Complete Ollama Web UI implementation featuring: Frontend (SvelteKit + Svelte 5 + Tailwind CSS + Skeleton UI): - Chat interface with streaming responses and markdown rendering - Message tree with branching support (edit creates branches) - Vision model support with image upload/paste - Code syntax highlighting with Shiki - Built-in tools: get_current_time, calculate, fetch_url - Function model middleware (functiongemma) for tool routing - IndexedDB storage with Dexie.js - Context window tracking with token estimation - Knowledge base with embeddings (RAG support) - Keyboard shortcuts and responsive design - Export conversations as Markdown/JSON Backend (Go + Gin + SQLite): - RESTful API for conversations and messages - SQLite persistence with branching message tree - Sync endpoints for IndexedDB ↔ SQLite synchronization - URL proxy endpoint for CORS-bypassed web fetching - Health check endpoint - Docker support with host network mode Infrastructure: - Docker Compose for development and production - Vite proxy configuration for Ollama and backend APIs - Hot reload development setup 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
62 lines
1.9 KiB
Go
62 lines
1.9 KiB
Go
package database
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
)
|
|
|
|
const migrationsSQL = `
|
|
-- Chats table
|
|
CREATE TABLE IF NOT EXISTS chats (
|
|
id TEXT PRIMARY KEY,
|
|
title TEXT NOT NULL DEFAULT 'New Chat',
|
|
model TEXT NOT NULL DEFAULT '',
|
|
pinned INTEGER NOT NULL DEFAULT 0,
|
|
archived INTEGER NOT NULL DEFAULT 0,
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
sync_version INTEGER NOT NULL DEFAULT 1
|
|
);
|
|
|
|
-- Messages table
|
|
CREATE TABLE IF NOT EXISTS messages (
|
|
id TEXT PRIMARY KEY,
|
|
chat_id TEXT NOT NULL,
|
|
parent_id TEXT,
|
|
role TEXT NOT NULL CHECK (role IN ('user', 'assistant', 'system')),
|
|
content TEXT NOT NULL,
|
|
sibling_index INTEGER NOT NULL DEFAULT 0,
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
sync_version INTEGER NOT NULL DEFAULT 1,
|
|
FOREIGN KEY (chat_id) REFERENCES chats(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (parent_id) REFERENCES messages(id) ON DELETE SET NULL
|
|
);
|
|
|
|
-- Attachments table
|
|
CREATE TABLE IF NOT EXISTS attachments (
|
|
id TEXT PRIMARY KEY,
|
|
message_id TEXT NOT NULL,
|
|
mime_type TEXT NOT NULL,
|
|
data BLOB NOT NULL,
|
|
filename TEXT NOT NULL DEFAULT '',
|
|
FOREIGN KEY (message_id) REFERENCES messages(id) ON DELETE CASCADE
|
|
);
|
|
|
|
-- Indexes for better query performance
|
|
CREATE INDEX IF NOT EXISTS idx_messages_chat_id ON messages(chat_id);
|
|
CREATE INDEX IF NOT EXISTS idx_messages_parent_id ON messages(parent_id);
|
|
CREATE INDEX IF NOT EXISTS idx_attachments_message_id ON attachments(message_id);
|
|
CREATE INDEX IF NOT EXISTS idx_chats_updated_at ON chats(updated_at DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_chats_sync_version ON chats(sync_version);
|
|
CREATE INDEX IF NOT EXISTS idx_messages_sync_version ON messages(sync_version);
|
|
`
|
|
|
|
// RunMigrations executes all database migrations
|
|
func RunMigrations(db *sql.DB) error {
|
|
_, err := db.Exec(migrationsSQL)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to run migrations: %w", err)
|
|
}
|
|
return nil
|
|
}
|