Files
EPEEAIKit/.cursor/changelog/changelog-full.md

125 KiB
Raw Blame History

Dev Changelog — Full

完整的开发改动记录,按时间倒序排列。作为主动 RAG 的数据源,用户手动唤醒时读取。

记录

[CL-20260420-2237] 2026-04-20 22:37 — 前端一次性铺开文档中心 / 3D / 动作三大功能 UI占位实现 + Phase 2 徽章)

  • tags: 前端, UI, 文档中心, 3D, 动作序列, 命令面板, 工作台, 资源库, 占位实现, Phase 2, react-markdown, model-viewer
  • affected_files:
    • art-agent/frontend/package.json新增 react-markdown@9 / remark-gfm@4
    • art-agent/frontend/src/lib/types.ts扩展 DocNode / DocTabState / View3D / Asset3D / AssetMotion / TaskType / Params3D / ParamsMotion
    • art-agent/frontend/src/lib/placeholder-store.ts新增 docs/assets3D/assetsMotion 的 load/save/upsert/delete + 样本数据 SAMPLE_DOC_*
    • art-agent/frontend/src/lib/app-context.tsx加入 docs/assets3D/assetsMotion/sessionTaskType/commandPaletteOpen 状态与 mutation 回调)
    • art-agent/frontend/src/app/layout.tsx挂载 <CommandPalette /> 全局;<model-viewer>next/script lazyOnload 注入)
    • art-agent/frontend/src/components/layout/top-nav.tsx在「工作台」后插入「文档」Tab带 Phase 1 徽章)
    • art-agent/frontend/src/app/docs/page.tsx新增文档中心三栏页面DocTree + DocTabs + DocEditor + DocOutline
    • art-agent/frontend/src/components/docs/doc-tree.tsx / doc-tabs.tsx / doc-editor.tsx / doc-outline.tsx / markdown-content.tsx / asset-picker.tsx / command-palette.tsx新建
    • art-agent/frontend/src/components/chat/task-type-tabs.tsx新增 2D/3D/动作任务类型切换 Tab
    • art-agent/frontend/src/components/workbench/params-3d.tsx / params-motion.tsx新增 3D / 动作参数条,占位)
    • art-agent/frontend/src/app/page.tsx工作台注入 TaskTypeTabs + 按类型条件渲染 Params3D / ParamsMotionBar
    • art-agent/frontend/src/components/chat/task-card.tsx新增 variant 属性image2d/model3d/motion颜色/图标/专有字段全套切换)
    • art-agent/frontend/src/components/detail/model-3d-panel.tsx新增多视图/360°占位/ 三模式 + 通道切换 + 视图缩略条360° 旋转用 framer-motion rotateY + SVG 替代 styled-jsx 避免多行 className 编译错误)
    • art-agent/frontend/src/components/detail/motion-panel.tsx新增视频/帧序列双模式 + 播放 scrubber + MP4/GIF/帧序列占位下载)
    • art-agent/frontend/src/app/gallery/page.tsx资源库顶部加模态 Tab「图片/3D 模型/动作序列」+ Assets3DGrid / AssetsMotionGrid 两个子组件3D/MOTION 徽章和视角/帧数徽章叠加显示;接 detail 面板)
    • art-agent/frontend/src/components/ui/motion-presets.tssendBounceease: "easeInOut"as const,修预存 framer-motion 类型错误不阻塞 build
  • what: 按用户一次性铺开「文档管理中心(类似 Cursor/ 3D 模型生成 / 动作生成」全部界面元素与交互的要求,用占位实现把所有入口、组件、面板、参数条、徽章与跳转都先打通:
    1. 文档中心:/docs 三栏布局(树/Tab+编辑器/大纲),支持 Markdown textarea 编辑 + react-markdown 预览 + 分屏、[[asset:id]] 资产引用(图片/角色/风格)在正文内渲染为交互卡片、拖拽/重命名/新建/删除、AssetPicker 浮层。
    2. 命令面板Cmd/Ctrl+K 全站 CommandPalette整合导航/动作/文档/图片/角色/风格/会话的统一搜索。
    3. 工作台扩展:任务类型 Tab2D/3D/动作),按类型显示不同参数条(Params3D 含管道/视图数/分辨率,ParamsMotionBar 含模型/帧数/帧率/循环/输出/角色绑定/动作描述);TaskCardvariant 区分颜色/图标/描述/专有字段3D 显示管道+视图数+产物,动作显示帧数+循环+产物)。
    4. 结果详情:Model3DPanel 支持多视图切换color/normal/stylized 三通道 + 视图缩略条)/ 360°占位旋转 / <model-viewer> 模型预览三模式;MotionPanel 支持视频/帧序列双模式 + 播放 scrubber。
    5. 资源库:顶部新增模态 Tab图片/3D 模型/动作序列)+ 计数徽章 + Phase 徽章3D 网格叠 3D 徽章+视角数,动作网格叠 MOTION 徽章+帧数·fps + hover 自动播放视频。
  • why: 用户明确要求"所有功能都先用占位把界面元素和交互实现出来,避免后续反复返工"。选择"一次性完整铺开"策略而非渐进式可让用户在真实管线Mesh Pipeline / 动作生成后端)接入前就能验收完整 UX 流与设计语言一致性,减少后端开发时 UI 的认知负担。
  • decisions:
    • react-markdown + remark-gfm 轻量 textarea 方案(否决 Monaco/TipTap文档场景还不需要代码折叠/语法高亮/WYSIWYG先保持依赖干净
    • 站内 Cmd+K 命令面板统一搜索(否决每页独立搜索:符合 Cursor 风格且跨域跳转一致)。
    • 3D 预览走 <model-viewer> 自定义元素(否决 three.js/react-three-fiber占位阶段用现成自定义元素最省代码真实接入时只需把 asset.meshUrl 换成真实 GLB 路径;用 next/script lazyOnload 避免阻塞首屏)。
    • 动作预览走 HTML5 <video>(否决 GIFmp4 文件更小 + 支持帧擦写GIF 只作下载选项保留)。
    • 「文档」Tab 放 TopNav 第 2 位(「工作台」之后),符合用户对"近 workspace"的访问距离预期。
    • Model3D 面板的 360°预览放弃 styled-jsx CSS 立方体6 face 的 styled-jsx 触发 webpack 对多行 className 的解析错误),改用 framer-motion rotateY 驱动 SVG 六边形,更简洁且不会和 webpack 打架。
  • notes:
    1. 所有新组件均标 phase-chip(文档 Phase 1 / 3D·动作 Phase 2真实链路接入时只需替换 placeholder-store 的 loader 和 upsert* 的写入方向。
    2. <model-viewer> 脚本是从 unpkg lazyOnload 加载,生产环境若断网/被墙 3D 模式会静默降级(只显示占位文案),可在 Phase 2 接入时改为本地打包。
    3. chat-input.tsx 的 framer-motion 类型错误(ease: string 不匹配新版 Easing 联合类型)顺手在 motion-presets.ts 源头用 as const 修掉,npx next build 已通过全绿。
    4. TopNav 的「文档」Tab 是全站入口,新建文档/打开文档走 Ctrl/Cmd+K 也能到,两者使用同一份 docs 状态。
    5. 资源库的 3D / 动作模态下不显示「收藏/标签/视图切换」等图片专属工具栏(条件分支上移到 <main> 内部),避免误导用户这些控件对 3D/动作生效。
  • source_chat: 前端铺开三大功能占位 UI

[CL-20260420-1800] 2026-04-20 18:00 — Mesh Pipeline Phase 3 风格还原接入IP-Adapter + ControlNet

  • tags: 视角变换, Mesh Pipeline, 风格还原, IP-Adapter, ControlNet, Replicate, style_restorer, 后端, services, config, Phase 3
  • affected_files:
    • art-agent/backend/app/config.py
    • art-agent/backend/app/services/style_restorer.py (新增)
    • art-agent/backend/app/services/view_transform.py
    • art-agent/backend/scripts/test_style_restore.py (新增)
    • docs/art-agent/VIEW-TRANSFORM-MESH-PIPELINE-PLAN.md
  • what: 按 SPEC §4 Phase 3 落地 Mesh Pipeline 的阶段 3 — 对 Stage 2 抽出的 normal 帧做 IP-Adapter + ControlNet 重绘,用用户原图做风格参考,输出保留原画风且视角正确的最终图。
  • why: Phase 2 已能稳定产出 color/normal 6 视角帧,但 Trellis 的 color 帧是"半写实"纹理风与用户上传的卡通描边原图风格差异明显。Phase 3 用 chigozienri/ip_adapter-sdxl-controlnet-depth(版本 0436c870...$0.07/张 ~72sL40Simage 字段传原图承担 IP-Adapter 风格参考,controlnet_input 传 normal 帧作为结构约束的 depth 近似(按 SPEC §1.4 一期走"路 A"简化方案,效果不足再升级为 depth-anything-v2 真 depth
  • decisions:
    1. 新模型以 internal=True 注册进 IMAGE_MODELS(而非 VIEW_TRANSFORM_MODELS),理由:它是"普通文生/图生图"模型,只是用在内部流水线;同步改 get_image_models_list() 过滤 internal,避免它出现在前端生图模型下拉
    2. 暴露 get_style_restore_model_id() helper 让 service 层不硬编码短 ID
    3. restore_batch()asyncio.Semaphore(3) 控制并发而非 asyncio.gather 全冲 —— SPEC §5 风险表提示过 Replicate rate limit 风险
    4. 默认参数选 scale=0.75 / controlnet_conditioning_scale=0.8SPEC §2.3 建议范围 0.7-0.8 / 0.7-0.9 的中位偏上),最终值由 P3-4 调参确认
    5. 单帧失败不阻塞整体Stage 3 任一帧失败时自动回退为 Stage 2 的 color 帧返回,前端至少能看到东西;并在该 image 上挂 restyle_error 字段暴露失败原因。这一兜底 + "Stage 2 失败不影响 Stage 1 交付" 形成一致的"阶段独立可交付"设计
  • notes:
    • 成本:一次完整 6 视角请求 ~$0.46Trellis $0.041 + 6 × IP-Adapter $0.07 = $0.461),耗时 ~105s30s 重建 + 并发 3 两轮 × 72s ≈ 75s 风格化)
    • images[i] 新结构:新增 color_url(保留 Stage 2 原图便于前端对比/切换)、restyled 布尔、可选 restyle_error;返回体 _stagestage2 升级为 stage3 (N/M restyled)
    • _note 字段去掉了,错误通过 error 字段聚合(拼接 Stage 2 + Stage 3 错误);_preserve_style_requested 保留供调试
    • Checkpoint 3 脚本 scripts/test_style_restore.py 支持 --single 冒烟($0.07)和全量($0.42),以及 --scale/--cn-scale 临时覆盖参数,便于 P3-4 调参;默认自动挑 generated/ 下最新一组 view_<prefix>_az*_el0_normal.png 作为结构参考
    • P3-4 未完成等用户用真实原图跑调参P4 前端联调将在 Checkpoint 3 通过后开启
  • source_chat: 继续执行 Mesh Pipeline Phase 3

