Rasmus Lellep commited on
Commit
03381f4
·
1 Parent(s): 2bac171

added estonian examples, changed demo description

Browse files
Files changed (4) hide show
  1. .DS_Store +0 -0
  2. app.py +97 -89
  3. app_local.py +0 -62
  4. examples/LJ005-0214.wav +3 -0
.DS_Store CHANGED
Binary files a/.DS_Store and b/.DS_Store differ
 
app.py CHANGED
@@ -96,9 +96,7 @@ supported_languages = config.languages
96
  def predict(
97
  prompt,
98
  language,
99
- audio_file_pth,
100
- mic_file_path,
101
- use_mic,
102
  voice_cleanup,
103
  no_lang_auto_detect,
104
  agree,
@@ -146,23 +144,6 @@ def predict(
146
  None,
147
  )
148
 
149
- if use_mic == True:
150
- if mic_file_path is not None:
151
- speaker_wav = mic_file_path
152
- else:
153
- gr.Warning(
154
- "Please record your voice with Microphone, or uncheck Use Microphone to use reference audios"
155
- )
156
- return (
157
- None,
158
- None,
159
- None,
160
- None,
161
- )
162
-
163
- else:
164
- speaker_wav = audio_file_pth
165
-
166
  # Filtering for microphone input, as it has BG noise, maybe silence in beginning and end
167
  # This is fast filtering not perfect
168
 
@@ -273,6 +254,7 @@ def predict(
273
  wav_chunks = []
274
  ## Direct mode
275
 
 
276
  print("I: Generating new audio...")
277
  t0 = time.time()
278
  out = model.inference(
@@ -293,9 +275,9 @@ def predict(
293
  print(f"Real-time factor (RTF): {real_time_factor}")
294
  metrics_text+=f"Real-time factor (RTF): {real_time_factor:.2f}\n"
295
  torchaudio.save("output.wav", torch.tensor(out["wav"]).unsqueeze(0), 24000)
 
296
 
297
-
298
- """
299
  print("I: Generating new audio in streaming mode...")
300
  t0 = time.time()
301
  chunks = model.inference_stream(
@@ -330,7 +312,7 @@ def predict(
330
  metrics_text += f"Real-time factor (RTF): {real_time_factor:.2f}\n"
331
 
332
  torchaudio.save("output.wav", wav.squeeze().unsqueeze(0).cpu(), 24000)
333
- """
334
 
335
  except RuntimeError as e:
336
  if "device-side assert" in str(e):
@@ -353,9 +335,7 @@ def predict(
353
  error_time,
354
  prompt,
355
  language,
356
- audio_file_pth,
357
- mic_file_path,
358
- use_mic,
359
  voice_cleanup,
360
  no_lang_auto_detect,
361
  agree,
@@ -436,27 +416,15 @@ description = """
436
 
437
  <br/>
438
 
439
- This demo is currently running **XTTS v2.0.3** <a href="https://huggingface.co/coqui/XTTS-v2">XTTS</a> is a multilingual text-to-speech and voice-cloning model. This demo features zero-shot voice cloning, however, you can fine-tune XTTS for better results. Leave a star 🌟 on Github <a href="https://github.com/coqui-ai/TTS">🐸TTS</a>, where our open-source inference and training code lives.
440
-
441
- <br/>
442
-
443
- Supported languages: Arabic: ar, Brazilian Portuguese: pt , Mandarin Chinese: zh-cn, Czech: cs, Dutch: nl, English: en, Estonian: et, French: fr, German: de, Italian: it, Polish: pl, Russian: ru, Spanish: es, Turkish: tr, Japanese: ja, Korean: ko, Hungarian: hu, Hindi: hi
444
 
445
  <br/>
446
  """
 
447
 
448
- links = """
449
- <img referrerpolicy="no-referrer-when-downgrade" src="https://static.scarf.sh/a.png?x-pxid=0d00920c-8cc9-4bf3-90f2-a615797e5f59" />
450
 
451
- | | |
452
- | ------------------------------- | --------------------------------------- |
453
- | 🐸💬 **CoquiTTS** | <a style="display:inline-block" href='https://github.com/coqui-ai/TTS'><img src='https://img.shields.io/github/stars/coqui-ai/TTS?style=social' /></a>|
454
- | 💼 **Documentation** | [ReadTheDocs](https://tts.readthedocs.io/en/latest/)
455
- | 👩‍💻 **Questions** | [GitHub Discussions](https://github.com/coqui-ai/TTS/discussions) |
456
- | 🗯 **Community** | [![Dicord](https://img.shields.io/discord/1037326658807533628?color=%239B59B6&label=chat%20on%20discord)](https://discord.gg/5eXr5seRrv) |
457
-
458
-
459
- """
460
 
461
  article = """
462
  <div style='margin:20px auto;'>
@@ -465,12 +433,91 @@ article = """
465
  </div>
466
  """
467
  examples = [
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
468
  [
469
  "Once when I was six years old I saw a magnificent picture",
470
  "en",
471
  "examples/female.wav",
472
- None,
473
- False,
474
  False,
475
  False,
476
  True,
@@ -479,8 +526,6 @@ examples = [
479
  "Lorsque j'avais six ans j'ai vu, une fois, une magnifique image",
480
  "fr",
481
  "examples/female.wav",
482
- None,
483
- False,
484
  False,
485
  False,
486
  True,
@@ -489,8 +534,6 @@ examples = [
489
  "Als ich sechs war, sah ich einmal ein wunderbares Bild",
490
  "de",
491
  "examples/female.wav",
492
- None,
493
- False,
494
  False,
495
  False,
496
  True,
@@ -499,8 +542,6 @@ examples = [
499
  "Cuando tenía seis años, vi una vez una imagen magnífica",
500
  "es",
501
  "examples/female.wav",
502
- None,
503
- False,
504
  False,
505
  False,
506
  True,
@@ -509,8 +550,6 @@ examples = [
509
  "Kunagi, kui olin kuueaastane, nägin ma ühte imelist pilti",
510
  "et",
511
  "examples/female.wav",
512
- None,
513
- False,
514
  False,
515
  False,
516
  True,
@@ -519,8 +558,6 @@ examples = [
519
  "Quando eu tinha seis anos eu vi, uma vez, uma imagem magnífica",
520
  "pt",
521
  "examples/female.wav",
522
- None,
523
- False,
524
  False,
525
  False,
526
  True,
@@ -529,8 +566,6 @@ examples = [
529
  "Kiedy miałem sześć lat, zobaczyłem pewnego razu wspaniały obrazek",
530
  "pl",
531
  "examples/female.wav",
532
- None,
533
- False,
534
  False,
535
  False,
536
  True,
@@ -539,8 +574,6 @@ examples = [
539
  "Un tempo lontano, quando avevo sei anni, vidi un magnifico disegno",
540
  "it",
541
  "examples/female.wav",
542
- None,
543
- False,
544
  False,
545
  False,
546
  True,
@@ -549,8 +582,6 @@ examples = [
549
  "Bir zamanlar, altı yaşındayken, muhteşem bir resim gördüm",
550
  "tr",
551
  "examples/male.wav",
552
- None,
553
- False,
554
  False,
555
  False,
556
  True,
@@ -559,8 +590,6 @@ examples = [
559
  "Когда мне было шесть лет, я увидел однажды удивительную картинку",
560
  "ru",
561
  "examples/female.wav",
562
- None,
563
- False,
564
  False,
565
  False,
566
  True,
@@ -569,8 +598,6 @@ examples = [
569
  "Toen ik een jaar of zes was, zag ik op een keer een prachtige plaat",
570
  "nl",
571
  "examples/male.wav",
572
- None,
573
- False,
574
  False,
575
  False,
576
  True,
@@ -579,8 +606,6 @@ examples = [
579
  "Když mi bylo šest let, viděl jsem jednou nádherný obrázek",
580
  "cs",
581
  "examples/female.wav",
582
- None,
583
- False,
584
  False,
585
  False,
586
  True,
@@ -589,8 +614,6 @@ examples = [
589
  "当我还只有六岁的时候, 看到了一副精彩的插画",
590
  "zh-cn",
591
  "examples/male.wav",
592
- None,
593
- False,
594
  False,
595
  False,
596
  True,
@@ -599,9 +622,7 @@ examples = [
599
  "かつて 六歳のとき、素晴らしい絵を見ました",
600
  "ja",
601
  "examples/female.wav",
602
- None,
603
  False,
604
- True,
605
  False,
606
  True,
607
  ],
@@ -609,9 +630,7 @@ examples = [
609
  "한번은 내가 여섯 살이었을 때 멋진 그림을 보았습니다.",
610
  "ko",
611
  "examples/male.wav",
612
- None,
613
  False,
614
- True,
615
  False,
616
  True,
617
  ],
@@ -619,12 +638,11 @@ examples = [
619
  "Egyszer hat éves koromban láttam egy csodálatos képet",
620
  "hu",
621
  "examples/male.wav",
622
- None,
623
  False,
624
- True,
625
  False,
626
  True,
627
  ],
 
628
  ]
629
 
630
 
@@ -644,12 +662,11 @@ with gr.Blocks(analytics_enabled=False) as demo:
644
  with gr.Row():
645
  with gr.Column():
646
  gr.Markdown(description)
647
- with gr.Column():
648
- gr.Markdown(links)
649
 
650
  with gr.Row():
651
  with gr.Column():
652
  input_text_gr = gr.Textbox(
 
653
  label="Text Prompt",
654
  info="One or two sentences at a time is better. Up to 200 text characters.",
655
  value="Tere, olen sinu hääle kloon. Ürita mulle lindistada võimalikult hea kvaliteediga klipp, et oskaksin su kõnet paremini jäljendada.",
@@ -679,24 +696,15 @@ with gr.Blocks(analytics_enabled=False) as demo:
679
  ],
680
  multiselect=False,
681
  value="et",
 
682
  )
683
  ref_gr = gr.Audio(
684
  label="Reference Audio",
 
685
  #info="Click on the ✎ button to upload your own target speaker audio",
686
  type="filepath",
687
  value="examples/female.wav",
688
  )
689
- mic_gr = gr.Audio(
690
- sources="microphone",
691
- #info="Use your microphone to record audio",
692
- type="filepath",
693
- label="Use Microphone for Reference",
694
- )
695
- use_mic_gr = gr.Checkbox(
696
- label="Use Microphone",
697
- value=False,
698
- info="Notice: Microphone input may not work properly under traffic",
699
- )
700
  clean_ref_gr = gr.Checkbox(
701
  label="Cleanup Reference Voice",
702
  value=False,
@@ -724,12 +732,12 @@ with gr.Blocks(analytics_enabled=False) as demo:
724
  with gr.Row():
725
  gr.Examples(examples,
726
  label="Examples",
727
- inputs=[input_text_gr, language_gr, ref_gr, mic_gr, use_mic_gr, clean_ref_gr, auto_det_lang_gr, tos_gr],
728
  outputs=[audio_gr, out_text_gr, ref_audio_gr],
729
  fn=predict,
730
  cache_examples=False,)
731
 
732
- tts_button.click(predict, [input_text_gr, language_gr, ref_gr, mic_gr, use_mic_gr, clean_ref_gr, auto_det_lang_gr, tos_gr], outputs=[audio_gr, out_text_gr, ref_audio_gr])
733
 
734
  if __name__ == "__main__":
735
  demo.queue()
 
96
  def predict(
97
  prompt,
98
  language,
99
+ speaker_wav,
 
 
100
  voice_cleanup,
101
  no_lang_auto_detect,
102
  agree,
 
144
  None,
145
  )
146
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  # Filtering for microphone input, as it has BG noise, maybe silence in beginning and end
148
  # This is fast filtering not perfect
149
 
 
254
  wav_chunks = []
255
  ## Direct mode
256
 
257
+ '''
258
  print("I: Generating new audio...")
259
  t0 = time.time()
260
  out = model.inference(
 
275
  print(f"Real-time factor (RTF): {real_time_factor}")
276
  metrics_text+=f"Real-time factor (RTF): {real_time_factor:.2f}\n"
277
  torchaudio.save("output.wav", torch.tensor(out["wav"]).unsqueeze(0), 24000)
278
+ '''
279
 
280
+
 
281
  print("I: Generating new audio in streaming mode...")
282
  t0 = time.time()
283
  chunks = model.inference_stream(
 
312
  metrics_text += f"Real-time factor (RTF): {real_time_factor:.2f}\n"
313
 
314
  torchaudio.save("output.wav", wav.squeeze().unsqueeze(0).cpu(), 24000)
315
+
316
 
317
  except RuntimeError as e:
318
  if "device-side assert" in str(e):
 
335
  error_time,
336
  prompt,
337
  language,
338
+ speaker_wav,
 
 
339
  voice_cleanup,
340
  no_lang_auto_detect,
341
  agree,
 
416
 
417
  <br/>
418
 
419
+ This demo is running an XTTS model fine-tuned on Estonian data. <a href="https://huggingface.co/coqui/XTTS-v2">XTTS</a> is a multilingual text-to-speech and voice-cloning model. This demo features zero-shot voice cloning.
 
 
 
 
420
 
421
  <br/>
422
  """
423
+ #Supported languages: Arabic: ar, Brazilian Portuguese: pt , Mandarin Chinese: zh-cn, Czech: cs, Dutch: nl, English: en, Estonian: et, French: fr, German: de, Italian: it, Polish: pl, Russian: ru, Spanish: es, Turkish: tr, Japanese: ja, Korean: ko, Hungarian: hu, Hindi: hi
424
 
425
+ #<br/>
426
+ #"""
427
 
 
 
 
 
 
 
 
 
 
428
 
429
  article = """
430
  <div style='margin:20px auto;'>
 
433
  </div>
434
  """
435
  examples = [
436
+ [
437
+ "Kuigi ilm oli vihmane ja tuuline, otsustasid matkajad siiski metsa minna, lootes, et pilved hajuvad.",
438
+ "et",
439
+ "examples/female.wav",
440
+ False,
441
+ False,
442
+ True,
443
+ ],
444
+ [
445
+ "Vanaema jutustatud muinasjutt oli nii kaasahaarav, et lapsed unustasid aja ja kuulasid vaikselt iga sõna.",
446
+ "et",
447
+ "examples/male.wav",
448
+ False,
449
+ False,
450
+ True,
451
+ ],
452
+ [
453
+ "Arvuti tarkvarauuendus lahendas mitu v��ikest, kuid tüütut probleemi, mis olid kasutusmugavust seganud.",
454
+ "et",
455
+ "examples/female.wav",
456
+ False,
457
+ False,
458
+ True,
459
+ ],
460
+ [
461
+ "Pärast pikka ja pingelist töönädalat tundus nädalavahetus maal vanemate juures nagu paradiis.",
462
+ "et",
463
+ "examples/male.wav",
464
+ False,
465
+ False,
466
+ True,
467
+ ],
468
+ [
469
+ "Kuigi laulja esitus oli tehniliselt veatu, puudus selles miskipärast südamest tulev emotsioon, mis publikut liigutaks.",
470
+ "et",
471
+ "examples/female.wav",
472
+ False,
473
+ False,
474
+ True,
475
+ ],
476
+ [
477
+ "Ajalooeksami ettevalmistamine nõudis väga palju materjali läbitöötamist, alates Vana-Roomast kuni tänapäevani.",
478
+ "et",
479
+ "examples/male.wav",
480
+ False,
481
+ False,
482
+ True,
483
+ ],
484
+ [
485
+ "Tõde ja ilu on kaks mõistet, mille tähendus on muutunud ajas ja kultuurides, kuid mis on alati olnud inimkonna arutelude keskmes.",
486
+ "et",
487
+ "examples/LJ001-0030.wav",
488
+ False,
489
+ False,
490
+ True,
491
+ ],
492
+ [
493
+ "Kogu pere osales kevadel talgupäeval, koristades parki ja istutades uusi puid, et anda oma panus kogukonda.",
494
+ "et",
495
+ "examples/LJ001-0030.wav",
496
+ False,
497
+ False,
498
+ True,
499
+ ],
500
+ [
501
+ "Kuigi ta oli reisinud paljudes maailma paikades, tunnistas ta, et kõige ilusamad päikeseloojangud on siiski Eesti rannikul.",
502
+ "et",
503
+ "examples/LJ005-0214.wav",
504
+ False,
505
+ False,
506
+ True,
507
+ ],
508
+ [
509
+ "Sõbrad arutasid pikalt, kas minna suvepuhkusele Lõuna-Euroopasse või avastada hoopis Lõuna-Eesti kauneid loodusradu.",
510
+ "et",
511
+ "examples/LJ005-0214.wav",
512
+ False,
513
+ False,
514
+ True,
515
+ ],
516
+ '''
517
  [
518
  "Once when I was six years old I saw a magnificent picture",
519
  "en",
520
  "examples/female.wav",
 
 
521
  False,
522
  False,
523
  True,
 
526
  "Lorsque j'avais six ans j'ai vu, une fois, une magnifique image",
527
  "fr",
528
  "examples/female.wav",
 
 
529
  False,
530
  False,
531
  True,
 
534
  "Als ich sechs war, sah ich einmal ein wunderbares Bild",
535
  "de",
536
  "examples/female.wav",
 
 
537
  False,
538
  False,
539
  True,
 
542
  "Cuando tenía seis años, vi una vez una imagen magnífica",
543
  "es",
544
  "examples/female.wav",
 
 
545
  False,
546
  False,
547
  True,
 
550
  "Kunagi, kui olin kuueaastane, nägin ma ühte imelist pilti",
551
  "et",
552
  "examples/female.wav",
 
 
553
  False,
554
  False,
555
  True,
 
558
  "Quando eu tinha seis anos eu vi, uma vez, uma imagem magnífica",
559
  "pt",
560
  "examples/female.wav",
 
 
561
  False,
562
  False,
563
  True,
 
566
  "Kiedy miałem sześć lat, zobaczyłem pewnego razu wspaniały obrazek",
567
  "pl",
568
  "examples/female.wav",
 
 
569
  False,
570
  False,
571
  True,
 
574
  "Un tempo lontano, quando avevo sei anni, vidi un magnifico disegno",
575
  "it",
576
  "examples/female.wav",
 
 
577
  False,
578
  False,
579
  True,
 
582
  "Bir zamanlar, altı yaşındayken, muhteşem bir resim gördüm",
583
  "tr",
584
  "examples/male.wav",
 
 
585
  False,
586
  False,
587
  True,
 
590
  "Когда мне было шесть лет, я увидел однажды удивительную картинку",
591
  "ru",
592
  "examples/female.wav",
 
 
593
  False,
594
  False,
595
  True,
 
598
  "Toen ik een jaar of zes was, zag ik op een keer een prachtige plaat",
599
  "nl",
600
  "examples/male.wav",
 
 
601
  False,
602
  False,
603
  True,
 
606
  "Když mi bylo šest let, viděl jsem jednou nádherný obrázek",
607
  "cs",
608
  "examples/female.wav",
 
 
609
  False,
610
  False,
611
  True,
 
614
  "当我还只有六岁的时候, 看到了一副精彩的插画",
615
  "zh-cn",
616
  "examples/male.wav",
 
 
617
  False,
618
  False,
619
  True,
 
622
  "かつて 六歳のとき、素晴らしい絵を見ました",
623
  "ja",
624
  "examples/female.wav",
 
625
  False,
 
626
  False,
627
  True,
628
  ],
 
630
  "한번은 내가 여섯 살이었을 때 멋진 그림을 보았습니다.",
631
  "ko",
632
  "examples/male.wav",
 
633
  False,
 
634
  False,
635
  True,
636
  ],
 
638
  "Egyszer hat éves koromban láttam egy csodálatos képet",
639
  "hu",
640
  "examples/male.wav",
 
641
  False,
 
642
  False,
643
  True,
644
  ],
645
+ '''
646
  ]
647
 
648
 
 
662
  with gr.Row():
663
  with gr.Column():
664
  gr.Markdown(description)
 
 
665
 
666
  with gr.Row():
667
  with gr.Column():
668
  input_text_gr = gr.Textbox(
669
+ lines=2,
670
  label="Text Prompt",
671
  info="One or two sentences at a time is better. Up to 200 text characters.",
672
  value="Tere, olen sinu hääle kloon. Ürita mulle lindistada võimalikult hea kvaliteediga klipp, et oskaksin su kõnet paremini jäljendada.",
 
696
  ],
697
  multiselect=False,
698
  value="et",
699
+ interactive=False,
700
  )
701
  ref_gr = gr.Audio(
702
  label="Reference Audio",
703
+ sources=["microphone", "upload"],
704
  #info="Click on the ✎ button to upload your own target speaker audio",
705
  type="filepath",
706
  value="examples/female.wav",
707
  )
 
 
 
 
 
 
 
 
 
 
 
708
  clean_ref_gr = gr.Checkbox(
709
  label="Cleanup Reference Voice",
710
  value=False,
 
732
  with gr.Row():
733
  gr.Examples(examples,
734
  label="Examples",
735
+ inputs=[input_text_gr, language_gr, ref_gr, clean_ref_gr, auto_det_lang_gr, tos_gr],
736
  outputs=[audio_gr, out_text_gr, ref_audio_gr],
737
  fn=predict,
738
  cache_examples=False,)
739
 
740
+ tts_button.click(predict, [input_text_gr, language_gr, ref_gr, clean_ref_gr, auto_det_lang_gr, tos_gr], outputs=[audio_gr, out_text_gr, ref_audio_gr])
741
 
742
  if __name__ == "__main__":
743
  demo.queue()
app_local.py DELETED
@@ -1,62 +0,0 @@
1
- import gradio as gr
2
- import numpy as np
3
- import torch
4
- from TTS.tts.configs.xtts_config import XttsConfig
5
- from TTS.tts.models.xtts import Xtts
6
-
7
- device = "cuda:0" if torch.cuda.is_available() else "cpu"
8
-
9
- def load_model():
10
- config = XttsConfig()
11
- config.load_json("model/config.json")
12
- XTTS_MODEL = Xtts.init_from_config(config)
13
- XTTS_MODEL.load_checkpoint(
14
- config,
15
- checkpoint_path="model/model.pth",
16
- vocab_path="model/vocab.json",
17
- eval=True,
18
- use_deepspeed=False
19
- )
20
- XTTS_MODEL.to(device)
21
- return XTTS_MODEL
22
-
23
- model = load_model()
24
-
25
- def predict(sentence, language, reference_clip):
26
- if not reference_clip or not reference_clip.split('.')[-1] in ['mp3', 'wav']:
27
- return
28
- gpt_cond_latent, speaker_embedding = model.get_conditioning_latents(
29
- audio_path=reference_clip,
30
- gpt_cond_len=model.config.gpt_cond_len,
31
- max_ref_length=model.config.max_ref_len,
32
- sound_norm_refs=model.config.sound_norm_refs,
33
- )
34
-
35
- wav_chunks = []
36
- for chunk in model.inference_stream(
37
- text=sentence,
38
- language=language,
39
- gpt_cond_latent=gpt_cond_latent,
40
- speaker_embedding=speaker_embedding,
41
- temperature=model.config.temperature,
42
- length_penalty=model.config.length_penalty,
43
- repetition_penalty=model.config.repetition_penalty,
44
- top_k=model.config.top_k,
45
- top_p=model.config.top_p,
46
- ):
47
- if chunk is not None:
48
- wav_chunks.append(chunk)
49
-
50
- return (22050, torch.cat(wav_chunks, dim=0).unsqueeze(0)[0].numpy())
51
-
52
- demo = gr.Interface(
53
- title="XTTSv2-est Demo",
54
- description="To get the best results, provide a reference clip around the same length as the output sentence you want.",
55
- fn=predict,
56
- inputs=["text", gr.Dropdown(["et", "en", "es", "fr", "de", "it", "pt", "pl", "tr", "ru", "nl", "cs", "ar", "zh-cn", "hu", "ko", "ja", "hi"]), gr.File()],
57
- outputs=[gr.Audio()],
58
- )
59
-
60
- if __name__ == "__main__":
61
- demo.queue()
62
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
examples/LJ005-0214.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:74ca9692e2c4180768c0eb2de07c056f75425615d47f7c0fcfd8e31589a2e643
3
+ size 424294