All files / services ai-call-logger.ts

0% Statements 0/35
0% Branches 0/1
0% Functions 0/1
0% Lines 0/35

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73                                                                                                                                                 
/**
 * AI 调用日志 —— 记录每次大模型 / TTS API 请求,方便对账
 *
 * 写入策略:fire-and-forget,不阻塞业务请求
 */
 
import { prisma } from '../models';
 
export interface LogCallParams {
  callType: string;    // tts_create | tts_poll | tts_download | llm_chat | llm_tools
  provider: string;    // minimax | bailian | volcengine
  model: string;       // speech-2.8-hd | qwen3-tts-instruct-flash | MiniMax-M2.7
  textLen?: number;
  prompt?: string;     // 提示词内容
  tokenCount?: number;
  duration?: number;
  success?: boolean;
  errorMsg?: string;
  bookId?: number;
  chapterId?: number;
}
 
/**
 * 记录一次 AI 调用(异步写入,不阻塞)
 */
export function logAiCall(params: LogCallParams): void {
  // Always log to console so we know it was called
  console.log(`[AiCallLog] ${params.callType} | ${params.provider} | ${params.model} | ${params.success ? 'OK' : 'FAIL'} | ${params.textLen || 0}字`);
  
  prisma.aiCallLog.create({
    data: {
      callType: params.callType,
      provider: params.provider,
      model: params.model,
      textLen: params.textLen ?? 0,
      prompt: params.prompt ?? null,
      duration: params.duration ?? 0,
      success: params.success ?? true,
      errorMsg: params.errorMsg?.substring(0, 200) ?? null,
      bookId: params.bookId ?? null,
      chapterId: params.chapterId ?? null,
    },
  }).then(result => {
    // Successfully written
  }).catch(err => {
    console.error('[AiCallLog] ❌ 写入数据库失败:', err.message);
  });
}
 
/**
 * 包装异步函数,自动计时 + 记录日志
 *
 * 用法:
 *   const result = await withAiLog(
 *     () => axios.post(url, body),
 *     { callType: 'tts_create', provider: 'minimax', model: 'speech-2.8-hd', textLen: 1000 }
 *   );
 */
export async function withAiLog<T>(
  fn: () => Promise<T>,
  params: LogCallParams,
): Promise<T> {
  const t0 = Date.now();
  try {
    const result = await fn();
    logAiCall({ ...params, duration: Date.now() - t0 });
    return result;
  } catch (err: any) {
    logAiCall({ ...params, duration: Date.now() - t0, success: false, errorMsg: err.message });
    throw err;
  }
}