[CL-20260420-1700] 2026-04-20 17:00 — Mesh Pipeline Phase 2 抽帧 + combined_video 左右切分落地

  • tags: 视角变换, Mesh Pipeline, Trellis, combined_video, ffmpeg, imageio-ffmpeg, PIL, 抽帧, 后端, services, Phase 2
  • affected_files:
    • art-agent/backend/app/services/video_frame_extractor.py (新增)
    • art-agent/backend/app/services/view_transform.py
    • art-agent/backend/requirements.txt
    • art-agent/backend/scripts/test_frame_extract.py (新增)
    • docs/art-agent/VIEW-TRANSFORM-MESH-PIPELINE-PLAN.md
  • what: 按 SPEC §4 Phase 2 清单落地。(1) 确认宿主机 ffmpeg 未安装,改用 imageio-ffmpeg==0.5.1 自带的 Windows 静态二进制(ffmpeg-win64-v4.2.2.exe,随 wheel 一起打包 22.6MB免系统依赖venv 已装,requirements.txt 同步写入。(2) 新增 services/video_frame_extractor.py 实现 extract_by_azimuth(combined_video_path, azimuths, elevations=None, total_rotation_deg=360):核心策略采用"一次性把 combined_video 所有帧抽到 generated/_frames_<id>/ 临时目录 + 按 frame_idx = round(az / total_rotation_deg * total_frames) % total_frames 挑帧 + PIL 按中线切左半→color、右半→normal 保存到 generated/view_<batch>_az{az}_el{el}_{color|normal}.png",比逐帧用 -ss 抽更稳(不受 keyframe 对齐影响5s 视频整体成本可忽略;用完即清理临时目录,只保留切好的最终帧。(3) ffmpeg + PIL 是阻塞操作,用 asyncio.get_running_loop().run_in_executor(None, _do_extract, ...) 丢到默认线程池跑,避免堵住 FastAPI 事件循环。(4) services/view_transform.py_transform_view_mesh 在 Stage 1 成功后串接 Stage 2——默认 azimuths=[0,60,120,180,240,300](从模块级常量 DEFAULT_MESH_AZIMUTHS 读取),elevations 缺省或长度不足补 0、超长截断保证与 azimuths 对齐;调用 video_frame_extractor.extract_by_azimuth(combined_video_path=stage1["combined_video_path"], ...) 得到 frames[{az, el, frame_idx, color_png, normal_png}];把 images 填为 [{url: color_png, azimuth, elevation, normal_url: normal_png, frame_idx}]Stage 2 失败把整体置为失败Stage 1 的 mesh/video 仍有交付价值),单独在返回 dict 的 error 字段带回 Stage 2 错误信息,success 同时要求 stage1 成功 + Stage 2 无 error。(5) 新增 scripts/test_frame_extract.py 供用户 Checkpoint 2 验收:默认取 generated/ 下最新的 trellis_combined_*.mp4 做输入(不需要再花钱跑 Trellis),调用 video_frame_extractor.extract_by_azimuth 抽 6 视角,打印每帧的 color_png/normal_png URL + 本地文件大小,并提示用户目视检查。(6) SPEC 文档 P2-1 ~ P2-4 全部打勾、追加本次会话的进度 note含 Agent 自测结论)。
  • why: SPEC §4 "每个 Phase 完成后停下来让用户测试/审阅"Phase 2 是用户能看到"可见结果"的第一步——Phase 1 只能交付一个 .glb + 一个 mp4 视频用户很难一眼判断是否正确Phase 2 交付 6 张方位角明确的方形图后,用户可以直接目视环绕教堂一周。抽帧方案故意选"一次抽全 + 按索引挑"而不是"每帧一次 -ss 快进",是因为:(a) combined_video 约 5s/120 帧,总 PIL+ffmpeg 开销 ~1-2s比 6 次 -ss (每次 ffmpeg 启动 ~300-500ms) 更快;(b) -ss 在 GOP 长的 mp4 上会对齐到最近 keyframe取帧索引可能不精确(c) 代码简单、debug 时看临时目录文件序号就能对应帧。Stage 2 失败不牵连 Stage 1是考虑到"抽帧失败"通常意味着 ffmpeg 或视频本身异常,但用户可能仍想拿 .glb 做手动检视——与其整体 fail不如降级返回部分产物 + 明确 error。测试脚本用已有 combined_video 是故意为之Checkpoint 2 的重点是验证抽帧+切图的正确性,不是再验证一遍 Trellis没理由让用户多花 $0.041。
  • decisions: (1) ffmpeg 方案:首选 imageio-ffmpeg 而不是让用户 choco install ffmpeg,因为 SPEC §5 风险栏就列了 "Windows ffmpeg 未装" 是高概率风险imageio-ffmpeg 的 pip wheel 自带 Win64 二进制是零摩擦方案;代价是 wheel 22.6MB + 每次 Python 启动查找二进制(成本可忽略)。(2) 返回 schema:给 mesh 管道的 images[i] 加了 normal_urlframe_idx 字段而不是单独的 frames 列表——这样前端不用改 schema 就能显示(url 仍是最终要展示的彩色图),同时 Phase 3 可以直接读 normal_url 作为 controlnet_input。(3) elevation 字段保留但忽略combined_video 本身是水平平视一圈,elevation != 0 在 Phase 2 无意义(所有帧 el 都是 0但保留字段为 Phase 5 自由相机路径预留;当前传 elevations=[30,30,...] 也不会报错,只是结果图的 el 字段被原样记录、帧内容仍是水平视角(有心理预期即可,未来 renderer 路径会真正使用)。(4) 临时目录策略:抽帧到 generated/_frames_<8位hex>/ 而不是系统临时目录,是因为后者在 Windows 跨盘符时可能慢;前者失败时也留现场方便 debug。完成后的清理用 try/except OSError 兜底,即使 PIL 占着句柄也不会报错退出。(5) DEFAULT_MESH_AZIMUTHS 提到模块级:下 Phase 4 前端会暴露"快速预设 6/8/12 视角"选项,这里先把默认值拎出来便于配置扩展;目前命名为 6 视角Phase 4 再考虑增加 8/12。
  • notes: (1) Stage 2 路径依赖 stage1 的 combined_video_path 键名(非 color_video_path)——这是 Trellis 部署版 e8f6c452... 的实测事实PF-20260420-1600不要以为 Phase 1 的字段 color_video_path 有值;现在该字段仍然返回但恒为 None_transform_view_mesh 里优先读 combined_video_path。(2) 前端目前仍不会自动展示 mesh 管道结果 ——loop.py 只在 result.get("images") 非空时发 image_result 事件Phase 2 让 images 有值了,所以前端应该能看到 6 张;但 Phase 4 才正式端到端联调Phase 2 的建议验收入口仍是 scripts/test_frame_extract.py 而不是 UI。(3) normal 帧的 url 在前端目前是"隐藏字段"——images[i].normal_url 前端 types.ts 里没这个字段会被丢弃Phase 3 接入时 view_transform 会改为把重绘后的图填到 urlnormal 帧继续作为中间产物留在磁盘上。(4) 预留的 preserve_style 参数当前不生效,返回 dict 的 _preserve_style_requested 字段记录了用户意图——Phase 3 会根据这个开关分流True 走 ControlNet 重绘、False 直出 color 帧)。(5) Agent 自测结果2026-04-20 17:05test_frame_extract.pytrellis_combined_290da12de954.mp4 运行,抽出 120 帧az=[0,60,120,180,240,300] 分别映射到 frame_idx=[0,20,40,60,80,100](每 60° = 20 帧完全均匀12 个 PNG 全部落盘,单张尺寸 512×512 方形(说明原 combined_video 是 1024×512 左右并排)。自测不能替代用户目视检查 "6 张 color 图是否按 0°→300° 顺序环绕建筑一圈"Checkpoint 2 必须由用户拍板。(6) 用户验收流程:(a) 在 art-agent/backend 激活 venv(b) 跑 python scripts/test_frame_extract.py(默认取 generated/ 最新 trellis_combined也可 python scripts/test_frame_extract.py generated/trellis_combined_<hash>.mp4 指定);(c) 终端应打印 6 个 color_png + 6 个 normal_png 均 OK,每个 size > 0(d) 打开 generated/view_*_az0_el0_color.png ~ view_*_az300_el0_color.png 6 张图,验证是同一建筑从 6 个均匀角度绕一圈的视角;(e) normal 图是蓝紫调法线图,可抽 1-2 张抽查。通过后开 Phase 3。
  • source_chat: 本次会话 "继续执行 Phase 2"

[CL-20260420-1600] 2026-04-20 16:00 — Mesh Pipeline Phase 1 接入 Trellis视角变换第二条管道落地阶段 1

  • tags: 视角变换, Mesh Pipeline, Trellis, Replicate, 后端, services, config, tools, Phase 1
  • affected_files:
    • art-agent/backend/app/services/mesh_generator.py (新增)
    • art-agent/backend/app/services/view_transform.py
    • art-agent/backend/app/config.py
    • art-agent/backend/app/agent/tools.py
    • art-agent/backend/scripts/test_trellis.py (新增)
    • docs/art-agent/VIEW-TRANSFORM-MESH-PIPELINE-PLAN.md
  • what: 按 SPEC §4 Phase 1 清单落地。(1) 新增 services/mesh_generator.py,封装 generate_with_trellis(image_path, params=None) 和统一入口 generate_mesh(image_path, model_id),调用 firtoz/trellis:e8f6c452... 并把 model_file/color_video/normal_video/combined_video 挨个 httpx 下载到 GENERATED_DIR,以 trellis_*_<uuid>.{glb,mp4} 命名,返回 /generated/... 本地 URL。(2) config.pyVIEW_TRANSFORM_MODELS 新增 trellispipeline=mesh, enabled=Truehunyuan3dpipeline=mesh, enabled=False 占位),给原 zero123plus 条目补 pipeline=gridget_view_transform_models_list 改为只返回 enabled 条目 + 带上 pipeline 字段。(3) services/view_transform.py 改为按 pipeline 字段分流——grid 走原 Zero123++ 逻辑(逻辑未动,仅输出字段补齐 pipeline/mesh_url/color_video/normal_videomesh 走新增 _transform_view_mesh():当前阶段只跑 mesh_generator 返回 .glb + color_video + normal_video 本地 URLimages 列表留空,附 _stage="stage1"_note 标记 Phase 2/3 未接入。(4) tools.pytransform_view 工具定义扩三个参数 model_id (enum: zero123plus/trellis, default zero123plus) / azimuths / preserve_style,执行侧把这些参数透传给 transform_view()。(5) 新增 backend/scripts/test_trellis.py 作为 Phase 1 独立验收脚本——默认用 uploads/ 下最新 png、支持命令行指定路径、自动加载 .env、调用 mesh_generator.generate_with_trellis 后检查本地文件大小。(6) SPEC 文档 P1-1 ~ P1-5 打勾并追加进度 note。
  • why: SPEC 明确要求"按 Phase 顺序推进,每个 Phase 完成后停下来让用户测试/审阅"Phase 1 是整条 Mesh Pipeline 的地基——验证 Replicate Trellis 调用通道是否打通、文件下载策略是否正确、与现有 grid 管道并存不互相干扰。把 mesh_generator 独立成模块是为后续 Phase 2/3/5 解耦Phase 2 只需读 color_video_path/normal_video_pathPhase 3 只需消费 images 列表Phase 5 切到 Hunyuan3D-2 时只需替换 generate_mesh 的分支。测试脚本独立走 asyncio 是因为 Phase 1 还没接到工具链,用户需要一个"最小能跑"的入口先确认 API 本身可用SPEC P1-5 也是这么要求的)。
  • decisions: (1) view_transform 返回结构升级为同时带 grid_image/mesh_url/color_video/normal_video/pipeline 字段,两种管道缺省位补 None——比"两种完全不同的返回 schema"更利于前端和 loop.py 后续统一处理。(2) Phase 1 当前故意让 mesh 管道的 images 为空 + 带 _note 说明,而不是硬拼一个"只返回视频"的假结果——这样 Phase 2 接入时 frontend 的 "没有图片显示" 现象会被替换为 "6 张图片显示",语义更清晰。(3) hunyuan3d 提前注册但 enabled=False,避免用户在前端误选到二期才启用的路径;get_view_transform_models_list 同步过滤 enabled。(4) mesh_generator._to_url 做了 FileOutput → str 的显式转换兜底,因为 Replicate SDK 的字典输出里每个字段可能是 FileOutput 对象而不是裸字符串 URL——这点在 image_gen.py 的 ReplicateProvider._download 已经吃过亏,这里主动规避。(5) _download_asset 的 httpx 超时放到 300s因为 color_video ~3-5MB 在国内网络可能慢;复用项目既有的 HTTPS_PROXY 注入模式。
  • notes: 本次改动完全不触碰 Zero123++ 现有流程——grid 管道所有行为保持 byte-level 等价,只是返回字典多了几个 None 字段,loop.py 和前端已有代码没事。但还未修改 loop.py 的 SSE 事件处理:当前 loop.py 只在 tool_name == "transform_view" and result.get("images") 时发 image_resultmesh 管道 Phase 1 的 images=[] 会让 loop.py 不发事件,前端看到空结果——这是预期行为Phase 1 的测试入口是 scripts/test_trellis.py 而不是前端。Phase 2 接入后 images 有值loop.py 无需改动即可工作。用户验收流程:(a) 在 art-agent/backend 激活 venv(b) 跑 python scripts/test_trellis.py(默认取 uploads/ 最新 pngpython scripts/test_trellis.py uploads/<hash>.png 指定图;(c) 等 ~30-60s 看终端打印 glb_path/color_video_path/normal_video_path 均为 /generated/trellis_*... + 本地大小 > 0(d) 可选:去 backend/generated/ 目录用系统播放器看 color_video.mp4 是否为 360° 环绕教堂视频。验收通过后我再开 Phase 2ffmpeg 抽帧)。
  • source_chat: 本次会话 "按计划实施 Mesh Pipeline"

