initial_commit

This commit is contained in:
2026-06-01 20:16:53 +09:00
commit 903d34761c
31 changed files with 1123 additions and 0 deletions
+91
View File
@@ -0,0 +1,91 @@
import uuid
from datetime import datetime, timezone
from fastapi import APIRouter, Depends, HTTPException
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
from sqlalchemy.orm import Session as DBSession
from app.db.database import get_db
from app.db.models import Session, Message
from app.core import memory as mem
from app.core import llm
from app.core.config import DEFAULT_MODEL
router = APIRouter(prefix="/chat", tags=["chat"])
class ChatRequest(BaseModel):
session_id: str | None = None
message: str
model: str | None = None
class SessionResponse(BaseModel):
id: str
title: str
model: str
updated_at: datetime
class Config:
from_attributes = True
@router.get("/sessions", response_model=list[SessionResponse])
def list_sessions(db: DBSession = Depends(get_db)):
return db.query(Session).order_by(Session.updated_at.desc()).all()
@router.delete("/sessions/{session_id}", status_code=204)
def delete_session(session_id: str, db: DBSession = Depends(get_db)):
session = db.get(Session, session_id)
if not session:
raise HTTPException(status_code=404, detail="Session not found")
db.delete(session)
db.commit()
@router.post("/stream")
async def stream_chat(req: ChatRequest, db: DBSession = Depends(get_db)):
# セッション取得 or 新規作成
if req.session_id:
session = db.get(Session, req.session_id)
if not session:
raise HTTPException(status_code=404, detail="Session not found")
else:
session = Session(
id=str(uuid.uuid4()),
title=req.message[:40],
model=req.model or DEFAULT_MODEL,
)
db.add(session)
db.commit()
# ユーザーメッセージを保存
user_msg = Message(session_id=session.id, role="user", content=req.message)
db.add(user_msg)
db.commit()
context = mem.get_context_messages(db, session.id)
async def generate():
# セッションIDをまず返す(新規セッション時にフロントへ通知)
yield f"data: {{\"type\":\"session_id\",\"value\":\"{session.id}\"}}\n\n"
full_response = []
async for chunk in llm.stream_chat(context, model=req.model or session.model):
full_response.append(chunk)
escaped = chunk.replace('"', '\\"').replace('\n', '\\n')
yield f"data: {{\"type\":\"chunk\",\"value\":\"{escaped}\"}}\n\n"
# アシスタントメッセージを保存
assistant_content = "".join(full_response)
db.add(Message(session_id=session.id, role="assistant", content=assistant_content))
session.updated_at = datetime.now(timezone.utc)
db.commit()
# メモリ要約チェック
await mem.maybe_summarize(db, session)
yield "data: {\"type\":\"done\"}\n\n"
return StreamingResponse(generate(), media_type="text/event-stream")