Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# AITokenPool — multi-stage release image (v0.3.3)
#
# Build: docker build -t aitokenpool:0.3.3 .
# Run: docker run -p 8080:8080 -v "$PWD/data:/data" \
# -e ATP_MASTER_KEY="$(openssl rand -hex 32)" \
# aitokenpool:0.3.3
#
# Notes:
# - runtime WORKDIR is / so the relative paths in config.example.toml work:
# db_path = "data/aitokenpool.db" -> /data/aitokenpool.db (mounted volume)
# ServeDir "ui" -> /ui (copied below)
# - master_key comes from env ATP_MASTER_KEY (32-byte hex), crypto reads env first.

# ---------- builder ----------
FROM rust:1.86-slim AS builder
WORKDIR /build
# native-tls (openssl-sys) 需要系统 OpenSSL 头文件
RUN apt-get update \
&& apt-get install -y --no-install-recommends pkg-config libssl-dev \
&& rm -rf /var/lib/apt/lists/*
# 依赖层缓存:源码变更不重编依赖
COPY Cargo.toml Cargo.lock ./
COPY src ./src
COPY ui ./ui
RUN cargo build --release --locked

# ---------- runtime ----------
FROM debian:bookworm-slim AS runtime
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates curl \
&& rm -rf /var/lib/apt/lists/* \
&& useradd --uid 10001 --create-home --shell /usr/sbin/nologin app

WORKDIR /
COPY --from=builder /build/target/release/aitokenpool /usr/local/bin/aitokenpool
COPY ui /ui
COPY config/config.example.toml /etc/aitokenpool/config.toml

RUN mkdir -p /data /etc/aitokenpool \
&& chown -R 10001:10001 /data /etc/aitokenpool

USER 10001
EXPOSE 8080
VOLUME ["/data"]
CMD ["aitokenpool", "--config", "/etc/aitokenpool/config.toml"]
67 changes: 57 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,75 @@ AITokenPool 是一个开源的 **AI Token 共享平台**:企业版(内部 ke
## 架构定论(详见 docs/architecture.md)

- **中心化(方案 A)**:平台托管 key + 平台执行调用——唯一可信执行者,计量可信、无篡改作弊空间。
- **技术栈**:Rust(axum + hyper + tokio + SQLite/PostgreSQL),基于 openlocalrouter 的既有积累演进。
- **双模式**:一套核心平台,企业部署 + 公共市场。
- **技术栈**:Rust(axum + hyper + tokio + SQLite),基于 openlocalrouter 的既有积累演进。
- **双模式**:一套核心平台,企业部署 + 公共市场;**角色是权限差异,不是产品差异**——公共版/企业版功能集合相同,管理员/运营者拥有额外管理视图(成员点数 / 用量报表 / 部门 / 运营数据),普通用户没有。

## 状态

后端已实现 **P0(A/B/C)+ P1**,当前版本 **v0.3.0**(61/61 测试全绿):
后端 + 前端已全部实现,当前版本 **v0.3.3**(70/70 测试全绿):

- ✅ **P0-A(v0.2.0)**:后端骨架 + TOML 配置(`Config::validate`:points_per_unit>0 / plan→provider 存在 / endpoints≥1 / protocol 枚举)+ SQLite 数据层(幂等迁移 v3 + demo/admin 种子)+ 认证(argon2 + Bearer API Key)+ API Key 端点
- ✅ **P0-A(v0.2.0)**:后端骨架 + TOML 配置(`Config::validate`:points_per_unit>0 / plan→provider 存在 / endpoints≥1 / protocol 枚举)+ SQLite 数据层(幂等迁移 v4 + demo/admin/ops 种子)+ 认证(argon2 + Bearer API Key)+ API Key 端点
- ✅ **P0-B(v0.2.1)**:网关转发(OpenAI Chat Completions + Anthropic Messages)+ 路由故障转移(粘性 / 健康冷却 / 3 次切换上限)+ 计量账本(点数计算、90/10 分成、事务性 settle)
- ✅ **P0-C(v0.2.2)**:SSE 流式转发(流尾 usage 入账、断连不入账)+ 上游 key AES-256-GCM 加密 + 共享 / 钱包 / 交易 API
- ✅ **P1(v0.3.0)**:点数规则细化——新人每日赠送(10 天窗口·当日有效)+ 先扣最早到期赠送再扣永久 + 管理员充值 API(role=admin)
- ✅ **P2-A(v0.3.1)**:前端对接——后端静态托管 `ui/` + API 客户端层 + 登录/会话对接(按 role 显隐管理视图)
- ✅ **P2-B(v0.3.2)**:各页面数据对接真实 API——市场 / 共享 / 交易 / 仪表盘 / API Key 管理全接后端
- ✅ **P2-C(v0.3.3)**:部门/成员管理 + 加额审批 + 用量报表(users/models/departments 三组聚合)+ 运营者视图(runtime/credits/users)

`cargo run` 后可用端点(Bearer 认证;demo@aitokenpool.local / demo1234,admin@aitokenpool.local / admin1234):
- `GET /healthz` → `{"status":"ok","version":"0.3.0"}`
- `POST /api/auth/login` → `{api_key}`;`POST|GET /api/api-keys`(key 脱敏 `atk_live_****xxxx`)
`ui/` 已由纯静态原型升级为**对接真实 API**(登录、钱包、市场、共享、交易、设置、管理、运营全部真实数据),由后端 `ServeDir` 静态托管,无需单独部署前端。

## 快速上手

### ① 本地运行(cargo)

```bash
cp config/config.example.toml config/config.toml # 首次
cargo run # http://localhost:8080/
```

### ② Docker 部署

```bash
docker compose up -d --build # 构建 + 启动
open http://localhost:8080/ # 浏览器访问
```

> ⚠️ **生产必须设置 `ATP_MASTER_KEY`**(32 字节 hex 主密钥,用于加密上游 key):
>
> ```bash
> export ATP_MASTER_KEY=$(openssl rand -hex 32)
> docker compose up -d
> ```
>
> 未设置时使用 dev 默认值,仅适合本地试用(重启后已加密的上游 key 不可解密)。数据持久化在 `./data/`(SQLite)。

### ③ 登录账号

| 角色 | 账号 | 密码 | 说明 |
|------|------|------|------|
| 普通用户 | `demo@aitokenpool.local` | `demo1234` | 市场/共享/钱包/设置 |
| 管理员 | `admin@aitokenpool.local` | `admin1234` | + 管理视图(成员/充值/用量/部门/加额审批) |
| 运营者 | `ops@aitokenpool.local` | `ops1234` | + 运营视图(运行概览/成员充值) |

## API 端点(Bearer 认证)

- `GET /healthz` → `{"status":"ok","version":"0.3.3"}`
- `POST /api/auth/login` → `{api_key}`;`GET /api/me` → `{id,email,name,role}`
- `POST|GET /api/api-keys`(key 脱敏 `atk_live_****xxxx`);`DELETE /api/api-keys/:id`(撤销)
- `POST /v1/chat/completions` / `POST /anthropic/v1/messages`(网关,支持 SSE 流式)
- `GET /api/models`(模型市场)
- `POST|GET /api/sharings` + `PATCH /api/sharings/:id`(key 上架 / 列表 / 暂停下线)
- `POST|GET /api/sharings` + `PATCH /api/sharings/:id`(上架 / 列表 / 暂停 / 恢复 / 删除)
- `GET /api/wallet` / `GET /api/transactions?type=` / `GET /api/dashboard`(钱包 / 交易 / 仪表盘)
- `POST /api/admin/credits` / `GET /api/admin/users` / `GET /api/admin/usage`(管理员充值 / 成员 / 用量)
- 管理员:`POST /api/admin/credits` / `GET /api/admin/users` + `PATCH /api/admin/users/:id` / `GET /api/admin/usage`
- 部门:`GET|POST /api/admin/departments` + `PATCH|DELETE /api/admin/departments/:id`
- 加额:`POST|GET /api/raise-requests` + `POST /api/admin/raise-requests/:id/approve|reject`
- 运营者:`GET /api/ops/runtime` / `POST /api/ops/credits` / `GET /api/ops/users`

## 环境变量

UI 原型 v1.20(`ui/` 静态页 + mock 数据);架构细节见 docs/architecture.md v0.3。
| 变量 | 说明 |
|------|------|
| `ATP_MASTER_KEY` | 上游 key 主密钥(hex 32 字节),优先级高于 config `[server].master_key`,生产必须设置 |

## License

Expand Down
30 changes: 30 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# AITokenPool — Docker Compose 一键部署(v0.3.3)
#
# 快速开始:
# docker compose up -d --build
# 浏览器打开 http://localhost:8080/
#
# ⚠️ 生产环境必须设置 ATP_MASTER_KEY(32 字节 hex 主密钥):
# 生成:openssl rand -hex 32
# 注入:export ATP_MASTER_KEY=$(openssl rand -hex 32) && docker compose up -d
# 未设置时使用示例默认值(dev 模式,重启后已加密的上游 key 不可解密,仅用于本地试用)。
services:
aitokenpool:
build: .
image: aitokenpool:0.3.3
ports:
- "8080:8080"
volumes:
# SQLite 数据持久化(config.example.toml 中 db_path = "data/aitokenpool.db",
# 容器内 WORKDIR=/,相对路径解析为 /data/aitokenpool.db)
- ./data:/data
environment:
# 主密钥(32 字节 hex;env 优先于 config [server].master_key)
- ATP_MASTER_KEY=${ATP_MASTER_KEY:-dev-master-key-请替换}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/healthz"]
interval: 10s
timeout: 3s
retries: 5
start_period: 10s
restart: unless-stopped
Loading