Maya1 مدلی برای تبدیل متن به صدا با احساس واقعی

ashafie 24 آبان 1404

Maya1 یک مدل گفتاری پیشرفته برای تولید صدای رسا برای ثبت احساسات واقعی انسان با طراحی دقیق صدا است.

شما می‌توانید از محیط اجرایی به آدرس زیر مراجعه کنید و به صورت برخط این مدل را استفاده کنید

https://www.mayaresearch.ai/studio

قابلیت ها

نمونه‌های آزمایشی Maya1

زن، حدوداً سی و چند ساله با لهجه آمریکایی و مجری مراسم، پرانرژی، با بیانی واضح
مرد، حدوداً بیست و چند ساله، آمریکایی خنثی، صدای باریتون گرم، ریتم آرام

مثال ۱: مجری زن پرانرژی رویداد
توضیح صدا:

Female, in her 30s with an American accent and is an event host, energetic, clear diction
زن، حدوداً سی و چند ساله با لهجه آمریکایی و مجری مراسم، پرانرژی، با بیانی واضح

متن:

Wow. This place looks even better than I imagined. How did they set all this up so perfectly? The lights, the music, everything feels magical. I can't stop smiling right now.
وای. این مکان حتی از چیزی که تصور می‌کردم هم بهتر به نظر می‌رسد. چطور همه اینها را اینقدر بی‌نقص چیده‌اند؟ نورها، موسیقی، همه چیز حس جادویی دارد. الان نمی‌توانم از لبخند زدن دست بردارم.

خروجی صدا:

مثال ۲: صدایی شرور و تاریک با خشم
توضیح صدا:

Dark villain character, Male voice in their 40s with a British accent. low pitch, gravelly timbre, slow pacing, angry tone at high intensity.
شخصیت شرور و تاریک، صدای مردانه حدوداً چهل و چند ساله با لهجه بریتانیایی. صدای بم، طنین زمخت، ریتم کند، لحن خشمگین با شدت بالا.

متن:

Welcome back to another episode of our podcast! <laugh_harder> Today we are diving into an absolutely fascinating topic
به قسمت دیگری از پادکست ما خوش آمدید! <خنده بیشتر> امروز به یک موضوع کاملاً جذاب می‌پردازیم.

خروجی صدا:

مثال ۳: شخصیت شیطانی (احساس جیغ)
توضیح صدا:

Demon character, Male voice in their 30s with a Middle Eastern accent. screaming tone at high intensity.
شخصیت شیطانی، صدای مرد حدوداً سی و چند ساله با لهجه خاورمیانه‌ای. لحن جیغ مانند با شدت بالا.

متن:

You dare challenge me, mortal <snort> how amusing. Your kind always thinks they can win
جرئت می‌کنی منو به چالش بکشی، فانی <پوزخند> چه بامزه. امثال تو همیشه فکر می‌کنن می‌تونن برنده بشن

خروجی صدا:

مثال ۴: الهه افسانه‌ای با احساسی از گریه
توضیح صدا:

Mythical godlike magical character, Female voice in their 30s slow pacing, curious tone at medium intensity.
شخصیت جادویی، خداگونه و اسطوره‌ای، صدای زنانه حدوداً سی و چند ساله با ریتم آهسته، لحنی کنجکاوانه با شدت متوسط.

متن:

After all we went through to pull him out of that mess <cry> I can't believe he was the traitor
بعد از همه اون سختی‌هایی که کشیدیم تا از اون مخمصه نجاتش بدیم باورم نمیشه که اون خائن بوده.

خروجی صدا:

ویژگی‌های مهم طراحی صدا


۱. کنترل صدای زبان طبیعی


صداها را طوری توصیف کنید که انگار به یک صداپیشه دستور می‌دهید:

<description="40-year-old, warm, low pitch, conversational">
<توصیف="40 ساله، خونگرم، با صدای بم، اهل گفتگو">

بدون پارامترهای پیچیده و بدون داده‌های آموزشی. فقط توصیف و تولید.

