MinAA commited on
Commit
3228848
·
1 Parent(s): 05f7dda
Files changed (1) hide show
  1. app.py +159 -13
app.py CHANGED
@@ -302,11 +302,28 @@ def audio_zero_shot_classifier(audio, candidate_labels, model_name):
302
  labels = [label.strip() for label in candidate_labels.split(",")]
303
  result = classifier(audio, candidate_labels=labels)
304
  output = "Результаты классификации:\n"
305
- for label, score in zip(result['labels'], result['scores']):
306
- output += f"{label}: {score:.4f}\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
307
  return output
308
  except Exception as e:
309
- return f"Ошибка: {str(e)}"
 
 
 
310
 
311
  @measure_time_and_save("Распознавание речи")
312
  def speech_recognition(audio, model_name):
@@ -331,7 +348,57 @@ def speech_synthesis(text, model_name):
331
  if not text or not text.strip():
332
  raise ValueError("Текст для синтеза не может быть пустым")
333
 
334
- # Используем стандартный pipeline
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
335
  tts = get_pipeline("text-to-speech", model_name)
336
  result = tts(text)
337
 
@@ -389,9 +456,18 @@ def speech_synthesis(text, model_name):
389
 
390
  return (sample_rate, audio_data)
391
  else:
392
- raise ValueError(f"Неожиданный формат результата от pipeline: {type(result)}")
393
  except Exception as e:
394
- raise Exception(f"Ошибка синтеза речи: {str(e)}")
 
 
 
 
 
 
 
 
 
395
 
396
  # ==================== ЗАДАЧИ С ИЗОБРАЖЕНИЯМИ ====================
397
 
@@ -696,15 +772,85 @@ def visual_qa(image, question, model_name):
696
  def image_zero_shot_classification(image, candidate_labels, model_name):
697
  """Zero-shot классификация изображений"""
698
  try:
699
- classifier = get_pipeline("zero-shot-image-classification", model_name)
700
  labels = [label.strip() for label in candidate_labels.split(",")]
701
- result = classifier(image, candidate_labels=labels)
702
- output = "Результаты классификации:\n"
703
- for label, score in zip(result['labels'], result['scores']):
704
- output += f"{label}: {score:.4f}\n"
705
- return output
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
706
  except Exception as e:
707
- return f"Ошибка: {str(e)}"
 
 
 
 
 
 
 
708
 
709
  # ==================== ФУНКЦИИ ДЛЯ ИСТОРИИ ====================
710
 
 
302
  labels = [label.strip() for label in candidate_labels.split(",")]
303
  result = classifier(audio, candidate_labels=labels)
304
  output = "Результаты классификации:\n"
305
+
306
+ # Обрабатываем разные форматы результатов
307
+ if isinstance(result, dict) and 'labels' in result and 'scores' in result:
308
+ # Формат: {'labels': [...], 'scores': [...]}
309
+ for label, score in zip(result['labels'], result['scores']):
310
+ output += f"{label}: {score:.4f}\n"
311
+ elif isinstance(result, list):
312
+ # Формат: [{'label': '...', 'score': ...}, ...]
313
+ for item in result:
314
+ if isinstance(item, dict):
315
+ label = item.get('label', '')
316
+ score = item.get('score', 0.0)
317
+ output += f"{label}: {score:.4f}\n"
318
+ else:
319
+ return f"Ошибка: Неожиданный формат результата от pipeline: {type(result)}. Ожидался словарь с ключами 'labels' и 'scores' или список словарей."
320
+
321
  return output
322
  except Exception as e:
323
+ error_msg = str(e)
324
+ if "Could not load model" in error_msg or "Unrecognized" in error_msg:
325
+ return f"Ошибка: Модель '{model_name}' не поддерживается для zero-shot классификации аудио. Попробуйте другую модель, например 'laion/clap-htsat-unfused'."
326
+ return f"Ошибка: {error_msg}"
327
 
328
  @measure_time_and_save("Распознавание речи")
329
  def speech_recognition(audio, model_name):
 
348
  if not text or not text.strip():
349
  raise ValueError("Текст для синтеза не может быть пустым")
350
 