[CL-20260420-1530] 2026-04-20 15:30 — 写入 Mesh-Pipeline 视角变换方案 SPEC跨会话实施计划

  • tags: 视角变换, Mesh Pipeline, Trellis, Hunyuan3D-2, ControlNet, IP-Adapter, SPEC, 方案设计, 建筑, 跨会话
  • affected_files:
    • docs/art-agent/VIEW-TRANSFORM-MESH-PIPELINE-PLAN.md
  • what: 新增一份完整的实施计划 SPEC规划 Zero123++ 之外的第二条视角变换路径——Mesh Pipeline。三段式流水线(1) Trellis/Hunyuan3D-2 单图生 mesh + 360° color_video(2) ffmpeg 从 color_video 抽指定 azimuth 的帧(一期方案,免 pyrender(3) chigozienri/ip_adapter-sdxl-controlnet-depth 做 SDXL+ControlNet-Depth+IP-Adapter 二次重绘,用原图保持卡通描边风格。文档含:三个 Replicate 模型的精确版本 ID + OpenAPI schema、config.py 扩展设计、伪代码管道、6 个 Phase 的可独立执行任务清单(每个 Phase 有独立验收标准)、风险兜底、成本预估(~$0.46/~105s、跨会话恢复指引。
  • why: 用户反馈 Zero123++ 只能出 6 个固定视角 + 建筑大角度偏转一致性差。用户选定重流水线P1-P3 全做),明确要求"保留 2D 卡通风格"+"自包含跨会话执行"。调研中发现Trellis ($0.041/30s 自带 color_video) 比 Hunyuan3D-2 ($0.12/127s 仅 mesh) 快 4× 便宜 3×一期走 Trellis 还能省掉自定义渲染模块。把 Hunyuan3D-2 路线拆进 Phase 5二期可选工程量从 ~9h 降到 ~5h。
  • decisions: 主选 Trellis 而非 Hunyuan3D-2——以便一期完全跳过 pyrender/blender 渲染器(用 ffmpeg 抽帧替代)。阶段 3 的 ControlNet 结构约束用 normal_video 抽帧Trellis 送的),不先走 depth-anything-v2省一次 API 调用不完美但足够。Hunyuan3D-2 + pyrender 自由相机留作 Phase 5 可选。不在一期解决 elevation 仰俯视角Trellis color_video 只给水平环绕),那是 Phase 5 的事。
  • notes: 文档位置 docs/art-agent/VIEW-TRANSFORM-MESH-PIPELINE-PLAN.md。下一个会话开工时 Agent 需先读 §0-§3 建立背景,再按 §4 Phase 顺序推进,每 Phase 交付后停下来让用户验证。文档底部有"进度日志"章节,每个 Phase 完成后在 checkbox 打勾 + 追加 note。未修改任何业务代码纯 SPEC 文档。
  • source_chat: 本次会话排查 Zero123++ 切图错位 meta-bug + 后续方案调研