۲. برچسب‌های احساسی درون‌خطی برای بیان احساسات


احساسات را دقیقاً در جایی که به آن تعلق دارند در متن خود اضافه کنید:

Our new update <laugh> finally ships with the feature you asked for.
به‌روزرسانی جدید ما <خنده> بالاخره با قابلیتی که درخواست کرده بودید، ارائه شد.

احساسات پشتیبانی شده: 

۳. تولید صدای پیوسته


سنتز صدای بلادرنگ با کدک عصبی SNAC (~۰.۹۸ کیلوبیت بر ثانیه). ایده‌آل برای:


۴. زیرساخت آماده برای تولید

بارگیری و اجرا

تولید صدای با احساس
#!/usr/bin/env python3

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from snac import SNAC
import soundfile as sf
import numpy as np

CODE_START_TOKEN_ID = 128257
CODE_END_TOKEN_ID = 128258
CODE_TOKEN_OFFSET = 128266
SNAC_MIN_ID = 128266
SNAC_MAX_ID = 156937
SNAC_TOKENS_PER_FRAME = 7

SOH_ID = 128259
EOH_ID = 128260
SOA_ID = 128261
BOS_ID = 128000
TEXT_EOT_ID = 128009


def build_prompt(tokenizer, description: str, text: str) -> str:
    """Build formatted prompt for Maya1."""
    soh_token = tokenizer.decode([SOH_ID])
    eoh_token = tokenizer.decode([EOH_ID])
    soa_token = tokenizer.decode([SOA_ID])
    sos_token = tokenizer.decode([CODE_START_TOKEN_ID])
    eot_token = tokenizer.decode([TEXT_EOT_ID])
    bos_token = tokenizer.bos_token
    
    formatted_text = f'<description="{description}"> {text}'
    
    prompt = (
        soh_token + bos_token + formatted_text + eot_token +
        eoh_token + soa_token + sos_token
    )
    
    return prompt


def extract_snac_codes(token_ids: list) -> list:
    """Extract SNAC codes from generated tokens."""
    try:
        eos_idx = token_ids.index(CODE_END_TOKEN_ID)
    except ValueError:
        eos_idx = len(token_ids)
    
    snac_codes = [
        token_id for token_id in token_ids[:eos_idx]
        if SNAC_MIN_ID <= token_id <= SNAC_MAX_ID
    ]
    
    return snac_codes


def unpack_snac_from_7(snac_tokens: list) -> list:
    """Unpack 7-token SNAC frames to 3 hierarchical levels."""
    if snac_tokens and snac_tokens[-1] == CODE_END_TOKEN_ID:
        snac_tokens = snac_tokens[:-1]
    
    frames = len(snac_tokens) // SNAC_TOKENS_PER_FRAME
    snac_tokens = snac_tokens[:frames * SNAC_TOKENS_PER_FRAME]
    
    if frames == 0:
        return [[], [], []]
    
    l1, l2, l3 = [], [], []
    
    for i in range(frames):
        slots = snac_tokens[i*7:(i+1)*7]
        l1.append((slots[0] - CODE_TOKEN_OFFSET) % 4096)
        l2.extend([
            (slots[1] - CODE_TOKEN_OFFSET) % 4096,
            (slots[4] - CODE_TOKEN_OFFSET) % 4096,
        ])
        l3.extend([
            (slots[2] - CODE_TOKEN_OFFSET) % 4096,
            (slots[3] - CODE_TOKEN_OFFSET) % 4096,
            (slots[5] - CODE_TOKEN_OFFSET) % 4096,
            (slots[6] - CODE_TOKEN_OFFSET) % 4096,
        ])
    
    return [l1, l2, l3]


