feat(ai): agente IA interno con RAG sobre NAN + app web en /ai
- API: /api/ai/chat, /conversations, /documents con embeddings qwen3-embedding, coseno en SQLite, dedup por hash, historial de conversaciones - Base de conocimiento semilla (6 docs, 36 chunks): catálogo DIAGONAL, propuestas del cotizador, créditos, proceso de venta, FAQ, privacidad - App agente-ia (Vite/React/Tailwind, StudioBlank) servida en /ai/ vía nginx - 21 tests nuevos (91/91 verdes)
This commit is contained in:
41
api-gateway/scripts/seed-ai.ts
Normal file
41
api-gateway/scripts/seed-ai.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Seed de la base de conocimiento del agente IA.
|
||||
* Lee knowledge/*.md, usa el primer encabezado H1 como título y los indexa
|
||||
* vía indexarDocumento (idempotente: solo re-embebe si cambió el hash).
|
||||
*
|
||||
* Uso: npm run seed:ai (requiere NAN_API_KEY en el .env del ecosistema)
|
||||
*/
|
||||
import { readdir, readFile } from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import { indexarDocumento } from '../src/services/ai.service.js'
|
||||
|
||||
const KNOWLEDGE_DIR = path.resolve(process.cwd(), 'knowledge')
|
||||
|
||||
function tituloDe(contenido: string, archivo: string): string {
|
||||
const h1 = contenido.split('\n').find((l) => l.startsWith('# '))
|
||||
return h1 ? h1.replace(/^#\s+/, '').trim() : archivo.replace(/\.md$/, '')
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const archivos = (await readdir(KNOWLEDGE_DIR)).filter((f) => f.endsWith('.md')).sort()
|
||||
if (archivos.length === 0) {
|
||||
console.error(`No hay archivos .md en ${KNOWLEDGE_DIR}`)
|
||||
process.exit(1)
|
||||
}
|
||||
console.log(`Indexando ${archivos.length} documentos desde ${KNOWLEDGE_DIR}…`)
|
||||
let totalChunks = 0
|
||||
for (const archivo of archivos) {
|
||||
const contenido = await readFile(path.join(KNOWLEDGE_DIR, archivo), 'utf8')
|
||||
const titulo = tituloDe(contenido, archivo)
|
||||
const r = await indexarDocumento(titulo, contenido)
|
||||
totalChunks += r.chunks
|
||||
console.log(` ${r.estado.padEnd(12)} ${titulo} (${r.chunks} chunks)`)
|
||||
}
|
||||
console.log(`Listo: ${archivos.length} documentos procesados.`)
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('Falló el seed:', err instanceof Error ? err.message : err)
|
||||
process.exit(1)
|
||||
})
|
||||
Reference in New Issue
Block a user