MichaelChou0806 commited on
Commit
4946511
·
verified ·
1 Parent(s): 4491b95

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +84 -27
app.py CHANGED
@@ -4,7 +4,7 @@ from openai import OpenAI
4
  import gradio as gr
5
 
6
  # ========================
7
- # 🔐 使用者設定區(安全版本)
8
  # ========================
9
  PASSWORD = os.getenv("APP_PASSWORD", "defaultpass")
10
  MAX_SIZE = 25 * 1024 * 1024
@@ -31,56 +31,113 @@ def split_audio_if_needed(input_path):
31
  return chunk_files
32
 
33
  # ========================
34
- # 🎧 主功能:轉錄 + 摘要
35
  # ========================
36
- def transcribe_and_summarize(file):
 
 
37
  if not file:
38
- return "請上傳音訊檔。", ""
 
39
  chunks = split_audio_if_needed(file)
40
  transcripts = []
41
  for idx, f in enumerate(chunks, 1):
42
  with open(f, "rb") as audio_file:
43
  text = client.audio.transcriptions.create(
44
- model="whisper-1",
45
  file=audio_file,
46
  response_format="text"
47
  )
48
  transcripts.append(text)
49
  full_text = "\n".join(transcripts)
 
50
  response = client.chat.completions.create(
51
  model="gpt-4o-mini",
52
  messages=[
53
  {"role": "system", "content": "你是一位精準且擅長摘要的助手。"},
54
- {"role": "user", "content": "請用繁體中文摘要以下內容:\n" + full_text}
55
  ],
56
  temperature=0.4,
57
  )
58
  summary = response.choices[0].message.content.strip()
59
- return full_text, summary
60
 
61
  # ========================
62
- # 🔑 密碼驗證包裝
63
  # ========================
64
- def transcribe_with_password(password, file):
65
- if password != PASSWORD:
66
- return " 密碼錯誤,請重新輸入。", ""
67
- return transcribe_and_summarize(file)
 
 
 
 
 
 
 
 
68
 
69
  # ========================
70
  # 🌐 Gradio 介面
71
  # ========================
72
- iface = gr.Interface(
73
- fn=transcribe_with_password,
74
- inputs=[
75
- gr.Textbox(label="輸入密碼", type="password", placeholder="請輸入授權密碼"),
76
- gr.Audio(type="filepath", label="上傳音訊檔 (.m4a, .aac, .wav)")
77
- ],
78
- outputs=[
79
- gr.Textbox(label="完整轉錄文字", lines=10),
80
- gr.Textbox(label="摘要結果", lines=10)
81
- ],
82
- title="語音轉錄與摘要工具 (受密碼保護)",
83
- description="上傳音訊後,自動轉錄文字與產生摘要。請先輸入授權密碼以使用本服務。",
84
- )
85
-
86
- iface.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  import gradio as gr
5
 
6
  # ========================
7
+ # 🔐 使用者設定區(安全)
8
  # ========================
9
  PASSWORD = os.getenv("APP_PASSWORD", "defaultpass")
10
  MAX_SIZE = 25 * 1024 * 1024
 
31
  return chunk_files
32
 
33
  # ========================
34
+ # 🎧 轉錄 + 摘要
35
  # ========================
36
+ def transcribe_and_summarize(password, file, model_choice):
37
+ if password != PASSWORD:
38
+ return "❌ 密碼錯誤,請重新輸入。", "", ""
39
  if not file:
40
+ return "請上傳音訊檔。", "", ""
41
+
42
  chunks = split_audio_if_needed(file)
43
  transcripts = []
44
  for idx, f in enumerate(chunks, 1):
45
  with open(f, "rb") as audio_file:
46
  text = client.audio.transcriptions.create(
47
+ model=model_choice,
48
  file=audio_file,
49
  response_format="text"
50
  )
51
  transcripts.append(text)
52
  full_text = "\n".join(transcripts)
53
+
54
  response = client.chat.completions.create(
55
  model="gpt-4o-mini",
56
  messages=[
57
  {"role": "system", "content": "你是一位精準且擅長摘要的助手。"},
58
+ {"role": "user", "content": f"請用繁體中文摘要以下內容:\n{full_text}"}
59
  ],
60
  temperature=0.4,
61
  )
