MinAA commited on
Commit
99831c1
·
1 Parent(s): b8580c5
Files changed (1) hide show
  1. app.py +92 -398
app.py CHANGED
@@ -1,13 +1,6 @@
1
  import gradio as gr
2
- from transformers import (
3
- pipeline,
4
- BlipProcessor, BlipForConditionalGeneration, BlipForImageTextRetrieval,
5
- CLIPProcessor, CLIPModel, ViltProcessor, ViltForQuestionAnswering,
6
- AutoProcessor
7
- )
8
  import torch
9
- from torch.nn.functional import cosine_similarity
10
- import torch.nn.functional as F
11
  from PIL import Image, ImageDraw, ImageFont
12
  import numpy as np
13
  import functools
@@ -305,149 +298,29 @@ def audio_classifier(audio, model_name):
305
  def audio_zero_shot_classifier(audio, candidate_labels, model_name):
306
  """Zero-shot классификация аудио"""
307
  try:
308
- import soundfile as sf
309
- import numpy as np
310
-
311
  labels = [label.strip() for label in candidate_labels.split(",")]
 
 
312
 
313
- # Загружаем аудио файл, если передан путь
314
- if isinstance(audio, str):
315
- # audio - это путь к файлу
316
- audio_data, sample_rate = sf.read(audio)
317
- elif isinstance(audio, tuple):
318
- # audio - это кортеж (sample_rate, audio_data) от Gradio
319
- sample_rate, audio_data = audio
320
- else:
321
- # audio уже является массивом numpy
322
- audio_data = audio
323
- sample_rate = None
324
-
325
- # Преобразуем в numpy array, если нужно
326
- if not isinstance(audio_data, np.ndarray):
327
- audio_data = np.array(audio_data)
328
-
329
- # Если аудио моно, убеждаемся что это 1D массив
330
- if len(audio_data.shape) > 1:
331
- audio_data = audio_data[:, 0] if audio_data.shape[1] > 0 else audio_data.flatten()
332
 