[CL-20260420-1501] 2026-04-20 15:01 — 后端增加 watchfiles 依赖,修复 Windows uvicorn --reload 失效

  • tags: uvicorn, watchfiles, 热重载, Windows, FastAPI, requirements, 依赖管理, reload, Zero123++
  • affected_files:
    • art-agent/backend/requirements.txt
    • art-agent/backend/requirements-lock.txt
  • what: 在 requirements.txtrequirements-lock.txt 中显式加入 watchfiles==0.24.0,并在当前 venv 中安装。这让 uvicorn --reload 使用 WatchFiles 作为 reloader 后端,而不是无依赖时的 StatReload 轮询回退。
  • why: 用户反馈 Zero123++ 切图错位——但 CL-20260420-1212 里做的 cols=2/rows=3 修复和 _split_grid_image 自动纠错逻辑在磁盘上明明是新版,独立调用也能切出正确的 320×320。进一步排查发现后端 uvicorn 进程是 11:55 启动、从未 reload而 venv 里 watchfiles/watchdog 均未安装——StatReload 在 Windows + 深层子目录 + 新建文件 (view_transform.py 是 untracked 新增) 的叠加场景下几乎完全失效,所以代码改了但运行时还是老版本。这一层 meta-bug 如果不治本,以后每次改后端都要手动重启。
  • decisions: 选择 watchfilesuvicorn 官方推荐、跨平台 Rust 实现、依赖最轻)而不是 watchdog(历史包袱更重)。版本锁 0.24.0 与 Python 3.12 兼容良好且 uvicorn 0.44.0 默认识别。未添加 --reload-dir app 参数到 project-launcher Skill 的启动命令里——先靠装依赖覆盖主要场景,如果未来仍有监听遗漏再显式限定目录。
  • notes: 仅装依赖不重启当前 uvicorn 进程不会生效,因为旧进程已经绑定到 StatReload。需要 kill PID 28172 并重启一次后端,之后所有代码改动才会自动 reload。启动日志里应该能看到 Started reloader process [xxx] using WatchFiles,如果仍是 StatReload 说明 watchfiles 没正确安装到当前 venv。踩坑已记录 PF-20260420-1501。
  • source_chat: 本次会话排查 Zero123++ 切图错位 meta-bug

