import type { Request } from 'express'; import { storage } from "../storage"; import { buildFormText, generateFormSummary, upsertEmbedding, buildTaskText, } from "../services/embedding.service"; async function indexFormAsync(formId: number, organizationId: number): Promise { try { const [form, fields, statuses] = await Promise.all([ storage.getForm(formId, organizationId), storage.getFormFields(formId, organizationId), storage.getFormStatuses(formId, organizationId), ]); if (!form) return; const content = buildFormText(form, fields, statuses); await upsertEmbedding(organizationId, 'form', formId, content, { name: form.name, description: form.description, }); } catch (err) { console.error('[RAG] indexFormAsync error:', err); } } async function indexFormWithSummaryAsync(formId: number, organizationId: number): Promise { try { const [form, fields, statuses] = await Promise.all([ storage.getForm(formId, organizationId), storage.getFormFields(formId, organizationId), storage.getFormStatuses(formId, organizationId), ]); if (!form) return; const summary = await generateFormSummary(form, fields, statuses); if (summary) { await storage.updateForm(formId, organizationId, { aiSummary: summary, aiSummaryIsAuto: true }); } const indexedForm = summary ? { ...form, aiSummary: summary } : form; const content = buildFormText(indexedForm, fields, statuses); await upsertEmbedding(organizationId, 'form', formId, content, { name: form.name, description: form.description, }); } catch (err) { console.error('[RAG] indexFormWithSummaryAsync error:', err); } } async function indexTaskAsync(taskId: number, organizationId: number): Promise { try { const task = await storage.getTask(taskId, organizationId); if (!task) return; const [form, statuses, users, fieldValues, formFields] = await Promise.all([ storage.getForm(task.formId, organizationId), storage.getFormStatuses(task.formId, organizationId), storage.getUsersByOrganization(organizationId), storage.getTaskFieldValues(taskId, organizationId), storage.getFormFields(task.formId, organizationId), ]); if (!form) return; const statusMap = new Map(statuses.map(s => [s.id, s.name])); const usersMap = new Map(users.map(u => [u.id, u])); const assigneeUser = task.assignedTo ? usersMap.get(task.assignedTo) : null; const assigneeName = assigneeUser ? `${assigneeUser.firstName ?? ''} ${assigneeUser.middleName ?? ''} ${assigneeUser.lastName ?? ''}`.trim() || assigneeUser.email : null; const fieldMap = new Map(formFields.map(f => [f.id, f])); const enrichedFieldValues = fieldValues.map(fv => ({ name: fieldMap.get(fv.fieldId)?.name ?? '', value: fv.value, type: fieldMap.get(fv.fieldId)?.type ?? 'text', })); const content = buildTaskText( task, form.name, statusMap.get(task.currentStatusId) ?? '', assigneeName, enrichedFieldValues ); await upsertEmbedding(organizationId, 'task', taskId, content, { formId: task.formId, formName: form.name, title: task.title, }); } 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 };