nullai-knowledge-system / backend /app /api /chat_sessions.py
kofdai's picture
Deploy NullAI Knowledge System to Spaces
075a2b6 verified
"""
Chat Sessions API
チャット履歴管理用のAPIエンドポイント
"""
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
from typing import List, Optional
from datetime import datetime
import json
import os
from pathlib import Path
import uuid
router = APIRouter()
# チャットセッションの保存先
SESSIONS_DIR = Path("chat_sessions")
SESSIONS_DIR.mkdir(exist_ok=True)
SESSIONS_FILE = SESSIONS_DIR / "sessions.json"
class ChatMessage(BaseModel):
"""チャットメッセージ"""
role: str # "user" or "assistant"
content: str
timestamp: str
class ChatSession(BaseModel):
"""チャットセッション"""
session_id: str
title: str
created_at: str
updated_at: str
domain_id: str
model_id: Optional[str] = None
messages: List[ChatMessage] = []
class CreateSessionRequest(BaseModel):
"""新規セッション作成リクエスト"""
title: Optional[str] = None
domain_id: str = "general"
model_id: Optional[str] = None
class UpdateSessionRequest(BaseModel):
"""セッション更新リクエスト"""
title: Optional[str] = None
def load_sessions() -> List[ChatSession]:
"""セッション一覧をロード"""
if not SESSIONS_FILE.exists():
return []
try:
with open(SESSIONS_FILE, 'r', encoding='utf-8') as f:
data = json.load(f)
return [ChatSession(**session) for session in data]
except Exception as e:
print(f"Error loading sessions: {e}")
return []
def save_sessions(sessions: List[ChatSession]):
"""セッション一覧を保存"""
try:
with open(SESSIONS_FILE, 'w', encoding='utf-8') as f:
json.dump([session.model_dump() for session in sessions], f, indent=2, ensure_ascii=False)
except Exception as e:
print(f"Error saving sessions: {e}")
raise HTTPException(status_code=500, detail=f"Failed to save sessions: {str(e)}")
def generate_title_from_message(message: str) -> str:
"""メッセージから自動でタイトルを生成"""
# 最初の50文字を取得
title = message[:50]
if len(message) > 50:
title += "..."
return title
@router.get("/", response_model=List[ChatSession])
async def list_sessions():
"""
チャットセッション一覧を取得
"""
sessions = load_sessions()
# 更新日時の降順でソート
sessions.sort(key=lambda x: x.updated_at, reverse=True)
return sessions
@router.post("/", response_model=ChatSession)
async def create_session(request: CreateSessionRequest):
"""
新規チャットセッションを作成
"""
session_id = f"session_{uuid.uuid4().hex[:12]}"
now = datetime.now().isoformat()
# タイトルが指定されていない場合はデフォルトタイトル
title = request.title or f"新しいチャット - {datetime.now().strftime('%Y/%m/%d %H:%M')}"
new_session = ChatSession(
session_id=session_id,
title=title,
created_at=now,
updated_at=now,
domain_id=request.domain_id,
model_id=request.model_id,
messages=[]
)
sessions = load_sessions()
sessions.append(new_session)
save_sessions(sessions)
return new_session
@router.get("/{session_id}", response_model=ChatSession)
async def get_session(session_id: str):
"""
特定のチャットセッションを取得
"""
sessions = load_sessions()
for session in sessions:
if session.session_id == session_id:
return session
raise HTTPException(status_code=404, detail="Session not found")
@router.put("/{session_id}", response_model=ChatSession)
async def update_session(session_id: str, request: UpdateSessionRequest):
"""
チャットセッションを更新(タイトル変更など)
"""
sessions = load_sessions()
for i, session in enumerate(sessions):
if session.session_id == session_id:
if request.title:
sessions[i].title = request.title
sessions[i].updated_at = datetime.now().isoformat()
save_sessions(sessions)
return sessions[i]
raise HTTPException(status_code=404, detail="Session not found")
@router.delete("/{session_id}")
async def delete_session(session_id: str):
"""
チャットセッションを削除
"""
sessions = load_sessions()
for i, session in enumerate(sessions):
if session.session_id == session_id:
del sessions[i]
save_sessions(sessions)
return {"message": "Session deleted successfully"}
raise HTTPException(status_code=404, detail="Session not found")
@router.post("/{session_id}/messages")
async def add_message(session_id: str, message: ChatMessage):
"""
セッションにメッセージを追加
"""
sessions = load_sessions()
for i, session in enumerate(sessions):
if session.session_id == session_id:
sessions[i].messages.append(message)
sessions[i].updated_at = datetime.now().isoformat()
# 最初のユーザーメッセージの場合、自動でタイトルを生成
if len(sessions[i].messages) == 1 and message.role == "user":
if sessions[i].title.startswith("新しいチャット"):
sessions[i].title = generate_title_from_message(message.content)
save_sessions(sessions)
return {"message": "Message added successfully"}
raise HTTPException(status_code=404, detail="Session not found")