benjamin5607 commited on
Commit
102cca0
ยท
verified ยท
1 Parent(s): b22fa4e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +53 -84
app.py CHANGED
@@ -1,121 +1,90 @@
1
- import gradio as gr
2
- import httpx
3
- import edge_tts
4
  import os
5
  import re
 
6
  import uuid
7
- import torch
8
- import numpy as np
9
  import scipy.io.wavfile
10
- import asyncio
 
11
  from transformers import pipeline
12
 
13
- # ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋กœ๋“œ ๋ฐ ๊ฒ€์ฆ
14
- GENAI_KEY = os.getenv("GEMINI_KEY")
 
15
 
16
- # ์Œ์•… ์ƒ์„ฑ ๋ชจ๋ธ ๋กœ๋“œ
17
  try:
18
  music_synthesiser = pipeline("text-to-audio", "facebook/musicgen-small")
19
  except Exception as e:
20
  print(f"Music Model Load Error: {e}")
21
  music_synthesiser = None
22
 
23
- # 8์ธ ๋ฉค๋ฒ„ ๋ฐ์ดํ„ฐ (์›๋ณธ ๋ณด์กด)
24
- MEMBERS = {
25
- "์„œ์œค (Korea)": { "voice": "ko-KR-SunHiNeural", "prompt": "๋ณด์ปฌ ์„œ์œค. ์‹œ๋‹ˆ์ปฌํ•˜์ง€๋งŒ ์ง„์‹ฌ์ž„." },
26
- "Chloe (USA)": { "voice": "en-US-AriaNeural", "prompt": "Guitarist Chloe. Cool rockstar vibe." },
27
- "Beatrice (Brazil)": { "voice": "pt-BR-FranciscaNeural", "prompt": "Drummer Beatrice. Rhythm focus." },
28
- "Naomi (Japan)": { "voice": "ja-JP-NanamiNeural", "prompt": "Naomi. Harmony focus." },
29
- "Elena (Spain)": { "voice": "es-ES-ElviraNeural", "prompt": "Elena. Groove focus." },
30
- "Amira (Egypt)": { "voice": "ar-EG-SalmaNeural", "prompt": "Amira. Atmosphere focus." },
31
- "Liwei (China)": { "voice": "zh-CN-XiaoxiaoNeural", "prompt": "Liwei. Sound design focus." },
32
- "Sophie (France)": { "voice": "fr-FR-DeniseNeural", "prompt": "Sophie. Melody focus." }
33
- }
34
-
35
  async def band_consulting(user_input, member_name, lang_code):
36
- # ๋ฆฌํ€˜์ŠคํŠธ๋ณ„ ๊ณ ์œ  ID ์ƒ์„ฑ (ํŒŒ์ผ ์ถฉ๋Œ ๋ฐฉ์ง€)
37
  req_id = str(uuid.uuid4())[:8]
38
  voice_path = f"/tmp/v_{req_id}.mp3"
39
  music_path = f"/tmp/m_{req_id}.wav"
40
 
41
- try:
42
- if not GENAI_KEY:
43
- raise ValueError("API Key is missing in Environment Variables")
 
 
 
 
 
 
44
 
45
- member_data = MEMBERS.get(member_name, MEMBERS["์„œ์œค (Korea)"])
46
- lang_map = {"ko":"Korean","en":"English","ja":"Japanese","pt":"Portuguese","es":"Spanish","ar":"Arabic","zh":"Chinese","fr":"French"}
47
- target_lang = lang_map.get(lang_code, "Korean")
48
-
49
- system_instruction = f"""
50
- ๋‹น์‹ ์€ '{member_name}'์ž…๋‹ˆ๋‹ค.
51
- 1. ๋ฐ˜๋“œ์‹œ {target_lang}๋กœ๋งŒ ๋‹ต๋ณ€ํ•˜์„ธ์š”.
52
- 2. ์Œ์„ฑ ๋‹ต๋ณ€์€ 5์ค„ ์ด๋‚ด ์š”์•ฝ, ์ƒ์„ธ ์„ค๋ช…/์•…๋ณด๋Š” [TAB]์— ๋„ฃ์œผ์„ธ์š”.
53
- 3. ๋งˆ์ง€๋ง‰์— [MUSIC: ์˜์–ด ํ”„๋กฌํ”„ํŠธ]๋ฅผ ํฌํ•จํ•˜์„ธ์š”.
54
- """
55
-
56
- # ๋น„๋™๊ธฐ HTTP ํด๋ผ์ด์–ธํŠธ ์‚ฌ์šฉ (Blocking ๋ฐฉ์ง€)
57
- url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key={GENAI_KEY}"
58
- payload = {"contents": [{"parts": [{"text": f"{system_instruction}\n์งˆ๋ฌธ: {user_input}"}]}]}
59
 
