feat!: 账号池改渠道网关,对外协议换成 vivid /v1

- 新增 channels/channel_models:上游 URL + AES-GCM 加密 key +
  并发/权重/本地统计,模型经渠道 /v1/models 导入绑定
- internal/upstream:vivid 协议客户端(NDJSON 流 + jobId 断流重连 +
  uploads 预签名 + models + balance + 错误分类)
- service/v1 重写:权重分组调度、Redis 并发槽 conc:c:、故障转移,
  站内/测试/对外统一走渠道执行器
- 对外端点换成 vivid 四件套:POST /v1/generate(NDJSON+jobId 重连)、
  POST /v1/uploads(SigV4 预签名 PUT)、GET /v1/models、GET /v1/balance,
  错误包 {"error":{"code","message"}}
- API key 新发改 vk_+48hex;删除全部内置 provider 与 token 池
- 管理端:渠道 CRUD/拉模型/导入/余额端点,前端账号页换渠道页,
  概览/文档/测试弹窗适配

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
2026-10-16 21:14:18 +08:00
co-authored by Devin
parent ecdbc0b281
commit b4efe6b192
75 changed files with 3598 additions and 23848 deletions
+9 -1
View File
@@ -2,6 +2,7 @@ package service
import (
"context"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"errors"
@@ -109,8 +110,15 @@ func (s *APIKeyService) DeleteOne(ctx context.Context, userID, keyID string) err
return s.keys.DeleteByID(ctx, userID, keyID)
}
// generatePlainAPIKey mints a vivid-shaped key: vk_ + 48 lowercase hex chars
// (upstream channel api_keys use the same shape, so one key format rules
// everything — no per-direction prefixes).
func generatePlainAPIKey() (string, error) {
return "sk-" + randomUpper(38), nil
b := make([]byte, 24)
if _, err := rand.Read(b); err != nil {
return "", err
}
return "vk_" + hex.EncodeToString(b), nil
}
func previewAPIKey(plain string) string {