JMAA00 commited on
Commit
ff801d4
·
1 Parent(s): 2731234

Version 12

Browse files
Files changed (1) hide show
  1. app.py +143 -79
app.py CHANGED
@@ -1,111 +1,175 @@
1
  import os
2
- import torch
3
  import gradio as gr
4
- import threading
5
- from transformers import AutoTokenizer, AutoModelForCausalLM, TextIteratorStreamer
6
-
7
- # 1) Cargar tokenizer y modelo
8
- print("Cargando tokenizer...")
9
- tokenizer = AutoTokenizer.from_pretrained("deepseek-ai/DeepSeek-R1-Distill-Llama-8B")
10
-
11
- print("Cargando modelo...")
12
- model = AutoModelForCausalLM.from_pretrained(
13
- "deepseek-ai/DeepSeek-R1-Distill-Llama-8B",
14
- device_map="auto", # Usa GPU si está disponible
15
- torch_dtype=torch.float16 # FP16 si GPU; en CPU, podrías usar float32
16
- )
17
- model.eval()
18
 
19
- # Ajuste de pad_token_id si fuese necesario
20
- if model.config.pad_token_id is None:
21
- model.config.pad_token_id = tokenizer.eos_token_id
 
 
22
 
 
 
 
 
23
 
24
- def respond(
25
- user_message: str,
26
- history: list[tuple[str, str]],
27
- system_message: str,
28
- max_new_tokens: int,
29
- temperature: float,
30
- top_p: float,
31
- ):
32
  """
33
- Llamada por ChatInterface en cada turno.
34
- - user_message: Texto nuevo del usuario.
35
- - history: Lista [(usuario, asistente), ...] de turnos previos.
36
- - system_message: Se añade SOLO si el historial está vacío.
37
- Devuelve tokens progresivamente (streaming).
38
  """
 
 
39
 
40
- # 1) Creamos un prompt vacío
41
- prompt = ""
 
 
 
 
42
 
43
- # 2) Solo añadimos system_message si no hay historial
44
- if not history:
45
- prompt += f"{system_message}\n\n"
 
 
46
 
47
- # 3) Añadimos la conversación previa: "User: ...\nAssistant: ..."
48
- for (past_user, past_assistant) in history:
49
- prompt += f"Usuario: {past_user}\nAsistente: {past_assistant}\n"
50
 
51
- # 4) Añadimos el nuevo turno del usuario
52
- prompt += f"Usuario: {user_message}\nAsistente:"
 
53
 
54
- # 5) Preparamos un TextIteratorStreamer para streaming
55
- streamer = TextIteratorStreamer(tokenizer=tokenizer, skip_special_tokens=True)
 
 
 
56
 
57
- # 6) Codificamos el prompt
58
- inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
59
 
60
- # 7) Preparamos parámetros de generate
61
- generation_kwargs = {
62
- "inputs": inputs["input_ids"],
63
- "attention_mask": inputs["attention_mask"],
64
- "max_new_tokens": max_new_tokens,
65
- "temperature": temperature,
66
- "top_p": top_p,
67
- "do_sample": True,
68
- "streamer": streamer,
69
- }
70
 
71
- # 8) Ejecutamos model.generate en un hilo
72
- generation_thread = threading.Thread(
73
- target=model.generate,
74
- kwargs=generation_kwargs
75
- )
76
- generation_thread.start()
77
 
78
- # 9) Iteramos sobre el streamer para devolver tokens sucesivamente
79
- output_text = ""
80
- for new_token in streamer:
81
- output_text += new_token
82
- yield output_text
 
 
 
 
 
 
 
 
 
 
83
 