def main():
    
    # Load the best open source voice AI model
    print("\n[1/3] Loading Maya1 model...")
    model = AutoModelForCausalLM.from_pretrained(
        "maya-research/maya1", 
        torch_dtype=torch.bfloat16, 
        device_map="auto",
        trust_remote_code=True
    )
    tokenizer = AutoTokenizer.from_pretrained(
        "maya-research/maya1",
        trust_remote_code=True
    )
    print(f"Model loaded: {len(tokenizer)} tokens in vocabulary")
    
    # Load SNAC audio decoder (24kHz)
    print("\n[2/3] Loading SNAC audio decoder...")
    snac_model = SNAC.from_pretrained("hubertsiuzdak/snac_24khz").eval()
    if torch.cuda.is_available():
        snac_model = snac_model.to("cuda")
    print("SNAC decoder loaded")
    
    # Design your voice with natural language
    description = "Realistic male voice in the 30s age with american accent. Normal pitch, warm timbre, conversational pacing."
    text = "Hello! This is Maya1 <laugh_harder> the best open source voice AI model with emotions."
    
    print("\n[3/3] Generating speech...")
    print(f"Description: {description}")
    print(f"Text: {text}")
    
    # Create prompt with proper formatting
    prompt = build_prompt(tokenizer, description, text)
    
    # Debug: Show prompt details
    print(f"\nPrompt preview (first 200 chars):")
    print(f"   {repr(prompt[:200])}")
    print(f"   Prompt length: {len(prompt)} chars")
    
    # Generate emotional speech
    inputs = tokenizer(prompt, return_tensors="pt")
    print(f"   Input token count: {inputs['input_ids'].shape[1]} tokens")
    if torch.cuda.is_available():
        inputs = {k: v.to("cuda") for k, v in inputs.items()}
    
    with torch.inference_mode():
        outputs = model.generate(
            **inputs, 
            max_new_tokens=2048,  # Increase to let model finish naturally
            min_new_tokens=28,  # At least 4 SNAC frames
            temperature=0.4, 
            top_p=0.9, 
            repetition_penalty=1.1,  # Prevent loops
            do_sample=True,
            eos_token_id=CODE_END_TOKEN_ID,  # Stop at end of speech token
            pad_token_id=tokenizer.pad_token_id,
        )
    
    # Extract generated tokens (everything after the input prompt)
    generated_ids = outputs[0, inputs['input_ids'].shape[1]:].tolist()
    
    print(f"Generated {len(generated_ids)} tokens")
    
    # Debug: Check what tokens we got
    print(f"   First 20 tokens: {generated_ids[:20]}")
    print(f"   Last 20 tokens: {generated_ids[-20:]}")
    
    # Check if EOS was generated
    if CODE_END_TOKEN_ID in generated_ids:
        eos_position = generated_ids.index(CODE_END_TOKEN_ID)
        print(f" EOS token found at position {eos_position}/{len(generated_ids)}")
    
    # Extract SNAC audio tokens
    snac_tokens = extract_snac_codes(generated_ids)
    
    print(f"Extracted {len(snac_tokens)} SNAC tokens")
    
    # Debug: Analyze token types
    snac_count = sum(1 for t in generated_ids if SNAC_MIN_ID <= t <= SNAC_MAX_ID)
    other_count = sum(1 for t in generated_ids if t < SNAC_MIN_ID or t > SNAC_MAX_ID)
    print(f"   SNAC tokens in output: {snac_count}")
    print(f"   Other tokens in output: {other_count}")
    
    # Check for SOS token
    if CODE_START_TOKEN_ID in generated_ids:
        sos_pos = generated_ids.index(CODE_START_TOKEN_ID)
        print(f"   SOS token at position: {sos_pos}")
    else:
        print(f"   No SOS token found in generated output!")
    
    if len(snac_tokens) < 7:
        print("Error: Not enough SNAC tokens generated")
        return
    
    # Unpack SNAC tokens to 3 hierarchical levels
    levels = unpack_snac_from_7(snac_tokens)
    frames = len(levels[0])
    
    print(f"Unpacked to {frames} frames")
    print(f"   L1: {len(levels[0])} codes")
    print(f"   L2: {len(levels[1])} codes")
    print(f"   L3: {len(levels[2])} codes")
    
    # Convert to tensors
    device = "cuda" if torch.cuda.is_available() else "cpu"
    codes_tensor = [
        torch.tensor(level, dtype=torch.long, device=device).unsqueeze(0)
        for level in levels
    ]
    
    # Generate final audio with SNAC decoder
    print("\n[4/4] Decoding to audio...")
    with torch.inference_mode():
        z_q = snac_model.quantizer.from_codes(codes_tensor)
        audio = snac_model.decoder(z_q)[0, 0].cpu().numpy()
    
    # Trim warmup samples (first 2048 samples)
    if len(audio) > 2048:
        audio = audio[2048:]
    
    duration_sec = len(audio) / 24000
    print(f"Audio generated: {len(audio)} samples ({duration_sec:.2f}s)")
    
    # Save your emotional voice output
    output_file = "output.wav"
    sf.write(output_file, audio, 24000)
    print(f"\nVoice generated successfully!")


