initial_commit
This commit is contained in:
@@ -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")
|
||||
Reference in New Issue
Block a user