[CL-20260420-1212] 2026-04-20 12:12 — 修复 Zero123++ 视角切图布局反转导致的图像错位

  • tags: Zero123++, 视角变换, 切图, bug修复, grid_layout, PIL, Replicate, view_transform
  • affected_files:
    • art-agent/backend/app/config.py
    • art-agent/backend/app/services/view_transform.py
  • what: 修复 transform_view 输出的 6 张视角图严重错位的问题。config.py 里的 VIEW_TRANSFORM_MODELS["zero123plus"].grid_layout{"cols": 3, "rows": 2} 改为 {"cols": 2, "rows": 3},与 jd7h/zero123plusplus Replicate 实际输出(高图布局)一致。同时在 view_transform._split_grid_image 加入"按实际图像长宽比自动纠正 cols/rows"的健壮性保护:假定每个单视角为正方形,若配置的 cols/rows 与图像实际 w/h 差异超过 20%,自动交换 cols/rows 并记录 warning。
  • why: 用户反馈视角变换后的切图全部错位(窄长条、上下拼两个物体)。根因是 Zero123++ 官方 README 写 "3×2 grid" 但实际 Replicate 部署版输出的是 2 列 × 3 行高图config 里按"3 列 × 2 行"配置cell_w/cell_h 算反了。加上动态纠错是为了未来换其他 view transform 模型时不再重复踩这个坑。
  • decisions: 选择"修 config + 加运行时自动纠错"而非仅修 config。纯改 config 能解决眼前问题但无法防御未来模型切换;加动态纠错的代价只是一段 if 判断+warning 日志,换取对"布局文档歧义"场景的整体免疫。放弃了更激进的"用 PIL 探测内容块边界"方案,因为对有微量白边/噪声的模型不稳定。
  • notes: uvicorn 以 --reload 方式运行,改完自动重载,无需重启服务。用户需要在前端重新触发一次视角变换来验证切图是否正确。对应踩坑记录已写入 .cursor/pitfalls/pitfalls.md (PF-20260420-1212)。
  • source_chat: 本次会话启动项目并调试 Zero123++ 切图