333
- # Проверяем тип модели
334
- if "clap" in model_name.lower():
335
- # Используем CLAP для zero-shot классификации аудио
336
- from transformers import ClapProcessor, ClapModel
337
-
338
- cache_key = f"audio_zero_shot_{model_name}"
339
- cached = model_cache.get(cache_key)
340
- if cached is None:
341
- processor = ClapProcessor.from_pretrained(model_name)
342
- model = ClapModel.from_pretrained(model_name)
343
- cached = (processor, model)
344
- model_cache.put(cache_key, cached)
345
-
346
- processor, model = cached
347
- inputs = processor(text=labels, audios=audio_data, return_tensors="pt", padding=True)
348
- with torch.no_grad():
349
- outputs = model(**inputs)
350
- logits_per_audio = outputs.logits_per_audio
351
- probs = logits_per_audio.softmax(dim=1)
352
-
353
- output = "Результаты классификации:\n"
354
- for label, prob in zip(labels, probs[0]):
355
- output += f"{label}: {prob.item():.4f}\n"
356
- return output
357
- elif "wav2vec2" in model_name.lower() or "hubert" in model_name.lower():
358
- # Используем подход с audio embeddings + text embeddings
359
- # Получаем аудио эмбеддинги через audio model и текстовые эмбеддинги через text model
360
- from transformers import AutoProcessor, AutoModel
361
- from sentence_transformers import SentenceTransformer
362
- import librosa
363
-
364
- cache_key = f"audio_zero_shot_{model_name}"
365
- cached = model_cache.get(cache_key)
366
- if cached is None:
367
- # Загружаем модель для аудио эмбеддингов
368
- audio_processor = AutoProcessor.from_pretrained(model_name)
369
- audio_model = AutoModel.from_pretrained(model_name)
370
- # Загружаем модель для текстовых эмбеддингов с размерностью 768
371
- # Используем модель с размерностью 768 для совместимости с Wav2Vec2
372
- text_model = SentenceTransformer('all-mpnet-base-v2')
373
- cached = (audio_processor, audio_model, text_model)
374
- model_cache.put(cache_key, cached)
375
-
376
- audio_processor, audio_model, text_model = cached
377
-
378
- # Получаем аудио эмбеддинги
379
- # Ресемплируем до 16000 Гц если нужно (Wav2Vec2 требует 16000 Гц)
380
- target_sample_rate = 16000
381
- if sample_rate is None:
382
- sample_rate = target_sample_rate
383
- elif sample_rate != target_sample_rate:
384
- # Ресемплируем аудио до нужной частоты дискретизации
385
- audio_data = librosa.resample(audio_data, orig_sr=sample_rate, target_sr=target_sample_rate)
386
- sample_rate = target_sample_rate
387
-
388
- inputs = audio_processor(audio_data, sampling_rate=sample_rate, return_tensors="pt")
389
- with torch.no_grad():
390
- audio_outputs = audio_model(**inputs)
391
- # Используем последний скрытый слой как эмбеддинг
392
- if hasattr(audio_outputs, 'last_hidden_state'):
393
- audio_embedding = audio_outputs.last_hidden_state.mean(dim=1) # Усредняем по временной оси
394
- else:
395
- audio_embedding = audio_outputs[0].mean(dim=1)
396
- audio_embedding = audio_embedding / audio_embedding.norm(dim=1, keepdim=True)
397
-
398
- # Получаем текстовые эмбеддинги
399
- text_embeddings = text_model.encode(labels, convert_to_tensor=True)
400
- text_embeddings = text_embeddings / text_embeddings.norm(dim=1, keepdim=True)
401
-
402
- # Проверяем размерности и проецируем если нужно
403
- audio_dim = audio_embedding.shape[1]
404
- text_dim = text_embeddings.shape[1]
405
-
406
- if audio_dim != text_dim:
407
- # Если размерности не совпадают, проецируем меньший эмбеддинг в большее пространство
408
- if audio_dim > text_dim:
409
- # Проецируем текстовые эмбеддинги в пространство аудио
410
- projection = torch.nn.Linear(text_dim, audio_dim).to(text_embeddings.device)
411
- text_embeddings = projection(text_embeddings)
412
- text_embeddings = text_embeddings / text_embeddings.norm(dim=1, keepdim=True)
413
- else:
414
- # Проецируем аудио эмбеддинги в пространство текста
415
- projection = torch.nn.Linear(audio_dim, text_dim).to(audio_embedding.device)
416
- audio_embedding = projection(audio_embedding)
417
- audio_embedding = audio_embedding / audio_embedding.norm(dim=1, keepdim=True)
418
-
419
- # Вычисляем косинусное сходство
420
- similarities = cosine_similarity(audio_embedding, text_embeddings).squeeze(0)
421
- # Применяем softmax для получения вероятностей
422
- probs = torch.softmax(similarities * 10, dim=0) # Масштабируем для лучшей точности
423
-
424
- output = "Результаты классификации (через audio + text embeddings):\n"
425
- for label, prob in zip(labels, probs):
426
- output += f"{label}: {prob.item():.4f}\n"
427
- return output
428
  else:
429
- # Для других моделей используем CLAP по умолчанию
430
- from transformers import ClapProcessor, ClapModel
431
-
432
- cache_key = f"audio_zero_shot_{model_name}"
433
- cached = model_cache.get(cache_key)
434
- if cached is None:
435
- processor = ClapProcessor.from_pretrained(model_name)
436
- model = ClapModel.from_pretrained(model_name)
437
- cached = (processor, model)
438
- model_cache.put(cache_key, cached)
439
-
440
- processor, model = cached
441
- inputs = processor(text=labels, audios=audio_data, return_tensors="pt", padding=True)
442
- with torch.no_grad():
443
- outputs = model(**inputs)
444
- logits_per_audio = outputs.logits_per_audio
445
- probs = logits_per_audio.softmax(dim=1)
446
-
447
- output = "Результаты классификации:\n"
448
- for label, prob in zip(labels, probs[0]):
449
- output += f"{label}: {prob.item():.4f}\n"
450
- return output
451
  except Exception as e:
452
  return f"Ошибка: {str(e)}"
453
 
@@ -470,153 +343,70 @@ def speech_synthesis(text, model_name):
470
  import numpy as np
471
  import torch
472
 
