init:初始化项目
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
@@ -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`
|
||||
|
||||
如果一个改动同时需要触达三层,先从边界文档开始,再改代码。
|
||||
Reference in New Issue
Block a user