a831012c48
CI / docker (push) Failing after 1m35s
Introduce Gitea Actions workflow and CI-aligned Dockerfile; remove file-based config in favor of SQLite settings; refresh branding and tighten gitignore. Co-authored-by: Cursor <cursoragent@cursor.com>
236 lines
8.7 KiB
Markdown
236 lines
8.7 KiB
Markdown
# Luminary AI Gateway
|
||
|
||
Go + Vue 3 AI 网关,参考 [Bifrost](https://github.com/maximhq/bifrost) 设计,支持多 Provider 出口、入口密钥治理、看板监控与安全管控。SQLite 持久化 + 内存缓存,单二进制部署。
|
||
|
||
## 功能
|
||
|
||
- **出口管理**:OpenAI / Anthropic / Azure OpenAI / OpenRouter / Ollama / Custom,多 Key 加权负载均衡与故障转移,接口 Path 覆盖,分类(语言模型 / 向量嵌入 / 重排序 / 图像)
|
||
- **入口管理**:OpenAI 兼容 API(含流式 SSE、`/v1/embeddings`、`/v1/rerank`),入口密钥(`sk-lum-*`),Virtual Key 路由规则,预算与 RPM/TPM 限流
|
||
- **看板监控**:Provider 健康检查、24h 请求/Token 统计、入口用量排行
|
||
- **请求日志**:全量请求记录、按模型定价的成本估算
|
||
- **安全**:管理员登录、Session、IP 白名单/黑名单(分 admin/proxy 范围)
|
||
|
||
## 快速开始
|
||
|
||
```bash
|
||
# 构建(含 Vue 前端嵌入)
|
||
make build
|
||
|
||
# 运行(数据目录默认 ./data,监听 :8293)
|
||
./luminary
|
||
# 或指定参数 / 环境变量
|
||
./luminary -data-dir ./data -addr :8293
|
||
# LUMINARY_DATA=./data LUMINARY_ADDR=:8293 ./luminary
|
||
```
|
||
|
||
首次启动自动创建 SQLite 数据库与默认系统设置(含随机加密密钥)。默认管理账号:`admin` / `admin123`(仅当数据库中尚无管理员时创建)
|
||
|
||
默认监听端口:`8293`(可通过 `-addr` 或 `LUMINARY_ADDR` 修改)
|
||
|
||
- **管理台**:http://localhost:8293
|
||
- **管理 API**:`/api/admin/*`(Session 登录)
|
||
- **推理入口 API**:`/v1/*`(入口密钥鉴权,OpenAI 兼容)
|
||
|
||
## 入口 API(推理)
|
||
|
||
客户端使用在管理台创建的**入口密钥**(`sk-lum-*`)调用,与 OpenAI SDK 兼容。
|
||
|
||
**鉴权**
|
||
|
||
```http
|
||
Authorization: Bearer sk-lum-<your-key>
|
||
```
|
||
|
||
**Base URL**:`http://<host>:8293/v1`(端口以启动参数 `-addr` 为准)
|
||
|
||
| 方法 | 路径 | 说明 | 状态 |
|
||
|------|------|------|------|
|
||
| `GET` | `/v1/models` | 列出当前入口密钥可用的模型 | 已支持 |
|
||
| `POST` | `/v1/chat/completions` | 对话补全;`stream: true` 时返回 SSE 流式 | 已支持 |
|
||
| `POST` | `/v1/responses` | OpenAI Responses API;`stream: true` 时返回 SSE 流式 | 已支持 |
|
||
| `POST` | `/v1/completions` | 文本补全(Legacy) | 已支持 |
|
||
| `POST` | `/v1/embeddings` | 向量嵌入 | 已支持 |
|
||
| `POST` | `/v1/rerank` | Cohere 兼容重排序 | 已支持 |
|
||
| `POST` | `/v1/audio/speech` | 语音合成 | 预留(需在出口启用对应分类) |
|
||
| `POST` | `/v1/audio/transcriptions` | 语音转写 | 预留 |
|
||
| `POST` | `/v1/images/generations` | 图像生成 | 预留 |
|
||
|
||
> 实际可访问的接口取决于上游 Provider 在「出口管理」中启用的 endpoint;未启用的接口网关不会转发。
|
||
>
|
||
> **Responses 适配**:若出口仅启用 `chat_completion` 而未启用 `responses`,网关会将 `/v1/responses` 自动转换为 `/v1/chat/completions` 请求,并将响应转回 Responses API 格式(含流式)。
|
||
|
||
**示例:对话补全**
|
||
|
||
```bash
|
||
curl http://localhost:8293/v1/chat/completions \
|
||
-H "Authorization: Bearer sk-lum-..." \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"Hello"}]}'
|
||
```
|
||
|
||
**示例:流式对话**
|
||
|
||
```bash
|
||
curl http://localhost:8293/v1/chat/completions \
|
||
-H "Authorization: Bearer sk-lum-..." \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"model":"gpt-4o-mini","stream":true,"messages":[{"role":"user","content":"Hello"}]}'
|
||
```
|
||
|
||
**示例:Embeddings**
|
||
|
||
```bash
|
||
curl http://localhost:8293/v1/embeddings \
|
||
-H "Authorization: Bearer sk-lum-..." \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"model":"text-embedding-3-small","input":"hello"}'
|
||
```
|
||
|
||
**示例:Rerank(Cohere 兼容)**
|
||
|
||
```bash
|
||
curl http://localhost:8293/v1/rerank \
|
||
-H "Authorization: Bearer sk-lum-..." \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"model":"bge-reranker-v2-m3","query":"What is the capital of France?","documents":["Paris is the capital of France.","Berlin is in Germany."],"top_n":2}'
|
||
```
|
||
|
||
**示例:列出模型**
|
||
|
||
```bash
|
||
curl http://localhost:8293/v1/models \
|
||
-H "Authorization: Bearer sk-lum-..."
|
||
```
|
||
|
||
入口密钥的 Provider / Model 白名单、预算、RPM/TPM 限流与路由规则均在管理台「入口管理」配置;白名单为空表示不限制。
|
||
|
||
## 开发
|
||
|
||
```bash
|
||
# 终端 1:后端
|
||
go run ./cmd/luminary
|
||
|
||
# 终端 2:前端(代理到后端,默认 8293)
|
||
cd web && npm install && npm run dev
|
||
```
|
||
|
||
## 系统设置
|
||
|
||
所有运行参数在管理台 **系统设置** 页面维护,存入 SQLite,**无需配置文件即可启动**。
|
||
|
||
| 设置项 | 说明 |
|
||
|------|------|
|
||
| 加密密钥 | Provider API Key 加密密钥(首次启动自动生成) |
|
||
| 信任代理 | 信任的反向代理 IP/CIDR;仅此时才读取 `X-Forwarded-For` |
|
||
| 会话 / 登录限制 | 管理员 Session 有效期、登录尝试次数与锁定时长 |
|
||
| 用量刷盘 / 健康检查 | 后台任务间隔 |
|
||
| 网关重试 | 上游故障时的重试次数与退避 |
|
||
|
||
启动参数(非阻塞,仅决定进程如何监听与数据存放位置):
|
||
|
||
| 参数 / 环境变量 | 说明 | 默认 |
|
||
|------|------|------|
|
||
| `-data-dir` / `LUMINARY_DATA` | SQLite 数据目录 | `./data` |
|
||
| `-addr` / `LUMINARY_ADDR` | HTTP 监听地址 | `:8293` |
|
||
|
||
可选环境变量 `LUMINARY_ENCRYPTION_KEY`:仅在首次初始化系统设置时写入加密密钥(一般无需设置,管理台可改)。
|
||
|
||
## Docker 部署
|
||
|
||
镜像在**构建阶段**完成前端与 Go 二进制编译,容器启动时直接运行,不再从 Git 拉取代码。
|
||
|
||
```bash
|
||
# 本地构建镜像
|
||
make docker-build
|
||
# 或指定标签
|
||
LUMINARY_IMAGE=registry.example.com/luminary:v1.0.0 make docker-build
|
||
|
||
# 推送到仓库
|
||
LUMINARY_IMAGE=registry.example.com/luminary:v1.0.0 make docker-push
|
||
|
||
# 启动(仅持久化 /data)
|
||
docker compose up -d
|
||
```
|
||
|
||
`docker-compose.yml` 通过环境变量 `LUMINARY_IMAGE` 指定镜像名(默认 `registry.rc707blog.top/rose_cat707/luminary:latest`)。更新版本需重新 `docker build` / `docker push` 后重启容器。
|
||
|
||
### Gitea Actions CI
|
||
|
||
生产镜像由 Gitea Actions 自动构建并推送到 Container Registry,工作流见 [`.gitea/workflows/ci.yml`](.gitea/workflows/ci.yml),详细配置见 [`.gitea/README.md`](.gitea/README.md)。
|
||
|
||
**一次性配置**(仓库 Settings → Actions):
|
||
|
||
| 类型 | 名称 | 说明 |
|
||
|------|------|------|
|
||
| Secret | `REGISTRY_TOKEN` | Gitea PAT,需 `write:package` 权限 |
|
||
| Variable | `REGISTRY` | 公网 Gitea 域名,如 `git.rc707blog.top`(勿用内网 IP) |
|
||
|
||
**触发与镜像 tag**:
|
||
|
||
- `pull_request`:go test + 单架构 Docker 构建验证(不推送)
|
||
- `push main/master`:多架构构建并推送 `:latest`、`:sha-xxxxxxx`
|
||
- `push tag v*`:额外推送 `:v1.2.3`
|
||
|
||
示例镜像地址(仓库 `rose_cat707/luminary`,Gitea 在 `git.rc707blog.top`):
|
||
|
||
```text
|
||
git.rc707blog.top/rose_cat707/luminary:latest
|
||
git.rc707blog.top/rose_cat707/luminary:sha-35b3b48
|
||
git.rc707blog.top/rose_cat707/luminary:v1.0.0
|
||
```
|
||
|
||
部署时设置 `LUMINARY_IMAGE` 指向 CI 推送的镜像即可。
|
||
|
||
## 应急恢复(容器内)
|
||
|
||
当 IP 白名单或登录冷却导致无法进入管理台时,可在容器内执行恢复工具(已内置在镜像中):
|
||
|
||
```bash
|
||
# 一键:重置密码为 admin123、清空 IP 规则与会话,并重启进程(清除内存中的登录冷却)
|
||
docker exec luminary luminary-recover.sh --all
|
||
|
||
# 指定新密码
|
||
docker exec luminary luminary-recover.sh --all --password 'your-new-password'
|
||
|
||
# 分项执行(不重启)
|
||
docker exec luminary luminary-recover.sh \
|
||
--reset-password --clear-ip --clear-sessions --password 'your-new-password'
|
||
|
||
# 仅清除登录冷却(需重启进程;登录冷却存在内存中)
|
||
docker exec luminary luminary-recover.sh --restart
|
||
```
|
||
|
||
本地非容器环境:
|
||
|
||
```bash
|
||
chmod +x scripts/luminary-recover.sh
|
||
./scripts/luminary-recover.sh --all
|
||
# 或
|
||
go run ./cmd/luminary-recover --all
|
||
```
|
||
|
||
| 参数 | 说明 |
|
||
|------|------|
|
||
| `--all` | 重置密码 + 清空 IP 规则 + 清空会话 + 重启进程 |
|
||
| `--reset-password` | 重置管理员密码 |
|
||
| `--clear-ip` | 删除全部 IP 规则 |
|
||
| `--clear-sessions` | 删除全部管理员 Session |
|
||
| `--restart` | 向 PID 1 发送 SIGTERM,由容器重启策略拉起新进程(清除登录冷却) |
|
||
| `--password` | 新密码(默认 `admin123`) |
|
||
| `--username` | 管理员用户名(默认 `admin`) |
|
||
| `-data-dir` / `LUMINARY_DATA` | 数据目录(默认 `./data`,容器内为 `/data`) |
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
cmd/luminary/ 主服务入口
|
||
cmd/luminary-recover/ 应急恢复 CLI(容器内 docker exec 使用)
|
||
scripts/ 运维脚本(含 luminary-recover.sh)
|
||
internal/ Go 后端(gateway、store、handler...)
|
||
web/ Vue 3 前端(构建产物嵌入二进制)
|
||
```
|
||
|
||
## License
|
||
|
||
MIT
|