473
- if "speecht5" in model_name.lower():
474
- from transformers import SpeechT5Processor, SpeechT5ForTextToSpeech, SpeechT5HifiGan
 
 
 
 
 
 
 
 
 
 
 
475
 
476
- cache_key = f"tts_{model_name}"
477
- cached = model_cache.get(cache_key)
478
- if cached is None:
479
- processor = SpeechT5Processor.from_pretrained(model_name)
480
- model = SpeechT5ForTextToSpeech.from_pretrained(model_name)
481
- vocoder = SpeechT5HifiGan.from_pretrained("microsoft/speecht5_hifigan")
482
-
483
- # Генерируем speaker embeddings используя модель напрямую
484
- # Используем размерность speaker embeddings из конфигурации модели
485
- speaker_embedding_dim = model.config.speaker_embedding_dim
486
- # Создаем случайный speaker embedding (можно заменить на предобученный)
487
- # Для более стабильного результата используем нормализованный случайный вектор
488
- speaker_embeddings = torch.randn(1, speaker_embedding_dim)
489
- speaker_embeddings = speaker_embeddings / torch.norm(speaker_embeddings, dim=1, keepdim=True)
490
-
491
- cached = (processor, model, vocoder, speaker_embeddings)
492
- model_cache.put(cache_key, cached)
493
 
494
- processor, model, vocoder, speaker_embeddings = cached
495
- inputs = processor(text=text, return_tensors="pt")
496
- with torch.no_grad():
497
- speech = model.generate_speech(inputs["input_ids"], speaker_embeddings, vocoder=vocoder)
 
498
 
499
- # Конвертируем в numpy и нормализуем
500
- audio_data = speech.numpy()
501
  # Убеждаемся, что это 1D массив
502
  if len(audio_data.shape) > 1:
503
  audio_data = audio_data.flatten()
504
- # Нормализуем в диапазон [-1, 1] если нужно
 
505
  if audio_data.dtype != np.float32:
506
  audio_data = audio_data.astype(np.float32)
 
507
  # Нормализуем если значения выходят за пределы [-1, 1]
508
  max_val = np.abs(audio_data).max()
509
  if max_val > 1.0:
510
  audio_data = audio_data / max_val
511
 
512
- sample_rate = 16000
513
  return (sample_rate, audio_data)
514
- else:
515
- # Проверяем, является ли модель неподдерживаемой
516
- unsupported_models = {
517
- "facebook/fastspeech2-en-ljspeech": "Эта модель требует библиотеку Fairseq, а не transformers. Используйте модель microsoft/speecht5_tts вместо неё.",
518
- "espnet/kan-bayashi_ljspeech_vits": "Эта модель требует библиотеку ESPnet, а не transformers. Используйте модель microsoft/speecht5_tts вместо неё."
519
- }
520
 
521
- if model_name in unsupported_models:
522
- raise ValueError(unsupported_models[model_name])
 
 
 
523
 
524
- # Для других моделей используем стандартный pipeline
525
- try:
526
- # Проверяем, что текст не пустой
527
- if not text or not text.strip():
528
- raise ValueError("Текст для синтеза не может быть пустым")
529
-
530
- # Для MMS TTS моделей проверяем язык
531
- if "mms-tts" in model_name.lower():
532
- # MMS TTS модели обычно поддерживают только один язык
533
- # eng - английский, rus - русский и т.д.
534
- if "mms-tts-eng" in model_name.lower():
535
- # Проверяем, что текст на английском (простая проверка)
536
- # Если текст содержит кириллицу, это может быть проблемой
537
- has_cyrillic = any('\u0400' <= char <= '\u04FF' for char in text)
538
- if has_cyrillic:
539
- raise ValueError(
540
- f"Модель '{model_name}' поддерживает только английский язык. "
541
- f"Для русского текста используйте модель 'facebook/mms-tts-rus' или 'microsoft/speecht5_tts'."
542
- )
543
-
544
- tts = get_pipeline("text-to-speech", model_name)
545
- result = tts(text)
546
- except Exception as e:
547
- error_msg = str(e)
548
- if "does not appear to have a file named" in error_msg or "Unrecognized model" in error_msg:
549
- raise ValueError(
550
- f"Модель '{model_name}' не поддерживается библиотекой transformers. "
551
- f"Эта модель может требовать другую библиотеку (например, Fairseq или ESPnet). "
552
- f"Попробуйте использовать модель microsoft/speecht5_tts, которая полностью поддерживается."
553
- ) from e
554
- elif "negative output size" in error_msg.lower() or "input size 0" in error_msg.lower():
555
- raise ValueError(
556
- f"Ошибка обработки текста моделью '{model_name}'. "
557
- f"Возможные причины: неподдерживаемый язык, пустой текст после обработки, или проблема с токенизацией. "
558
- f"Попробуйте использовать другую модель или проверьте язык текста."
559
- ) from e
560
- raise
561
 
