CamiloVega commited on
Commit
ab6abb0
·
verified ·
1 Parent(s): c316edb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +80 -75
app.py CHANGED
@@ -6,7 +6,8 @@ import tempfile
6
  import pandas as pd
7
  import requests
8
  from bs4 import BeautifulSoup
9
- from transformers import pipeline, AutoModelForCausalLM, AutoTokenizer
 
10
  import torch
11
  import whisper
12
  from moviepy.editor import VideoFileClip
@@ -15,6 +16,7 @@ import fitz
15
  import docx
16
  import yt_dlp
17
  from functools import lru_cache
 
18
 
19
  # Configure logging
20
  logging.basicConfig(
@@ -44,7 +46,6 @@ class ModelManager:
44
  def initialize_models(self):
45
  """Initialize models with optimized settings"""
46
  try:
47
- # Get HuggingFace token
48
  HUGGINGFACE_TOKEN = os.environ.get('HUGGINGFACE_TOKEN')
49
  if not HUGGINGFACE_TOKEN:
50
  raise ValueError("HUGGINGFACE_TOKEN environment variable not set")
@@ -60,28 +61,45 @@ class ModelManager:
60
  use_fast=True,
61
  model_max_length=512
62
  )
63
- if self.tokenizer is None:
64
- raise RuntimeError("Failed to initialize tokenizer")
65
  self.tokenizer.pad_token = self.tokenizer.eos_token
66
 
67
- # Load model with optimized memory settings
68
- logger.info("Loading model...")
69
- self.model = AutoModelForCausalLM.from_pretrained(
70
- model_name,
71
  token=HUGGINGFACE_TOKEN,
72
- torch_dtype=torch.float16,
73
- device_map="auto",
74
- low_cpu_mem_usage=True,
75
- max_memory={0: "6GiB"},
76
- load_in_8bit=True
 
 
 
 
77
  )
78
- if self.model is None:
79
- raise RuntimeError("Failed to initialize model")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
 
81
- # Create pipeline with optimized settings
82
  logger.info("Creating pipeline...")
83
- self.news_generator = pipeline(
84
- "text-generation",
85
  model=self.model,
86
  tokenizer=self.tokenizer,
87
  device_map="auto",
@@ -94,18 +112,15 @@ class ModelManager:
94
  num_return_sequences=1,
95
  early_stopping=True
96
  )
97
- if self.news_generator is None:
98
- raise RuntimeError("Failed to initialize news generator pipeline")
99
 
100
  # Load Whisper model with optimized settings
101
  logger.info("Loading Whisper model...")
102
  self.whisper_model = whisper.load_model(
103
  "tiny",
104
  device="cuda",
105
- download_root="/tmp/whisper"
 
106
  )
107
- if self.whisper_model is None:
108
- raise RuntimeError("Failed to initialize Whisper model")
109
 
110
  logger.info("All models initialized successfully")
111
  return True
@@ -118,21 +133,31 @@ class ModelManager:
118
  def reset_models(self):
119
  """Reset all models and clear GPU memory"""
120
  try:
121
- del self.tokenizer
122
- del self.model
123
- del self.news_generator
124
- del self.whisper_model
 
 
 
 
 
 
 
 
 
125
 
126
  self.tokenizer = None
127
  self.model = None
128
  self.news_generator = None
129
  self.whisper_model = None
130
 
131
- # Clear CUDA cache
132
  if torch.cuda.is_available():
133
  torch.cuda.empty_cache()
134
  torch.cuda.synchronize()
135
 
 
 
136
  except Exception as e:
137
  logger.error(f"Error during model reset: {str(e)}")
138
 
@@ -150,12 +175,7 @@ class ModelManager:
150
  # Create global model manager instance
151
  model_manager = ModelManager()
152
 
153
- # Initialize models at startup
154
- try:
155
- model_manager.initialize_models()
156
- except Exception as e:
157
- logger.error(f"Initial model initialization failed: {str(e)}")
158
-
159
  def download_social_media_video(url):
160
  """Download a video from social media."""
