Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import openai | |
| from pydub import AudioSegment | |
| import os | |
| import re | |
| # 轉譯音檔函式,使用 OpenAI Whisper 模型 | |
| def transcribe(filename, api_key): | |
| client = openai.OpenAI(api_key=api_key) | |
| with open(filename, "rb") as audio_file: | |
| transcript_txt = client.audio.transcriptions.create( | |
| model="whisper-1", | |
| file=audio_file, | |
| response_format="text" | |
| ) | |
| return transcript_txt | |
| # 檢查檔案大小並分段處理(若檔案過大) | |
| def transcribe_large_audio(filename, api_key, segment_length_ms=30 * 60 * 1000): | |
| def get_file_size_in_mb(file_path): | |
| return os.path.getsize(file_path) / (1024 * 1024) | |
| def split_audio_file(file_path, segment_length_ms=30 * 60 * 1000): | |
| audio = AudioSegment.from_file(file_path, format="mp3") | |
| segment_filenames = [] | |
| for i in range(0, len(audio), segment_length_ms): | |
| end = min(i + segment_length_ms, len(audio)) | |
| segment = audio[i:end] | |
| segment_filename = f"{file_path}_part{len(segment_filenames) + 1}.mp3" | |
| segment.export(segment_filename, format="mp3", bitrate="36k") | |
| segment_filenames.append(segment_filename) | |
| return segment_filenames | |
| transcript_txt = "" | |
| if get_file_size_in_mb(filename) > 25: | |
| audio_chunks = split_audio_file(filename) | |
| for chunk_filename in audio_chunks: | |
| transcript_txt += transcribe(chunk_filename, api_key) | |
| os.remove(chunk_filename) | |
| else: | |
| transcript_txt = transcribe(filename, api_key) | |
| return transcript_txt | |
| # 字數統計函式 | |
| def count_words(text): | |
| # 移除空白字符後計算字數 | |
| cleaned_text = re.sub(r'\s+', '', text) | |
| return len(cleaned_text) | |
| # 自動斷句與標點符號功能 | |
| def auto_punctuate(text, api_key): | |
| openai.api_key = api_key | |
| prompt = """請幫我將以下逐字稿加入適當的標點符號和段落分隔,使文本更容易閱讀: | |
| 原文: | |
| """ + text | |
| completion = openai.chat.completions.create( | |
| model="gpt-4", | |
| messages=[{"role": "user", "content": prompt}] | |
| ) | |
| return completion.choices[0].message.content | |
| # OpenAI 翻譯文本的函式 | |
| def openai_translate_text(text, target_lang, api_key): | |
| openai.api_key = api_key | |
| language_mapping = { | |
| "繁體中文": "繁體中文", | |
| "英文": "英文", | |
| "日文": "日文", | |
| "韓文": "韓文", | |
| "法文": "法文", | |
| "德文": "德文", | |
| "西班牙文": "西班牙文" | |
| } | |
| prompt = f"請將以下文本翻譯成{language_mapping[target_lang]},保持原文的語氣和風格:\n\n{text}" | |
| completion = openai.chat.completions.create( | |
| model="gpt-4", | |
| messages=[{"role": "user", "content": prompt}] | |
| ) | |
| return completion.choices[0].message.content | |
| # OpenAI 生成摘要的函式(根據不同受眾) | |
| def openai_generate_summary(text, audience_type, api_key): | |
| openai.api_key = api_key | |
| audience_prompts = { | |
| "學生": "請將以下會議內容整理成適合學生閱讀的摘要,重點放在學習價值和知識傳遞:", | |
| "老師": "請將以下會議內容整理成適合教師參考的摘要,重點放在教學應用和教育意義:", | |
| "會議": "請將以下會議內容整理成正式的會議摘要,重點放在決策、行動項目和重要討論:", | |
| "主管": "請將以下會議內容整理成適合管理層閱讀的摘要,重點放在策略決策和關鍵績效:", | |
| "技術人員": "請將以下會議內容整理成適合技術團隊閱讀的摘要,重點放在技術細節和實作方向:", | |
| "行銷人員": "請將以下會議內容整理成適合行銷團隊閱讀的摘要,重點放在市場策略和推廣重點:", | |
| "一般員工": "請將以下會議內容整理成適合一般員工閱讀的摘要,重點放在執行重點和日常工作相關內容:", | |
| "客戶": "請將以下會議內容整理成適合客戶閱讀的摘要,重點放在服務優化和價值傳遞:", | |
| "投資者": "請將以下會議內容整理成適合投資者閱讀的摘要,重點放在財務表現和未來展望:", | |
| "研究人員": "請將以下會議內容整理成適合研究人員閱讀的摘要,重點放在研究方法和數據分析:" | |
| } | |
| prompt = f"{audience_prompts[audience_type]}\n\n{text}" | |
| completion = openai.chat.completions.create( | |
| model="gpt-4", | |
| messages=[{"role": "user", "content": prompt}] | |
| ) | |
| return completion.choices[0].message.content | |
| # 處理音檔轉文字 | |
| def process_audio(audio_file, api_key): | |
| if not audio_file or not api_key: | |
| return "請確保上傳音檔和輸入API金鑰", "", 0 | |
| try: | |
| # 轉譯音檔 | |
| transcript = transcribe_large_audio(audio_file, api_key) | |
| # 計算字數 | |
| word_count = count_words(transcript) | |
| return transcript, f"字數統計:{word_count} 字", word_count | |
| except Exception as e: | |
| return f"處理失敗:{str(e)}", "", 0 | |
| # 處理標點與段落 | |
| def process_punctuation(text, api_key): | |
| if not text or not api_key: | |
| return "請確保有文本內容和API金鑰" | |
| try: | |
| return auto_punctuate(text, api_key) | |
| except Exception as e: | |
| return f"標點處理失敗:{str(e)}" | |
| # 處理翻譯 | |
| def process_translation(text, target_lang, api_key): | |
| if not all([text, target_lang, api_key]): | |
| return "請確保所有必要欄位都已填寫" | |
| try: | |
| return openai_translate_text(text, target_lang, api_key) | |
| except Exception as e: | |
| return f"翻譯失敗:{str(e)}" | |
| # 處理摘要 | |
| def process_summary(text, audience_type, api_key): | |
| if not all([text, audience_type, api_key]): | |
| return "請確保所有必要欄位都已填寫" | |
| try: | |
| return openai_generate_summary(text, audience_type, api_key) | |
| except Exception as e: | |
| return f"摘要生成失敗:{str(e)}" | |
| # 建立 Gradio 介面 | |
| with gr.Blocks() as demo: | |
| gr.Markdown("會議音檔轉文字處理系統") | |
| with gr.Row(): | |
| audio_file_input = gr.Audio(type="filepath", label="上傳音檔") | |
| api_key_input = gr.Textbox(label="輸入 OpenAI API 金鑰", type="password") | |
| with gr.Row(): | |
| transcript_output = gr.Textbox(label="原始逐字稿", lines=5) | |
| word_count_output = gr.Textbox(label="字數統計") | |
| with gr.Row(): | |
| punctuated_output = gr.Textbox(label="加入標點符號後的文本", lines=5) | |
| with gr.Row(): | |
| target_lang_input = gr.Dropdown( | |
| choices=["繁體中文", "英文", "日文", "韓文", "法文", "德文", "西班牙文"], | |
| label="選擇目標語言", | |
| value="繁體中文" | |
| ) | |
| translated_output = gr.Textbox(label="翻譯結果", lines=5) | |
| with gr.Row(): | |
| audience_type_input = gr.Dropdown( | |
| choices=[ | |
| "學生", "老師", "會議", "主管", "技術人員", | |
| "行銷人員", "一般員工", "客戶", "投資者", "研究人員" | |
| ], | |
| label="選擇摘要類型", | |
| value="會議" | |
| ) | |
| summary_output = gr.Textbox(label="客製化摘要", lines=5) | |
| with gr.Row(): | |
| transcribe_button = gr.Button("1. 開始轉譯") | |
| punctuate_button = gr.Button("2. 添加標點符號") | |
| translate_button = gr.Button("3. 翻譯文本") | |
| summary_button = gr.Button("4. 生成摘要") | |
| # 連接按鈕和函式 | |
| transcribe_button.click( | |
| process_audio, | |
| inputs=[audio_file_input, api_key_input], | |
| outputs=[transcript_output, word_count_output] | |
| ) | |
| punctuate_button.click( | |
| process_punctuation, | |
| inputs=[transcript_output, api_key_input], | |
| outputs=punctuated_output | |
| ) | |
| translate_button.click( | |
| process_translation, | |
| inputs=[punctuated_output, target_lang_input, api_key_input], | |
| outputs=translated_output | |
| ) | |
| summary_button.click( | |
| process_summary, | |
| inputs=[translated_output, audience_type_input, api_key_input], | |
| outputs=summary_output | |
| ) | |
| # 啟動介面 | |
| if __name__ == "__main__": | |
| demo.launch() |