feat: admin billing API — query DeepSeek + SiliconFlow balances
All checks were successful
Deploy API Server / build-and-deploy (push) Successful in 39s

This commit is contained in:
WangDL 2026-05-22 15:23:25 +08:00
parent cdf6195e6d
commit c170f6048b
4 changed files with 133 additions and 0 deletions

View File

@ -15,6 +15,7 @@ import { AuthModule } from './modules/auth/auth.module';
import { AdminAuthModule } from './modules/admin-auth/admin-auth.module';
import { AdminDashboardModule } from './modules/admin-dashboard/admin-dashboard.module';
import { AdminUsersModule } from './modules/admin-users/admin-users.module';
import { AdminBillingModule } from './modules/admin-billing/admin-billing.module';
import { AdminServersModule } from './modules/admin-servers/admin-servers.module';
import { AdminConversationModule } from './modules/admin-conversation/admin-conversation.module';
import { AdminAiChatModule } from './modules/admin-ai-chat/admin-ai-chat.module';
@ -90,6 +91,7 @@ import appleConfig from './config/apple.config';
AdminAuthModule,
AdminDashboardModule,
AdminUsersModule,
AdminBillingModule,
AdminServersModule,
AdminConversationModule,
AdminAiChatModule,

View File

@ -0,0 +1,22 @@
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 { AdminRolesGuard } from '../../common/guards/admin-roles.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, AdminRolesGuard)
@ApiBearerAuth()
export class AdminBillingController {
constructor(private readonly billingService: AdminBillingService) {}
@Get()
@AdminRoles('SUPER_ADMIN' as AdminRole)
@ApiOperation({ summary: 'API 用量与费用(仅超级管理员)' })
async getBilling() {
return this.billingService.getAllBilling();
}
}

View File

@ -0,0 +1,11 @@
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';
import { AdminRolesGuard } from '../../common/guards/admin-roles.guard';
@Module({
controllers: [AdminBillingController],
providers: [AdminBillingService, AdminAuthGuard, AdminRolesGuard],
})
export class AdminBillingModule {}

View File

@ -0,0 +1,98 @@
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<BillingInfo> {
try {
const resp = await fetch('https://api.deepseek.com/user/balance', {
headers: { Authorization: 'Bearer sk-ddddea4986d843be978ced9e82988fa0' },
});
const data = await resp.json();
const bal = data?.balance_infos?.[0]?.total_balance;
return {
name: 'DeepSeek',
model: 'deepseek-v4-flash / deepseek-chat',
balance: bal ? `¥${bal}` : '—',
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<BillingInfo> {
try {
const resp = await fetch('https://api.siliconflow.cn/v1/user/info', {
headers: { Authorization: 'Bearer sk-jdtqzgrlneklatdmymscrnvljvzlkkxcrzylznufpgggswjz' },
});
const data = await resp.json();
const bal = data?.data?.totalBalance;
return {
name: '硅基流动',
model: 'BGE-M3 / BGE-Reranker',
balance: bal ? `¥${bal}` : '—',
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: '按调用次数计费,需登录控制台查看',
};
}
}