161
  ydl_opts = {
@@ -206,7 +226,6 @@ def preprocess_audio(audio_file):
206
  def transcribe_audio(file):
207
  """Transcribe an audio or video file."""
208
  try:
209
- # Get initialized models
210
  _, _, _, whisper_model = model_manager.get_models()
211
 
212
  if isinstance(file, str) and file.startswith('http'):
@@ -232,6 +251,7 @@ def transcribe_audio(file):
232
  logger.error(f"Error transcribing: {str(e)}")
233
  return f"Error processing the file: {str(e)}"
234
 
 
235
  def read_document(document_path):
236
  """Read the content of a document."""
237
  try:
@@ -251,6 +271,7 @@ def read_document(document_path):
251
  logger.error(f"Error reading document: {str(e)}")
252
  return f"Error reading document: {str(e)}"
253
 
 
254
  def read_url(url):
255
  """Read the content of a URL."""
256
  try:
@@ -283,10 +304,8 @@ def process_social_content(url):
283
  @spaces.GPU(duration=120)
284
  def generate_news(instructions, facts, size, tone, *args):
285
  try:
286
- # Get initialized models
287
  tokenizer, _, news_generator, _ = model_manager.get_models()
288
 
289
- # Initialize knowledge base
290
  knowledge_base = {
291
  "instructions": instructions,
292
  "facts": facts,
@@ -296,7 +315,6 @@ def generate_news(instructions, facts, size, tone, *args):
296
  "social_content": []
297
  }
298
 
299
- # Parse arguments
300
  num_audios = 5 * 3
301
  num_social_urls = 3 * 3
302
  num_urls = 5
@@ -306,21 +324,18 @@ def generate_news(instructions, facts, size, tone, *args):
306
  urls = args[num_audios+num_social_urls:num_audios+num_social_urls+num_urls]
307
  documents = args[num_audios+num_social_urls+num_urls:]
308
 
309
- # Process URLs
310
  for url in urls:
311
  if url:
312
  content = read_url(url)
313
  if content and not content.startswith("Error"):
314
  knowledge_base["url_content"].append(content)
315
 
316
- # Process documents
317
  for document in documents:
318
  if document is not None:
319
  content = read_document(document.name)
320
  if content and not content.startswith("Error"):
321
  knowledge_base["document_content"].append(content)
322
 
323
- # Process audio files
324
  for i in range(0, len(audios), 3):
325
  audio_file, name, position = audios[i:i+3]
326
  if audio_file is not None:
@@ -330,7 +345,6 @@ def generate_news(instructions, facts, size, tone, *args):
330
  "position": position
331
  })
332
 
333
- # Process social media content
334
  for i in range(0, len(social_urls), 3):
335
  social_url, social_name, social_context = social_urls[i:i+3]
336
  if social_url:
@@ -344,7 +358,6 @@ def generate_news(instructions, facts, size, tone, *args):
344
  "video": social_content["video"]
345
  })
346
 
347
- # Build transcriptions
348
  transcriptions_text = ""
349
  raw_transcriptions = ""
350
 
@@ -367,7 +380,7 @@ def generate_news(instructions, facts, size, tone, *args):
367
  document_content = "\n\n".join(knowledge_base["document_content"])
368
  url_content = "\n\n".join(knowledge_base["url_content"])
369
 
