diff --git a/apps/sub2api/app.json b/apps/sub2api/app.json new file mode 100644 index 0000000..21c956c --- /dev/null +++ b/apps/sub2api/app.json @@ -0,0 +1,232 @@ +{ + "appid": 304, + "appname": "sub2api", + "apptitle": "Sub2API", + "apptype": "AI", + "appTypeCN": "AI/大模型", + "appversion": [ + { + "m_version": "latest", + "s_version": [] + } + ], + "appdesc": "AI API 网关平台,用于分发和管理 AI 产品订阅配额。支持多种上游账号类型与 API Key 分发,提供 Token 级用量追踪和成本计算、智能账号调度与粘性会话、用户级和账号级并发控制、请求与 Token 速率限制,并内置 Web 管理后台及自助支付能力。采用 Go + Vue 架构,配套 PostgreSQL 与 Redis,通过 Docker Compose 一键部署。", + "appstatus": 1, + "icon": "", + "sort": 1, + "home": "https://github.com/Wei-Shaw/sub2api", + "help": "https://github.com/Wei-Shaw/sub2api/blob/main/README_CN.md", + "cpu": 0, + "mem": 0, + "disk": 10240, + "updateat": 1783865400, + "installed": false, + "reuse": true, + "depend": null, + "field": [ + { + "attr": "domain", + "name": "域名", + "type": "textarea", + "default": "", + "suffix": "选填,可使用绑定域名访问 Web 控制台", + "unit": "" + }, + { + "attr": "allow_access", + "name": "允许外部访问", + "type": "checkbox", + "default": true, + "suffix": "允许直接通过服务器 IP + 端口访问", + "unit": "" + }, + { + "attr": "server_port", + "name": "WEB端口", + "type": "number", + "default": 8080, + "suffix": "Web 控制台与 API 服务访问端口", + "unit": "" + }, + { + "attr": "admin_email", + "name": "管理员邮箱", + "type": "text", + "default": "", + "suffix": "首次启动创建的管理员登录邮箱,必填", + "unit": "" + }, + { + "attr": "admin_password", + "name": "管理员密码", + "type": "password", + "default": "", + "suffix": "首次启动创建的管理员登录密码,必填", + "unit": "" + }, + { + "attr": "postgres_user", + "name": "数据库用户", + "type": "text", + "default": "sub2api", + "suffix": "PostgreSQL 数据库用户名,默认 sub2api", + "unit": "" + }, + { + "attr": "postgres_password", + "name": "数据库密码", + "type": "password", + "default": "", + "suffix": "留空由宝塔自动生成,也可手动填写", + "unit": "" + }, + { + "attr": "postgres_db", + "name": "数据库名", + "type": "text", + "default": "sub2api", + "suffix": "PostgreSQL 数据库名称,默认 sub2api", + "unit": "" + }, + { + "attr": "redis_password", + "name": "Redis 密码", + "type": "password", + "default": "", + "suffix": "留空由宝塔自动生成,也可手动填写", + "unit": "" + }, + { + "attr": "jwt_seed", + "name": "JWT 密钥", + "type": "password", + "default": "", + "suffix": "留空自动生成,用于登录令牌签名", + "unit": "" + }, + { + "attr": "totp_seed", + "name": "TOTP 密钥", + "type": "password", + "default": "", + "suffix": "留空自动生成,用于两步验证数据加密", + "unit": "" + }, + { + "attr": "cpus", + "name": "CPU核心数限制", + "type": "number", + "default": 0, + "suffix": "0 为不限制,最大可用核心数:", + "unit": "" + }, + { + "attr": "memory_limit", + "name": "内存限制", + "type": "number", + "default": 0, + "suffix": "0 为不限制,最大可用内存:", + "unit": "MB" + } + ], + "env": [ + { + "key": "version", + "type": "string", + "default": null, + "desc": "版本号" + }, + { + "key": "server_port", + "type": "port", + "default": null, + "desc": "Sub2API WEB端口" + }, + { + "key": "admin_email", + "type": "string", + "default": null, + "desc": "管理员邮箱" + }, + { + "key": "admin_password", + "type": "string", + "default": null, + "desc": "管理员密码(用户填写)" + }, + { + "key": "postgres_user", + "type": "string", + "default": null, + "desc": "PostgreSQL 用户" + }, + { + "key": "postgres_password", + "type": "password", + "default": null, + "desc": "PostgreSQL 密码" + }, + { + "key": "postgres_db", + "type": "string", + "default": null, + "desc": "PostgreSQL 数据库名" + }, + { + "key": "redis_password", + "type": "password", + "default": null, + "desc": "Redis 密码" + }, + { + "key": "jwt_seed", + "type": "password", + "default": null, + "desc": "JWT 随机种子(安装时自动生成)" + }, + { + "key": "totp_seed", + "type": "password", + "default": null, + "desc": "TOTP 随机种子(安装时自动生成)" + }, + { + "key": "app_path", + "type": "path", + "default": null, + "desc": "应用数据目录" + }, + { + "key": "host_ip", + "type": "string", + "default": null, + "desc": "主服务监听地址" + }, + { + "key": "cpus", + "type": "number", + "default": null, + "desc": "Sub2API 主服务 CPU 核心数限制" + }, + { + "key": "memory_limit", + "type": "number", + "default": null, + "desc": "Sub2API 主服务内存限制" + } + ], + "volumes": { + "data": { + "type": "path", + "desc": "Sub2API 运行数据和日志" + }, + "postgres_data": { + "type": "path", + "desc": "PostgreSQL 数据目录" + }, + "redis_data": { + "type": "path", + "desc": "Redis 持久化数据目录" + } + } +} diff --git a/apps/sub2api/ico-dkapp_sub2api.png b/apps/sub2api/ico-dkapp_sub2api.png new file mode 100644 index 0000000..7d3fa42 Binary files /dev/null and b/apps/sub2api/ico-dkapp_sub2api.png differ diff --git a/apps/sub2api/latest/.env b/apps/sub2api/latest/.env new file mode 100644 index 0000000..f98121e --- /dev/null +++ b/apps/sub2api/latest/.env @@ -0,0 +1,14 @@ +VERSION=latest +SERVER_PORT=8080 +ADMIN_EMAIL= +ADMIN_PASSWORD= +POSTGRES_USER=sub2api +POSTGRES_PASSWORD= +POSTGRES_DB=sub2api +REDIS_PASSWORD= +JWT_SEED= +TOTP_SEED= +HOST_IP=0.0.0.0 +CPUS=0 +MEMORY_LIMIT=0MB +APP_PATH=/www/dk_project/dk_app/sub2api diff --git a/apps/sub2api/latest/docker-compose.yml b/apps/sub2api/latest/docker-compose.yml new file mode 100644 index 0000000..d776349 --- /dev/null +++ b/apps/sub2api/latest/docker-compose.yml @@ -0,0 +1,124 @@ +services: + BT_SERVICE_NAME6: + image: ghcr.io/wei-shaw/sub2api:${VERSION} + restart: unless-stopped + ulimits: + nofile: + soft: 100000 + hard: 100000 + deploy: + resources: + limits: + cpus: ${CPUS} + memory: ${MEMORY_LIMIT} + ports: + - ${HOST_IP}:${SERVER_PORT}:8080 + volumes: + - ${APP_PATH}/data:/app/data + - /etc/localtime:/etc/localtime:ro + environment: + AUTO_SETUP: "true" + SERVER_HOST: "0.0.0.0" + SERVER_PORT: "8080" + SERVER_MODE: "release" + RUN_MODE: "standard" + DATABASE_HOST: "postgres" + DATABASE_PORT: "5432" + DATABASE_USER: ${POSTGRES_USER} + DATABASE_PASSWORD: ${POSTGRES_PASSWORD} + DATABASE_DBNAME: ${POSTGRES_DB} + DATABASE_SSLMODE: "disable" + REDIS_HOST: "redis" + REDIS_PORT: "6379" + REDIS_PASSWORD: ${REDIS_PASSWORD} + REDIS_DB: "0" + ADMIN_EMAIL: ${ADMIN_EMAIL:?请填写管理员邮箱} + ADMIN_PASSWORD: ${ADMIN_PASSWORD:?请填写管理员密码} + JWT_EXPIRE_HOUR: "24" + JWT_SEED: ${JWT_SEED} + TOTP_SEED: ${TOTP_SEED} + TZ: "Asia/Shanghai" + command: + - /bin/sh + - -c + - | + export JWT_SECRET="$$(printf '%s' "$$JWT_SEED" | sha256sum | cut -d ' ' -f 1)" + export TOTP_ENCRYPTION_KEY="$$(printf '%s' "$$TOTP_SEED" | sha256sum | cut -d ' ' -f 1)" + exec /app/sub2api + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + healthcheck: + test: ["CMD", "wget", "-q", "-T", "5", "-O", "/dev/null", "http://localhost:8080/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 30s + labels: + createdBy: "bt_apps" + networks: + - sub2api-network + - baota_net + + postgres: + image: postgres:18-alpine + restart: unless-stopped + ulimits: + nofile: + soft: 100000 + hard: 100000 + volumes: + - ${APP_PATH}/postgres_data:/var/lib/postgresql/data + - /etc/localtime:/etc/localtime:ro + environment: + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: ${POSTGRES_DB} + PGDATA: /var/lib/postgresql/data + TZ: "Asia/Shanghai" + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 10s + labels: + createdBy: "bt_apps" + networks: + - sub2api-network + + redis: + image: redis:8-alpine + restart: unless-stopped + ulimits: + nofile: + soft: 100000 + hard: 100000 + volumes: + - ${APP_PATH}/redis_data:/data + - /etc/localtime:/etc/localtime:ro + command: >- + sh -c 'redis-server --save 60 1 --appendonly yes --appendfsync everysec + ${REDIS_PASSWORD:+--requirepass "$$REDIS_PASSWORD"}' + environment: + REDIS_PASSWORD: ${REDIS_PASSWORD} + REDISCLI_AUTH: ${REDIS_PASSWORD} + TZ: "Asia/Shanghai" + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 5s + labels: + createdBy: "bt_apps" + networks: + - sub2api-network + +networks: + sub2api-network: + driver: bridge + baota_net: + external: true