Files
probably-rendering-one-more…/README.md
T
codex-bot a60d19b3c9
PROMPT Docker CI and deployment / verify-and-deploy (push) Failing after 24m58s
Separate authored canvases from post snapshots and unify linked skill documentation
2026-10-23 11:59:44 +08:00

9.9 KiB
Raw Blame History

PROMPT

仓库名:Probably Rendering One More Pixel Tonight。其余命名使用 PROMPT / prompt。

自己的素材与创作工作台:Next.js Pages Router、React、TypeScript、Tailwind CSS、Node.js 24。中文界面包含瀑布流、日期贡献热力图、素材导入、多媒体详情、分类管理、独立素材架与线条图形工具。没有创建作品的按钮;图文和动态作品由代码实现。

全 Docker 启动

本机只需 Docker Engine / Docker Desktop 和 Compose v2。Node、npm、FFmpeg、迁移程序、网站与后台处理都在镜像里。

cp .env.example .env
# 修改 .env 中的三个密码 / 密钥,不能使用示例值。
docker build --target runtime -t prompt:local .
docker compose --env-file .env up -d --wait postgres objects
docker compose --env-file .env run --rm migrate
docker compose --env-file .env up -d --wait web worker

访问 http://localhost:18131。图片与其他文件保存在 S3 对象卷,文字、分类、素材包引用和任务保存在 PostgreSQL 卷;停止、重建应用容器不会删除这些数据。

容器服务 职责
web Next.js 页面、API、素材上传/读取;宿主机 18131 → 容器 3000
worker FFmpeg 音画分离、封面与音轨处理;没有 HTTP 端口
postgres PostgreSQL 元数据和文字;兼容维护用回环端口 18132
objects RustFS 私有 S3 对象存储;兼容维护用回环端口 18133,控制台关闭
migrate 一次性数据库迁移与对象桶初始化,执行后退出
tests CI 的一次性集成测试执行器,执行后退出

四个常驻服务使用 restart: unless-stopped,Web 和 worker 以非 root 用户运行。worker 通过心跳检查存活;Web 健康检查同时验证当前版本、数据库和 S3。

页面与数据

  • /:所有非空素材包与已注册代码作品,按创建时间倒序;顶部为过去一年的贡献汇总。
  • /images、/videos、/audio:图片、视频、声音收藏。
  • /articles、/motion:代码编写的图文与动态作品。
  • 上述五类路径可以附加标签树路径,如 /images/style/white-line;父分类会包含后代分类的内容。
  • /p/<slug>:素材包的稳定详情地址,不随标签改变。多图切换、多视频及其关联音轨、多声音均可展示。
  • /library/import:导入同一类型的一组文件和说明,自动收为一份收藏。支持最多 16 个文件,单个 250 MB,总计 1 GB。
  • /tools/doodle:手绘线条造型参考,可选色、复制和下载透明 SVG。不是 AI 图片编辑器。

素材库不插入演示或占位帖子。空分类显示简洁的空状态;空素材包不进入任何瀑布流。分页游标由时间与 UUID 组成,重复时间戳下仍稳定。

详细模型见 docs/data-model.md。应用容器通过 Docker 网络的 postgres:5432 和 objects:9000 访问存储,不使用宿主机回环地址。浏览器通过应用访问媒体,支持 Range 分段读取。

视频原件保持不变,后台生成无声 MP4、封面,以及存在声音时的 M4A 音轨。音轨记录在 asset_variants,始终属于原视频;不会生成独立声音资产。后台单任务处理,使用数据库锁领取任务,失败重试三次,支持超时任务恢复。FFmpeg 禁止输入网络协议。

编程加入素材包与作品

POST /api/posts 接收 kind、title、可选 slug、assets: [{id, role?}]、tags: [tagId]、text、coverAssetId 和 pageKey。role 为 content 或 caption。素材和说明文字都可以通过 ID 引用已有资产;text 是创建新文字资产的快捷方式。引用不会复制原文件。

POST /api/tags 接收 name、slug 和可选 parentId。

图文或动态作品需要先在 src/content/registry.tsx 注册 React 组件与类型,再通过 API 创建引用对应 pageKey 的素材包。封面引用普通图片资产。动态作品的 React 组件就是画面本身,不会被强制套入视频播放器。未注册的页面不会出现在瀑布流中,也不会执行数据库中的任意路径或脚本。

当前不内置作品模板或视频导出引擎;后续一起确定设计系统和制作方案。

贡献记录

contribution_events 保存细分的 kind、对象类型、对象 ID、数量、发生时间、元数据和可选幂等键。显示时按上海时区汇总所有类型。当前没有将上传、分类或保存动作自动算作贡献;触发规则留待确定。没有随机或伪造热力图数据。

CI/CD 与生产部署

.gitea/workflows/ci.yml 使用 runs-on: ces-control。依赖安装、类型检查、单元测试、生产构建、启动检查都在 Docker 构建阶段运行。集成测试启动隔离的完整容器栈,并由测试容器请求真实的非 root Web / worker 容器,验证 PostgreSQL、RustFS、上传、共享引用和音画分离。