370
- # Create prompt
371
  prompt = f"""[INST] You are a professional news writer. Write a news article based on the following information:
372
 
373
  Instructions: {knowledge_base["instructions"]}
@@ -394,40 +407,45 @@ Follow these requirements:
394
 
395
  # Generate article with optimized settings
396
  with torch.inference_mode():
397
- outputs = news_generator(
398
- prompt,
399
- max_new_tokens=max_tokens,
400
- num_return_sequences=1,
401
- do_sample=True,
402
- temperature=0.7,
403
- top_p=0.95,
404
- repetition_penalty=1.2,
405
- early_stopping=True,
406
- pad_token_id=tokenizer.eos_token_id
407
- )
408
-
409
- news_article = outputs[0]['generated_text']
410
- news_article = news_article.replace('[INST]', '').replace('[/INST]', '').strip()
 
 
 
 
 
 
411
 
412
  return news_article, raw_transcriptions
413
 
414
  except Exception as e:
415
  logger.error(f"Error generating news: {str(e)}")
416
  try:
 
417
  model_manager.reset_models()
418
  model_manager.initialize_models()
419
- logger.info("Models reinitialized successfully")
420
  except Exception as reinit_error:
421
  logger.error(f"Failed to reinitialize models: {str(reinit_error)}")
422
  return f"Error generating the news article: {str(e)}", ""
423
-
424
  def create_demo():
425
  with gr.Blocks() as demo:
426
  gr.Markdown("## Generador de noticias todo en uno")
427
 
428
- # Contenedor principal con dos columnas
429
  with gr.Row():
430
- # Columna izquierda - Formulario principal
431
  with gr.Column(scale=2):
432
  instrucciones = gr.Textbox(
433
  label="Instrucciones para la noticia",
@@ -447,14 +465,10 @@ def create_demo():
447
  value="neutral"
448
  )
449
 
450
- # Columna derecha - Tabs y campos
451
  with gr.Column(scale=3):
452
- # Lista de inputs que empezamos a construir
453
  inputs_list = [instrucciones, hechos, tamaño, tono]
454
 
455
- # Tabs en la parte superior
456
  with gr.Tabs():
457
- # Audio/Video tabs
458
  for i in range(1, 6):
459
  with gr.TabItem(f"Audio/Video {i}"):
460
  file = gr.File(
@@ -471,7 +485,6 @@ def create_demo():
471
  )
472
  inputs_list.extend([file, nombre, cargo])
473
 
474
- # Redes Sociales tabs
475
  for i in range(1, 4):
476
  with gr.TabItem(f"Red Social {i}"):
477
  social_url = gr.Textbox(
@@ -487,7 +500,6 @@ def create_demo():
487
  )
488
  inputs_list.extend([social_url, social_nombre, social_contexto])
489
 
490
- # URL tabs
491
  for i in range(1, 6):
492
  with gr.TabItem(f"URL {i}"):
493
  url = gr.Textbox(
@@ -496,7 +508,6 @@ def create_demo():
496
  )
497
  inputs_list.append(url)
498
 
499
- # Documento tabs
500
  for i in range(1, 6):
501
  with gr.TabItem(f"Documento {i}"):
502
  documento = gr.File(
@@ -506,10 +517,8 @@ def create_demo():
506
  )
507
  inputs_list.append(documento)
508
 
509
- # Separador
510
  gr.Markdown("---")
511
 
512
- # Transcripciones
513
  with gr.Row():
514
  transcripciones_output = gr.Textbox(
515
  label="Transcripciones",
@@ -517,10 +526,8 @@ def create_demo():
517
  show_copy_button=True
518
  )
519
 
520
- # Separador
521
  gr.Markdown("---")
522
 
523
- # Botón y output
524
  with gr.Row():
525
  generar = gr.Button("Generar borrador")
526
 
@@ -531,7 +538,6 @@ def create_demo():
531
  show_copy_button=True
532
  )
533
 
534
- # Event handler
535
  generar.click(
536
  fn=generate_news,
537
  inputs=inputs_list,
@@ -540,7 +546,6 @@ def create_demo():
540
 
541
  return demo
542
 
543
- # Launch the app
544
  if __name__ == "__main__":
545
  demo = create_demo()
546
  demo.queue()
 
6
  import pandas as pd
7
  import requests
8
  from bs4 import BeautifulSoup
9
+ from transformers import AutoTokenizer
10
+ from unsloth import FastLanguageModel
11
  import torch
12
  import whisper
13
  from moviepy.editor import VideoFileClip
 
16
  import docx
17
  import yt_dlp
18
  from functools import lru_cache
19
+ import gc
20
 
21
  # Configure logging
22
  logging.basicConfig(
 
46
  def initialize_models(self):
47
  """Initialize models with optimized settings"""
48
  try:
 
49
  HUGGINGFACE_TOKEN = os.environ.get('HUGGINGFACE_TOKEN')
50
  if not HUGGINGFACE_TOKEN:
51
  raise ValueError("HUGGINGFACE_TOKEN environment variable not set")
 
61
  use_fast=True,
62
  model_max_length=512
63
  )
 
 
64
  self.tokenizer.pad_token = self.tokenizer.eos_token
65
 
66
+ # Initialize model with Unsloth optimizations
67
+ logger.info("Loading model with Unsloth optimizations...")
68
+ model, tokenizer = FastLanguageModel.from_pretrained(
69
+ model_name=model_name,
70
  token=HUGGINGFACE_TOKEN,
71
+ max_seq_length=512,
72
+ dtype="float16",
73
+ load_in_4bit=True, # Use 4-bit quantization
74
+ device_map="auto", # Automatically handle device mapping
75
+ kwargs=dict(
76
+ use_gradient_checkpointing=True,
77
+ use_flash_attention_2=True,
78
+ use_merged_kernels=True,
79
+ )
80
  )
81
+
82
+ # Apply additional optimizations
83
+ model = FastLanguageModel.get_peft_model(
84
+ model,
85
+ r=16,
86
+ target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
87
+ modules_to_save=None,
88
+ lora_alpha=16,
89
+ lora_dropout=0.05,
90
+ bias="none",
91
+ use_gradient_checkpointing=True,
92
+ random_state=42,
93
+ use_rslora=False,
94
+ use_dora=False,
95
+ )
96
+
97
+ self.model = model
98
+ logger.info("Model loaded successfully with Unsloth optimizations")
99
 
100
+ # Create optimized pipeline
101
  logger.info("Creating pipeline...")
102
+ self.news_generator = FastLanguageModel.get_pipeline(
 
103
  model=self.model,
104
  tokenizer=self.tokenizer,
105
  device_map="auto",
 
112
  num_return_sequences=1,
113
  early_stopping=True
114
  )
 
 
115
 
116
  # Load Whisper model with optimized settings
117
  logger.info("Loading Whisper model...")
118
  self.whisper_model = whisper.load_model(
119
  "tiny",
120
  device="cuda",
121
+ download_root="/tmp/whisper",
122
+ in_memory=True
123
  )
 
 
124
 
125
  logger.info("All models initialized successfully")
126
  return True
 
133
  def reset_models(self):
134
  """Reset all models and clear GPU memory"""
135
  try:
136
+ if hasattr(self, 'model') and self.model is not None:
137
+ self.model.cpu()
138
+ del self.model
139
+
140
+ if hasattr(self, 'tokenizer') and self.tokenizer is not None:
141
+ del self.tokenizer
142
+
143
+ if hasattr(self, 'news_generator') and self.news_generator is not None:
144
+ del self.news_generator
145
+
146
+ if hasattr(self, 'whisper_model') and self.whisper_model is not None:
147
+ self.whisper_model.cpu()
148
+ del self.whisper_model
149
 
150
  self.tokenizer = None
151
  self.model = None
152
  self.news_generator = None
153
  self.whisper_model = None
154
 
 
155
  if torch.cuda.is_available():
156
  torch.cuda.empty_cache()
157
  torch.cuda.synchronize()
158
 
159
+ gc.collect()
160
+
161
  except Exception as e:
162
  logger.error(f"Error during model reset: {str(e)}")
163
 
 
175
  # Create global model manager instance
176
  model_manager = ModelManager()
177
 
178
+ @lru_cache(maxsize=32)
 
 
 
 
 
179
  def download_social_media_video(url):
180
  """Download a video from social media."""
181
  ydl_opts = {
 
226
  def transcribe_audio(file):
227
  """Transcribe an audio or video file."""
228
  try:
 
229
  _, _, _, whisper_model = model_manager.get_models()
230
 
231
  if isinstance(file, str) and file.startswith('http'):
 
251
  logger.error(f"Error transcribing: {str(e)}")
252
  return f"Error processing the file: {str(e)}"
253
 
254
+ @lru_cache(maxsize=32)
255
  def read_document(document_path):
256
  """Read the content of a document."""
257
  try:
 
271
  logger.error(f"Error reading document: {str(e)}")
272
  return f"Error reading document: {str(e)}"
273
 
274
+ @lru_cache(maxsize=32)
275
  def read_url(url):
276
  """Read the content of a URL."""
277
  try:
 
304
  @spaces.GPU(duration=120)
305
  def generate_news(instructions, facts, size, tone, *args):
306
  try:
 
307
  tokenizer, _, news_generator, _ = model_manager.get_models()
308
 
 
309
  knowledge_base = {
310
  "instructions": instructions,
311
  "facts": facts,
 
315
  "social_content": []
316
  }
317
 
 
318
  num_audios = 5 * 3
319
  num_social_urls = 3 * 3
320
  num_urls = 5
 
324
  urls = args[num_audios+num_social_urls:num_audios+num_social_urls+num_urls]
325
  documents = args[num_audios+num_social_urls+num_urls:]
326
 
 
327
  for url in urls:
328
  if url:
329
  content = read_url(url)
330
  if content and not content.startswith("Error"):
331
  knowledge_base["url_content"].append(content)
332
 
 
333
  for document in documents:
334
  if document is not None:
335
  content = read_document(document.name)
336
  if content and not content.startswith("Error"):
337
  knowledge_base["document_content"].append(content)
338
 
 
339
  for i in range(0, len(audios), 3):
340
  audio_file, name, position = audios[i:i+3]
341
  if audio_file is not None:
 
345
  "position": position
346
  })
347
 
 
348
  for i in range(0, len(social_urls), 3):
349
  social_url, social_name, social_context = social_urls[i:i+3]
350
  if social_url:
 
358
  "video": social_content["video"]
359
  })
360
 
 
361
  transcriptions_text = ""
362
  raw_transcriptions = ""
363
 
 
380
  document_content = "\n\n".join(knowledge_base["document_content"])
381
  url_content = "\n\n".join(knowledge_base["url_content"])
382
 
383
+
384
  prompt = f"""[INST] You are a professional news writer. Write a news article based on the following information:
