Files
cv-site/doc/30-CHAT-MODULE-PORTABILITY.md
T
juanatsap 328faae953 feat: chat module portability guide + fix mobile wave position
- doc/30-CHAT-MODULE-PORTABILITY.md: step-by-step guide to port the
  chat agent to other Go apps (files, dependencies, customization)
- Fix wave emoji position on mobile (follows button to bottom:5rem right:1rem)
2026-04-09 13:08:17 +01:00

6.5 KiB

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

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

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

// 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

{{template "chat-widget" .}}
{{template "chat-help-modal" .}}

Conditionally load CSS:

{{if .ChatEnabled}}
<link rel="stylesheet" href="/static/css/_chat.css">
{{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.gobuildIconMap() and CSS
CSS theme _chat.css — colors, --accent-green, fonts
Rate limits routes.go — requests per hour

References