diff --git a/yuy-chat-complete/.gitignore b/yuy-chat/.gitignore similarity index 100% rename from yuy-chat-complete/.gitignore rename to yuy-chat/.gitignore diff --git a/yuy-chat-complete/Cargo.toml b/yuy-chat/Cargo.toml similarity index 100% rename from yuy-chat-complete/Cargo.toml rename to yuy-chat/Cargo.toml diff --git a/yuy-chat/README.md b/yuy-chat/README.md new file mode 100644 index 0000000..696ecd9 --- /dev/null +++ b/yuy-chat/README.md @@ -0,0 +1,180 @@ +# yuy-chat + +
+ +``` +$$\ $$\ +\$$\ $$ | + \$$\ $$ /$$\ $$\ $$\ $$\ + \$$$$ / $$ | $$ |$$ | $$ | + \$$ / $$ | $$ |$$ | $$ | + $$ | $$ | $$ |$$ | $$ | + $$ | \$$$$$$ |\$$$$$$$ | + \__| \______/ \____$$ | + $$\ $$ | + \$$$$$$ | + \______/ +``` + +**Beautiful TUI chat interface for local AI models** + +[![Rust](https://img.shields.io/badge/rust-1.70%2B-orange.svg)](https://www.rust-lang.org) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) + +
+ +--- + +## 🌟 Features + +- ✨ **Beautiful TUI** - Gorgeous terminal interface powered by ratatui +- 🔍 **Auto-discovery** - Automatically finds `.gguf` and `.llamafile` models +- 🎨 **Presets** - Creative, Balanced, and Precise modes +- 💾 **Save conversations** - Keep your chat history +- 🌐 **HuggingFace API** - Use models from HuggingFace (optional) +- ⚡ **Fast & Lightweight** - ~5MB binary, minimal dependencies +- 🚀 **Streaming responses** - See words appear as they're generated +- 🎯 **Zero configuration** - Just run and chat + +## 📦 Installation + +### From source: + +```bash +git clone https://github.com/YuuKi-OS/yuy-chat +cd yuy-chat +cargo build --release +``` + +### Install globally: + +```bash +cargo install --path . +``` + +## 🚀 Quick Start + +```bash +# Run yuy-chat +yuy-chat + +# It will auto-scan ~/.yuuki/models/ for .gguf and .llamafile files +# Select a model and start chatting! +``` + +## 📁 Supported Model Formats + +- ✅ **GGUF** (`.gguf`) - Runs with llama.cpp +- ✅ **Llamafile** (`.llamafile`) - Self-contained executables + +## 🎮 Controls + +### Model Selector +- `↑/↓` or `j/k` - Navigate models +- `Enter` - Select model +- `R` - Refresh model list +- `Q` - Quit + +### Chat +- `Type` - Write your message +- `Enter` - Send message +- `Shift+Enter` - New line +- `Ctrl+Enter` - Send (always) +- `Ctrl+C` - Open menu +- `Ctrl+L` - Clear chat +- `Ctrl+S` - Save conversation +- `↑/↓` - Scroll chat (when input is empty) + +### Menu +- `1` - Change model +- `2` - Change preset +- `3` - Save conversation +- `4` - Load conversation +- `5` - Clear chat +- `6` - Settings +- `Q` - Back to chat + +## ⚙️ Configuration + +Config file location: `~/.config/yuy-chat/config.toml` + +```toml +models_dir = "/home/user/.yuuki/models" +hf_token = "hf_xxxxxxxxxxxxx" # Optional +default_preset = "Balanced" +save_history = true +theme = "Dark" +``` + +## 🎯 Presets + +- **Creative** (temp: 0.8, top_p: 0.9) - More random and creative +- **Balanced** (temp: 0.6, top_p: 0.7) - Good middle ground +- **Precise** (temp: 0.3, top_p: 0.5) - More focused and deterministic + +## 🌐 HuggingFace Integration + +Add your HuggingFace token in settings to use models via API: + +1. Press `Ctrl+C` → `6` (Settings) +2. Edit `HuggingFace Token` +3. Paste your token from https://huggingface.co/settings/tokens +4. Save and refresh models + +## 📚 Directory Structure + +``` +~/.config/yuy-chat/ +├── config.toml # Configuration +└── conversations/ # Saved chats + ├── conversation-20240206-143022.json + └── conversation-20240206-150133.json +``` + +## 🔧 Requirements + +- **Rust 1.70+** (for building) +- **llama.cpp** (for .gguf models) - Install with: `yuy runtime install llama-cpp` +- **chmod +x** (for .llamafile models) + +## 🤝 Integration with yuy + +yuy-chat is designed to work alongside [yuy](https://github.com/YuuKi-OS/yuy): + +```bash +# Download models with yuy +yuy download Yuuki-best + +# Chat with yuy-chat +yuy-chat +``` + +## 🐛 Troubleshooting + +**No models found?** +- Make sure you have models in `~/.yuuki/models/` +- Or specify custom directory: `yuy-chat --models-dir /path/to/models` + +**llama.cpp not found?** +- Install with: `yuy runtime install llama-cpp` +- Or: `brew install llama.cpp` (macOS) +- Or: `pkg install llama-cpp` (Termux) + +**Streaming not working?** +- Ensure llama.cpp is installed and in PATH +- Check model file permissions + +## 📝 License + +MIT License - see [LICENSE](LICENSE) file + +## 🌸 Credits + +Made with love by the Yuuki team + +- TUI Framework: [ratatui](https://github.com/ratatui-org/ratatui) +- Inference: [llama.cpp](https://github.com/ggerganov/llama.cpp) + +--- + +**For model management, see [yuy](https://github.com/YuuKi-OS/yuy)** diff --git a/yuy-chat/USAGE.md b/yuy-chat/USAGE.md new file mode 100644 index 0000000..1f728e2 --- /dev/null +++ b/yuy-chat/USAGE.md @@ -0,0 +1,495 @@ +# yuy-chat - Guía de Uso Completa + +## 📖 Contenido + +1. [Instalación](#instalación) +2. [Primera Vez](#primera-vez) +3. [Uso Diario](#uso-diario) +4. [Configuración Avanzada](#configuración-avanzada) +5. [Integración con HuggingFace](#integración-con-huggingface) +6. [Tips y Trucos](#tips-y-trucos) +7. [Troubleshooting](#troubleshooting) + +--- + +## 🔧 Instalación + +### Termux (Android) + +```bash +# Instalar Rust +pkg install rust + +# Clonar y compilar +git clone https://github.com/YuuKi-OS/yuy-chat +cd yuy-chat +cargo build --release -j 1 # Usar 1 thread en Termux + +# Instalar globalmente +cargo install --path . +``` + +### Linux/macOS + +```bash +# Clonar y compilar +git clone https://github.com/YuuKi-OS/yuy-chat +cd yuy-chat +cargo build --release + +# Instalar +cargo install --path . +``` + +### Windows + +```bash +# Mismo proceso que Linux/macOS +git clone https://github.com/YuuKi-OS/yuy-chat +cd yuy-chat +cargo build --release +cargo install --path . +``` + +--- + +## 🎬 Primera Vez + +### 1. Asegúrate de tener modelos + +yuy-chat busca modelos en `~/.yuuki/models/` por defecto. + +**Opción A: Usar yuy** +```bash +yuy download Yuuki-best +``` + +**Opción B: Copiar manualmente** +```bash +mkdir -p ~/.yuuki/models/ +cp /path/to/your/model.gguf ~/.yuuki/models/ +``` + +### 2. Instalar llama.cpp + +**Termux:** +```bash +pkg install llama-cpp +``` + +**macOS:** +```bash +brew install llama.cpp +``` + +**Linux:** +```bash +# Descargar desde releases +wget https://github.com/ggerganov/llama.cpp/releases/... +chmod +x llama-cli +sudo mv llama-cli /usr/local/bin/ +``` + +### 3. Ejecutar yuy-chat + +```bash +yuy-chat +``` + +Verás el selector de modelos. Usa `↑/↓` para navegar y `Enter` para seleccionar. + +--- + +## 💬 Uso Diario + +### Flujo Básico + +``` +1. Ejecuta: yuy-chat + ↓ +2. Selecciona modelo con ↑/↓ y Enter + ↓ +3. Escribe tu mensaje + ↓ +4. Presiona Enter para enviar + ↓ +5. Yuuki responde (streaming) + ↓ +6. Continúa la conversación +``` + +### Atajos de Teclado Útiles + +**En chat:** +- `Enter` - Enviar mensaje +- `Shift+Enter` - Nueva línea (para mensajes multi-línea) +- `Ctrl+L` - Limpiar chat +- `Ctrl+S` - Guardar conversación +- `Ctrl+C` - Abrir menú + +**Escribir código:** +``` +You: Dame un ejemplo de código Python + +[Shift+Enter para nueva línea] +def hello(): + print("Hola") +[Shift+Enter] + +hello() + +[Ctrl+Enter para enviar] +``` + +### Cambiar Preset + +``` +1. Ctrl+C (abrir menú) + ↓ +2. Presiona 2 (Change Preset) + ↓ + Cicla entre: Creative → Balanced → Precise +``` + +**Cuándo usar cada preset:** +- **Creative**: Escribir historias, brainstorming, ideas +- **Balanced**: Uso general, conversación +- **Precise**: Código, matemáticas, datos exactos + +--- + +## ⚙️ Configuración Avanzada + +### Cambiar Directorio de Modelos + +**Método 1: Configuración** +```bash +yuy-chat +Ctrl+C → 6 (Settings) +Editar "Models Directory" +``` + +**Método 2: Archivo config** +```bash +nano ~/.config/yuy-chat/config.toml +``` + +```toml +models_dir = "/custom/path/to/models" +``` + +### Personalizar Presets + +Edita el código o usa parámetros de llama.cpp directamente: + +```bash +# En models/runtime.rs, modifica: +pub fn temperature(&self) -> f32 { + match self { + Preset::Creative => 0.9, // Más aleatorio + // ... + } +} +``` + +### Tema Claro + +```toml +theme = "Light" +``` + +--- + +## 🌐 Integración con HuggingFace + +### 1. Obtener Token + +1. Ve a https://huggingface.co/settings/tokens +2. Click "Create new token" +3. Tipo: "Read" +4. Copia el token + +### 2. Configurar en yuy-chat + +**Método A: UI** +``` +Ctrl+C → 6 (Settings) +Navigate to "HuggingFace Token" +Enter → Pega tu token +``` + +**Método B: Config file** +```toml +hf_token = "hf_abcdefghijklmnopqrstuvwxyz1234567890" +``` + +### 3. Usar Modelos de HF + +Después de configurar el token: +``` +yuy-chat +[Verás modelos locales + modelos HF API] + +> Yuuki-best.gguf (Local) + Yuuki-3.7.gguf (Local) + Yuuki-best (HF API) <-- Usa la API +``` + +**Ventajas:** +- No ocupa espacio local +- Siempre actualizado +- Acceso a modelos privados + +**Desventajas:** +- Requiere internet +- Más lento que local +- Rate limits en plan gratis + +--- + +## 💡 Tips y Trucos + +### Guardar Conversaciones Importantes + +``` +Ctrl+S mientras chateas +→ Se guarda en ~/.config/yuy-chat/conversations/ +``` + +### Cargar Conversación Anterior + +``` +Ctrl+C → 4 (Load Conversation) +↑/↓ para navegar +Enter para cargar +``` + +### Prompt Engineering + +**Para mejores respuestas, sé específico:** + +❌ Malo: +``` +You: Explica Rust +``` + +✅ Bueno: +``` +You: Explica el sistema de ownership en Rust con un ejemplo simple de borrowing. Quiero entender por qué evita memory leaks. +``` + +### Conversaciones Multi-paso + +``` +You: Vamos a diseñar una API REST + +Yuuki: Claro, ¿qué tipo de API? + +You: Para gestionar tareas tipo TODO + +Yuuki: Perfecto, estos son los endpoints... +``` + +### Usar Presets Dinámicamente + +- **Creative preset**: "Escribe un cuento de terror" +- **Precise preset**: "¿Cuál es la complejidad de quicksort?" +- **Balanced preset**: "Explícame cómo funciona Git" + +--- + +## 🔧 Troubleshooting + +### Error: "No models found" + +**Solución:** +```bash +# Verifica que tienes modelos +ls ~/.yuuki/models/ + +# Si está vacío, descarga uno +yuy download Yuuki-best + +# O especifica otro directorio +yuy-chat --models-dir /path/to/models +``` + +### Error: "llama.cpp binary not found" + +**Solución:** +```bash +# Termux +pkg install llama-cpp + +# macOS +brew install llama.cpp + +# Linux - verifica que está en PATH +which llama-cli +# Si no, instala o agrega al PATH +export PATH=$PATH:/path/to/llama-cpp +``` + +### Error: "Permission denied" (llamafile) + +**Solución:** +```bash +chmod +x ~/.yuuki/models/*.llamafile +``` + +### Chat no responde / se congela + +**Diagnóstico:** +1. Verifica que llama.cpp funciona: +```bash +llama-cli -m ~/.yuuki/models/Yuuki-best.gguf -p "Hola" +``` + +2. Revisa logs: +```bash +RUST_LOG=debug yuy-chat +``` + +3. Reduce context size si es falta de RAM + +### Respuestas muy lentas + +**Causas comunes:** +- Modelo muy grande para tu RAM +- Cuantización muy alta (F32, Q8) +- Sin aceleración GPU + +**Solución:** +```bash +# Descarga versión cuantizada más pequeña +yuy download Yuuki-best --quant q4_0 + +# Verifica RAM disponible +free -h # Linux +top # macOS/Linux +``` + +### No puedo escribir mensajes largos + +El input box tiene límite visual pero **no de contenido**: +- Usa `Shift+Enter` para multi-línea +- Scroll automático después de 5 líneas +- O escribe en editor externo y pega + +### HuggingFace API no funciona + +**Verifica:** +```bash +# Test manual +curl https://api-inference.huggingface.co/models/OpceanAI/Yuuki-best \ + -H "Authorization: Bearer YOUR_TOKEN" \ + -d '{"inputs": "test"}' +``` + +**Problemas comunes:** +- Token expirado → Genera nuevo +- Rate limit → Espera o upgrade plan +- Modelo privado → Verifica permisos + +--- + +## 📊 Performance Tips + +### Termux/Móvil + +```bash +# Usa modelos pequeños +yuy download Yuuki-best --quant q4_0 + +# Preset Balanced o Precise +# Creative es más lento +``` + +### Desktop High-end + +```bash +# Usa Q8 o F32 para mejor calidad +yuy download Yuuki-best --quant q8_0 + +# Habilita GPU en llama.cpp +llama-cli -m model.gguf -ngl 32 # 32 layers en GPU +``` + +--- + +## 🎓 Casos de Uso + +### 1. Coding Assistant + +``` +Preset: Precise + +You: Cómo implemento un servidor HTTP en Rust? +You: Muestra ejemplo con tokio +You: Agrega manejo de errores +You: Ahora agrega logging +``` + +### 2. Creative Writing + +``` +Preset: Creative + +You: Escribe el inicio de una novela de ciencia ficción ambientada en Marte en el año 2157 +You: Continúa describiendo al protagonista +You: ¿Qué conflicto enfrenta? +``` + +### 3. Learning/Study + +``` +Preset: Balanced + +You: Explícame la diferencia entre mutex y semaphore +You: Dame un ejemplo de cuándo usar cada uno +You: ¿Qué pasa si no uso sincronización? +``` + +--- + +## 🚀 Workflow Recomendado + +### Developer + +```bash +# Mañana: Coding +yuy-chat # Preset: Precise +> Ayuda con bugs, arquitectura, código + +# Tarde: Docs +yuy-chat # Preset: Balanced +> Escribir documentación, READMEs + +# Noche: Ideas +yuy-chat # Preset: Creative +> Brainstorming features +``` + +### Writer + +```bash +yuy-chat # Preset: Creative +> Generar ideas +> Escribir borradores +> Feedback de historias +``` + +### Estudiante + +```bash +yuy-chat # Preset: Balanced +> Explicaciones de conceptos +> Resolver dudas +> Preparar exámenes +``` + +--- + +**¿Preguntas? Abre un issue en GitHub!** + +🌸 Hecho con amor por el equipo Yuuki diff --git a/yuy-chat-complete/src/app.rs b/yuy-chat/src/app.rs similarity index 100% rename from yuy-chat-complete/src/app.rs rename to yuy-chat/src/app.rs diff --git a/yuy-chat-complete/src/config.rs b/yuy-chat/src/config.rs similarity index 91% rename from yuy-chat-complete/src/config.rs rename to yuy-chat/src/config.rs index a121669..ac2c82e 100644 --- a/yuy-chat-complete/src/config.rs +++ b/yuy-chat/src/config.rs @@ -110,3 +110,9 @@ impl Config { Ok(config_dir) } } + +// Yuuki constants +pub const HF_ORG: &str = "OpceanAI"; +pub const OLLAMA_ORG: &str = "aguitachan3"; +pub const YUUKI_API: &str = "https://huggingface.co/spaces/OpceanAI/Yuuki-api"; +pub const AVAILABLE_QUANTS: &[&str] = &["q4_0", "q4_k_m", "q5_k_m", "q8_0", "f32"]; diff --git a/yuy-chat-complete/src/conversation.rs b/yuy-chat/src/conversation.rs similarity index 100% rename from yuy-chat-complete/src/conversation.rs rename to yuy-chat/src/conversation.rs diff --git a/yuy-chat-complete/src/main.rs b/yuy-chat/src/main.rs similarity index 100% rename from yuy-chat-complete/src/main.rs rename to yuy-chat/src/main.rs diff --git a/yuy-chat-complete/src/models/hf_api.rs b/yuy-chat/src/models/hf_api.rs similarity index 100% rename from yuy-chat-complete/src/models/hf_api.rs rename to yuy-chat/src/models/hf_api.rs diff --git a/yuy-chat-complete/src/models/mod.rs b/yuy-chat/src/models/mod.rs similarity index 100% rename from yuy-chat-complete/src/models/mod.rs rename to yuy-chat/src/models/mod.rs diff --git a/yuy-chat-complete/src/models/runtime.rs b/yuy-chat/src/models/runtime.rs similarity index 76% rename from yuy-chat-complete/src/models/runtime.rs rename to yuy-chat/src/models/runtime.rs index 8fbae15..3073b44 100644 --- a/yuy-chat-complete/src/models/runtime.rs +++ b/yuy-chat/src/models/runtime.rs @@ -1,5 +1,5 @@ use super::{Model, ModelFormat, ModelSource}; -use crate::config::Preset; +use crate::config::{Preset, YUUKI_API}; use anyhow::{Context, Result}; use std::process::Stdio; use tokio::io::{AsyncBufReadExt, BufReader}; @@ -109,19 +109,44 @@ impl ModelRuntime { } async fn generate_hf(&mut self, prompt: &str) -> Result<()> { - // Placeholder for HuggingFace API call + // Use Yuuki API let (tx, rx) = mpsc::channel(100); self.response_rx = Some(rx); let prompt_owned = prompt.to_string(); + let api_url = YUUKI_API.to_string(); + let temp = self.preset.temperature(); + let top_p = self.preset.top_p(); tokio::spawn(async move { - // Simulated streaming response - let response = format!("Response to: {}", prompt_owned); - for word in response.split_whitespace() { - let _ = tx.send(format!("{} ", word)).await; - tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + // Call Yuuki API + let client = reqwest::Client::new(); + let response = client + .post(&api_url) + .json(&serde_json::json!({ + "prompt": prompt_owned, + "temperature": temp, + "top_p": top_p, + "max_tokens": 512 + })) + .send() + .await; + + match response { + Ok(resp) => { + if let Ok(text) = resp.text().await { + // Stream response word by word + for word in text.split_whitespace() { + let _ = tx.send(format!("{} ", word)).await; + tokio::time::sleep(tokio::time::Duration::from_millis(50)).await; + } + } + } + Err(_) => { + let _ = tx.send("Error: Could not connect to Yuuki API".to_string()).await; + } } + let _ = tx.send("[DONE]".to_string()).await; }); diff --git a/yuy-chat-complete/src/models/scanner.rs b/yuy-chat/src/models/scanner.rs similarity index 100% rename from yuy-chat-complete/src/models/scanner.rs rename to yuy-chat/src/models/scanner.rs diff --git a/yuy-chat-complete/src/ui/chat.rs b/yuy-chat/src/ui/chat.rs similarity index 100% rename from yuy-chat-complete/src/ui/chat.rs rename to yuy-chat/src/ui/chat.rs diff --git a/yuy-chat-complete/src/ui/conversations.rs b/yuy-chat/src/ui/conversations.rs similarity index 100% rename from yuy-chat-complete/src/ui/conversations.rs rename to yuy-chat/src/ui/conversations.rs diff --git a/yuy-chat-complete/src/ui/menu.rs b/yuy-chat/src/ui/menu.rs similarity index 100% rename from yuy-chat-complete/src/ui/menu.rs rename to yuy-chat/src/ui/menu.rs diff --git a/yuy-chat-complete/src/ui/mod.rs b/yuy-chat/src/ui/mod.rs similarity index 100% rename from yuy-chat-complete/src/ui/mod.rs rename to yuy-chat/src/ui/mod.rs diff --git a/yuy-chat-complete/src/ui/selector.rs b/yuy-chat/src/ui/selector.rs similarity index 100% rename from yuy-chat-complete/src/ui/selector.rs rename to yuy-chat/src/ui/selector.rs diff --git a/yuy-chat-complete/src/ui/settings.rs b/yuy-chat/src/ui/settings.rs similarity index 100% rename from yuy-chat-complete/src/ui/settings.rs rename to yuy-chat/src/ui/settings.rs