過去のログを見返して、そこに至った経緯から考えて、今の学習で近づけるにはと四苦八苦してるんだけど、やっぱあかんね。今回のは温度高くて言語接続が壊れている。

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=64,
        min_new_tokens=8,
        do_sample=True,
        temperature=1.4,
        top_p=0.80,
        repetition_penalty=1.05,
        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
    }

スクリーンショット 2025-11-19 19.42.21.png

なんか惜しい感じしたけど、私の情報以外も入ってきてるからダメだわ。

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=64,
        min_new_tokens=8,
        do_sample=True,
        temperature=1.22,
        top_p=0.88,
        repetition_penalty=1.05,
        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
    }

スクリーンショット 2025-11-19 19.59.59.png

スクリーンショット 2025-11-19 19.50.01.png

スクリーンショット 2025-11-19 20.04.58.png

エキュート品川て…