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 兼容保留,后者返回相同入口文档。