84
- # 10) Definimos la interfaz ChatInterface
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  demo = gr.ChatInterface(
86
  fn=respond,
87
  additional_inputs=[
88
- # Cuadro para "mensaje de sistema", solo usado en la 1ª interacción
89
  gr.Textbox(
90
- label="Mensaje del sistema (se usará sólo al inicio)",
91
- value="Eres un asistente amable y paciente. Responde siempre en español."
 
 
 
 
 
 
92
  ),
93
  gr.Slider(
94
- minimum=1, maximum=1024, value=100, step=1, label="Max new tokens"
 
 
 
 
95
  ),
96
  gr.Slider(
97
- minimum=0.1, maximum=2.0, value=0.7, step=0.1, label="Temperatura"
 
 
 
 
98
  ),
99
  gr.Slider(
100
- minimum=0.1, maximum=1.0, value=0.9, step=0.05, label="Top-p"
 
 
 
 
 
 
 
 
 
 
101
  ),
102
  ],
103
- title="DeepSeek Chat Demo",
104
- description=(
105
- "Este demo carga el modelo deepseek-ai/DeepSeek-R1-Distill-Llama-8B "
106
- "y permite conversar en varios turnos. El mensaje de sistema se añade "
107
- "sólo en la primera interacción, y luego la charla fluye como Usuario/Asistente."
108
- )
109
  )
110
 
111
  if __name__ == "__main__":
 
1
  import os
 
2
  import gradio as gr
3
+ import requests
4
+ from huggingface_hub import InferenceClient
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
+ """
7
+ For more information on `huggingface_hub` Inference API support,
8
+ please check the docs:
9
+ https://huggingface.co/docs/huggingface_hub/v0.22.2/en/guides/inference
10
+ """
11
 
12
+ # ----------------------------------------------------------------
13
+ # CONFIGURACIÓN DE SERPER (búsqueda web)
14
+ # ----------------------------------------------------------------
15
+ SERPER_API_KEY = os.getenv("SERPER_API_KEY")
16
 
17
+ def do_websearch(query: str) -> str:
 
 
 
 
 
 
 
18
  """
19
+ Llama a serper.dev para hacer la búsqueda en Google y devolver
20
+ un texto resumido de los resultados.
 
 
 
21
  """
22
+ if not SERPER_API_KEY:
23
+ return "(SERPER_API_KEY no está configurado)"
24
 
25
+ url = "https://google.serper.dev/search"
26
+ headers = {
27
+ "X-API-KEY": SERPER_API_KEY,
28
+ "Content-Type": "application/json",
29
+ }
30
+ payload = {"q": query}
31
 
32
+ try:
33
+ resp = requests.post(url, json=payload, headers=headers, timeout=10)
34
+ data = resp.json()
35
+ except Exception as e:
36
+ return f"(Error al llamar a serper.dev: {e})"
37
 
38
+ # Se espera un campo 'organic' con resultados
39
+ if "organic" not in data:
40
+ return "No se encontraron resultados en serper.dev."
41
 
42
+ results = data["organic"]
43
+ if not results:
44
+ return "No hay resultados relevantes."
45
 
46
+ text = []
47
+ for i, item in enumerate(results, start=1):
48
+ title = item.get("title", "Sin título")
49
+ link = item.get("link", "Sin enlace")
50
+ text.append(f"{i}. {title}\n {link}")
51
 
52
+ return "\n".join(text)
 
53
 
 
 
 
 
 
 
 
 
 
 
54
 
55
+ # ----------------------------------------------------------------
56
+ # CONFIGURACIÓN DEL MODELO
57
+ # ----------------------------------------------------------------
58
+ client = InferenceClient("meta-llama/Llama-3.1-8B-Instruct")
 
 
59
 
60
+ def respond(
61
+ message,
62
+ history: list[tuple[str, str]],
63
+ system_message,
64
+ max_tokens,
65
+ temperature,
66
+ top_p,
67
+ use_search # <-- Nuevo parámetro: si está "activado" el botón
68
+ ):
69
+ """
70
+ - system_message: Texto del rol "system"
71
+ - history: lista de (user_msg, assistant_msg)
72
+ - message: Mensaje actual del usuario
73
+ - use_search: booleano que indica si se habilita la búsqueda en serper
74
+ """
75
 