351
+ # Проверяем, является ли модель SpeechT5
352
+ if "speecht5" in model_name.lower():
353
+ try:
354
+ # Для SpeechT5 нужны speaker_embeddings
355
+ from transformers import SpeechT5Processor, SpeechT5ForTextToSpeech, SpeechT5HifiGan
356
+
357
+ cache_key = f"tts_speecht5_{model_name}"
358
+ cached = model_cache.get(cache_key)
359
+ if cached is None:
360
+ processor = SpeechT5Processor.from_pretrained(model_name)
361
+ model = SpeechT5ForTextToSpeech.from_pretrained(model_name)
362
+ vocoder = SpeechT5HifiGan.from_pretrained("microsoft/speecht5_hifigan")
363
+
364
+ # Генерируем speaker embeddings используя модель напрямую
365
+ # Используем размерность speaker embeddings из конфигурации модели
366
+ speaker_embedding_dim = model.config.speaker_embedding_dim
367
+ # Создаем случайный speaker embedding (можно заменить на предобученный)
368
+ # Для более стабильного результата используем нормализованный случайный вектор
369
+ speaker_embeddings = torch.randn(1, speaker_embedding_dim)
370
+ speaker_embeddings = speaker_embeddings / torch.norm(speaker_embeddings, dim=1, keepdim=True)
371
+
372
+ cached = (processor, model, vocoder, speaker_embeddings)
373
+ model_cache.put(cache_key, cached)
374
+
375
+ processor, model, vocoder, speaker_embeddings = cached
376
+ inputs = processor(text=text, return_tensors="pt")
377
+ with torch.no_grad():
378
+ speech = model.generate_speech(inputs["input_ids"], speaker_embeddings, vocoder=vocoder)
379
+
380
+ # Конвертируем в numpy и нормализуем
381
+ audio_data = speech.numpy()
382
+ # Убеждаемся, что это 1D массив
383
+ if len(audio_data.shape) > 1:
384
+ audio_data = audio_data.flatten()
385
+ # Нормализуем в диапазон [-1, 1] если нужно
386
+ if audio_data.dtype != np.float32:
387
+ audio_data = audio_data.astype(np.float32)
388
+ # Нормализуем если значения выходят за пределы [-1, 1]
389
+ max_val = np.abs(audio_data).max()
390
+ if max_val > 1.0:
391
+ audio_data = audio_data / max_val
392
+
393
+ sample_rate = 16000
394
+ return (sample_rate, audio_data)
395
+ except Exception as e:
396
+ error_msg = str(e)
397
+ if "ImportError" in str(type(e)) or "ModuleNotFoundError" in str(type(e)):
398
+ raise Exception(f"Ошибка: Не удалось импортировать необходимые модули для SpeechT5. Убедитесь, что transformers установлен: {error_msg}")
399
+ raise Exception(f"Ошибка синтеза речи с SpeechT5: {error_msg}")
400
+
401
+ # Используем стандартный pipeline для других моделей
402
  tts = get_pipeline("text-to-speech", model_name)
403
  result = tts(text)
404
 
 
456
 
457
  return (sample_rate, audio_data)
458
  else:
459
+ raise ValueError(f"Неожиданный формат результата от pipeline: {type(result)}. Ожидался словарь с ключами 'audio' и 'sampling_rate' или кортеж (sample_rate, audio_data).")
460
  except Exception as e:
461
+ error_msg = str(e)
462
+ if "speaker_embeddings" in error_msg.lower():
463
+ if "speecht5" in model_name.lower():
464
+ return f"Ошибка: Модель SpeechT5 требует speaker_embeddings. Они должны генерироваться автоматически, но произошла ошибка: {error_msg}"
465
+ return f"Ошибка: Модель '{model_name}' требует speaker_embeddings. Для SpeechT5 они генерируются автоматически, но для других моделей может потребоваться дополнительная настройка."
466
+ if "does not appear to have a file named" in error_msg or "Unrecognized model" in error_msg:
467
+ return f"Ошибка: Модель '{model_name}' не поддерживается библиотекой transformers для синтеза речи. Попробуйте использовать модель 'microsoft/speecht5_tts'."
468
+ if "negative output size" in error_msg.lower() or "input size 0" in error_msg.lower():
469
+ return f"Ошибка: Проблема с обработкой текста моделью '{model_name}'. Возможные причины: неподдерживаемый язык, пустой текст после обработки, или проблема с токенизацией. Попробуйте использовать другой текст или модель."
470
+ raise Exception(f"Ошибка синтеза речи: {error_msg}")
471
 
472
  # ==================== ЗАДАЧИ С ИЗОБРАЖЕНИЯМИ ====================
473
 
 
772
  def image_zero_shot_classification(image, candidate_labels, model_name):
