From 93c79eee77d7796e8ee78e21a93b7cae98759023 Mon Sep 17 00:00:00 2001 From: "Roberto.silva" Date: Tue, 25 Nov 2025 11:34:00 -0600 Subject: [PATCH] Se agrega modelo de respuestas y conversaciones archivos multiples y contexto de id plan de estudios --- src/components/ai/AIChatModal.jsx | 96 +++++++++++---------- src/components/planes/academic-sections.tsx | 4 +- 2 files changed, 53 insertions(+), 47 deletions(-) diff --git a/src/components/ai/AIChatModal.jsx b/src/components/ai/AIChatModal.jsx index 98077cd..3cfd6aa 100644 --- a/src/components/ai/AIChatModal.jsx +++ b/src/components/ai/AIChatModal.jsx @@ -1,5 +1,6 @@ import React, { useEffect, useRef, useState } from "react"; import { supabase } from "@/auth/supabase"; +import ReactMarkdown from "react-markdown" /* ---------- UI Mocks (sin cambios) ---------- */ const Paperclip = (props) => ( @@ -32,13 +33,13 @@ const CardContent = ({ className, children }) =>
{children}
; /* ------------- COMPONENT ------------- */ -export default function AIChatModal({ open, onClose, context, onAccept,planId }) { +export default function AIChatModal({ open, onClose, context, onAccept }) { const [vectorStores, setVectorStores] = useState([]); const [vectorFiles, setVectorFiles] = useState([]); const [selectedVectorFile, setSelectedVectorFile] = useState(null); - const [attachedFile, setAttachedFile] = useState(null); - const [attachedPreview, setAttachedPreview] = useState(null); + const [attachedFiles, setAttachedFiles] = useState([]); + const [attachedPreviews, setAttachedPreviews] = useState([]); const [messages, setMessages] = useState([]); const [input, setInput] = useState(""); @@ -79,7 +80,8 @@ export default function AIChatModal({ open, onClose, context, onAccept,planId }) // Al abrir: reset o crear conversación useEffect(() => { - console.log(planId); + console.log(context.cont_conversation); + console.log(context); if (!open) { // si ya existe una conversación la eliminamos @@ -89,8 +91,8 @@ export default function AIChatModal({ open, onClose, context, onAccept,planId }) setMessages([]); setInput(""); setSelectedVectorFile(null); - setAttachedFile(null); - setAttachedPreview(null); + setAttachedFiles([]); + setAttachedPreviews([]); setConversationId(null); return; } @@ -127,7 +129,7 @@ export default function AIChatModal({ open, onClose, context, onAccept,planId }) // llamada const resp = await supabase.functions.invoke("modal-conversation", { headers: { Authorization: `Bearer ${token}` }, - body: { action: "start" } + body: { action: "start" , role:"system", content:context.cont_conversation, } }); console.log("createConversation -> raw resp:", resp); @@ -221,17 +223,17 @@ export default function AIChatModal({ open, onClose, context, onAccept,planId }) const token = session?.access_token; let filesInput = []; - console.log(attachedFile); - if (attachedFile) { - const base64 = await fileToBase64(attachedFile); - console.log(attachedFile); - - filesInput.push({ - type: "input_file", - filename: attachedFile.name, - file_data: `data:application/pdf;base64,${base64}` - }); - } + + if (attachedFiles.length > 0) { + for (const file of attachedFiles) { + const base64 = await fileToBase64(file); + filesInput.push({ + type: "input_file", + filename: file.name, + file_data: `data:${file.type};base64,${base64}` + }); + } +} if (selectedVectorFile) { // si el archivo del vector viene sólo con id @@ -297,8 +299,9 @@ export default function AIChatModal({ open, onClose, context, onAccept,planId }) setMessages(prev => [...prev, { role: "assistant", content: assistantText }]); - setAttachedFile(null); - setAttachedPreview(null); + setAttachedFiles([]); + setAttachedPreviews([]); + } catch (err) { console.error("Error en handleConversation:", err); @@ -356,14 +359,14 @@ export default function AIChatModal({ open, onClose, context, onAccept,planId }) }; // ---------- UI helpers ---------- - const handleAttach = (e) => { - const file = e.target.files?.[0]; - console.log(file); - - if (!file) return; - setAttachedFile(file); - setAttachedPreview(file.name); - }; + const handleAttach = (e) => { + const files = Array.from(e.target.files); + if (!files.length) return; + + setAttachedFiles(prev => [...prev, ...files]); + setAttachedPreviews(prev => [...prev, ...files.map(f => f.name)]); +}; + const handleSelectVectorFile = (file) => { setSelectedVectorFile(file); @@ -371,7 +374,7 @@ export default function AIChatModal({ open, onClose, context, onAccept,planId }) // ---------- Send flow ---------- const handleSend = async () => { - if (!input.trim() && !attachedFile && !selectedVectorFile) return; + if (!input.trim() && attachedFiles.length === 0 && !selectedVectorFile) return; // esperar si aún se está creando la conversación if (creatingConversation) { @@ -411,8 +414,8 @@ export default function AIChatModal({ open, onClose, context, onAccept,planId }) Asistente Inteligente -
-
+
+
{/* Left: vectors */} @@ -471,17 +474,21 @@ export default function AIChatModal({ open, onClose, context, onAccept,planId }) {/* Right: Chat */} - + +

Chat con IA

-
- {messages.length === 0 ? ( +
+ {/* CONTENEDOR SCROLL DE LOS MENSAJES */} +
+ {messages.length === 0 ? (

Inicia una conversación...

) : ( messages.map((m, i) => (
{m.role === "user" ? "Tú:" : m.role === "assistant" ? "IA:" : "Sistema:"}{" "} -
{m.content}
+ {m.content} +
)) )} @@ -498,21 +505,20 @@ export default function AIChatModal({ open, onClose, context, onAccept,planId })
+
- {attachedPreview && ( -
- - - {attachedPreview} - - -
+ {attachedPreviews.length > 0 && ( +
    + {attachedPreviews.map((name, i) => ( +
  • 📄 {name}
  • + ))} +
)}