if __name__ == "__main__":
    main()
تولید صدای بی وقفه با vLLM

برای استقرارهای عملیاتی با پخش زنده (استریم) در لحظه، از اسکریپت vLLM استفاده کنید:

https://huggingface.co/maya-research/maya1/blob/main/vllm_streaming_inference.py

ویژگی‌های کلیدی:

برتری فنی


معماری Maya1 : پایه مدل لاما با پارامتر ۳B برای صدا


یک transformer فقط-رمزگشای ۳B پارامتر (به سبک لاما) را از قبل آموزش دادند تا به جای شکل موج‌های خام، توکن‌های کدک عصبی SNAC را پیش‌بینی کند.

جریان پردازش:

<description="..."> text → tokenize → generate SNAC codes (7 tokens/frame) → decode → 24 kHz audio

چرا SNAC؟ ساختار سلسله مراتبی چند مقیاسی (≈12/23/47 هرتز) توالی‌های خودهمبسته را برای پخش همزمان با سرعت تقریبی 0.98 کیلوبیت بر ثانیه فشرده نگه می‌دارد.

داده‌های آموزشی: آن‌چه هوش مصنوعی صدا را به بهترین تبدیل می‌کند
پیش‌آموزش: پیکره گفتار انگلیسی در مقیاس اینترنتی برای پوشش صوتی گسترده و هم‌بیانی طبیعی.

آموزش بهینه نظارت شده(Supervised Fine-Tuning): مجموعه داده‌های اختصاصی از ضبط‌های استودیویی با:

برتری جریان داده:
  1. نمونه‌برداری مجدد مونو 24 کیلوهرتز با نرمال‌سازی LUFS -23
  2. ترمیم سکوت VAD با محدوده‌های زمانی (1-14 ثانیه)
  3. هم‌ترازی اجباری (MFA) برای مرزهای عبارت تمیز
  4. حذف تکرار متن MinHash-LSH
  5. حذف تکرار صوتی Chromaprint
  6. رمزگذاری SNAC با بسته‌بندی فریم 7 توکنی

آزمایش‌های طراحی صدا: چرا زبان طبیعی برنده شد


۴ قالب شرطی‌سازی را آزمایش شدند و فقط یکی از آنها نتایج با کیفیت تولید ارائه داد:

❌ قالب دو نقطه‌ای: {description}: {text} . تغییر قالب و توضیحات مدل گفتار

❌ ویژگی‌های لیست زاویه: <{age}، {pitch}، {character}> – خیلی سفت و سخت و تعمیم ضعیف

❌ برچسب‌های کلید و مقدار:  <age=40><pitch=low> تورم توکن، شکننده در برابر اشتباهات

✅ ویژگی XML (برنده): <description=”40-yr old, low-pitch, warm”>- زبان طبیعی و قوی و مقیاس‌پذیر

موارد استفاده


صداهای شخصیت‌های بازی


صداهای منحصر به فرد شخصیت‌ها را با احساسات در لحظه تولید می‌کند. بدون جلسات ضبط صداپیشه.

تولید پادکست و کتاب صوتی


روایت محتوا با دامنه احساسی و شخصیت‌های سازگار در طول ساعت‌ها صدا.