385
 
386
  Instructions: {knowledge_base["instructions"]}
 
407
 
408
  # Generate article with optimized settings
409
  with torch.inference_mode():
410
+ try:
411
+ news_article = news_generator(
412
+ prompt,
413
+ max_new_tokens=max_tokens,
414
+ num_return_sequences=1,
415
+ do_sample=True,
416
+ temperature=0.7,
417
+ top_p=0.95,
418
+ repetition_penalty=1.2,
419
+ early_stopping=True
420
+ )
421
+
422
+ # Process the generated text
423
+ if isinstance(news_article, list):
424
+ news_article = news_article[0]['generated_text']
425
+ news_article = news_article.replace('[INST]', '').replace('[/INST]', '').strip()
426
+
427
+ except Exception as gen_error:
428
+ logger.error(f"Error in text generation: {str(gen_error)}")
429
+ raise
430
 
431
  return news_article, raw_transcriptions
432
 
433
  except Exception as e:
434
  logger.error(f"Error generating news: {str(e)}")
435
  try:
436
+ # Attempt to recover by resetting and reinitializing models
437
  model_manager.reset_models()
438
  model_manager.initialize_models()
439
+ logger.info("Models reinitialized successfully after error")
440
  except Exception as reinit_error:
441
  logger.error(f"Failed to reinitialize models: {str(reinit_error)}")
