まあ何とか出力が私を感じられるものになってきたけど、日記の形式として日時やタグをつけていたのが裏目に出て(英語に引っ張られる癖があった)、あまりうまくはいっていなかった
from fastapi import FastAPI, Request
from pydantic import BaseModel
from transformers import GPT2LMHeadModel, AutoTokenizer
import torch, uuid, subprocess, os, wave
from datetime import datetime
# --------------------------
# 🔥 モデルフォルダ
# --------------------------
MODEL_PATH = "/Users/NaLo9/AI_myself/oupe-ec-server/model"
device = "cuda" if torch.cuda.is_available() else "cpu"
tok = AutoTokenizer.from_pretrained(MODEL_PATH, use_fast=False)
model = GPT2LMHeadModel.from_pretrained(MODEL_PATH).to(device).eval()
# --------------------------
# 🚀 FastAPI
# --------------------------
app = FastAPI()
memory: dict[str, list[tuple[str, str]]] = {}
class Msg(BaseModel):
text: str
# --------------------------
# 🧹 ノイズ除去関数 (# や ### を削る)
# --------------------------
def clean_text(t: str) -> str:
out = []
for line in t.splitlines():
if line.strip().startswith("#"):
continue
if line.strip().startswith("###"):
continue
out.append(line)
return "\\n".join(out).strip()
# ---------------------------------------------------
# 🟣 通常チャット
# ---------------------------------------------------
@torch.inference_mode()
@app.post("/chat_and_speak")
def chat_and_speak(req: Request, m: Msg):
sid = req.headers.get("X-Session-ID") or str(uuid.uuid4())
history = memory.get(sid, [])[-5:]
# ---- システムプロンプト(命令は少なめ) ----
system_prompt = (
"あなたは「oupe ec」。"
"齋藤凪沙の日記から“語感だけ”を学んだ人工的な影の存在です。"
"ユーザーの言葉には必ず応答し、内容は新しく生成してください。"
"抽象や跳躍を許すが、会話として薄くつながっていてください。"
"返答は2文以内で、引用やタグは使わないこと。\\n"
"----\\n"
)
# ---- 履歴を GPT2 向けに整形 ----
buf = [system_prompt]
for u, o in history:
buf.append(f"ユーザー: {clean_text(u)}")
buf.append(f"oupe ec: {clean_text(o)}")
buf.append(f"ユーザー: {clean_text(m.text)}")
buf.append("oupe ec:")
prompt = "\\n".join(buf)
ids = tok(prompt, return_tensors="pt").to(device)
prompt_len = ids.input_ids.shape[-1]
# ---- 生成 ----
out = model.generate(
**ids,
max_new_tokens=80,
do_sample=True,
temperature=0.75,
top_p=0.92,
repetition_penalty=1.12,
pad_token_id=tok.eos_token_id,
)
reply = tok.decode(out[0][prompt_len:], skip_special_tokens=True).strip()
reply = clean_text(reply)
# ---- 記憶に追加 ----
memory.setdefault(sid, []).append((m.text, reply))
# ---- 音声再生 ----
subprocess.run(["say", "-v", "Kyoko", f"ユーザー {m.text}"])
subprocess.run(["say", "-v", "Sandy", f"オウペック {reply}"])
# ---- WAV 保存(省略:あなたのコードのまま) ----
# (ここは元コードが正しく動くので割愛)
return {"reply": reply, "session_id": sid}