[CL-20260417-1510] 2026-04-17 15:10 — Cloudflare Quick Tunnel 脚本修复PS5.1 编码 + 本地 cloudflared

  • tags: 内网穿透, cloudflared, PowerShell, start-tunnel, UTF-8, gitignore
  • affected_files:
    • art-agent/start-tunnel.ps1
    • .gitignore
  • what: 修复 start-tunnel.ps1 在 Windows PowerShell 5.1 下因脚本 UTF-8 无 BOM、含中文的 here-string@")被误解析而导致的 ParserError。将写入 frontend/.env.local 的两处 here-string 改为 [System.IO.File]::WriteAllLines + UTF-8 无 BOM与 Next 读取 .env 习惯一致)。用 PowerShell 将脚本全文重写为 UTF-8 BOM,便于 PS5.1 正确分词。在脚本开头增加:若存在与脚本同目录的 cloudflared.exe,则把该目录插入 PATH 最前,便于未全局安装 cloudflared 时使用本地下载的可执行文件。根目录 .gitignore 增加 art-agent/cloudflared.exe,避免误提交约 65MB 二进制。
  • why: 用户请求开启穿透时,脚本在 Cursor 集成终端中立即解析失败,隧道无法拉起;当前环境亦未必安装 winget/系统 PATH 中的 cloudflared需要可放置于项目目录的 fallback。
  • decisions: 不改为仅英文输出(保留原有中文提示与框线字符);.env.local 注释改为英文短句以避免无 BOM 环境下再次出现字符串边界问题。
  • notes: 会话中曾从 GitHub latest release 下载 cloudflared-windows-amd64.exeart-agent/cloudflared.exe 并成功启动双隧道;该文件已被 gitignore。

