Add model selection, dashboard chat input, and model warming

- Add GET /api/chat/ps and POST /api/chat/warm endpoints for hot model
  visibility and pre-loading
- Extend PATCH /api/chat/conversations/:id to accept model in addition
  to title
- Add ModelSelector component with hot/cold indicators from Ollama /api/ps
- Add DashboardChatInput component (model selector + note picker + textarea)
  replacing the simple "New Chat" button on the dashboard
- Add model selector dropdown to ChatView header, persisted per-conversation
- Warm default model on dashboard mount via fire-and-forget background task
- Configure Ollama with OLLAMA_MAX_LOADED_MODELS=2 and OLLAMA_KEEP_ALIVE=30m
- Always-visible edit buttons on NoteCard/TaskCard (remove hover-only behavior)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-14 18:49:06 -05:00
parent 987ec56dc3
commit 953eaf2feb
13 changed files with 710 additions and 306 deletions
+15 -3
View File
@@ -103,8 +103,11 @@ async def delete_conversation(user_id: int, conversation_id: int) -> bool:
return True
async def update_conversation_title(
user_id: int, conversation_id: int, title: str
async def update_conversation(
user_id: int,
conversation_id: int,
title: str | None = None,
model: str | None = None,
) -> Conversation | None:
async with async_session() as session:
result = await session.execute(
@@ -116,13 +119,22 @@ async def update_conversation_title(
conv = result.scalars().first()
if conv is None:
return None
conv.title = title
if title is not None:
conv.title = title
if model is not None:
conv.model = model
conv.updated_at = datetime.now(timezone.utc)
await session.commit()
await session.refresh(conv)
return conv
async def update_conversation_title(
user_id: int, conversation_id: int, title: str
) -> Conversation | None:
return await update_conversation(user_id, conversation_id, title=title)
async def add_message(
conversation_id: int,
role: str,