From c6aa4cf88a70a83987697d564094ddeb3284d523 Mon Sep 17 00:00:00 2001 From: WangDL Date: Fri, 22 May 2026 15:31:51 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20admin=20billing=20API=20=E2=80=94=20Dee?= =?UTF-8?q?pSeek=20+=20SiliconFlow=20balances?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin-billing/admin-billing.controller.ts | 18 ++++++++++ .../admin-billing/admin-billing.module.ts | 6 ++++ .../admin-billing/admin-billing.service.ts | 34 +++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 src/modules/admin-billing/admin-billing.controller.ts create mode 100644 src/modules/admin-billing/admin-billing.module.ts create mode 100644 src/modules/admin-billing/admin-billing.service.ts diff --git a/src/modules/admin-billing/admin-billing.controller.ts b/src/modules/admin-billing/admin-billing.controller.ts new file mode 100644 index 0000000..1c89162 --- /dev/null +++ b/src/modules/admin-billing/admin-billing.controller.ts @@ -0,0 +1,18 @@ +import { Controller, Get, UseGuards } from '@nestjs/common'; +import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger'; +import { AdminBillingService } from './admin-billing.service'; +import { AdminAuthGuard } from '../../common/guards/admin-auth.guard'; +import { AdminRoles } from '../../common/decorators/admin-roles.decorator'; +import type { AdminRole } from '../../common/types/admin-role.enum'; + +@ApiTags('admin-billing') +@Controller('admin-api/billing') +@UseGuards(AdminAuthGuard) +@ApiBearerAuth() +export class AdminBillingController { + constructor(private readonly svc: AdminBillingService) {} + @Get() + @AdminRoles('SUPER_ADMIN' as AdminRole) + @ApiOperation({ summary: 'API 用量与费用' }) + async get() { return this.svc.getAllBilling(); } +} diff --git a/src/modules/admin-billing/admin-billing.module.ts b/src/modules/admin-billing/admin-billing.module.ts new file mode 100644 index 0000000..ebe0dad --- /dev/null +++ b/src/modules/admin-billing/admin-billing.module.ts @@ -0,0 +1,6 @@ +import { Module } from '@nestjs/common'; +import { AdminBillingController } from './admin-billing.controller'; +import { AdminBillingService } from './admin-billing.service'; +import { AdminAuthGuard } from '../../common/guards/admin-auth.guard'; +@Module({ controllers: [AdminBillingController], providers: [AdminBillingService, AdminAuthGuard] }) +export class AdminBillingModule {} diff --git a/src/modules/admin-billing/admin-billing.service.ts b/src/modules/admin-billing/admin-billing.service.ts new file mode 100644 index 0000000..d124dbe --- /dev/null +++ b/src/modules/admin-billing/admin-billing.service.ts @@ -0,0 +1,34 @@ +import { Injectable, Logger } from '@nestjs/common'; + +export interface BillingInfo { + name: string; model: string; balance: string; currency: string; status: 'ok' | 'unknown'; consoleUrl: string; note: string; +} + +@Injectable() +export class AdminBillingService { + private readonly logger = new Logger(AdminBillingService.name); + + async getAllBilling(): Promise<{ providers: BillingInfo[] }> { + const [deepseek, siliconflow] = await Promise.all([this.getDeepSeek(), this.getSiliconFlow()]); + return { providers: [deepseek, siliconflow, this.getMiniMax(), this.getBaiduOcr()] }; + } + + private async getDeepSeek(): Promise { + try { + const r = await fetch('https://api.deepseek.com/user/balance', { headers: { Authorization: 'Bearer sk-ddddea4986d843be978ced9e82988fa0' } }); + const d = await r.json(); const b = d?.balance_infos?.[0]?.total_balance; + return { name: 'DeepSeek', model: 'v4-flash / deepseek-chat', balance: b ? `¥${b}` : '—', currency: 'CNY', status: 'ok', consoleUrl: 'https://platform.deepseek.com', note: '充值余额' }; + } catch { return { name: 'DeepSeek', model: 'v4-flash', balance: '—', currency: 'CNY', status: 'unknown', consoleUrl: 'https://platform.deepseek.com', note: '查询失败' }; } + } + + private async getSiliconFlow(): Promise { + try { + const r = await fetch('https://api.siliconflow.cn/v1/user/info', { headers: { Authorization: 'Bearer sk-jdtqzgrlneklatdmymscrnvljvzlkkxcrzylznufpgggswjz' } }); + const d = await r.json(); const b = d?.data?.totalBalance; + return { name: '硅基流动', model: 'BGE-M3 / BGE-Reranker', balance: b ? `¥${b}` : '—', currency: 'CNY', status: 'ok', consoleUrl: 'https://cloud.siliconflow.cn', note: '充值 + 赠送' }; + } catch { return { name: '硅基流动', model: 'Embedding/Rerank', balance: '—', currency: 'CNY', status: 'unknown', consoleUrl: 'https://cloud.siliconflow.cn', note: '查询失败' }; } + } + + private getMiniMax(): BillingInfo { return { name: 'MiniMax', model: 'MiniMax 2.7', balance: '点数制', currency: 'points', status: 'unknown', consoleUrl: 'https://platform.minimaxi.com', note: '需登录控制台查看' }; } + private getBaiduOcr(): BillingInfo { return { name: '百度 OCR', model: '通用文字识别', balance: '次数制', currency: 'calls', status: 'unknown', consoleUrl: 'https://console.bce.baidu.com', note: '需登录控制台查看' }; } +}