MichaelChou0806 commited on
Commit
eee7f73
·
verified ·
1 Parent(s): b2e700d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +52 -41
app.py CHANGED
@@ -4,12 +4,14 @@ import shutil
4
  from pydub import AudioSegment
5
  from openai import OpenAI
6
  import gradio as gr
7
- from fastapi import HTTPException
 
 
8
 
9
  # ======================================================
10
  # 🔐 設定區
11
  # ======================================================
12
- PASSWORD = os.getenv("APP_PASSWORD", "defaultpass")
13
  MAX_SIZE = 25 * 1024 * 1024
14
  client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
15
 
@@ -25,77 +27,82 @@ def split_audio_if_needed(path):
25
  if size <= MAX_SIZE:
26
  return [path]
27
  audio = AudioSegment.from_file(path)
28
- num = int(size / MAX_SIZE) + 1
29
- chunk_ms = len(audio) / num
30
- files = []
31
- for i in range(num):
32
- start, end = int(i * chunk_ms), int((i + 1) * chunk_ms)
33
- chunk = audio[start:end]
34
  fn = f"chunk_{i+1}.wav"
35
- chunk.export(fn, format="wav")
36
- files.append(fn)
37
- return files
38
 
39
  def transcribe_core(path, model="whisper-1"):
40
- if path and path.lower().endswith(".mp4"):
41
- fixed_path = path[:-4] + ".m4a"
42
  try:
43
- shutil.copy(path, fixed_path)
44
- path = fixed_path
45
- print("🔧 已自動修正 mp4 → m4a")
46
  except Exception as e:
47
  print(f"⚠️ mp4→m4a 轉檔失敗:{e}")
48
 
49
  chunks = split_audio_if_needed(path)
50
- raw_parts = []
51
  for f in chunks:
52
  with open(f, "rb") as af:
53
- res = client.audio.transcriptions.create(
54
- model=model,
55
- file=af,
56
- response_format="text"
57
- )
58
- raw_parts.append(res)
59
- full_raw = "\n".join(raw_parts)
60
 
61
- # 簡轉繁
62
  conv_prompt = (
63
  "請將以下內容完整轉換為「繁體中文(台灣用語)」:\n"
64
- "規則:1) 僅做簡→繁字形轉換;2) 不要意譯或改寫;3) 不要添加任何前後綴。\n"
65
- "-----\n" + full_raw
66
  )
67
- trad_resp = client.chat.completions.create(
68
  model="gpt-4o-mini",
69
  messages=[
70
- {"role": "system", "content": "你是嚴格的繁體中文轉換器,只進行字形轉換。"},
71
  {"role": "user", "content": conv_prompt}
72
  ],
73
  temperature=0.0,
74
- )
75
- full_trad = trad_resp.choices[0].message.content.strip()
76
 
77
- # 摘要
78
  sum_prompt = (
79
- "請用台灣繁體中文撰寫摘要。若內容資訊多,可條列出重點;若內容簡短,請用一句話概述即可。\n\n"
80
- + full_trad
81
  )
82
- sum_resp = client.chat.completions.create(
83
  model="gpt-4o-mini",
84
  messages=[
85
  {"role": "system", "content": "你是一位精準且嚴格使用台灣繁體中文的摘要助手。"},
86
  {"role": "user", "content": sum_prompt}
87
  ],
88
  temperature=0.2,
89
- )
90
- summ = sum_resp.choices[0].message.content.strip()
91
- return full_trad, summ
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
  # ======================================================
94
  # 💬 Gradio 介面
95
  # ======================================================
96
  def transcribe_with_password(password, file):
97
  if password.strip() != PASSWORD:
98
- raise HTTPException(status_code=403, detail="密碼錯誤 ")
99
  if not file:
100
  return "⚠️ 未選擇檔案", "", ""
101
  text, summary = transcribe_core(file.name)
@@ -114,7 +121,11 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
114
  # ======================================================
115
  # 🚀 啟動
116
  # ======================================================
 
 
 
 
 
 
117
  if __name__ == "__main__":
118
  demo.launch(server_name="0.0.0.0", server_port=7860)
119
- else:
120
- demo.launch()
 
4
  from pydub import AudioSegment
5
  from openai import OpenAI
6
  import gradio as gr
