MichaelChou0806 commited on
Commit
34eab1f
·
verified ·
1 Parent(s): 89d8668

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +47 -76
app.py CHANGED
@@ -1,120 +1,95 @@
1
- import os, shutil, base64, io
2
  from pydub import AudioSegment
3
  from openai import OpenAI
4
  import gradio as gr
5
 
6
- # 強制允許 base64 虛擬檔案
7
- if hasattr(gr, "processing_utils"):
8
- try:
9
- gr.processing_utils.ALLOW_DUPLICATE_UPLOADS = True
10
- except Exception:
11
- pass
12
- try:
13
- # 解除 Gradio FileData 的 path 限制
14
- import gradio.processing_utils as pu
15
- def _dummy_check_allowed(*a, **kw): return True
16
- pu._check_allowed = _dummy_check_allowed
17
- print("🔓 已解除 Gradio 上傳路徑限制")
18
- except Exception as e:
19
- print(f"⚠️ 無法解除限制: {e}")
20
 
21
- # ======================================================
22
- # 🔐 設定區
23
- # ======================================================
24
  PASSWORD = os.getenv("APP_PASSWORD", "chou")
25
  MAX_SIZE = 25 * 1024 * 1024
26
  client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
27
-
28
  print("===== 🚀 啟動中 =====")
29
- print(f"APP_PASSWORD: {'✅ 已載入' if PASSWORD else '❌ 未載入'}")
30
- print(f"目前密碼內容:{PASSWORD}")
31
 
32
- # ======================================================
33
- # 🎧 音訊轉錄核心
34
- # ======================================================
35
  def split_audio(path):
36
  size = os.path.getsize(path)
37
- if size <= MAX_SIZE:
38
- return [path]
39
  audio = AudioSegment.from_file(path)
40
  n = int(size / MAX_SIZE) + 1
41
- parts = []
42
  chunk_ms = len(audio) / n
 
43
  for i in range(n):
44
  fn = f"chunk_{i+1}.wav"
45
  audio[int(i*chunk_ms):int((i+1)*chunk_ms)].export(fn, format="wav")
46
- parts.append(fn)
47
- return parts
48
-
49
 
 
50
  def transcribe_core(path, model="whisper-1"):
51
  if path.lower().endswith(".mp4"):
52
  fixed = path[:-4] + ".m4a"
53
- try:
54
- shutil.copy(path, fixed)
55
- path = fixed
56
- except Exception as e:
57
- print(f"⚠️ mp4→m4a 失敗: {e}")
58
 
59
  chunks = split_audio(path)
60
- raw = []
61
- for c in chunks:
62
- with open(c, "rb") as af:
63
- txt = client.audio.transcriptions.create(
64
- model=model,
65
- file=af,
66
- response_format="text"
67
- )
68
- raw.append(txt)
69
- raw_txt = "\n".join(raw)
70
-
71
- # === 簡轉繁 ===
72
- conv = client.chat.completions.create(
73
  model="gpt-4o-mini",
74
  messages=[
75
  {"role":"system","content":"你是嚴格的繁體中文轉換器"},
76
- {"role":"user","content":f"將以下內容轉為台灣繁體,不意譯:\n{raw_txt}"}
77
- ],
78
- temperature=0.0)
79
- trad = conv.choices[0].message.content.strip()
80
 
81
- # === 摘要 ===
82
  summ = client.chat.completions.create(
83
  model="gpt-4o-mini",
84
  messages=[
85
  {"role":"system","content":"你是繁體摘要助手"},
86
  {"role":"user","content":f"用條列或一句話摘要:\n{trad}"}
87
- ],
88
- temperature=0.2)
89
- return trad, summ.choices[0].message.content.strip()
90
 
91
- # ======================================================
92
- # 💬 介面邏輯
93
- # ======================================================
94
  def transcribe(password, file):
95
  if password.strip() != PASSWORD:
96
  return "❌ 密碼錯誤", "", ""
97
  if not file:
98
  return "⚠️ 未選擇檔案", "", ""
99
 
100
- # ⚙️ file base64 資料
101
- if hasattr(file, "data") and isinstance(file.data, str) and file.data.startswith("data:audio"):
102
- base64_str = file.data.split(",")[1]
103
- audio_bytes = base64.b64decode(base64_str)
104
- temp_path = "uploaded_audio.m4a"
105
- with open(temp_path, "wb") as f:
106
- f.write(audio_bytes)
107
- file.name = temp_path
 
 
 
 
 
 
 
 
 
108
 
109
  text, summary = transcribe_core(file.name)
110
  return "✅ 完成", text, summary
111
 
112
-
113
- # ======================================================
114
- # 🖥️ Gradio 介面
115
- # ======================================================
116
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
117
- gr.Markdown("## 🎧 LINE 語音轉錄與摘要(Hugging Face 版)")
118
  pw = gr.Textbox(label="密碼", type="password")
119
  f = gr.File(label="上傳音訊檔")
120
  run = gr.Button("開始轉錄 🚀")
@@ -124,9 +99,5 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
124
  run.click(transcribe, [pw, f], [s, t, su])