دستیارهای صوتی هوش مصنوعی


ساخت عامل های مکالمه‌ای با پاسخ‌های عاطفی طبیعی در زمان واقعی.

تولید محتوای ویدیویی


ایجاد صداگذاری برای یوتیوب، تیک‌تاک و رسانه‌های اجتماعی با ارائه رسا.

هوش مصنوعی خدمات مشتری


استقرار ربات‌های صوتی همدل که زمینه را درک می‌کنند و با احساسات مناسب پاسخ می‌دهند.

ابزارهای دسترسی


ساخت صفحه‌خوان‌ها و فناوری‌های کمکی با صداهای طبیعی و جذاب.

سوالات متداول


سؤال: چه چیزی Maya1 را متفاوت می‌کند؟
پاسخ: تنها مدل متن‌بازی هست که بیش از ۲۰ نوع احساس، طراحی صدای بدون نقص، استریم آماده برای تولید و پارامترهای ۳B را ارائه می‌دهد. همه در یک بسته.

سؤال: آیا می‌توانم از این به صورت تجاری استفاده کنم؟
پاسخ: کاملاً. مجوز آپاچی ۲.۰. ساخت محصولات، استقرار خدمات، کسب درآمد رایگان.

سؤال: از چه زبان‌هایی پشتیبانی می‌کند؟
پاسخ: در حال حاضر انگلیسی با پشتیبانی از چند لهجه. مدل‌های آینده به زبان‌ها و لهجه‌هایی که توسط هوش مصنوعی های حوزه صدای رایج پشتیبانی نمی‌شوند، گسترش خواهند یافت.

سؤال: چگونه با ElevenLabs، Murf.ai یا سایر ابزارهای متن‌باز مقایسه می‌شود؟
پاسخ: برابری ویژگی‌ها با احساسات و طراحی صدا. مزیت: شما مالک استقرار هستید، هیچ هزینه‌ای برای هر ثانیه پرداخت نمی‌کنید و می‌توانید مدل را سفارشی کنید.

سؤال: آیا می‌توانم صدای خودم را fine tune کنم؟
پاسخ: بله. معماری مدل از fine tune روی مجموعه داده‌های سفارشی برای صداهای تخصصی پشتیبانی می‌کند.

سؤال: به چه پردازنده گرافیکی نیاز دارم؟
پاسخ: یک پردازنده گرافیکی با ۱۶ گیگابایت یا بیشتر حافظه گرافیکی (A100، H100 یا RTX 4090 مخصوص مصرف‌کننده).

سؤال: آیا استریمینگ واقعاً بلادرنگ است؟
پاسخ: بله. کدک SNAC با استقرار vLLM تأخیر زیر ۱۰۰ میلی‌ثانیه را امکان‌پذیر می‌کند.

مقایسه

ویژگیMaya1ElevenLabsOpenAI TTSCoqui TTS
متن بازبلهخیرخیربله
احساسات20+محدودخیرخیر
طراحی صوتزبان طبیعیکتابخانه صوتیثابتمجتمع
استریمینگبلادرنگبلهبلهخیر
هزینهرایگانپرداخت بر استفادهپرداخت بر استفادهرایگان
شخصی سازیکاملمحدودهیچ کداممتوسظ
پارامترها3Bناشناختهناشناخته<1B

استفاده

مرجع مدل Hugging Face
# Clone the model repository
git lfs install
git clone https://huggingface.co/maya-research/maya1

# Or load directly in Python
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("maya-research/maya1")
پیش نیاز ها
pip install torch transformers snac soundfile

منابع تکمیلی

لیست تمامی احساسات:
https://huggingface.co/maya-research/maya1/blob/main/emotions.txt

نمونه پرامپت:
https://huggingface.co/maya-research/maya1/blob/main/prompt.txt

متن کد استریم:
https://huggingface.co/maya-research/maya1/blob/main/vllm_streaming_inference.py

منبع

https://huggingface.co

نظرات بسته شده است