60
- async with httpx.AsyncClient() as client:
61
- response = await client.post(url, json=payload, timeout=25.0)
62
- res_data = response.json()
63
 
64
- if 'candidates' not in res_data:
65
- ai_text_raw = "์˜๊ฐ์ด ์ž ์‹œ ์ฐจ๋‹จ๋์–ด. ๋‹ค์‹œ ๋ฌผ์–ด๋ด์ค„๋ž˜? [TAB] API ์‘๋‹ต ์˜ค๋ฅ˜ [MUSIC: rock guitar riff]"
 
 
 
 
 
 
 
 
 
66
  else:
67
- ai_text_raw = res_data['candidates'][0]['content']['parts'][0]['text']
68
-
69
- # ์ •๊ทœํ‘œํ˜„์‹ ํŒŒ์‹ฑ (๋Œ€์†Œ๋ฌธ์ž ๋ฌด์‹œ ๋ฐ ์œ ์—ฐํ•œ ๋งค์นญ)
 
 
70
  tab_match = re.search(r'\[TAB\](.*?)(\[|$)', ai_text_raw, re.DOTALL | re.IGNORECASE)
71
  music_match = re.search(r'\[MUSIC:(.*?)\]', ai_text_raw, re.IGNORECASE)
72
 
73
- tab_display = tab_match.group(1).strip() if tab_match else "์ƒ์„ธ ์ •๋ณด ์—†์Œ"
74
  clean_text = re.sub(r'\[TAB\].*?(\[|$)', '', ai_text_raw, flags=re.DOTALL | re.IGNORECASE)
75
  clean_text = re.sub(r'\[MUSIC:.*?\]', '', clean_text, flags=re.IGNORECASE).strip()
76
 
77
- # TTS ์Œ์„ฑ ์ƒ์„ฑ
78
- tts_text = "\n".join(clean_text.split('\n')[:5])
79
- communicate = edge_tts.Communicate(re.sub(r'[\*\#\-\_\~\|]', '', tts_text), member_data['voice'])
80
- await communicate.save(voice_path)
 
 
81
 
82
- # ์Œ์•… ์ƒ์„ฑ (Blocking ๋ฐฉ์ง€ ์œ„ํ•ด ๋ณ„๋„ ์Šค๋ ˆ๋“œ ๊ณ ๋ ค ๊ฐ€๋Šฅํ•˜๋‚˜ Gradio Queue๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ์ง์ ‘ ์‹คํ–‰)
83
  if music_synthesiser:
84
- music_p = music_match.group(1).strip() if music_match else "rock music"
85
- # ๊ฐ€์ด๋“œ๋ผ์ธ ์œ„๋ฐ˜ ๋‹จ์–ด ์šฐํšŒ
86
- if any(x in music_p.lower() for x in ['laugh', 'vocal', 'voice', 'human']):
87
- music_p = "energetic rock electric guitar solo"
88
-
89
- # [MUSICGEN ์‹คํ–‰] - 512 ํ† ํฐ (์•ฝ 12์ดˆ)
90
- music_output = music_synthesiser(music_p, forward_params={"max_new_tokens": 512})
91
 
92
- # ์˜ค๋””์˜ค ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ (Float32 -> Int16)
93
- audio_tensor = music_output["audio"]
94
- if torch.is_tensor(audio_tensor):
95
- audio_data = audio_tensor.cpu().numpy()
96
- else:
97
- audio_data = np.array(audio_tensor)
98
-
99
- audio_data = np.squeeze(audio_data) # ์ฐจ์› ์••์ถ•
100
- audio_int16 = (audio_data * 32767).astype(np.int16) # ์ •๊ทœํ™”
101
  scipy.io.wavfile.write(music_path, music_output["sampling_rate"], audio_int16)