62
  summary = response.choices[0].message.content.strip()
63
+ return full_text, summary, "✅ 已完成轉錄與摘要"
64
 
65
  # ========================
66
+ # 💬 進一步問 AI
67
  # ========================
68
+ def ask_about_transcript(full_text, user_question):
69
+ if not full_text.strip():
70
+ return "⚠️ 尚未有轉錄內容,請先上傳音訊。"
71
+ if not user_question.strip():
72
+ return "請輸入想詢問的問題。"
73
+ prompt = f"以下是語音轉錄的完整內容:\n\n{full_text}\n\n使用者的問題是:{user_question}\n\n請以繁體中文回答。"
74
+ response = client.chat.completions.create(
75
+ model="gpt-4o-mini",
76
+ messages=[{"role": "user", "content": prompt}],
77
+ temperature=0.6,
78
+ )
79
+ return response.choices[0].message.content.strip()
80
 
81
  # ========================
82
  # 🌐 Gradio 介面
83
  # ========================
84
+ with gr.Blocks(theme=gr.themes.Soft(), css=".gr-button {font-size: 16px;} .copy-btn {background: #e0e0e0;}") as demo:
85
+ gr.Markdown("## 🎧 語音轉錄與摘要工具 (受密碼保護)")
86
+ gr.Markdown("上傳音訊後,自動轉錄文字並生成摘要。可進一步詢問 AI 關於對話內容。")
87
+
88
+ with gr.Row():
89
+ password_input = gr.Textbox(label="輸入密碼", type="password", placeholder="請輸入授權密碼")
90
+ model_choice = gr.Dropdown(
91
+ choices=["whisper-1", "gpt-4o-mini-transcribe"],
92
+ value="whisper-1",
93
+ label="選擇轉錄模型"
94
+ )
95
+
96
+ audio_input = gr.Audio(type="filepath", label="上傳音訊檔 (.m4a, .aac, .wav)")
97
+ transcribe_btn = gr.Button("開始轉錄與摘要 🚀")
98
+
99
+ status_box = gr.Textbox(label="狀態", interactive=False)
100
+
101
+ with gr.Row():
102
+ transcript_box = gr.Textbox(label="完整轉錄文字", lines=10)
103
+ copy_transcript = gr.Button("📋 複製", elem_classes="copy-btn")
104
+
105
+ with gr.Row():
106
+ summary_box = gr.Textbox(label="摘要結果", lines=10)
107
+ copy_summary = gr.Button("📋 複製", elem_classes="copy-btn")
108
+
109
+ with gr.Accordion("💬 進一步問 AI", open=False):
110
+ user_question = gr.Textbox(label="輸入你的問題(例如:我該如何回應?)", lines=2)
111
+ ask_btn = gr.Button("詢問 AI 🤔")
112
+ ai_reply = gr.Textbox(label="AI 回覆", lines=6)
113
+ copy_reply = gr.Button("📋 複製 AI 回覆", elem_classes="copy-btn")
114
+
115
+ # 事件綁定
116
+ transcribe_btn.click(
117
+ fn=transcribe_and_summarize,
118
+ inputs=[password_input, audio_input, model_choice],
119
+ outputs=[transcript_box, summary_box, status_box]
120
+ )
121
+
122
+ ask_btn.click(
123
+ fn=ask_about_transcript,
124
+ inputs=[transcript_box, user_question],
125
+ outputs=[ai_reply]
126
+ )
127
+
128
+ # 前端 JS 複製功能
129
+ copy_js = """
130
+ async (text) => {
131
+ try {
132
+ await navigator.clipboard.writeText(text);
133
+ alert("✅ 已複製到剪貼簿!");
134
+ } catch (err) {
135
+ alert("❌ 複製失敗:" + err);
136
+ }
137
+ }
138
+ """
139
+ copy_transcript.click(None, transcript_box, None, _js=copy_js)
140
+ copy_summary.click(None, summary_box, None, _js=copy_js)
141
+ copy_reply.click(None, ai_reply, None, _js=copy_js)
142
+
143
+ demo.launch()