feat(chat): add LibreChat-inspired chat interface with MongoDB persistence

Implement full chat functionality with persistent sessions and messages
stored in MongoDB, LLM completion via Ollama (with multi-provider
dispatch support), markdown rendering, and a model selector.

- Add ChatSession/ChatMessage models with serde attributes for MongoDB
  ObjectId handling (skip_serializing_if empty, alias _id)
- Add CRUD server functions: list/create/rename/delete sessions,
  list/save messages, non-streaming chat completion
- Add raw Document collection accessor for BSON ObjectId -> String
  conversion in read paths
- Add SSE streaming endpoint (Axum handler) for future streaming support
- Add provider dispatch client (Ollama, OpenAI, Anthropic, HuggingFace)
- Add frontend components: ChatSidebar with namespace grouping,
  ChatModelSelector, ChatMessageList, ChatInputBar, ChatBubble with
  pulldown-cmark markdown rendering and StreamingBubble thinking indicator
- Rewrite ChatPage with full signal-based state management
- Add comprehensive CSS for chat UI, markdown prose, animations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sharang Parnerkar
2026-02-20 19:40:31 +01:00
parent 1f9629f111
commit 1a244f8f3d
19 changed files with 2225 additions and 161 deletions

View File

@@ -36,7 +36,7 @@ mongodb = { version = "3.2", default-features = false, features = [
"compat-3-0-0",
], optional = true }
futures = { version = "0.3.31", default-features = false }
reqwest = { version = "0.13", optional = true, features = ["json", "form"] }
reqwest = { version = "0.13", optional = true, features = ["json", "form", "stream"] }
tower-sessions = { version = "0.15", default-features = false, features = [
"axum-core",
"memory-store",
@@ -61,11 +61,14 @@ secrecy = { version = "0.10", default-features = false, optional = true }
serde_json = { version = "1.0.133", default-features = false }
maud = { version = "0.27", default-features = false }
url = { version = "2.5.4", default-features = false, optional = true }
wasm-bindgen = { version = "0.2", optional = true }
web-sys = { version = "0.3", optional = true, features = [
"Clipboard",
"Document",
"Element",
"EventSource",
"HtmlElement",
"MessageEvent",
"Navigator",
"Storage",
"Window",
@@ -81,10 +84,14 @@ dioxus-free-icons = { version = "0.10", features = [
sha2 = { version = "0.10.9", default-features = false, optional = true }
base64 = { version = "0.22.1", default-features = false, optional = true }
scraper = { version = "0.22", default-features = false, optional = true }
pulldown-cmark = { version = "0.12", default-features = false, features = ["html"] }
tokio-stream = { version = "0.1", optional = true, features = ["sync"] }
async-stream = { version = "0.3", optional = true }
bytes = { version = "1", optional = true }
[features]
# default = ["web"]
web = ["dioxus/web", "dep:reqwest", "dep:web-sys"]
web = ["dioxus/web", "dep:reqwest", "dep:web-sys", "dep:wasm-bindgen"]
server = [
"dioxus/server",
"dep:axum",
@@ -100,6 +107,9 @@ server = [
"dep:scraper",
"dep:secrecy",
"dep:petname",
"dep:tokio-stream",
"dep:async-stream",
"dep:bytes",
]
[[bin]]