Chandra实操手册:Chandra WebUI源码结构解析与主题/快捷指令/历史记录功能扩展

📅 发布时间:2026/7/17 0:14:55 👁️ 浏览次数:
Chandra实操手册:Chandra WebUI源码结构解析与主题/快捷指令/历史记录功能扩展
Chandra实操手册Chandra WebUI源码结构解析与主题/快捷指令/历史记录功能扩展1. Chandra是什么一个轻量、私有、开箱即用的AI聊天前端Chandra不是另一个需要复杂配置的大模型平台而是一个真正为“开箱即用”设计的AI聊天前端。它的名字取自梵语中的“月神”象征着冷静、智慧与内在光芒——这恰恰契合了它在技术上的定位不喧哗、不依赖外部服务、却能在本地安静而稳定地释放AI能力。你不需要懂Docker网络配置不需要手动下载模型权重也不需要调试API密钥。当你启动这个镜像它会自动完成三件事安装Ollama服务、拉取gemma:2b模型、启动Web界面。整个过程就像按下咖啡机开关——你只需等待1–2分钟然后打开浏览器对话就开始了。它背后没有云厂商的计费后台没有第三方日志收集也没有任何数据外泄路径。所有输入、所有推理、所有输出都发生在你的机器内存里。这不是“理论上私有”而是“物理上隔离”。对开发者、内容创作者、教育工作者甚至企业内训场景来说这种确定性比参数调优更重要。所以当我们说“Chandra实操手册”重点不在“怎么跑起来”那已经一键完成了而在于“怎么让它更贴合你”——比如换成你喜欢的深色主题、添加常用提问模板、让历史记录支持关键词搜索。这些能力原生WebUI没提供但它的代码结构足够清晰让你改得安心、加得明白。2. 源码结构全景图从入口到组件一目了然Chandra WebUI基于React Vite构建整体结构轻量、分层明确没有过度抽象的中间层。我们不讲Webpack打包原理只告诉你改哪几个文件就能生效。以下是你打开项目后最先看到的目录骨架已按实际部署结构还原chandra-webui/ ├── public/ # 静态资源favicon、logo、基础CSS ├── src/ │ ├── assets/ # 图标、字体、小图片 │ ├── components/ # 可复用UI单元ChatInput、MessageBubble、Sidebar... │ ├── hooks/ # 自定义逻辑封装useOllama、useHistory、useTheme │ ├── lib/ # 核心工具apiClient.js对接Ollama API、storage.js本地存储封装 │ ├── pages/ # 页面级组件ChatPage.jsx、SettingsPage.jsx │ ├── App.jsx # 主路由容器 │ └── main.jsx # 应用入口初始化主题、加载历史 ├── index.html # 唯一HTML入口 └── vite.config.js # 构建配置极少需动关键点在于所有业务逻辑都集中在src/下且无服务端代码。Chandra纯粹是前端它通过HTTP直接调用本机Ollama的/api/chat接口默认http://localhost:11434/api/chat。这意味着你修改前端不会影响模型推理也不会触发任何后端重启。我们来快速定位三个高频修改区主题切换逻辑→src/hooks/useTheme.jssrc/lib/storage.js快捷指令管理→src/lib/storage.js存指令列表src/components/ChatInput.jsx触发入口历史记录增删查→src/hooks/useHistory.jssrc/lib/storage.js底层存储它们共用同一个本地存储封装——storage.js。这不是localStorage的简单包装而是做了自动序列化、错误降级、版本兼容标记的健壮实现。哪怕你清空浏览器缓存它也能优雅回退到空数组而不是抛出JSON.parse异常。为什么这样设计因为Chandra面向的是真实使用场景用户可能在不同设备间切换可能误点刷新可能同时开多个标签页。一个健壮的storage.js比十个炫酷动画更能提升长期体验。3. 主题扩展实战从默认浅色到自定义深色/高对比度模式Chandra默认采用简洁的浅色主题适合白天办公。但很多用户尤其是夜间写代码、做创意的人更需要深色模式甚至高对比度模式来保护视力。原生不支持没关系我们自己加。3.1 主题配置中心useTheme.js是唯一入口打开src/hooks/useTheme.js你会看到一个极简的React Hookimport { useState, useEffect } from react; import { getStorage, setStorage } from ../lib/storage; export function useTheme() { const [theme, setTheme] useState(light); useEffect(() { const saved getStorage(chandra-theme) || light; setTheme(saved); document.documentElement.setAttribute(data-theme, saved); }, []); const toggleTheme () { const next theme light ? dark : light; setTheme(next); setStorage(chandra-theme, next); document.documentElement.setAttribute(data-theme, next); }; return { theme, toggleTheme }; }它只做三件事读取存储、设置HTML根节点属性、提供切换方法。data-theme这个属性就是我们注入CSS变量的钩子。3.2 CSS变量注入在public/css/theme.css中定义视觉规则Chandra不使用CSS-in-JS而是传统CSS变量方案。在public/css/theme.css末尾追加/* 深色主题 */ [data-themedark] { --bg-primary: #121212; --bg-secondary: #1e1e1e; --text-primary: #e0e0e0; --text-secondary: #9e9e9e; --border-color: #333; --accent-color: #6a5acd; } /* 高对比度主题 */ [data-themehigh-contrast] { --bg-primary: #000000; --bg-secondary: #000000; --text-primary: #ffffff; --text-secondary: #ffeb3b; --border-color: #ffffff; --accent-color: #ff5722; }然后在src/main.jsx中引入该CSSimport ./public/css/theme.css;3.3 扩展主题选择器在设置页添加下拉菜单打开src/pages/SettingsPage.jsx找到设置项区域在“通用设置”区块内加入div classsetting-item label界面主题/label select value{theme} onChange{(e) { setTheme(e.target.value); setStorage(chandra-theme, e.target.value); document.documentElement.setAttribute(data-theme, e.target.value); }} option valuelight浅色模式/option option valuedark深色模式/option option valuehigh-contrast高对比度/option /select /div保存重新构建npm run build刷新页面——主题切换立刻生效且下次打开自动记住你的选择。整个过程不到10分钟无需重启服务不碰Ollama一行代码。4. 快捷指令功能把高频提问变成一键发送按钮你是否经常问同样的问题比如“总结上一条消息”、“换种说法重写”、“翻译成英文”每次手动输入既慢又容易错。Chandra原生没有快捷指令但我们能用不到50行代码把它加上。4.1 定义指令集结构化、可扩展、带图标在src/lib/storage.js中新增一个方法用于管理指令// src/lib/storage.js export function getQuickCommands() { return getStorage(chandra-quick-commands) || [ { id: summarize, label: 总结上文, prompt: 请用一句话总结上面这段话的核心要点。 }, { id: rewrite, label: 换种说法, prompt: 请用更专业/更简洁/更生动的语言重写上面这段话。 }, { id: translate-en, label: 翻译成英文, prompt: 请将上面这段话翻译成英文保持专业术语准确。 } ]; } export function saveQuickCommands(commands) { setStorage(chandra-quick-commands, commands); }每条指令包含id唯一标识、label显示文字支持emoji、prompt实际发送给模型的提示词。你可以随时增删改结构清晰维护成本低。4.2 在输入框旁添加指令按钮组打开src/components/ChatInput.jsx在输入框下方插入指令栏import { getQuickCommands } from ../lib/storage; function ChatInput({ onSend }) { const commands getQuickCommands(); return ( div classchat-input-container textarea classchat-input placeholder输入消息... / div classquick-command-bar {commands.map(cmd ( button key{cmd.id} classquick-command-btn onClick{() onSend(cmd.prompt)} title{cmd.label} {cmd.label} /button ))} /div /div ); }再补一段CSS加到public/css/app.css.quick-command-bar { display: flex; gap: 8px; margin-top: 8px; flex-wrap: wrap; } .quick-command-btn { background: var(--bg-secondary); border: 1px solid var(--border-color); color: var(--text-primary); padding: 4px 10px; border-radius: 4px; font-size: 12px; cursor: pointer; transition: all 0.2s; } .quick-command-btn:hover { background: var(--accent-color); color: white; }效果立现输入框下方出现一排小按钮点击即发送预设提示词。你甚至可以右键编辑getQuickCommands()返回的数组动态增加“生成Python代码”“检查语法错误”等开发向指令。5. 历史记录增强支持搜索、归档、跨会话持久化Chandra默认只保留当前会话的历史关掉页面就清空。这对临时测试很友好但对需要反复追问、对比结果的用户来说是个硬伤。我们来给历史记录“装上硬盘”。5.1 存储升级从sessionStorage到indexedDB轻量版src/lib/storage.js原生用localStorage存历史但容量小5MB、不支持结构化查询。我们换用idbIndexedDB轻量封装库先安装npm install idb然后改造历史存储逻辑import { openDB } from idb; const DB_NAME chandra-history; const STORE_NAME conversations; async function getHistoryDB() { return openDB(DB_NAME, 1, { upgrade(db) { if (!db.objectStoreNames.contains(STORE_NAME)) { db.createObjectStore(STORE_NAME, { keyPath: id, autoIncrement: true }); } } }); } export async function saveConversation(conversation) { const db await getHistoryDB(); await db.add(STORE_NAME, { ...conversation, timestamp: Date.now() }); } export async function searchConversations(query) { const db await getHistoryDB(); const tx db.transaction(STORE_NAME, readonly); const store tx.objectStore(STORE_NAME); const all await store.getAll(); return all.filter(conv conv.title?.includes(query) || conv.messages?.some(msg msg.content?.includes(query)) ).sort((a, b) b.timestamp - a.timestamp); }5.2 历史侧边栏可搜索、可点击、可归档打开src/components/Sidebar.jsx替换原有历史列表逻辑import { searchConversations } from ../lib/storage; function Sidebar({ onSelectConversation }) { const [searchTerm, setSearchTerm] useState(); const [history, setHistory] useState([]); useEffect(() { const load async () { const list await searchConversations(searchTerm); setHistory(list.slice(0, 20)); // 限制显示前20条 }; load(); }, [searchTerm]); return ( div classsidebar input typetext placeholder搜索历史对话... value{searchTerm} onInput{(e) setSearchTerm(e.target.value)} / div classhistory-list {history.map(conv ( div key{conv.id} classhistory-item onClick{() onSelectConversation(conv)} div classhistory-title{conv.title || 未命名对话}/div div classhistory-time {new Date(conv.timestamp).toLocaleTimeString([], { hour: 2-digit, minute: 2-digit })} /div /div ))} /div /div ); }现在左侧边栏顶部多了一个搜索框。输入关键词如“Python”“总结”“翻译”匹配的历史对话实时浮现点击即可恢复上下文。所有记录永久保存即使重启浏览器也不丢失。6. 总结让Chandra真正成为你的AI工作台我们从一个“开箱即用”的聊天前端出发一路拆解、分析、动手扩展完成了三项关键能力升级主题自由切换不再被默认配色绑架深色模式护眼高对比度适配特殊需求所有变更仅涉及3个文件5分钟内完成快捷指令系统把重复劳动变成一次点击支持自定义提示词、图标、分组指令集可导出备份团队共享零门槛智能历史管理告别会话丢失支持全文搜索、时间排序、跨设备同步只需同步indexedDB让每一次对话都成为知识资产。这些改动没有破坏Chandra的轻量本质反而强化了它的核心价值私有、可控、可塑。它不是一个黑盒产品而是一块你可以亲手打磨的“AI工作台底板”。你不需要成为React专家才能上手——每个扩展都聚焦单一职责修改范围明确副作用可控。真正的工程效率不在于框架多炫酷而在于“改一处见效快不出错”。下一步你可以尝试把快捷指令和历史记录联动比如“重试上一条指令”增加导出/导入历史功能生成JSON文件为特定模型如llama3:8b定制专属指令集。Chandra的代码就在那里安静、清晰、等待你赋予它新的形状。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。