File size: 4,431 Bytes
da89e23
8ee2277
b22fa4e
102cca0
5884655
 
 
13bbb40
 
5884655
13bbb40
 
 
 
 
da89e23
5884655
 
 
 
eef5842
5884655
 
 
13bbb40
5884655
 
13bbb40
5884655
 
8ee2277
5884655
 
13bbb40
 
5884655
 
 
 
 
 
 
 
13bbb40
 
 
 
 
 
 
 
7483917
b22fa4e
13bbb40
b22fa4e
 
13bbb40
5884655
 
13bbb40
5884655
 
 
13bbb40
 
 
5884655
13bbb40
 
102cca0
13bbb40
5884655
13bbb40
 
 
102cca0
13bbb40
5884655
 
 
 
 
13bbb40
 
 
 
 
 
102cca0
13bbb40
5884655
13bbb40
 
 
 
 
102cca0
13bbb40
d400633
5884655
13bbb40
 
 
25c52a1
5884655
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import os
import re
import uuid
import torch
import numpy as np
import scipy.io.wavfile
import gradio as gr
import edge_tts
import asyncio
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
from groq import Groq

# API ν‚€ 및 ν™˜κ²½ μ„€μ •
GENAI_KEY = os.getenv("GEMINI_KEY") # κΈ°μ‘΄ ν‚€ μœ μ§€ μ‹œ
GROQ_API_KEY = os.getenv("GROQ_API_KEY")

class ModelManager:
    _llm_pipeline = None
    _music_pipeline = None
    _groq_client = None

    @classmethod
    def get_qwen(cls):
        if cls._llm_pipeline is None:
            # CPU μ΅œμ ν™” 버전 Qwen 0.5B
            model_id = "Qwen/Qwen2.5-0.5B-Instruct"
            tokenizer = AutoTokenizer.from_pretrained(model_id)
            model = AutoModelForCausalLM.from_pretrained(model_id, device_map="cpu", torch_dtype=torch.float32)
            cls._llm_pipeline = pipeline("text-generation", model=model, tokenizer=tokenizer)
        return cls._llm_pipeline

    @classmethod
    def get_groq(cls):
        if cls._groq_client is None and GROQ_API_KEY:
            cls._groq_client = Groq(api_key=GROQ_API_KEY)
        return cls._groq_client

    @classmethod
    def get_music(cls):
        if cls._music_pipeline is None:
            cls._music_pipeline = pipeline("text-to-audio", "facebook/musicgen-small", device="cpu")
        return cls._music_pipeline

# 8인 멀버 보이슀 λ§€ν•‘
MEMBERS_VOICE = {
    "μ„œμœ€ (Korea)": "ko-KR-SunHiNeural", "Chloe (USA)": "en-US-AriaNeural", 
    "Naomi (Japan)": "ja-JP-NanamiNeural", "Beatrice (Brazil)": "pt-BR-FranciscaNeural",
    "Elena (Spain)": "es-ES-ElviraNeural", "Amira (Egypt)": "ar-EG-SalmaNeural",
    "Liwei (China)": "zh-CN-XiaoxiaoNeural", "Sophie (France)": "fr-FR-DeniseNeural"
}

async def band_consulting(user_input, member_name, lang_code):
    req_id = str(uuid.uuid4())[:8]
    voice_path = f"/tmp/v_{req_id}.mp3"
    music_path = f"/tmp/m_{req_id}.wav"
    
    system_prompt = f"당신은 λ°΄λ“œ 멀버 {member_name}μž…λ‹ˆλ‹€. {lang_code}둜 λ‹΅λ³€ν•˜μ„Έμš”. 5쀄 이내 μš”μ•½, 상세 μ„€λͺ…은 [TAB]에, μŒμ•… ν”„λ‘¬ν”„νŠΈλŠ” [MUSIC: μ˜μ–΄ν”„λ‘¬ν”„νŠΈ]에 λ„£μœΌμ„Έμš”."
    
    ai_text_raw = ""
    # 1. Groq μ‹œλ„
    groq_client = ModelManager.get_groq()
    if groq_client:
        try:
            res = groq_client.chat.completions.create(
                messages=[{"role": "system", "content": system_prompt}, {"role": "user", "content": user_input}],
                model="llama-3.3-70b-versatile"
            )
            ai_text_raw = res.choices[0].message.content
        except: pass

    # 2. 둜컬 Qwen Fallback
    if not ai_text_raw:
        qwen = ModelManager.get_qwen()
        out = qwen(f"<|im_start|>system\n{system_prompt}<|im_end|>\n<|im_start|>user\n{user_input}<|im_end|>\nassistant\n", max_new_tokens=512)
        ai_text_raw = out[0]['generated_text'].split("assistant\n")[-1]

    # νŒŒμ‹±
    tab_match = re.search(r'\[TAB\](.*?)(\[|$)', ai_text_raw, re.DOTALL | re.IGNORECASE)
    music_match = re.search(r'\[MUSIC:(.*?)\]', ai_text_raw, re.IGNORECASE)
    tab_display = tab_match.group(1).strip() if tab_match else "상세 악보 μ€€λΉ„ 쀑..."
    clean_text = re.sub(r'\[TAB\].*?(\[|$)', '', ai_text_raw, flags=re.DOTALL | re.IGNORECASE)
    clean_text = re.sub(r'\[MUSIC:.*?\]', '', clean_text, flags=re.IGNORECASE).strip()
    
    # 3. TTS μŒμ„± 생성 (볡ꡬ)
    tts_text = "\n".join(clean_text.split('\n')[:5])
    voice_name = MEMBERS_VOICE.get(member_name, "ko-KR-SunHiNeural")
    communicate = edge_tts.Communicate(re.sub(r'[\*\#\-\_\~\|]', '', tts_text), voice_name)
    await communicate.save(voice_path)

    # 4. μŒμ•… 생성 (길이 μ—°μž₯: 512 토큰 = μ•½ 12초)
    music_gen = ModelManager.get_music()
    music_p = music_match.group(1).strip() if music_match else "energetic rock guitar solo"
    music_output = music_gen(music_p, forward_params={"max_new_tokens": 512})
    audio_data = np.squeeze(music_output["audio"])
    audio_int16 = (audio_data * 32767).astype(np.int16)
    scipy.io.wavfile.write(music_path, music_output["sampling_rate"], audio_int16)

    return tts_text, voice_path, music_path, tab_display

with gr.Blocks() as demo:
    i1 = gr.Textbox(); i2 = gr.Textbox(); i3 = gr.Textbox()
    o1 = gr.Textbox(); o2 = gr.Audio(); o3 = gr.Audio(); o4 = gr.Textbox()
    btn = gr.Button("GO"); btn.click(band_consulting, [i1, i2, i3], [o1, o2, o3, o4], api_name="predict")

demo.queue().launch()