File size: 4,006 Bytes
0b329f8
fa15145
0bdb813
 
 
fa15145
 
0bdb813
 
b439d72
0bdb813
 
 
b439d72
 
0bdb813
fa15145
0bdb813
 
 
 
 
fa15145
0bdb813
fa15145
0bdb813
 
fa15145
 
410a8fc
92693e6
b439d72
0bdb813
fa15145
0bdb813
 
fa15145
0bdb813
 
 
 
 
 
 
 
 
92693e6
0bdb813
 
 
 
 
 
92693e6
a155f45
 
 
 
fa15145
0bdb813
fa15145
92693e6
 
 
0bdb813
92693e6
0bdb813
 
410a8fc
 
 
 
 
 
0bdb813
 
a155f45
0bdb813
 
92693e6
0bdb813
 
fa15145
 
0bdb813
fa15145
 
 
0bdb813
fa15145
92693e6
0bdb813
 
 
fa15145
 
0bdb813
fa15145
 
0bdb813
 
fa15145
 
 
 
0bdb813
 
 
fa15145
 
0bdb813
 
 
 
fa15145
0bdb813
fa15145
0bdb813
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import gradio as gr
import torch
import sys
import traceback
import os
from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer
from threading import Thread

# Configuración del Modelo
MODEL_ID = "Qwen/Qwen2.5-0.5B-Instruct"

# Optimizaciones extremas de CPU y RAM para Tier Gratuito
os.environ["OMP_NUM_THREADS"] = "4"
os.environ["MKL_NUM_THREADS"] = "4"
torch.set_num_threads(4)

device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"🚀 Iniciando arranque de Lumin Flash ({MODEL_ID}) en {device}...")

model = None
tokenizer = None

try:
    print("⏳ Descargando y cargando Tokenizer...")
    tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, trust_remote_code=True)
    
    print("⏳ Descargando y cargando Modelo en RAM...")
    model = AutoModelForCausalLM.from_pretrained(
        MODEL_ID, 
        dtype=torch.float16 if device == "cuda" else torch.float32, 
        device_map="auto",
        trust_remote_code=True,
        low_cpu_mem_usage=True
    )
    print("✅ ¡Modelo cargado correctamente en memoria!")
    
except Exception as e:
    print("❌" * 20)
    print(f"ERROR CRÍTICO FATAL AL CARGAR EL MODELO:\n{e}")
    print(traceback.format_exc())
    print("❌" * 20)
    # Obligamos al container a morir si no hay modelo, así HF te avisará del fallo 
    # y evitará el estado "Running zombi" que da el "NameError".
    sys.exit(1)


def chat(message, history):
    # Detección de seguridad en tiempo real
    if model is None or tokenizer is None:
        yield "⚠️ Error del servidor: El modelo de IA no está cargado correctamente. Contacta al administrador."
        return

    # Preparar el contexto del sistema
    messages = []
    messages.append({
        "role": "system", 
        "content": "You are Lumin Flash, an advanced AI assistant created by Lumin Web. You are helpful, precise, and professional. Answer questions clearly and concisely. Do not cut off sentences."
    })
    
    # Inyectar el historial de chat anterior
    for user_msg, bot_msg in history:
        messages.append({"role": "user", "content": user_msg})
        messages.append({"role": "assistant", "content": bot_msg})
    
    # Añadir el nuevo mensaje del usuario
    messages.append({"role": "user", "content": message})
    
    # Formatear el texto usando la plantilla oficial de Qwen/ChatML
    try:
        text = tokenizer.apply_chat_template(
            messages, 
            tokenize=False, 
            add_generation_prompt=True
        )
    except Exception as e:
        print(f"Aviso tokenizer: Falló el apply_chat_template, usando fallback manual. {e}")
        text = f"<|im_start|>system\nYou are Lumin Flash.<|im_end|>\n<|im_start|>user\n{message}<|im_end|>\n<|im_start|>assistant\n"
    
    # Enviar al procesador (device)
    inputs = tokenizer([text], return_tensors="pt").to(device)
    
    # Streamer para respuestas rápidas
    streamer = TextIteratorStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)
    
    # Parámetros de generación inteligentes
    generation_kwargs = dict(
        inputs, 
        streamer=streamer, 
        max_new_tokens=1024,
        temperature=0.7, 
        do_sample=True,
        top_k=50,
        top_p=0.9,
        repetition_penalty=1.1
    )
    
    # Iniciar la generación en segundo plano
    thread = Thread(target=model.generate, kwargs=generation_kwargs)
    thread.start()
    
    # Devolver texto palabra por palabra
    partial_text = ""
    for new_text in streamer:
        partial_text += new_text
        yield partial_text


# Interfaz Gráfica de Gradio
demo = gr.ChatInterface(
    fn=chat, 
    chatbot=gr.Chatbot(height=500),
    textbox=gr.Textbox(placeholder="Pregúntale a Lumin Flash...", container=False, scale=7),
    title="⚡ Lumin Flash (High Performance)",
    description="Backend oficial de inferencia rápida para Lumin Web."
)

if __name__ == "__main__":
    demo.queue().launch(server_name="0.0.0.0", server_port=7860)