|
|
@@ -0,0 +1,500 @@
|
|
|
+# Token计费系统设计
|
|
|
+
|
|
|
+## 📊 成本分析基础
|
|
|
+
|
|
|
+### AI模型定价(你提供的数据)
|
|
|
+
|
|
|
+| 模型 | 输入价格 | 输出价格 | 特点 |
|
|
|
+|------|---------|---------|------|
|
|
|
+| DeepSeek V3.2 | ¥2.0/千token | ¥8.0/千token | ⭐ 高性价比 |
|
|
|
+| 通义 Qwen Plus | ¥4.0/千token | ¥12.0/千token | 高质量生成 |
|
|
|
+| 豆包 Pro | ¥2.0/千token | ¥6.0/千token | 稳定通用 |
|
|
|
+
|
|
|
+### TTS场景成本计算
|
|
|
+
|
|
|
+**场景**:用户输入文本 → AI处理 → 生成音频
|
|
|
+
|
|
|
+**成本构成**:
|
|
|
+1. **输入成本**:文本处理
|
|
|
+ - 公式:`字数 × 输入价格 / 1000`
|
|
|
+ - 示例:2000字 × ¥2.0/千 = ¥4.0
|
|
|
+
|
|
|
+2. **输出成本**:音频合成
|
|
|
+ - 公式:`字数 × 输出价格 / 1000 × 系数`
|
|
|
+ - 系数:0.05-0.1(相对固定成本)
|
|
|
+ - 示例:2000字 × ¥8.0/千 × 0.1 = ¥1.6
|
|
|
+
|
|
|
+3. **总成本**:¥4.0 + ¥1.6 = ¥5.6
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 💰 安全定价策略
|
|
|
+
|
|
|
+### 核心原则
|
|
|
+
|
|
|
+1. **Token单价 ≥ ¥2.0**(DeepSeek成本价)
|
|
|
+2. **利润率 ≥ 50%**(企业健康利润率)
|
|
|
+3. **套餐定价 ≥ 成本**(避免亏本)
|
|
|
+
|
|
|
+### Token单价计算
|
|
|
+
|
|
|
+```
|
|
|
+成本价:¥2.0/千token(DeepSeek基础价)
|
|
|
+合理售价:¥3.0-4.0/千token
|
|
|
+利润率:33-50%
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 📋 套餐成本分析
|
|
|
+
|
|
|
+### 免费版(¥0/月)
|
|
|
+
|
|
|
+```
|
|
|
+配额:5,000 Token/月
|
|
|
+成本:5,000 × ¥2.0/千 = ¥10.0
|
|
|
+利润:-¥10.0(平台补贴)
|
|
|
+策略:体验引流,吸引付费转化
|
|
|
+```
|
|
|
+
|
|
|
+### 入门版(¥9.9/月)
|
|
|
+
|
|
|
+```
|
|
|
+配额:10,000 Token/月
|
|
|
+成本:10,000 × ¥2.0/千 = ¥20.0
|
|
|
+售价:¥9.9
|
|
|
+利润:-¥10.1(亏损,获客用)
|
|
|
+策略:薄利或亏损,用于付费转化漏斗
|
|
|
+```
|
|
|
+
|
|
|
+### 专业版(¥59/月)⭐ 推荐
|
|
|
+
|
|
|
+```
|
|
|
+配额:20,000 Token/月
|
|
|
+成本:20,000 × ¥2.0/千 = ¥40.0
|
|
|
+售价:¥59.0
|
|
|
+利润:¥19.0
|
|
|
+利润率:32%
|
|
|
+策略:主要盈利产品
|
|
|
+```
|
|
|
+
|
|
|
+### 旗舰版(¥199/月)
|
|
|
+
|
|
|
+```
|
|
|
+配额:50,000 Token/月
|
|
|
+成本:50,000 × ¥2.0/千 = ¥100.0
|
|
|
+售价:¥199.0
|
|
|
+利润:¥99.0
|
|
|
+利润率:50%
|
|
|
+策略:高端用户,保证利润
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 🔧 Token扣费逻辑
|
|
|
+
|
|
|
+### 扣费流程
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 1. 用户提交生成请求
|
|
|
+async function generateAudio(userId: number, text: string) {
|
|
|
+ const textLength = text.length;
|
|
|
+
|
|
|
+ // 2. 计算Token消耗
|
|
|
+ const tokens = calculateTokens(textLength); // 1字 ≈ 1 token
|
|
|
+ const cost = calculateCost(tokens, 'deepseek'); // ¥2.0/千token
|
|
|
+
|
|
|
+ // 3. 检查用户配额
|
|
|
+ const balance = await getUserTokenBalance(userId);
|
|
|
+
|
|
|
+ if (balance.remainingTokens < tokens) {
|
|
|
+ throw new Error('Token余额不足,请充值');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 扣除Token
|
|
|
+ await consumeToken(userId, tokens, {
|
|
|
+ type: 'text_to_speech',
|
|
|
+ description: `生成音频:${textLength}字`
|
|
|
+ });
|
|
|
+
|
|
|
+ // 5. 调用AI生成音频
|
|
|
+ const audioUrl = await callTTSAPI(text);
|
|
|
+
|
|
|
+ return { audioUrl, tokens, cost };
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 成本计算函数
|
|
|
+
|
|
|
+```typescript
|
|
|
+// server/src/modules/subscription/subscription.service.ts
|
|
|
+
|
|
|
+// Token成本配置
|
|
|
+export const TOKEN_COST_CONFIG = {
|
|
|
+ baseCostPerThousand: 2.0, // DeepSeek基础价
|
|
|
+ extraPricePerThousand: 3.5, // 超额单价
|
|
|
+
|
|
|
+ models: {
|
|
|
+ deepseek: {
|
|
|
+ name: 'DeepSeek V3.2',
|
|
|
+ inputCost: 2.0, // ¥2.0/千token
|
|
|
+ outputCost: 8.0, // ¥8.0/千token
|
|
|
+ quality: 'standard'
|
|
|
+ },
|
|
|
+ qwen_plus: {
|
|
|
+ name: '通义 Qwen Plus',
|
|
|
+ inputCost: 4.0, // ¥4.0/千token
|
|
|
+ outputCost: 12.0, // ¥12.0/千token
|
|
|
+ quality: 'high'
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 计算Token成本
|
|
|
+export function calculateTokenCost(textLength: number, model: string = 'deepseek') {
|
|
|
+ const modelConfig = TOKEN_COST_CONFIG.models[model];
|
|
|
+
|
|
|
+ // 输入成本
|
|
|
+ const inputCost = (textLength / 1000) * modelConfig.inputCost;
|
|
|
+
|
|
|
+ // 输出成本(简化计算)
|
|
|
+ const outputCost = (textLength / 1000) * modelConfig.outputCost * 0.1;
|
|
|
+
|
|
|
+ // 总成本
|
|
|
+ const totalCost = inputCost + outputCost;
|
|
|
+
|
|
|
+ // 建议售价(成本 × 1.5,保证50%利润)
|
|
|
+ const suggestedPrice = totalCost * 1.5;
|
|
|
+
|
|
|
+ return {
|
|
|
+ inputCost: Math.round(inputCost * 100) / 100,
|
|
|
+ outputCost: Math.round(outputCost * 100) / 100,
|
|
|
+ totalCost: Math.round(totalCost * 100) / 100,
|
|
|
+ suggestedPrice: Math.round(suggestedPrice * 100) / 100
|
|
|
+ };
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### Token扣费示例
|
|
|
+
|
|
|
+#### 示例1:免费版用户
|
|
|
+```
|
|
|
+用户等级:免费版
|
|
|
+配额:5,000 Token/月
|
|
|
+已用:2,000 Token
|
|
|
+剩余:3,000 Token
|
|
|
+
|
|
|
+生成请求:1,500字
|
|
|
+
|
|
|
+检查:
|
|
|
+ ✓ 剩余3,000 ≥ 需要1,500
|
|
|
+ ✓ 字数1,500 ≤ 每次限制2,000
|
|
|
+
|
|
|
+扣费:
|
|
|
+ 成本:1,500 × ¥2.0/千 = ¥3.0
|
|
|
+ 剩余Token:3,000 - 1,500 = 1,500
|
|
|
+ 记录使用:1,500 Token
|
|
|
+```
|
|
|
+
|
|
|
+#### 示例2:专业版用户
|
|
|
+```
|
|
|
+用户等级:专业版
|
|
|
+配额:20,000 Token/月
|
|
|
+已用:15,000 Token
|
|
|
+剩余:5,000 Token
|
|
|
+
|
|
|
+生成请求:3,000字
|
|
|
+
|
|
|
+检查:
|
|
|
+ ✓ 剩余5,000 ≥ 需要3,000
|
|
|
+ ✓ 字数3,000 ≤ 每次限制10,000
|
|
|
+
|
|
|
+扣费:
|
|
|
+ 成本:3,000 × ¥2.0/千 = ¥6.0
|
|
|
+ 剩余Token:5,000 - 3,000 = 2,000
|
|
|
+ 记录使用:3,000 Token
|
|
|
+```
|
|
|
+
|
|
|
+#### 示例3:Token不足
|
|
|
+```
|
|
|
+用户等级:入门版
|
|
|
+配额:10,000 Token/月
|
|
|
+已用:9,500 Token
|
|
|
+剩余:500 Token
|
|
|
+
|
|
|
+生成请求:2,000字
|
|
|
+
|
|
|
+检查:
|
|
|
+ ✗ 剩余500 < 需要2,000
|
|
|
+ → 余额不足
|
|
|
+
|
|
|
+处理:
|
|
|
+ 返回错误:Token余额不足
|
|
|
+ 建议:升级套餐或等待月度重置
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 📐 超额使用计费
|
|
|
+
|
|
|
+### 超额单价
|
|
|
+
|
|
|
+| 套餐 | 月配额 | 超额单价 | 说明 |
|
|
|
+|------|--------|---------|------|
|
|
|
+| 免费版 | 5,000 | ¥4.0/千 | 不支持超额 |
|
|
|
+| 入门版 | 10,000 | ¥3.5/千 | 超额自动计费 |
|
|
|
+| 专业版 | 20,000 | ¥3.0/千 | 超额自动计费 |
|
|
|
+| 旗舰版 | 50,000 | ¥2.5/千 | 超额享受折扣 |
|
|
|
+
|
|
|
+### 超额计费示例
|
|
|
+
|
|
|
+```
|
|
|
+用户等级:入门版
|
|
|
+月配额:10,000 Token
|
|
|
+月费:¥9.9
|
|
|
+
|
|
|
+当月使用:
|
|
|
+ Token消耗:13,500 Token
|
|
|
+
|
|
|
+计费:
|
|
|
+ 包含部分:10,000 Token = ¥0(已付月费)
|
|
|
+ 超额部分:3,500 Token × ¥3.5/千 = ¥12.25
|
|
|
+
|
|
|
+额外费用:¥12.25
|
|
|
+总费用:¥9.9 + ¥12.25 = ¥22.15
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 🎯 模型选择策略
|
|
|
+
|
|
|
+### 默认模型:DeepSeek V3.2
|
|
|
+
|
|
|
+```
|
|
|
+成本:¥2.0/千token
|
|
|
+适用:95%场景
|
|
|
+质量:标准/良好
|
|
|
+```
|
|
|
+
|
|
|
+### 高质量模型:通义 Qwen Plus
|
|
|
+
|
|
|
+```
|
|
|
+成本:¥4.0/千token
|
|
|
+适用:5%高质量需求
|
|
|
+额外费用:+¥2.0/千token
|
|
|
+质量:优秀
|
|
|
+```
|
|
|
+
|
|
|
+### 模型选择UI
|
|
|
+
|
|
|
+```vue
|
|
|
+<!-- 前端模型选择 -->
|
|
|
+<view class="model-selector">
|
|
|
+ <text class="label">选择模型</text>
|
|
|
+
|
|
|
+ <view class="option" @click="selectModel('deepseek')">
|
|
|
+ <text class="name">DeepSeek V3.2</text>
|
|
|
+ <text class="price">¥2.0/千token</text>
|
|
|
+ <text class="desc">高性价比,推荐</text>
|
|
|
+ <view class="check" v-if="selectedModel === 'deepseek'">✓</view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="option" @click="selectModel('qwen_plus')">
|
|
|
+ <text class="name">通义 Qwen Plus</text>
|
|
|
+ <text class="price">¥4.0/千token</text>
|
|
|
+ <text class="desc">高质量生成</text>
|
|
|
+ <view class="check" v-if="selectedModel === 'qwen_plus'">✓</view>
|
|
|
+ </view>
|
|
|
+</view>
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 💡 成本控制措施
|
|
|
+
|
|
|
+### 1. 每日使用限制
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 每日生成次数
|
|
|
+const DAILY_LIMITS = {
|
|
|
+ 0: 3, // 免费版:3次/天
|
|
|
+ 1: 10, // 入门版:10次/天
|
|
|
+ 2: 50, // 专业版:50次/天
|
|
|
+ 3: -1 // 旗舰版:无限制
|
|
|
+};
|
|
|
+
|
|
|
+// 检查每日限制
|
|
|
+async function checkDailyLimit(userId: number) {
|
|
|
+ const today = new Date().toISOString().slice(0, 10);
|
|
|
+ const todayUsage = await prisma.tokenUsage.count({
|
|
|
+ where: {
|
|
|
+ userId,
|
|
|
+ createdAt: { gte: new Date(today) }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ const limit = DAILY_LIMITS[user.memberLevel];
|
|
|
+
|
|
|
+ if (limit !== -1 && todayUsage >= limit) {
|
|
|
+ throw new Error(`今日生成次数已用完(${limit}次),请明天再试`);
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 2. 每次生成上限
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 每次生成字数限制
|
|
|
+const PER_GENERATION_LIMITS = {
|
|
|
+ 0: 1000, // 免费版:1000字
|
|
|
+ 1: 3000, // 入门版:3000字
|
|
|
+ 2: 10000, // 专业版:10000字
|
|
|
+ 3: 50000 // 旗舰版:50000字
|
|
|
+};
|
|
|
+
|
|
|
+// 检查单次限制
|
|
|
+function checkPerGenerationLimit(textLength: number, memberLevel: number) {
|
|
|
+ const limit = PER_GENERATION_LIMITS[memberLevel];
|
|
|
+
|
|
|
+ if (textLength > limit) {
|
|
|
+ throw new Error(`单次生成字数不能超过${limit}字`);
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 3. 每月配额重置
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 每月1日重置配额
|
|
|
+async function resetMonthlyQuota() {
|
|
|
+ const users = await prisma.user.findMany();
|
|
|
+
|
|
|
+ for (const user of users) {
|
|
|
+ const balance = await prisma.tokenBalance.findUnique({
|
|
|
+ where: { userId: user.id }
|
|
|
+ });
|
|
|
+
|
|
|
+ if (balance) {
|
|
|
+ const plan = await prisma.subscriptionPlan.findFirst({
|
|
|
+ where: { level: user.memberLevel }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 重置配额
|
|
|
+ await prisma.tokenBalance.update({
|
|
|
+ where: { userId: user.id },
|
|
|
+ data: {
|
|
|
+ totalTokens: plan.monthlyTokens,
|
|
|
+ usedTokens: 0,
|
|
|
+ resetDate: new Date()
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 📊 成本监控
|
|
|
+
|
|
|
+### 每日成本报表
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 生成成本报表
|
|
|
+async function generateCostReport(date: string) {
|
|
|
+ const startDate = new Date(date);
|
|
|
+ const endDate = new Date(startDate.getTime() + 24 * 60 * 60 * 1000);
|
|
|
+
|
|
|
+ const usages = await prisma.tokenUsage.findMany({
|
|
|
+ where: {
|
|
|
+ createdAt: {
|
|
|
+ gte: startDate,
|
|
|
+ lt: endDate
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 统计
|
|
|
+ const totalTokens = usages.reduce((sum, u) => sum + u.amount, 0);
|
|
|
+ const totalCost = totalTokens * TOKEN_COST_CONFIG.baseCostPerThousand / 1000;
|
|
|
+ const userCount = new Set(usages.map(u => u.userId)).size;
|
|
|
+
|
|
|
+ return {
|
|
|
+ date,
|
|
|
+ totalTokens,
|
|
|
+ totalCost: Math.round(totalCost * 100) / 100,
|
|
|
+ userCount,
|
|
|
+ avgTokensPerUser: Math.round(totalTokens / userCount),
|
|
|
+ avgCostPerUser: Math.round((totalCost / userCount) * 100) / 100
|
|
|
+ };
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 预警机制
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 成本预警
|
|
|
+async function checkCostWarning(userId: number) {
|
|
|
+ const balance = await prisma.tokenBalance.findUnique({
|
|
|
+ where: { userId }
|
|
|
+ });
|
|
|
+
|
|
|
+ const usagePercent = balance.usedTokens / balance.totalTokens * 100;
|
|
|
+
|
|
|
+ if (usagePercent >= 90) {
|
|
|
+ // 发送预警通知
|
|
|
+ await sendNotification(userId, {
|
|
|
+ type: 'warning',
|
|
|
+ title: 'Token余额不足',
|
|
|
+ content: `已使用${usagePercent.toFixed(0)}%,建议续费`
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 📋 定价公式总结
|
|
|
+
|
|
|
+### 单次生成成本
|
|
|
+
|
|
|
+```
|
|
|
+输入成本 = 字数 × ¥2.0 / 1000
|
|
|
+输出成本 = 字数 × ¥8.0 / 10000
|
|
|
+总成本 = 输入成本 + 输出成本
|
|
|
+```
|
|
|
+
|
|
|
+### 套餐月费成本
|
|
|
+
|
|
|
+```
|
|
|
+月成本 = 月Token配额 × ¥2.0 / 1000
|
|
|
+月售价 = 月成本 × 1.5(50%利润率)
|
|
|
+```
|
|
|
+
|
|
|
+### 超额使用计费
|
|
|
+
|
|
|
+```
|
|
|
+超额费用 = 超额Token × 超额单价 / 1000
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## ✅ 定价检查清单
|
|
|
+
|
|
|
+- [x] Token单价 ≥ ¥2.0(成本价)
|
|
|
+- [x] 套餐利润率 ≥ 30%
|
|
|
+- [x] 专业版:主要盈利产品
|
|
|
+- [x] 旗舰版:50%利润率
|
|
|
+- [x] 超额单价 ≥ 成本价
|
|
|
+- [x] 成本监控机制
|
|
|
+- [x] 每日/每月限制
|
|
|
+- [x] 预警通知系统
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 🚀 下一步行动
|
|
|
+
|
|
|
+1. [ ] 集成Token扣费到TTS生成流程
|
|
|
+2. [ ] 配置成本监控报表
|
|
|
+3. [ ] 测试超额计费逻辑
|
|
|
+4. [ ] 上线监控告警
|