7
+ from fastapi import FastAPI, UploadFile, File, Form
8
+ from threading import Thread
9
+ import uvicorn
10
 
11
  # ======================================================
12
  # 🔐 設定區
13
  # ======================================================
14
+ PASSWORD = os.getenv("APP_PASSWORD", "chou")
15
  MAX_SIZE = 25 * 1024 * 1024
16
  client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
17
 
 
27
  if size <= MAX_SIZE:
28
  return [path]
29
  audio = AudioSegment.from_file(path)
30
+ n = int(size / MAX_SIZE) + 1
31
+ chunk_ms = len(audio) / n
32
+ parts = []
33
+ for i in range(n):
 
 
34
  fn = f"chunk_{i+1}.wav"
35
+ audio[int(i * chunk_ms):int((i + 1) * chunk_ms)].export(fn, format="wav")
36
+ parts.append(fn)
37
+ return parts
38
 
39
  def transcribe_core(path, model="whisper-1"):
40
+ if path.lower().endswith(".mp4"):
41
+ fixed = path[:-4] + ".m4a"
42
  try:
43
+ shutil.copy(path, fixed)
44
+ path = fixed
 
45
  except Exception as e:
46
  print(f"⚠️ mp4→m4a 轉檔失敗:{e}")
47
 
48
  chunks = split_audio_if_needed(path)
49
+ txts = []
50
  for f in chunks:
51
  with open(f, "rb") as af:
52
+ res = client.audio.transcriptions.create(model=model, file=af, response_format="text")
53
+ txts.append(res)
54
+ full_raw = "\n".join(txts)
 
 
 
 
55
 
 
56
  conv_prompt = (
57
  "請將以下內容完整轉換為「繁體中文(台灣用語)」:\n"
58
+ "規則:1) 僅做簡→繁字形轉換;2) 不要意譯或改寫;3) 不要添加任何前後綴。\n-----\n" + full_raw
 
59
  )
60
+ trad = client.chat.completions.create(
61
  model="gpt-4o-mini",
62
  messages=[
63
+ {"role": "system", "content": "你是嚴格的繁體中文轉換器。"},
64
  {"role": "user", "content": conv_prompt}
65
  ],
66
  temperature=0.0,
67
+ ).choices[0].message.content.strip()
 
68
 
 
69
  sum_prompt = (
70
+ "請用台灣繁體中文撰寫摘要。若內容資訊多,可條列出重點;"
71
+ "若內容簡短,請用一句話概述即可。\n\n" + trad
72
  )
73
+ summ = client.chat.completions.create(
74
  model="gpt-4o-mini",
75
  messages=[
76
  {"role": "system", "content": "你是一位精準且嚴格使用台灣繁體中文的摘要助手。"},
77
  {"role": "user", "content": sum_prompt}
78
  ],
79
  temperature=0.2,
80
+ ).choices[0].message.content.strip()
81
+
82
+ return trad, summ
83
+
84
+ # ======================================================
85
+ # 🌐 FastAPI for 捷徑
86
+ # ======================================================
87
+ api_app = FastAPI()
88
+
89
+ @api_app.post("/api/transcribe")
90
+ async def api_transcribe(file: UploadFile = File(...), token: str = Form(...)):
91
+ if token != PASSWORD:
92
+ return {"error": "Invalid token"}
93
+ temp = file.filename
94
+ with open(temp, "wb") as f:
95
+ f.write(await file.read())
96
+ text, summary = transcribe_core(temp)
97
+ os.remove(temp)
98
+ return {"text": text, "summary": summary}
99
 
100
  # ======================================================
101
  # 💬 Gradio 介面
102
  # ======================================================
103
  def transcribe_with_password(password, file):
104
  if password.strip() != PASSWORD:
105
+ return "❌ 密碼錯誤", "", ""
106
  if not file:
107
  return "⚠️ 未選擇檔案", "", ""
108
  text, summary = transcribe_core(file.name)
 
121
  # ======================================================
122
  # 🚀 啟動
123
  # ======================================================
124
+ def run_api():
125
+ uvicorn.run(api_app, host="0.0.0.0", port=7861)
126
+
127
+ Thread(target=run_api, daemon=True).start()
128
+ app = demo # ✅ Hugging Face 主入口使用 Gradio
129
+
130
  if __name__ == "__main__":
131
  demo.launch(server_name="0.0.0.0", server_port=7860)