498 lines
12 KiB
TypeScript
498 lines
12 KiB
TypeScript
import { ApiResponse } from '@/types';
|
|
|
|
// API配置
|
|
interface ApiConfig {
|
|
baseUrl: string;
|
|
timeout: number;
|
|
retries: number;
|
|
}
|
|
|
|
// Twilio配置
|
|
interface TwilioConfig {
|
|
accountSid: string;
|
|
authToken: string;
|
|
phoneNumber: string;
|
|
}
|
|
|
|
// Stripe配置
|
|
interface StripeConfig {
|
|
publishableKey: string;
|
|
secretKey: string;
|
|
}
|
|
|
|
// OpenAI配置
|
|
interface OpenAIConfig {
|
|
apiKey: string;
|
|
model: string;
|
|
}
|
|
|
|
class ApiManager {
|
|
private config: ApiConfig;
|
|
private twilioConfig?: TwilioConfig;
|
|
private stripeConfig?: StripeConfig;
|
|
private openaiConfig?: OpenAIConfig;
|
|
|
|
constructor(config: ApiConfig) {
|
|
this.config = config;
|
|
}
|
|
|
|
// 配置第三方服务
|
|
configureTwilio(config: TwilioConfig) {
|
|
this.twilioConfig = config;
|
|
}
|
|
|
|
configureStripe(config: StripeConfig) {
|
|
this.stripeConfig = config;
|
|
}
|
|
|
|
configureOpenAI(config: OpenAIConfig) {
|
|
this.openaiConfig = config;
|
|
}
|
|
|
|
// 通用HTTP请求方法
|
|
private async request<T>(
|
|
endpoint: string,
|
|
options: RequestInit = {}
|
|
): Promise<ApiResponse<T>> {
|
|
const url = `${this.config.baseUrl}${endpoint}`;
|
|
|
|
const defaultHeaders = {
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json',
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(url, {
|
|
...options,
|
|
headers: {
|
|
...defaultHeaders,
|
|
...options.headers,
|
|
},
|
|
signal: AbortSignal.timeout(this.config.timeout),
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (!response.ok) {
|
|
return {
|
|
success: false,
|
|
error: data.message || `HTTP ${response.status}: ${response.statusText}`,
|
|
};
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
data,
|
|
};
|
|
} catch (error) {
|
|
console.error('API请求失败:', error);
|
|
return {
|
|
success: false,
|
|
error: error instanceof Error ? error.message : '网络请求失败',
|
|
};
|
|
}
|
|
}
|
|
|
|
// GET请求
|
|
async get<T>(endpoint: string, params?: Record<string, any>): Promise<ApiResponse<T>> {
|
|
const url = new URL(`${this.config.baseUrl}${endpoint}`);
|
|
if (params) {
|
|
Object.entries(params).forEach(([key, value]) => {
|
|
if (value !== undefined && value !== null) {
|
|
url.searchParams.append(key, String(value));
|
|
}
|
|
});
|
|
}
|
|
|
|
return this.request<T>(url.pathname + url.search);
|
|
}
|
|
|
|
// POST请求
|
|
async post<T>(endpoint: string, data?: any): Promise<ApiResponse<T>> {
|
|
return this.request<T>(endpoint, {
|
|
method: 'POST',
|
|
body: data ? JSON.stringify(data) : undefined,
|
|
});
|
|
}
|
|
|
|
// PUT请求
|
|
async put<T>(endpoint: string, data?: any): Promise<ApiResponse<T>> {
|
|
return this.request<T>(endpoint, {
|
|
method: 'PUT',
|
|
body: data ? JSON.stringify(data) : undefined,
|
|
});
|
|
}
|
|
|
|
// DELETE请求
|
|
async delete<T>(endpoint: string): Promise<ApiResponse<T>> {
|
|
return this.request<T>(endpoint, {
|
|
method: 'DELETE',
|
|
});
|
|
}
|
|
|
|
// Twilio相关API
|
|
async initiateCall(callData: {
|
|
from: string;
|
|
to: string;
|
|
sourceLanguage: string;
|
|
targetLanguage: string;
|
|
type: 'ai' | 'human' | 'video' | 'sign';
|
|
}): Promise<ApiResponse<{ callSid: string; status: string }>> {
|
|
if (!this.twilioConfig) {
|
|
return {
|
|
success: false,
|
|
error: 'Twilio配置未初始化',
|
|
};
|
|
}
|
|
|
|
// 模拟Twilio API调用
|
|
console.log('发起Twilio通话:', callData);
|
|
|
|
// 模拟API响应
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
callSid: `CA${Date.now().toString()}`,
|
|
status: 'initiated',
|
|
},
|
|
};
|
|
}
|
|
|
|
async endCall(callSid: string): Promise<ApiResponse<{ status: string }>> {
|
|
if (!this.twilioConfig) {
|
|
return {
|
|
success: false,
|
|
error: 'Twilio配置未初始化',
|
|
};
|
|
}
|
|
|
|
console.log('结束Twilio通话:', callSid);
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
status: 'completed',
|
|
},
|
|
};
|
|
}
|
|
|
|
async getCallStatus(callSid: string): Promise<ApiResponse<{
|
|
status: string;
|
|
duration: number;
|
|
startTime: string;
|
|
endTime?: string;
|
|
}>> {
|
|
if (!this.twilioConfig) {
|
|
return {
|
|
success: false,
|
|
error: 'Twilio配置未初始化',
|
|
};
|
|
}
|
|
|
|
console.log('查询通话状态:', callSid);
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 300));
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
status: 'completed',
|
|
duration: 900,
|
|
startTime: '2024-01-15T10:30:00Z',
|
|
endTime: '2024-01-15T10:45:00Z',
|
|
},
|
|
};
|
|
}
|
|
|
|
// Stripe相关API
|
|
async createPaymentIntent(paymentData: {
|
|
amount: number;
|
|
currency: string;
|
|
customerId?: string;
|
|
description?: string;
|
|
}): Promise<ApiResponse<{ clientSecret: string; paymentIntentId: string }>> {
|
|
if (!this.stripeConfig) {
|
|
return {
|
|
success: false,
|
|
error: 'Stripe配置未初始化',
|
|
};
|
|
}
|
|
|
|
console.log('创建Stripe支付意向:', paymentData);
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 800));
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
clientSecret: `pi_${Date.now()}_secret_${Math.random().toString(36).substr(2, 9)}`,
|
|
paymentIntentId: `pi_${Date.now()}`,
|
|
},
|
|
};
|
|
}
|
|
|
|
async confirmPayment(paymentIntentId: string): Promise<ApiResponse<{
|
|
status: string;
|
|
amount: number;
|
|
currency: string;
|
|
}>> {
|
|
if (!this.stripeConfig) {
|
|
return {
|
|
success: false,
|
|
error: 'Stripe配置未初始化',
|
|
};
|
|
}
|
|
|
|
console.log('确认Stripe支付:', paymentIntentId);
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 1200));
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
status: 'succeeded',
|
|
amount: 2500,
|
|
currency: 'cny',
|
|
},
|
|
};
|
|
}
|
|
|
|
async refundPayment(paymentIntentId: string, amount?: number): Promise<ApiResponse<{
|
|
refundId: string;
|
|
status: string;
|
|
amount: number;
|
|
}>> {
|
|
if (!this.stripeConfig) {
|
|
return {
|
|
success: false,
|
|
error: 'Stripe配置未初始化',
|
|
};
|
|
}
|
|
|
|
console.log('Stripe退款:', { paymentIntentId, amount });
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
refundId: `re_${Date.now()}`,
|
|
status: 'succeeded',
|
|
amount: amount || 2500,
|
|
},
|
|
};
|
|
}
|
|
|
|
// OpenAI相关API
|
|
async translateText(textData: {
|
|
text: string;
|
|
sourceLanguage: string;
|
|
targetLanguage: string;
|
|
context?: string;
|
|
}): Promise<ApiResponse<{ translatedText: string; confidence: number }>> {
|
|
if (!this.openaiConfig) {
|
|
return {
|
|
success: false,
|
|
error: 'OpenAI配置未初始化',
|
|
};
|
|
}
|
|
|
|
console.log('OpenAI文本翻译:', textData);
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
|
|
// 模拟翻译结果
|
|
const translations: Record<string, string> = {
|
|
'zh-CN_en-US': 'Hello, this is a translated text.',
|
|
'en-US_zh-CN': '您好,这是翻译后的文本。',
|
|
'zh-CN_ja-JP': 'こんにちは、これは翻訳されたテキストです。',
|
|
};
|
|
|
|
const key = `${textData.sourceLanguage}_${textData.targetLanguage}`;
|
|
const translatedText = translations[key] || 'Translation completed.';
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
translatedText,
|
|
confidence: 0.95,
|
|
},
|
|
};
|
|
}
|
|
|
|
async transcribeAudio(audioData: {
|
|
audioUrl: string;
|
|
language: string;
|
|
}): Promise<ApiResponse<{ transcription: string; confidence: number }>> {
|
|
if (!this.openaiConfig) {
|
|
return {
|
|
success: false,
|
|
error: 'OpenAI配置未初始化',
|
|
};
|
|
}
|
|
|
|
console.log('OpenAI音频转录:', audioData);
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
transcription: '这是转录的音频内容,包含了用户的语音信息。',
|
|
confidence: 0.92,
|
|
},
|
|
};
|
|
}
|
|
|
|
async translateDocument(documentData: {
|
|
fileUrl: string;
|
|
fileName: string;
|
|
sourceLanguage: string;
|
|
targetLanguage: string;
|
|
quality: 'draft' | 'professional' | 'certified';
|
|
}): Promise<ApiResponse<{ taskId: string; estimatedTime: number }>> {
|
|
if (!this.openaiConfig) {
|
|
return {
|
|
success: false,
|
|
error: 'OpenAI配置未初始化',
|
|
};
|
|
}
|
|
|
|
console.log('OpenAI文档翻译:', documentData);
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
taskId: `task_${Date.now()}`,
|
|
estimatedTime: 1800, // 30分钟
|
|
},
|
|
};
|
|
}
|
|
|
|
async getTranslationProgress(taskId: string): Promise<ApiResponse<{
|
|
status: 'pending' | 'processing' | 'completed' | 'failed';
|
|
progress: number;
|
|
translatedFileUrl?: string;
|
|
}>> {
|
|
if (!this.openaiConfig) {
|
|
return {
|
|
success: false,
|
|
error: 'OpenAI配置未初始化',
|
|
};
|
|
}
|
|
|
|
console.log('查询翻译进度:', taskId);
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
|
|
// 模拟进度查询
|
|
const progress = Math.floor(Math.random() * 100);
|
|
const status = progress >= 100 ? 'completed' : 'processing';
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
status,
|
|
progress,
|
|
translatedFileUrl: status === 'completed' ? `/downloads/translated_${taskId}.pdf` : undefined,
|
|
},
|
|
};
|
|
}
|
|
|
|
// 文件上传
|
|
async uploadFile(file: File, type: 'document' | 'audio' | 'video'): Promise<ApiResponse<{
|
|
fileUrl: string;
|
|
fileName: string;
|
|
fileSize: number;
|
|
uploadId: string;
|
|
}>> {
|
|
console.log('上传文件:', { name: file.name, size: file.size, type });
|
|
|
|
// 模拟文件上传
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
fileUrl: `/uploads/${type}/${Date.now()}_${file.name}`,
|
|
fileName: file.name,
|
|
fileSize: file.size,
|
|
uploadId: `upload_${Date.now()}`,
|
|
},
|
|
};
|
|
}
|
|
|
|
// 重试机制
|
|
async retryRequest<T>(
|
|
requestFn: () => Promise<ApiResponse<T>>,
|
|
maxRetries: number = this.config.retries
|
|
): Promise<ApiResponse<T>> {
|
|
let lastError: string = '';
|
|
|
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
try {
|
|
const result = await requestFn();
|
|
if (result.success) {
|
|
return result;
|
|
}
|
|
lastError = result.error || '未知错误';
|
|
} catch (error) {
|
|
lastError = error instanceof Error ? error.message : '请求失败';
|
|
}
|
|
|
|
if (attempt < maxRetries) {
|
|
// 指数退避策略
|
|
const delay = Math.pow(2, attempt - 1) * 1000;
|
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
console.log(`重试请求 (${attempt}/${maxRetries})...`);
|
|
}
|
|
}
|
|
|
|
return {
|
|
success: false,
|
|
error: `请求失败,已重试${maxRetries}次: ${lastError}`,
|
|
};
|
|
}
|
|
}
|
|
|
|
// 创建API实例
|
|
const apiConfig: ApiConfig = {
|
|
baseUrl: process.env.REACT_APP_API_URL || 'http://localhost:3001/api',
|
|
timeout: 30000,
|
|
retries: 3,
|
|
};
|
|
|
|
export const api = new ApiManager(apiConfig);
|
|
|
|
// 初始化第三方服务配置
|
|
if (process.env.REACT_APP_TWILIO_ACCOUNT_SID) {
|
|
api.configureTwilio({
|
|
accountSid: process.env.REACT_APP_TWILIO_ACCOUNT_SID,
|
|
authToken: process.env.REACT_APP_TWILIO_AUTH_TOKEN || '',
|
|
phoneNumber: process.env.REACT_APP_TWILIO_PHONE_NUMBER || '',
|
|
});
|
|
}
|
|
|
|
if (process.env.REACT_APP_STRIPE_PUBLISHABLE_KEY) {
|
|
api.configureStripe({
|
|
publishableKey: process.env.REACT_APP_STRIPE_PUBLISHABLE_KEY,
|
|
secretKey: process.env.REACT_APP_STRIPE_SECRET_KEY || '',
|
|
});
|
|
}
|
|
|
|
if (process.env.REACT_APP_OPENAI_API_KEY) {
|
|
api.configureOpenAI({
|
|
apiKey: process.env.REACT_APP_OPENAI_API_KEY,
|
|
model: process.env.REACT_APP_OPENAI_MODEL || 'gpt-3.5-turbo',
|
|
});
|
|
}
|
|
|
|
// 导出类型和实例
|
|
export type { ApiConfig, TwilioConfig, StripeConfig, OpenAIConfig };
|
|
export { ApiManager };
|