562
- # Pipeline может возвращать словарь или кортеж
563
- if isinstance(result, dict):
564
- # Стандартный формат: {"audio": array, "sampling_rate": int}
565
- audio_data = result.get("audio", result.get("raw", None))
566
- sample_rate = result.get("sampling_rate", result.get("sample_rate", 22050))
567
-
568
- if audio_data is None:
569
- raise ValueError("Не удалось извлечь аудио данные из результата pipeline")
570
-
571
- # Конвертируем в numpy array если нужно
572
- if isinstance(audio_data, torch.Tensor):
573
- audio_data = audio_data.numpy()
574
- elif not isinstance(audio_data, np.ndarray):
575
- audio_data = np.array(audio_data)
576
-
577
- # Убеждаемся, что это 1D массив
578
- if len(audio_data.shape) > 1:
579
- audio_data = audio_data.flatten()
580
-
581
- # Нормализуем в float32
582
- if audio_data.dtype != np.float32:
583
- audio_data = audio_data.astype(np.float32)
584
-
585
- # Нормализуем если значения выходят за пределы [-1, 1]
586
- max_val = np.abs(audio_data).max()
587
- if max_val > 1.0:
588
- audio_data = audio_data / max_val
589
-
590
- return (sample_rate, audio_data)
591
- elif isinstance(result, tuple) and len(result) == 2:
592
- # Уже в правильном формате (sample_rate, audio_data)
593
- sample_rate, audio_data = result
594
-
595
- # Конвертируем в numpy если нужно
596
- if isinstance(audio_data, torch.Tensor):
597
- audio_data = audio_data.numpy()
598
- elif not isinstance(audio_data, np.ndarray):
599
- audio_data = np.array(audio_data)
600
-
601
- # Убеждаемся, что это 1D массив
602
- if len(audio_data.shape) > 1:
603
- audio_data = audio_data.flatten()
604
-
605
- # Нормализуем в float32
606
- if audio_data.dtype != np.float32:
607
- audio_data = audio_data.astype(np.float32)
608
-
609
- # Нормализуем если значения выходят за пределы [-1, 1]
610
- max_val = np.abs(audio_data).max()
611
- if max_val > 1.0:
612
- audio_data = audio_data / max_val
613
-
614
- return (sample_rate, audio_data)
615
- else:
616
- raise ValueError(f"Неожиданный формат результата от pipeline: {type(result)}")
617
  except Exception as e:
618
- # В случае ошибки возвращаем None, чтобы Gradio мог обработать это
619
- # Но также логируем ошибку в историю через декоратор
620
  raise Exception(f"Ошибка синтеза речи: {str(e)}")
621
 
622
  # ==================== ЗАДАЧИ С ИЗОБРАЖЕНИЯМИ ====================
@@ -898,26 +688,11 @@ def image_segmentation(image, model_name):
898
  def image_captioning(image, model_name):
899
  """Описание изображения"""
900
  try:
901
- if "blip" in model_name.lower():
902
- cache_key = f"caption_blip_{model_name}"
903
- cached = model_cache.get(cache_key)
904
- if cached is None:
905
- processor = BlipProcessor.from_pretrained(model_name)
906
- model = BlipForConditionalGeneration.from_pretrained(model_name)
907
- cached = (processor, model)
908
- model_cache.put(cache_key, cached)
909
-
910
- processor, model = cached
911
- inputs = processor(image, return_tensors="pt")
912
- out = model.generate(**inputs, max_length=50)
913
- caption = processor.decode(out[0], skip_special_tokens=True)
914
- return caption
915
- else:
916
- captioner = get_pipeline("image-to-text", model_name)
917
- result = captioner(image)
918
- if isinstance(result, list):
919
- result = result[0]
920
- return result['generated_text']
921
  except Exception as e:
922
  return f"Ошибка: {str(e)}"
923
 
@@ -925,28 +700,11 @@ def image_captioning(image, model_name):
925
  def visual_qa(image, question, model_name):
926
  """Визуальный вопрос-ответ"""
927
  try:
928
- if "vilt" in model_name.lower():
929
- cache_key = f"vqa_vilt_{model_name}"
930
- cached = model_cache.get(cache_key)
931
- if cached is None:
932
- processor = ViltProcessor.from_pretrained(model_name)
933
- model = ViltForQuestionAnswering.from_pretrained(model_name)
934
- cached = (processor, model)
935
- model_cache.put(cache_key, cached)
936
-
937
- processor, model = cached
938
- inputs = processor(image, question, return_tensors="pt")
939
- outputs = model(**inputs)
940
- logits = outputs.logits
941
- idx = logits.argmax(-1).item()
942
- answer = model.config.id2label[idx]
943
- return f"Ответ: {answer}"
944
- else:
945
- vqa = get_pipeline("visual-question-answering", model_name)
946
- result = vqa(image=image, question=question)
947
- if isinstance(result, list):
948
- result = result[0]
949
- return f"Ответ: {result['answer']}"
950
  except Exception as e:
951
  return f"Ошибка: {str(e)}"
952
 
@@ -954,89 +712,25 @@ def visual_qa(image, question, model_name):
954
  def image_zero_shot_classification(image, candidate_labels, model_name):
955
  """Zero-shot классификация изображений"""
956
  try:
957
- cache_key = f"clip_zs_{model_name}"
958
- cached = model_cache.get(cache_key)
959
- if cached is None:
960
- # Проверяем, является ли модель из sentence-transformers
961
- if "sentence-transformers" in model_name:
962
- from sentence_transformers import SentenceTransformer
963
- model = SentenceTransformer(model_name)
964
- cached = ("sentence_transformers", model)
965
- # Проверяем, является ли модель LAION (требует OpenCLIP)
966
- elif "laion/" in model_name.lower() or "laion5b" in model_name.lower():
967
- import open_clip
968
- # Определяем имя модели и веса для OpenCLIP
969
- if "xlm-roberta-base-ViT-B-32" in model_name or "xlm-roberta-base" in model_name:
970
- clip_model_name = "xlm-roberta-base-ViT-B-32"
971
- pretrained = "laion5b_s13b_b90k"
972
- else:
973
- # Пытаемся извлечь информацию из имени модели
974
- clip_model_name = "xlm-roberta-base-ViT-B-32"
975
- pretrained = "laion5b_s13b_b90k"
976
-
977
- model, _, preprocess = open_clip.create_model_and_transforms(
978
- clip_model_name,
979
- pretrained=pretrained
980
- )
981
- tokenizer = open_clip.get_tokenizer(clip_model_name)
982
- model.eval()
983
- cached = ("openclip", model, preprocess, tokenizer)
984
- else:
985
- processor = CLIPProcessor.from_pretrained(model_name)
986
- model = CLIPModel.from_pretrained(model_name)
987
- cached = ("transformers", processor, model)
988
- model_cache.put(cache_key, cached)
989
-
990
  labels = [label.strip() for label in candidate_labels.split(",")]
 
 
991
 
