oriolgds commited on
Commit
d6aca47
·
unverified ·
1 Parent(s): 766694a

Revert "Some optimizations"

Browse files

This reverts commit 766694a1e0d3cd95cd563db918de82dad3f192dd.

Files changed (2) hide show
  1. app.py +67 -85
  2. script.py +208 -0
app.py CHANGED
@@ -2,117 +2,105 @@ import gradio as gr
2
  import transformers
3
  import torch
4
  import os
5
- import time # Para medir el tiempo
6
-
7
- # --- 0. Optimización de Hilos (Threads) ---
8
- # Los Spaces gratuitos de HF suelen tener 2 o 4 CPUs.
9
- # Forzamos a PyTorch a usar todos los núcleos disponibles
10
- # para operaciones que SÍ puede paralelizar (ej. matmul)
11
- try:
12
- cpu_count = os.cpu_count()
13
- torch.set_num_threads(cpu_count)
14
- print(f"INFO: Configurando PyTorch para usar {cpu_count} hilos.")
15
- except Exception as e:
16
- print(f"ADVERTENCIA: No se pudo configurar el número de hilos de PyTorch: {e}")
17
-
18
 
19
  # --- 1. Configuración del Modelo ---
20
 
21
  # Obtenemos el HF_TOKEN de los "Secrets" del Space.
 
22
  HF_TOKEN = os.environ.get("HF_TOKEN")
23
 
24
  if not HF_TOKEN:
25
  print("ADVERTENCIA: No se ha configurado el secret 'HF_TOKEN'.")
 
 
26
  # raise ValueError("Falta el HF_TOKEN. Configúralo en los secrets del Space.")
27
 
28
  # Cargamos el modelo Llama-3.2-1B-Instruct
 
29
  try:
30
- print("Iniciando carga del pipeline...")
31
- start_load = time.time()
32
  generator = transformers.pipeline(
33
  "text-generation",
34
  model="meta-llama/Llama-3.2-1B-Instruct",
35
- dtype=torch.bfloat16,
36
- device_map="auto", # En un Space de CPU, esto será "cpu"
37
- token=HF_TOKEN
38
  )
39
 
 
 
 
40
  if generator.tokenizer.pad_token_id is None:
41
  generator.tokenizer.pad_token_id = generator.tokenizer.eos_token_id
42
  print("INFO: pad_token_id no estaba configurado. Se ha establecido en eos_token_id.")
43
-
44
- end_load = time.time()
45
- print(f"Pipeline de Llama-3.2-1B cargado exitosamente en {end_load - start_load:.2f} segundos.")
46
  except Exception as e:
47
  print(f"Error cargando el pipeline: {e}")
48
- generator = None
 
49
 
50
- # --- 2. Lógica de Generación (Modificada para Batching) ---
51
 
52
- # Esta función ahora recibirá una LISTA de textos
53
- def generate_title(text_inputs_list):
54
  """
55
- Toma una LISTA de textos y genera un título para CADA uno.
56
  """
57
  if not generator:
58
- return ["Error: El modelo no pudo cargarse."] * len(text_inputs_list)
59
-
60
- print(f"Procesando un lote (batch) de {len(text_inputs_list)} peticiones.")
61
- start_gen = time.time()
62
 
63
- prompts = []
64
- for text_input in text_inputs_list:
65
- if not text_input or text_input.strip() == "":
66
- prompts.append(None) # Marcamos para saltar
67
- continue
68
-
69
- system_prompt = "Eres un experto en resumir textos en títulos cortos y llamativos. Te daré un texto o un historial de chat y tú generarás un título de entre 3 y 7 palabras. Responde SOLAMENTE con el título y nada más."
70
- user_prompt = f"Genera un título para el siguiente contenido:\n\n---\n{text_input}\n---"
71
- messages = [
72
- {"role": "system", "content": system_prompt},
73
- {"role": "user", "content": user_prompt},
74
- ]
75
- prompts.append(messages)
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  terminators_safe = list(set([
78
  generator.tokenizer.eos_token_id,
79
  13 # ID del token de nueva línea (\n)
80
  ]))
 
81
 
82
  try:
83
- # El pipeline maneja la lista de prompts automáticamente
84
- outputs_list = generator(
85
- prompts, # Pasamos la lista de prompts
86
- max_new_tokens=20,
87
- eos_token_id=terminators_safe,
88
- do_sample=False,
89
- temperature=None,
90
- top_p=None,
91
- pad_token_id=generator.tokenizer.eos_token_id
92
  )
93
 
94
- titles = []
95
- for i, outputs in enumerate(outputs_list):
96
- if prompts[i] is None:
97
- titles.append("Por favor, introduce un texto.")
98
- continue
99
-
100
- # Extraemos la respuesta del asistente
101
- title = outputs[0]["generated_text"][-1]["content"]
102
- title = title.strip().replace('"', '').replace("Título:", "").strip()
103
-
104
- if not title:
105
- titles.append("No se pudo generar un título.")
106
- else:
107
- titles.append(title)
108
 
109
- end_gen = time.time()
110
- print(f"Lote de {len(text_inputs_list)} procesado en {end_gen - start_gen:.2f} segundos.")
111
- return titles
 
 
 
 
112
 
113
  except Exception as e:
114
  print(f"Error durante la generación: {e}")
115
- return [f"Error al generar: {e}"] * len(text_inputs_list)
116
 
117
  # --- 3. Interfaz de Gradio ---
118
 
@@ -128,27 +116,22 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
128
  text_input = gr.Textbox(
129
  lines=15,
130
  label="Texto o Historial de Chat",
131
- placeholder="Pega tu contenido aquí..."
132
  )
133
  title_output = gr.Textbox(
134
  label="Título Generado",
135
- interactive=False
136
  )
137
 
138
  generate_btn = gr.Button("🚀 Generar Título", variant="primary")
139
 
140
- # --- Optimización de Batching ---
141
- # 1. fn: La función ahora espera una lista y devuelve una lista.
142
- # 2. batch=True: Le dice a Gradio que agrupe las peticiones.
143
- # 3. max_batch_size=4: Agrupa hasta 4 peticiones juntas.
144
- # Ajusta este número según la RAM de tu Space.
145
  generate_btn.click(
146
  fn=generate_title,
147
  inputs=text_input,
148
  outputs=title_output,
149
- api_name="generate_title",
150
- batch=True, # <-- Habilitar batching
151
- max_batch_size=4 # <-- Definir tamaño del lote
152
  )
153
 
154
  gr.Examples(
@@ -164,9 +147,8 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
164
  label="Ejemplos de Entrada"
165
  )
166
 
167
- # --- Optimización de Fila (Queue) ---
168
- # enable_queue=True es ESENCIAL para que el batching funcione.
169
- # Permite que Gradio ponga las peticiones en una fila mientras espera
170
- # a que se llene el lote (batch).
171
  if __name__ == "__main__":
172
- demo.queue().launch() # <-- Usamos .queue()
 
 
 
2
  import transformers
3
  import torch
4
  import os
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
  # --- 1. Configuración del Modelo ---
7
 
8
  # Obtenemos el HF_TOKEN de los "Secrets" del Space.
9
+ # ¡NUNCA escribas tu token directamente en el código!
10
  HF_TOKEN = os.environ.get("HF_TOKEN")
11
 
12
  if not HF_TOKEN:
13
  print("ADVERTENCIA: No se ha configurado el secret 'HF_TOKEN'.")
14
+ # Si no hay token, la app puede fallar al cargar el modelo gated.
15
+ # Para pruebas locales, puedes crear un archivo .env o setear la variable.
16
  # raise ValueError("Falta el HF_TOKEN. Configúralo en los secrets del Space.")
17
 
18
  # Cargamos el modelo Llama-3.2-1B-Instruct
19
+ # Usamos un pipeline para facilitar la generación de texto
20
  try:
 
 
21
  generator = transformers.pipeline(
22
  "text-generation",
23
  model="meta-llama/Llama-3.2-1B-Instruct",
24
+ dtype=torch.bfloat16, # Optimización para velocidad y memoria (reemplaza a torch_dtype)
25
+ device_map="auto", # Usa GPU si está disponible
26
+ token=HF_TOKEN # Token para acceder al modelo gated
27
  )
28
 
