Integração com o banco de dados

This commit is contained in:
luisfepsale
2025-10-23 23:27:28 -03:00
parent 8a9096470f
commit a85465e332
9 changed files with 1909 additions and 670 deletions
+432 -4
View File
@@ -59,6 +59,54 @@ export interface StoredFolder {
chatIds: string[];
}
/**
* Interface para Folder no banco de dados
*/
export interface FolderRecord {
id: string;
name: string;
created_at: string;
updated_at: string;
}
/**
* Interface para Chat no banco de dados
*/
export interface ChatRecord {
id: string;
title: string;
model_id: number;
folder_id: string | null;
created_at: string;
updated_at: string;
estabelecimento_id: number;
}
/**
* Interface para resposta do GET de chats e folders
*/
export interface GetChatsAndFoldersResponse {
chats: ChatRecord[];
folders: FolderRecord[];
}
/**
* Interface para Message no banco de dados
*/
export interface MessageRecord {
id: string;
chat_id: string;
role: 'user' | 'assistant';
content: string;
model_id: number;
has_attachments: number;
input_tokens: number;
output_tokens: number;
total_tokens: number;
cost_usd: string;
created_at: string;
}
/**
* Serviço de chat com IA
*/
@@ -67,6 +115,14 @@ class ChatService {
private readonly STORAGE_KEY_CHATS = 'hgtx_chats';
private readonly STORAGE_KEY_FOLDERS = 'hgtx_folders';
// Endpoints para folders e chats
private readonly POST_FOLDER_ENDPOINT = '/webhook/codex/post_folders';
private readonly GET_CHATS_FOLDERS_ENDPOINT = '/webhook/fd073ec0-81ab-4681-8acd-b0da71f6ad30/codex/get_chat_folders';
private readonly PUT_CHAT_IN_FOLDER_ENDPOINT = '/webhook/fd073ec0-81ab-4681-8acd-b0da71f6ad30/codex/insert_chat_in_folder';
private readonly DELETE_FOLDER_ENDPOINT = '/webhook/fd073ec0-81ab-4681-8acd-b0da71f6ad30/codex/delete_chat_folder';
private readonly DELETE_CHAT_ENDPOINT = '/webhook/fd073ec0-81ab-4681-8acd-b0da71f6ad30/codex/delete_chat_messages';
private readonly GET_CHAT_MESSAGES_ENDPOINT = '/webhook/fd073ec0-81ab-4681-8acd-b0da71f6ad30/codex/get_chat_messages';
// Formatos de arquivo permitidos (atualmente)
private readonly ALLOWED_FILE_TYPES = {
// Formatos ativos
@@ -280,11 +336,11 @@ class ChatService {
}
/**
* Deleta um chat
* Deleta um chat do localStorage
*
* @param chatId - ID do chat a ser deletado
*/
deleteChat(chatId: string): void {
deleteChatLocal(chatId: string): void {
try {
const chats = this.getAllChats();
const filteredChats = chats.filter(c => c.id !== chatId);
@@ -342,11 +398,11 @@ class ChatService {
}
/**
* Deleta uma pasta
* Deleta uma pasta do localStorage
*
* @param folderId - ID da pasta a ser deletada
*/
deleteFolder(folderId: string): void {
deleteFolderLocal(folderId: string): void {
try {
const folders = this.getAllFolders();
const filteredFolders = folders.filter(f => f.id !== folderId);
@@ -476,6 +532,378 @@ class ChatService {
getMaxAttachments(): number {
return this.MAX_ATTACHMENTS;
}
// ===== MÉTODOS DE INTEGRAÇÃO COM BANCO DE DADOS =====
/**
* Cria uma nova pasta no banco de dados
*
* @param name - Nome da pasta
* @param userEmail - Email do usuário (opcional)
* @returns Promise com sucesso ou erro
*/
async createFolder(name: string, userEmail?: string): Promise<{ success: boolean; folder?: FolderRecord }> {
const email = userEmail || GlobalFunctions.getTransferProperty(TransferAreaProperties.UsuarioEmail);
if (!email) {
throw {
success: false,
message: 'Email do usuário não fornecido',
};
}
if (!name || name.trim().length === 0) {
throw {
success: false,
message: 'Nome da pasta não pode estar vazio',
};
}
console.log('Criando pasta:', {
name,
userEmail: email,
});
try {
const response = await apiService.post<Array<{ success: boolean; user_email?: string; name?: string }>>(
this.POST_FOLDER_ENDPOINT,
{
user_email: email,
name: name.trim(),
}
);
console.log('Resposta completa do POST:', response);
console.log('response.data:', response.data);
// A API retorna um array com um objeto: [{"success":true, ...}]
let result: { success: boolean; user_email?: string; name?: string };
if (Array.isArray(response.data)) {
result = response.data[0];
console.log('API retornou array, usando primeiro elemento:', result);
} else {
result = response.data as any;
console.log('API retornou objeto direto:', result);
}
return {
success: result.success ?? true,
};
} catch (error: any) {
console.error('Erro ao criar pasta:', error);
throw {
success: false,
message: error.message || 'Erro ao criar pasta',
status: error.status,
};
}
}
/**
* Busca todos os chats e pastas do usuário
*
* @param userEmail - Email do usuário (opcional)
* @returns Promise com chats e folders
*/
async getChatsAndFolders(userEmail?: string): Promise<GetChatsAndFoldersResponse> {
const email = userEmail || GlobalFunctions.getTransferProperty(TransferAreaProperties.UsuarioEmail);
if (!email) {
throw {
success: false,
message: 'Email do usuário não fornecido',
};
}
console.log('Buscando chats e pastas:', {
userEmail: email,
});
try {
const response = await apiService.get<Array<{ result: GetChatsAndFoldersResponse }>>(
`${this.GET_CHATS_FOLDERS_ENDPOINT}/${email}`
);
console.log('Resposta completa da API:', response);
console.log('response.data:', response.data);
// A API retorna um array com um objeto "result": [{"result": {"chats": [...], "folders": [...]}}]
let result: GetChatsAndFoldersResponse;
if (Array.isArray(response.data) && response.data.length > 0) {
result = response.data[0].result;
console.log('API retornou array com result:', result);
} else if ((response.data as any).result) {
result = (response.data as any).result;
console.log('API retornou objeto com result:', result);
} else {
// Fallback: retorna vazio
console.warn('Estrutura inesperada da resposta');
result = { chats: [], folders: [] };
}
// Garante que chats e folders são arrays
return {
chats: Array.isArray(result.chats) ? result.chats : [],
folders: Array.isArray(result.folders) ? result.folders : [],
};
} catch (error: any) {
console.error('Erro ao buscar chats e pastas:', error);
throw {
success: false,
message: error.message || 'Erro ao buscar chats e pastas',
status: error.status,
};
}
}
/**
* Move um chat para dentro de uma pasta
*
* @param chatId - ID do chat
* @param folderId - ID da pasta
* @returns Promise com sucesso ou erro
*/
async moveChatToFolder(chatId: string, folderId: string): Promise<{ success: boolean }> {
if (!chatId || !folderId) {
throw {
success: false,
message: 'Chat ID e Folder ID são obrigatórios',
};
}
console.log('Movendo chat para pasta:', {
chatId,
folderId,
});
try {
const response = await apiService.put<Array<{ success: boolean }>>(
`${this.PUT_CHAT_IN_FOLDER_ENDPOINT}/${folderId}/${chatId}`
);
console.log('Resposta completa do PUT:', response);
console.log('response.data:', response.data);
// A API retorna um array com um objeto: [{"success":true}]
let result: { success: boolean };
if (Array.isArray(response.data)) {
result = response.data[0];
console.log('API retornou array, usando primeiro elemento:', result);
} else {
result = response.data;
console.log('API retornou objeto direto:', result);
}
return {
success: result.success ?? true,
};
} catch (error: any) {
console.error('Erro ao mover chat para pasta:', error);
throw {
success: false,
message: error.message || 'Erro ao mover chat para pasta',
status: error.status,
};
}
}
/**
* Deleta uma pasta do banco de dados
*
* @param folderId - ID da pasta
* @param userEmail - Email do usuário (opcional)
* @returns Promise com sucesso ou erro
*/
async deleteFolder(folderId: string, userEmail?: string): Promise<{ success: boolean }> {
const email = userEmail || GlobalFunctions.getTransferProperty(TransferAreaProperties.UsuarioEmail);
if (!email) {
throw {
success: false,
message: 'Email do usuário não fornecido',
};
}
if (!folderId) {
throw {
success: false,
message: 'ID da pasta não fornecido',
};
}
console.log('Deletando pasta:', {
folderId,
userEmail: email,
});
try {
const response = await apiService.delete<Array<{ success: boolean }>>(
`${this.DELETE_FOLDER_ENDPOINT}/${email}/${folderId}`
);
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 };
if (Array.isArray(response.data)) {
result = response.data[0];
console.log('API retornou array, usando primeiro elemento:', result);
} else {
result = response.data;
console.log('API retornou objeto direto:', result);
}
return {
success: result.success ?? true,
};
} catch (error: any) {
console.error('Erro ao deletar pasta:', error);
throw {
success: false,
message: error.message || 'Erro ao deletar pasta',
status: error.status,
};
}
}
/**
* Deleta um chat do banco de dados
*
* @param chatId - ID do chat
* @param userEmail - Email do usuário (opcional)
* @returns Promise com sucesso ou erro
*/
async deleteChat(chatId: string, userEmail?: string): Promise<{ success: boolean }> {
const email = userEmail || GlobalFunctions.getTransferProperty(TransferAreaProperties.UsuarioEmail);
if (!email) {
throw {
success: false,
message: 'Email do usuário não fornecido',
};
}
if (!chatId) {
throw {
success: false,
message: 'ID do chat não fornecido',
};
}
console.log('Deletando chat:', {
chatId,
userEmail: email,
});
try {
const response = await apiService.delete<Array<{ success: boolean }>>(
`${this.DELETE_CHAT_ENDPOINT}/${email}/${chatId}`
);
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 };
if (Array.isArray(response.data)) {
result = response.data[0];
console.log('API retornou array, usando primeiro elemento:', result);
} else {
result = response.data;
console.log('API retornou objeto direto:', result);
}
return {
success: result.success ?? true,
};
} catch (error: any) {
console.error('Erro ao deletar chat:', error);
throw {
success: false,
message: error.message || 'Erro ao deletar chat',
status: error.status,
};
}
}
/**
* Busca todas as mensagens de um chat específico
*
* @param chatId - ID do chat
* @param userEmail - Email do usuário (opcional)
* @returns Promise com array de mensagens
*/
async getChatMessages(chatId: string, userEmail?: string): Promise<MessageRecord[]> {
const email = userEmail || GlobalFunctions.getTransferProperty(TransferAreaProperties.UsuarioEmail);
if (!email) {
throw {
success: false,
message: 'Email do usuário não fornecido',
};
}
if (!chatId) {
throw {
success: false,
message: 'ID do chat não fornecido',
};
}
console.log('Buscando mensagens do chat:', {
chatId,
userEmail: email,
});
try {
const response = await apiService.get<MessageRecord[]>(
`${this.GET_CHAT_MESSAGES_ENDPOINT}/${email}/${chatId}`
);
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 mensagens
// 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 'messages' 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).messages)) {
return (response.data as any).messages;
} 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 mensagens da resposta');
return [];
} catch (error: any) {
console.error('Erro ao buscar mensagens:', error);
throw {
success: false,
message: error.message || 'Erro ao buscar mensagens',
status: error.status,
};
}
}
}
// Exporta instância única (Singleton)