import { prisma } from '../../models'; import { MemberLevel } from '../../types'; // ============================================ // TTS服务商成本配置(2026-04-12 更新) // ============================================ export const TTS_COST_CONFIG = { // TTS服务商配置 providers: { // 免费方案(科大讯飞基础版) iflytek_free: { name: '科大讯飞-基础版', costPerThousand: 0, // 免费 quality: 'standard', voiceOptions: 10, freeQuota: 100000, // 10万/月(永久) novelRating: 3 // ★★★☆☆ }, // 性价比方案(百度基础版) baidu_standard: { name: '百度智能云-基础版', costPerThousand: 3.0, // ¥3/千字符 quality: 'standard', voiceOptions: 20, freeQuota: 2000000, // 200万/月(首年) novelRating: 4 // ★★★★☆ }, // 高质量方案(百度精品版) baidu_premium: { name: '百度智能云-精品版', costPerThousand: 15.0, // ¥15/千字符 quality: 'premium', voiceOptions: 50, freeQuota: 0, novelRating: 5 // ★★★★★ }, // 阿里云方案 aliyun_plus: { name: '阿里云Qwen3-Plus', costPerThousand: 12.0, // ¥12/千字符 quality: 'high', voiceOptions: 30, freeQuota: 0, novelRating: 5 // ★★★★★ }, // 企业方案(火山引擎) volcano_premium: { name: '火山引擎豆包-标准版', costPerThousand: 50.0, // ¥50/千字符 quality: 'premium', voiceOptions: 40, freeQuota: 20000, // 2万/应用 novelRating: 5 // ★★★★★ } }, // AI模型成本配置 aiModels: { deepseek: { name: 'DeepSeek V3.2', inputCost: 2.0, // ¥2.0/千token outputCost: 8.0, // ¥8.0/千token quality: 'standard', default: true }, qwen_plus: { name: '通义Qwen Plus', inputCost: 4.0, // ¥4.0/千token outputCost: 12.0, // ¥12.0/千token quality: 'high' }, doubao_pro: { name: '豆包 Pro', inputCost: 2.0, // ¥2.0/千token outputCost: 6.0, // ¥6.0/千token quality: 'high' } }, // 各等级默认TTS方案 planTTSProvider: { 0: 'iflytek_free', // 免费版:科大讯飞免费 1: 'baidu_standard', // 入门版:百度基础 2: 'baidu_premium', // 专业版:百度精品 3: 'volcano_premium' // 旗舰版:火山引擎 }, // 默认AI模型 defaultAIModel: 'deepseek' }; // ============================================ // Token成本配置(AI生成成本 + TTS成本) // ============================================ export const TOKEN_COST_CONFIG = { // 基础Token成本(DeepSeek V3.2 + 百度基础TTS) baseCostPerThousand: 5.0, // AI: ¥2 + TTS: ¥3 = ¥5/千字符 // 超额使用单价 extraPricePerThousand: 6.0, // 略高于成本价 // 模型选择 models: { deepseek: { name: 'DeepSeek V3.2', inputCost: 2.0, // ¥2.0/千token outputCost: 8.0, // ¥8.0/千token quality: 'standard', default: true }, qwen_plus: { name: '通义 Qwen Plus', inputCost: 4.0, // ¥4.0/千token outputCost: 12.0, // ¥12.0/千token quality: 'high', extraFee: 1.5 // 每千token额外收费 }, doubao_pro: { name: '豆包 Pro', inputCost: 2.0, // ¥2.0/千token outputCost: 6.0, // ¥6.0/千token quality: 'high' } } }; // 计算Token生成成本 export function calculateTokenCost(textLength: number, model: string = 'deepseek'): { inputCost: number; outputCost: number; totalCost: number; suggestedPrice: number; } { const modelConfig = TOKEN_COST_CONFIG.models[model] || TOKEN_COST_CONFIG.models.deepseek; // 输入成本 const inputTokens = textLength; // 1字 ≈ 1 token const inputCost = (inputTokens / 1000) * modelConfig.inputCost; // 输出成本(音频合成) const outputCost = textLength * 0.001 * 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 }; } // 默认套餐配置(基于TTS成本,2026-04-12更新) export const DEFAULT_PLANS = [ { name: '免费版', level: 0, priceMonthly: 0, priceYearly: 0, description: '适合轻度体验', features: JSON.stringify([ '每天3次生成', '每次最多2000字', '基础音色5种', '标准音质', '科大讯飞免费额度(10万/月永久)', 'Token成本:¥17.5/月(平台补贴)' ]), isRecommended: false, sortOrder: 0, dailyGenerations: 3, perGenerationLimit: 2000, monthlyTokens: 5000, // AI+基础TTS成本:¥17.5 yearlyTokens: null, voiceOptions: 5, audioQuality: 'standard', apiAccess: false, batchProcessing: false, teamManagement: false, // 成本分析 costAnalysis: { tokenCost: 17.5, // Token成本 platformSubsidy: true, // 平台补贴 profitMargin: 0, ttsProvider: '科大讯飞-基础版', aiModel: 'DeepSeek V3.2' } }, { name: '入门版', level: 1, priceMonthly: 9.9, priceYearly: 99, description: '适合日常使用', features: JSON.stringify([ '每月10000 Token', '每次最多5000字', '全部音色', '高清音质', '百度基础版TTS(¥3/千字符)', 'Token成本:¥35/月' ]), isRecommended: false, sortOrder: 1, dailyGenerations: 10, perGenerationLimit: 5000, monthlyTokens: 10000, // AI+基础TTS成本:¥35 yearlyTokens: null, voiceOptions: -1, audioQuality: 'high', apiAccess: false, batchProcessing: false, teamManagement: false, // 成本分析(亏损,用于获客转化) costAnalysis: { tokenCost: 35.0, monthlyPrice: 9.9, loss: -25.1, // 每单亏损,获客用 strategy: '获客转化', ttsProvider: '百度智能云-基础版' } }, { name: '专业版', level: 2, priceMonthly: 49, priceYearly: 490, description: '适合内容创作者 ⭐推荐', features: JSON.stringify([ '每月30000 Token', '每次最多20000字', '全部音色+定制音色', '高清音质', '百度精品版TTS(¥15/千字符)', 'VIP优先队列', 'Token成本:¥105/月' ]), isRecommended: true, sortOrder: 2, dailyGenerations: -1, perGenerationLimit: 20000, monthlyTokens: 30000, // AI+精品TTS成本:¥105 yearlyTokens: null, voiceOptions: -1, audioQuality: 'lossless', apiAccess: false, batchProcessing: false, teamManagement: false, // 成本分析(部分补贴,核心盈利) costAnalysis: { tokenCost: 105.0, monthlyPrice: 49, loss: -56.0, // 部分补贴 profitMargin: 0, // 保本微亏 strategy: '核心转化产品', ttsProvider: '百度智能云-精品版' } }, { name: '旗舰版', level: 3, priceMonthly: 199, priceYearly: 1999, description: '适合企业用户', features: JSON.stringify([ '每月100000 Token', '每次最多100000字', '全部功能', '无损音质', '火山引擎豆包TTS(¥50/千字符)', '专属技术支持', '批量处理', '团队管理', 'Token成本:¥350/月' ]), isRecommended: false, sortOrder: 3, dailyGenerations: -1, // 无限制 perGenerationLimit: 100000, monthlyTokens: 100000, // AI+高端TTS成本:¥350 yearlyTokens: null, voiceOptions: -1, audioQuality: 'lossless', apiAccess: true, batchProcessing: true, teamManagement: true, // 成本分析(盈利) costAnalysis: { tokenCost: 350.0, monthlyPrice: 199, profit: -151.0, // 仍有亏损,建议涨价 profitMargin: 0, suggestion: '建议定价¥399-499/月', ttsProvider: '火山引擎豆包' } } ]; // 初始化套餐数据 export async function initializePlans() { const existingPlans = await prisma.subscriptionPlan.count(); if (existingPlans === 0) { console.log('初始化订阅套餐数据...'); for (const plan of DEFAULT_PLANS) { await prisma.subscriptionPlan.create({ data: plan }); } console.log('订阅套餐初始化完成'); } } // 获取所有套餐列表 export async function getPlans() { const plans = await prisma.subscriptionPlan.findMany({ where: { isActive: true }, orderBy: { sortOrder: 'asc' } }); return plans.map(plan => ({ ...plan, priceMonthly: Number(plan.priceMonthly), priceYearly: Number(plan.priceYearly), features: JSON.parse(plan.features || '[]') })); } // 获取单个套餐详情 export async function getPlanById(planId: number) { const plan = await prisma.subscriptionPlan.findUnique({ where: { id: planId } }); if (!plan) { throw new Error('套餐不存在'); } return { ...plan, priceMonthly: Number(plan.priceMonthly), priceYearly: Number(plan.priceYearly), features: JSON.parse(plan.features || '[]') }; } // 获取用户当前订阅信息 export async function getUserSubscription(userId: number) { const subscription = await prisma.subscription.findFirst({ where: { userId, status: 'active', endDate: { gt: new Date() } }, include: { plan: true }, orderBy: { endDate: 'desc' } }); return subscription; } // 获取用户Token余额 export async function getUserTokenBalance(userId: number) { let balance = await prisma.tokenBalance.findUnique({ where: { userId } }); if (!balance) { // 初始化Token余额 balance = await prisma.tokenBalance.create({ data: { userId, totalTokens: 10000, // 默认免费额度 usedTokens: 0 } }); } const remaining = balance.totalTokens - balance.usedTokens; return { totalTokens: balance.totalTokens, usedTokens: balance.usedTokens, remainingTokens: remaining, resetDate: balance.resetDate, isUnlimited: balance.totalTokens === -1 }; } // 获取Token使用记录 export async function getTokenUsageList(userId: number, page: number = 1, pageSize: number = 20) { const where = { userId }; const total = await prisma.tokenUsage.count({ where }); const list = await prisma.tokenUsage.findMany({ where, orderBy: { createdAt: 'desc' }, skip: (page - 1) * pageSize, take: pageSize }); return { list, total, page, pageSize, totalPages: Math.ceil(total / pageSize) }; } // 消耗Token export async function consumeToken( userId: number, amount: number, type: string, contentLength: number, description?: string ) { const balance = await prisma.tokenBalance.findUnique({ where: { userId } }); if (!balance) { throw new Error('用户Token余额不存在'); } if (balance.totalTokens !== -1 && balance.usedTokens + amount > balance.totalTokens) { throw new Error('Token余额不足'); } // 更新余额 await prisma.tokenBalance.update({ where: { userId }, data: { usedTokens: { increment: amount } } }); // 记录使用 const usage = await prisma.tokenUsage.create({ data: { userId, type, amount, contentLength, description } }); return usage; } // 获取用户配额(兼容旧接口) export async function getUserQuota(userId: number) { const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user) { throw new Error('用户不存在'); } const subscription = await getUserSubscription(userId); const tokenBalance = await getUserTokenBalance(userId); const memberLevel = user.memberLevel as MemberLevel; const levelNames = ['免费版', '基础版', '专业版', '旗舰版']; return { level: memberLevel, levelName: levelNames[memberLevel] || '免费版', isValid: subscription !== null, expireAt: subscription?.endDate, plan: subscription?.plan ? { name: subscription.plan.name, features: JSON.parse(subscription.plan.features || '[]') } : null, tokenBalance, limits: subscription?.plan ? { dailyGenerations: subscription.plan.dailyGenerations, perGenerationLimit: subscription.plan.perGenerationLimit, monthlyTokens: subscription.plan.monthlyTokens, voiceOptions: subscription.plan.voiceOptions, audioQuality: subscription.plan.audioQuality } : { dailyGenerations: 3, perGenerationLimit: 2000, monthlyTokens: 10000, voiceOptions: 5, audioQuality: 'standard' } }; } // 检查用户配额 export async function checkQuota(userId: number, requiredTokens: number) { const quota = await getUserQuota(userId); const balance = quota.tokenBalance; if (balance.isUnlimited) { return { allowed: true, reason: null }; } if (balance.remainingTokens < requiredTokens) { return { allowed: false, reason: 'Token余额不足', required: requiredTokens, remaining: balance.remainingTokens }; } return { allowed: true, reason: null }; }