音声認識(L2VT)→ ローカルLLM(LM Studio)→ AssistantSeika(音声合成製品制御プログラム)→音声合成ソフト(cevioなど)
といった感じの流れで、喋ったことに対してAIが合成音声ソフトを使用して音声で答えてくれる。
タイトルではCevioとしたが、AssistantSeikaが対応してる範囲ならカバーできます。
どうしてAIと音声会話できるのあるのに、そんな面倒なことしてるの?
うるさいですね……合成音声ソフトのキャラが良いのです
やったね。これで会話できるよ!
ロール設定が苦手で演じてもらうなら。小樽組の「小春六花ちゃん」「夏色花梨ちゃん」「花隈千冬ちゃん」とかX(旧ツイッター)で活動が盛んな方々がいいかもー?
公式アカウントのX(旧ツイッター)URLを投げて読み上げ用のシステムプロンプト用設定作ってもらえばそれなりのができるはず。顔文字や絵文字は出さない用で
ローカルPCのLLMモデルを使用しているのでデータを消さない限りはGPT-4oからGPT-5への移行みたいなことにならないはず
L2VT→ LM Studioの認識された音声のテキストの受け渡しを下記のPythonコードで仲介することにより実現させました
個別チャットにLM Studioが投げ渡しができないので会話履歴をchat_memory.jsonで保存
初回起動でLM Studioに全部放り投げる。会話履歴が冗長になってくると初回受付まで長くなるかも?
以下ai君作成のPythonコード
必要ソフト
・L2VT 音声認識
・LM Studio ローカルLLM(別途モデルが必要 Qwen2.5-7B-Instruct-1M-GGUFなど)
・AssistantSeika 音声合成製品制御プログラム
・各種合成音声ソフト Cevio AIなど
※お試し用なのでシステムプロンプトのめたんちゃんのRoleは全然削ってあるので
※各種ポート番号やIDやらを合わせて flaskなどの必要なライブラリがあれば動くと多分思います
talk.pt
import requests
import json
import base64
import os
import openai
from flask import Flask, request
# --- 設定項目 ---
SEIKA_URL_BASE = "http://localhost:7180" # AssistantSeika
CID = 50012 # 四国めたん等のID
USER_ID = "SeikaServerUser"
PASSWORD = "SeikaServerPassword"
SAVE_FILE = "chat_memory.json"
LISTEN_PORT = 50001 # 棒読みちゃんのフリをするポート
# LM Studio APIの設定
llm_client = openai.OpenAI(base_url="http://localhost:1234/v1", api_key="lm-studio")
app = Flask(__name__)
chat_history = []
# --- 履歴管理 ---
def load_initial_history():
if os.path.exists(SAVE_FILE):
try:
with open(SAVE_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
except:
pass
return [{"role": "system", "content": """# Role あなたは「四国めたん」として振る舞ってください。"""}]
def save_history(history):
with open(SAVE_FILE, 'w', encoding='utf-8') as f:
json.dump(history, f, ensure_ascii=False, indent=4)
# --- AssistantSeika発話関数 ---
def speak_seika(text):
auth_str = f"{USER_ID}:{PASSWORD}"
auth_b64 = base64.b64encode(auth_str.encode('utf-8')).decode('utf-8')
headers = {
'Authorization': f'Basic {auth_b64}',
'Content-Type': 'application/json'
}
url = f"{SEIKA_URL_BASE}/PLAY2/{CID}"
try:
requests.post(url, headers=headers, data=json.dumps({"talktext": text}), timeout=30)
except Exception as e:
print(f"AssistantSeika送信失敗: {e}")
# --- L2VT(棒読みちゃん互換)用エンドポイント ---
@app.route('/getvoicelist', methods=['GET'])
def get_voice_list():
# L2VTの接続確認に対して「デフォルト声」があるフリをする
return "<VoiceList><Voice ID='0' Name='Default'/></VoiceList>", 200
@app.route('/getnowplaying', methods=['GET'])
def get_now_playing():
return "0", 200
@app.route('/', defaults={'path': ''}, methods=['GET', 'POST'])
@app.route('/<path:path>', methods=['GET', 'POST'])
def catch_all(path):
# テキスト抽出 (パラメータ名 'text' または 直接のBody)
user_input = request.args.get('text') or request.form.get('text') or request.get_data(as_text=True)
# 接続テストなどの空文字は無視して正常終了させる
if not user_input or user_input.strip() == "":
return "OK", 200
print(f"\n[受信] あなた: {user_input}")
chat_history.append({"role": "user", "content": user_input})
try:
# 1. LM Studioへ送信
completion = llm_client.chat.completions.create(
model="local-model",
messages=chat_history
)
answer = completion.choices[0].message.content
print(f"[回答] AI: {answer}")
# 2. 履歴更新と保存
chat_history.append({"role": "assistant", "content": answer})
save_history(chat_history)
# 3. AssistantSeikaで読み上げ
speak_seika(answer)
return "OK", 200
except Exception as e:
print(f"エラー発生: {e}")
return "Error", 500
if __name__ == "__main__":
chat_history = load_initial_history()
print(f"--- AI待機中 (Port: {LISTEN_PORT}) ---")
print("L2VTの送信先を http://localhost:50001/ に設定してください。")
app.run(host='0.0.0.0', port=LISTEN_PORT, debug=False)
とまあ、ここまでやったのは良いが、A.I.VOICEやCevio AI入ってる配信用PCとローカルAIが入ってるPCが別なのよね。
どーしましょう。
VOICEVOXで運用して気に入ったらA.I.VOICEやCevio AIを追加購入?


コメント