442
  return f"Error generating the news article: {str(e)}", ""
443
+
444
  def create_demo():
445
  with gr.Blocks() as demo:
446
  gr.Markdown("## Generador de noticias todo en uno")
447
 
 
448
  with gr.Row():
 
449
  with gr.Column(scale=2):
450
  instrucciones = gr.Textbox(
451
  label="Instrucciones para la noticia",
 
465
  value="neutral"
466
  )
467
 
 
468
  with gr.Column(scale=3):
 
469
  inputs_list = [instrucciones, hechos, tamaño, tono]
470
 
 
471
  with gr.Tabs():
 
472
  for i in range(1, 6):
473
  with gr.TabItem(f"Audio/Video {i}"):
474
  file = gr.File(
 
485
  )
486
  inputs_list.extend([file, nombre, cargo])
487
 
 
488
  for i in range(1, 4):
489
  with gr.TabItem(f"Red Social {i}"):
490
  social_url = gr.Textbox(
 
500
  )
501
  inputs_list.extend([social_url, social_nombre, social_contexto])
502
 
 
503
  for i in range(1, 6):
504
  with gr.TabItem(f"URL {i}"):
505
  url = gr.Textbox(
 
508
  )
509
  inputs_list.append(url)
510
 
 
511
  for i in range(1, 6):
512
  with gr.TabItem(f"Documento {i}"):
513
  documento = gr.File(
 
517
  )
518
  inputs_list.append(documento)
519
 
 
520
  gr.Markdown("---")
521
 
 
522
  with gr.Row():
523
  transcripciones_output = gr.Textbox(
524
  label="Transcripciones",
 
526
  show_copy_button=True
527
  )
528
 
 
529
  gr.Markdown("---")
530
 
 
531
  with gr.Row():
532
  generar = gr.Button("Generar borrador")
533
 
 
538
  show_copy_button=True
539
  )
540
 
 
541
  generar.click(
542
  fn=generate_news,
543
  inputs=inputs_list,
 
546
 
547
  return demo
548
 
 
549
  if __name__ == "__main__":
550
  demo = create_demo()
551
  demo.queue()