[PYTHON] J'ai essayé de reproduire M. Saito qui apparaît dans "Aine Kleine Nachtmusik" comme M. Sakurai de Mischil

introduction

Le roman de Kotaro Isaka ["Aine Kleine Nachtmusik"](https://www.amazon.co.jp/%E3%82%A2%E3%82%A4%E3%83%8D%E3%82%AF% E3% 83% A9% E3% 82% A4% E3% 83% 8D% E3% 83% 8A% E3% 83% 8F% E3% 83% 88% E3% 83% A0% E3% 82% B8% E3% 83% BC% E3% 82% AF-% E5% B9% BB% E5% 86% AC% E8% 88% 8E% E6% 96% 87% E5% BA% AB-% E4% BC% 8A% E5% Connaissez-vous le travail 9D% 82% E5% B9% B8% E5% A4% AA% E9% 83% 8E-ebook / dp / B0746CS4T6)? Si vous aimez les romans, vous le savez peut-être. C'est un montage court qui ressemble à tous les jours, mais Une personne nommée «M. Saito» apparaît dans l'œuvre. Si vous payez 100 yens et parlez de "Je me sens comme ça maintenant" et "Je suis dans cette situation", M. Saito jouera certaines des chansons qui correspondent à l'humeur du client sur l'ordinateur. Il n'y a que M. Saito dans la chanson, et une partie de la chanson de Kazuyoshi Saito est jouée.

J'ai donc pensé que je pourrais faire la même chose en utilisant l'analyse des émotions. J'ai décidé de le faire cette fois. Tout artiste va bien, mais je suis moi-même un mystérieux fan Je l'ai fait avec un personnage appelé M. Sakurai.

Cette fois, nous utiliserons l'analyse des émotions de l 'API COTOHA. Il semble qu'ils font également Campagne, et ils participent également.

Ce que tu as fait

C'est plus rapide de voir si vous avez fait quelque chose que d'expliquer.

tu:
Vous: Chaque jour est monotone et ennuyeux. Je me demande s'il y a quelque chose de bon.
Vous: Chaque jour est monotone et ennuyeux. Je me demande s'il y a quelque chose de bon.
M. Sakurai: Je suis à la fin de la vingtaine et je fais la navette entre Tokyo et Paris.[Delmo]

Tu peux tout prendre, Il semble que vous pouvez interpréter que vous pouvez avoir une vie de voile douce en faisant un travail que vous allez souvent à Paris. Cela fera partie des paroles de la chanson de Mischil "Delmo".

Présentation du système

Il peut être grossièrement divisé en (1) construction de données et (2) traitement de recherche de phrase.

sakuraisan-image.png

① Construction des données Gratter les paroles du réseau de chansons, Divisez en phrases. (Un paragraphe de toutes les paroles est une phrase) Chaque phrase est appliquée à l'API d'analyse des émotions et le résultat de l'analyse est enregistré dans la base de données.

② Recherche de phrase Le client explique la situation et applique le contenu à l'API d'analyse des émotions pour obtenir le résultat de l'analyse. Après cela, recherchez dans la base de données des phrases avec des scores similaires. La recherche est une recherche par plage de la partition, tout en élargissant la plage. Si plusieurs phrases peuvent être obtenues, l'une est sélectionnée au hasard et répond au client.

Résultat d'exécution

Voici quelques-unes des choses que j'ai faites et que j'ai trouvées intéressantes.

Vous: Je suis si heureux d'être félicité au travail aujourd'hui!
Sakurai: Si vous êtes frustré, remplissez votre amour. Les flammes de l'amour envers vous brûlent. Le chien Shiba dans la maison d'en face dit aussi "Hyponjour".!Ah, le monde est rose, donc ici CENTRE DE L'UNIVERS Je suis le centre Ah, le monde est merveilleux[CENTER OF UNIVERSE]

En regardant uniquement la première mi-temps, est-ce frustrant? J? ai compris, Je chante quelque chose de vraiment joyeux en seconde période. Le travail va bien, je suis le champion du monde! Cible.

Vous: J'ai échoué à étudier pour l'examen. Je me demande si je ferai de mon mieux l'année prochaine. .. ..
M. Sakurai: Je veux prendre une profonde inspiration et libérer ce sentiment dans le ciel Je veux sortir de l'humeur terne que je suis piégé dans mon propre monde[SUNRISE]

Pour le moment, respirez et sortez de l'ambiance terne. Cela me semble négatif, mais cela me donne aussi beaucoup d'encouragement.

Toi: je ne dirai pas que je ne suis plus amoureux
M. Sakurai: Je peux vous entendre, les sentiments incontrôlables à votre sujet sont ici, même si vous fermez les oreilles, ils sonnent[365 jours]

Les sentiments que j'aime et irrésistibles correspondent.

Vous: En fait, je pense à rompre avec sa datation
Sakurai: Déjà bon!?Terminons ça!?Tu le penses aussi!? [I]

Cela peut vous dire que vous pouvez le terminer.

code

Si vous êtes intéressé, jetez un œil. J'ai fait quelque chose qui fonctionne pour le moment, alors sachez que ce n'est pas bien organisé. .. ..

<détails>

Schéma DB </ summary>

J'utilise MYSQL. Cette fois, Mr.Children sera enregistré à l'avance comme information d'artiste.

create database sakurai;

create table artist
  (artist_id smallint auto_increment not null primary key,
  artist_name varchar(100));

insert into artist (artist_name) values('Mr.Children');

create table title
  (title_id smallint auto_increment not null primary key,
  title varchar(100),
  artist_id smallint);
 
create table lyric
 (title_id smallint,
  phrase_id int auto_increment not null primary key,
  phrase varchar(1000),
  score float,
  sentiment tinyint);

<détails>

Code Python </ summary>

sakuraisan.py


# -*- coding: utf-8 -*-

import random, requests, json, sys, time
import urllib.request
import mysql.connector as mydb
import pandas as pd

from bs4 import BeautifulSoup

ARTIST_ID = 1 #Identifiant d'artiste enregistré à l'avance dans DB
AGENT_NAME = 'Sakurai' #Le nom de l'agent qui répond

#Classe API COTOHA
class CotohaApi():
    def __init__(self):
        self.COTOHA_ACCESS_INFO = {
            "grantType": "client_credentials",
            "clientId": "<Votre identifiant client>",
            "clientSecret": "<Votre propre secret client>"
        }
        self.ACCESS_TOKEN_PUBLISH_URL = '<URL de publication de votre jeton d'accès>'
        self.BASE_URL = '<Votre URL de base API'

        self.ACCESS_TOKEN = self.get_access_token()

    #Obtenez un jeton d'accès
    def get_access_token(self):
        headers = {
            "Content-Type": "application/json;charset=UTF-8"
        }
        access_data = json.dumps(self.COTOHA_ACCESS_INFO).encode()
        request_data = urllib.request.Request(self.ACCESS_TOKEN_PUBLISH_URL, access_data, headers)
        token_body = urllib.request.urlopen(request_data)
        token_body = json.loads(token_body.read())
        self.access_token = token_body["access_token"]
        self.headers = {
            'Content-Type': 'application/json;charset=UTF-8',
            'Authorization': 'Bearer {}'.format(self.access_token)
        }

    #Implémentation de l'API d'analyse des émotions et retour des résultats d'analyse
    def sentiment_analysis(self, text):
        request_body = {
            'sentence': text
        }
        url = self.BASE_URL + 'nlp/v1/sentiment'
        text_data = json.dumps(request_body).encode()
        request_data = urllib.request.Request(url, text_data, headers=self.headers, method='POST')
        sentiment_result = urllib.request.urlopen(request_data)
        sentiment_result = json.loads(sentiment_result.read())
        return sentiment_result

    # Positive:1, Negative:-1, Neutral:Convertir en 0
    def convert_sentiment(self, sentiment_in_word):
        if sentiment_in_word == 'Positive':
            return 1
        elif sentiment_in_word == 'Neutral':
            return 0
        elif sentiment_in_word == 'Negative':
            return -1

#Classe d'opération DB
class DBHandler():
    def __init__(self):
        self.conn = mydb.connect(
            host = '<Nom d'hôte de la base de données>',
            port = '<Numéro de port DB>',
            user = '<Nom d'utilisateur DB>',
            password = '<Mot de passe DB>',
            database = '<Nom de la base de données>',
            charset='utf8'
        )

        self.conn.ping(reconnect=True)
        self.cur = self.conn.cursor()

#Classe de construction de données
class Learn():
    def __init__(self):
        self.FILE_NAME = 'list.csv'
        self.ARTIST_NUMBER = '684' #Uta Net Artist Non.(Mr.Enfants 684)
        self.MAX_PAGE = 2 #Nombre de pages de liste de chansons des artistes du réseau de chansons (Mr.Les enfants ont 2 pages)

    #Recueillir les paroles de Song Net
    def gather_lyric(self):
        #Créer une table pour contenir les données récupérées
        list_df = pd.DataFrame(columns=['Titre de la chanson', 'Paroles'])

        for page in range(1, self.MAX_PAGE + 1):
            #Adresse du haut de la page de la chanson
            base_url = 'https://www.uta-net.com'

            #Page de la liste des paroles
            url = 'https://www.uta-net.com/artist/' + self.ARTIST_NUMBER + '/0/' + str(page) + '/'
            response = requests.get(url)
            soup = BeautifulSoup(response.text, 'lxml')
            links = soup.find_all('td', class_='side td1')

            for link in links:
                a = base_url + (link.a.get('href'))

                #Page de détail des paroles
                response = requests.get(a)
                soup = BeautifulSoup(response.text, 'lxml')
                title = soup.find('h2').text
                print(title)
                song_lyrics = soup.find('div', itemprop='text')
                
                for lyric in song_lyrics.find_all("br"):
                    lyric.replace_with('\n')
                song_lyric = song_lyrics.text

                #Attendez 1 seconde pour ne pas charger le serveur
                time.sleep(1)

                #Ajouter les paroles acquises au tableau
                tmp_se = pd.DataFrame([title, song_lyric], index=list_df.columns).T
                list_df = list_df.append(tmp_se)

        #csv enregistrer
        list_df.to_csv(self.FILE_NAME, mode = 'a', encoding='utf8')

    #Divisez les paroles en phrases et enregistrez les données, y compris les résultats de l'analyse des émotions dans la base de données
    def add_lyric(self):
        db = DBHandler()
        df_file = pd.read_csv(self.FILE_NAME, encoding='utf8')
        song_titles = df_file['Titre de la chanson'].tolist()
        song_lyrics = df_file['Paroles'].tolist()
        
        #Remarque: s'il y a beaucoup de chansons, la limite supérieure d'API pouvant être exécutée dans COTOHA par jour sera atteinte (environ 100 chansons par jour sont un guide).
        for i in range(len(song_titles)):

            #Ajouter un titre
            title = song_titles[i]

            print("Info: Saving {}...".format(title), end="")
            db.cur.execute(
                """
                insert into title (title, artist_id)
                values (%s, %s);
                """,
                (title, ARTIST_ID)
            )
            db.conn.commit()
            db.cur.execute(
                """
                select title_id from title
                where title= %s
                and artist_id = %s;
                """,
                (title, ARTIST_ID)
            )
            title_id = db.cur.fetchall()[-1][0]

            #Enregistrer le résultat de l'analyse des émotions de la phrase des paroles
            #Délimiteur de phrase lorsque deux sauts de ligne apparaissent
            lyric = song_lyrics[i]
            lyric_phrases = lyric.split('\n\n')
            lyric_phrases = [lyric.replace('\u3000', ' ').replace('\n', ' ') for lyric in lyric_phrases]
            
            #Utilisez l'API d'analyse des émotions pour chaque phrase et enregistrez les résultats de l'analyse des émotions dans la base de données
            cotoha_api= CotohaApi()
            for phrase in lyric_phrases:
                sentiment_result = cotoha_api.sentiment_analysis(phrase)['result']
                sentiment = cotoha_api.convert_sentiment(sentiment_result['sentiment'])
                score = sentiment_result['score']
                
                db.cur.execute(
                    """
                    insert into lyric (title_id, score, sentiment, phrase)
                    values (%s, %s, %s, %s);
                    """,
                    (title_id, score, sentiment, phrase)
                )
                db.conn.commit()

            print("Done")
                
        db.conn.close()
        if db.conn.is_connected() == False:
            print("Info: DB Disonnected")

    def execute(self):
        print("Info:Collectionner les paroles...")
        self.gather_lyric()
        print("Info:Ajout de paroles à DB...")
        self.add_lyric()

#Classe de recherche d'expression
class Search():
    def __init__(self):
        self.SEARCH_SCOPE = [0.01, 0.1, 0.3] #Largeur du score à rechercher SCORE ± SEARCH_Rechercher dans l'ordre de la liste dans la plage de SCOPE

    def execute(self):
        print("tu:", end="")
        input_data = input()
        print("{}:".format(AGENT_NAME), end="")
        
        cotoha_api= CotohaApi()
        sentiment_result = cotoha_api.sentiment_analysis(input_data)['result']
        sentiment = cotoha_api.convert_sentiment(sentiment_result['sentiment'])
        score = sentiment_result['score']
        
        db = DBHandler()

        find_flag = 0
        #Recherchez des expressions avec des scores similaires tout en élargissant progressivement la plage de recherche
        for scope in self.SEARCH_SCOPE:

            #Confirmez qu'il y en a au moins un
            db.cur.execute(
                """
                select count(phrase_id) from lyric
                join title on lyric.title_id = title.title_id
                where sentiment = %s
                and score between %s and %s
                and artist_id = %s;
                """,
                (sentiment, score-scope, score+scope, ARTIST_ID)
            )
            hit_num = db.cur.fetchall()[-1][0]
            if hit_num > 0:
                find_flag = 1
                break
        
        #S'il y a même un résultat de recherche, obtenez le résultat de la recherche et répondez au client
        if find_flag == 1:
            db.cur.execute(
                """
                select phrase,title from lyric
                join title on lyric.title_id = title.title_id
                where sentiment = %s
                and score between %s and %s
                and artist_id = %s;
                """,
                (sentiment, score-scope, score+scope, ARTIST_ID)
            )
            search_result = db.cur.fetchall()
            phrase_chosen = random.choice(search_result)
            print("{} [{}]".format(phrase_chosen[0], phrase_chosen[1]))
        else:
            print("Je n'ai pas trouvé de bonnes paroles.")
        
        db.conn.close()
        

if __name__ == "__main__":
    args = sys.argv
    if len(args) == 2:
        process = args[1] #Argument de ligne de commande apprendre:Enregistrer les informations sur les paroles dans DB, rechercher:Extraire des phrases émotionnelles similaires de DB
        if process == 'search':
            searcher = Search()
            searcher.execute()
        elif process == 'learn':
            learner = Learn()
            learner.execute()
        else:
            print("Error:Spécifiez un argument de ligne de commande[learn/search]")
    else:
        print("Error:Spécifiez un argument de ligne de commande[learn/search]")

Il existe deux manières de l'exécuter.

  • Lors de la création de données
python sakuraisan.py learn
  • Lors de la recherche de phrases
python sakuraisan.py search

en conclusion

Cette fois, je l'ai implémenté avec un algorithme simple qui récupère des phrases avec des paroles qui ont des scores similaires dans les résultats de l'analyse des émotions. L'API COTOHA peut également prendre les émotions des mots. Par exemple, comme dans l'exemple officiel Le mot «chanson» donne des sentiments tels que «agréable» et «soulagé». Je pense que de meilleurs résultats seront renvoyés si les informations ici peuvent être bien intégrées dans la recherche.

De plus, je pense qu'il serait intéressant d'utiliser LINE Bot.

référence

J'ai fait référence à l'article suivant!

Recommended Posts