773
  """Zero-shot классификация изображений"""
774
  try:
 
775
  labels = [label.strip() for label in candidate_labels.split(",")]
776
+
777
+ # Проверяем, является ли модель LAION
778
+ if "laion/" in model_name.lower() or "laion5b" in model_name.lower():
779
+ # Используем OpenCLIP для LAION моделей
780
+ import open_clip
781
+
782
+ cache_key = f"clip_laion_{model_name}"
783
+ cached = model_cache.get(cache_key)
784
+ if cached is None:
785
+ # Определяем имя модели и веса для OpenCLIP
786
+ if "xlm-roberta-base-ViT-B-32" in model_name or "xlm-roberta-base" in model_name:
787
+ clip_model_name = "xlm-roberta-base-ViT-B-32"
788
+ pretrained = "laion5b_s13b_b90k"
789
+ else:
790
+ # Пытаемся извлечь информацию из имени модели
791
+ clip_model_name = "xlm-roberta-base-ViT-B-32"
792
+ pretrained = "laion5b_s13b_b90k"
793
+
794
+ model, _, preprocess = open_clip.create_model_and_transforms(
795
+ clip_model_name,
796
+ pretrained=pretrained
797
+ )
798
+ tokenizer = open_clip.get_tokenizer(clip_model_name)
799
+ model.eval()
800
+ cached = (model, preprocess, tokenizer)
801
+ model_cache.put(cache_key, cached)
802
+
803
+ model, preprocess, tokenizer = cached
804
+
805
+ # Обрабатываем изображение и тексты
806
+ image_tensor = preprocess(image).unsqueeze(0)
807
+ text_tokens = tokenizer(labels)
808
+
809
+ with torch.no_grad():
810
+ image_features = model.encode_image(image_tensor)
811
+ text_features = model.encode_text(text_tokens)
812
+ # Нормализуем признаки
813
+ image_features = image_features / image_features.norm(dim=-1, keepdim=True)
814
+ text_features = text_features / text_features.norm(dim=-1, keepdim=True)
815
+ # Вычисляем косинусное сходство (логиты)
816
+ logits_per_image = (image_features @ text_features.T) * 100 # Масштабируем для лучшей точности
817
+ probs = logits_per_image.softmax(dim=1)
818
+
819
+ output = "Результаты классификации:\n"
820
+ for label, prob in zip(labels, probs[0]):
821
+ output += f"{label}: {prob.item():.4f}\n"
822
+ return output
823
+ else:
824
+ # Используем стандартный pipeline
825
+ classifier = get_pipeline("zero-shot-image-classification", model_name)
826
+ result = classifier(image, candidate_labels=labels)
827
+ output = "Результаты классификации:\n"
828
+
829
+ # Обрабатываем разные форматы результатов
830
+ if isinstance(result, dict) and 'labels' in result and 'scores' in result:
831
+ # Формат: {'labels': [...], 'scores': [...]}
832
+ for label, score in zip(result['labels'], result['scores']):
833
+ output += f"{label}: {score:.4f}\n"
834
+ elif isinstance(result, list):
835
+ # Формат: [{'label': '...', 'score': ...}, ...]
836
+ for item in result:
837
+ if isinstance(item, dict):
838
+ label = item.get('label', '')
839
+ score = item.get('score', 0.0)
840
+ output += f"{label}: {score:.4f}\n"
841
+ else:
842
+ return f"Ошибка: Неожиданный формат результата от pipeline: {type(result)}. Ожидался словарь с ключами 'labels' и 'scores' или список словарей."
843
+
844
+ return output
845
  except Exception as e:
846
+ error_msg = str(e)
847
+ if "Could not load model" in error_msg or "Unrecognized" in error_msg:
848
+ if "laion" in model_name.lower():
849
+ return f"Ошибка: Модель '{model_name}' требует библиотеку open-clip-torch. Убедитесь, что она установлена: pip install open-clip-torch"
850
+ return f"Ошибка: Модель '{model_name}' не поддерживается для zero-shot классификации изображений. Попробуйте другую модель, например 'openai/clip-vit-base-patch32'."
851
+ if "open_clip" in error_msg or "open-clip" in error_msg:
852
+ return f"Ошибка: Для работы с LAION моделями требуется библиотека open-clip-torch. Установите её: pip install open-clip-torch"
853
+ return f"Ошибка: {error_msg}"
854
 
855
  # ==================== ФУНКЦИИ ДЛЯ ИСТОРИИ ====================
856