22ac40450f
Завершающий кусок Спринта 2 — UI для ведения диалогов. static/sandbox.html: - Трёхколоночная раскладка во всю высоту экрана. - Слева: список сохранённых диалогов (имя, дата последнего обновления, счётчик сообщений, превью первой реплики), кнопка «+ новый»; на каждой карточке — «переименовать» (prompt) и «удалить» (confirm). - Центр: чат в привычной стилистике (пузыри, user справа, assistant слева), Enter — отправить, Shift+Enter — перенос строки. Заголовок сверху показывает имя активного треда. - Справа: отладка ответа — найденные фрагменты со score в процентах + собранный промпт в моноширинном блоке на светлом фоне. - При отправке первой реплики тред создаётся автоматически, API возвращает thread_id и thread_name — дальше реплики уходят в тот же тред. static/index.html: в шапке добавлены ссылки «Отладка» / «Песочница», подсветка активной страницы; тот же стиль nav-ссылок продублирован в sandbox.html. routers/chat: detail сообщения ошибки теперь включает тип исключения (удобнее при диагностике), trace пишется через logger.exception. SPRINTS.md: Спринт 2 помечен как закрытый. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
49 lines
1.6 KiB
Python
49 lines
1.6 KiB
Python
import logging
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from db.session import get_session
|
|
from models.requests import ChatRequest
|
|
from models.responses import ChatResponse, SourceInfo
|
|
from services import chat_service
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
router = APIRouter(prefix="/chat", tags=["chat"])
|
|
|
|
|
|
@router.post("", response_model=ChatResponse)
|
|
async def chat(req: ChatRequest, session: AsyncSession = Depends(get_session)):
|
|
from main import llm_client, vectorstore_service
|
|
|
|
if vectorstore_service is None or llm_client is None:
|
|
raise HTTPException(status_code=503, detail="Service not ready")
|
|
|
|
try:
|
|
result = await chat_service.send_message(
|
|
session=session,
|
|
vectorstore=vectorstore_service,
|
|
llm=llm_client,
|
|
text=req.text,
|
|
thread_id=req.thread_id,
|
|
top_k=req.top_k,
|
|
temperature=req.temperature,
|
|
max_tokens=req.max_tokens,
|
|
)
|
|
except LookupError as e:
|
|
raise HTTPException(status_code=404, detail=str(e))
|
|
except Exception as e:
|
|
logger.exception("Chat failed")
|
|
raise HTTPException(status_code=500, detail=f"Chat error [{type(e).__name__}]: {e}")
|
|
|
|
return ChatResponse(
|
|
thread_id=result["thread_id"],
|
|
thread_name=result["thread_name"],
|
|
message_id=result["message_id"],
|
|
answer=result["answer"],
|
|
sources=[SourceInfo(**s) for s in result["sources"]],
|
|
model_used=result["model_used"],
|
|
assembled_prompt=result["assembled_prompt"],
|
|
)
|