File size: 2,908 Bytes
b1289bd
886f73a
6f0daea
a4fe52a
886f73a
6f0daea
b1289bd
8ec94c6
3cd4a72
 
 
8ec94c6
3cd4a72
8ec94c6
6f0daea
8ec94c6
044aa70
8ec94c6
a4fe52a
8ec94c6
 
 
 
 
0a3784c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
886f73a
 
d2cfeaf
044aa70
 
8ec94c6
886f73a
8ec94c6
7d8ba9a
a4fe52a
9cf409f
886f73a
a4fe52a
886f73a
a4fe52a
 
 
 
 
886f73a
 
a4fe52a
7d8ba9a
8ec94c6
 
 
aa50abc
8ec94c6
886f73a
001bc64
8ec94c6
a4fe52a
 
 
044aa70
 
 
cc18b6a
8ec94c6
b1289bd
8ec94c6
6cbae4b
 
9cf409f
8ec94c6
181c6f4
6cbae4b
b1289bd
886f73a
14ce91a
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
import gradio as gr
import spaces
from huggingface_hub import login
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
import os

# AUTENTICACIÓN CORRECTA PARA GEMMA EN SPACES
hf_token = os.getenv("HF_CLASSIFIER")
if hf_token:
    login(token=hf_token)
    print("Autenticado con HF_CLASSIFIER")
else:
    print("ERROR: HF_CLASSIFIER no encontrado en Secrets")

# Carga modelo y tokenizer
model_id = "google/gemma-3-4b-it"
print(f"Cargando {model_id}...")
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    torch_dtype=torch.bfloat16,
    low_cpu_mem_usage=True
)

SYSTEM_PROMPT = """You are an expert assistant that analyzes user messages. 
ALWAYS respond ONLY with valid JSON in this EXACT format:

{
  "summary": "Brief and clear summary of the user's message (max 1-2 sentences)",
  "tags": ["tag1", "tag2", "tag3"],
  "sentiment": {
    "score": -1.0,
    "label": "NEGATIVE | NEUTRAL | POSITIVE",
    "explanation": "Brief reason for the analysis"
  }
}

RULES:
- summary: Capture the main essence
- tags: 3-5 relevant keywords (themes, emotions, entities)
- sentiment: score (-1.0=negative, 0=neutral, +1.0=positive)
- NEVER add text outside the JSON
- JSON must be valid and parseable"""

@spaces.GPU(duration=120)
def generate_response(message, history):
    model.to('cuda')
    
    messages = []
    for user_msg, ai_msg in history:
        messages.append({"role": "user", "content": user_msg})
        if ai_msg:
            messages.append({"role": "assistant", "content": ai_msg})
    messages.append({"role": "user", "content": "System: "+SYSTEM_PROMPT+" User:"+message})
    
    prompt = tokenizer.apply_chat_template(
        messages,
        tokenize=False,
        add_generation_prompt=True
    )
    
    inputs = tokenizer(prompt, return_tensors="pt").to("cuda")
    
    with torch.no_grad():
        outputs = model.generate(
            **inputs,
            max_new_tokens=1512,  # Aumentado para evitar respuestas cortadas (truncadas)
            do_sample=True,
            temperature=0.7,
            pad_token_id=tokenizer.eos_token_id,
            eos_token_id=tokenizer.eos_token_id  # Añadido para forzar fin completo y evitar truncado
        )
    
    response = tokenizer.decode(
        outputs[0][inputs.input_ids.shape[1]:], 
        skip_special_tokens=True
    ).strip()
    
    model.to('cpu')
    torch.cuda.empty_cache()
    
    return response

# Interfaz estándar genérica con Gradio ChatInterface (sin CSS personalizado ni Blocks, como pide la documentación oficial de Gradio)
demo = gr.ChatInterface(
    fn=generate_response,
    title="Desxtools Crypto News Text Analyzer",
    description="Chatbot estándar con google/gemma-3-4b-it en ZeroGPU. Diseño genérico sin modificaciones.",
    cache_examples=True
)

if __name__ == "__main__":
    demo.launch()