1082 lines
90 KiB
Markdown
1082 lines
90 KiB
Markdown
# Dev Changelog — Full
|
||
|
||
完整的开发改动记录,按时间倒序排列。作为主动 RAG 的数据源,用户手动唤醒时读取。
|
||
|
||
## 记录
|
||
|
||
### [CL-20260416-1600] 2026-04-16 16:00 — 视觉风格从暗绿底全面转为白底青绿(绢本山水)
|
||
- **tags**: 前端, 视觉风格, 色彩体系, CSS变量, 白底, 千里江山图
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/app/globals.css
|
||
- art-agent/frontend/src/app/page.tsx
|
||
- art-agent/frontend/src/app/login/page.tsx
|
||
- art-agent/frontend/src/app/gallery/page.tsx
|
||
- art-agent/frontend/src/components/chat/chat-messages.tsx
|
||
- art-agent/frontend/src/components/chat/chat-input.tsx
|
||
- art-agent/frontend/src/components/layout/top-nav.tsx
|
||
- art-agent/frontend/src/components/sidebar/sidebar.tsx
|
||
- art-agent/frontend/src/components/sidebar/session-list.tsx
|
||
- art-agent/frontend/src/components/profile-modal.tsx
|
||
- art-agent/frontend/src/components/detail/image-detail-panel.tsx
|
||
- art-agent/frontend/src/components/ui/ambient-particles.tsx
|
||
- docs/art-agent/VISUAL-STYLE-GUIDE.md
|
||
- **what**: 整个应用从暗色(墨绿黑 #0C1210)底色改为白色(绢本白 #FAFAF7)底色,文字改为墨黑(#1A1A1A),框体和光效保留千里江山图的蓝绿配色但色值加深适配白底
|
||
- **why**: 用户反馈当前风格"太偏绿了"。评估后认同——原版将背景、面板、文字全都带绿调,导致全屏绿色信息过载。千里江山图本身是青绿设色于白色绢本之上,白底才更贴近原画精髓
|
||
- **decisions**:
|
||
- 背景 #0C1210 → #FAFAF7(绢本微暖白),面板从绿底毛玻璃改为白色毛玻璃
|
||
- accent #4DB8A4 → #2E8B7A(加深以确保白底上对比度)
|
||
- 文字 #E0E8E2 → #1A1A1A(墨黑),次级文字 #7A9485 → #6B7B8A(灰蓝去绿调)
|
||
- 所有 rgba(77,184,164,...) 硬编码统一替换为 rgba(46,139,122,...)
|
||
- 云雾背景透明度大幅降低(白底上需要更淡才不会突兀)
|
||
- Logo 内部颜色从 #0C1210 改为 white(石青底白字)
|
||
- 保留所有动效系统(云烟缭绕、萤火粒子、水波纹等),仅调整颜色参数
|
||
- **notes**:
|
||
- surface-1/2/3 从深色半透明改为白色半透明,阴影也从重阴影改为轻阴影
|
||
- 网格底纹 opacity 从 0.03 降为 0.018
|
||
- VISUAL-STYLE-GUIDE.md 文档同步重写
|
||
- **source_chat**: [白底青绿视觉风格改造]
|
||
|
||
### [CL-20260416-1500] 2026-04-16 15:00 — UX风格指南实现度补全:接入涟漪/sendBounce/会话切换动画/Error飘散/全屏云雾加载/流式opacity阶梯等10项
|
||
- **tags**: 前端, UX补全, 动效, framer-motion, 微交互, 排版使用, 实现状态文档
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/components/chat/chat-input.tsx
|
||
- art-agent/frontend/src/components/chat/chat-messages.tsx
|
||
- art-agent/frontend/src/components/chat/image-grid.tsx
|
||
- art-agent/frontend/src/components/ui/motion-presets.ts
|
||
- art-agent/frontend/src/app/page.tsx
|
||
- art-agent/frontend/src/app/login/page.tsx
|
||
- art-agent/frontend/src/app/gallery/page.tsx
|
||
- art-agent/frontend/src/app/globals.css
|
||
- art-agent/frontend/src/lib/app-context.tsx
|
||
- art-agent/frontend/src/components/sidebar/sidebar.tsx
|
||
- art-agent/frontend/src/components/profile-modal.tsx
|
||
- docs/art-agent/UX-STYLE-GUIDE.md
|
||
- **what**: 补全 UX-STYLE-GUIDE.md 中描述但未实现的 10 项特性,并在文档中标注每项实现状态
|
||
- **why**: 分析发现风格指南完成度约 65-70%,多项微交互只写了文档描述或代码定义了但未接入业务
|
||
- **decisions**: 对每项未实现特性逐一补全代码,同时更新文档加入 ✅/🔶/⬜ 状态标记
|
||
- **notes**: 补全项包括:(1) ripple-effect.tsx 接入发送按钮 (2) sendBounce 替代 buttonTap (3) 会话切换 sessionSlide 滑入滑出 (4) Error errorFloat 飘散消失+4s自动清除 (5) 回到底部按钮水滴形 (6) 全屏加载改云雾凝聚 mist-loader (7) AI回复 StreamingLines 逐行 opacity 阶梯 (8) typo-h1/h2/strong 实际使用到组件 (9) 用户消息 .user-bubble 左上切角 (10) 图片占位 .stone-placeholder 石青渐变呼吸脉冲。文档每个 section 加入实现文件路径和状态标记。
|
||
|
||
### [CL-20260416-1330] 2026-04-16 13:30 — 交互体验全面升级:信息层级 + 科技质感 + 微交互趣味性
|
||
- **tags**: 前端, UX升级, 动效, framer-motion, 排版体系, 微交互, 视觉层级, 科技感, 粒子, 流光
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/app/globals.css
|
||
- art-agent/frontend/src/app/page.tsx
|
||
- art-agent/frontend/src/app/login/page.tsx
|
||
- art-agent/frontend/src/app/gallery/page.tsx
|
||
- art-agent/frontend/src/components/chat/chat-messages.tsx
|
||
- art-agent/frontend/src/components/chat/chat-input.tsx
|
||
- art-agent/frontend/src/components/chat/image-grid.tsx
|
||
- art-agent/frontend/src/components/chat/model-selector.tsx
|
||
- art-agent/frontend/src/components/sidebar/sidebar.tsx
|
||
- art-agent/frontend/src/components/sidebar/session-list.tsx
|
||
- art-agent/frontend/src/components/layout/top-nav.tsx
|
||
- art-agent/frontend/src/components/detail/image-detail-panel.tsx
|
||
- art-agent/frontend/src/components/profile-modal.tsx
|
||
- art-agent/frontend/src/components/ui/motion-presets.ts (新建)
|
||
- art-agent/frontend/src/components/ui/ambient-particles.tsx (新建)
|
||
- art-agent/frontend/src/components/ui/data-stream.tsx (新建)
|
||
- art-agent/frontend/src/components/ui/ripple-effect.tsx (新建)
|
||
- art-agent/frontend/src/components/ui/firefly-burst.tsx (新建)
|
||
- docs/art-agent/UX-STYLE-GUIDE.md (新建)
|
||
- **what**: 四阶段全面升级交互体验:信息层级体系、科技质感注入、微交互趣味性、统一状态反馈
|
||
- **why**: 用户要求信息层级差异更突出、画面更高级典雅且具科技感、交互有巧思让使用心情愉悦
|
||
- **decisions**:
|
||
- 新增 framer-motion 作为动画引擎(~30KB gzipped),不引入其他 UI 库
|
||
- 排版从 5 级扩展到 7 级(Display 渐变文字 / H1 底部石青线 / H2 左侧竖线 / Body Strong 石青色 / Caption / Micro 大写加宽字间距),CSS 工具类 `.typo-*`
|
||
- Surface 层级从 1 级扩展到 4 级(Surface-0 背景 → Surface-3 弹窗),每级递增 backdrop-blur、border 亮度、box-shadow
|
||
- 背景网格底纹(radial-gradient 点阵 opacity 0.03)从 body::before 实现,原云雾改为独立 DOM 元素 `.fog-layer-far/near`
|
||
- 环境粒子纯 CSS 实现(15-28 个随机漂浮+闪烁的石青色小光点),空态时增多营造"未探索深山"感
|
||
- 数据流光(石青色 linear-gradient 横向流动 2px),AI 活动时出现在输入栏上方,生图时加速
|
||
- 用户消息改为右对齐渐变背景+右上切角,助手消息改为 surface-2 + 左侧 2px 石青竖线
|
||
- 消息入场动画:用户消息 translateY+scale spring,助手消息 blur 消散(云雾凝聚)
|
||
- 发送按钮 whileTap scale 0.85,可发送时呼吸脉冲发光
|
||
- 输入框水面感应:焦点时底部 scaleX 扩展线 + box-shadow 随输入长度增强
|
||
- 收藏星标改为赭金色,点击时 5-7 个金色粒子向四周飘散(萤火点亮)
|
||
- 图片水墨晕染:skeleton shimmer 占位 → clip-path circle 从中心扩展揭示
|
||
- Loading 从 bounce 圆点改为水波纹 scaleY 动画,skeleton 用 shimmer 横向扫描
|
||
- 错误状态赭石红 + translateX 震动 2px × 4 次
|
||
- 空态使用 Display 级渐变文字 + stagger 入场动画
|
||
- 滚到底部按钮改圆形 + spring 弹入/退出
|
||
- 侧栏会话项 hover 时左侧 2px 竖线 slide-in
|
||
- 所有按钮 hover 添加 translateY(-1px) + shadow 加深浮起效果
|
||
- 所有弹出层改用 surface-3(强模糊+明显阴影+更亮边框)
|
||
- 统一动画参数:motion-presets.ts 定义 spring/springGentle、fadeIn/slideUp/mistReveal、messageEnter/assistantEnter、buttonTap/sendBounce、ripple/sparkle/inkReveal、staggerContainer/staggerItem
|
||
- **notes**:
|
||
- framer-motion 通过 npm install 添加(3 个包),前端 bundle 增加约 30KB gzipped
|
||
- 环境粒子使用 CSS animation 而非 Canvas,不影响性能
|
||
- 所有动画使用 transform/opacity/filter,避免触发 layout
|
||
- body::before 原来用于云雾现改为点阵网格,云雾改为 AmbientParticles 组件内的 DOM 元素
|
||
- 构建验证通过(next build 无错误),First Load JS 增量约 50KB(framer-motion)
|
||
- **source_chat**: [交互体验全面升级](6b0e5860-9c5a-4b44-aa96-affba21e9472)
|
||
|
||
### [CL-20260416-1000] 2026-04-16 10:00 — 集成 Zero123++ 视角变换工具(单图→6视角)
|
||
- **tags**: 视角变换, Zero123++, Novel View Synthesis, 新工具, Replicate, 图片处理
|
||
- **affected_files**:
|
||
- art-agent/backend/app/config.py
|
||
- art-agent/backend/app/agent/tools.py
|
||
- art-agent/backend/app/agent/loop.py
|
||
- art-agent/backend/app/services/view_transform.py
|
||
- **what**: 新增 `transform_view` 工具,集成 Zero123++ 模型实现单图生成 6 个固定视角图片
|
||
- **why**: 用户需要将手绘建筑从侧面视角转为其他角度,视角变换是与生图完全不同的能力,需要独立工具
|
||
- **decisions**:
|
||
- 视角变换作为独立工具 `transform_view` 而非 `generate_image` 的扩展——输入不需要 prompt,只需一张图
|
||
- 新增独立服务模块 `view_transform.py`,与 `image_gen.py` 分离——逻辑完全不同(无 prompt、grid 拆分)
|
||
- 在 `config.py` 中新增 `VIEW_TRANSFORM_MODELS` 独立注册表——与 `IMAGE_MODELS` 分离,未来可扩展更多视角变换模型
|
||
- Zero123++ 输出为 3x2 grid 拼接图,用 Pillow 拆分为 6 张独立图片返回
|
||
- 进阶方案(3D 重建 + ControlNet 风格还原 pipeline)记录到延期方案 `[advanced-view-transform]`
|
||
- **notes**:
|
||
- Zero123++ 视角固定(Azimuth: 30/90/150/210/270/330°, Elevation: 30/-20 交替),不支持自定义角度
|
||
- 手绘风格保持度可能不理想(模型偏向写实/3D 风格),需实际测试验证
|
||
- 输入图片需为正方形,建议 >= 320x320
|
||
- Replicate 上的模型 ID: `jd7h/zero123plusplus:c69c6559...`,~$0.074/次,~76s
|
||
- loop.py 中对 `transform_view` 做了特殊结果处理(返回带视角信息的图片列表)
|
||
|
||
### [CL-20260416-0930] 2026-04-16 09:30 — 设备绑定配置与 Skill/Hooks 解耦(local-env.json)
|
||
- **tags**: 基础设施, local-env, 跨设备, hooks, project-launcher, Skill
|
||
- **affected_files**:
|
||
- .cursor/local-env.json
|
||
- .cursor/local-env.example.json
|
||
- .cursor/hooks.json
|
||
- .cursor/hooks/run-hook.ps1
|
||
- .cursor/hooks/session-init.sh
|
||
- .cursor/hooks/check-changelog.sh
|
||
- .cursor/hooks/README.md
|
||
- .cursor/rules/project/local-env-check.mdc
|
||
- .cursor/skills/project-launcher/SKILL.md
|
||
- .gitignore
|
||
- art-agent/ENVIRONMENT.md
|
||
- **what**: 将设备绑定的配置(Node.js 路径、shell 类型)从 Skill 和 hooks 中解耦到 `.cursor/local-env.json`(gitignored)。project-launcher Skill 改为从 local-env.json 读取路径;hooks 增加 run-hook.ps1 dispatcher + bash 版脚本支持跨平台;新增 local-env-check Rule 自动探测生成;ENVIRONMENT.md 去除平台硬编码改为通用说明
|
||
- **why**: Node.js 路径和 shell 类型在不同设备上不同,硬编码在 Skill/hooks 中导致换机或跨平台时需要修改 git tracked 文件
|
||
- **decisions**: 采用 `.cursor/local-env.json`(gitignored)+ `.cursor/local-env.example.json`(tracked 模板)的模式,类似 `.env` / `.env.example` 的惯例;hooks.json 的跨平台靠为每个 hook 提供 .ps1 和 .sh 双版本
|
||
- **notes**: hooks.json 的 command 字段本身仍需按平台手动调整(Windows 用 powershell,macOS/Linux 用 bash),这是 Cursor hooks 机制的限制
|
||
- **source_chat**: [local-env 设备配置解耦]
|
||
|
||
### [CL-20260416-0900] 2026-04-16 09:00 — 环境依赖全面修复 + 统一环境文档
|
||
- **tags**: 环境, 依赖, Node.js, Python, venv, npm, requirements, ENVIRONMENT
|
||
- **affected_files**:
|
||
- art-agent/backend/requirements.txt
|
||
- art-agent/backend/requirements-lock.txt
|
||
- art-agent/ENVIRONMENT.md
|
||
- .cursor/skills/project-launcher/SKILL.md
|
||
- **what**: 排查并修复缺失的前后端依赖(venv 和 node_modules 均不存在),安装 Node.js v22.15.0 到 %LOCALAPPDATA%\nodejs\,创建 Python venv 并安装全部后端依赖,npm install 前端依赖;requirements.txt 从范围版本更新为精确锁定版本;新增 requirements-lock.txt(完整依赖树 61 个包)和 ENVIRONMENT.md 统一环境文档
|
||
- **why**: venv 和 node_modules 被 gitignore,换机/重装后需要重新搭建;原 Node.js 安装已丢失;requirements.txt 仅用 >= 范围无版本锁定
|
||
- **decisions**: Node.js 采用 zip 解压到 %LOCALAPPDATA% 而非 MSI 安装(无管理员权限);requirements.txt 直接锁定到当前精确版本而非继续用范围约束
|
||
- **notes**: project-launcher Skill 中的 Node.js 路径已同步更新为 %LOCALAPPDATA%\nodejs\
|
||
- **source_chat**: [环境依赖修复与文档生成]
|
||
|
||
### [CL-20260416-0830] 2026-04-16 08:30 — 生图按模型预处理 prompt(官网/社区策略对齐)
|
||
- **tags**: 后端, 生图, prompt, SDXL, Flux, GPT Image, Gemini, Replicate, IP-Adapter, image_gen, Agent
|
||
- **affected_files**:
|
||
- art-agent/backend/app/services/image_prompt_strategy.py
|
||
- art-agent/backend/app/services/image_gen.py
|
||
- art-agent/backend/app/agent/tools.py
|
||
- **what**: 为当前注册的全部 7 个生图模型增加「进入 provider 前」的 prompt 预处理层;SDXL 向 Replicate 传入独立 `negative_prompt` 字段(与 stability-ai/sdxl API 一致)
|
||
- **why**: 各后端对 prompt 的惯例不同(如 SDXL 双通道、FLUX 无 negative、IP-Adapter 重参考图语义),原先同一字符串直传难以发挥模型能力
|
||
- **decisions**:
|
||
- 新模块 `image_prompt_strategy`:策略按 `IMAGE_MODELS` 的 `id` 分发,docstring 注明依据(OpenAI Image 指南、BFL FLUX 文档、Replicate API 字段、Stability 系默认负向词)
|
||
- SDXL:未拆分时使用模块内 `DEFAULT_SDXL_NEGATIVE`;可选 `default_params.negative_prompt` 覆盖;支持正文内 `---NEGATIVE---` 或 `|||NEG|||`
|
||
- Flux:剥除误粘贴的 `negative prompt:` 等段,符合 BFL「用正向描述替代负向」的指引
|
||
- `GenerateResult` 携带 `effective_prompt`/`negative_prompt` 供调试与工具回传
|
||
- **notes**: 未引入二次 LLM 调用;复杂措辞重排仍依赖对话模型在工具参数里写好英文描述
|
||
|
||
### [CL-20260416-0810] 2026-04-16 08:10 — 对话栏支持剪贴板粘贴图片为参考图
|
||
- **tags**: 前端, ChatInput, 剪贴板, paste, 参考图, UX
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/components/chat/chat-input.tsx
|
||
- **what**: 在输入区通过 Ctrl+V 或右键粘贴时,若剪贴板含图片文件则自动上传为参考图(与拖拽/点选上传同一路径)
|
||
- **why**: 截图或复制图片后直接粘贴比保存再选文件更快
|
||
- **decisions**: 使用根容器 `onPasteCapture` 在文本插入前拦截;仅当 `clipboardData.items` 中存在 `kind==="file"` 且 `type` 以 `image/` 开头时才 `preventDefault`,避免影响纯文本粘贴
|
||
- **notes**: 依赖浏览器将剪贴板图片暴露为 file item;多图时逐项上传
|
||
|
||
### [CL-20260416-0745] 2026-04-16 07:45 — Gemini 原生生图:延长超时 + 断连类错误自动重试
|
||
- **tags**: 后端, Gemini, httpx, 超时, 重试, RemoteProtocolError, 向量引擎, 稳定性
|
||
- **affected_files**:
|
||
- art-agent/backend/app/services/image_gen.py
|
||
- art-agent/backend/.env.example
|
||
- **what**: 缓解 Gemini 3.1 Flash Image 调用时出现 `Server disconnected without sending a response` 的失败率
|
||
- **why**: 多参考图时请求体大、生图耗时长,上游或本地代理可能在响应返回前关闭连接,httpx 抛出 `RemoteProtocolError`;原先 read 仅 180s 且单次失败即返回
|
||
- **decisions**: 默认 read=600s、write=180s、connect/pool=60s;对 `RemoteProtocolError`、`ConnectError`、`Read/Write/Connect/PoolTimeout` 最多重试 3 次、间隔 1s/2s;可通过 `VECTORENGINE_GEMINI_READ_TIMEOUT` 等环境变量覆盖;`.env.example` 增加注释说明
|
||
- **notes**: 若仍频繁断连,需排查代理 idle 超时或向量引擎侧限流;用户可暂时换 GPT Image 1.5 对比
|
||
- **source_chat**: [Gemini断连重试](eb8bd100-5a4b-439f-bdc9-077311a456ad)
|
||
|
||
### [CL-20260416-0720] 2026-04-16 07:20 — 修复拖拽参考图到 ChatInput 区域后覆盖层卡住不消失
|
||
- **tags**: bug修复, 拖拽, 覆盖层, ChatInput, stopPropagation, UX, 事件冒泡
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/components/chat/chat-input.tsx
|
||
- art-agent/frontend/src/app/page.tsx
|
||
- **what**: 修复拖拽图片到 ChatInput 区域松开后,全屏拖拽覆盖层("松开以添加参考图")不消失的 bug
|
||
- **why**: CL-20260416-0620 为防止重复上传在 ChatInput.handleDrop 中加了 stopPropagation,但这也阻止了事件冒泡到 page.tsx 的 main.onDrop,后者负责清除 mainDragging 状态和 dragCounter。覆盖层有 pointer-events-none,不直接接收事件,但它的显示由 mainDragging 控制
|
||
- **decisions**: 新增 onFileDrop 回调 prop 让 ChatInput 在 handleDrop 中通知父组件,而非移除 stopPropagation(移除会导致 CL-20260416-0620 修复的重复上传问题复发)
|
||
- **notes**: 这是 stopPropagation 的典型副作用 — 解决了一个冒泡问题的同时切断了另一个需要冒泡的事件链。onFileDrop 回调模式是解决此类问题的标准方式
|
||
- **source_chat**: [拖拽覆盖层卡住修复](eb8bd100-5a4b-439f-bdc9-077311a456ad)
|
||
|
||
### [CL-20260416-0700] 2026-04-16 07:00 — 新增 GeminiNativeImageProvider:Gemini 原生 generateContent 接口对接
|
||
- **tags**: 后端, Gemini, Provider, 原生API, generateContent, 多图参考, 架构, 向量引擎
|
||
- **affected_files**:
|
||
- art-agent/backend/app/services/image_gen.py
|
||
- art-agent/backend/app/config.py
|
||
- **what**: 新增 `GeminiNativeImageProvider` 类,对接 Gemini 原生 `generateContent` 接口,使 Gemini 3.1 Flash Image 恢复多图参考能力
|
||
- **why**: 向量引擎对 Gemini 不支持 OpenAI 兼容的 `images/edit` 端点(CL-20260416-0620 回退了此方案)。Gemini 原生 API 通过 `generateContent` + `inline_data` 支持文字+图片混合输入,这是唯一可行的路径
|
||
- **decisions**:
|
||
- 选择直接 HTTP 调用向量引擎中转的 `/v1beta/models/{model}:generateContent` 端点,而非引入 `google-genai` SDK 新依赖——避免依赖膨胀且向量引擎已提供中转
|
||
- 新增 `_resolve_image_base64` 公共工具函数统一 data URI / 本地路径到 (mime, base64) 的解析,Gemini inline_data 和未来其他 provider 都可复用
|
||
- Gemini 响应中同时处理 `inlineData`(camelCase)和 `inline_data`(snake_case)两种字段名,因为向量引擎中转可能改变命名风格
|
||
- **notes**:
|
||
- Provider 注册表现有三个:`replicate`、`openai`、`gemini_native`,分发逻辑无需改动
|
||
- `generate_images` 中 Replicate 独有的"无参考图报错"逻辑已有 `provider_name == "replicate"` 限定,Gemini 无参考图时正常走纯文生图
|
||
- API key 复用 `VECTORENGINE_API_KEY`,base_url 从 `VECTORENGINE_BASE_URL` 推导(去掉 `/v1` 后拼 `/v1beta/...`)
|
||
- **source_chat**: [Gemini原生Provider实现](eb8bd100-5a4b-439f-bdc9-077311a456ad)
|
||
|
||
### [CL-20260416-0620] 2026-04-16 06:20 — 修复拖拽上传重复 + Gemini 改回不支持参考图 + images.edit 参数修正
|
||
- **tags**: bug修复, 拖拽, 事件冒泡, Gemini, 向量引擎, images.edit, config, stopPropagation
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/components/chat/chat-input.tsx
|
||
- art-agent/backend/app/config.py
|
||
- art-agent/backend/app/services/image_gen.py
|
||
- **what**: 三个问题修复:拖拽上传重复、Gemini 500 错误、images.edit quality 参数不支持
|
||
- **why**: 用户测试多图上传时发现拖 1 张图显示 2 张;Gemini 使用参考图时 500 报错
|
||
- **decisions**:
|
||
- 拖拽重复:ChatInput 的 handleDrop/handleDragOver 加 e.stopPropagation(),阻止事件冒泡到 page.tsx 的 onDrop
|
||
- Gemini 500:向量引擎的 Gemini 图片编辑走原生 `/v1beta/models/xxx:generateContent` 端点,不支持 OpenAI 兼容的 `/v1/images/edits`。Gemini 改回 supports_ref_image=False,有参考图时走纯文生图
|
||
- images.edit 的 quality 参数:OpenAI SDK images.edit 不接受 quality 参数(那是 images.generate 的),移除避免报错
|
||
- **notes**:
|
||
- Gemini 图片编辑需要对接原生 generateContent 接口才能支持参考图,作为未来方向
|
||
- GPT Image 1.5 通过向量引擎 /v1/images/edits 走通的前提是向量引擎正确转发 multipart/form-data
|
||
|
||
### [CL-20260416-0600] 2026-04-16 06:00 — 多张参考图全链路支持
|
||
- **tags**: 前端, 后端, 参考图, 多图, OpenAI, images.edit, Provider, API, Agent Loop, UX
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/components/chat/chat-input.tsx
|
||
- art-agent/frontend/src/app/page.tsx
|
||
- art-agent/frontend/src/components/chat/chat-messages.tsx
|
||
- art-agent/frontend/src/lib/api.ts
|
||
- art-agent/frontend/src/lib/types.ts
|
||
- art-agent/backend/app/api/chat.py
|
||
- art-agent/backend/app/agent/loop.py
|
||
- art-agent/backend/app/agent/tools.py
|
||
- art-agent/backend/app/services/image_gen.py
|
||
- art-agent/backend/app/config.py
|
||
- **what**: 从单张参考图扩展为多张参考图全链路支持(前端上传/显示 + API + Agent Loop + 生图 Provider)
|
||
- **why**: GPT Image 1.5 支持最多 16 张参考图(images.edit 端点),Gemini 支持 14 张,用户需要"保留图1主体+图2视角"等多图组合控制能力
|
||
- **decisions**:
|
||
- OpenAI Provider 有参考图时从 images.generate 切换到 images.edit 端点(而非统一用 edit)
|
||
- Replicate IP-Adapter 模型仍只支持单张,取 ref_image_urls[0] 兼容
|
||
- 后端 API 新增 ref_image_urls JSON 数组字段,保留旧 ref_image_url 单值字段向后兼容
|
||
- 前端 ChatMessage 新增 refImageUrls 数组字段,保留旧 refImageUrl 兼容已有聊天记录
|
||
- System Prompt 更新:LLM 需要理解多张参考图各自的角色并在 prompt 中传达
|
||
- **notes**:
|
||
- 向量引擎中转需支持 /v1/images/edits 端点才能真正生效,待验证
|
||
- Gemini 走 OpenAI 兼容 API 中转,images.edit 是否被正确转发取决于中转层实现
|
||
- _load_image_bytes 新函数用于将本地路径/data URI 转为 bytes 供 images.edit 使用
|
||
|
||
### [CL-20260416-0510] 2026-04-16 05:10 — 生图模型新增 Gemini 3.1 Flash Image
|
||
- **tags**: 后端, 生图模型, Gemini, 向量引擎, config
|
||
- **affected_files**:
|
||
- art-agent/backend/app/config.py
|
||
- art-agent/backend/.env
|
||
- **what**: IMAGE_MODELS 注册表新增 gemini-3.1-flash-image 条目,model_id 为 gemini-3.1-flash-image-preview,provider 为 openai
|
||
- **why**: 用户希望使用 Google Gemini 3.1 Flash 的原生生图能力,速度快价格低
|
||
- **decisions**: 复用已有的 OpenAIImageProvider(向量引擎中转兼容 OpenAI images/generations 端点),零代码改动
|
||
- **notes**: 如向量引擎对 Gemini 生图的返回格式有差异(如只返回 b64 不返回 URL),OpenAIImageProvider 已兼容两种格式
|
||
|
||
### [CL-20260416-0500] 2026-04-16 05:00 — 全区域拖拽添加参考图
|
||
- **tags**: 前端, UX, 拖拽, 参考图, 上传
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/app/page.tsx
|
||
- art-agent/frontend/src/components/chat/chat-input.tsx
|
||
- **what**: 将拖拽上传参考图的区域从底部输入栏扩展到整个对话区域(main),拖入时显示全屏半透明覆盖层提示"松开以添加参考图"
|
||
- **why**: 原先拖拽事件只绑在 ChatInput 组件(底部一小条),用户拖图片到对话区域无反应,体验不直觉
|
||
- **decisions**: ChatInput 改为 forwardRef,暴露 `uploadFile` 方法(ChatInputHandle 接口)。page.tsx 的 `<main>` 处理 dragEnter/dragOver/dragLeave/drop,drop 时调用 `chatInputRef.current.uploadFile(file)` 复用已有上传逻辑。用 dragCounter ref 解决子元素 dragEnter/dragLeave 冒泡导致覆盖层闪烁的经典问题
|
||
- **notes**: ChatInput 自身的拖拽处理保留(作为 fallback),两套不冲突
|
||
|
||
### [CL-20260416-0430] 2026-04-16 04:30 — 接入 GPT Image 1.5 生图模型(向量引擎中转)
|
||
- **tags**: 后端, 生图模型, GPT-Image, OpenAI, 向量引擎, provider
|
||
- **affected_files**:
|
||
- art-agent/backend/app/services/image_gen.py
|
||
- art-agent/backend/app/config.py
|
||
- art-agent/backend/.env
|
||
- **what**: 新增 OpenAIImageProvider,通过向量引擎 API 中转调用 GPT Image 1.5 模型生图。IMAGE_MODELS 注册表新增 gpt-image-1.5 条目,放在列表首位
|
||
- **why**: 用户希望使用 OpenAI 最新的 GPT Image 1.5 模型,该模型在 prompt 理解和文字渲染方面表现最好。通过向量引擎中转可复用已有的 API Key
|
||
- **decisions**: 新建 `OpenAIImageProvider` 类(与 `ReplicateProvider` 并列),使用 OpenAI Python SDK 的 `images.generate` 端点,懒初始化客户端。支持 URL 和 base64 两种返回格式。Provider 注册键为 `"openai"`
|
||
- **notes**: GPT Image 系列不支持参考图(IP-Adapter),`supports_ref_image=False`。如果后续需要接入 gpt-image-1 或 gpt-image-1-mini,只需在注册表新增条目,Provider 代码无需改动
|
||
|
||
### [CL-20260416-0400] 2026-04-16 04:00 — Session 级参考图自动沿用 + 缺参考图前置校验
|
||
- **tags**: 前端, 后端, 参考图, UX, InstantStyle, 风格迁移
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/app/page.tsx
|
||
- art-agent/frontend/src/components/chat/chat-input.tsx
|
||
- art-agent/backend/app/services/image_gen.py
|
||
- **what**: 发送消息使用参考图后,在 session 级别记住该参考图 URL,后续消息自动沿用。输入框上方显示"沿用上次参考图"提示条(含缩略图+清除按钮)。后端对需要参考图但未收到的模型(InstantStyle/Kolors 等)返回友好错误而非发给模型得到诡异结果
|
||
- **why**: 用户切换到 InstantStyle 模型后输入"再执行一次前面的任务",因前端每次发送后清除参考图状态,导致 InstantStyle 收不到 style_image 参数,模型返回 "No input, Save money" 文本。高频场景(换模型重试同任务)不应要求重新上传参考图
|
||
- **decisions**: 参考图以 per-session `Map<sessionId, serverUrl>` 存在 `useRef` 中(不持久化到 localStorage),切换 session 时恢复对应参考图。UI 提示条仅在无主动上传且有历史参考图时显示,用户可一键清除。后端在 `generate_images` 统一入口处加前置校验,比在各 provider 内部检查更统一
|
||
- **notes**: 参考图信息不写入 Session 类型定义(不持久化到 localStorage),因为服务端文件可能被清理;如果将来需要持久化,需考虑文件存在性校验
|
||
|
||
### [CL-20260416-0300] 2026-04-16 03:00 — System Prompt 禁止 LLM 在回复中嵌入图片 Markdown 链接
|
||
- **tags**: 后端, agent-loop, system-prompt, LLM行为约束
|
||
- **affected_files**:
|
||
- art-agent/backend/app/agent/loop.py
|
||
- **what**: 在 System Prompt 注意事项中新增约束,禁止 LLM 在回复文字中使用 `` 或 `sandbox:` 等 Markdown 图片语法
|
||
- **why**: GPT 系列模型在收到 generate_image 工具返回的本地路径后,会自行拼凑 `sandbox:/generated/xxx.png` 格式的 Markdown 图片链接嵌入回复。该链接在前端不可渲染(`sandbox:` 不是有效协议),且图片展示已由 `image_result` SSE 事件独立处理,文字中的链接纯属多余
|
||
- **decisions**: 通过 System Prompt 约束解决(而非后端过滤),因为这是 LLM 行为问题,从源头阻止更干净
|
||
- **notes**: 同时排查发现 gpt-5.4 在向量引擎中转后实际调用了 gpt-4o-mini,该问题属于向量引擎 API 侧的模型映射/降级,非代码 bug
|
||
|
||
### [CL-20260416-0245] 2026-04-16 02:45 — 修复三点菜单被右侧对话区遮挡
|
||
- **tags**: 前端, UI, sidebar, 菜单, z-index
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/components/sidebar/session-list.tsx
|
||
- **what**: 三点菜单从 fixed 右侧弹出改为 inline 下方展开,模型子菜单改为折叠式内联
|
||
- **why**: 菜单用 fixed 定位弹到侧栏右侧,被主内容区的 stacking context 遮挡
|
||
- **decisions**: 放弃 fixed+绝对坐标的弹出菜单方案,改为在会话项下方 inline 渲染。模型子菜单从右侧 absolute 弹出改为折叠展开式,带 max-h 240px 滚动防止过长
|
||
- **notes**: 移除了 menuPos 状态,简化了定位逻辑
|
||
|
||
### [CL-20260416-0230] 2026-04-16 02:30 — LLM 模型注册表扩充:新增 5 个前沿模型,默认改为 GPT-5.4
|
||
- **tags**: 后端, config, LLM, 模型注册表
|
||
- **affected_files**:
|
||
- art-agent/backend/app/config.py
|
||
- art-agent/backend/.env
|
||
- **what**: LLM_MODELS 注册表从 3 个模型扩充到 7 个,默认模型从 gpt-4o-mini 改为 gpt-5.4
|
||
- **why**: 用户需要使用 2026 年前沿模型(GPT-5.4, Claude Sonnet/Opus 4.6, Gemini 3.1 Pro, GLM-4.7)
|
||
- **decisions**: 所有新增模型走 vectorengine provider,model_id 使用向量引擎确认的名称;gpt-4o-mini 和 deepseek-chat 保留作为轻量/直连选项
|
||
- **notes**: 新增模型的 model_id 需向量引擎实际支持,如有出入需调整
|
||
|
||
### [CL-20260416-0200] 2026-04-16 02:00 — 接入向量引擎中转 API + 对话级 LLM 模型切换
|
||
- **tags**: 后端, 前端, LLM, 向量引擎, 中转API, 模型切换, config, UI, session
|
||
- **affected_files**:
|
||
- art-agent/backend/app/config.py
|
||
- art-agent/backend/app/agent/loop.py
|
||
- art-agent/backend/app/api/chat.py
|
||
- art-agent/backend/.env
|
||
- art-agent/frontend/src/lib/types.ts
|
||
- art-agent/frontend/src/lib/api.ts
|
||
- art-agent/frontend/src/lib/app-context.tsx
|
||
- art-agent/frontend/src/components/sidebar/session-list.tsx
|
||
- art-agent/frontend/src/app/page.tsx
|
||
- **what**: 接入向量引擎中转 API(OpenAI 兼容格式),实现对话级 LLM 模型切换
|
||
- **why**: 用户需要通过中转 API 使用 OpenAI 系模型(GPT-4o/4o-mini),同时保留 DeepSeek 直连。每条对话应可独立选择不同模型
|
||
- **decisions**:
|
||
- 后端采用 LLM_MODELS 注册表 + provider 分发的架构(参考已有 IMAGE_MODELS 模式)
|
||
- provider 分为 vectorengine(向量引擎中转 OpenAI 系)和 deepseek(直连),各有独立的 API key 和 base_url
|
||
- 移除旧的 OPENAI_API_KEY/OPENAI_BASE_URL 全局配置,改为 provider 级别
|
||
- vision 能力检测改为从注册表读取,不再子串匹配模型名
|
||
- 前端对话列表的右键菜单改为显式三点按钮菜单,模型选择作为子菜单项
|
||
- Session 类型新增 llmModel 字段,llmModel 为空时使用后端默认
|
||
- **notes**:
|
||
- .env 中 VECTORENGINE_API_KEY 需要用户填入自己的 key
|
||
- Mem0 记忆系统仍使用 DEEPSEEK_API_KEY,不受影响
|
||
- 三点菜单预留了分享、归档等功能的扩展位
|
||
- 旧 localStorage 中没有 llmModel 字段的 Session 自动走默认模型
|
||
|
||
### [CL-20260416-0030] 2026-04-16 00:30 — 青绿山水风格改造:从 Cyberpunk 霓虹转为千里江山图色调 + 云烟雾气动效
|
||
- **tags**: 前端, UI改造, 视觉风格, 青绿山水, 千里江山图, CSS动画, 色彩体系, 云烟, 雾气
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/app/globals.css
|
||
- art-agent/frontend/src/components/layout/top-nav.tsx
|
||
- art-agent/frontend/src/components/sidebar/sidebar.tsx
|
||
- art-agent/frontend/src/components/sidebar/session-list.tsx
|
||
- art-agent/frontend/src/components/chat/chat-messages.tsx
|
||
- art-agent/frontend/src/components/chat/chat-input.tsx
|
||
- art-agent/frontend/src/components/chat/image-grid.tsx
|
||
- art-agent/frontend/src/components/detail/image-detail-panel.tsx
|
||
- art-agent/frontend/src/components/profile-modal.tsx
|
||
- art-agent/frontend/src/app/page.tsx
|
||
- art-agent/frontend/src/app/gallery/page.tsx
|
||
- art-agent/frontend/src/app/login/page.tsx
|
||
- docs/art-agent/VISUAL-STYLE-GUIDE.md
|
||
- **what**: 全站视觉风格从 Cyberpunk Dark Neon 改为"青绿山水"——以《千里江山图》矿物质颜料色为灵感的现代演绎。色彩体系、动画效果、背景光晕全面重做
|
||
- **why**: 用户希望美术风格从赛博朋克调整为中国传统青绿山水的现代演绎,发光效果添加"雾气感"
|
||
- **decisions**:
|
||
- 色彩体系:深墨绿底色(#0C1210)+ 石青绿高亮(#4DB8A4)+ 石绿蓝辅助(#3A8FB7)+ 赭石红(#C4654A)+ 赭金(#B8935A)
|
||
- 新增 --mist 和 --gold CSS 变量
|
||
- 背景改为双层漂移云雾(body::before 60s + body::after 45s),inset 负值防漂移露白
|
||
- .glow-border hover 效果:conic-gradient 弧段从 20% 扩大到 40-50%(更柔和),旋转从 3s 减慢到 6s,blur 从 6px 增到 12px,transition 从 500ms 增到 600ms
|
||
- .glass-panel 加内层渐变 + blur 从 20px 增到 24px + saturate(1.1)
|
||
- 新增 .fog-scroll 类(mask-image 渐变遮罩),应用到聊天区和会话列表
|
||
- 11 个组件文件中的硬编码 rgba(0,229,160,...) 全部替换为 rgba(77,184,164,...)
|
||
- 动画命名从 glowSpin 改为 mistSpin
|
||
- **notes**:
|
||
- profile-modal.tsx 也有硬编码颜色,在计划外被一并修复
|
||
- Logo SVG 中的 #0B0E14 替换为新的 --bg-primary 色值 #0C1210
|
||
- VISUAL-STYLE-GUIDE.md 完全重写,包含新旧风格对比表
|
||
- **source_chat**: [青绿山水风格改造]
|
||
|
||
### [CL-20260415-2330] 2026-04-15 23:30 — 用户个人信息 + 记忆查看面板:右上角菜单弹窗
|
||
- **tags**: 前端, 后端, 用户信息, 记忆系统, Mem0, Modal, ProfileModal, API
|
||
- **affected_files**:
|
||
- art-agent/backend/app/api/memory.py
|
||
- art-agent/backend/app/main.py
|
||
- art-agent/frontend/src/components/profile-modal.tsx
|
||
- art-agent/frontend/src/components/layout/top-nav.tsx
|
||
- **what**: 新增用户个人信息弹窗,展示用户基本信息和 Mem0 记忆系统中按时间分组的记忆列表
|
||
- **why**: 用户希望能查看记忆系统为自己记录了哪些信息,右上角菜单是最自然的入口
|
||
- **decisions**:
|
||
- 后端新建独立路由文件 api/memory.py(职责分离),暴露 GET /api/memory/list 端点
|
||
- 使用 Mem0 OSS `Memory.get_all(user_id=..., limit=200)` 获取全部记忆
|
||
- 同步调用通过 `run_in_executor` 包装避免阻塞事件循环
|
||
- 前端用居中 Modal(非 Drawer/独立页),复用 glass-panel + Cyberpunk 风格
|
||
- 记忆按 created_at 时间分组(今天/最近7天/更早),不依赖 Mem0 不稳定的 categories 字段
|
||
- 只读模式,不实现删除功能
|
||
- **notes**:
|
||
- TopNav 的 username 行从静态文本改为可点击按钮,点击打开 ProfileModal
|
||
- TopNav return 改为 Fragment 以容纳 header + Modal 两个顶级元素
|
||
- ESC 键可关闭弹窗,点击遮罩层也可关闭
|
||
- **source_chat**: [用户个人信息记忆面板]
|
||
|
||
### [CL-20260415-2230] 2026-04-15 22:30 — 光影流动边框效果:导航活动项 + 活动会话项
|
||
- **tags**: 前端, CSS动画, 视觉效果, conic-gradient, 霓虹边框, 导航, 侧边栏
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/app/globals.css
|
||
- art-agent/frontend/src/components/layout/top-nav.tsx
|
||
- art-agent/frontend/src/components/sidebar/session-list.tsx
|
||
- art-agent/frontend/src/components/sidebar/sidebar.tsx
|
||
- **what**: 实现 Dribbble 设计图中的边框光影流动效果,应用到导航活动 Tab 和活动会话项
|
||
- **why**: 用户指出按钮/标签缺少设计图中的发光+光影流动感。需要用 CSS 动画实现旋转锥形渐变边框
|
||
- **decisions**:
|
||
- 用 `@property --glow-angle` + `conic-gradient` 实现旋转光线,3s 一圈
|
||
- 双伪元素方案:`::before` 做精确渐变边框(mask-composite 裁掉内部),`::after` 做外层模糊扩散光晕
|
||
- 提供两个 CSS 类:`.glow-border`(动画旋转,用于活动态)、`.glow-border-static`(静态发光,用于 hover)
|
||
- 导航非活动项 hover 时用静态发光,不抢活动项视觉焦点
|
||
- **notes**:
|
||
- `@property` 需要浏览器支持 CSS Houdini(Chrome 85+, Edge 85+, Safari 15.4+),对目标用户群体覆盖足够
|
||
- 光影流动 3s 周期可通过修改 `glowSpin` 动画时长调整
|
||
- **source_chat**: [光影流动边框效果实现]
|
||
|
||
### [CL-20260415-2200] 2026-04-15 22:00 — 全站 UI 风格改造:Cyberpunk Dark Neon 主题
|
||
- **tags**: 前端, UI改造, 视觉风格, Cyberpunk, Neon, 毛玻璃, 全局样式, 组件重构
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/app/globals.css
|
||
- art-agent/frontend/src/app/page.tsx
|
||
- art-agent/frontend/src/app/gallery/page.tsx
|
||
- art-agent/frontend/src/app/login/page.tsx
|
||
- art-agent/frontend/src/components/layout/top-nav.tsx
|
||
- art-agent/frontend/src/components/sidebar/sidebar.tsx
|
||
- art-agent/frontend/src/components/sidebar/session-list.tsx
|
||
- art-agent/frontend/src/components/sidebar/tag-filter.tsx
|
||
- art-agent/frontend/src/components/chat/chat-messages.tsx
|
||
- art-agent/frontend/src/components/chat/chat-input.tsx
|
||
- art-agent/frontend/src/components/chat/image-grid.tsx
|
||
- art-agent/frontend/src/components/chat/model-selector.tsx
|
||
- art-agent/frontend/src/components/detail/image-detail-panel.tsx
|
||
- docs/art-agent/VISUAL-STYLE-GUIDE.md
|
||
- **what**: 参考 SolCasino Dribbble 设计,将全站 UI 从朴素暗色主题改造为 Cyberpunk Dark Neon 风格
|
||
- **why**: 用户希望产品页面更具视觉冲击力,参考了 Dribbble 上的加密赌场 Cases 页面设计,提取其核心视觉语言(霓虹发光、毛玻璃、环境光晕、卡片网格)应用到美术 Agent 工具
|
||
- **decisions**:
|
||
- 主色从紫色(#6366f1)改为青绿霓虹(#00E5A0),更符合 Cyberpunk 调性
|
||
- 新增 CSS 变量:`--bg-card`, `--hot`, `--accent-secondary`, `--border-glow`
|
||
- 背景加 body::before 环境光晕(两团 radial-gradient 光斑)
|
||
- 全部面板改为 backdrop-blur 毛玻璃效果
|
||
- 圆角从 rounded-lg/2xl 统一升级为 rounded-xl/2xl
|
||
- 新增 `.glass-panel` 和 `.neon-border` 全局 CSS 类
|
||
- 图片卡片 hover 时有微缩放(1.03) + 霓虹边框发光
|
||
- 登录页加独立环境光背景 + 毛玻璃表单容器
|
||
- Gallery 卡片改为 neon-border 风格,选中时霓虹发光阴影
|
||
- 收藏色从金色改为 accent 青绿色,保持色彩一致性
|
||
- **notes**:
|
||
- 同时编写了视觉风格文档 `docs/art-agent/VISUAL-STYLE-GUIDE.md`,记录完整的设计规范
|
||
- annotation-canvas.tsx 未做改动(工具型组件,暗色已适配)
|
||
- 所有组件保留原有功能和交互逻辑,仅变更视觉层
|
||
- **source_chat**: [Cyberpunk UI 风格改造]
|
||
|
||
### [CL-20260414-2350] 2026-04-14 23:50 — 修复登录后 useApp must be used within AppProvider 报错
|
||
- **tags**: bug修复, 前端, 认证, AppProvider, 初始化时序
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/lib/app-context.tsx
|
||
- **what**: 修复登录成功跳转到主页时 useApp() 拿到 null context 报错
|
||
- **why**: AppProvider 在 `!initialized` 时直接渲染 `<>{children}</>`(不提供 AppContext),但已登录用户跳转到 `/` 后 `page.tsx` 立即调用 `useApp()`,而 `useEffect` 中的 `setInitialized(true)` 还没执行,导致 context 为 null
|
||
- **decisions**: 区分两种 `!initialized` 场景——已认证时显示加载状态(不渲染需要 context 的子组件),未认证时渲染 children(供 /login 页面使用)
|
||
- **notes**: 这是 React 的 useEffect 异步特性导致的时序问题,登录跳转瞬间路由已变但 state 还没更新
|
||
- **source_chat**: [修复 AppProvider 初始化时序](a33b7af6-a8c0-4e88-8372-ec4b5b9dd703)
|
||
|
||
### [CL-20260414-2340] 2026-04-14 23:40 — 用 pwdlib (Argon2id) 替换 passlib (bcrypt),彻底解决兼容性问题
|
||
- **tags**: 重构, 安全, 密码哈希, Argon2, pwdlib, passlib, 依赖升级
|
||
- **affected_files**:
|
||
- art-agent/backend/app/auth.py
|
||
- art-agent/backend/requirements.txt
|
||
- docs/art-agent/USER-SYSTEM.md
|
||
- **what**: 将密码哈希从 passlib+bcrypt 替换为 pwdlib+Argon2id
|
||
- **why**: passlib 已停止维护,Python 3.13+ 不可用,且与 bcrypt 5.x 有兼容性问题。pwdlib 是 passlib 的现代替代,原生支持 bcrypt 5.x
|
||
- **decisions**: 选择 pwdlib[argon2,bcrypt] 而非纯 argon2-cffi:pwdlib 提供与 passlib 类似的统一接口,同时内置 BcryptHasher 兼容已有旧哈希。新密码一律 Argon2id,旧 bcrypt 哈希仍可验证(过渡期)
|
||
- **notes**: 已有 admin 用户的 bcrypt 哈希无需迁移,下次改密时自动升级为 Argon2id 格式。不再需要锁定 bcrypt 版本
|
||
- **source_chat**: [替换 passlib 为 pwdlib](a33b7af6-a8c0-4e88-8372-ec4b5b9dd703)
|
||
|
||
### [CL-20260414-2330] 2026-04-14 23:30 — 修复 passlib + bcrypt 5.x 兼容性问题,锁定 bcrypt<4.1
|
||
- **tags**: bug修复, 依赖, bcrypt, passlib, 用户系统
|
||
- **affected_files**:
|
||
- art-agent/backend/requirements.txt
|
||
- docs/art-agent/USER-SYSTEM.md
|
||
- **what**: 修复 passlib 1.7.4 与 bcrypt 5.0.0 不兼容导致后端启动失败
|
||
- **why**: passlib 已停止维护,bcrypt 4.1+ 移除了 `__about__` 属性且改变了密码长度校验行为,导致 passlib 加载后端报 `AttributeError` + `ValueError`
|
||
- **decisions**: 降级 bcrypt 到 4.0.1 并锁定 `>=4.0.1,<4.1`,而非替换 passlib(改动最小)
|
||
- **notes**: 如果未来需要升级 bcrypt,需替换 passlib 为 bcrypt 直接调用或改用 argon2-cffi 等不依赖 passlib 的方案
|
||
- **source_chat**: [修复 bcrypt 兼容性](a33b7af6-a8c0-4e88-8372-ec4b5b9dd703)
|
||
|
||
### [CL-20260414-2300] 2026-04-14 23:00 — 用户系统:管理员邀请制 + JWT 认证 + 数据按用户隔离
|
||
- **tags**: 用户系统, 认证, JWT, SQLite, 数据隔离, 多用户, 安全
|
||
- **affected_files**:
|
||
- art-agent/backend/requirements.txt
|
||
- art-agent/backend/app/db.py(新建)
|
||
- art-agent/backend/app/auth.py(新建)
|
||
- art-agent/backend/app/api/auth.py(新建)
|
||
- art-agent/backend/app/api/admin.py(新建)
|
||
- art-agent/backend/app/api/chat.py
|
||
- art-agent/backend/app/main.py
|
||
- art-agent/backend/app/agent/loop.py
|
||
- art-agent/backend/.env.example
|
||
- art-agent/frontend/src/lib/auth-context.tsx(新建)
|
||
- art-agent/frontend/src/lib/auth-guard.tsx(新建)
|
||
- art-agent/frontend/src/lib/api.ts
|
||
- art-agent/frontend/src/lib/store.ts
|
||
- art-agent/frontend/src/lib/app-context.tsx
|
||
- art-agent/frontend/src/app/layout.tsx
|
||
- art-agent/frontend/src/app/login/page.tsx(新建)
|
||
- art-agent/frontend/src/components/layout/top-nav.tsx
|
||
- art-agent/frontend/src/components/chat/model-selector.tsx
|
||
- **what**: 为 EPEEKit 添加完整用户系统:管理员创建账号、JWT 登录、所有 API 鉴权、Mem0 记忆按用户隔离、前端 localStorage 按用户隔离
|
||
- **why**: 之前无认证,所有访问者共享 `default_user` 的记忆,多人通过穿透使用时数据互相混杂
|
||
- **decisions**:
|
||
- SQLite(data/epeekit.db)存用户表,零部署成本,与 Qdrant 数据目录在同一 data/ 下
|
||
- JWT access token (30min) + refresh token (7d),passlib bcrypt 密码哈希
|
||
- 不开放注册,管理员通过 /api/admin/users 创建账号
|
||
- 首次启动自动创建 admin 账号(密码从 ADMIN_DEFAULT_PASSWORD 读取或随机生成打印到控制台)
|
||
- 前端 localStorage 键名加 user_id 前缀(如 `epeekit-{userId}-sessions`)实现数据隔离
|
||
- Mem0 的 user_id 从 JWT 中解析的真实用户 ID 传入,替代硬编码 `default_user`
|
||
- AppProvider 未登录时返回 `<>{children}</>` 而非 null,确保 /login 页面可渲染
|
||
- **notes**:
|
||
- 旧 Mem0 数据仍在 `default_user` 下,不自动迁移,新用户从零积累
|
||
- 前端 401 响应自动跳转 /login,XHR(上传)和 fetch 均处理
|
||
- TopNav 右侧新增用户菜单(显示名称 + 退出登录)
|
||
- 需在 .env 中配置 JWT_SECRET,否则启动时 RuntimeError
|
||
|
||
### [CL-20260414-2230] 2026-04-14 22:30 — 对话区域新增"回到底部"浮动按钮
|
||
- **tags**: 前端, UX, 滚动, 浮动按钮
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/app/page.tsx
|
||
- **what**: 当用户在对话中间位置时,显示一个浮动的向下箭头按钮,点击平滑滚到最新消息
|
||
- **why**: 长对话中浏览历史消息后,缺少快速回到最新内容的入口
|
||
- **decisions**: 复用已有的 scroll 事件监听器检测距底部距离(阈值 200px),按钮定位在输入框上方右侧。切换会话恢复位置后也主动检查按钮显示状态。使用已有的 `fadeIn` keyframes 动画
|
||
- **notes**: 按钮使用 `absolute` 定位在 `main` 容器内,`bottom-16` 避开输入框
|
||
|
||
### [CL-20260414-2220] 2026-04-14 22:20 — 修复长对话切换回来滚动位置上移:scroll 事件实时保存取代 effect 延迟保存
|
||
- **tags**: 前端, bug修复, 滚动, 多会话, UX, scroll 事件
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/app/page.tsx
|
||
- **what**: 修复长对话切换回来后滚动位置上移的 bug
|
||
- **why**: 之前在 useEffect 中保存旧会话的 scrollTop,但 effect 执行时 DOM 已经渲染了新会话(短对话)的内容,scrollHeight 变小,浏览器自动将 scrollTop 钳位(clamp)到 `scrollHeight - clientHeight`,导致保存的值远小于真实位置。最长的对话受影响最大,因为它的 scrollTop 差值最大
|
||
- **decisions**: 改用 scroll 事件监听器实时保存当前会话的 scrollTop 到 Map 中。这样在任何 state 变更或 DOM 重渲染之前,最新的滚动位置已经被记录。切换期间(`isSwitching=true`)跳过 scroll handler 写入,避免恢复过程中的中间值覆盖正确值
|
||
- **notes**: 这是 CL-20260414-2210 的后续修复。scroll 事件加了 `{ passive: true }` 避免影响滚动性能。cleanup 函数在 `activeSessionId` 变化时正确移除旧 listener
|
||
|
||
### [CL-20260414-2210] 2026-04-14 22:10 — 修复会话切换时滚动位置跳动:解决时序竞争 + 抑制切换期间 smooth scroll
|
||
- **tags**: 前端, bug修复, 滚动, 多会话, UX, 时序
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/app/page.tsx
|
||
- **what**: 修复会话切换时滚动条频繁跳动的问题
|
||
- **why**: 上一版修复(CL-20260414-2200)存在时序竞争:`useEffect` 中 `requestAnimationFrame` 执行时 React 可能还没将新会话的 messages 渲染到 DOM 中,导致 `scrollHeight` 是旧值。另外切换期间 `scrollToBottom(smooth)` 没有被抑制,smooth 动画与位置恢复互相干扰
|
||
- **decisions**:
|
||
- 拆为两个 effect:第一个(依赖 `activeSessionId`)只做保存旧位置 + 设 `isSwitching` 标记;第二个(依赖 `activeSessionId` + `messages.length`)在 messages 内容更新后才恢复位置
|
||
- 新增 `isSwitching` ref,切换期间抑制非 instant 的 `scrollToBottom` 调用,避免 smooth 动画干扰
|
||
- instant 模式改为直接赋值 `el.scrollTop = ...`,不再走 setTimeout,消除额外异步
|
||
- `messages` 声明提前到 effect 之前,确保 `messages.length` 可在 effect 依赖中使用
|
||
- **notes**: 图片异步加载仍可能导致 scrollHeight 变化使恢复位置偏移,但这是更深层问题,当前改动先解决核心的切换跳动
|
||
|
||
### [CL-20260414-2200] 2026-04-14 22:00 — 修复多会话滚动位置共享 bug:per-session 独立记录 + 切换恢复
|
||
- **tags**: 前端, bug修复, 滚动, 多会话, UX
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/app/page.tsx
|
||
- **what**: 修复多会话切换时滚动条位置共享的 bug,实现 per-session 滚动位置独立记录与恢复
|
||
- **why**: 所有会话共用同一个 scrollRef DOM 元素,切换会话时既不保存旧会话的 scrollTop,也不恢复目标会话的位置。导致:从长会话切到短会话可能看到空白底部,从短会话切到长会话不会停在最新消息处
|
||
- **decisions**: 用 `useRef<Map<string, number>>` 在内存中记录每个会话的 scrollTop(而非 localStorage),因为滚动位置是临时状态,刷新页面后重新滚到底部是合理的默认行为
|
||
- **notes**:
|
||
- 切换会话时,先保存离开会话的 scrollTop,再用 `requestAnimationFrame` 等 DOM 渲染完新消息后恢复目标位置
|
||
- 无记录的会话(首次进入或新建)使用 `scrollToBottom(true)` 即时滚到底部
|
||
- `scrollToBottom` 改为 `useCallback` 并新增 `instant` 参数,恢复位置时用 instant 避免视觉跳动,正常对话流用 smooth
|
||
- 将 `scrollToBottom` 加入 `handleSend` 的依赖数组,修复潜在的陈旧闭包问题
|
||
|
||
### [CL-20260413-2320] 2026-04-13 23:20 — 集成 Mem0 记忆系统:滑动窗口 + 跨会话长期记忆
|
||
- **tags**: Mem0, 记忆系统, 上下文管理, 长期记忆, Ollama, embedding, 滑动窗口
|
||
- **affected_files**:
|
||
- art-agent/backend/app/memory.py(新建)
|
||
- art-agent/backend/app/agent/loop.py
|
||
- art-agent/backend/app/config.py
|
||
- art-agent/backend/app/api/chat.py
|
||
- art-agent/backend/requirements.txt
|
||
- art-agent/backend/.env
|
||
- art-agent/frontend/src/lib/api.ts
|
||
- art-agent/frontend/src/app/page.tsx
|
||
- .gitignore
|
||
- **what**: 集成 Mem0 开源版作为统一记忆方案,一次性解决两个延期方案:上下文管理(滑动窗口截断)和跨会话长期记忆(事实提取+语义检索)
|
||
- **why**: 当前对话全量透传无截断,长对话会超 token 上限且费用线性增长;且每次会话从零开始无法记住用户偏好
|
||
- **decisions**:
|
||
- 选择 Mem0 OSS 自部署(非平台托管),完全本地化,数据在 ./data/qdrant
|
||
- DeepSeek 作为事实提取 LLM(复用现有 key,成本极低)
|
||
- Ollama nomic-embed-text 作为本地 embedding(免费,768维,性能足够)
|
||
- 不做静默降级:Ollama 不可用 → 阻止启动;search 失败 → SSE error 中断对话;add 失败 → SSE warning 告知用户
|
||
- 用 asyncio.run_in_executor 异步执行 memory.add(),不阻塞用户体验
|
||
- **notes**:
|
||
- 测试时创建了 data/qdrant 目录(含测试记忆数据),已加入 .gitignore
|
||
- Ollama 需要作为后台服务保持运行
|
||
- 首次 Mem0 初始化约需 5-8 秒(创建 Qdrant collection)
|
||
- 解决了延期方案 [context-window-management] 和 [mem0-long-term-memory]
|
||
- **source_chat**: [Mem0 记忆系统集成](mem0-memory-integration)
|
||
|
||
### [CL-20260413-1130] 2026-04-13 11:30 — 修复 SDXL 模型 404 错误:补全 Replicate 版本 hash
|
||
- **tags**: bug修复, Replicate, SDXL, 模型配置, 404
|
||
- **affected_files**:
|
||
- art-agent/backend/app/config.py
|
||
- **what**: 修复 Stable Diffusion XL 模型调用 Replicate API 返回 404 的问题
|
||
- **why**: 与之前 Kolors IP-Adapter(CL-20260413-0440)完全相同的根因——Replicate 对非 Black Forest Labs 官方模型需要 `owner/model:version_hash` 完整格式,短格式 `stability-ai/sdxl` 无法定位到具体版本
|
||
- **decisions**: 使用 Replicate 官方文档中的最新推荐版本 hash `39ed52f2...e08b`
|
||
- **notes**: Flux 系列(black-forest-labs/flux-schnell、flux-dev)不受此问题影响,Replicate 对其支持短格式。后续新增模型时应默认使用完整的 `owner/model:version_hash` 格式
|
||
|
||
### [CL-20260413-1100] 2026-04-13 11:00 — 修复切换模型后 LLM 仍声称使用旧模型名
|
||
- **tags**: Agent Loop, system prompt, 模型选择, LLM 幻觉, 模型名
|
||
- **affected_files**:
|
||
- art-agent/backend/app/agent/loop.py
|
||
- **what**: System Prompt 中动态注入当前生图模型名称,防止 LLM 从对话历史幻觉旧模型名
|
||
- **why**: 用户在同一会话内切换模型(如从 InstantStyle 切到 Kolors),LLM 在回复中仍声称使用旧模型。根因是 System Prompt 不包含模型信息,LLM 从对话历史中的工具返回结果/文字记录推断模型名,导致幻觉
|
||
- **decisions**: 在 system prompt 末尾动态拼接当前模型名 + 强调忽略旧记录。同时在假生成重试的纠正消息中也附带模型名
|
||
- **notes**: 通过 debug 日志验证:前端→后端→工具执行的模型传递链路完全正确(kolors-ipadapter 一路贯穿),问题仅在 LLM 文字输出层面。修复后验证通过
|
||
|
||
### [CL-20260413-1030] 2026-04-13 10:30 — Agent Loop 假生成检测 + 自动重试机制
|
||
- **tags**: Agent Loop, DeepSeek, function calling, 防幻觉, 自动修复
|
||
- **affected_files**:
|
||
- art-agent/backend/app/agent/loop.py
|
||
- **what**: 当 LLM 返回纯文字(无 tool_calls)但内容包含"已生成"等模拟生图关键词时,自动注入纠正消息强制 LLM 重新调用工具
|
||
- **why**: DeepSeek 即使在 System Prompt 中明确禁止模拟工具调用(CL-0930),仍会在复杂多步任务中用文字"扮演"生图过程,导致前端收不到 image_result 事件。Prompt 约束对 DeepSeek 无效,必须在代码层面硬性拦截
|
||
- **decisions**: 用正则匹配"已生成"、"生成完成"、"图片已"等关键词,命中 2 次以上且文本 >= 50 字时判定为假生成。检测到后将 LLM 的回复保留在历史中,追加一条纠正消息"你没有调用工具,请立即调用",然后 continue 回到循环让 LLM 重试。重试消耗一次迭代配额,不影响正常对话
|
||
- **notes**: 此机制主要针对 DeepSeek 的 function calling 纪律问题。GPT-4o 等模型通常不会触发。如果 DeepSeek 重试后仍然不调用工具,会在 max_iterations 用尽后正常结束
|
||
|
||
### [CL-20260413-1000] 2026-04-13 10:00 — 助手消息气泡添加复制文本按钮
|
||
- **tags**: 前端, UX, chat-messages, 复制
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/components/chat/chat-messages.tsx
|
||
- **what**: 助手回复气泡下方新增复制文本按钮,hover 时显示,点击复制文本内容并显示对勾反馈
|
||
- **why**: LLM 生成的 prompt 思路、风格描述等文字内容用户经常需要复制,之前只能手动选中
|
||
- **decisions**: 按钮放在气泡下方左侧而非内部,避免干扰阅读。只对 assistant 消息显示(用户自己的消息不需要复制)。使用 navigator.clipboard API,hover 显示 + 1.5s 对勾反馈
|
||
- **notes**: 仅复制纯文本内容,不含图片信息
|
||
|
||
### [CL-20260413-0930] 2026-04-13 09:30 — System Prompt 加入"禁止模拟工具调用"约束
|
||
- **tags**: prompt 工程, system prompt, DeepSeek, function calling, 防幻觉
|
||
- **affected_files**:
|
||
- art-agent/backend/app/agent/loop.py
|
||
- **what**: System Prompt 注意事项中新增"禁止模拟工具调用"硬性约束
|
||
- **why**: DeepSeek 在复杂多步任务(如一次生成 3 种不同建筑)中,有时不通过 function calling 调用 generate_image 工具,而是用文字"模拟"生成过程(如"已生成"),导致 Agent Loop 第一轮就因 tool_calls_data 为空而 yield done,前端收不到 image_result 事件,用户看不到图片
|
||
- **decisions**: 在 System Prompt 中加一条行为红线,告诉 LLM 必须实际调用工具。轻量级防御(检测文字中包含"已生成"但无工具调用时发警告)暂不实现,先观察 prompt 约束的效果
|
||
- **notes**: 这是 DeepSeek function calling 纪律问题,GPT-4o 等模型通常不会出现。如果 prompt 约束不够,后续可加检测机制
|
||
|
||
### [CL-20260413-0900] 2026-04-13 09:00 — 非 vision + 参考图场景:尊重用户主动指定的风格意图
|
||
- **tags**: prompt 工程, IP-Adapter, 风格, system prompt, UX
|
||
- **affected_files**:
|
||
- art-agent/backend/app/agent/loop.py
|
||
- **what**: 将"绝对禁止风格关键词"改为"不自行猜测,但保留用户明确指定的风格"
|
||
- **why**: 之前的 system prompt 和非 vision hint 中对风格关键词的禁止是绝对性的("绝对不要"、"不要添加任何"),导致 LLM 在用户主动输入了风格描述(如"赛博朋克风"、"水彩风")时也会丢弃用户意图。系统不应替用户做决定
|
||
- **decisions**: 措辞从"绝对禁止"改为"不自行猜测,但用户明确指定则保留"。两处同步修改:SYSTEM_PROMPT 第 47 行 + 非 vision 模型的 hint 文本。IP-Adapter 风格迁移与用户文字风格描述可叠加不冲突
|
||
- **notes**: 这是对 CL-20260413-0540 策略的修正——当时为了防止 DeepSeek 脑补画风而加了绝对禁止,现在细化为区分 LLM 猜测 vs 用户意图
|
||
|
||
### [CL-20260413-0800] 2026-04-13 08:00 — 修复 InstantStyle ReadTimeout + 多次生成丢失参考图
|
||
- **tags**: bug修复, Replicate, InstantStyle, timeout, 参考图, Agent Loop, wait, SDK
|
||
- **affected_files**:
|
||
- art-agent/backend/app/services/image_gen.py
|
||
- art-agent/backend/app/agent/loop.py
|
||
- **what**: 修复 InstantStyle 首次调用 ReadTimeout (61.4s) + 后续调用丢失参考图返回 "No input, Save money"
|
||
- **why**: 两个运行时日志证实的独立问题:(1) `wait=60` 时 SDK `_create_prediction_timeout` 生成 `httpx.Timeout(5.0, read=60.5)` 作为 per-request timeout 传给 `httpx.AsyncClient.request()`,优先级高于客户端级 300s timeout;(2) 成功生成后执行 `ref_image_url = None`,但 LLM 可能在后续轮次继续调用工具,此时 InstantStyle 因没有 `style_image` 返回 "No input, Save money"
|
||
- **decisions**: (1) `wait=60` → `wait=False`:不发 `Prefer: wait` header,create 请求立即返回 prediction ID,SDK 自动进入 `prediction.async_wait()` 轮询路径。轮询请求不带 per-request timeout,使用客户端级 `read=300s`。代价:比 `Prefer: wait` 模式多几秒轮询延迟,但绝不会 timeout。(2) 完全移除 `ref_image_url = None`:消息构建(附加参考图到 LLM 消息)在外层循环前一次性完成,不受影响。ref_image_url 只在 `execute_tool()` 中使用,整个对话期间都应该传递
|
||
- **notes**: 迭代了 CL-0700 和 CL-0730 的方案。wait 参数完整语义:`True` = `Prefer: wait` + read=60.5s;`int(n)` = `Prefer: wait={n}` + read={n+0.5}s(n 必须 1-60);`False` = 不等待、纯轮询。对慢模型(InstantStyle ~128s)配合大 payload(1.6MB base64),`wait=False` 是唯一可靠选项
|
||
|
||
### [CL-20260413-0730] 2026-04-13 07:30 — 修复生图失败后 LLM 重试丢失参考图
|
||
- **tags**: bug修复, Agent Loop, 参考图, InstantStyle, ref_image_url
|
||
- **affected_files**:
|
||
- art-agent/backend/app/agent/loop.py
|
||
- **what**: 修复 LLM 第一次生图工具调用失败后重试时参考图丢失,InstantStyle 返回 "No input, Save money"
|
||
- **why**: `loop.py` 在每轮工具调用循环结束后无条件执行 `ref_image_url = None`。当第一次调用超时失败后,LLM 决定重试,但此时 ref_image_url 已被清空,第二次工具调用没有参考图。InstantStyle 模型必须有 `style_image` 才能工作
|
||
- **decisions**: 改为条件性清除:在工具调用循环中标记 `tc_data["_had_images"] = True`,循环结束后检查是否有任何成功产出,只有 `any_success` 时才清除 ref_image_url。失败时保留参考图供后续重试
|
||
- **notes**: 这个改动对所有参考图模型生效(Kolors、InstantStyle 等)。只要本轮所有工具调用都失败了,ref_image_url 会一直保留直到某次成功为止
|
||
|
||
### [CL-20260413-0700] 2026-04-13 07:00 — 修复 InstantStyle 生图 422 + ReadTimeout:wait 参数超限与 SDK 内部 timeout 覆盖
|
||
- **tags**: bug修复, Replicate, InstantStyle, API参数, async_run, Prefer header, timeout
|
||
- **affected_files**:
|
||
- art-agent/backend/app/services/image_gen.py
|
||
- **what**: 修复 InstantStyle 生图 422(`Prefer: wait=x must be 1-60`)和后续 ReadTimeout(61.4s 超时)
|
||
- **why**: 上次修超时时将 `async_run(wait=300)` 设为 300 秒。Replicate SDK 将 int 类型的 wait 值设为 `Prefer: wait=300` header → API 返回 422。改为 `wait=True` 后 SDK 生成内部 `httpx.Timeout(read=60.5)` 作为请求级 timeout 覆盖了客户端级 300s timeout → 上传 1.6MB base64 style_image + 等待响应超过 60s → ReadTimeout
|
||
- **decisions**: 最终改为 `wait=60`(API 允许的最大 int 值)。SDK 行为:(1) `Prefer: wait=60` header(合法);(2) 内部 timeout `read=60.5s` 用于初始 create prediction 请求;(3) 60s 内未完成自动 fallback 到 `prediction.async_wait()` 轮询;(4) 轮询请求用客户端级 `httpx.Timeout(read=300s)`
|
||
- **notes**: Replicate SDK wait 参数语义:`True` = `Prefer: wait` + read=60.5s;`int(n)` = `Prefer: wait={n}` + read={n+0.5}s(n 必须 1-60);`False` = 不等待。对慢模型用 `wait=60` + 长客户端 timeout 是最优组合
|
||
|
||
### [CL-20260413-0630] 2026-04-13 06:30 — 修复 Replicate SDK 不走代理 + 超时:自定义 Client 注入代理和长超时
|
||
- **tags**: bug修复, Replicate, InstantStyle, 代理, httpx, 超时, 图像生成
|
||
- **affected_files**:
|
||
- art-agent/backend/app/services/image_gen.py
|
||
- **what**: 修复 InstantStyle 调用时 ConnectTimeout / ReadTimeout + "URL missing protocol" 连环错误
|
||
- **why**: Replicate Python SDK 的 `_build_httpx_client` 显式传入 `transport=AsyncHTTPTransport()`,导致 httpx 跳过环境变量中的 `HTTPS_PROXY` 代理配置直连 Replicate API。网络不稳定时直连超时,SDK 内部状态异常导致后续请求报 "URL missing protocol"。同时默认 read timeout 30s 不够 InstantStyle 的 ~128s 生成时间
|
||
- **decisions**: 创建 `_make_replicate_client()` 工厂函数,从环境变量读取代理并注入到 `AsyncHTTPTransport(proxy=...)` 中传给 `ReplicateClient`。read timeout 300s、connect timeout 30s。`_download_image` 也加了代理和 60s 超时
|
||
- **notes**: Replicate SDK 的代理绕过是个已知设计缺陷(显式 transport 覆盖了 httpx 的代理自动检测)。此修复对所有通过 `_replicate_client` 的 Replicate API 调用生效。无代理环境下也兼容(`proxy=None` 时 httpx 不走代理)
|
||
|
||
### [CL-20260413-0600] 2026-04-13 06:00 — 新增 InstantStyle 模型:强风格迁移选项
|
||
- **tags**: 模型注册, InstantStyle, 风格迁移, IP-Adapter, 模型配置
|
||
- **affected_files**:
|
||
- art-agent/backend/app/config.py
|
||
- **what**: 在模型注册表中新增 InstantStyle(`jyoung105/instant-style`),专门做风格分离迁移,与 Kolors IP-Adapter 并列为两个参考图模型选项
|
||
- **why**: Kolors IP-Adapter 的风格迁移弱(内容+风格+构图混合提取),经调研 InstantStyle 是 Replicate 上风格迁移能力最强的可用模型,能从参考图中分离出纯画风(线条、着色、色调)
|
||
- **decisions**: 利用现有 `supports_ref_image` + `ref_image_param` 抽象机制,InstantStyle 的 `style_image` 参数名通过配置映射,无需修改 `_build_input` 逻辑。默认 `block_mode: "style-only"`(只迁移风格不迁移构图),`style_strength: 1.0`
|
||
- **notes**: InstantStyle 较贵(~$0.12/次)且慢(~128s),适合风格定调阶段使用;Kolors 保留为低成本快速测试选项。社区模型需版本 hash
|
||
|
||
### [CL-20260413-0540] 2026-04-13 05:40 — 非 vision LLM + 参考图时禁止猜测风格,避免 prompt 与参考图风格冲突
|
||
- **tags**: prompt 工程, IP-Adapter, 风格一致性, system prompt, 非vision模型
|
||
- **affected_files**:
|
||
- art-agent/backend/app/agent/loop.py
|
||
- **what**: 修改 system prompt 和非 vision 模型的参考图文字提示,明确要求 LLM 不要猜测/指定画风关键词,风格完全交给 IP-Adapter 从参考图提取
|
||
- **why**: DeepSeek 等非 vision LLM 看不到参考图内容,会根据"2D 游戏"等关键词脑补风格(如 pixel art),导致 prompt 中的风格描述与参考图实际风格严重冲突。IP-Adapter 优先服从 prompt 的显式风格指令,参考图的风格影响被稀释
|
||
- **decisions**: 双重约束——system prompt 中加入"看不到参考图时不猜风格"的通用指引 + 注入的文字提示中用编号列表明确三条规则。保留了 vision 模型路径不变(vision 模型能看图,可以写风格词)
|
||
- **notes**: 这是过渡方案,等切换到 vision LLM(如 GPT-4o)后,LLM 可直接看图描述风格,此约束自动失效(走 vision_capable 分支)
|
||
|
||
### [CL-20260413-0520] 2026-04-13 05:20 — 多图生成改为单次 API 调用 + 修复空错误信息
|
||
- **tags**: 性能优化, Replicate, 速率限制, 错误处理, 模型配置
|
||
- **affected_files**:
|
||
- art-agent/backend/app/services/image_gen.py
|
||
- art-agent/backend/app/config.py
|
||
- **what**: 多图生成从 for 循环多次 API 调用改为单次调用(利用模型原生批量参数),同时修复异常 str() 为空时的错误信息丢失
|
||
- **why**: LLM 传 num_images=3 时会发 3 个独立 API 请求,在低余额账户的严格速率限制(burst=1)下后续请求会被 429 拦截。改为单次调用后只消耗 1 次请求配额。空错误信息(`[生成失败: ]`)导致用户无法诊断失败原因
|
||
- **decisions**: 新增 `num_images_param` 配置字段(Flux 用 `num_outputs`,Kolors 用 `number_of_images`),由 `_build_input` 统一注入。从 kolors 的 default_params 中移除了硬编码的 `number_of_images: 1`,改为动态设置
|
||
- **notes**: 空异常现在显示为 `{TypeName}: {repr(e)}`,确保始终有诊断信息
|
||
|
||
### [CL-20260413-0500] 2026-04-13 05:00 — 生成图片后显示使用的模型名称
|
||
- **tags**: 模型溯源, SSE, 图片生成, 前端展示
|
||
- **affected_files**:
|
||
- art-agent/backend/app/services/image_gen.py
|
||
- art-agent/backend/app/agent/tools.py
|
||
- art-agent/backend/app/agent/loop.py
|
||
- art-agent/frontend/src/lib/types.ts
|
||
- art-agent/frontend/src/app/page.tsx
|
||
- art-agent/frontend/src/components/chat/chat-messages.tsx
|
||
- **what**: 图片生成后在对话中显示实际使用的模型名称(如"由 Kolors IP-Adapter 生成"),失败时也附带模型名称
|
||
- **why**: 用户无法确认前端选择的模型是否真的被用于生图,特别是在多模型切换场景下需要明确溯源
|
||
- **decisions**: `generate_images` 返回值从 `list[str]` 改为 `GenerateResult` 数据类(包含 urls + model_name + model_id),模型名称通过 SSE `image_result` 和 `tool_error` 事件透传到前端。ChatMessage 类型新增 `modelName` 可选字段,消息归档后仍可查看模型来源
|
||
- **notes**: 模型名称来自 config.py 注册表中的 `name` 字段,所以显示的是友好名称而非 Replicate 的 model_id
|
||
|
||
### [CL-20260413-0440] 2026-04-13 04:40 — 修复 Kolors IP-Adapter 模型 404 错误:补全 Replicate 版本 hash
|
||
- **tags**: bug修复, Replicate, Kolors, IP-Adapter, 模型配置
|
||
- **affected_files**:
|
||
- art-agent/backend/app/config.py
|
||
- **what**: 在 kolors-ipadapter 的 model_id 中补全版本 hash,从 `fofr/kolors-with-ipadapter` 改为 `fofr/kolors-with-ipadapter:5a1a92b2...`
|
||
- **why**: Replicate SDK `async_run` 对非 official 模型(社区模型)只用 `owner/model` 格式调用时,会尝试 official model predictions 端点,该端点返回 404。必须使用 `owner/model:version_hash` 格式才能正确创建 prediction
|
||
- **decisions**: 只修复 kolors 模型(唯一报错的),其他三个模型(flux-schnell、flux-dev、sdxl)均为 official/热门模型,`owner/model` 格式能正常工作
|
||
- **notes**: 未来新增社区模型时,需确保 model_id 包含版本 hash。经实测加版本 hash 后生图成功
|
||
|
||
### [CL-20260413-0430] 2026-04-13 04:30 — 图片生成失败时将具体错误信息透传到前端
|
||
- **tags**: 错误处理, Agent Loop, SSE, 调试体验
|
||
- **affected_files**:
|
||
- art-agent/backend/app/agent/loop.py
|
||
- art-agent/frontend/src/app/page.tsx
|
||
- art-agent/frontend/src/lib/api.ts
|
||
- **what**: 新增 `tool_error` SSE 事件类型,将图片生成工具的具体错误信息(如 Replicate API 报错详情)直接透传到前端展示
|
||
- **why**: 之前工具调用失败时,错误信息只传回给 LLM,LLM 会自行"翻译"错误(如说成"速率限制"),用户无法看到真实报错,排查困难。典型场景:使用 Kolors IP-Adapter 生图失败,前端只看到 LLM 的模糊描述,无法定位是参数错误、超时还是 API 限制
|
||
- **decisions**: 错误信息同时发给前端展示和 LLM 继续对话,不互斥。前端用 ⚠️ 前缀醒目显示错误详情
|
||
- **notes**: 此改动不影响 LLM 的重试机制(工具结果仍然回传给 LLM),只是额外增加了一条面向用户的 SSE 事件
|
||
|
||
### [CL-20260413-0330] 2026-04-13 03:30 — README 补充访问地址汇总 + 穿透管理文档
|
||
- **tags**: 文档, README, 穿透, Cloudflare, cloudflared
|
||
- **affected_files**:
|
||
- art-agent/README.md (新增"访问地址"章节 + 重写"远程访问"章节)
|
||
- **what**: README 新增三种访问场景(本机/局域网/外网)的地址汇总表,重写远程访问章节补充 cloudflared 安装指引、穿透管理操作表、代理配置排错
|
||
- **why**: 原 README 远程访问章节过于简略,缺少 cloudflared 安装方式、穿透的启动/停止/排错说明,用户实际操作时需要这些信息
|
||
- **decisions**:
|
||
- 访问地址章节放在"使用"之后、"配置说明"之前,让用户启动后立即看到访问方式
|
||
- cloudflared 安装提供 winget 和手动下载两种方式(winget 安装后可能不在 PATH 中)
|
||
- 穿透管理用表格呈现(启动/停止/查看状态/重启),简洁直观
|
||
- 代理排错放在注意事项中,因为国内环境常需代理才能连上 Cloudflare
|
||
- **notes**: 无
|
||
|
||
### [CL-20260412-2345] 2026-04-12 23:45 — 参考图上传独立化:进度条 + 状态反馈 + 失败重试
|
||
- **tags**: 前端, 后端, 参考图, 上传, UX, 进度反馈
|
||
- **affected_files**:
|
||
- art-agent/backend/app/api/chat.py (新增 POST /api/upload-ref-image 独立上传端点,chat 端点新增 ref_image_url 字段)
|
||
- art-agent/frontend/src/lib/api.ts (新增 uploadRefImage 函数,XMLHttpRequest 实现进度回调;sendChat 参数从 File 改为服务端路径字符串)
|
||
- art-agent/frontend/src/components/chat/chat-input.tsx (重写上传流程:选图即上传、环形进度条、状态角标、失败重试、input value 重置)
|
||
- art-agent/frontend/src/app/page.tsx (handleSend 适配新签名:接收服务端路径而非 File;标注截图也走独立上传)
|
||
- **what**: 将参考图从"随消息一起提交"改为"选中后立即独立上传",全程有进度条、状态提示、失败重试入口
|
||
- **why**: 原方案图片上传绑定在发送消息时才执行,无任何进度反馈。大图或走 Cloudflare Tunnel 时用户完全无法判断上传是否开始、是否成功、是否卡住。多次上传参考图后 file input 不重置也导致交互异常
|
||
- **decisions**: 使用 XMLHttpRequest 而非 fetch(fetch 不支持 upload progress 事件);后端同时保留 ref_image 文件上传和 ref_image_url 路径两种方式,向后兼容
|
||
- **notes**: 上传超时设为 120 秒;支持 AbortController 取消;file input 每次选择后立即重置 value,确保同一文件可重复选择
|
||
|
||
### [CL-20260412-2315] 2026-04-12 23:15 — 修复 Cloudflare Tunnel 跨域开发警告
|
||
- **tags**: 前端, 配置, Next.js, Cloudflare, 跨域
|
||
- **affected_files**:
|
||
- art-agent/frontend/next.config.ts (新增 allowedDevOrigins)
|
||
- **what**: 在 next.config.ts 中添加 `allowedDevOrigins: ["*.trycloudflare.com"]`,消除 Cloudflare Tunnel 穿透时的跨域警告
|
||
- **why**: Next.js 检测到来自 trycloudflare.com 的跨域请求,发出警告提示未来版本将强制要求配置
|
||
- **decisions**: 使用通配符 `*.trycloudflare.com` 覆盖所有 Quick Tunnel 随机域名
|
||
- **notes**: 仅影响开发模式,生产构建不受影响
|
||
|
||
### [CL-20260412-2300] 2026-04-12 23:00 — 集成 Kolors IP-Adapter 模型,参考图可直接用于风格生成
|
||
- **tags**: 后端, 前端, IP-Adapter, 风格迁移, 参考图, 模型注册, Replicate, 架构
|
||
- **affected_files**:
|
||
- art-agent/backend/app/config.py (新增 kolors-ipadapter 模型注册 + supports_ref_image / ref_image_param 通用字段)
|
||
- art-agent/backend/app/services/image_gen.py (ReplicateProvider._build_input 支持参考图注入 + to_data_uri 公共工具函数)
|
||
- art-agent/backend/app/agent/loop.py (复用 to_data_uri 替代原 _to_vision_url,移除冗余 import)
|
||
- art-agent/frontend/src/lib/types.ts (ImageModelInfo 新增 supports_ref_image 字段)
|
||
- art-agent/frontend/src/components/chat/model-selector.tsx (模型列表中显示"参考图"标记)
|
||
- **what**: 集成 Kolors IP-Adapter 模型(fofr/kolors-with-ipadapter),参考图可真正参与图像生成的风格控制;架构上为后续切换其他 IP-Adapter 模型预留了通用扩展机制
|
||
- **why**: 之前参考图仅由 LLM 侧理解(且 DeepSeek 看不到图),生图工具侧完全忽略了参考图。用户希望参考图能真正影响生成结果的风格
|
||
- **decisions**:
|
||
- 模型注册表新增两个通用字段:supports_ref_image(布尔标记)和 ref_image_param(参考图参数名,不同模型可能不同)
|
||
- _build_input 根据 supports_ref_image 自动走不同构建逻辑,新增 IP-Adapter 模型只需加注册表配置
|
||
- 参考图通过 base64 data URI 传递给 Replicate(避免本地 URL 不可达的问题)
|
||
- to_data_uri 抽为 image_gen.py 中的公共函数,loop.py 复用(替代原 _to_vision_url)
|
||
- Kolors IP-Adapter 默认 ip_adapter_weight=0.8(非 1.0),给 prompt 文字留一些影响空间
|
||
- 前端模型列表中为支持参考图的模型显示绿色"参考图"徽章
|
||
- get_image_models_list 返回 supports_ref_image 字段,前端据此渲染标记
|
||
- **notes**:
|
||
- Kolors IP-Adapter 成本极低(~$0.004/次),速度快(~4s)
|
||
- 后续要换其他 IP-Adapter 模型(如 Flux IP-Adapter v2),只需在 IMAGE_MODELS 中新增配置
|
||
- 分层组合产线方案(IP-Adapter → LoRA → ControlNet)已记录为延期方案 [style-pipeline-layered]
|
||
|
||
### [CL-20260412-2230] 2026-04-12 22:30 — 用户消息气泡中显示参考图缩略图
|
||
- **tags**: 前端, 参考图, UX, chat-messages
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/lib/types.ts (ChatMessage 新增 refImageUrl 字段)
|
||
- art-agent/frontend/src/app/page.tsx (构造 userMessage 时保存参考图 Blob URL)
|
||
- art-agent/frontend/src/components/chat/chat-messages.tsx (用户消息气泡中渲染参考图缩略图)
|
||
- **what**: 用户上传参考图发送后,在聊天气泡中显示参考图缩略图,让用户确认图片确实被附带发送了
|
||
- **why**: 之前用户上传参考图后,发送消息后气泡中看不到参考图,无法确认是否上传成功,体验不好
|
||
- **decisions**:
|
||
- 使用 URL.createObjectURL 创建 Blob URL 用于当前会话内显示(轻量、即时)
|
||
- Blob URL 不持久化到 localStorage(刷新后失效),避免存储 base64 data URI 的空间开销
|
||
- 参考图缩略图显示在消息文本上方,最大尺寸 160×120px
|
||
- **notes**:
|
||
- Blob URL 仅在当前标签页有效,刷新页面后旧消息中的参考图缩略图不可见(MVP 可接受)
|
||
- 如需持久化,后续可改为存储后端上传路径(需要等后端返回 upload URL 后再构造 userMessage)
|
||
|
||
### [CL-20260412-2200] 2026-04-12 22:00 — 修复 DeepSeek 不支持 image_url 导致参考图上传报错
|
||
- **tags**: bug修复, 后端, Agent Loop, vision, DeepSeek, 多模态
|
||
- **affected_files**:
|
||
- art-agent/backend/app/agent/loop.py (新增 vision 能力检测,非 vision 模型走文字提示)
|
||
- **what**: 修复使用 DeepSeek 作为 LLM 时,上传参考图后报 400 错误 `unknown variant 'image_url', expected 'text'`
|
||
- **why**: 代码原本假设所有 LLM 都支持 OpenAI Vision API 的 `image_url` content type,但 DeepSeek 的 Chat API 只支持 `text` 类型
|
||
- **decisions**:
|
||
- 通过模型名称关键词检测 vision 能力(gpt-4o / gpt-4-vision / claude 视为支持)
|
||
- 不支持 vision 的模型:用文字提示告知 LLM 有参考图存在,参考图仍由图像生成工具侧处理
|
||
- 支持 vision 的模型:保持原有 image_url 格式不变
|
||
- **notes**:
|
||
- 此方案确保参考图功能在任何 LLM 下都不会报错
|
||
- 非 vision 模型无法"看到"参考图,但生图工具仍会收到参考图用于 img2img 场景
|
||
- 如需更精确的 vision 能力检测,可后续改为在 config.py 中按模型注册 vision 标志
|
||
|
||
### [CL-20260412-2130] 2026-04-12 21:30 — 修复图片生成失败时前端显示破碎图标
|
||
- **tags**: bug修复, 前端, 后端, 图像生成, 错误处理
|
||
- **affected_files**:
|
||
- art-agent/backend/app/agent/tools.py (分离有效 URL 和错误信息)
|
||
- art-agent/frontend/src/app/page.tsx (过滤无效 URL,空列表时不渲染图片网格)
|
||
- **what**: 修复 Replicate API 失败时前端出现 4 个破碎图标框的问题
|
||
- **why**: 用户在 Replicate 余额不足(402)时生图,错误字符串被当作图片 URL 传给 `<img>` 标签
|
||
- **decisions**:
|
||
- 后端 tools.py:将 generate_images 返回值分为 images(有效 URL)和 errors(错误信息)两个字段
|
||
- 前端 page.tsx:过滤以 `[` 开头的无效 URL,无有效图片时直接 break 不创建 ImageAsset
|
||
- **notes**:
|
||
- 根因是 Replicate 账户余额不足,需用户到 https://replicate.com/account/billing#billing 充值
|
||
- 此修复确保任何 API 错误场景下前端都不会显示破碎图标
|
||
|
||
### [CL-20260412-2100] 2026-04-12 21:00 — 生图模型动态切换:Provider 抽象 + 前端模型选择器
|
||
- **tags**: 后端, 前端, 图像生成, 模型切换, Provider, 重构, Replicate
|
||
- **affected_files**:
|
||
- art-agent/backend/app/config.py (新增 IMAGE_MODELS 注册表 + get_image_model_config / get_image_models_list / get_default_image_model_id)
|
||
- art-agent/backend/app/services/image_gen.py (重构:ImageProvider 抽象基类 + ReplicateProvider 实现 + generate_images 接受 model_id)
|
||
- art-agent/backend/app/api/chat.py (新增 GET /api/models 端点 + POST /api/chat 增加 image_model 参数)
|
||
- art-agent/backend/app/agent/loop.py (run_agent_loop 增加 image_model 参数透传)
|
||
- art-agent/backend/app/agent/tools.py (execute_tool 增加 image_model 参数透传)
|
||
- art-agent/backend/.env (IMAGE_MODEL 改为短 ID 格式)
|
||
- art-agent/backend/.env.example (同步更新)
|
||
- art-agent/frontend/src/lib/types.ts (新增 ImageModelInfo 类型)
|
||
- art-agent/frontend/src/lib/api.ts (新增 fetchModels() + sendChat 增加 imageModel 参数)
|
||
- art-agent/frontend/src/components/chat/model-selector.tsx (新建:模型选择下拉组件)
|
||
- art-agent/frontend/src/components/chat/chat-input.tsx (集成 ModelSelector + onSend 签名扩展)
|
||
- art-agent/frontend/src/app/page.tsx (handleSend 透传 imageModel 到 sendChat)
|
||
- **what**: 将图像生成服务从 Replicate 硬绑定重构为 Provider 抽象架构,支持 Replicate 上多模型(flux-schnell / flux-dev / SDXL)按消息粒度切换
|
||
- **why**: 用户希望能在对话中随时切换生图模型来对比不同模型的效果
|
||
- **decisions**:
|
||
- Provider 模式:抽象基类 ImageProvider + 具体实现(当前只有 ReplicateProvider),预留 DalleProvider/ComfyUIProvider 等扩展点
|
||
- 模型注册表放在 config.py 中(Python dict),新增模型只需加一条配置
|
||
- 前端模型列表由后端 API 驱动(GET /api/models),不在前端硬编码
|
||
- 切换粒度为每条消息级(最灵活),通过 FormData 传递 image_model 参数
|
||
- 模型选择持久化到 localStorage,作为后续消息的默认值
|
||
- Flux 系列使用 aspect_ratio 参数,SDXL 使用 width/height 参数,由 ReplicateProvider._build_input 内部分流处理
|
||
- **notes**:
|
||
- 向后兼容:image_model 参数可选,不传时使用 .env 中的默认模型
|
||
- .env 中 IMAGE_MODEL 支持短 ID(flux-schnell)和完整 Replicate ID(black-forest-labs/flux-schnell),自动转换
|
||
|
||
### [CL-20260412-1800] 2026-04-12 18:00 — 移动端适配 + Cloudflare Tunnel 内网穿透
|
||
- **tags**: 前端, 响应式, 移动端, 部署, Cloudflare, 穿透, 配置
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/app/layout.tsx (viewport meta 配置)
|
||
- art-agent/frontend/src/app/globals.css (iOS bounce 防护、tap highlight、dvh 支持、遮罩动画)
|
||
- art-agent/frontend/src/app/page.tsx (桌面端展开按钮加 hidden md:flex)
|
||
- art-agent/frontend/src/app/gallery/page.tsx (网格 gap/列数适配、hover 操作移动端始终可见、选择框可见)
|
||
- art-agent/frontend/src/components/sidebar/sidebar.tsx (移动端固定定位抽屉 + 遮罩)
|
||
- art-agent/frontend/src/components/layout/top-nav.tsx (新增汉堡菜单按钮、间距微调)
|
||
- art-agent/frontend/src/components/detail/image-detail-panel.tsx (移动端全屏 overlay)
|
||
- art-agent/frontend/src/components/chat/chat-messages.tsx (气泡宽度 90%、间距收紧)
|
||
- art-agent/frontend/src/components/chat/chat-input.tsx (padding 收紧)
|
||
- art-agent/frontend/src/components/chat/image-grid.tsx (max-width 适配、操作栏移动端可见)
|
||
- art-agent/frontend/src/lib/app-context.tsx (小屏默认折叠侧边栏、切换会话自动收起)
|
||
- art-agent/frontend/next.config.ts (trycloudflare.com + replicate.delivery 白名单)
|
||
- art-agent/start-tunnel.ps1 (新建:一键穿透脚本)
|
||
- art-agent/README.md (新增远程访问章节、uvicorn 加 --host 0.0.0.0)
|
||
- **what**: 为实现手机浏览器远程访问,完成移动端响应式适配(9 个组件)和 Cloudflare Quick Tunnel 穿透方案
|
||
- **why**: 用户希望把项目发给自己和朋友在手机上通过浏览器使用
|
||
- **decisions**:
|
||
- 移动端断点统一用 `md:` (768px),与 Tailwind 默认保持一致
|
||
- 侧边栏移动端用 fixed + overlay 抽屉模式,桌面端保持原有 w-0/w-[280px] 切换
|
||
- 图片详情面板移动端全屏(fixed inset-0),不做半屏,因为手机屏幕空间有限
|
||
- 穿透方案选 Cloudflare Quick Tunnel(免费、免注册),不选 ngrok(有连接限制)
|
||
- 穿透脚本自动管理 .env.local 的更新和恢复,减少手动操作
|
||
- hover 操作在移动端始终显示(无 hover 事件),避免操作不可达
|
||
- 路线 B(云服务器正式部署)记录为延期方案,待后续实施
|
||
- **notes**:
|
||
- 构建验证通过,无 lint 错误
|
||
- cloudflared 通过 winget 安装,版本 2025.8.1
|
||
- Quick Tunnel 每次启动分配随机域名(xxx.trycloudflare.com),非固定
|
||
- 穿透启动后需重启前端才能读取新的 NEXT_PUBLIC_API_URL
|
||
- project-launcher Skill 中的 uvicorn 命令也同步加了 --host 0.0.0.0
|
||
|
||
### [CL-20260412-1530] 2026-04-12 15:30 — 修复 .env 配置加载时序问题
|
||
- **tags**: 后端, bug修复, 配置, dotenv, Python
|
||
- **affected_files**:
|
||
- art-agent/backend/app/main.py (load_dotenv 前置 + override=True)
|
||
- art-agent/backend/app/config.py (模块级常量 → 函数式懒读取)
|
||
- art-agent/backend/app/agent/loop.py (引用改为函数调用)
|
||
- art-agent/backend/app/services/image_gen.py (引用改为函数调用)
|
||
- art-agent/backend/.env (OPENAI_BASE_URL 去掉 /v1)
|
||
- **what**: 修复切换 DeepSeek API 后报 "Model Not Exist" 400 错误
|
||
- **why**: 用户修改 .env 切换到 DeepSeek,但实际发出的请求仍使用默认模型名 gpt-4o-mini
|
||
- **decisions**:
|
||
- load_dotenv(override=True) 放在 main.py 所有业务 import 之前,确保环境变量在任何模块读取前就位
|
||
- config.py 从模块级常量改为函数(get_llm_model() 等),避免 import 时求值被固化
|
||
- 不使用 lru_cache(避免首次调用在 load_dotenv 前就缓存了空值)
|
||
- **notes**:
|
||
- 根因有两层:import 时序(config.py 在 load_dotenv 前被 import)+ override 默认行为(不覆盖已有环境变量)
|
||
- 通过在 uvicorn 同环境中运行 Python 脚本成功复现了 API 调通,证明问题在进程内加载顺序而非 API 本身
|
||
- DeepSeek base_url 使用 https://api.deepseek.com(不带 /v1),与官方文档一致
|
||
|
||
### [CL-20260412-1500] 2026-04-12 15:00 — 品牌重命名 EPEEKit + API 配置集中化
|
||
- **tags**: EPEEKit, 品牌, 配置, 后端, 前端, 重构
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/app/layout.tsx (title/description)
|
||
- art-agent/frontend/src/components/layout/top-nav.tsx (Logo SVG + 品牌名)
|
||
- art-agent/frontend/src/app/page.tsx (欢迎文案)
|
||
- art-agent/frontend/src/lib/store.ts (localStorage 键名)
|
||
- art-agent/frontend/src/app/gallery/page.tsx (下载前缀)
|
||
- art-agent/frontend/src/components/detail/image-detail-panel.tsx (下载前缀)
|
||
- art-agent/frontend/src/components/chat/image-grid.tsx (下载前缀)
|
||
- art-agent/frontend/package.json (项目名)
|
||
- art-agent/frontend/package-lock.json (项目名)
|
||
- art-agent/backend/app/main.py (FastAPI title)
|
||
- art-agent/backend/app/config.py (新建:集中配置)
|
||
- art-agent/backend/app/agent/loop.py (引用集中配置)
|
||
- art-agent/backend/app/services/image_gen.py (引用集中配置 + 简化重复分支)
|
||
- art-agent/backend/.env (重组为分组结构 + 新增 LLM_MODEL/IMAGE_MODEL 等)
|
||
- art-agent/backend/.env.example (新建)
|
||
- art-agent/README.md (全文更新)
|
||
- **what**: 将应用从 "Art Agent" 正式命名为 "EPEEKit",同时将后端所有硬编码的 API/模型配置抽取到 .env 文件,通过 config.py 集中管理
|
||
- **why**: 用户要求正式命名应用并希望能方便地切换 LLM 和图像生成模型进行测试
|
||
- **decisions**:
|
||
- 品牌名全部统一为 "EPEEKit",包括页面标题、Logo、下载文件名、localStorage 键名
|
||
- Logo 采用内联 SVG 设计(主题色圆角方块 + A/i 组合),不引入外部图片资源
|
||
- API 配置走 .env + config.py 方案(非 settings.py 类模式),保持极简
|
||
- 切换 LLM 只需改 .env 中 3 个值:OPENAI_BASE_URL + OPENAI_API_KEY + LLM_MODEL
|
||
- image_gen.py 中去除了参考图分支的重复代码(两个分支逻辑完全相同)
|
||
- **notes**:
|
||
- localStorage 键名变更意味着旧数据不会自动迁移(MVP 阶段可接受)
|
||
- .env 文件中含真实密钥,需确认 .gitignore 覆盖
|
||
|
||
### [CL-20260412-0300] 2026-04-12 03:00 — 完成交互原型全面重构
|
||
- **tags**: art-agent, 前端, 交互设计, 三栏布局, 标签系统, Canvas标注, 资源库, 后端
|
||
- **affected_files**:
|
||
- art-agent/frontend/src/app/page.tsx (重写)
|
||
- art-agent/frontend/src/app/layout.tsx (添加 AppProvider)
|
||
- art-agent/frontend/src/app/globals.css (增加样式)
|
||
- art-agent/frontend/src/app/gallery/page.tsx (新建)
|
||
- art-agent/frontend/src/lib/types.ts (新建:全局类型定义)
|
||
- art-agent/frontend/src/lib/store.ts (新建:localStorage 持久化存储)
|
||
- art-agent/frontend/src/lib/app-context.tsx (新建:全局状态 Context)
|
||
- art-agent/frontend/src/lib/api.ts (更新类型兼容)
|
||
- art-agent/frontend/src/components/layout/top-nav.tsx (新建)
|
||
- art-agent/frontend/src/components/sidebar/sidebar.tsx (新建)
|
||
- art-agent/frontend/src/components/sidebar/session-list.tsx (新建)
|
||
- art-agent/frontend/src/components/sidebar/tag-filter.tsx (新建)
|
||
- art-agent/frontend/src/components/chat/chat-messages.tsx (适配新类型)
|
||
- art-agent/frontend/src/components/chat/chat-input.tsx (增加拖拽上传)
|
||
- art-agent/frontend/src/components/chat/image-grid.tsx (增加操作栏)
|
||
- art-agent/frontend/src/components/detail/image-detail-panel.tsx (新建)
|
||
- art-agent/frontend/src/components/detail/annotation-canvas.tsx (新建)
|
||
- art-agent/backend/app/agent/loop.py (System Prompt + base64 转换)
|
||
- **what**: 从单页对话 MVP 全面重构为完整交互原型,三个 Phase 一次性完成
|
||
- **why**: 用户要求完整设计交互原型,通过规划讨论确定了三栏布局 + 标签系统 + 标注 + 资源库的完整方案
|
||
- **decisions**:
|
||
- 数据持久化使用 localStorage(MVP 阶段),后续可迁移到后端数据库
|
||
- 全局状态管理使用 React Context + useReducer 模式,不引入第三方状态库
|
||
- 标注功能使用原生 Canvas API,不引入第三方画板库(减少依赖)
|
||
- 标注坐标使用归一化比例(0-1),与图片实际分辨率解耦
|
||
- 资源库使用 Modal overlay 展示详情,而非独立路由页面
|
||
- 标注截图通过 base64 data URI 直接传给 OpenAI Vision,后端自动处理本地路径转换
|
||
- **notes**:
|
||
- 新增 12 个源文件,修改 6 个现有文件,无新依赖引入
|
||
- 内置标签 6 个:UI、Icon、原画、风格探索、立绘、概念图
|
||
- 标注工具 4 种:矩形框选、箭头、自由画笔、文字,含撤销/清除
|
||
- 构建验证通过,无 linter 错误
|
||
- 未来可优化:标签自动推荐逻辑(当前仅预留接口)、后端会话持久化、图片搜索索引
|
||
|
||
### [CL-20260411-1500] 2026-04-11 15:00 — 完成美术 Agent 产品决策和技术选型
|
||
- **tags**: art-agent, 产品决策, 技术选型, 规划
|
||
- **affected_files**:
|
||
- docs/art-agent/DECISIONS.md
|
||
- docs/art-agent/TECH-STACK.md
|
||
- **what**: 通过 5 轮结构化讨论确定了美术 Agent 工具的产品决策(产品形态、交互模型、AI 架构、风格管理、资源 Pipeline),并完成全部 8 个维度的技术选型
|
||
- **why**: 项目从零开始,需要先把产品方向和技术基准定下来再动手写代码
|
||
- **decisions**:
|
||
- 产品形态选 Chat-first Web App(排除纯 Bot 和桌面应用)
|
||
- 前端 Next.js / 后端 Python FastAPI / 自建 Agent Loop(不用 LangChain)
|
||
- 数据库 PostgreSQL / 图像生成 Replicate / 部署 Vercel + Railway
|
||
- 对象存储 MVP 先用本地文件系统
|
||
- **notes**: 技术选型中图像生成 API、部署方案、异步任务三项用户未明确选定,采用了推荐方案
|
||
|
||
### [CL-20260411-1600] 2026-04-11 16:00 — 搭建美术 Agent MVP 全部前后端代码
|
||
- **tags**: art-agent, MVP, 前端, 后端, FastAPI, Next.js, Agent Loop
|
||
- **affected_files**:
|
||
- art-agent/README.md
|
||
- art-agent/backend/requirements.txt
|
||
- art-agent/backend/.env.example
|
||
- art-agent/backend/app/main.py
|
||
- art-agent/backend/app/api/chat.py
|
||
- art-agent/backend/app/agent/loop.py
|
||
- art-agent/backend/app/agent/tools.py
|
||
- art-agent/backend/app/services/image_gen.py
|
||
- art-agent/frontend/package.json
|
||
- art-agent/frontend/src/app/page.tsx
|
||
- art-agent/frontend/src/app/layout.tsx
|
||
- art-agent/frontend/src/app/globals.css
|
||
- art-agent/frontend/src/components/chat/chat-messages.tsx
|
||
- art-agent/frontend/src/components/chat/chat-input.tsx
|
||
- art-agent/frontend/src/components/chat/image-grid.tsx
|
||
- art-agent/frontend/src/lib/api.ts
|
||
- docs/art-agent/MVP-PLAN.md
|
||
- **what**: 从零创建了完整的 MVP 前后端代码,包括 FastAPI 后端(Agent Loop + Replicate 图像生成 + SSE 流式推送)和 Next.js 前端(Chat UI + 参考图上传 + 图片下载),后端已验证可正常启动
|
||
- **why**: 以最小流程跑通端到端闭环(对话 → 生图 → 迭代 → 保存),快速暴露集成问题
|
||
- **decisions**:
|
||
- MVP 范围刻意砍掉:数据库/持久化、Skill/Rules 机制、风格库、用户认证、云端部署
|
||
- Agent Loop 硬编码 system prompt,不走 Skill 扩展(最简化)
|
||
- 图像模型选 flux-schnell(快速版),优先验证流程通畅
|
||
- OpenAI 客户端延迟初始化,避免无 Key 时模块加载失败
|
||
- **notes**:
|
||
- 前端使用 Tailwind CSS v4 + PostCSS 配置方式(非 tailwind.config.ts)
|
||
- 参考图在 MVP 阶段仅通过 GPT vision 理解风格后融入 prompt,未直接传给图像模型做 img2img
|
||
|
||
### [CL-20260411-1630] 2026-04-11 16:30 — 完成开发环境搭建和依赖安装
|
||
- **tags**: art-agent, 环境搭建, Node.js, Python
|
||
- **affected_files**:
|
||
- art-agent/backend/venv/
|
||
- art-agent/frontend/node_modules/
|
||
- **what**: 通过 winget 安装 Node.js v24.14.1,创建 Python 虚拟环境并安装后端依赖(9 个包),安装前端 npm 依赖(46 个包),后端启动验证通过
|
||
- **why**: 代码写好后需要实际运行环境来验证
|
||
- **decisions**:
|
||
- Node.js 用 winget 安装 LTS 版本
|
||
- Python 虚拟环境放在 backend/venv/ 下
|
||
- **notes**:
|
||
- 遇到 3 个环境问题已解决:OpenAI 延迟初始化、PowerShell 不支持 &&、脚本执行策略限制
|
||
- 端到端完整测试待用户配置 API Key 后进行
|