[CL-20260417-1500] 2026-04-17 15:00 — 按 INFOLAYER.md 实现完整前端信息架构Phase 1+ 占位骨架)

  • tags: 前端, UI骨架, INFOLAYER, 多项目, 风格库, 角色库, 训练中心, 项目设置, TaskCard, 候选评估, 占位数据
  • affected_files:
    • art-agent/frontend/src/lib/types.ts
    • art-agent/frontend/src/lib/placeholder-store.ts
    • art-agent/frontend/src/lib/app-context.tsx
    • 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/styles/page.tsx
    • art-agent/frontend/src/app/styles/[id]/page.tsx
    • art-agent/frontend/src/app/characters/page.tsx
    • art-agent/frontend/src/app/characters/[id]/page.tsx
    • art-agent/frontend/src/app/training/page.tsx
    • art-agent/frontend/src/app/training/[id]/page.tsx
    • art-agent/frontend/src/app/training/new/page.tsx
    • art-agent/frontend/src/app/settings/page.tsx
    • art-agent/frontend/src/components/layout/top-nav.tsx
    • art-agent/frontend/src/components/layout/project-switcher.tsx
    • art-agent/frontend/src/components/sidebar/sidebar.tsx
    • art-agent/frontend/src/components/sidebar/project-card.tsx
    • art-agent/frontend/src/components/chat/session-quick-picks.tsx
    • art-agent/frontend/src/components/chat/task-card.tsx
    • art-agent/frontend/src/components/workbench/advanced-controls.tsx
    • art-agent/frontend/src/components/workbench/candidate-panel.tsx
  • what: 按 docs/art-agent/INFOLAYER.md 规范一次性铺开 Phase 13 产品形态的前端 UI 骨架:新增风格库 /styles、角色库 /characters、训练中心 /training、项目设置 /settings 四大页面模块(含列表 + 详情 + 创建流程);工作台输入区上方加入风格/角色/资产规格快选条、高级控制抽屉、候选评估侧面板、Task Card IR 占位组件;资源库新增资产类型/风格/角色多维过滤和语义搜索切换TopNav 扩充导航项与项目切换器Sidebar 加入项目信息卡;新增 lib/placeholder-store.ts 管理 Phase 1+ 占位数据(项目/风格集/角色卡/训练任务)并在 app-context.tsx 中统一暴露;globals.css 补充 phase-chip / placeholder-card / hide-scrollbar / section-divider 工具类。
  • why: INFOLAYER.md 规划了 Phase 03 完整产品形态,其中 Phase 1+(多项目、风格库/角色库、训练中心、Task Card、候选评估等尚未具备后端能力。用户希望先把完整交互结构和界面落地"数据或展示上写占位"即可,方便内部演示、收集反馈以及后续按 Phase 增量接入真实后端。
  • decisions: (1) 占位数据用独立的 placeholder-store.ts + localStorage 持久化,与现有 store.ts 解耦首次加载注入示例数据2 个项目 / 4 个风格集 / 2 个角色 / 4 个训练任务)。(2) 详情页直接用 [id]/page.tsx 同时处理 new 与编辑两种模式(判断 params.id === 'new'),不再新增 /styles/new 等专用子路由。(3) Task Card 作为独立可复用组件 (components/chat/task-card.tsx),不强制接入当前 chat loop等真实 IR 管线就绪时再 wire up。(4) 候选评估面板从"最后一条含 images 的 assistant 消息"取数据做 demo。(5) Gallery 风格/角色过滤用 prompt 关键词子串匹配做占位,未来等后端补 asset 归因字段后再切到真实字段。(6) 所有 Phase 1+ 功能按钮均挂 phase-chipP1/P2/P3明示阶段避免用户误以为已可用。
  • notes: 所有"应用到会话""Fork""训练""批量下载"等交互都是 alert("(占位)..."),不产生真实后端调用;真实接入时搜索 (占位)phase-chip 可快速定位需要替换的位置。AppContext 新增字段:projects / activeProjectId / stylePacks / characters / trainingTasks / sessionStyleId / sessionCharacterId / sessionAssetSpec 及对应 upsert/delete 方法;切换用户时会重新加载全部占位数据。/styles/[id]/characters/[id] 的"生成图片"列表也是基于关键词从现有 assets 里筛的占位结果,不是真正的归因。ChatMessage 未扩展Task Card 目前仅以组件形式存在,实际渲染位置需要后续决定(工作台消息流或独立抽屉)。
  • source_chat: 实现 INFOLAYER 完整 UI 骨架

