Lowking commited on
Commit
f1d02d3
·
verified ·
1 Parent(s): 34ca716

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +100 -94
main.py CHANGED
@@ -1,14 +1,15 @@
1
- from fastapi import FastAPI, HTTPException, WebSocket, WebSocketDisconnect
2
  from fastapi.middleware.cors import CORSMiddleware
3
- from gradio_client import Client, handle_file
4
- import tempfile
5
- import wave
6
  import base64
7
  import os
8
- import json
9
 
10
  app = FastAPI()
11
 
 
 
 
 
12
  app.add_middleware(
13
  CORSMiddleware,
14
  allow_origins=["*"],
@@ -17,16 +18,12 @@ app.add_middleware(
17
  )
18
 
19
  # ==========================================
20
- # 🔗 連結核心大腦 (依照您最順的 16 族配置)
21
  # ==========================================
22
- # 1. 翻譯大腦
23
  trans_client = Client("https://ai-labs.ilrdf.org.tw/kari-seejiq-tnpusu-ai-hmjil/")
24
- # 2. 語音合成大腦
25
  tts_client = Client("https://ai-labs.ilrdf.org.tw/hnang-kari-ai-asi-sluhay/")
26
- # 3. 語音辨識大腦 (最新 Kaldi 規格)
27
- asr_client = Client("https://ai-labs.ilrdf.org.tw/sapolita-kaldi/")
28
 
29
- # 🛠️ 您最順的解析工具
30
  def parse_dialect(dialect_result):
31
  if isinstance(dialect_result, dict) and 'value' in dialect_result:
32
  return dialect_result['value']
@@ -34,109 +31,118 @@ def parse_dialect(dialect_result):
34
  return dialect_result[0]
35
  return dialect_result
36
 
37
- @app.get("/")
38
- async def root():
39
- return {"message": "16 族全能雙語神獸正在運行中!"}
40
-
41
- # ==========================================
42
- # 🐉 核心進化:雅美語即時雙語字幕 (WebSocket)
43
- # ==========================================
44
- @app.websocket("/ws/subtitle")
45
- async def websocket_subtitle(websocket: WebSocket):
46
- await websocket.accept()
47
- audio_buffer = bytearray()
48
- # ✨ 鎖定剛才測試成功的正確代碼
49
- TAO_MT_CODE = "tao_Yami"
50
-
51
- try:
52
- while True:
53
- audio_chunk = await websocket.receive_bytes()
54
- audio_buffer.extend(audio_chunk)
55
-
56
- # 累積約 2.5 秒音訊進行辨識
57
- if len(audio_buffer) > 110000:
58
- with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as temp_wav:
59
- with wave.open(temp_wav.name, 'wb') as wav_file:
60
- wav_file.setnchannels(1)
61
- wav_file.setsampwidth(2)
62
- wav_file.setframerate(44100)
63
- wav_file.writeframes(audio_buffer)
64
- temp_path = temp_wav.name
65
-
66
- ind_text, zh_text = "", ""
67
- try:
68
- # 1. ASR 辨識
69
- asr_res = asr_client.predict(
70
- dialect_id="formosan_tao",
71
- audio_data=handle_file(temp_path),
72
- api_name="/automatic_speech_recognition"
73
- )
74
- ind_text = str(asr_res).strip()
75
-
76
- # 2. MT 翻譯 (鎖定 tao_Yami)
77
- if ind_text and ind_text != "...":
78
- zh_res = trans_client.predict(
79
- text=ind_text,
80
- src_lang=TAO_MT_CODE,
81
- tgt_lang="zho_Hant",
82
- api_name="/translate"
83
- )
84
- zh_text = str(zh_res)
85
- except Exception as e:
86
- print(f"⚠️ 即時處理錯誤: {e}")
87
-
88
- await websocket.send_json({
89
- "status": "recognizing",
90
- "indigenous": ind_text if ind_text else "...",
91
- "chinese": zh_text
92
- })
93
-
94
- audio_buffer = bytearray()
95
- if os.path.exists(temp_path): os.remove(temp_path)
96
- else:
97
- if len(audio_buffer) % 40 == 0:
98
- await websocket.send_json({"status": "buffering", "text": "🟢 神獸正在聽..."})
99
- except Exception: pass
100
-
101
  # ==========================================
102
- # 📚 保留您原本最順暢的 REST 功能 (16 族)
103
  # ==========================================
104
  @app.post("/translate")
105
  async def translate(data: dict):
106
  source_text = data.get("text")
107
- direction = data.get("direction", "zh2indigenous")
108
- ethnicity = data.get("ethnicity", "太魯閣")
 
109
  try:
 
110
  if direction in ["zh2trv", "zh2indigenous", "中翻族"]:
111
- dialect_code = parse_dialect(trans_client.predict(ethnicity=ethnicity, api_name="/lambda_1"))
112
- result = trans_client.predict(text=source_text, src_lang="zho_Hant", tgt_lang=dialect_code, api_name="/translate_1")
 
 
 
 
 
 
 
 
113
  else:
114
- dialect_code = parse_dialect(trans_client.predict(ethnicity=ethnicity, api_name="/lambda"))
115
- result = trans_client.predict(text=source_text, src_lang=dialect_code, tgt_lang="zho_Hant", api_name="/translate")
 
 
 
 
 
 
 
 
 
116
  return {"result": result}
117
- except Exception as e: return {"result": str(e)}
 
 
 
118
 
 
 
 
119
  @app.post("/get_speakers")
120
  async def get_speakers(data: dict):
 
121
  try:
122
- result = tts_client.predict(ethnicity=data.get("ethnicity", "太魯閣"), api_name="/lambda")
123
- speakers = [c[0] if isinstance(c, list) else c for c in result['choices']] if isinstance(result, dict) else result
 
 
 
124
  return {"speakers": speakers}
125
- except Exception as e: return {"error": str(e)}
 
 
126
 
 
 
 
127
  @app.post("/synthesize")
128
  async def synthesize(data: dict):
 
 
 
 
 
 
 
 
 
 
129
  try:
130
- text, ethnicity, req_speaker = data.get("text", ""), data.get("ethnicity", "太魯閣"), data.get("speaker", "太魯閣_男聲")
 
131
  speaker_choices = tts_client.predict(ethnicity=ethnicity, api_name="/lambda")
132
  full_list = [c[0] if isinstance(c, list) else c for c in speaker_choices['choices']]
133
- target_speaker = req_speaker if req_speaker in full_list else full_list[0]
134
- audio_path = tts_client.predict(ref=target_speaker, gen_text_input=text[:300], api_name="/default_speaker_tts")
135
- with open(audio_path, "rb") as f: encoded_audio = base64.b64encode(f.read()).decode('utf-8')
136
- os.remove(audio_path)
137
- return {"audio_base64": encoded_audio, "mime_type": "audio/wav"}
138
- except Exception as e: raise HTTPException(status_code=500, detail=str(e))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
 
140
  if __name__ == "__main__":
141
  import uvicorn
142
- uvicorn.run(app, host="0.0.0.0", port=7860)
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
  from fastapi.middleware.cors import CORSMiddleware
3
+ from gradio_client import Client
 
 
4
  import base64
5
  import os
 
6
 
7
  app = FastAPI()
8
 
9
+ @app.get("/")
10
+ async def root():
11
+ return {"message": "16 族語 AI 大師雲端大腦正在運行中!請透過 Chrome 套件呼叫 API。"}
12
+
13
  app.add_middleware(
14
  CORSMiddleware,
15
  allow_origins=["*"],
 
18
  )
19
 
20
  # ==========================================
21
+ # 🔗 連結原語會 AI 實驗室 (16 族雙大腦)
22
  # ==========================================
 
23
  trans_client = Client("https://ai-labs.ilrdf.org.tw/kari-seejiq-tnpusu-ai-hmjil/")
 
24
  tts_client = Client("https://ai-labs.ilrdf.org.tw/hnang-kari-ai-asi-sluhay/")
 
 
25
 
26
+ # 🛠️ 解析字典檔的小工具
27
  def parse_dialect(dialect_result):
28
  if isinstance(dialect_result, dict) and 'value' in dialect_result:
29
  return dialect_result['value']
 
31
  return dialect_result[0]
32
  return dialect_result
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  # ==========================================
35
+ # 📚 功能 A:16 族雙向文字翻譯 (✨ 已升級支援 16 族)
36
  # ==========================================
37
  @app.post("/translate")
38
  async def translate(data: dict):
39
  source_text = data.get("text")
40
+ direction = data.get("direction", "zh2indigenous") # 改為更通用的命名
41
+ ethnicity = data.get("ethnicity", "太魯閣") # ✨ 關鍵升級:動態接收族別
42
+
43
  try:
44
+ # 相容舊的 zh2trv 參數,確保原本的右鍵選單不會壞掉
45
  if direction in ["zh2trv", "zh2indigenous", "中翻族"]:
46
+ # 【中翻族】
47
+ dialect_result = trans_client.predict(ethnicity=ethnicity, api_name="/lambda_1")
48
+ dialect_code = parse_dialect(dialect_result)
49
+
50
+ result = trans_client.predict(
51
+ text=source_text,
52
+ src_lang="zho_Hant",
53
+ tgt_lang=dialect_code,
54
+ api_name="/translate_1"
55
+ )
56
  else:
57
+ # 【族翻中】
58
+ dialect_result = trans_client.predict(ethnicity=ethnicity, api_name="/lambda")
59
+ dialect_code = parse_dialect(dialect_result)
60
+
61
+ result = trans_client.predict(
62
+ text=source_text,
63
+ src_lang=dialect_code,
64
+ tgt_lang="zho_Hant",
65
+ api_name="/translate"
66
+ )
67
+
68
  return {"result": result}
69
+
70
+ except Exception as e:
71
+ print(f"❌ {ethnicity} 翻譯發生錯誤: {e}")
72
+ return {"result": f"API 呼叫失敗: {str(e)}"}
73
 
74
+ # ==========================================
75
+ # 📋 功能 B:獲取 16 族配音員名單
76
+ # ==========================================
77
  @app.post("/get_speakers")
78
  async def get_speakers(data: dict):
79
+ ethnicity = data.get("ethnicity", "太魯閣")
80
  try:
81
+ result = tts_client.predict(ethnicity=ethnicity, api_name="/lambda")
82
+ if isinstance(result, dict) and 'choices' in result:
83
+ speakers = [c[0] if isinstance(c, list) else c for c in result['choices']]
84
+ else:
85
+ speakers = result
86
  return {"speakers": speakers}
87
+ except Exception as e:
88
+ print(f"❌ 獲取名單失敗: {e}")
89
+ return {"error": str(e)}
90
 
91
+ # ==========================================
92
+ # 🎵 功能 C:16 族核心語音合成
93
+ # ==========================================
94
  @app.post("/synthesize")
95
  async def synthesize(data: dict):
96
+ text = data.get("text", "")
97
+ ethnicity = data.get("ethnicity", "太魯閣")
98
+ requested_speaker = data.get("speaker", "太魯閣_男聲")
99
+
100
+ if not text:
101
+ raise HTTPException(status_code=400, detail="請提供文字")
102
+
103
+ sanitized_text = text.replace("!", "!").replace("?", "?").replace(",", ",").replace("。", ".")
104
+ sanitized_text = sanitized_text.replace(":", ":").replace("(", "(").replace(")", ")")
105
+
106
  try:
107
+ print(f"🌍 處理族別:{ethnicity},選定:{requested_speaker}")
108
+
109
  speaker_choices = tts_client.predict(ethnicity=ethnicity, api_name="/lambda")
110
  full_list = [c[0] if isinstance(c, list) else c for c in speaker_choices['choices']]
111
+
112
+ if requested_speaker in full_list:
113
+ target_speaker = requested_speaker
114
+ else:
115
+ gender_keyword = "男聲" if "男聲" in requested_speaker else "女聲"
116
+ matches = [s for s in full_list if gender_keyword in s]
117
+ target_speaker = matches[0] if matches else full_list[0]
118
+
119
+ audio_filepath = tts_client.predict(
120
+ ref=target_speaker,
121
+ gen_text_input=sanitized_text[:300],
122
+ api_name="/default_speaker_tts"
123
+ )
124
+
125
+ if not os.path.exists(audio_filepath):
126
+ raise Exception("音檔生成失敗")
127
+
128
+ with open(audio_filepath, "rb") as audio_file:
129
+ encoded_audio = base64.b64encode(audio_file.read()).decode('utf-8')
130
+
131
+ try: os.remove(audio_filepath)
132
+ except: pass
133
+
134
+ return {
135
+ "audio_base64": encoded_audio,
136
+ "mime_type": "audio/wav",
137
+ "speaker_used": target_speaker
138
+ }
139
+
140
+ except Exception as e:
141
+ print(f"❌ 合成錯誤: {e}")
142
+ raise HTTPException(status_code=500, detail=str(e))
143
 
144
  if __name__ == "__main__":
145
  import uvicorn
146
+ port = int(os.environ.get("PORT", 8000))
147
+ print(f"🎬 正在啟動 16 族全能超級大腦 (Port {port})...")
148
+ uvicorn.run(app, host="0.0.0.0", port=port)