992
- if cached[0] == "sentence_transformers":
993
- # Используем sentence-transformers
994
- model = cached[1]
995
- # Вычисляем эмбеддинги изображения и текстов
996
- image_embedding = model.encode(image, convert_to_tensor=True)
997
- text_embeddings = model.encode(labels, convert_to_tensor=True)
998
- # Вычисляем косинусное сходство
999
- similarities = cosine_similarity(image_embedding.unsqueeze(0), text_embeddings).squeeze(0)
1000
- # Нормализуем в диапазон [0, 1] и применяем softmax для вероятностей
1001
- similarities = (similarities + 1) / 2
1002
- probs = torch.softmax(similarities, dim=0)
1003
-
1004
- output = "Результаты классификации:\n"
1005
- for label, prob in zip(labels, probs):
1006
- output += f"{label}: {prob.item():.4f}\n"
1007
- elif cached[0] == "openclip":
1008
- # Используем OpenCLIP
1009
- model, preprocess, tokenizer = cached[1], cached[2], cached[3]
1010
- # Обрабатываем изображение и тексты
1011
- image_tensor = preprocess(image).unsqueeze(0)
1012
- text_tokens = tokenizer(labels)
1013
-
1014
- with torch.no_grad():
1015
- image_features = model.encode_image(image_tensor)
1016
- text_features = model.encode_text(text_tokens)
1017
- # Нормализуем признаки
1018
- image_features = image_features / image_features.norm(dim=-1, keepdim=True)
1019
- text_features = text_features / text_features.norm(dim=-1, keepdim=True)
1020
- # Вычисляем косинусное сходство (логиты)
1021
- logits_per_image = (image_features @ text_features.T) * 100 # Масштабируем для лучшей точности
1022
- probs = logits_per_image.softmax(dim=1)
1023
-
1024
- output = "Результаты классификации:\n"
1025
- for label, prob in zip(labels, probs[0]):
1026
- output += f"{label}: {prob.item():.4f}\n"
1027
  else:
1028
- # Используем стандартный CLIP из transformers
1029
- processor, model = cached[1], cached[2]
1030
- inputs = processor(text=labels, images=image, return_tensors="pt", padding=True)
1031
-
1032
- with torch.no_grad():
1033
- outputs = model(**inputs)
1034
- logits_per_image = outputs.logits_per_image
1035
- probs = logits_per_image.softmax(dim=1)
1036
-
1037
- output = "Результаты классификации:\n"
1038
- for label, prob in zip(labels, probs[0]):
1039
- output += f"{label}: {prob.item():.4f}\n"
1040
 
1041
  return output
1042
  except Exception as e:
 
1
  import gradio as gr
2
+ from transformers import pipeline
 
 
 
 
 
3
  import torch
 
 
4
  from PIL import Image, ImageDraw, ImageFont
5
  import numpy as np
6
  import functools
 
298
  def audio_zero_shot_classifier(audio, candidate_labels, model_name):
299
  """Zero-shot классификация аудио"""
300
  try:
 
 
 
301
  labels = [label.strip() for label in candidate_labels.split(",")]
302
+ classifier = get_pipeline("zero-shot-audio-classification", model_name)
303
+ result = classifier(audio, candidate_labels=labels)
304
 