29
+ # --- INICIO DE LA CORRECCIÓN ---
30
+ # CORRECCIÓN 1: Asegurarse de que pad_token_id esté configurado
31
+ # Algunos modelos no tienen un pad_token_id por defecto, lo que causa el error 'NoneType'
32
  if generator.tokenizer.pad_token_id is None:
33
  generator.tokenizer.pad_token_id = generator.tokenizer.eos_token_id
34
  print("INFO: pad_token_id no estaba configurado. Se ha establecido en eos_token_id.")
35
+ # --- FIN DE LA CORRECCIÓN ---
36
+
37
+ print("Pipeline de Llama-3.2-1B cargado exitosamente.")
38
  except Exception as e:
39
  print(f"Error cargando el pipeline: {e}")
40
+ # Si falla aquí, probablemente es por el token o falta de acceso.
41
+ generator = None # Marcamos que falló
42
 
43
+ # --- 2. Lógica de Generación ---
44
 
45
+ def generate_title(text_input):
 
46
  """
47
+ Toma un texto (o historial) y genera un título conciso.
48
  """
49
  if not generator:
50
+ return "Error: El modelo no pudo cargarse. ¿Configuraste el HF_TOKEN y tienes acceso a meta-llama/Llama-3.2-1B-Instruct?"
 
 
 
51
 
52
+ if not text_input or text_input.strip() == "":
53
+ return "Por favor, introduce un texto."
 
 
 
 
 
 
 
 
 
 
 
54
 
55
+ # Prompt engineering: Damos instrucciones claras al modelo.
56
+ # Llama 3.2 usa un formato de chat específico.
57
+ system_prompt = "Eres un experto en resumir textos en títulos cortos y llamativos. Te daré un texto o un historial de chat y tú generarás un título de entre 3 y 7 palabras. Responde SOLAMENTE con el título y nada más."
58
+
59
+ user_prompt = f"Genera un título para el siguiente contenido:\n\n---\n{text_input}\n---"
60
+
61
+ messages = [
62
+ {"role": "system", "content": system_prompt},
63
+ {"role": "user", "content": user_prompt},
64
+ ]
65
+
66
+ # --- INICIO DE LA CORRECCIÓN ---
67
+ # CORRECCIÓN 2: Lista de terminadores robusta
68
+ # El ID para "\n" (nueva línea) en Llama 3 es 13.
69
+ # generator.tokenizer.eos_token_id es el ID de <|eot_id|>
70
+ # Usamos una lista explícita de enteros para evitar 'None'.
71
  terminators_safe = list(set([
72
  generator.tokenizer.eos_token_id,
73
  13 # ID del token de nueva línea (\n)
74
  ]))
75
+ # --- FIN DE LA CORRECCIÓN ---
76
 
77
  try:
78
+ outputs = generator(
79
+ messages,
80
+ max_new_tokens=20, # Un título no necesita más de 20 tokens
81
+ eos_token_id=terminators_safe, # Usamos la lista corregida
82
+ do_sample=False, # Queremos la respuesta más probable, no creativa
83
+ temperature=None, # No necesario si do_sample=False
84
+ top_p=None, # No necesario si do_sample=False
85
+ pad_token_id=generator.tokenizer.eos_token_id # Ahora es seguro usar esto
 
86
  )
87
 
88
+ # Extraemos la respuesta del asistente
89
+ # La estructura es: outputs[0]["generated_text"] es una *lista* de mensajes
90
+ # El último mensaje [-1] es el del asistente
91
+ title = outputs[0]["generated_text"][-1]["content"]
 
 
 
 
 
 
 
 
 
 
92
 
93
+ # Limpiamos el título (quitar espacios, comillas, etc.)
94
+ title = title.strip().replace('"', '').replace("Título:", "").strip()
95
+
96
+ if not title:
97
+ return "No se pudo generar un título."
98
+
99
+ return title
100
 
101
  except Exception as e:
102
  print(f"Error durante la generación: {e}")
103
+ return f"Error al generar: {e}"
104
 
105
  # --- 3. Interfaz de Gradio ---
106
 
 
116
  text_input = gr.Textbox(
117
  lines=15,
118
  label="Texto o Historial de Chat",
119
+ placeholder="Pega tu contenido aquí. Por ejemplo:\n\nUser: ¿Qué es la IA?\nAssistant: La IA es...\nUser: ¿Y el machine learning?\n\nO simplemente pega un artículo largo."
120
  )
