# Chat Module Portability Guide **Project:** CV Interactive Website **Last Updated:** 2026-04-09 **Tag Reference:** `v1.2.0` --- ## Overview The AI chat agent is a self-contained module that can be ported to other Go web applications. It provides an embeddable chat widget powered by Google Gemini (production) with Ollama fallback (local development). --- ## Module Files ### Backend (Go) | File | Purpose | Dependencies | |------|---------|-------------| | `internal/chat/agent.go` | ADK agent definition, tools, prompt | `google.golang.org/adk`, your data model | | `internal/chat/handler.go` | HTTP handlers, provider init, warmup, icon injection | `internal/chat/agent.go`, `internal/cache` | | `internal/chat/ollama.go` | Ollama/OpenAI-compatible LLM adapter | None (standalone) | ### Frontend (HTML + CSS + JS) | File | Purpose | |------|---------| | `templates/partials/widgets/chat-widget.html` | Complete widget: panel, header, messages, input, JS | | `templates/partials/modals/chat-help-modal.html` | Help accordion with suggested questions | | `static/css/04-interactive/_chat.css` | All styling: layout modes, responsive, dark mode, animations | ### Configuration | File | Keys | |------|------| | `.env` | `GOOGLE_API_KEY`, `OLLAMA_MODEL`, `OLLAMA_HOST` | | `config/systemd/cv.service` | `EnvironmentFile` for production secrets | --- ## Go Dependencies Add to your `go.mod`: ``` google.golang.org/adk v1.0.0 google.golang.org/genai v1.x.x ``` --- ## Integration Steps ### 1. Copy the backend files ```bash mkdir -p internal/chat cp internal/chat/agent.go internal/chat/handler.go internal/chat/ollama.go YOUR_PROJECT/internal/chat/ ``` ### 2. Adapt `agent.go` This is the only file that needs significant changes per project: - **`NewAgent()`**: Change the `Instruction` prompt to describe YOUR data, not a CV - **`QueryCVArgs` / `QueryCVResult`**: Rename and adapt the tool to query YOUR data source - **`newQueryCVTool()`**: Replace with a tool that queries your application's data - **Filter functions**: Adapt `filterExperience()`, `filterProjects()`, etc. to your data model ### 3. Adapt `handler.go` Minimal changes needed: - **`buildIconMap()`**: Remove or adapt for your icon system (sprite sheets, image files) - **`formatResponse()`**: The markdown→HTML converter works generically. Icon injection is optional. - **`NewHandler(dataCache)`**: Change the parameter type to your data source ### 4. Keep `ollama.go` as-is This is a generic Ollama/OpenAI-compatible adapter. No changes needed — it implements `model.LLM` interface for any ADK agent. ### 5. Copy frontend files ```bash cp templates/partials/widgets/chat-widget.html YOUR_PROJECT/templates/partials/widgets/ cp templates/partials/modals/chat-help-modal.html YOUR_PROJECT/templates/partials/modals/ cp static/css/04-interactive/_chat.css YOUR_PROJECT/static/css/ ``` ### 6. Adapt the widget - Change suggested questions (chips) to match your domain - Change help modal questions - Update welcome message - Adjust CSS variables to match your theme ### 7. Register routes ```go // In your routes setup: chatHandler := chat.NewHandler(yourDataSource) mux.Handle("/api/chat", rateLimiter.Middleware(http.HandlerFunc(chatHandler.HandleChat))) mux.HandleFunc("/api/chat/warmup", chatHandler.HandleWarmup) mux.HandleFunc("/api/chat/status", chatHandler.HandleStatus) ``` ### 8. Include in templates ```html {{template "chat-widget" .}} {{template "chat-help-modal" .}} ``` Conditionally load CSS: ```html {{if .ChatEnabled}} {{end}} ``` --- ## Architecture Overview ``` User clicks chat → HTMX POST /api/chat ↓ handler.HandleChat() ↓ runAgent(primary) ← Gemini or Ollama ↓ ADK Runner loop: 1. LLM sees prompt + user message 2. LLM calls query tool (function calling) 3. Tool queries your data source 4. LLM generates response from tool results ↓ formatResponse() → HTML with icons + links ↓ HTMX appends to #chat-messages ``` --- ## Features Included | Feature | What it does | |---------|-------------| | **Dual provider** | Gemini (prod) + Ollama (dev) with auto-fallback | | **Auto-warmup** | Local model pre-loaded on startup in dev mode | | **Status polling** | `/api/chat/status` → "Initializing AI model..." indicator | | **4 layout modes** | Compact, Side Panel, Floating (draggable), Full Screen | | **Mobile responsive** | Split mode on phones, desktop modes hidden | | **User + bot avatars** | Teams-style bubble layout | | **Inline icons** | Sprite + image fallback next to navigation links | | **External links** | `[text](https://...)` rendered as clickable links | | **Wave greeting** | 👋 animation to attract visitors | | **Help modal** | Accordion with suggested questions | | **Chip questions** | One-click with instant bubble rendering | | **Rate limiting** | 30 req/hour per IP (configurable) | | **Dark mode** | Lighter panel to contrast with dark backgrounds | | **HTMX timeout** | 120s for slow local models | --- ## Testing | Test file | Assertions | Covers | |-----------|-----------|--------| | `tests/mjs/84-chat-layout-modes.test.mjs` | 38 | Desktop layout modes, drag, switching, avatars | | `tests/mjs/85-chat-mobile.test.mjs` | 79 | Mobile on 3 iPhone viewports + desktop sanity | | `tests/mjs/83-chat-mascot.test.mjs` | 39 | Chat UX, chips, responses, navigation | --- ## What to Customize Per Project | Component | What to change | |-----------|---------------| | Agent prompt | `agent.go` — describe YOUR domain, not a CV | | Query tool | `agent.go` — query YOUR data source | | Suggested questions | `chat-widget.html` — chips and help modal | | Welcome message | `chat-widget.html` — greeting text | | Icons/sprites | `handler.go` — `buildIconMap()` and CSS | | CSS theme | `_chat.css` — colors, `--accent-green`, fonts | | Rate limits | `routes.go` — requests per hour | --- ## References - [Google ADK Go Documentation](https://google.github.io/adk-docs/) - [Ollama API](https://github.com/ollama/ollama/blob/main/docs/api.md) - [HTMX Documentation](https://htmx.org/docs/) - [doc/28-AI-CHAT-AGENT.md](./28-AI-CHAT-AGENT.md) — Full technical documentation - [doc/29-AI-CHAT-SHOWCASE.md](./29-AI-CHAT-SHOWCASE.md) — Public showcase writeup