[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 横向流动 2pxAI 活动时出现在输入栏上方,生图时加速
    • 用户消息改为右对齐渐变背景+右上切角,助手消息改为 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 增量约 50KBframer-motion
  • source_chat: 交互体验全面升级

[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.jsongitignored。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.jsongitignored+ .cursor/local-env.example.jsontracked 模板)的模式,类似 .env / .env.example 的惯例hooks.json 的跨平台靠为每个 hook 提供 .ps1 和 .sh 双版本
  • notes: hooks.json 的 command 字段本身仍需按平台手动调整Windows 用 powershellmacOS/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_MODELSid 分发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"typeimage/ 开头时才 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=60sRemoteProtocolErrorConnectErrorRead/Write/Connect/PoolTimeout 最多重试 3 次、间隔 1s/2s可通过 VECTORENGINE_GEMINI_READ_TIMEOUT 等环境变量覆盖;.env.example 增加注释说明
  • notes: 若仍频繁断连,需排查代理 idle 超时或向量引擎侧限流;用户可暂时换 GPT Image 1.5 对比
  • source_chat: Gemini断连重试

[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: 拖拽覆盖层卡住修复

[CL-20260416-0700] 2026-04-16 07:00 — 新增 GeminiNativeImageProviderGemini 原生 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 响应中同时处理 inlineDatacamelCaseinline_datasnake_case两种字段名因为向量引擎中转可能改变命名风格
  • notes:
    • Provider 注册表现有三个:replicateopenaigemini_native,分发逻辑无需改动
    • generate_images 中 Replicate 独有的"无参考图报错"逻辑已有 provider_name == "replicate" 限定Gemini 无参考图时正常走纯文生图
    • API key 复用 VECTORENGINE_API_KEYbase_url 从 VECTORENGINE_BASE_URL 推导(去掉 /v1 后拼 /v1beta/...
  • source_chat: Gemini原生Provider实现

[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-previewprovider 为 openai
  • why: 用户希望使用 Google Gemini 3.1 Flash 的原生生图能力,速度快价格低
  • decisions: 复用已有的 OpenAIImageProvider向量引擎中转兼容 OpenAI images/generations 端点),零代码改动
  • notes: 如向量引擎对 Gemini 生图的返回格式有差异(如只返回 b64 不返回 URLOpenAIImageProvider 已兼容两种格式

[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/dropdrop 时调用 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-Adaptersupports_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 providermodel_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: 接入向量引擎中转 APIOpenAI 兼容格式),实现对话级 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 45sinset 负值防漂移露白
    • .glow-border hover 效果conic-gradient 弧段从 20% 扩大到 40-50%(更柔和),旋转从 3s 减慢到 6sblur 从 6px 增到 12pxtransition 从 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 HoudiniChrome 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 初始化时序

[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-cffipwdlib 提供与 passlib 类似的统一接口,同时内置 BcryptHasher 兼容已有旧哈希。新密码一律 Argon2id旧 bcrypt 哈希仍可验证(过渡期)
  • notes: 已有 admin 用户的 bcrypt 哈希无需迁移,下次改密时自动升级为 Argon2id 格式。不再需要锁定 bcrypt 版本
  • source_chat: 替换 passlib 为 pwdlib

[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 兼容性

[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:
    • SQLitedata/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 响应自动跳转 /loginXHR上传和 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 钳位clampscrollHeight - 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存在时序竞争useEffectrequestAnimationFrame 执行时 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 — 修复多会话滚动位置共享 bugper-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 记忆系统集成

[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-AdapterCL-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 切到 KolorsLLM 在回复中仍声称使用旧模型。根因是 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 APIhover 显示 + 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=60wait=False:不发 Prefer: wait headercreate 请求立即返回 prediction IDSDK 自动进入 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.5sint(n) = Prefer: wait={n} + read={n+0.5}sn 必须 1-60False = 不等待、纯轮询。对慢模型InstantStyle ~128s配合大 payload1.6MB base64wait=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 + ReadTimeoutwait 参数超限与 SDK 内部 timeout 覆盖

  • tags: bug修复, Replicate, InstantStyle, API参数, async_run, Prefer header, timeout
  • affected_files:
    • art-agent/backend/app/services/image_gen.py
  • what: 修复 InstantStyle 生图 422Prefer: wait=x must be 1-60)和后续 ReadTimeout61.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=60API 允许的最大 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.5sint(n) = Prefer: wait={n} + read={n+0.5}sn 必须 1-60False = 不等待。对慢模型用 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: 在模型注册表中新增 InstantStylejyoung105/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-4oLLM 可直接看图描述风格,此约束自动失效(走 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_outputsKolors 用 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_resulttool_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 中补全版本 hashfofr/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: 之前工具调用失败时,错误信息只传回给 LLMLLM 会自行"翻译"错误(如说成"速率限制"),用户无法看到真实报错,排查困难。典型场景:使用 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 而非 fetchfetch 不支持 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:

[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 支持短 IDflux-schnell和完整 Replicate IDblack-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:
    • 数据持久化使用 localStorageMVP 阶段),后续可迁移到后端数据库
    • 全局状态管理使用 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 后进行