main 上的 push 或手动运行,在全部检查通过后才发布。测试环境使用独立 Compose 项目、随机端口和随机凭据;测试结束只删除它自己的容器和卷。

生产使用固定 Compose project prompt,复用原有 prompt_postgres_data 和 prompt_objects 卷,以及 /etc/prompt.env 的凭据。由旧部署升级时,发布脚本会停用 prompt.service、prompt-worker.service,由容器接管运行;宿主机无需项目专用的 Node/FFmpeg 进程。旧发布目录留作首次迁移失败时的回退依据。

项目 值
生产运行 Docker Compose:web、worker、postgres、objects
网站端口 18131,映射到 Web 容器 3000
应用镜像 prompt:<commit>;回退使用上一版镜像
发布清单 /opt/prompt/releases/<commit>/compose.yml 和 release.env
当前发布 /opt/prompt/current 原子软链接
密钥 /etc/prompt.env,保留既有凭据,新建时随机生成;不进代码和日志
持久数据 Docker named volumes,不随应用发布删除
数据库备份 /var/lib/prompt/backups,每次发布前备份,保留最近 10 份

发布使用宿主机文件锁串行执行,自动跳过已落后的提交。先备份、迁移,再切换 Web / worker;新版本失败时恢复上一版容器,首次迁移失败时可恢复原先的宿主机服务。生产发布从不执行 down -v。对象卷需要独立快照,数据库 dump 不能代替对象备份。

在服务器上维护当前版本:

cd /opt/prompt/current
sudo docker compose -p prompt --env-file /etc/prompt.env --env-file release.env ps
sudo docker compose -p prompt --env-file /etc/prompt.env --env-file release.env logs --tail 100 web worker
sudo docker compose -p prompt --env-file /etc/prompt.env --env-file release.env exec web node container-health.mjs

GET /api/health 返回应用版本;GET /api/ready 检查数据库与对象存储。

内网与公网访问

172.31.212.211 是服务器内网 IP,不能作为公网入口。Web 端口默认映射为 0.0.0.0:18131:3000;公网访问仍需要实例绑定公网 IP / EIP 或反向代理,并配置相应安全组和防火墙。Docker 化不会使内网 IP 自动变成公网 IP。本项目不会擅自修改云安全组或开放数据库/S3 的公网端口。

独立运行 CI 验证

docker build --target integration -t prompt:tests .
docker build --target runtime -t prompt:local .
PROMPT_IMAGE=prompt:local PROMPT_TEST_IMAGE=prompt:tests bash scripts/integration.sh

整个验证过程无需在宿主机安装 Node.js、PostgreSQL、S3 或 FFmpeg。runner 仅需 Docker Engine、Compose、Git、Bash、flock 和管理 Docker/旧服务所需的权限。

街头小人技能与 Agent 接口

导航「工具 → 技能」打开 /tools/skills,/tools/skills/street-people 包含风格约定、提示词、上传示例和两个独立图包入口。

把 GET /api/skills/street-people 的完整地址交给有绘图工具的 coding agent。GET 返回 JSON 规范,?format=md 返回 Markdown。agent 用自己的绘图能力生成单人透明 PNG,再向同一地址 POST multipart/form-data,字段 files 可重复,title、description、tags 和 slug 可选。网站不调用外部模型,也不需要模型密钥。PNG 必须有真实透明与接近不透明的像素(alpha ≥250),最多 4000 万像素,其余上传数量和大小限制与导入页一致。成功返回 post 地址和可复用素材 ID。

seed/characters 存放本次参考图提取 15 张、新生成测试 4 张及来源说明。部署健康检查后通过 scripts/import-character-packs.mjs 调用真实上传接口写入 PostgreSQL/S3,生成 /p/street-people-reference 与 /p/street-people-original 两个独立 post。已有同 slug 时跳过,重发版不重复导入。原图提取由 imagegen 执行,可能重建细节,并非逐像素无损裁剪。

网页原稿、截图与技能文档

图文笔记中的每张图片拥有独立网页:/p/<slug>/pages/1 至 /pages/8。笔记页展示真实服务器截图,可刷新一张或全部,并单独打开 HTML 原稿。截图由 Docker worker 内 Chromium 生成并存入私有 S3,发布会等待当版全部 24 张截图完成。数据与任务结构见 db/002_page_snapshots.sql,详细行为见 docs/learning-series.md。

工具栏首项为技能;素材库与分类管理页面已移除,已有素材、标签、导入和数据 API 保留。技能使用瀑布卡片,首页也混排展示。

交给 agent 的入口为 /skills/street-people/SKILL.md,后续子文档为 style.md、upload.md、checks.md;纯文本只通过链接引用图片、文档和 API。人类阅读入口 /tools/skills/street-people 和对应子页面使用相同文档数据。右侧资源面板分类收录全部文档、图片和 API,支持预览与打开;不会执行 POST,也不展示与技能流程无关的测试图包。旧 JSON API 和 ?format=md 兼容保留,后者返回相同入口文档。