76
+ # ----------------------------------------------------------------
77
+ # 1) Si el toggle está activo, hacemos búsqueda y la agregamos al prompt
78
+ # ----------------------------------------------------------------
79
+ if use_search:
80
+ web_info = do_websearch(message)
81
+ # Agregamos info al final del texto del usuario
82
+ message = f"{message}\nInformación de la web:\n{web_info}"
83
+
84
+ # ----------------------------------------------------------------
85
+ # 2) Construimos la lista de mensajes para la API de chat
86
+ # ----------------------------------------------------------------
87
+ messages = [{"role": "system", "content": system_message}]
88
+ for val in history:
89
+ if val[0]:
90
+ messages.append({"role": "user", "content": val[0]})
91
+ if val[1]:
92
+ messages.append({"role": "assistant", "content": val[1]})
93
+
94
+ # Añadimos el mensaje nuevo del usuario (posiblemente complementado con la info web)
95
+ messages.append({"role": "user", "content": message})
96
+
97
+ # ----------------------------------------------------------------
98
+ # 3) Llamamos a la API con streaming de tokens
99
+ # ----------------------------------------------------------------
100
+ response = ""
101
+ for chunk in client.chat_completion(
102
+ messages,
103
+ max_tokens=max_tokens,
104
+ stream=True,
105
+ temperature=temperature,
106
+ top_p=top_p,
107
+ ):
108
+ token = chunk.choices[0].delta.get("content", "")
109
+ response += token
110
+ yield response
111
+
112
+
113
+ # ----------------------------------------------------------------
114
+ # CONFIGURACIÓN DE LA INTERFAZ
115
+ # ----------------------------------------------------------------
116
+ # Para usar Tailwind, podemos asignar clases en "elem_classes".
117
+ # Ejemplo de clases genéricas (puedes cambiarlas a tu gusto):
118
+ tailwind_toggle_classes = [
119
+ "inline-flex",
120
+ "items-center",
121
+ "bg-blue-500",
122
+ "hover:bg-blue-700",
123
+ "text-white",
124
+ "font-bold",
125
+ "py-1",
126
+ "px-2",
127
+ "rounded",
128
+ "cursor-pointer"
129
+ ]
130
+
131
+ # ChatInterface, con un input Checkbox para "🌐 Búsqueda"
132
  demo = gr.ChatInterface(
133
  fn=respond,
134
  additional_inputs=[
 
135
  gr.Textbox(
136
+ value=(
137
+ "Eres Juan, un asistente virtual en español. "
138
+ "Debes responder con mucha paciencia y empatía a usuarios que "
139
+ "pueden tener dificultades cognitivas o escribir frases confusas. "
140
+ "Provee explicaciones simples, procura entender la intención del usuario "
141
+ "aunque la frase esté mal escrita, y mantén siempre un tono amable."
142
+ ),
143
+ label="Mensaje del sistema",
144
  ),
145
  gr.Slider(
146
+ minimum=1,
147
+ maximum=2048,
148
+ value=512,
149
+ step=1,
150
+ label="Máxima cantidad de tokens"
151
  ),
152
  gr.Slider(
153
+ minimum=0.1,
154
+ maximum=4.0,
155
+ value=0.7,
156
+ step=0.1,
157
+ label="Temperatura"
158
  ),
159
  gr.Slider(
160
+ minimum=0.1,
161
+ maximum=1.0,
162
+ value=0.95,
163
+ step=0.05,
164
+ label="Top-p (muestreo por núcleo)",
165
+ ),
166
+ # Un checkbox que hace de "toggle" para la búsqueda
167
+ gr.Checkbox(
168
+ value=False, # Por defecto desactivado
169
+ label="🌐 Búsqueda", # Etiqueta
170
+ elem_classes=tailwind_toggle_classes
171
  ),
172
  ],
 
 
 
 
 
 
173
  )
174
 
175
  if __name__ == "__main__":