diff --git a/src/modules/ai/README.md b/src/modules/ai/README.md new file mode 100644 index 0000000..2ce39fb --- /dev/null +++ b/src/modules/ai/README.md @@ -0,0 +1,76 @@ +# AI Module + +## Descripcion + +Modulo de integracion con modelos de Inteligencia Artificial. Proporciona capacidades de chat conversacional, completions, embeddings y gestion de bases de conocimiento. Soporta multiples proveedores (OpenAI, Anthropic, Google, Azure) a traves de OpenRouter, con control de acceso basado en roles y gestion de cuotas por tenant. + +## Entidades + +| Entidad | Schema | Descripcion | +|---------|--------|-------------| +| `AIModel` | ai.models | Catalogo de modelos de IA disponibles (GPT-4, Claude, etc.) con configuracion de costos y capacidades | +| `AIPrompt` | ai.prompts | Templates de prompts versionados con variables y configuracion de modelo | +| `AIConversation` | ai.conversations | Conversaciones de chat con historial, contexto y estadisticas | +| `AIMessage` | ai.messages | Mensajes individuales dentro de una conversacion | +| `AICompletion` | ai.completions | Registros de completions individuales (no conversacionales) | +| `AIEmbedding` | ai.embeddings | Vectores de embeddings para busqueda semantica | +| `AIKnowledgeBase` | ai.knowledge_base | Articulos de conocimiento con embeddings para RAG | +| `AIUsageLog` | ai.usage_logs | Registro detallado de uso por request | +| `AITenantQuota` | ai.tenant_quotas | Cuotas mensuales de tokens, requests y costos por tenant | + +## Servicios + +| Servicio | Responsabilidades | +|----------|-------------------| +| `AIService` | Servicio base: CRUD de modelos, prompts, conversaciones, mensajes; registro de uso; gestion de cuotas | +| `RoleBasedAIService` | Extension con control de acceso basado en roles ERP; integracion con OpenRouter; ejecucion de tools | + +## Endpoints + +| Method | Path | Descripcion | +|--------|------|-------------| +| GET | `/models` | Lista todos los modelos activos | +| GET | `/models/:id` | Obtiene modelo por ID | +| GET | `/models/code/:code` | Obtiene modelo por codigo | +| GET | `/models/provider/:provider` | Lista modelos por proveedor | +| GET | `/models/type/:type` | Lista modelos por tipo (chat/embedding/etc) | +| GET | `/prompts` | Lista prompts del tenant | +| GET | `/prompts/:id` | Obtiene prompt por ID | +| GET | `/prompts/code/:code` | Obtiene prompt por codigo | +| POST | `/prompts` | Crea nuevo prompt | +| PATCH | `/prompts/:id` | Actualiza prompt existente | +| GET | `/conversations` | Lista conversaciones del tenant | +| GET | `/conversations/:id` | Obtiene conversacion con mensajes | +| GET | `/conversations/user/:userId` | Lista conversaciones de usuario | +| POST | `/conversations` | Crea nueva conversacion | +| PATCH | `/conversations/:id` | Actualiza conversacion | +| POST | `/conversations/:id/archive` | Archiva conversacion | +| GET | `/conversations/:conversationId/messages` | Lista mensajes de conversacion | +| POST | `/conversations/:conversationId/messages` | Agrega mensaje a conversacion | +| GET | `/conversations/:conversationId/tokens` | Obtiene conteo de tokens | +| POST | `/usage` | Registra uso de IA | +| GET | `/usage/stats` | Obtiene estadisticas de uso | +| GET | `/quotas` | Obtiene cuota del tenant | +| PATCH | `/quotas` | Actualiza cuota del tenant | +| GET | `/quotas/check` | Verifica disponibilidad de cuota | + +## Dependencias + +- `common` - Utilidades compartidas +- `auth` - Autenticacion y tenant context +- OpenRouter API (proveedor externo) + +## Configuracion + +| Variable | Descripcion | Requerida | +|----------|-------------|-----------| +| `OPENROUTER_API_KEY` | API key para OpenRouter | Si | +| `APP_URL` | URL de la aplicacion (para HTTP-Referer) | No | + +## Roles ERP Soportados + +El `RoleBasedAIService` soporta prompts y accesos diferenciados por rol: +- `admin` - Acceso completo +- `supervisor` - Acceso a reportes y analisis +- `operator` - Acceso a operaciones basicas +- `customer` - Acceso limitado a consultas diff --git a/src/modules/ai/roles/erp-roles.config.ts b/src/modules/ai/roles/erp-roles.config.ts index f855b84..500035b 100644 --- a/src/modules/ai/roles/erp-roles.config.ts +++ b/src/modules/ai/roles/erp-roles.config.ts @@ -1,17 +1,17 @@ /** - * ERP Construcción - Roles Configuration + * ERP Roles Configuration * - * Roles específicos para operaciones de construcción y obras. - * Adaptado desde erp-core v1.5.0 (PROP-CORE-004) + * Define roles, tools permitidos, y system prompts para cada rol en el ERP. + * Basado en: michangarrito MCH-012/MCH-013 (role-based chatbot) * - * Roles: - * - ADMIN: Gerente General - acceso completo - * - SUPERVISOR_OBRA: Supervisor de obra - gestión de proyectos - * - RESIDENTE: Residente de obra - operaciones en sitio - * - ALMACENISTA: Control de almacén y materiales + * Roles disponibles: + * - ADMIN: Acceso completo a todas las operaciones + * - SUPERVISOR: Gestión de equipos y reportes de sucursal + * - OPERATOR: Operaciones de punto de venta + * - CUSTOMER: Acceso limitado para clientes (si se expone chatbot) */ -export type ERPRole = 'ADMIN' | 'SUPERVISOR_OBRA' | 'RESIDENTE' | 'ALMACENISTA'; +export type ERPRole = 'ADMIN' | 'SUPERVISOR' | 'OPERATOR' | 'CUSTOMER'; export interface ERPRoleConfig { name: string; @@ -19,140 +19,234 @@ export interface ERPRoleConfig { tools: string[]; systemPromptFile: string; maxConversationHistory: number; - allowedModels?: string[]; + allowedModels?: string[]; // Si vacío, usa el default del tenant rateLimit: { requestsPerMinute: number; tokensPerMinute: number; }; } +/** + * Configuración de roles ERP + */ export const ERP_ROLES: Record = { ADMIN: { - name: 'Gerente General', - description: 'Gerente con acceso completo a todas las obras y operaciones', + name: 'Administrador', + description: 'Acceso completo a todas las operaciones del sistema ERP', tools: [ - // Proyectos/Obras - 'get_projects_summary', 'get_project_status', 'get_project_budget', - 'approve_budget_change', 'get_all_projects', - // Finanzas - 'get_financial_report', 'get_accounts_receivable', 'get_accounts_payable', - 'get_cash_flow', 'get_kpis', - // Compras - 'get_pending_orders', 'get_supplier_info', 'create_purchase_order', 'approve_purchase', + // Ventas + 'get_sales_summary', + 'get_sales_report', + 'get_top_products', + 'get_top_customers', + 'get_sales_by_branch', + 'create_sale', + 'void_sale', + // Inventario - 'get_inventory_status', 'get_inventory_value', 'transfer_inventory', - // Configuración - 'manage_users', 'view_audit_logs', 'update_settings', - 'get_branch_info', 'manage_branches', - // Reportes - 'generate_report', 'export_data', - // TPV - 'configure_terminal', 'get_payment_history', 'process_refund', - // Presupuestos - 'get_estimates', 'approve_estimate', + 'get_inventory_status', + 'get_low_stock_products', + 'get_inventory_value', + 'adjust_inventory', + 'transfer_inventory', + + // Compras + 'get_pending_orders', + 'get_supplier_info', + 'create_purchase_order', + 'approve_purchase', + + // Finanzas + 'get_financial_report', + 'get_accounts_receivable', + 'get_accounts_payable', + 'get_cash_flow', + + // Usuarios y configuración + 'manage_users', + 'view_audit_logs', + 'update_settings', + 'get_branch_info', + 'manage_branches', + + // Reportes avanzados + 'generate_report', + 'export_data', + 'get_kpis', ], systemPromptFile: 'admin-system-prompt', maxConversationHistory: 50, - rateLimit: { requestsPerMinute: 100, tokensPerMinute: 50000 }, + rateLimit: { + requestsPerMinute: 100, + tokensPerMinute: 50000, + }, }, - SUPERVISOR_OBRA: { - name: 'Supervisor de Obra', - description: 'Supervisor con gestión de proyectos asignados y equipo', + SUPERVISOR: { + name: 'Supervisor', + description: 'Gestión de equipos, reportes de sucursal y aprobaciones', tools: [ - // Proyectos - 'get_my_projects', 'get_project_status', 'update_project_progress', - 'get_project_budget', 'request_budget_change', + // Ventas (lectura + acciones limitadas) + 'get_sales_summary', + 'get_sales_report', + 'get_top_products', + 'get_sales_by_branch', + 'create_sale', + + // Inventario (lectura + ajustes) + 'get_inventory_status', + 'get_low_stock_products', + 'adjust_inventory', + // Equipo - 'get_team_performance', 'get_worker_schedule', 'manage_schedules', - // Compras (solicitud) - 'create_purchase_request', 'get_pending_requests', - // Inventario - 'get_inventory_status', 'request_materials', 'get_low_stock_products', - // Sucursal/Obra - 'get_branch_info', 'get_branch_report', - // Avances - 'register_progress', 'upload_evidence', 'get_progress_report', + 'get_team_performance', + 'get_employee_schedule', + 'manage_schedules', + + // Aprobaciones + 'approve_discounts', + 'approve_voids', + 'approve_refunds', + + // Sucursal + 'get_branch_info', + 'get_branch_report', + + // Clientes + 'get_customer_info', + 'get_customer_balance', ], systemPromptFile: 'supervisor-system-prompt', maxConversationHistory: 30, - rateLimit: { requestsPerMinute: 60, tokensPerMinute: 30000 }, + rateLimit: { + requestsPerMinute: 60, + tokensPerMinute: 30000, + }, }, - RESIDENTE: { - name: 'Residente de Obra', - description: 'Residente con operaciones en sitio y registro de avances', + OPERATOR: { + name: 'Operador', + description: 'Operaciones de punto de venta y consultas básicas', tools: [ - // Avances - 'register_daily_progress', 'upload_photos', 'register_incidents', - // Materiales - 'request_materials', 'confirm_material_receipt', 'check_stock', - // Personal - 'register_attendance', 'get_daily_crew', + // Productos + 'search_products', + 'get_product_price', + 'check_product_availability', + + // Ventas + 'create_sale', + 'get_my_sales', + 'apply_discount', // Con límite + + // Clientes + 'search_customers', + 'get_customer_balance', + 'register_payment', + + // Inventario (solo lectura) + 'check_stock', + // Información - 'get_project_info', 'get_branch_hours', 'get_my_tasks', - // Comunicación - 'report_issue', 'request_support', + 'get_branch_hours', + 'get_promotions', ], systemPromptFile: 'operator-system-prompt', maxConversationHistory: 20, - rateLimit: { requestsPerMinute: 30, tokensPerMinute: 15000 }, + rateLimit: { + requestsPerMinute: 30, + tokensPerMinute: 15000, + }, }, - ALMACENISTA: { - name: 'Almacenista', - description: 'Control de almacén, recepción y despacho de materiales', + CUSTOMER: { + name: 'Cliente', + description: 'Acceso limitado para clientes externos', tools: [ - // Inventario - 'get_inventory_status', 'check_stock', 'adjust_inventory', - 'register_material_entry', 'register_material_exit', - // Recepción - 'confirm_purchase_receipt', 'register_quality_inspection', - // Despacho - 'prepare_dispatch', 'confirm_dispatch', - // Proveedores - 'get_pending_deliveries', 'get_supplier_info', - // Alertas - 'get_low_stock_products', 'get_expiring_materials', + // Catálogo + 'view_catalog', + 'search_products', + 'check_availability', + + // Pedidos + 'get_my_orders', + 'track_order', + + // Cuenta + 'get_my_balance', + 'get_my_history', + + // Soporte + 'contact_support', + 'get_store_info', + 'get_promotions', ], - systemPromptFile: 'operator-system-prompt', - maxConversationHistory: 20, - rateLimit: { requestsPerMinute: 30, tokensPerMinute: 15000 }, + systemPromptFile: 'customer-system-prompt', + maxConversationHistory: 10, + rateLimit: { + requestsPerMinute: 10, + tokensPerMinute: 5000, + }, }, }; +/** + * Mapeo de rol de base de datos a ERPRole + */ export const DB_ROLE_MAPPING: Record = { - // Administradores - admin: 'ADMIN', administrator: 'ADMIN', gerente: 'ADMIN', owner: 'ADMIN', - director: 'ADMIN', + // Roles típicos de sistema + admin: 'ADMIN', + administrator: 'ADMIN', + superadmin: 'ADMIN', + owner: 'ADMIN', + // Supervisores - supervisor: 'SUPERVISOR_OBRA', supervisor_obra: 'SUPERVISOR_OBRA', - project_manager: 'SUPERVISOR_OBRA', manager: 'SUPERVISOR_OBRA', - // Residentes - residente: 'RESIDENTE', resident: 'RESIDENTE', operator: 'RESIDENTE', - ingeniero: 'RESIDENTE', field_engineer: 'RESIDENTE', - // Almacenistas - almacenista: 'ALMACENISTA', warehouse: 'ALMACENISTA', bodeguero: 'ALMACENISTA', - storekeeper: 'ALMACENISTA', + supervisor: 'SUPERVISOR', + manager: 'SUPERVISOR', + branch_manager: 'SUPERVISOR', + store_manager: 'SUPERVISOR', + + // Operadores + operator: 'OPERATOR', + cashier: 'OPERATOR', + sales: 'OPERATOR', + employee: 'OPERATOR', + staff: 'OPERATOR', + + // Clientes + customer: 'CUSTOMER', + client: 'CUSTOMER', + guest: 'CUSTOMER', }; +/** + * Obtener rol ERP desde rol de base de datos + */ export function getERPRole(dbRole: string | undefined): ERPRole { - if (!dbRole) return 'RESIDENTE'; + if (!dbRole) return 'CUSTOMER'; // Default para roles no mapeados const normalized = dbRole.toLowerCase().trim(); - return DB_ROLE_MAPPING[normalized] || 'RESIDENTE'; + return DB_ROLE_MAPPING[normalized] || 'CUSTOMER'; } +/** + * Verificar si un rol tiene acceso a un tool + */ export function hasToolAccess(role: ERPRole, toolName: string): boolean { const roleConfig = ERP_ROLES[role]; if (!roleConfig) return false; return roleConfig.tools.includes(toolName); } +/** + * Obtener todos los tools para un rol + */ export function getToolsForRole(role: ERPRole): string[] { const roleConfig = ERP_ROLES[role]; return roleConfig?.tools || []; } +/** + * Obtener configuración completa de un rol + */ export function getRoleConfig(role: ERPRole): ERPRoleConfig | null { return ERP_ROLES[role] || null; }