102
  else:
103
  music_path = None
104
 
105
- return tts_text, voice_path, music_path, tab_display
106
 
107
  except Exception as e:
108
- print(f"Critical Error: {e}")
109
- return f"System Overload: ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”. ({str(e)})", None, None, "Error"
110
-
111
- # Gradio Interface
112
- with gr.Blocks() as demo:
113
- # ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ๋‚ด๋ถ€ ํ†ต๋กœ
114
- i1 = gr.Textbox(visible=False); i2 = gr.Textbox(visible=False); i3 = gr.Textbox(visible=False)
115
- o1 = gr.Textbox(visible=False); o2 = gr.Audio(visible=False); o3 = gr.Audio(visible=False); o4 = gr.Textbox(visible=False)
116
-
117
- btn = gr.Button("GO", visible=False) # JS์—์„œ ํ˜ธ์ถœ์šฉ
118
- btn.click(band_consulting, [i1, i2, i3], [o1, o2, o3, o4], api_name="predict")
119
-
120
- # ํ ํ™œ์„ฑํ™” ๋ฐ ์‹คํ–‰
121
- demo.queue().launch(ssr_mode=False)
 
 
 
 
1
  import os
2
  import re
3
+ import requests
4
  import uuid
 
 
5
  import scipy.io.wavfile
6
+ import numpy as np
7
+ import torch
8
  from transformers import pipeline
9
 
10
+ # Hugging Face ํ† ํฐ ๋ฐ ๋ชจ๋ธ ์„ค์ •
11
+ HF_TOKEN = os.getenv("HF_TOKEN")
12
+ MODEL_ID = "Qwen/Qwen2.5-7B-Instruct"
13
 
14
+ # ์Œ์•… ๋ชจ๋ธ ๋กœ๋“œ (๊ธฐ์กด ์œ ์ง€)
15
  try:
16
  music_synthesiser = pipeline("text-to-audio", "facebook/musicgen-small")
17
  except Exception as e:
18
  print(f"Music Model Load Error: {e}")
19
  music_synthesiser = None
20
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  async def band_consulting(user_input, member_name, lang_code):
 
22
  req_id = str(uuid.uuid4())[:8]
23
  voice_path = f"/tmp/v_{req_id}.mp3"
24
  music_path = f"/tmp/m_{req_id}.wav"
25
 
26
+ # 1. Qwen์šฉ ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ ๊ตฌ์„ฑ (Gemini๋ณด๋‹ค ๋” ๊ฐ•๋ ฅํ•˜๊ฒŒ ์ง€์‹œ)
27
+ system_instruction = f"""
28
+ You are '{member_name}', a professional rock band member.
29
+ [Language Rules] Respond ONLY in {lang_code}.
30
+ [Output Format]
31
+ 1. Short advice (under 5 lines).
32
+ 2. Detailed sheet music/advice inside [TAB] tags.
33
+ 3. Music generation prompt inside [MUSIC: English Prompt] tags.
34
+ """
35
 
36
+ try:
37
+ # 2. Hugging Face Inference API ํ˜ธ์ถœ
38
+ api_url = f"https://api-inference.huggingface.co/models/{MODEL_ID}"
39
+ headers = {"Authorization": f"Bearer {HF_TOKEN}"}
 
 
 
 
 
 
 
 
 
 
40
 
41
+ prompt = f"<|im_start|>system\n{system_instruction}<|im_end|>\n<|im_start|>user\n{user_input}<|im_end|>\n<|im_start|>assistant\n"
 
 
42
 
43
+ payload = {
44
+ "inputs": prompt,
45
+ "parameters": {"max_new_tokens": 1024, "temperature": 0.7, "top_p": 0.9}
46
+ }
47
+
48
+ response = requests.post(api_url, headers=headers, json=payload, timeout=20)
49
+ res_json = response.json()
50
+
51
+ # ์‘๋‹ต์ด ๋น„์–ด์žˆ๊ฑฐ๋‚˜ ์—๋Ÿฌ์ผ ๊ฒฝ์šฐ 'Improv Mode' ๋ฐœ๋™
52
+ if not res_json or 'error' in res_json:
53
+ ai_text_raw = "์ด๋ด ๋ฆฌ๋”, ์ง€๊ธˆ์€ ๋ง๋ณด๋‹ค ์—ฐ์ฃผ๊ฐ€ ํ•„์š”ํ•œ ์ˆœ๊ฐ„์ด์•ผ! ๋‚ด ์ฆ‰ํฅ ์—ฐ์ฃผ๋ฅผ ๋“ค์–ด๋ด. [TAB] ์ฆ‰ํฅ ์—ฐ์ฃผ ๋ชจ๋“œ ๊ฐ€๋™ [MUSIC: aggressive hard rock guitar solo]"
54
  else:
55
+ # Qwen์€ ์ž…๋ ฅ ํ”„๋กฌํ”„ํŠธ๋ฅผ ํฌํ•จํ•ด์„œ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ assistant ์‘๋‹ต๋งŒ ์ถ”์ถœ
56
+ full_text = res_json[0]['generated_text']
57
+ ai_text_raw = full_text.split("assistant\n")[-1].strip()
58
+
59
+ # 3. ํŒŒ์‹ฑ ๋กœ์ง (Regex ๊ฐ•ํ™”)
60
  tab_match = re.search(r'\[TAB\](.*?)(\[|$)', ai_text_raw, re.DOTALL | re.IGNORECASE)
61
  music_match = re.search(r'\[MUSIC:(.*?)\]', ai_text_raw, re.IGNORECASE)
62
 
63
+ tab_display = tab_match.group(1).strip() if tab_match else "์˜ค๋Š˜์˜ ์ฆ‰ํฅ ์กฐ์–ธ: ๋А๋‚Œ๋Œ€๋กœ ์ณ๋ด!"
64
  clean_text = re.sub(r'\[TAB\].*?(\[|$)', '', ai_text_raw, flags=re.DOTALL | re.IGNORECASE)
65
  clean_text = re.sub(r'\[MUSIC:.*?\]', '', clean_text, flags=re.IGNORECASE).strip()
66
 
67
+ # ํ…์ŠคํŠธ๊ฐ€ ๋น„์–ด์žˆ์œผ๋ฉด Fallback
68
+ if len(clean_text) < 5:
69
+ clean_text = "๋ง์ด ํ•„์š” ์—†๋Š” ๋๋‚ด์ฃผ๋Š” ๋ผ์ธ์ด ์ƒ๊ฐ๋‚ฌ์–ด. ๋ฐ”๋กœ ๋“ค์–ด๋ณด์ž๊ณ !"
70
+
71
+ # 4. ์Œ์•… ์ƒ์„ฑ (MusicGen ์—ฐ๋™)
72
+ music_p = music_match.group(1).strip() if music_match else "energetic rock riff"
73
 
 
74
  if music_synthesiser:
75
+ # ์•ˆ์ „ ํ•„ํ„ฐ ๋‹จ์–ด ์šฐํšŒ (Vocal ๋“ฑ ์ฐจ๋‹จ ๋ฐฉ์ง€)
76
+ safe_p = re.sub(r'(laugh|vocal|voice|human)', 'rock guitar', music_p.lower())
77
+ music_output = music_synthesiser(safe_p, forward_params={"max_new_tokens": 512})
 
 
 
 
78
 
79
+ # ์˜ค๋””์˜ค ์ฒ˜๋ฆฌ (Float32 -> Int16)
80
+ audio_data = np.squeeze(music_output["audio"])
81
+ audio_int16 = (audio_data * 32767).astype(np.int16)
 
 
 
 
 
 
82
  scipy.io.wavfile.write(music_path, music_output["sampling_rate"], audio_int16)
83
  else:
84
  music_path = None
85
 
86
+ return clean_text, None, music_path, tab_display # voice_path๋Š” ํ•„์š”์‹œ edge_tts ์ถ”๊ฐ€
87
 
88
  except Exception as e:
89
+ print(f"Critical System Error: {e}")
90
+ return "์‹œ์Šคํ…œ ๊ณผ๋ถ€ํ•˜์ธ๊ฐ€? ํ•˜์ง€๋งŒ ๋ฝ์€ ๋ฉˆ์ถ”์ง€ ์•Š์•„! [MUSIC: basic rock drum beat]", None, None, "Retry Mode"