Files
OPEN_CODEX_API/src/services/transcription.ts
T
2025-10-23 23:27:28 -03:00

273 lines
8.5 KiB
TypeScript

import { GlobalFunctions, TransferAreaProperties } from '@/GlobalFunctions';
import { apiService } from './api';
/**
* Interface para a resposta da API de transcrição
*/
export interface TranscriptionResponse {
success: boolean;
transcription_id: string;
audio_url: string;
message: string;
}
/**
* Interface para uma transcrição armazenada no banco de dados
*/
export interface TranscriptionRecord {
id: string;
user_email: string;
estabelecimento_id: number;
audio_file_name: string;
audio_duration_seconds: number;
transcription_text: string;
model: string;
audio_url: string;
cost_usd: string;
created_at: string;
}
/**
* Interface para os dados necessários para transcrição
*/
export interface TranscriptionRequest {
audioFile: File;
userEmail?: string;
estabelecimentoId?: number;
}
/**
* Serviço de transcrição de áudio
*/
class TranscriptionService {
private readonly TRANSCRIPTION_ENDPOINT = '/webhook/codex/transcrever_audio';
private readonly GET_TRANSCRIPTIONS_ENDPOINT = '/webhook/fd073ec0-81ab-4681-8acd-b0da71f6ad30/codex/get_transcrever_audio';
private readonly DELETE_TRANSCRIPTION_ENDPOINT = '/webhook/fd073ec0-81ab-4681-8acd-b0da71f6ad30/codex/delete_transcrever_audio';
/**
* Transcreve um arquivo de áudio
*
* @param request - Dados da requisição (arquivo, email, estabelecimento)
* @returns Promise com a resposta da API
*/
async transcribeAudio(request: TranscriptionRequest): Promise<TranscriptionResponse> {
const { audioFile, userEmail, estabelecimentoId } = request;
// Cria FormData para envio multipart
const formData = new FormData();
formData.append('data', audioFile);
// Usa valores do .env se não forem fornecidos
const email = GlobalFunctions.getTransferProperty(TransferAreaProperties.UsuarioEmail);//userEmail || import.meta.env.VITE_USER_EMAIL || '';
const estabId = GlobalFunctions.getTransferProperty(TransferAreaProperties.EstabelecimentoCodigo);//estabelecimentoId || import.meta.env.VITE_ESTABELECIMENTO_ID || '';
formData.append('user_email', email);
formData.append('estabelecimento_id', estabId.toString());
// Log para debug (remover em produção se necessário)
console.log('Enviando transcrição:', {
fileName: audioFile.name,
fileSize: audioFile.size,
fileType: audioFile.type,
userEmail: email,
estabelecimentoId: estabId,
});
try {
// Faz a requisição usando o serviço de API
const response = await apiService.postFormData<TranscriptionResponse>(
this.TRANSCRIPTION_ENDPOINT,
formData
);
return response.data;
} catch (error: any) {
// Trata erros específicos
console.error('Erro na transcrição:', error);
throw {
success: false,
message: error.message || 'Erro ao transcrever áudio',
status: error.status,
};
}
}
/**
* Valida se o arquivo de áudio é suportado
*
* @param file - Arquivo a ser validado
* @param maxSizeMB - Tamanho máximo em MB (padrão: 25MB)
* @returns Objeto com resultado da validação
*/
validateAudioFile(file: File, maxSizeMB: number = 25): { valid: boolean; error?: string } {
const SUPPORTED_FORMATS = ['flac', 'm4a', 'mp3', 'mp4', 'mpeg', 'mpga', 'oga', 'ogg', 'wav', 'webm'];
const MAX_FILE_SIZE = maxSizeMB * 1024 * 1024;
// Valida tamanho
if (file.size > MAX_FILE_SIZE) {
return {
valid: false,
error: `Arquivo muito grande. Tamanho máximo: ${maxSizeMB}MB`,
};
}
// Valida formato
const fileExtension = file.name.split('.').pop()?.toLowerCase();
if (!fileExtension || !SUPPORTED_FORMATS.includes(fileExtension)) {
return {
valid: false,
error: `Formato não suportado. Formatos aceitos: ${SUPPORTED_FORMATS.join(', ')}`,
};
}
return { valid: true };
}
/**
* Lista transcrições do banco de dados com paginação
*
* @param userEmail - Email do usuário
* @param page - Número da página (padrão: 1)
* @param perPage - Quantidade de itens por página (padrão: 10)
* @returns Promise com o array de transcrições
*/
async getTranscriptions(
userEmail?: string,
page: number = 1,
perPage: number = 10
): Promise<TranscriptionRecord[]> {
// Usa valores do GlobalFunctions se não forem fornecidos
const email = userEmail || GlobalFunctions.getTransferProperty(TransferAreaProperties.UsuarioEmail);
if (!email) {
throw {
success: false,
message: 'Email do usuário não fornecido',
};
}
console.log('Buscando transcrições:', {
userEmail: email,
page,
perPage,
});
try {
// Faz a requisição GET com parâmetros na URL e query
const response = await apiService.get<TranscriptionRecord[]>(
`${this.GET_TRANSCRIPTIONS_ENDPOINT}/${email}`,
{
params: {
page: page.toString(),
per_page: perPage.toString(),
},
}
);
console.log('Resposta completa da API:', response);
console.log('response.data:', response.data);
console.log('É array?:', Array.isArray(response.data));
// A API retorna diretamente o array de transcrições
// Garante que sempre retorna um array
if (Array.isArray(response.data)) {
return response.data;
} else if (response.data && typeof response.data === 'object') {
// Se a resposta for um objeto com uma propriedade 'transcriptions' ou similar
console.warn('API retornou objeto em vez de array:', response.data);
// Tenta encontrar o array dentro do objeto
if (Array.isArray((response.data as any).transcriptions)) {
return (response.data as any).transcriptions;
} else if (Array.isArray((response.data as any).data)) {
return (response.data as any).data;
}
}
// Se não conseguir extrair array, retorna vazio
console.warn('Não foi possível extrair array de transcrições da resposta');
return [];
} catch (error: any) {
console.error('Erro ao buscar transcrições:', error);
throw {
success: false,
message: error.message || 'Erro ao buscar transcrições',
status: error.status,
};
}
}
/**
* Deleta uma transcrição do banco de dados
*
* @param transcriptionId - ID da transcrição a ser deletada
* @param userEmail - Email do usuário (opcional)
* @returns Promise com sucesso ou erro
*/
async deleteTranscription(transcriptionId: string, userEmail?: string): Promise<{ success: boolean; message?: string }> {
// Usa valores do GlobalFunctions se não forem fornecidos
const email = userEmail || GlobalFunctions.getTransferProperty(TransferAreaProperties.UsuarioEmail);
if (!email) {
throw {
success: false,
message: 'Email do usuário não fornecido',
};
}
if (!transcriptionId) {
throw {
success: false,
message: 'ID da transcrição não fornecido',
};
}
console.log('Deletando transcrição:', {
transcriptionId,
userEmail: email,
});
try {
// Faz a requisição DELETE com parâmetros na URL
const response = await apiService.delete<{ success: boolean; message?: string } | Array<{ success: boolean; message?: string }>>(
`${this.DELETE_TRANSCRIPTION_ENDPOINT}/${email}/${transcriptionId}`
);
console.log('Resposta completa do DELETE:', response);
console.log('response.data:', response.data);
// A API retorna um array com um objeto: [{"success":true}]
let result: { success: boolean; message?: string };
if (Array.isArray(response.data)) {
// Se for array, pega o primeiro elemento
result = response.data[0];
console.log('API retornou array, usando primeiro elemento:', result);
} else {
// Se for objeto direto
result = response.data;
console.log('API retornou objeto direto:', result);
}
// Garante que tem a estrutura mínima
return {
success: result.success ?? true,
message: result.message || 'Transcrição deletada com sucesso',
};
} catch (error: any) {
console.error('Erro ao deletar transcrição:', error);
throw {
success: false,
message: error.message || 'Erro ao deletar transcrição',
status: error.status,
};
}
}
}
// Exporta instância única (Singleton)
export const transcriptionService = new TranscriptionService();