121
  title_output = gr.Textbox(
122
  label="Título Generado",
123
+ interactive=False # El usuario no puede editar esto
124
  )
125
 
126
  generate_btn = gr.Button("🚀 Generar Título", variant="primary")
127
 
128
+ # Conectamos el botón a la función
129
+ # api_name="generate_title" habilita el endpoint /api/generate_title
 
 
 
130
  generate_btn.click(
131
  fn=generate_title,
132
  inputs=text_input,
133
  outputs=title_output,
134
+ api_name="generate_title"
 
 
135
  )
136
 
137
  gr.Examples(
 
147
  label="Ejemplos de Entrada"
148
  )
149
 
150
+ # Lanzamos la aplicación
 
 
 
151
  if __name__ == "__main__":
152
+ demo.launch()
153
+
154
+
script.py ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ # Crear el código completo para un espacio de Hugging Face que genera títulos
3
+ # usando Llama-3.2-1B-Instruct con interfaz Gradio y API
4
+
5
+ app_code = '''import gradio as gr
6
+ import os
7
+ from huggingface_hub import InferenceClient
8
+
9
+ # Obtener el token de HF desde los secrets
10
+ HF_TOKEN = os.environ.get("HF_TOKEN")
11
+
12
+ # Inicializar el cliente de inferencia con el modelo Llama
13
+ client = InferenceClient(
14
+ model="meta-llama/Llama-3.2-1B-Instruct",
15
+ token=HF_TOKEN
16
+ )
17
+
18
+ def generate_title(text_or_history, max_length=50):
19
+ """
20
+ Genera un título a partir de texto o historial de conversación
21
+
22
+ Args:
23
+ text_or_history: Puede ser texto simple o una lista de mensajes
24
+ max_length: Longitud máxima del título
25
+
26
+ Returns:
27
+ El título generado
28
+ """
29
+ try:
30
+ # Si es una lista (historial), convertirla a texto
31
+ if isinstance(text_or_history, list):
32
+ # Formatear el historial como conversación
33
+ conversation_text = "\\n".join([
34
+ f"{msg.get('role', 'user')}: {msg.get('content', '')}"
35
+ for msg in text_or_history
36
+ ])
37
+ else:
38
+ conversation_text = str(text_or_history)
39
+
40
+ # Crear el prompt para generar título
41
+ prompt = f"""Based on the following conversation or text, generate a short, concise title (maximum 10 words):
42
+
43
+ {conversation_text}
44
+
45
+ Title:"""
46
+
47
+ # Generar el título usando el modelo
48
+ messages = [
49
+ {"role": "user", "content": prompt}
50
+ ]
51
+
52
+ response = ""
53
+ for message in client.chat_completion(
54
+ messages=messages,
55
+ max_tokens=max_length,
56
+ temperature=0.7,
57
+ stream=True
58
+ ):
59
+ token = message.choices[0].delta.content
60
+ if token:
61
+ response += token
62
+
63
+ # Limpiar el título (quitar saltos de línea extra, etc.)
64
+ title = response.strip().split("\\n")[0]
65
+
66
+ return title
67
+
68
+ except Exception as e:
69
+ return f"Error: {str(e)}"
70
+
71
+ # Crear la interfaz de Gradio
72
+ with gr.Blocks(title="Title Generator with Llama 3.2") as demo:
73
+ gr.Markdown("# 📝 AI Title Generator")
74
+ gr.Markdown("Generate concise titles from text or conversation history using Llama 3.2-1B-Instruct")
75
+
76
+ with gr.Tab("Text Input"):
77
+ text_input = gr.Textbox(
78
+ label="Enter your text",
79
+ placeholder="Paste your text or conversation here...",
80
+ lines=10
81
+ )
82
+ text_button = gr.Button("Generate Title", variant="primary")
83
+ text_output = gr.Textbox(label="Generated Title", lines=2)
84
+
85
+ text_button.click(
86
+ fn=generate_title,
87
+ inputs=[text_input],
88
+ outputs=[text_output]
89
+ )
90
+
91
+ with gr.Tab("History/List Input"):
92
+ gr.Markdown("Enter conversation history as JSON format:")
93
+ gr.Markdown('Example: `[{"role": "user", "content": "Hello"}, {"role": "assistant", "content": "Hi there!"}]`')
94
+
95
+ history_input = gr.Textbox(
96
+ label="Conversation History (JSON)",
97
+ placeholder='[{"role": "user", "content": "Your message here"}]',
98
+ lines=10
99
+ )
100
+ history_button = gr.Button("Generate Title", variant="primary")
101
+ history_output = gr.Textbox(label="Generated Title", lines=2)
102
+
103
+ def process_history(history_json):
104
+ try:
105
+ import json
106
+ history_list = json.loads(history_json)
107
+ return generate_title(history_list)
108
+ except json.JSONDecodeError:
109
+ return "Error: Invalid JSON format"
110
+
111
+ history_button.click(
112
+ fn=process_history,
113
+ inputs=[history_input],
114
+ outputs=[history_output]
115
+ )
116
+
117
+ gr.Markdown("---")
118
+ gr.Markdown("### API Usage")
119
+ gr.Markdown("""
120
+ You can use this API with CURL:
121
+
122
+ ```bash
123
+ curl -X POST "https://YOUR-SPACE-URL/call/generate_title" \\
124
+ -H "Content-Type: application/json" \\
125
+ -d '{"data": ["Your text here"]}'
126
+ ```
127
+ """)
128
+
129
+ # Lanzar la aplicación con API habilitada
130
+ if __name__ == "__main__":
131
+ demo.launch(show_api=True)
132
+ '''
133
+
134
+ # Guardar el código en un archivo
135
+ with open('app.py', 'w', encoding='utf-8') as f:
136
+ f.write(app_code)
137
+
138
+ # Crear el archivo requirements.txt
139
+ requirements = '''gradio>=4.0.0
140
+ huggingface_hub>=0.19.0
141
+ '''
142
+
143
+ with open('requirements.txt', 'w', encoding='utf-8') as f:
144
+ f.write(requirements)
145
+
146
+ # Crear el README con instrucciones
147
+ readme = '''---
148
+ title: Title Generator with Llama 3.2
149
+ emoji: 📝
150
+ colorFrom: blue
151
+ colorTo: purple
152
+ sdk: gradio
153
+ sdk_version: 4.44.0
154
+ app_file: app.py
155
+ pinned: false
156
+ license: mit
157
+ ---
158
+
159
+ # Title Generator with Llama 3.2-1B-Instruct
160
+
161
+ Generate concise titles from text or conversation history using Meta's Llama 3.2-1B-Instruct model.
162
+
163
+ ## Features
164
+
165
+ - 📝 Generate titles from plain text
166
+ - 💬 Generate titles from conversation history
167
+ - 🚀 Fast inference with Llama 3.2-1B
168
+ - 🔌 RESTful API support for integration
169
+
170
+ ## Setup
171
+
172
+ 1. Go to your Space settings
173
+ 2. Add a new secret: `HF_TOKEN` with your Hugging Face token
174
+ 3. Make sure you have access to `meta-llama/Llama-3.2-1B-Instruct` (accept the gated model)
175
+
176
+ ## API Usage
177
+
178
+ ### CURL Example
179
+
180
+ ```bash
181
+ curl -X POST "https://YOUR-SPACE-URL/call/generate_title" \\
182
+ -H "Content-Type: application/json" \\
183
+ -d '{"data": ["Your text or conversation here"]}'
184
+ ```
185
+
186
+ ### Python Example
187
+
188
+ ```python
189
+ from gradio_client import Client
190
+
191
+ client = Client("YOUR-SPACE-URL")
192
+ result = client.predict("Your text here", api_name="/generate_title")
193
+ print(result)
194
+ ```
195
+
196
+ ## License
197
+
198
+ MIT License
199
+ '''
200
+
201
+ with open('README.md', 'w', encoding='utf-8') as f:
202
+ f.write(readme)
203
+
204
+ print("✅ Archivos generados exitosamente:")
205
+ print("- app.py")
206
+ print("- requirements.txt")
207
+ print("- README.md")
208
+ print("\n📦 Archivos listos para subir a Hugging Face Space")