見出し画像

OpenAIのFunction calling機能を活かした、LangChainの新機能Taggingを試す

Tagging機能

  • OpenAIのFunction calling機能を活かした、LangChainのTagging(tags)機能を試してみます。

  • pydanticの機能を使ってスキーマを設定して、テキストにタグ付けできる機能のようです。

さっそく試してみます

  • ネタは青空文庫の「走れメロス」の読み上げをシュッと試してみようと思います。読み上げの実装はbbzさんの記事を参考にさせてもらいました。

ファイル読み込み

# ファイルを読み込み、テキストを取得します。
with open("hashire_merosu.txt", mode="r", encoding="utf-8") as f:
    text_original = f.read()

print(text_original) 

整形

import re

# ルビなどを削除
text = re.sub("《[^》]+》", "", text_original)
text = re.sub("[[^]]+]", "", text) 
text = re.sub("[|  ]", "", text)

seperator = "\n" 
text_list = text.split(seperator)  
text_list.pop() 

スキーマ定義

from typing import Optional, List
from pydantic import BaseModel, Field

# PydanticのBaseModelを継承して、新しいデータモデルを定義します。
class Tags(BaseModel):
    sentiment: str =Field(...,description="Speaker's emotion" , enum=['talk','happy','sad','angry','fear','surprised'])
    speed: float = Field(..., description="Speaking speed in line with emotional intensity, default:1.0", ge=0.5, le=5.0)
    volume: float = Field(..., description="Loudness of voice in line with emotional intensity, default:1.0", ge=0.5, le=5.0)

sentiment = {'talk':1, 'happy':2, 'sad':3, 'angry':5, 'fear':6, 'surprised':7}

音声生成用の関数

import requests
import json

from langchain.chat_models import ChatOpenAI
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
from langchain.chains import create_tagging_chain, create_tagging_chain_pydantic

def txt_to_speach(text, filename):
    # APIのエンドポイントURL
    url = "https://api.rinna.co.jp/models/cttse/v2"
    
    # Tags生成用 chain
    llm = ChatOpenAI(model_name="gpt-3.5-turbo-0613", streaming=True, callbacks=[StreamingStdOutCallbackHandler()], temperature=0.7)
    chain = create_tagging_chain_pydantic(Tags, llm)

    tags = chain.run(text)
    tid = sentiment[tags.sentiment]
    # tid = 7
    
    # リクエストボディの作成
    data = {
        "sid": 28,  # ボイスID
        "tid": tid,   # スタイルID
        "speed": tags.speed, # 話速
        "text": text, # 合成するテキスト
        "volume": tags.volume, # 音量
        "format": "wav" # 出力ファイル形式
    }

    # リクエストヘッダーの作成
    headers = {
        "Content-Type": "application/json",
        "Cache-Control": "no-cache",
        "Ocp-Apim-Subscription-Key": RINNA_API_KEY
    }

    # POSTリクエストの送信
    response = requests.post(url, data=json.dumps(data), headers=headers)

    # レスポンスの確認
    if response.status_code == 200:
        print("Request was successful.")
        response_data = response.json()
        print("Media Content URL: ", response_data['mediaContentUrl'])
        print("Type: ", response_data['type'])

        # 音声ファイルのダウンロードと保存
        audio_response = requests.get(response_data['mediaContentUrl'])
        with open(f"./outputs/{filename}.wav", 'wb') as f:
            f.write(audio_response.content)
        print(f"Audio file has been saved as {filename}.wav.")
    else:
        print("Request failed. Status code: ", response.status_code)

実行!

import time

for index, value in enumerate(text_list):
    txt_to_speach(value, index)
    time.sleep(1)

--------------------------------------------------------------------------- KeyError Traceback (most recent call last) /tmp/ipykernel_1458/2411938320.py in 23 for index, value in enumerate(text_list): ----> 4 txt_to_speach(value, index) 5 time.sleep(1) /tmp/ipykernel_1458/608713805.py in txt_to_speach(text, filename) 1516 tags = chain.run(text) ---> 17 tid = sentiment[tags.sentiment] 1819 # リクエストボディの作成 KeyError: 'embarrassed'

ありゃりゃ、一番最後で止まってしまいました。

「勇者は、ひどく赤面した。」の部分を感情推定しようとすると、確かに 'embarrassed'が適当だと思いますよ、gpt -3.5-turboさん😓。でも、残念ながら選択肢にないんですよ…ごめんね。
というわけで、たまにエラーが発生してしまうようなので、実際に使うときは例外処理も書かないといけませんね。今回は、お試しですし、一番最後の部分だったので、ひとまず手動で生成しました。😋

いちおう結果はこちら

最終的に生成された音声ファイルは、期待通りの結果を得ることができました。感情推定がなんとも微妙な感じの部分はありますが、Tagging機能を使い方が分かったので、今回はここまで。

参考情報

おしまい


この記事が気に入ったらサポートをしてみませんか?