implementando openAI y busqueda de productos en woo
This commit is contained in:
@@ -1,21 +1,111 @@
|
||||
// src/services/openai.js (o directo en main.js por ahora)
|
||||
import OpenAI from "openai";
|
||||
import { z } from "zod";
|
||||
|
||||
export const openai = new OpenAI({ apiKey: process.env.OPENAI_APIKEY });
|
||||
const apiKey = process.env.OPENAI_API_KEY || process.env.OPENAI_APIKEY;
|
||||
|
||||
// promptSystem = tu prompt (no lo tocamos mucho)
|
||||
// input = { last_user_message, conversation_history, current_conversation_state, ... }
|
||||
export async function llmPlan({ promptSystem, input }) {
|
||||
const resp = await openai.responses.create({
|
||||
model: "gpt-5-mini", // o gpt-5 (más caro/mejor) / el que estés usando
|
||||
input: [
|
||||
{ role: "system", content: promptSystem },
|
||||
{ role: "user", content: JSON.stringify(llmInput) }
|
||||
export const openai = new OpenAI({ apiKey });
|
||||
|
||||
const NextStateSchema = z.enum([
|
||||
"IDLE",
|
||||
"BROWSING",
|
||||
"BUILDING_ORDER",
|
||||
"WAITING_ADDRESS",
|
||||
"WAITING_PAYMENT",
|
||||
"COMPLETED",
|
||||
]);
|
||||
|
||||
const IntentSchema = z.enum([
|
||||
"ask_recommendation",
|
||||
"ask_price",
|
||||
"browse_products",
|
||||
"create_order",
|
||||
"add_item",
|
||||
"remove_item",
|
||||
"checkout",
|
||||
"provide_address",
|
||||
"confirm_payment",
|
||||
"track_order",
|
||||
"other",
|
||||
]);
|
||||
|
||||
const OrderActionSchema = z.enum(["none", "create", "update", "cancel", "checkout"]);
|
||||
|
||||
const BasketItemSchema = z.object({
|
||||
product_id: z.number().int().nonnegative(),
|
||||
variation_id: z.number().int().nonnegative().nullable(),
|
||||
quantity: z.number().positive(),
|
||||
unit: z.enum(["kg", "g", "unit"]),
|
||||
label: z.string().min(1),
|
||||
});
|
||||
|
||||
const PlanSchema = z
|
||||
.object({
|
||||
reply: z.string().min(1).max(350).catch(z.string().min(1)), // respetar guideline, sin romper si excede
|
||||
next_state: NextStateSchema,
|
||||
intent: IntentSchema,
|
||||
missing_fields: z.array(z.string()).default([]),
|
||||
order_action: OrderActionSchema.default("none"),
|
||||
basket_resolved: z
|
||||
.object({
|
||||
items: z.array(BasketItemSchema).default([]),
|
||||
})
|
||||
.default({ items: [] }),
|
||||
})
|
||||
.strict();
|
||||
|
||||
function extractJsonObject(text) {
|
||||
const s = String(text || "");
|
||||
const i = s.indexOf("{");
|
||||
const j = s.lastIndexOf("}");
|
||||
if (i >= 0 && j > i) return s.slice(i, j + 1);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Genera un "plan" de conversación (salida estructurada) usando OpenAI.
|
||||
*
|
||||
* - `promptSystem`: instrucciones del bot
|
||||
* - `input`: { last_user_message, conversation_history, current_conversation_state, context }
|
||||
*/
|
||||
export async function llmPlan({ promptSystem, input, model } = {}) {
|
||||
if (!apiKey) {
|
||||
const err = new Error("OPENAI_API_KEY is not set");
|
||||
err.code = "OPENAI_NO_KEY";
|
||||
throw err;
|
||||
}
|
||||
|
||||
const chosenModel = model || process.env.OPENAI_MODEL || "gpt-4o-mini";
|
||||
|
||||
const resp = await openai.chat.completions.create({
|
||||
model: chosenModel,
|
||||
temperature: 0.2,
|
||||
response_format: { type: "json_object" },
|
||||
messages: [
|
||||
{
|
||||
role: "system",
|
||||
content:
|
||||
`${promptSystem}\n\n` +
|
||||
"Respondé SOLO con un JSON válido (sin markdown). Respetá estrictamente el formato requerido.",
|
||||
},
|
||||
{ role: "user", content: JSON.stringify(input ?? {}) },
|
||||
],
|
||||
// Si estás usando "Structured Outputs" nativo, acá va tu schema.
|
||||
// En caso de que tu SDK no lo soporte directo, lo hacemos con zod/JSON parse robusto.
|
||||
});
|
||||
|
||||
const text = resp.output_text; // ojo: depende del SDK/model; es el agregado de outputs
|
||||
return text;
|
||||
const text = resp?.choices?.[0]?.message?.content || "";
|
||||
let parsed;
|
||||
try {
|
||||
parsed = JSON.parse(text);
|
||||
} catch {
|
||||
const extracted = extractJsonObject(text);
|
||||
if (!extracted) throw new Error("openai_invalid_json");
|
||||
parsed = JSON.parse(extracted);
|
||||
}
|
||||
|
||||
const plan = PlanSchema.parse(parsed);
|
||||
return {
|
||||
plan,
|
||||
raw_text: text,
|
||||
model: chosenModel,
|
||||
usage: resp?.usage || null,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user