16092e94a3
fix #51
100 lines
3.1 KiB
TypeScript
100 lines
3.1 KiB
TypeScript
// ./plan_mensajes_ia/index.ts
|
|
import type { OpenAI } from "openai";
|
|
|
|
import type { Json } from "../../_shared/database.types.ts";
|
|
import { ResponseMetadata } from "../../_shared/utils.ts";
|
|
import { supabase } from "../../openai-webhook-responses/supabase.ts";
|
|
|
|
function extractOutputText(response: OpenAI.Responses.Response): string {
|
|
const direct = (response as any).output_text;
|
|
if (typeof direct === "string") return direct;
|
|
|
|
const output = (response as any).output;
|
|
if (!Array.isArray(output)) return "";
|
|
|
|
try {
|
|
return output
|
|
.filter((item) => item?.type === "message")
|
|
.flatMap((item) => item?.content ?? [])
|
|
.filter((c) => c?.type === "output_text")
|
|
.map((c) => String(c?.text ?? ""))
|
|
.join("");
|
|
} catch {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
export async function handleAsignaturaMensajesResponse(
|
|
response: OpenAI.Responses.Response,
|
|
): Promise<void> {
|
|
const metadata = response.metadata as any;
|
|
const mensajeId = metadata?.mensaje_id;
|
|
|
|
console.log("Procesando Webhook para Asignatura. Mensaje ID:", mensajeId);
|
|
|
|
const isStructured = metadata?.is_structured === "true" || metadata?.is_structured === true;
|
|
|
|
if (!mensajeId) {
|
|
console.warn("No se recibió mensaje_id en la metadata del webhook de asignatura");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const outputText = extractOutputText(response);
|
|
if (!outputText) {
|
|
throw new Error("La respuesta de OpenAI está vacía");
|
|
}
|
|
|
|
let respuestaJSON: any;
|
|
try {
|
|
respuestaJSON = JSON.parse(outputText);
|
|
} catch (e) {
|
|
throw new Error(`Error parseando JSON de OpenAI: ${e.message}`);
|
|
}
|
|
|
|
// Normalización de campos de la IA
|
|
const aiMessage = respuestaJSON["ai-message"] || respuestaJSON["ai_message"] || "";
|
|
const is_refusal = !!respuestaJSON.is_refusal || respuestaJSON["is-refusal"] === true;
|
|
|
|
let recommendations: any[] = [];
|
|
|
|
// Si es estructurado y no es un rechazo de la IA, generamos las recomendaciones
|
|
if (isStructured && !is_refusal) {
|
|
recommendations = Object.entries(respuestaJSON)
|
|
.filter(([k]) => !["ai-message", "ai_message", "is-refusal", "is_refusal"].includes(k))
|
|
.map(([campo, valor]) => ({
|
|
campo_afectado: campo,
|
|
texto_mejora: valor,
|
|
aplicada: false,
|
|
}));
|
|
}
|
|
|
|
// --- CAMBIO CLAVE: TABLA 'asignatura_mensajes_ia' ---
|
|
const { error } = await supabase
|
|
.from("asignatura_mensajes_ia")
|
|
.update({
|
|
respuesta: aiMessage,
|
|
// Guardamos la propuesta completa para mantener historial
|
|
propuesta: {
|
|
respuesta: aiMessage,
|
|
recommendations
|
|
},
|
|
is_refusal,
|
|
estado: "COMPLETADO",
|
|
})
|
|
.eq("id", mensajeId);
|
|
|
|
if (error) throw error;
|
|
|
|
console.log(`Mensaje de asignatura ${mensajeId} actualizado con éxito.`);
|
|
|
|
} catch (e) {
|
|
console.error("Error en handleAsignaturaMensajesResponse:", { mensajeId, error: e.message });
|
|
|
|
// Marcamos como error en la tabla correcta para que el front deje de mostrar el spinner
|
|
await supabase
|
|
.from("asignatura_mensajes_ia")
|
|
.update({ estado: "ERROR" })
|
|
.eq("id", mensajeId);
|
|
}
|
|
} |