开源、可自托管的全功能 AI 聊天站
服务端统一代理多家上游模型(OpenAI Responses API / chat/completions 与 Anthropic Messages API),实时流式回传浏览器, 内置断线续传、对话分支、思考模型、联网搜索 / X 搜索、图片生成与完整管理后台。
✨ 功能特性 · 🚀 快速开始 · 📸 界面预览 · 🏗️ 技术架构 · 📦 生产部署
浅色 / 深色 / 跟随系统 · 七种可选重点色 · 全界面简体中文 · 桌面与手机全面适配
- 精心设计的 UI:界面美观现代,交互经过反复打磨,浅色 / 深色 / 移动端全面适配;博采 ChatGPT 与 Gemini 官网之长,取其精华、去其糟粕。
- 一切配置都在管理面板里完成:接入上游、同步模型、定价、思考等级、权限、公告……全部在直观易用的后台界面点选即可,实时生效。
- 开箱即用的完整产品:可配置的邀请码注册、多账号、权限、分享、公告、统计、成本核算一应俱全,部署完成即可直接投入使用。
- 部署极简:Node + SQLite,单端口即可跑完整应用。不需要 Docker、PostgreSQL、Redis、独立 worker。
- 对上游极致兼容:同时支持 OpenAI Responses API、chat/completions 与 Anthropic Messages 原生协议;兼容网关和 Anthropic 官方服务都能接入,还能从上游目录一键挑选模型。
- 细节丰富的聊天体验:断线续传、对话分支、提示词缓存优化、统一过程轨、消息时间轴……大量精心打磨的交互细节。
- 实时流式输出:文字逐段渐入,生成中可随时停止,失败一键重新生成
- 后台自动重试:管理员可在「系统设置 → 自动重试」开启(默认关闭),配置次数、递增间隔、随机延迟、超时和可重试错误。遇到临时连接或 HTTP 错误后,聊天显示重试进度与倒计时;离开页面或刷新不影响服务端继续,用户可随时停止。已开始的流式输出不自动重放,服务重启仍会中断未完成任务。
- 后台回复提醒:切到其他会话后,原会话在侧栏显示生成中转圈;回复完成后切换为跟随重点色的未读圆点,并在右上角弹出可直接打开会话的摘要通知
- 断线续传:刷新页面 / 网络中断后自动重连,从上次位置继续接收未完成的生成
- 对话分支:编辑消息不会覆盖原内容,而是在该位置创建子分支,可随时在
‹ 1/2 ›间切换;还能一键把「根消息 → 当前助手消息」整条链路复制为独立新对话 - 上下文优化与附件清单:聊天顶栏可分别控制历史轮数、上传附件与模型生成图,支持按轮整组保留、按个数、全部或不携带;生成图数量可超过初始的 12 张。附件面板展示所有分支的图片和文件,支持搜索、预览、整组或逐项勾选,并实时展示下次携带数量与文件大小。手动调整只用于下一次发送,失败后保留以便重试;新聊天默认值只保存规则,不保存手选附件。管理员可在「系统设置 → 常用设置」配置长对话提醒开关与阈值(默认 100,000 个估算文字 Token,即 100K);达到阈值时在右上角上下文按钮旁提示当前估算量及优化作用,可直接打开面板,不会自动裁剪历史。
- 现代输入体验:桌面端新对话输入框居中 + 重点色光晕,发出首条消息后平滑落底;单行 ⇄ 多行自适应、行扩展动画保证输入文字全程可见;图片 / 文件上传聚合进「+」菜单;顶栏为模糊交叉渐变悬浮层
- 消息时间轴导航(桌面端):聊天右缘小横条随滚动高亮当前位置,悬停展开你发过的消息列表,点击快速跳转;可在设置中关闭
- 聊天文件夹与批量管理:一键新建文件夹归类聊天;文件夹支持自定义颜色(12 色柔和浅色预设 + 自定义取色)与 Emoji 图标(支持中文搜索的表情选择器,数据自托管、不依赖公网 CDN)、可置顶、展开状态记忆;批量模式下多选删除 / 移动;删除文件夹不删聊天
- 完整 Markdown 渲染:Markdown 图片、GFM 表格、GitHub Alerts、LaTeX 公式(KaTeX)、代码高亮 + 一键复制、CJK 友好强调语法(粗体 / 斜体 / 删除线以中日韩标点结尾后可紧跟正文),且仅放行小范围安全 HTML
- 三种上游协议:供应商先决定 OpenAI 兼容或 Anthropic Messages 协议;OpenAI 兼容供应商的模型可选 Responses API / chat/completions,Anthropic 供应商的模型固定走 Messages API。服务端统一翻译成同一事件流,前端零差异。供应商支持额外请求头,统一用于模型目录、聊天、标题和生图请求;可覆盖鉴权或版本头,传输头与非法值会在保存时拦截。
- 上游请求预览:在「模型 → 请求预览」查看当前草稿构建的 URL、请求头、完整 JSON 与参数来源,模拟用户参数、历史和附件,并复制 JSON / cURL。预览复用实际请求构建器;动态内容用占位符表示,不读取真实聊天、不调用上游;管理员可查看完整 URL、鉴权头、额外请求头与正文配置,预览及复制保留实际值。Images 预览仅使用本次图片描述,不携带历史。
- 模型使用提示:管理员可按模型配置标题、正文与三种提示风格,选择确认后不再提示或每次选用时提示,并控制是否允许关闭;编辑时可即时预览,用户选用模型后在输入框上方看到。确认按当前浏览器与账号记忆,文案更新后重新展示。
- 思考模型完整支持(GPT-5.6、Claude Sonnet 5 等):精致的交互界面一键调节推理强度(none / low / medium / high / xhigh / max)+ 实时展示官方推理摘要;Responses API 的
commentary进展、推理与检索动作会按真实顺序汇入同一条过程轨,终答开始时自动折叠;管理员可按模型自由增删、排序思考等级并自定义上游值与中文描述,不受前端枚举限制 - 提供商私有上下文回传(可选):Responses 的
encrypted_content,以及 Anthropic 的 thinking 签名、redacted_thinking、搜索密文与引用索引,都只在服务端按来源严格门控并原样重放——绝不进入浏览器事件、消息 DTO 或分享快照 - 联网搜索 / X 搜索:一键开关 + 引用来源展示;支持 Responses web search 与 Anthropic 原生 web search(含
pause_turn续跑和搜索错误状态);X 搜索(xAIx_search)检索 X(原 Twitter)站内的帖子、讨论串与用户。检索过程与模型思考、进展说明按真实交错顺序展示在同一条过程轨里 - 提示词缓存优化:OpenAI 文本会话使用稳定
prompt_cache_key,Anthropic 使用高级 JSON 中明确可见的cache_control;每轮发送时间以 runtime context 冻结重放;缓存写入 / 读取 Token 分开计量、分别定价、独立展示 - 聚合模型选择器:模型 / 推理强度 / 联网搜索 / X 搜索(图片模型则是分辨率 / 画质)收进一个菜单 —— 推理强度分段选择 + 一键固定默认,分辨率带宽高比缩略图;模型列表直接显示品牌图标与管理员配置且可自定义颜色的标签(如「内测」「禁止滥用」),带描述的模型有 ⓘ 气泡(桌面悬浮 / 移动端点按);桌面端在输入框内弹出,移动端为底部弹层
- 推理强度明确选择:思考模型必须有一个有效档位才能发送、编辑重发或重新生成;没有管理员默认值或已保存档位失效时,会提示先选择,不会以「自动」状态发送。支持的
none(不推理)仍可正常选择。 - 模型分组与两种视图:管理员可新建分组、拖拽排序、批量把模型移入;用户侧可自由切换 平铺视图(分组标题可折叠)与 二级目录视图(先选分组再钻取模型),选择记在账户里;模型多时列表内还有搜索框,未配置分组的站点则与从前完全一致
- 模型 / 分组图标:内置 900+ AI 品牌图标(lobe-icons,随应用自托管,不依赖公网 CDN),也可上传自定义图标或直接用 Emoji;分组还能显式设为无图标,标题像「未分组」一样直接左对齐。内置搜索支持中文品牌名、全拼与英文。未配置时按模型 ID 自动识别品牌图标,管理端还能批量识别并套用;即使识别成功,也可显式改用名称首字母。单色图标经 CSS mask 渲染,浅色 / 深色下均自动适配
- 多模态输入输出:图片输入、文件输入(OpenAI 文件格式;Anthropic 原生图片、PDF 与纯文本 document block)、图片生成(GPT-Image-2,支持分辨率与画质选择)。等待时以矩形点阵中的蓝紫流光展示生成状态与真实耗时,保留上游提供的 partial image 中间预览,新图加载完成后平滑过渡,支持多图进展与放大查看;等待时可展开贪吃蛇,用键盘、方向按钮或触屏滑动操作,切到后台自动暂停。Images API 非流式请求仍在完成后显示最终图片。
- 用户设置中心:主题、重点色、字号、Enter 发送(桌面 / 手机分别配置)、自动滚动、消息时间 / 模型名 / Token(含缓存写入读取)· TPS · 耗时明细开关;管理员还可全局决定是否展示单次预估成本,并选择 USD 或按实时汇率换算的 CNY(仅影响聊天消息用量行,成本为 0 时不显示)
- 可自定义重点色:七种配色(默认 / 蓝 / 绿 / 黄 / 粉 / 橙 / 紫)一键切换,用户消息气泡、发送按钮、输入框光晕等聊天核心 UI 随之统一变色,浅色 / 深色模式下均经过独立调校
- 账号自助管理:头像上传(支持裁切)、改密码、清空对话、删除账号
- 聊天标题自动总结:标题模型与提示词管理员可配,浏览器标签页标题随会话标题逐字动态同步
- 提示词模板变量:
{{current_date}}/{{current_user}}等,涉及时间的变量会智能提示其对缓存命中的影响 - 全简体中文界面:浅色 / 深色 / 跟随系统三主题,登录 / 注册页未登录时也能切换(偏好仅存本地);手机端侧栏抽屉 + 触摸优化,全面可用
- 用户限额:管理员用「策略模板 + 用户单独覆写」控制每个人的用量——例如「默认用户:$10/月」「VIP:$100/月」「朋友:不限额」「测试账号:$2/天」;张三可以继承默认策略但把月上限单独改成 $30,不必逐人维护完整配置
- 多条件与多口径:同一策略内可并存多条规则(如「每月最多 $30 且每天最多 300 次」),任意一条触顶即拦截;计量支持消费金额(USD)或请求次数,范围支持全部模型 / 指定模型 / 模型分组,且可选「每个目标各自独立额度」或「所选目标共享一个额度池」。策略与用户专属规则都是可折叠列表,拖拽调整展示顺序(顺序只影响阅读,不改变判定);用户端「我的额度」与管理端用户用量列表都按这个顺序排列,「各自独立」的多个目标收在同一条规则下
- 优先级与例外放行:每条规则可设优先级(数字越大越优先)。一个模型只受「命中它的最高优先级」那一档规则约束,所以「OpenAI 分组整体 $30/月,但组内 mini 不限额」只要两条规则,不必枚举组内其他模型——以后往组里加新模型也会自动落入分组限额
- 周期与重置:自然日 / 周 / 月自动重置(边界时区与周起始日可配);另有两种按小时窗口——首次请求起算的固定周期(空闲时不计时,到期整段清零)与真实滚动窗口(始终统计过去 N 小时、旧用量逐步释放),也支持永久累计
- 豁免而不是大数字:「不限额」是显式状态而不是一个很大的数字;配合更高的优先级即可把个别模型从大范围规则里放行。豁免不计量也不按周期重置,编辑与展示都不带统计周期
- 按模型精细拦截:某个模型额度耗尽只禁用该模型,选择器里标记「额度已用尽」,其他仍有额度的模型照常可用
- 临时增加额度:给某人本周期临时加 $5($10 → $15),周期结束自动失效,不污染长期配置;也可手动重置当前周期——既能一键重置全部,也能只重置某一个模型/分组的额度(日历 / 滚动 / 永久累计只抬高统计起点;首次请求起算的固定周期会清空锚点,等下次请求后再开始计时。历史用量与后台统计不受影响;修改策略或规则后需先保存再执行周期操作)
- 暂停 / 恢复限额:临时放行某个用户,期间用量照常累计,恢复后立即按累计值重新判定
- 额度预警:输入框上方用轻量提示展示用量、恢复时间与可用操作;管理员可在「用户限额 → 周期与提醒」配置触发阈值,并分别设置接近限额、已达到限额的提示。两类文案默认留空,空值只显示状态、用量与恢复时间。只提示当前模型实际生效的规则,可关闭接近上限的提醒;额度耗尽仍保留拦截状态和使用情况入口。
- 个人使用情况面板(
/usage):今日 / 本周 / 本月 / 本年窗口随 URL 保留,按浏览器 IANA 时区与夏令时统计;四项概览支持查看完整数值,趋势图可切换请求 / Token / 预估花费及数据表,模型用量支持品牌图标、搜索、排序与完整列表。额度按策略顺序单栏展示剩余量、重置时刻与临时额度,单个 / 多个独立计量模型均有目标明细,无限额度也保留模型名,所有规则与目标直接完整展示。近一年活跃日历支持点选、日期选择、方向键与逐日浏览,活跃时段支持触屏与键盘读数。页首可导出趋势、全部模型用量或全年每日活动 CSV;每分钟自动更新,兼顾浅深模式与手机布局。 - 标题总结单独记账:会话标题的后台调用无论成功或失败都进入「请求事件」(能取得上游用量时计入真实成本),但不计入任何用户额度规则,也不会启动“首次请求起算”的固定周期
- 管理端用户总览:用户限额页的用户视图顶部一眼给出受限额人数、需关注、平均占用与近 24 小时 / 7 天 / 30 天对话消费;状态条和策略芯片可点选筛选名单,「用量最多」按可比时间窗排序(无限额度用户也会上榜),「最接近上限」看当前额度周期
- 随时开关:限额总开关关闭后不做任何判定、用户端完全看不到额度信息,而策略配置与用量计数完整保留,重新打开即恢复
- 分享聊天:快照式公开只读链接,可选是否显示名称 / 头像、可设有效期、可手动挑选要分享的消息与附件开关;分享页首个 HTML 直接带会话标题、公开消息摘要与应用图标,微信 / QQ 等应用无需执行 JavaScript 即可生成内容预览;用户在「我的分享」独立页面集中管理;管理员可全局或按用户开关分享能力并查看全部分享
- 导出聊天:六种格式一键导出——chatlog-md 对话日记(遵循 chatlog-md/1 规范,适合长期保存与程序解析)、Markdown、自包含 HTML 网页(附件内联、双主题)、JSON 全量数据(可含完整分支树)、JSONL(OpenAI messages,适合微调数据集)、纯文本;支持消息逐条挑选或快捷选择全部消息 / 全部用户消息 / 全部 AI 回复,思考过程 / 模型名 / 引用来源 / 检索过程 / Token 用量逐项开关,时间精度四档,附件三种模式(打包 ZIP + assets · 仅文件名 · 不包含);JSON 结构化导出以有序
processSteps统一表达思考、进展说明和检索动作(不再输出旧reasoningSummary/searchActions);弹窗内实时预览导出效果;侧栏批量模式可多选一键批量导出 - 站内公告系统:管理员发布 Markdown 公告,四种级别(通知 / 更新 / 提醒 / 重要)× 三种触达渠道(通知中心铃铛 / 顶部横幅 / 强提示弹窗);宽版图文阅读、手机全屏与底部连续浏览,通知中心支持全部 / 未读筛选,编辑时可预览实际阅读效果;支持置顶、全体或精确到具体账号的推送受众(复用模型可用范围面板,含头像、搜索、管理员 / 普通用户分组与批量勾选)、定时发布与自动过期;强弹窗在用户明确确认前持续展示,不允许通过关闭按钮、Esc、背景点击或“全部已读”跳过;管理员可查看「谁已读」名单、一键重置已读再次推送
扁平轻盈的工作台、可折叠分组侧栏与 recharts 可视化,支持浅色 / 深色 / 跟随系统;Ctrl/⌘+K 快速前往页面、模型和用户,手机提供完整导航与适配的列表。从接入上游到模型定价,所有配置均在界面内完成并实时生效,无需编辑任何配置文件。
| 模块 | 能力 |
|---|---|
| 概览 | 请求 / Token / 成本 / 活跃用户与上一时段对比、请求趋势与七类结果分布、平均首字与总耗时、缓存读取率、RPM/TPM、站点规模;每分钟刷新,可从结果直接查看请求明细 |
| 分析 | 供应商 / 模型 / 用户 / 请求类型联动筛选、请求 / Token / 成本趋势切换、Token 构成、模型与供应商排行、用户搜索 / 排序 / 分页,以及当前筛选趋势 CSV 导出;筛选可随 URL 保留 |
| 请求事件 / 错误日志 | 每次已结算上游调用的模型 ID / 外显名称、原始推理强度、总耗时 / 上游首响应 / 首字延迟、生成速度、Token / 缓存 / 成本与终态审计,删除原会话后审计快照仍会保留;模型路由生图与 Images API 生图均显示最终图片数量,聊天清理后保留数量;上游首响应包含请求体上传、网络、排队、自动重试等待与兼容降级重试,不包含发送消息前已完成的附件预上传;可区分并筛选完成、截断、拒绝、内容过滤、失败、取消和中断,悬停或键盘聚焦状态标签可查看原因、内容处理与下一步建议;请求筛选随 URL 保留;错误日志支持暂停刷新、展开与复制详情、查看原始数据 |
| 账号中心 | 用户搜索与状态筛选、直达用户额度配置 + 遗忘密码重置(随机临时密码、旧会话失效、首次登录强制改密)+ 邀请码生成与有效状态筛选 + 会话设备 / IP 搜索(首位注册用户自动成为管理员) |
| 供应商 | OpenAI 兼容 / Anthropic Messages 原生协议接入,额外请求头配置、测试连接、一键同步、从上游目录挑选添加模型 |
| 模型 | 按列比较能力、默认思考、价格与权限;点击名称 / 价格直达编辑,左侧模型目录快捷切换,保留当前分区并保护未保存修改;拖拽排序、一键复制并配置、供应商切换、自定义图标与标签、同 ID 多实例、思考等级、硬参数 JSON、指定可用用户、批量分组 / 识别图标;模型使用提示与实时预览;请求构造预览、参数来源及 JSON / cURL 复制 |
| 模型分组 | 新建 / 重命名 / 删除 / 拖拽排序;搜索并批量加入已有模型,点击模型数直达分组列表;支持默认文件夹、无图标与自定义图标;删除分组仅将模型移回未分组 |
| 用户限额 | 策略模板 CRUD / 复制 / 设为默认 / 拖拽排序;策略内规则可折叠浏览、拖拽调整展示顺序、行内改优先级;用户视图顶部是总览(状态分布、近窗用量排行、最接近上限),点状态 / 策略可筛选名单;用户按需关注 / 最近使用 / 名称排序,额度摘要可按需展开,展开后按同一顺序列出全部规则,「各自独立」的目标收在同一条下,统一展示状态、用量 / 上限、临时额度与明确的周期 / 重置时间;支持批量修改策略、暂停或恢复限额、按桶或整体重置周期、临时赠送额度、逐规则覆写(含优先级)并在保存前预览最终生效结果;预警阈值与接近 / 达到限额时的提示文案 |
| 分享管理 | 全局 / 按用户开关,搜索与状态筛选、一键复制、打开及撤销分享链接 |
| 公告 | 搜索与状态筛选、Markdown 正文预览、发布、精确用户受众、定时、过期、已读名单、重置推送 |
| 系统设置 | 注册邀请码、分享、消息成本开关与币种、标题总结;长对话提醒开关与估算 Token 阈值;自动重试开关、次数、退避与随机延迟、超时及错误范围。限额总开关、周期口径与额度提示文案在「用户限额」页 |
以下截图均会跟随你的 GitHub 主题自动切换浅色 / 深色版本。
登录页 |
思考摘要 + 联网搜索 |
聚合模型选择器 |
后台概览 |
用量分析 |
模型管理 |
本地开发(Windows 亦可直接运行,无需 WSL / Docker):
npm install
cp .env.example .env # 可按需修改端口、数据目录、数据库路径;开发环境 SESSION_SECRET 可留空
npm run dev # 同时启动后端(8787)与前端(5173)打开 http://localhost:5173:
- 注册管理员 —— 首次访问时注册页会提示「首位用户将成为管理员」,无需邀请码。
- 接入上游 —— 进入「管理后台 → 提供商」,先选择 OpenAI 兼容或 Anthropic Messages 原生协议,再填写 Base URL + API Key 并点「测试连接」「同步模型」。OpenAI 兼容地址通常带
/v1;Anthropic 可直接填官方根地址https://api.anthropic.com,也兼容已带/v1的网关地址。 - 配置模型 —— 在「模型」页按需调整能力、默认参数、思考等级(值与中文描述均可自定义);Responses / Anthropic 思考模型还可开启「回传提供商私有上下文」。同步或手动选择 Anthropic Provider 时,默认参数栏会将必填的
max_output_tokens预设为官方 thinking 指南使用的宽裕示例值16000,发送时映射为max_tokens;高级 JSON 则明示 thinking、缓存和 web search 模板,管理员删掉的模板不会被请求层暗中补回。 - 邀请朋友 —— 默认情况下,后续用户需使用「邀请码」页生成的有效邀请码注册;如需开放注册,可在「系统设置」关闭“注册需要邀请码”。
也可分别运行:npm run dev:server / npm run dev:web。
npm run typecheck # 前后端类型检查
npm run lint # ESLint
npm run test # Vitest 单元测试scripts/ 下还有一套基于 Playwright 的端到端冒烟脚本(流式、续传、分支、思考、联网、图片输入、图片生成、Markdown、管理后台、侧栏搜索、文件夹与批量管理、全模型冒烟),先 npm run dev 起站后用 npx tsx scripts/<name>.ts 运行。
| 层 | 选型 |
|---|---|
| 前端 | Vite · React · TypeScript · Tailwind v4 · TanStack Query · Zustand · recharts |
| 后端 | Hono · Node.js(tsx 运行) |
| 数据 | SQLite(WAL)· Drizzle ORM · 本地文件存储 |
| 流式 | SSE 流式输出 + 断线续传(进程内 RunManager + run_events 事件持久化) |
happychat/
├── shared/ # 前后端共享类型与 zod schema —— 一处定义,两端校验
├── server/ # Hono 后端:鉴权、上游代理、SSE、管理 API
├── web/ # React 前端
└── scripts/ # Playwright 端到端冒烟脚本
单仓库(非 monorepo)、单进程、单端口。刻意不依赖 Next.js、独立 worker、PostgreSQL、Redis、Docker,尽量降低部署与运维复杂度。
Tip
虽然当前使用 SQLite,但 Drizzle schema 刻意保持 PostgreSQL 可迁移(JSON 文本、整型时间戳、无 SQLite 专有特性),为未来迁移预留了空间。
npm run build # 构建前端到 dist/web
NODE_ENV=production npm run start生产模式下后端直接静态托管 dist/web(含 SPA 回退),单端口(默认 8787)即可提供完整应用。数据库迁移在启动时自动执行。
Important
生产环境必须设置高强度的 SESSION_SECRET,否则启动会被拒绝。
# 需 Node 20+(推荐 22/24)
git clone https://github.com/happycola233/happychat && cd happychat
npm ci
npm run build
# .env(生产)
cat > .env <<'EOF'
NODE_ENV=production
PORT=8787
DATA_DIR=./data
DATABASE_URL=./data/happychat.db
SESSION_SECRET=<openssl rand -hex 32>
CLIENT_IP_HEADER=
TRUSTED_PROXY_HOPS=1
EOF
npm run start用 systemd 常驻:
# /etc/systemd/system/happychat.service
[Unit]
Description=happychat
After=network.target
[Service]
WorkingDirectory=/opt/happychat
ExecStart=/usr/bin/npm run start
Restart=always
EnvironmentFile=/opt/happychat/.env
[Install]
WantedBy=multi-user.targetWarning
SSE 路由必须关闭缓冲,否则流式输出会被反向代理缓冲,无法逐段到达浏览器。
location /api/ {
proxy_pass http://127.0.0.1:8787;
proxy_http_version 1.1;
proxy_set_header Connection '';
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_buffering off; # 关键:SSE 流式不被缓冲
proxy_cache off;
proxy_read_timeout 3600s;
}
location / {
proxy_pass http://127.0.0.1:8787;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}Host 与 X-Forwarded-Proto 用于生成分享卡片中的绝对规范链接与应用图标地址;X-Forwarded-For 用于记录登录与最近活动 IP。nginx 默认不会自动补充 X-Forwarded-For,两个 location 都不要省略这些请求头设置。
HappyChat 默认设置 TRUSTED_PROXY_HOPS=0,会完全忽略 X-Forwarded-For 并只采用 TCP socket 地址;因此反代后若不按实际拓扑配置,记录到的会是 nginx 的 127.0.0.1。常见拓扑的配置如下:
- 公网 → 单机 nginx → HappyChat:
CLIENT_IP_HEADER=、TRUSTED_PROXY_HOPS=1。 - 公网 → Cloudflare → nginx → HappyChat:使用 XFF 链时设置
CLIENT_IP_HEADER=、TRUSTED_PROXY_HOPS=2;若源站只允许 Cloudflare 访问,且边缘会设置并剥离用户提交的同名头,也可设置CLIENT_IP_HEADER=cf-connecting-ip,此时该专用头优先于 XFF 跳数。
TRUSTED_PROXY_HOPS 必须与真实代理层数一致。设置得大于实际跳数会越过可信代理,选中客户端可伪造的 XFF 前缀。CLIENT_IP_HEADER 也只能指向由可信边缘重写、且用户无法绕过边缘直接提交的请求头。
浏览器缓存策略由应用统一返回,反向代理不要覆盖 Cache-Control:
- HTML(含
/与所有 SPA 回退路由)使用no-cache,每次打开都会确认最新入口; - Vite 生成的
/assets/*内容哈希资源使用一年immutable缓存; - 已被新构建删除的旧哈希资源返回 404,不会错误回退为
index.html。
所有数据都在 data/ 目录:happychat.db(SQLite)+ uploads/(图片 / 文件 / 生成图)。备份时直接复制该目录即可。
上传成功但未随消息发送的附件会保留至少 24 小时;服务启动时及此后每小时自动扫描清理,正常负载下约在上传后 24~25 小时删除数据库记录与磁盘文件。
透明说明几个刻意的架构决策:
- 本地上下文重放:按聊天的保留规则选取当前分支历史,再读取附件并构建请求(OpenAI 路径的
store默认 false,不依赖previous_response_id)。规则只影响请求,不删除历史或原文件;手选其他分支附件只带入文件,不恢复那条分支的文字。Responses 私有 reasoning item 单轮超过 256KB 时放弃保存;Anthropic 原样保存完整 assistant content blocks。只有保留轮次内、Provider / Base URL / 上游模型 id 完全匹配的私有上下文才注入;同一轮的pause_turn续跑由引擎直接处理。 - 进程内续传:续传基于进程内 RunManager +
run_events持久化;进程重启会把未完成的生成标记为「已中断」。这是用「无 worker / 无 Redis」换来的简单性。 - 限额只按 USD 计量,且成本型额度事后判定:用量成本统一以 USD 记账(聊天消息行的 CNY 展示只是按实时汇率换算的显示层),限额判定不引入任何汇率换算。额度用量全部从
usage_logs实时聚合,不维护计数器,因此策略调整立即按新口径生效、与后台统计永不打架;代价是「消费金额」类额度只能在响应结束后才知道真实用量,剩余额度极少时仍会放行一次请求而小幅超支(请求次数类额度会把在途任务计入,不受此影响)。 - 附件内联 base64:跳过 Files API,只有本次选中的附件才读盘并内联发送。不在应用里固化上游的文件大小或请求体容量上限,上游拒绝时显示错误,用户可调整携带内容。仍校验附件归属、可读取性、模型能力和协议支持的内容类型;Anthropic 图片支持 PNG/JPEG/GIF/WEBP,文件支持 PDF 与
text/*。面板中的大小是原文件合计,不是编码后请求体大小。
如果这个项目对你有帮助,点个 ⭐ Star 支持一下吧!
Made with ❤️ · 欢迎 Issue 与 PR