import type { Request } from 'express'; import { storage } from "../storage"; import { generateFormSummary } from "../services/embedding.service"; async function indexFormAsync(formId: number, organizationId: number): Promise { try { await storage.enqueueEmbedding(organizationId, 'form', formId, 'upsert'); } catch (err) { console.error('[RAG] indexFormAsync error:', err); } } async function indexFormWithSummaryAsync(formId: number, organizationId: number): Promise { try { // Summary generation uses external chat provider (Kimi), so it can stay synchronous. const [form, fields, statuses] = await Promise.all([ storage.getForm(formId, organizationId), storage.getFormFields(formId, organizationId), storage.getFormStatuses(formId, organizationId), ]); if (form) { const summary = await generateFormSummary(form, fields, statuses); if (summary) { await storage.updateForm(formId, organizationId, { aiSummary: summary, aiSummaryIsAuto: true }); } } // Actual embedding is deferred to the nightly batch. await storage.enqueueEmbedding(organizationId, 'form', formId, 'upsert'); } catch (err) { console.error('[RAG] indexFormWithSummaryAsync error:', err); } } async function indexTaskAsync(taskId: number, organizationId: number): Promise { try { await storage.enqueueEmbedding(organizationId, 'task', taskId, 'upsert'); } catch (err) { console.error('[RAG] indexTaskAsync error:', err); } } function parseOfflineTimestamp(req: Request): Date | undefined { const h = req.headers['x-offline-enqueued-at']; if (!h || typeof h !== 'string') return undefined; const n = parseInt(h, 10); if (isNaN(n)) return undefined; const now = Date.now(); if (n > now || n < now - 30 * 24 * 60 * 60 * 1000) return undefined; return new Date(n); } export { indexFormAsync, indexFormWithSummaryAsync, indexTaskAsync, parseOfflineTimestamp };