init:初始化项目

This commit is contained in:
2026-04-07 15:21:27 +08:00
commit 1b494b6029
366 changed files with 11461 additions and 0 deletions
Binary file not shown.
Binary file not shown.
+163
View File
@@ -0,0 +1,163 @@
# popiartServer 薄膜持久化设计
这份文档描述当前的轻量化持久化方案。目标不是把 `popiartServer`
做成第二个模型平台,而是让它只保存 PopiArt 自己的产品语义。
## 设计原则
`PopiNewAPI` 已经负责:
- 上游 provider key
- 模型请求
- 原始用量
- 一部分任务型能力的 task 状态
所以 `popiartServer` 不再重复持有:
- 本地 artifact blob store
- 本地 artifact metadata table
- 本地 job_logs table
它只保留三类本地状态:
- `sessions`
- `jobs`(更准确说是 job refs
- `skill_routes`
## 当前关系
```text
session -> jobs
jobs -> result_refs_json
project -> skill_routes
```
其中:
- `session` 保存 PopiArt 登录态和对应的 `PopiNewAPI token`
- `jobs` 保存 skill 语义、用户归属、上游引用和同步结果引用
- `result_refs_json` 保存同步能力的返回引用,例如 `data_url` 或远端 `url`
- `skill_routes` 保存项目级路由覆盖
## 存储位置
默认配置来自这些环境变量:
- `POPIART_DATA_DIR`
- `POPIART_SQLITE_PATH`
- `POPIART_SESSION_SECRET`
默认值:
```text
POPIART_DATA_DIR=./data
POPIART_SQLITE_PATH=./data/popiart.db
```
## Repository 接口
代码位置:
- `internal/server/repository.go`
当前只保留三层 repository
1. `SessionRepository`
2. `JobRepository`
3. `RouteRepository`
没有单独的 blob storage 抽象。
## SQLite Schema
### sessions
```sql
CREATE TABLE sessions (
session_id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
user_json TEXT NOT NULL,
token_enc BLOB NOT NULL,
token_masked TEXT NOT NULL,
created_at TEXT NOT NULL,
expires_at TEXT NOT NULL
);
```
### jobs
```sql
CREATE TABLE jobs (
job_id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
session_id TEXT,
project_id TEXT,
skill_id TEXT,
route_key TEXT,
model_id TEXT,
exec_mode TEXT NOT NULL,
newapi_task_id TEXT,
status TEXT NOT NULL,
input_json TEXT NOT NULL,
result_refs_json TEXT,
usage_json TEXT,
error_json TEXT,
idempotency_key TEXT,
created_at TEXT NOT NULL,
started_at TEXT,
finished_at TEXT,
UNIQUE(user_id, idempotency_key)
);
```
### skill_routes
```sql
CREATE TABLE skill_routes (
route_key TEXT NOT NULL,
scope_key TEXT NOT NULL,
model_id TEXT NOT NULL,
options_json TEXT,
updated_at TEXT NOT NULL,
PRIMARY KEY(route_key, scope_key)
);
```
## 运行时流程
### 登录
1. CLI 把 `PopiNewAPI token` 交给 `popiartServer`
2. `popiartServer``/v1/models` 验证 token
3. server 签发本地 `sess_xxx`
4. 本地 session 持久化到 SQLite,重启后仍可继续使用
### 创建 job
1. server 解析 `skill_id -> route_key -> model_id`
2. `jobs` 表写入一条本地 job ref
3. goroutine 开始向 `PopiNewAPI` 发请求
### 完成同步结果 job
1. 如果 `PopiNewAPI` 直接返回同步结果,例如 `b64_json``url`
2. `popiartServer` 只把它转换成 `result_refs_json`
3. `GET /jobs/:id/artifacts` 时再从 `result_refs_json` 派生 artifact 列表
### 拉取 artifact
1. server 从 `artifact_id` 反推出 `job_id + result index`
2. 读取 `jobs.result_refs_json`
3. 如果是 `data_url`,直接解码并流式返回
4. 如果是远端 `url`server 代理下载并返回
## 当前边界
- server 重启后:
- `session` 会保留
- `job ref` 会保留
- `artifact` 通过 `result_refs_json` 继续可读
- 已存在的 `pending/running` job 仍然不会自动恢复执行
- 视频类 `upstream_task` 路径只预留了字段,后续再接 `PopiNewAPI` task 查询
- 对同步图像结果来说,`data_url` 仍然会落在 SQLite 的 `result_refs_json`
这是当前 `PopiNewAPI` 没有统一 file id 的现实折中,但已经不再有本地 artifact 表和 blob store
+107
View File
@@ -0,0 +1,107 @@
# PopiArt 项目关系
这份文档用于说明 `popiartcli``popiartServer``PopiNewAPI` 三个项目之间的职责边界、调用链路和联调顺序。
同一份文档会分别放在三个仓库中,目的不是重复维护,而是让开发者在任何一个仓库里开始工作时,都能先看到完整上下文,避免把职责放错层。
## 三个项目分别做什么
| 项目 | 角色 | 应该负责 | 不应该负责 |
|---|---|---|---|
| `popiartcli` | 面向 coding agent 和创作者的统一 CLI 入口 | 登录、发现 skill、调用 skill、查看 jobs、拉取 artifacts、本地配置 | 不直接持有上游 provider key,不直接做模型路由,不直接做供应商计费 |
| `popiartServer` | PopiArt 产品后端 | 用户鉴权、项目权限、skill 注册表聚合、skill 执行、job 引用管理、artifact read-through、路由决策、计费归因 | 不把供应商细节暴露给 CLI,不把 skillhub 直接耦合到 CLI,不重复实现 `PopiNewAPI` 已有的模型网关能力 |
| `PopiNewAPI` | 模型网关和通道管理层 | 管理上游渠道和 key、代理模型请求、记录原始用量、提供模型层能力 | 不承载 PopiArt 的 skill 业务语义,不负责 CLI 交互,不负责产品级项目上下文 |
## 标准调用链路
```text
coding agent / creator
->
popiartcli
->
popiartServer
->
PopiNewAPI
->
model providers
```
这条链路里,`popiartcli` 是入口层,`popiartServer` 是产品编排层,`PopiNewAPI` 是模型网关层。
## skillhub 放在哪一层
`skillhub` 是公开 skill 注册表,不是模型执行层。
推荐关系是:
```text
GitHub skillhub / skillhub.popi.art
->
popiartServer 同步或聚合
->
/skills API
->
popiartcli
```
这样做有三个好处:
1. CLI 不需要直接依赖 GitHub 或站点结构。
2. skill 搜索、过滤、版本兼容可以统一放在后端处理。
3. 以后从 GitHub 仓库切到 `skillhub.popi.art` 时,不需要改 CLI。
## 授权、路由、计费分别在哪一层
- 用户登录和项目权限:`popiartServer`
- CLI 本地 key 持久化:`popiartcli`
- 模型路由选择:`popiartServer`
- 上游 provider key 管理:`PopiNewAPI`
- 原始模型调用计量:`PopiNewAPI`
- 面向 skill / project / user 的计费归因:`popiartServer`
- artifact 文件存储与 task 内容代理:优先复用 `PopiNewAPI``popiartServer` 只做 read-through
一个重要原则是:
**真实 provider key 不进入 `popiartcli`。**
CLI 只拿产品层 key;后端再用自己的方式调用 `PopiNewAPI`
## 当前测试应该怎么分阶段
### 第一阶段:只验证产品协议
先验证:
- `auth`
- `skills`
- `run`
- `jobs`
- `artifacts`
这一阶段可以完全不接真实模型,也不需要真实 provider key。
### 第二阶段:接一个真实模型
先只打通一个最小 skill,例如:
- `popiskill-image-text2image-basic-v1`
并让 `popiartServer` 将它映射到一个明确的 `route_key` 和一个真实可用模型。
这一阶段才需要在 `PopiNewAPI` 中放可用渠道和 key。
### 第三阶段:扩展 skill 与路由
在文生图跑通后,再逐步加入:
- 图生图
- 图生视频
- 更多供应商和项目级路由覆盖
## 什么时候改哪个仓库
- 你在改命令体验、输出格式、配置逻辑:改 `popiartcli`
- 你在改 skill 调度、项目权限、artifact 规则、计费归因:改 `popiartServer`
- 你在改渠道、模型映射、供应商 key、原始模型代理:改 `PopiNewAPI`
如果一个改动同时需要触达三层,先从边界文档开始,再改代码。