import { api } from "../lib/api.js";
import { on } from "../lib/bus.js";
const PROMPT_LABELS = {
router: "Router (clasificador de dominio)",
greeting: "Saludos",
orders: "Pedidos",
shipping: "Envio/Retiro",
payment: "Pago",
browse: "Consultas de catalogo",
};
class PromptsCrud extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
this.items = [];
this.selected = null;
this.loading = false;
this.versions = [];
this.availableVariables = [];
this.availableModels = [];
this.currentSettings = {}; // Valores actuales de las variables
this.testResult = null;
this.testLoading = false;
this.shadowRoot.innerHTML = `
`;
}
connectedCallback() {
this.load();
// Refrescar settings cuando se vuelve a esta vista (por si cambiaron en Config)
this._unsubRouter = on("router:viewChanged", ({ view }) => {
if (view === "prompts") {
this.refreshSettings();
}
});
}
disconnectedCallback() {
this._unsubRouter?.();
}
async refreshSettings() {
try {
const settings = await api.getSettings();
this.currentSettings = {
store_name: settings.store_name || "",
store_hours: this.formatStoreHours(settings),
store_address: settings.store_address || "",
store_phone: settings.store_phone || "",
bot_name: settings.bot_name || "",
current_date: new Date().toLocaleDateString("es-AR"),
customer_name: "(nombre del cliente)",
state: "(estado actual)",
};
// Re-renderizar el form si hay uno seleccionado
if (this.selected) {
this.renderForm();
}
} catch (e) {
console.debug("Error refreshing settings:", e);
}
}
async load() {
this.loading = true;
this.renderList();
try {
// Cargar prompts y settings en paralelo
const [data, settings] = await Promise.all([
api.prompts(),
api.getSettings().catch(() => ({})),
]);
this.items = data.items || [];
this.availableVariables = data.available_variables || [];
this.availableModels = data.available_models || [];
// Mapear settings a variables
this.currentSettings = {
store_name: settings.store_name || "",
store_hours: this.formatStoreHours(settings),
store_address: settings.store_address || "",
store_phone: settings.store_phone || "",
bot_name: settings.bot_name || "",
current_date: new Date().toLocaleDateString("es-AR"),
customer_name: "(nombre del cliente)",
state: "(estado actual)",
};
this.loading = false;
this.renderList();
} catch (e) {
console.error("Error loading prompts:", e);
this.items = [];
this.loading = false;
this.renderList();
}
}
formatStoreHours(settings) {
if (!settings.pickup_days) return "";
// Mapeo de días cortos a nombres legibles
const dayNames = {
lun: "Lun", mar: "Mar", mie: "Mié", jue: "Jue",
vie: "Vie", sab: "Sáb", dom: "Dom"
};
const days = settings.pickup_days.split(",").map(d => dayNames[d.trim()] || d).join(", ");
const start = (settings.pickup_hours_start || "08:00").slice(0, 5);
const end = (settings.pickup_hours_end || "20:00").slice(0, 5);
return `${days} de ${start} a ${end}`;
}
renderList() {
const list = this.shadowRoot.getElementById("list");
if (this.loading) {
list.innerHTML = `Cargando...
`;
return;
}
if (!this.items.length) {
list.innerHTML = `No se encontraron prompts
`;
return;
}
list.innerHTML = "";
for (const item of this.items) {
const el = document.createElement("div");
el.className = "item" + (this.selected?.prompt_key === item.prompt_key ? " active" : "");
const label = PROMPT_LABELS[item.prompt_key] || item.prompt_key;
const statusClass = item.is_default ? "default" : "custom";
const statusText = item.is_default ? "Default" : `v${item.version}`;
el.innerHTML = `
${label}
${statusText}
${item.model ? ` | ${item.model}` : ""}
`;
el.onclick = () => this.selectPrompt(item);
list.appendChild(el);
}
}
async selectPrompt(item) {
this.selected = item;
this.testResult = null;
this.renderList();
// Cargar detalles con versiones
try {
const details = await api.getPrompt(item.prompt_key);
this.selected = { ...item, ...details.current };
this.versions = details.versions || [];
this.availableVariables = details.available_variables || this.availableVariables;
this.availableModels = details.available_models || this.availableModels;
this.renderForm();
} catch (e) {
console.error("Error loading prompt details:", e);
this.renderForm();
}
}
renderForm() {
const form = this.shadowRoot.getElementById("form");
const title = this.shadowRoot.getElementById("formTitle");
if (!this.selected) {
title.textContent = "Editor de Prompt";
form.innerHTML = `Selecciona un prompt para editarlo
`;
return;
}
const label = PROMPT_LABELS[this.selected.prompt_key] || this.selected.prompt_key;
title.textContent = `Editar: ${label}`;
const content = this.selected.content || "";
const model = this.selected.model || "gpt-4-turbo";
form.innerHTML = `
Variables disponibles (click para insertar):
${this.availableVariables.map(v => {
const key = typeof v === 'string' ? v : v.key;
const desc = typeof v === 'string' ? '' : (v.description || '');
const value = this.currentSettings[key] || '';
const displayValue = value ? `= ${value}` : '(vacío)';
return `
${this.escapeHtml(displayValue)}
`;
}).join("")}
${this.versions.length > 0 ? `
${this.versions.map(v => `
v${v.version} ${v.is_active ? "(activa)" : ""}
${this.formatDate(v.created_at)}
${!v.is_active ? `` : ""}
`).join("")}
` : ""}
`;
// Event listeners
this.shadowRoot.getElementById("saveBtn").onclick = () => this.save();
this.shadowRoot.getElementById("resetBtn").onclick = () => this.reset();
this.shadowRoot.getElementById("testBtn").onclick = () => this.toggleTestSection();
this.shadowRoot.getElementById("runTestBtn").onclick = () => this.runTest();
// Variable buttons
this.shadowRoot.querySelectorAll(".var-btn").forEach(btn => {
btn.onclick = () => this.insertVariable(btn.dataset.var);
});
// Version restore buttons
this.shadowRoot.querySelectorAll(".versions-list button").forEach(btn => {
btn.onclick = () => this.rollback(parseInt(btn.dataset.version, 10));
});
}
escapeHtml(str) {
return (str || "").replace(/&/g, "&").replace(//g, ">").replace(/"/g, """);
}
formatDate(dateStr) {
if (!dateStr) return "";
const d = new Date(dateStr);
return d.toLocaleDateString("es-AR", { day: "2-digit", month: "2-digit", hour: "2-digit", minute: "2-digit" });
}
insertVariable(varName) {
const textarea = this.shadowRoot.getElementById("contentInput");
const start = textarea.selectionStart;
const end = textarea.selectionEnd;
const text = textarea.value;
const insertion = `{{${varName}}}`;
textarea.value = text.slice(0, start) + insertion + text.slice(end);
textarea.selectionStart = textarea.selectionEnd = start + insertion.length;
textarea.focus();
}
toggleTestSection() {
const section = this.shadowRoot.getElementById("testSection");
section.style.display = section.style.display === "none" ? "block" : "none";
}
async save() {
const content = this.shadowRoot.getElementById("contentInput").value;
const model = this.shadowRoot.getElementById("modelSelect").value;
if (!content.trim()) {
alert("El contenido no puede estar vacio");
return;
}
try {
await api.savePrompt(this.selected.prompt_key, { content, model });
alert("Prompt guardado correctamente");
await this.load();
// Re-seleccionar el prompt actual
const updated = this.items.find(i => i.prompt_key === this.selected.prompt_key);
if (updated) this.selectPrompt(updated);
} catch (e) {
console.error("Error saving prompt:", e);
alert("Error guardando: " + (e.message || e));
}
}
async reset() {
if (!confirm("Esto desactivara todas las versiones custom y volvera al prompt por defecto. Continuar?")) {
return;
}
try {
await api.resetPrompt(this.selected.prompt_key);
alert("Prompt reseteado a default");
await this.load();
const updated = this.items.find(i => i.prompt_key === this.selected.prompt_key);
if (updated) this.selectPrompt(updated);
} catch (e) {
console.error("Error resetting prompt:", e);
alert("Error: " + (e.message || e));
}
}
async rollback(version) {
if (!confirm(`Restaurar version ${version}? Se creara una nueva version con ese contenido.`)) {
return;
}
try {
await api.rollbackPrompt(this.selected.prompt_key, version);
alert("Version restaurada");
await this.load();
const updated = this.items.find(i => i.prompt_key === this.selected.prompt_key);
if (updated) this.selectPrompt(updated);
} catch (e) {
console.error("Error rolling back:", e);
alert("Error: " + (e.message || e));
}
}
async runTest() {
const testMessage = this.shadowRoot.getElementById("testMessage").value;
if (!testMessage.trim()) {
alert("Ingresa un mensaje de prueba");
return;
}
const content = this.shadowRoot.getElementById("contentInput").value;
const container = this.shadowRoot.getElementById("testResultContainer");
container.innerHTML = `Ejecutando prueba...
`;
try {
const result = await api.testPrompt(this.selected.prompt_key, {
content,
test_message: testMessage,
store_config: { store_name: "Carniceria Demo", bot_name: "Piaf" },
});
if (result.ok) {
let parsed = result.response;
try {
parsed = JSON.stringify(JSON.parse(result.response), null, 2);
} catch (e) { /* no es JSON */ }
container.innerHTML = `
${this.escapeHtml(parsed)}
Modelo: ${result.model} | Latencia: ${result.latency_ms}ms |
Tokens: ${result.usage?.total_tokens || "?"}
`;
} else {
container.innerHTML = `Error: ${result.error || "Unknown"}
`;
}
} catch (e) {
console.error("Error testing prompt:", e);
container.innerHTML = `Error: ${e.message || e}
`;
}
}
}
customElements.define("prompts-crud", PromptsCrud);