125
 
126
  app = demo
127
-
128
- # ======================================================
129
- # 🚀 啟動
130
- # ======================================================
131
  if __name__ == "__main__":
132
  demo.launch(server_name="0.0.0.0", server_port=7860)
 
1
+ import os, shutil, base64
2
  from pydub import AudioSegment
3
  from openai import OpenAI
4
  import gradio as gr
5
 
6
+ # === 解鎖 Gradio 檔案限制 ===
7
+ import gradio.processing_utils as pu
8
+ def _dummy_check_allowed(*a, **kw): return True
9
+ pu._check_allowed = _dummy_check_allowed
10
+ print("🔓 已解除 Gradio 上傳路徑限制")
 
 
 
 
 
 
 
 
 
11
 
12
+ # === 設定 ===
 
 
13
  PASSWORD = os.getenv("APP_PASSWORD", "chou")
14
  MAX_SIZE = 25 * 1024 * 1024
15
  client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
 
16
  print("===== 🚀 啟動中 =====")
 
 
17
 
18
+ # === 分段 ===
 
 
19
  def split_audio(path):
20
  size = os.path.getsize(path)
21
+ if size <= MAX_SIZE: return [path]
 
22
  audio = AudioSegment.from_file(path)
23
  n = int(size / MAX_SIZE) + 1
 
24
  chunk_ms = len(audio) / n
25
+ files = []
26
  for i in range(n):
27
  fn = f"chunk_{i+1}.wav"
28
  audio[int(i*chunk_ms):int((i+1)*chunk_ms)].export(fn, format="wav")
29
+ files.append(fn)
30
+ return files
 
31
 
32
+ # === 核心轉錄 ===
33
  def transcribe_core(path, model="whisper-1"):
34
  if path.lower().endswith(".mp4"):
35
  fixed = path[:-4] + ".m4a"
36
+ try: shutil.copy(path, fixed); path = fixed
37
+ except Exception as e: print(f"⚠️ mp4→m4a 失敗: {e}")
 
 
 
38
 
39
  chunks = split_audio(path)
40
+ text_list = []
41
+ for f in chunks:
42
+ with open(f, "rb") as af:
43
+ txt = client.audio.transcriptions.create(model=model, file=af, response_format="text")
44
+ text_list.append(txt)
45
+ full_txt = "\n".join(text_list)
46
+
47
+ trad = client.chat.completions.create(
 
 
 
 
 
48
  model="gpt-4o-mini",
49
  messages=[
50
  {"role":"system","content":"你是嚴格的繁體中文轉換器"},
51
+ {"role":"user","content":f"將以下內容轉為台灣繁體,不意譯:\n{full_txt}"}
52
+ ], temperature=0.0).choices[0].message.content.strip()
 
 
53
 
 
54
  summ = client.chat.completions.create(
55
  model="gpt-4o-mini",
56
  messages=[
57
  {"role":"system","content":"你是繁體摘要助手"},
58
  {"role":"user","content":f"用條列或一句話摘要:\n{trad}"}
59
+ ], temperature=0.2).choices[0].message.content.strip()
60
+ return trad, summ
 
61
 
62
+ # === 外層驗證 ===
 
 
63
  def transcribe(password, file):
64
  if password.strip() != PASSWORD:
65
  return "❌ 密碼錯誤", "", ""
66
  if not file:
67
  return "⚠️ 未選擇檔案", "", ""
68
 
69
+ # 🔒 防呆處理 base64 與錯誤 path
70
+ temp_path = "uploaded_audio.m4a"
71
+ try:
72
+ if hasattr(file, "data") and isinstance(file.data, str) and file.data.startswith("data:audio"):
73
+ base64_str = file.data.split(",")[1]
74
+ with open(temp_path, "wb") as f:
75
+ f.write(base64.b64decode(base64_str))
76
+ file.name = temp_path
77
+ elif os.path.isdir(getattr(file, "name", "")):
78
+ print("⚠️ path 是資料夾,改用 base64")
79
+ base64_str = getattr(file, "data", "").split(",")[1]
80
+ with open(temp_path, "wb") as f:
81
+ f.write(base64.b64decode(base64_str))
82
+ file.name = temp_path
83
+ except Exception as e:
84
+ print(f"⚠️ base64 寫入失敗: {e}")
85
+ return f"❌ 上傳格式錯誤: {e}", "", ""
86
 
87
  text, summary = transcribe_core(file.name)
88
  return "✅ 完成", text, summary
89
 
90
+ # === Gradio UI ===
 
 
 
91
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
92
+ gr.Markdown("## 🎧 LINE 語音轉錄與摘要(Base64 安全版)")
93
  pw = gr.Textbox(label="密碼", type="password")
94
  f = gr.File(label="上傳音訊檔")
95
  run = gr.Button("開始轉錄 🚀")
 
99
  run.click(transcribe, [pw, f], [s, t, su])
100
 
101
  app = demo
 
 
 
 
102
  if __name__ == "__main__":
103
  demo.launch(server_name="0.0.0.0", server_port=7860)