305
+ # Обрабатываем результат
306
+ if isinstance(result, list):
307
+ result = result[0] if result else {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
 
309
+ output = "Результаты классификации:\n"
310
+ if isinstance(result, dict) and 'scores' in result:
311
+ for label, score in zip(result.get('labels', labels), result['scores']):
312
+ output += f"{label}: {score:.4f}\n"
313
+ elif isinstance(result, list):
314
+ for item in result:
315
+ if isinstance(item, dict):
316
+ label = item.get('label', '')
317
+ score = item.get('score', 0.0)
318
+ output += f"{label}: {score:.4f}\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
319
  else:
320
+ # Если формат неожиданный, пытаемся извлечь информацию
321
+ output += str(result)
322
+
323
+ return output
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
324
  except Exception as e:
325
  return f"Ошибка: {str(e)}"
326
 
 
343
  import numpy as np
344
  import torch
345
 
346
+ # Проверяем, что текст не пустой
347
+ if not text or not text.strip():
348
+ raise ValueError("Текст для синтеза не может быть пустым")
349
+
350
+ # Используем стандартный pipeline
351
+ tts = get_pipeline("text-to-speech", model_name)
352
+ result = tts(text)
353
+
354
+ # Pipeline может возвращать словарь или кортеж
355
+ if isinstance(result, dict):
356
+ # Стандартный формат: {"audio": array, "sampling_rate": int}
357
+ audio_data = result.get("audio", result.get("raw", None))
358
+ sample_rate = result.get("sampling_rate", result.get("sample_rate", 22050))
359
 
360
+ if audio_data is None:
361
+ raise ValueError("Не удалось извлечь аудио данные из результата pipeline")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
362
 
363
+ # Конвертируем в numpy array если нужно
364
+ if isinstance(audio_data, torch.Tensor):
365
+ audio_data = audio_data.numpy()
366
+ elif not isinstance(audio_data, np.ndarray):
367
+ audio_data = np.array(audio_data)
368
 
 
 
369
  # Убеждаемся, что это 1D массив
370
  if len(audio_data.shape) > 1:
371
  audio_data = audio_data.flatten()
372
+
373
+ # Нормализуем в float32
374
  if audio_data.dtype != np.float32:
375
  audio_data = audio_data.astype(np.float32)
376
+
377
  # Нормализуем если значения выходят за пределы [-1, 1]
378
  max_val = np.abs(audio_data).max()
379
  if max_val > 1.0:
380
  audio_data = audio_data / max_val
381
 
 
382
  return (sample_rate, audio_data)
383
+ elif isinstance(result, tuple) and len(result) == 2:
384
+ # Уже в правильном формате (sample_rate, audio_data)
385
+ sample_rate, audio_data = result
 
 
 
386
 
387
+ # Конвертируем в numpy если нужно
388
+ if isinstance(audio_data, torch.Tensor):
389
+ audio_data = audio_data.numpy()
390
+ elif not isinstance(audio_data, np.ndarray):
391
+ audio_data = np.array(audio_data)
392
 
393
+ # Убеждаемся, что это 1D массив
394
+ if len(audio_data.shape) > 1:
395
+ audio_data = audio_data.flatten()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
396
 
397
+ # Нормализуем в float32
398
+ if audio_data.dtype != np.float32:
399
+ audio_data = audio_data.astype(np.float32)
400
+
401
+ # Нормализуем если значения выходят за пределы [-1, 1]
402
+ max_val = np.abs(audio_data).max()
403
+ if max_val > 1.0:
404
+ audio_data = audio_data / max_val
405
+
406
+ return (sample_rate, audio_data)
407
+ else:
408
+ raise ValueError(f"Неожиданный формат результата от pipeline: {type(result)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
409
  except Exception as e:
 
 
410
  raise Exception(f"Ошибка синтеза речи: {str(e)}")
411
 
412
  # ==================== ЗАДАЧИ С ИЗОБРАЖЕНИЯМИ ====================
 
688
  def image_captioning(image, model_name):
689
  """Описание изображения"""
690
  try:
691
+ captioner = get_pipeline("image-to-text", model_name)
692
+ result = captioner(image)
693
+ if isinstance(result, list):
694
+ result = result[0]
695
+ return result['generated_text']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
696
  except Exception as e:
697
  return f"Ошибка: {str(e)}"
698
 
 
700
  def visual_qa(image, question, model_name):
701
  """Визуальный вопрос-ответ"""
702
  try:
703
+ vqa = get_pipeline("visual-question-answering", model_name)
704
+ result = vqa(image=image, question=question)
705
+ if isinstance(result, list):
706
+ result = result[0]
707
+ return f"Ответ: {result['answer']}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
708
  except Exception as e:
709
  return f"Ошибка: {str(e)}"
710
 
 
712
  def image_zero_shot_classification(image, candidate_labels, model_name):
713
  """Zero-shot классификация изображений"""
714
  try:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
715
  labels = [label.strip() for label in candidate_labels.split(",")]
716
+ classifier = get_pipeline("zero-shot-image-classification", model_name)
717
+ result = classifier(image, candidate_labels=labels)
718
 
719
+ # Обрабатываем результат
720
+ if isinstance(result, list):
721
+ # Сортируем по score если нужно
722
+ result = sorted(result, key=lambda x: x.get('score', 0), reverse=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
723
  else:
724
+ result = [result] if result else []
725
+
726
+ output = "Результаты классификации:\n"
727
+ for item in result:
728
+ if isinstance(item, dict):
729
+ label = item.get('label', '')
730
+ score = item.get('score', 0.0)
731
+ output += f"{label}: {score:.4f}\n"
732
+ else:
733
+ output += f"{item}\n"
 
 
734
 
735
  return output
736
  except Exception as e: