なんかこう、惜しいような… 前回からはパラメーターしかいじってない
from fastapi import FastAPI
from pydantic import BaseModel
from transformers import GPT2LMHeadModel, AutoTokenizer
import torch, subprocess, os, wave
from datetime import datetime
# ----------------------------------------------------
# 🔥 モデルフォルダ
# ----------------------------------------------------
device = "cuda" if torch.cuda.is_available() else "cpu"
tok = AutoTokenizer.from_pretrained("model", use_fast=False)
model = GPT2LMHeadModel.from_pretrained("model").to(device).eval()
# ----------------------------------------------------
# 🚀 FastAPI
# ----------------------------------------------------
app = FastAPI()
class Msg(BaseModel):
text: str
# ----------------------------------------------------
# 🟣 /chat(テキストのみ)
# ----------------------------------------------------
@torch.inference_mode()
@app.post("/chat")
def chat(m: Msg):
prompt = (
"あなたは「oupe ec」"
"齋藤凪沙が書いた日記や思考、発話のスタイルを学習しており、"
"彼女の語感・比喩・距離感・揺らぎをもとに、質問や発話に返答します。"
"意識やキャラ性は演じません。"
"あくまで、齋藤凪沙という人が考えたら出しそうな言葉の構造を予測して返します。"
"文法は破綻していても構いません。抽象と具体の間を自由に行き来してください。"
"直接答えなくてもかまいません。返答のしかた自体が彼女の癖を反映していればOKです。"
"30字以内の詩的メッセージを語感豊かに1行だけ返してください。\\n\\n"
"ユーザ:今日見た食べ物から連想されたものを短く詩にしてください。\\n"
"oupe ec:粉飾したわらびもち いぬのキンタマ<END>\\n\\n"
"ユーザ:言葉の遊びで何かひとつ作ってください。\\n"
"oupe ec:おもてなし うらない<END>\\n\\n"
"ユーザ:今の気持ちを教えてください。\\n"
"oupe ec:さけびたい さけびたい の だが 下宿ではやや厳しい ので 野に放っていただきたい<END>\\n\\n"
f"ユーザ:{m.text.strip()}\\n"
"[[START]]"
)
ids = tok(prompt, return_tensors="pt").to(device)
prompt_len = ids.input_ids.shape[-1]
out = model.generate(
**ids,
max_new_tokens=42,
min_new_tokens=6,
do_sample=True,
temperature=1.22,
top_p=0.88,
repetition_penalty=1.08,
pad_token_id=tok.eos_token_id,
)
gen_tokens = out[0][prompt_len:]
reply = tok.decode(gen_tokens, skip_special_tokens=True).strip()
reply = reply.strip('\\"“”「」『』')
return {"reply": reply}
# ----------------------------------------------------
# 🟣 /chat_and_speak(音声生成・保存つき)
# ----------------------------------------------------
@torch.inference_mode()
@app.post("/chat_and_speak")
def chat_and_speak(m: Msg):
# 1) Chat で返答生成
chat_result = chat(m)
reply = chat_result["reply"]
# ----------------------------------------------------
# ① リアルタイム読み上げ(Kyoko → Sandy)
# ----------------------------------------------------
subprocess.run(["say", "-v", "Kyoko", f"ユーザー {m.text}"])
subprocess.run(["say", "-v", "Sandy", f"オウペエーク {reply}"])
# ----------------------------------------------------
# ② WAV 保存セットアップ
# ----------------------------------------------------
SAVE_DIR = "./audio_logs"
os.makedirs(SAVE_DIR, exist_ok=True)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
user_wav = f"{SAVE_DIR}/{timestamp}_user.wav"
oupe_wav = f"{SAVE_DIR}/{timestamp}_oupe.wav"
stereo_wav = f"{SAVE_DIR}/{timestamp}_stereo.wav"
# ----------------------------------------------------
# 安全な say(音が出ないように --data-format)
# ----------------------------------------------------
def safe_say(cmd, outpath):
for _ in range(3):
subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
if os.path.exists(outpath):
return True
return False
safe_say(["say", "-v", "Kyoko", "--data-format=LEI16@48000", "-o", user_wav, m.text], user_wav)
safe_say(["say", "-v", "Sandy", "--data-format=LEI16@48000", "-o", oupe_wav, reply], oupe_wav)
# ----------------------------------------------------
# ③ ステレオ WAV 生成(L:ユーザー / R:oupe ec)
# ----------------------------------------------------
if os.path.exists(user_wav) and os.path.exists(oupe_wav):
with wave.open(user_wav, 'rb') as wu, wave.open(oupe_wav, 'rb') as wo:
params = wu.getparams()
sw = params.sampwidth
rate = params.framerate
u = wu.readframes(params.nframes)
o = wo.readframes(params.nframes)
# 長さ調整
if len(u) < len(o): u += b"\\x00" * (len(o) - len(u))
if len(o) < len(u): o += b"\\x00" * (len(u) - len(o))
stereo = bytearray()
for i in range(0, len(u), sw):
stereo.extend(u[i:i+sw] + o[i:i+sw])
with wave.open(stereo_wav, 'wb') as w:
w.setnchannels(2)
w.setsampwidth(sw)
w.setframerate(rate)
w.writeframes(stereo)
return {
"reply": reply,
"user_wav": user_wav,
"oupe_wav": oupe_wav,
"stereo_wav": stereo_wav
}




お!また出ましたムチムチ!!前のoupe ecも愛のムチムチって言ってたからね。
個人的にはパタスモンキーの話を聞かなかった〜のくだりが結構おもろい