modulo de agente pessoal de IA

This commit is contained in:
Vitex Tecnologia
2026-01-14 20:10:42 -03:00
parent ee7204982c
commit 76cbd80eef
25 changed files with 3619 additions and 3 deletions
+435
View File
@@ -0,0 +1,435 @@
/**
* Serviço para integração com API do Asana
*/
/**
* Interface para workspace do Asana (resposta da API)
*/
export interface AsanaWorkspaceResponse {
gid: string;
resource_type: string;
name: string;
}
/**
* Interface para resposta da API de workspaces
*/
export interface AsanaWorkspacesResponse {
data: AsanaWorkspaceResponse[];
}
/**
* Interface para workspace formatado (usado no componente)
*/
export interface AsanaWorkspace {
id: string;
name: string;
}
/**
* Interface para usuário do Asana (resposta da API)
*/
export interface AsanaUserResponse {
gid: string;
name: string;
resource_type: string;
}
/**
* Interface para resposta da API de usuários
*/
export interface AsanaUsersResponse {
data: AsanaUserResponse[];
}
/**
* Interface para usuário formatado (usado no componente)
*/
export interface AsanaUser {
id: string;
name: string;
}
/**
* Interface para resposta da API de integração do Asana
*/
export interface AsanaIntegrationResponse {
success: boolean;
integracao_id?: string;
id?: string;
api_key?: string;
workspace_gid?: string;
workspace_nome?: string;
usuario_asana_gid?: string;
usuario_asana_nome?: string;
}
/**
* Interface para request de criação/atualização de integração
*/
export interface AsanaIntegrationRequest {
user_id?: string;
api_key: string;
workspace_gid: string;
workspace_nome: string;
usuario_asana_gid: string;
usuario_asana_nome: string;
}
/**
* Serviço para integração com Asana
*/
class AsanaService {
private readonly BASE_URL = 'https://app.asana.com/api/1.0';
private readonly INTEGRATION_BASE_URL = 'https://prod-hgtx-intelligence-n8n.hgtx.com.br';
private readonly INTEGRATION_WEBHOOK_ID = 'c898beff-84cb-44df-a69c-6eff27ccd7aa';
/**
* Lista os workspaces do Asana usando o token fornecido
*
* @param token - Token de acesso do Asana
* @returns Promise com a lista de workspaces formatados
*/
async getWorkspaces(token: string): Promise<AsanaWorkspace[]> {
if (!token || token.trim().length === 0) {
throw {
success: false,
message: 'Token do Asana é obrigatório',
};
}
try {
const axios = (await import('axios')).default;
const headers: Record<string, string> = {
'accept': 'application/json',
'authorization': `Bearer ${token.trim()}`,
};
const response = await axios.get<AsanaWorkspacesResponse>(
`${this.BASE_URL}/workspaces`,
{ headers }
);
// Converte a resposta da API para o formato esperado pelo componente
// A API retorna gid, mas o componente espera id
return response.data.data.map((workspace) => ({
id: workspace.gid,
name: workspace.name,
}));
} catch (error: unknown) {
console.error('Erro ao buscar workspaces do Asana:', error);
// Retorna o erro da API se existir
if (error && typeof error === 'object' && 'response' in error) {
const axiosError = error as { response?: { data?: any; status?: number } };
if (axiosError.response?.status === 401) {
throw {
success: false,
message: 'Token inválido ou expirado. Verifique sua chave de API.',
};
}
if (axiosError.response?.data) {
throw {
success: false,
message: axiosError.response.data.message || 'Erro ao buscar workspaces do Asana',
};
}
}
throw {
success: false,
message: error instanceof Error ? error.message : 'Erro ao buscar workspaces do Asana',
};
}
}
/**
* Lista os usuários de um workspace do Asana
*
* @param token - Token de acesso do Asana
* @param workspaceId - ID do workspace (gid)
* @returns Promise com a lista de usuários formatados
*/
async getUsers(token: string, workspaceId: string): Promise<AsanaUser[]> {
if (!token || token.trim().length === 0) {
throw {
success: false,
message: 'Token do Asana é obrigatório',
};
}
if (!workspaceId || workspaceId.trim().length === 0) {
throw {
success: false,
message: 'ID do workspace é obrigatório',
};
}
try {
const axios = (await import('axios')).default;
const headers: Record<string, string> = {
'accept': 'application/json',
'authorization': `Bearer ${token.trim()}`,
};
const response = await axios.get<AsanaUsersResponse>(
`${this.BASE_URL}/users?workspace=${workspaceId}`,
{ headers }
);
// Converte a resposta da API para o formato esperado pelo componente
// A API retorna gid, mas o componente espera id
return response.data.data.map((user) => ({
id: user.gid,
name: user.name,
}));
} catch (error: unknown) {
console.error('Erro ao buscar usuários do Asana:', error);
// Retorna o erro da API se existir
if (error && typeof error === 'object' && 'response' in error) {
const axiosError = error as { response?: { data?: any; status?: number } };
if (axiosError.response?.status === 401) {
throw {
success: false,
message: 'Token inválido ou expirado. Verifique sua chave de API.',
};
}
if (axiosError.response?.data) {
throw {
success: false,
message: axiosError.response.data.message || 'Erro ao buscar usuários do Asana',
};
}
}
throw {
success: false,
message: error instanceof Error ? error.message : 'Erro ao buscar usuários do Asana',
};
}
}
/**
* Obtém os detalhes da integração do Asana do usuário
*
* @param userId - ID do usuário
* @returns Promise com os detalhes da integração ou null se não houver
*/
async getIntegration(userId: string): Promise<AsanaIntegrationResponse | null> {
if (!userId || userId.trim().length === 0) {
throw {
success: false,
message: 'ID do usuário é obrigatório',
};
}
try {
const axios = (await import('axios')).default;
const { GlobalFunctions } = await import('@/GlobalFunctions');
// Obtém o token JWT para autenticação
const token = await GlobalFunctions.getToken();
const apiKey = import.meta.env.VITE_API_KEY || '';
const headers: Record<string, string> = {
'Content-Type': 'application/json',
'accept': 'application/json',
};
// Adiciona API key (obrigatória)
if (apiKey) {
headers['apikey'] = apiKey;
}
// Adiciona token JWT se disponível
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
// Em desenvolvimento, usa proxy do Vite para evitar CORS
const baseUrl = import.meta.env.DEV
? '/api/intelligence'
: this.INTEGRATION_BASE_URL;
const response = await axios.get<AsanaIntegrationResponse>(
`${baseUrl}/webhook/${this.INTEGRATION_WEBHOOK_ID}/codex/agente-pessoal/integracoes/asana/${userId}`,
{ headers }
);
// Se success é false, retorna null (não tem integração)
if (!response.data.success) {
return null;
}
return response.data;
} catch (error: unknown) {
console.error('Erro ao buscar integração do Asana:', error);
// Se o erro for 404 ou similar, significa que não tem integração cadastrada
if (error && typeof error === 'object' && 'response' in error) {
const axiosError = error as { response?: { status?: number } };
if (axiosError.response?.status === 404) {
return null;
}
}
// Para outros erros, retorna null silenciosamente (não quebra a aplicação)
return null;
}
}
/**
* Cria uma nova integração do Asana
*
* @param request - Dados da integração a ser criada
* @returns Promise com a resposta da criação
*/
async createIntegration(request: AsanaIntegrationRequest): Promise<AsanaIntegrationResponse> {
if (!request.user_id || !request.api_key || !request.workspace_gid || !request.usuario_asana_gid) {
throw {
success: false,
message: 'Dados incompletos para criar integração',
};
}
try {
const axios = (await import('axios')).default;
const { GlobalFunctions } = await import('@/GlobalFunctions');
// Obtém o token JWT para autenticação
const token = await GlobalFunctions.getToken();
const apiKey = import.meta.env.VITE_API_KEY || '';
const headers: Record<string, string> = {
'Content-Type': 'application/json',
'accept': 'application/json',
};
// Adiciona API key (obrigatória)
if (apiKey) {
headers['apikey'] = apiKey;
}
// Adiciona token JWT se disponível
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
// Em desenvolvimento, usa proxy do Vite para evitar CORS
const baseUrl = import.meta.env.DEV
? '/api/intelligence'
: this.INTEGRATION_BASE_URL;
const response = await axios.post<AsanaIntegrationResponse>(
`${baseUrl}/webhook/codex/agente-pessoal/integracoes/asana`,
request,
{ headers }
);
return response.data;
} catch (error: unknown) {
console.error('Erro ao criar integração do Asana:', error);
// Retorna o erro da API se existir
if (error && typeof error === 'object' && 'response' in error) {
const axiosError = error as { response?: { data?: any; status?: number } };
if (axiosError.response?.data) {
const errorData = axiosError.response.data;
throw {
success: false,
message: errorData.message || 'Erro ao criar integração do Asana',
};
}
}
throw {
success: false,
message: error instanceof Error ? error.message : 'Erro ao criar integração do Asana',
};
}
}
/**
* Atualiza uma integração existente do Asana
*
* @param integracaoId - ID da integração a ser atualizada
* @param request - Dados da integração a ser atualizada
* @returns Promise com a resposta da atualização
*/
async updateIntegration(integracaoId: string, request: Omit<AsanaIntegrationRequest, 'user_id'>): Promise<AsanaIntegrationResponse> {
if (!integracaoId || !request.api_key || !request.workspace_gid || !request.usuario_asana_gid) {
throw {
success: false,
message: 'Dados incompletos para atualizar integração',
};
}
try {
const axios = (await import('axios')).default;
const { GlobalFunctions } = await import('@/GlobalFunctions');
// Obtém o token JWT para autenticação
const token = await GlobalFunctions.getToken();
const apiKey = import.meta.env.VITE_API_KEY || '';
const headers: Record<string, string> = {
'Content-Type': 'application/json',
'accept': 'application/json',
};
// Adiciona API key (obrigatória)
if (apiKey) {
headers['apikey'] = apiKey;
}
// Adiciona token JWT se disponível
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
// Em desenvolvimento, usa proxy do Vite para evitar CORS
const baseUrl = import.meta.env.DEV
? '/api/intelligence'
: this.INTEGRATION_BASE_URL;
const response = await axios.put<AsanaIntegrationResponse>(
`${baseUrl}/webhook/${this.INTEGRATION_WEBHOOK_ID}/codex/agente-pessoal/integracoes/asana/${integracaoId}`,
request,
{ headers }
);
return response.data;
} catch (error: unknown) {
console.error('Erro ao atualizar integração do Asana:', error);
// Retorna o erro da API se existir
if (error && typeof error === 'object' && 'response' in error) {
const axiosError = error as { response?: { data?: any; status?: number } };
if (axiosError.response?.data) {
const errorData = axiosError.response.data;
throw {
success: false,
message: errorData.message || 'Erro ao atualizar integração do Asana',
};
}
}
throw {
success: false,
message: error instanceof Error ? error.message : 'Erro ao atualizar integração do Asana',
};
}
}
}
// Exporta instância única (Singleton)
export const asanaService = new AsanaService();