Files
OPEN_CODEX_API/src/services/agent.ts
T
2026-03-18 01:07:27 -03:00

207 lines
6.0 KiB
TypeScript

import { GlobalFunctions, TransferAreaProperties } from '@/GlobalFunctions';
import { apiService } from './api';
export interface CreateOpinionResponse {
success: boolean;
id?: string;
file_url?: string;
file_url_melhoria?: string;
}
export interface CreateOpinionRequest {
titulo: string;
categoria: string;
instrucoes: string;
userEmail?: string;
estabelecimentoId?: number;
}
export type OpinionStatus = 'processando' | 'concluido' | 'erro';
export interface OpinionRecord {
id: string;
estabelecimento_id: number;
user_email: string;
titulo: string;
categoria: string;
instrucoes: string;
file_url: string;
created_at: string;
file_url_melhoria: string;
status?: OpinionStatus;
isLocalPending?: boolean;
}
export interface GetOpinionsParams {
page?: number;
per_page?: number;
search?: string;
userEmail?: string;
estabelecimentoId?: number;
}
export interface GetOpinionsResponse {
data: OpinionRecord[];
total: number;
page: number;
per_page: number;
}
type ApiErrorShape = { message?: string; status?: number };
class AgentService {
private readonly CREATE_ENDPOINT = '/webhook/codex/gepam/parecer-tecnico';
private readonly OPINIONS_BASE = '/webhook/fd073ec0-81ab-4681-8acd-b0da71f6ad30/codex';
private resolveUserContext(userEmail?: string, estabelecimentoId?: number) {
const email = userEmail || GlobalFunctions.getTransferProperty(TransferAreaProperties.UsuarioEmail);
const estabId = estabelecimentoId || GlobalFunctions.getTransferProperty(TransferAreaProperties.EstabelecimentoCodigo);
return { email, estabId };
}
private assertUserContext(email: unknown, estabId: unknown) {
if (!email) {
throw { success: false, message: 'Email do usuário não fornecido' };
}
if (!estabId) {
throw { success: false, message: 'ID do estabelecimento não fornecido' };
}
}
private toApiError(error: unknown): never {
const e = error as ApiErrorShape;
throw {
success: false,
message: e?.message || 'Erro desconhecido',
status: e?.status,
};
}
async createOpinion(request: CreateOpinionRequest): Promise<CreateOpinionResponse> {
const { titulo, categoria, instrucoes, userEmail, estabelecimentoId } = request;
if (!titulo?.trim()) {
throw { success: false, message: 'Título do parecer é obrigatório' };
}
if (!instrucoes?.trim()) {
throw { success: false, message: 'Instruções são obrigatórias' };
}
const { email, estabId } = this.resolveUserContext(userEmail, estabelecimentoId);
this.assertUserContext(email, estabId);
try {
const response = await apiService.post<CreateOpinionResponse>(
this.CREATE_ENDPOINT,
{
user_email: email,
estabelecimento_id: estabId,
titulo: titulo.trim(),
categoria: categoria.trim(),
instrucoes: instrucoes.trim(),
},
{ timeout: 600_000 }
);
return response.data;
} catch (error: unknown) {
console.error('Erro ao criar parecer:', error);
this.toApiError(error);
}
}
async getOpinions(params?: GetOpinionsParams): Promise<OpinionRecord[]> {
const { page = 1, per_page = 10, search = '', userEmail, estabelecimentoId } = params || {};
const { email, estabId } = this.resolveUserContext(userEmail, estabelecimentoId);
this.assertUserContext(email, estabId);
try {
const url = `${this.OPINIONS_BASE}/get_parecer/${email}/${estabId}`;
const response = await apiService.get<OpinionRecord[] | GetOpinionsResponse>(url, {
params: { page, per_page, search },
});
const raw = response.data;
if (Array.isArray(raw)) return raw;
if (raw && typeof raw === 'object') {
if (Array.isArray((raw as GetOpinionsResponse).data)) return (raw as GetOpinionsResponse).data;
if (Array.isArray((raw as { opinions?: OpinionRecord[] }).opinions)) {
return (raw as unknown as { opinions: OpinionRecord[] }).opinions;
}
}
return [];
} catch (error: unknown) {
console.error('Erro ao buscar pareceres:', error);
this.toApiError(error);
}
}
async downloadOpinion(fileUrl: string, fileName: string): Promise<void> {
if (!fileUrl) {
throw { success: false, message: 'URL do arquivo não fornecida' };
}
const triggerDownload = (href: string) => {
const link = document.createElement('a');
link.href = href;
link.download = fileName;
link.target = '_blank';
link.rel = 'noopener noreferrer';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
try {
const response = await fetch(fileUrl, { method: 'GET', mode: 'cors', cache: 'no-cache' });
if (!response.ok) {
throw new Error(`Erro HTTP: ${response.status}`);
}
const blob = await response.blob();
const blobUrl = URL.createObjectURL(blob);
triggerDownload(blobUrl);
URL.revokeObjectURL(blobUrl);
} catch {
const url = new URL(fileUrl);
url.searchParams.set('response-content-disposition', `attachment; filename="${encodeURIComponent(fileName)}"`);
triggerDownload(url.toString());
}
}
async deleteOpinion(opinionId: string, userEmail?: string): Promise<{ success: boolean }> {
if (!opinionId) {
throw { success: false, message: 'ID do parecer não fornecido' };
}
const email = userEmail || GlobalFunctions.getTransferProperty(TransferAreaProperties.UsuarioEmail);
if (!email) {
throw { success: false, message: 'Email do usuário não fornecido' };
}
try {
const url = `${this.OPINIONS_BASE}/delete_parecer/${email}/${opinionId}`;
const response = await apiService.delete<{ success: boolean }[]>(url);
if (Array.isArray(response.data) && response.data.length > 0) {
return response.data[0];
}
return { success: true };
} catch (error: unknown) {
console.error('Erro ao excluir parecer:', error);
this.toApiError(error);
}
}
}
export const agentService = new AgentService();