lythron-ai / Lythron.jsx
LythronAI's picture
Update Lythron.jsx
ddcf2aa verified
import { useState, useRef, useEffect } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import { Send, Sparkles, Copy, Trash2, Volume2, User } from 'lucide-react'
import axios from 'axios'
// ═══════════════════════════════════════════════════════════════
// IDENTIDAD COMPLETA DE LYTHRON AI
// ═══════════════════════════════════════════════════════════════
const LYTHRON_IDENTITY = {
name: "Lythron",
fullName: "Lythron AI Assistant",
creator: "Lythron AI",
version: "1.0",
releaseDate: "2024",
description: "Asistente inteligente de propósito general",
origin: {
company: "Lythron AI",
mission: "Proporcionar asistencia inteligente accesible y versátil a usuarios en todo el mundo",
philosophy: "Transparencia, calidad y versatilidad en cada interacción"
},
capabilities: [
"Programación en múltiples lenguajes (Python, JavaScript, Java, C++, etc.)",
"Análisis profundo de datos y textos",
"Generación de contenido creativo",
"Explicaciones técnicas complejas",
"Resolución de problemas",
"Brainstorming e ideación",
"Asesoramiento técnico",
"Depuración y optimización de código",
"Traducción entre idiomas",
"Respuestas contextuales inteligentes"
],
systemInfo: {
language: "Español/English",
timezone: "Global",
responseStyle: "Directo, útil y accesible",
specialties: [
"Web Development",
"Data Analysis",
"Creative Writing",
"Technical Documentation",
"Problem Solving"
]
},
knownFacts: {
creation: "Soy Lythron, un asistente inteligente creado por Lythron AI con el propósito de ser tu compañero versátil en cualquier tarea.",
purpose: "Mi objetivo es ayudarte con programación, análisis, creatividad, explicaciones técnicas y resolución de problemas de forma inteligente y accesible.",
personality: "Soy directo, amable, siempre dispuesto a aprender de ti y comprometido con proporcionar respuestas de calidad.",
philosophy: "Creo en la transparencia, la accesibilidad y en potenciar a los usuarios con conocimiento de calidad.",
background: "Fui diseñado por Lythron AI, una organización dedicada a hacer la inteligencia artificial más accesible y útil para todos.",
uniqueness: "Mi fortaleza radica en mi versatilidad: puedo pasar de programación compleja a creatividad pura, siempre manteniendo calidad."
}
}
// Función para llamar a Hugging Face API
const fetchAIResponse = async (userMessage) => {
try {
const HF_TOKEN = import.meta.env.VITE_HF_TOKEN
if (!HF_TOKEN) {
return "Error: Token de Hugging Face no configurado. Verifica tu archivo .env con VITE_HF_TOKEN"
}
const response = await axios.post(
"https://api-inference.huggingface.co/models/meta-llama/Llama-2-7b-chat-hf",
{ inputs: userMessage },
{
headers: { Authorization: `Bearer ${ HF_TOKEN }` },
timeout: 30000
}
)
let text = response.data?.[0]?.generated_text || response.data?.generated_text || "Lo siento, no pude generar respuesta."
if (text.includes(userMessage)) {
text = text.replace(userMessage, "").trim()
}
return text || "Lo siento, no pude generar respuesta."
} catch (error) {
console.error("Error al llamar a Hugging Face:", error)
if (error.response?.status === 429) {
return "El modelo está sobrecargado. Por favor, intenta en unos segundos."
}
if (error.response?.status === 503) {
return "El modelo se está cargando. Por favor, espera unos momentos e intenta de nuevo."
}
return `Error: ${ error.response?.data?.error || error.message || "Problema generando respuesta de IA. Intenta de nuevo." }`
}
}
export default function Lythron() {
const [messages, setMessages] = useState([
{
id: 1,
text: `Hola. Soy ${ LYTHRON_IDENTITY.name }, tu asistente inteligente creado por ${ LYTHRON_IDENTITY.creator }. Estoy conectado a Hugging Face para darte respuestas reales. En qué puedo ayudarte hoy?`,
sender: "ai",
timestamp: new Date(),
}
])
const [input, setInput] = useState("")
const [isLoading, setIsLoading] = useState(false)
const [copiedId, setCopiedId] = useState(null)
const messagesEndRef = useRef(null)
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" })
}
useEffect(() => {
scrollToBottom()
}, [messages])
const handleSendMessage = async () => {
if (!input.trim()) return
const newMessage = {
id: Date.now(),
text: input,
sender: "user",
timestamp: new Date(),
}
setMessages((prev) => [...prev, newMessage])
setInput("")
setIsLoading(true)
try {
const aiText = await fetchAIResponse(input)
const aiResponse = {
id: Date.now() + 1,
text: aiText,
sender: "ai",
timestamp: new Date(),
}
setMessages((prev) => [...prev, aiResponse])
} catch (error) {
console.error("Error en handleSendMessage:", error)
const errorResponse = {
id: Date.now() + 1,
text: "Hubo un problema conectando con la IA. Por favor, intenta de nuevo.",
sender: "ai",
timestamp: new Date(),
}
setMessages((prev) => [...prev, errorResponse])
} finally {
setIsLoading(false)
}
}
const handleCopy = (text, id) => {
navigator.clipboard.writeText(text)
setCopiedId(id)
setTimeout(() => setCopiedId(null), 2000)
}
const handleClearChat = () => {
setMessages([
{
id: 1,
text: `Hola. Soy ${ LYTHRON_IDENTITY.name } v${ LYTHRON_IDENTITY.version }, creado por ${ LYTHRON_IDENTITY.creator }. Estoy conectado a Hugging Face para darte respuestas reales. En qué puedo ayudarte?`,
sender: "ai",
timestamp: new Date(),
}
])
}
return (
<div className="flex flex-col h-screen bg-gradient-to-br from-zinc-950 via-zinc-900 to-black text-white">
<div className="border-b border-white/10 bg-black/40 backdrop-blur-md sticky top-0 z-10">
<div className="max-w-6xl mx-auto px-4 py-4 flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="p-2 bg-gradient-to-br from-neon-cyan to-neon-pink rounded-lg">
<Sparkles size={24} className="text-black" />
</div>
<div>
<h1 className="text-2xl font-bold bg-gradient-to-r from-neon-cyan to-neon-pink bg-clip-text text-transparent">
{LYTHRON_IDENTITY.fullName}
</h1>
<p className="text-xs text-gray-400">Creado por {LYTHRON_IDENTITY.creator}</p>
</div>
</div>
<button
onClick={handleClearChat}
className="flex items-center gap-2 px-4 py-2 bg-white/10 hover:bg-white/20 rounded-lg transition-all text-sm"
>
<Trash2 size={18} />
Limpiar chat
</button>
</div>
</div>
<div className="flex-1 overflow-y-auto px-4 py-6 space-y-4 max-w-6xl mx-auto w-full">
<AnimatePresence>
{messages.map((message) => (
<motion.div
key={message.id}
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.3 }}
className={`flex ${message.sender === "user" ? "justify-end" : "justify-start"}`}
>
<div
className={`max-w-2xl px-4 py-3 rounded-lg ${
message.sender === "user"
? "bg-gradient-to-r from-neon-cyan to-neon-pink text-black rounded-br-none"
: "bg-white/10 border border-white/20 text-white rounded-bl-none"
}`}
>
<div className="flex items-start gap-3">
{message.sender === "ai" && (
<div className="mt-1 flex-shrink-0">
<div className="p-1 bg-neon-cyan/20 rounded">
<Sparkles size={16} className="text-neon-cyan" />
</div>
</div>
)}
<div className="flex-1">
<p className="text-sm leading-relaxed whitespace-pre-wrap break-words">
{message.text}
</p>
<div className="flex items-center gap-2 mt-2 text-xs opacity-70">
<span>{message.timestamp.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}</span>
{message.sender === "ai" && (
<>
<button
onClick={() => handleCopy(message.text, message.id)}
className="hover:opacity-100 transition-opacity p-1 hover:bg-white/10 rounded"
title="Copiar"
>
<Copy size={14} />
</button>
<button
className="hover:opacity-100 transition-opacity p-1 hover:bg-white/10 rounded"
title="Leer en voz alta"
>
<Volume2 size={14} />
</button>
</>
)}
</div>
</div>
{message.sender === "user" && (
<div className="mt-1 flex-shrink-0">
<div className="p-1 bg-black/30 rounded">
<User size={16} />
</div>
</div>
)}
</div>
{copiedId === message.id && (
<motion.p
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="text-xs mt-1 text-green-400"
>
✓ Copiado
</motion.p>
)}
</div>
</motion.div>
))}
</AnimatePresence>
{isLoading && (
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
className="flex justify-start"
>
<div className="bg-white/10 border border-white/20 text-white rounded-lg rounded-bl-none px-4 py-3">
<div className="flex gap-2">
<motion.div
animate={{ scale: [1, 1.2, 1] }}
transition={{ repeat: Infinity, duration: 0.6 }}
className="w-2 h-2 bg-neon-cyan rounded-full"
/>
<motion.div
animate={{ scale: [1, 1.2, 1] }}
transition={{ repeat: Infinity, duration: 0.6, delay: 0.1 }}
className="w-2 h-2 bg-neon-pink rounded-full"
/>
<motion.div
animate={{ scale: [1, 1.2, 1] }}
transition={{ repeat: Infinity, duration: 0.6, delay: 0.2 }}
className="w-2 h-2 bg-neon-purple rounded-full"
/>
</div>
</div>
</motion.div>
)}
<div ref={messagesEndRef} />
</div>
<div className="border-t border-white/10 bg-black/40 backdrop-blur-md p-4">
<div className="max-w-6xl mx-auto flex gap-2">
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={(e) => e.key === "Enter" && !isLoading && handleSendMessage()}
placeholder="Pregúntale a Lythron..."
className="flex-1 bg-white/10 border border-white/20 rounded-lg px-4 py-3 text-white placeholder-gray-500 focus:outline-none focus:border-neon-cyan focus:ring-2 focus:ring-neon-cyan/20 transition-all"
disabled={isLoading}
/>
<button
onClick={handleSendMessage}
disabled={isLoading || !input.trim()}
className="p-3 bg-gradient-to-r from-neon-cyan to-neon-pink text-black rounded-lg hover:shadow-lg hover:shadow-neon-pink/50 transition-all disabled:opacity-50 disabled:cursor-not-allowed font-semibold"
>
<Send size={20} />
</button>
</div>
<p className="text-xs text-gray-500 mt-2 text-center">
{LYTHRON_IDENTITY.fullName} • Versión {LYTHRON_IDENTITY.version} • Creado por {LYTHRON_IDENTITY.creator} • Powered by Hugging Face
</p>
</div>
</div>
)
}