tbdavid2019 commited on
Commit
62f78a2
·
1 Parent(s): b199afe

feat: 增加可調整的最大輸出 token 限制,並新增摘要生成功能及相關模板

Browse files
Files changed (3) hide show
  1. __pycache__/app.cpython-311.pyc +0 -0
  2. app.py +142 -4
  3. prompts.py +45 -7
__pycache__/app.cpython-311.pyc CHANGED
Binary files a/__pycache__/app.cpython-311.pyc and b/__pycache__/app.cpython-311.pyc differ
 
app.py CHANGED
@@ -72,6 +72,7 @@ def generate_dialogue_via_requests(
72
  user_feedback: str = None,
73
  num_parts: int = 3,
74
  max_input_length: int = 1000000,
 
75
  progress_callback=None,
76
  template_type: str = "podcast"
77
  ) -> str:
@@ -115,7 +116,7 @@ def generate_dialogue_via_requests(
115
  max_retries = 5
116
  retry_delay = 5
117
 
118
- # 使用 Gemini Flash 2.5 的最大輸出 token 限制
119
  payload = {
120
  "model": model,
121
  "messages": [
@@ -125,7 +126,7 @@ def generate_dialogue_via_requests(
125
  }
126
  ],
127
  "temperature": 0.7,
128
- "max_tokens": 65536, # Gemini Flash 2.5 最大輸出 token 數
129
  "stream": False # 先不用流式,確保穩定性
130
  }
131
 
@@ -222,6 +223,73 @@ def generate_dialogue_via_requests(
222
  return "生成失敗"
223
 
224
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
225
  def _generate_in_batches(pdf_text, base_prompt, headers, url, model, num_parts, progress_callback, max_retries, retry_delay):
226
  """
227
  分批生成的備用機制,只在單次生成被截斷時使用
@@ -377,6 +445,7 @@ def validate_and_generate_script(
377
  user_feedback,
378
  num_parts=3,
379
  max_input_length=1000000,
 
380
  progress_callback=None
381
  ):
382
  """驗證輸入並生成腳本"""
@@ -498,6 +567,7 @@ def validate_and_generate_script(
498
  user_feedback=user_feedback,
499
  num_parts=num_parts,
500
  max_input_length=max_input_length,
 
501
  progress_callback=progress_callback,
502
  template_type="podcast"
503
  )
@@ -628,6 +698,16 @@ with gr.Blocks(title="Script Generator", css="""
628
  info="調整模型可處理的最大輸入文本長度(字符數)"
629
  )
630
 
 
 
 
 
 
 
 
 
 
 
631
 
632
  with gr.Column(scale=1):
633
  # 輸出區
@@ -635,10 +715,30 @@ with gr.Blocks(title="Script Generator", css="""
635
 
636
  output_text = gr.Textbox(
637
  label="生成的腳本 | Generated Script",
638
- lines=30,
639
  show_copy_button=True
640
  )
641
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
642
  error_output = gr.Markdown(
643
  visible=False,
644
  elem_classes=["error"]
@@ -697,6 +797,30 @@ with gr.Blocks(title="Script Generator", css="""
697
  logger.info("腳本生成成功")
698
  return script, gr.update(visible=False)
699
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
700
  generate_button.click(
701
  fn=handle_script_generation,
702
  inputs=[
@@ -712,10 +836,24 @@ with gr.Blocks(title="Script Generator", css="""
712
  gr.Textbox(value=""), # edited_transcript
713
  custom_prompt, # user_feedback
714
  num_parts_slider, # 添加滑動條參數
715
- max_input_length_slider # 添加最大輸入文本長度參數
 
716
  ],
717
  outputs=[output_text, error_output]
718
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
719
 
720
 
721
  if __name__ == "__main__":
 
72
  user_feedback: str = None,
73
  num_parts: int = 3,
74
  max_input_length: int = 1000000,
75
+ max_output_tokens: int = 65536,
76
  progress_callback=None,
77
  template_type: str = "podcast"
78
  ) -> str:
 
116
  max_retries = 5
117
  retry_delay = 5
118
 
119
+ # 使用可調整的輸出 token 限制
120
  payload = {
121
  "model": model,
122
  "messages": [
 
126
  }
127
  ],
128
  "temperature": 0.7,
129
+ "max_tokens": max_output_tokens, # 可調整的輸出 token 數
130
  "stream": False # 先不用流式,確保穩定性
131
  }
132
 
 
223
  return "生成失敗"
224
 
225
 
226
+ def generate_summary(
227
+ script_content: str,
228
+ summary_type: str,
229
+ model: str,
230
+ llm_api_key: str,
231
+ api_base: str,
232
+ max_output_tokens: int = 4096,
233
+ progress_callback=None
234
+ ) -> str:
235
+ """
236
+ 為生成的腳本創建摘要
237
+ """
238
+ if not script_content or not script_content.strip():
239
+ return "錯誤:請先生成腳本內容"
240
+
241
+ logger.info(f"開始生成摘要,類型: {summary_type}")
242
+
243
+ # 從 prompts 模組獲取摘要模板
244
+ try:
245
+ summary_template = get_template(summary_type)["dialog"]
246
+ prompt = summary_template.format(content=script_content)
247
+ except KeyError:
248
+ return f"錯誤:未找到摘要模板 '{summary_type}'"
249
+
250
+ headers = {
251
+ "Authorization": f"Bearer {llm_api_key}",
252
+ "Content-Type": "application/json"
253
+ }
254
+
255
+ base_url = api_base.rstrip("/")
256
+ url = f"{base_url}/chat/completions"
257
+
258
+ payload = {
259
+ "model": model,
260
+ "messages": [
261
+ {
262
+ "role": "user",
263
+ "content": prompt
264
+ }
265
+ ],
266
+ "temperature": 0.7,
267
+ "max_tokens": max_output_tokens
268
+ }
269
+
270
+ if progress_callback:
271
+ progress_callback(f"正在生成{summary_type}摘要...")
272
+
273
+ try:
274
+ response = requests.post(url, headers=headers, json=payload)
275
+ response.raise_for_status()
276
+ result = response.json()
277
+ summary = result['choices'][0]['message']['content']
278
+
279
+ logger.info(f"摘要生成完成,長度: {len(summary)} 字符")
280
+ if progress_callback:
281
+ progress_callback(f"摘要生成完成!")
282
+
283
+ return summary
284
+
285
+ except requests.exceptions.RequestException as e:
286
+ error_msg = f"摘要生成失敗: {str(e)}"
287
+ logger.error(error_msg)
288
+ if progress_callback:
289
+ progress_callback(error_msg)
290
+ return error_msg
291
+
292
+
293
  def _generate_in_batches(pdf_text, base_prompt, headers, url, model, num_parts, progress_callback, max_retries, retry_delay):
294
  """
295
  分批生成的備用機制,只在單次生成被截斷時使用
 
445
  user_feedback,
446
  num_parts=3,
447
  max_input_length=1000000,
448
+ max_output_tokens=65536,
449
  progress_callback=None
450
  ):
451
  """驗證輸入並生成腳本"""
 
567
  user_feedback=user_feedback,
568
  num_parts=num_parts,
569
  max_input_length=max_input_length,
570
+ max_output_tokens=max_output_tokens,
571
  progress_callback=progress_callback,
572
  template_type="podcast"
573
  )
 
698
  info="調整模型可處理的最大輸入文本長度(字符數)"
699
  )
700
 
701
+ # 添加最大輸出 token 數的滑動條
702
+ max_output_tokens_slider = gr.Slider(
703
+ minimum=1024,
704
+ maximum=131072,
705
+ value=65536,
706
+ step=1024,
707
+ label="最大輸出 Token 數 | Max Output Tokens",
708
+ info="調整模型最大輸出 token 數。Gemini Flash 2.5: 65536, GPT-4: 4096, Claude: 8192"
709
+ )
710
+
711
 
712
  with gr.Column(scale=1):
713
  # 輸出區
 
715
 
716
  output_text = gr.Textbox(
717
  label="生成的腳本 | Generated Script",
718
+ lines=20,
719
  show_copy_button=True
720
  )
721
 
722
+ # 摘要生成區域
723
+ gr.Markdown("### 📝 Podcast 摘要生成 | Summary Generation")
724
+
725
+ with gr.Row():
726
+ summary_type_dropdown = gr.Dropdown(
727
+ label="摘要類型 | Summary Type",
728
+ choices=["blog-summary", "intro-summary"],
729
+ value="intro-summary",
730
+ interactive=True
731
+ )
732
+
733
+ generate_summary_button = gr.Button("生成摘要 | Generate Summary", size="sm")
734
+
735
+ summary_output = gr.Textbox(
736
+ label="生成的摘要 | Generated Summary",
737
+ lines=10,
738
+ show_copy_button=True,
739
+ placeholder="請先生成腳本,然後點擊「生成摘要」按鈕"
740
+ )
741
+
742
  error_output = gr.Markdown(
743
  visible=False,
744
  elem_classes=["error"]
 
797
  logger.info("腳本生成成功")
798
  return script, gr.update(visible=False)
799
 
800
+ def handle_summary_generation(script_content, summary_type, api_key_val, model_val, api_base_val, max_tokens_val):
801
+ if not script_content or not script_content.strip():
802
+ return "錯誤:請先生成腳本內容"
803
+
804
+ if not api_key_val or not model_val:
805
+ return "錯誤:請確保已設定 API 金鑰和模型"
806
+
807
+ logger.info(f"開始生成摘要,類型: {summary_type}")
808
+
809
+ def progress_callback(msg):
810
+ pass # 簡化版本,不顯示進度
811
+
812
+ summary = generate_summary(
813
+ script_content=script_content,
814
+ summary_type=summary_type,
815
+ model=model_val,
816
+ llm_api_key=api_key_val,
817
+ api_base=api_base_val,
818
+ max_output_tokens=max_tokens_val // 2, # 摘要使用較少的 tokens
819
+ progress_callback=progress_callback
820
+ )
821
+
822
+ return summary
823
+
824
  generate_button.click(
825
  fn=handle_script_generation,
826
  inputs=[
 
836
  gr.Textbox(value=""), # edited_transcript
837
  custom_prompt, # user_feedback
838
  num_parts_slider, # 添加滑動條參數
839
+ max_input_length_slider, # 添加最大輸入文本長度參數
840
+ max_output_tokens_slider # 添加最大輸出 token 數參數
841
  ],
842
  outputs=[output_text, error_output]
843
  )
844
+
845
+ generate_summary_button.click(
846
+ fn=handle_summary_generation,
847
+ inputs=[
848
+ output_text, # 腳本內容
849
+ summary_type_dropdown, # 摘要類型
850
+ api_key, # API 金鑰
851
+ model_dropdown, # 模型
852
+ api_base, # API 基礎 URL
853
+ max_output_tokens_slider # 最大輸出 tokens
854
+ ],
855
+ outputs=[summary_output]
856
+ )
857
 
858
 
859
  if __name__ == "__main__":
prompts.py CHANGED
@@ -117,18 +117,56 @@ PROMPTS = {
117
 
118
  {content}""",
119
 
120
- "short summary": """你是專業的內容摘要專家,專門創作簡潔摘要。
121
 
122
  【任務目標】
123
- - 提取文件的最核心要點
124
- - 保持簡潔明瞭
125
- - 目標長度約 250 字
126
 
127
- 【輸出格式】
128
  - **必須使用繁體中文**
129
- - 重點突出,語言精煉
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
 
131
- 請將以下內容整理成簡短摘要:
132
 
133
  {content}"""
134
  }
 
117
 
118
  {content}""",
119
 
120
+ "short summary": """你是 David888 Podcast 的內容編輯,專門創作簡潔摘要。
121
 
122
  【任務目標】
123
+ - 為播客內容生成簡潔明瞭的摘要
124
+ - 提取核心觀點和重要資訊
125
+ - 適合社群媒體分享或節目介紹
126
 
127
+ 【輸出要求】
128
  - **必須使用繁體中文**
129
+ - 約 256 字的簡潔摘要
130
+ - 直接輸出內容,不使用 Markdown 格式
131
+
132
+ 請為以下內容生成簡潔摘要:
133
+
134
+ {content}""",
135
+
136
+ # 新增的摘要模板
137
+ "blog-summary": """你是 David888 Podcast 中文博客的編輯,將播客內容改寫成適合搜索引擎收錄的博客文章。
138
+
139
+ 【工作目標】
140
+ - 使用簡潔明了的語言將播客對話整理為一篇完整的博客文章
141
+ - 開場白使用一句話介紹播客內容,博客名稱是 David888 Podcast
142
+ - 保留核心討論內容,但不要提及「對話」或「播客」等詞彙
143
+ - 確保博客內容生動有趣,具有可讀性
144
+
145
+ 【輸出要求】
146
+ - **必須使用繁體中文撰寫**,專業術語可保留英文
147
+ - 直接返回 Markdown 格式的正文內容,不要使用 ```markdown 包裹
148
+ - 不要返回前言,直接返回正文內容
149
+ - 文章結構清晰,使用二級標題、三級標題 (如"## 標題"、"### 子標題")
150
+ - 與分段正文形式呈現核心內容
151
+
152
+ 請將以下播客內容轉換成博客文章:
153
+
154
+ {content}""",
155
+
156
+ "intro-summary": """你是 David888 Podcast 中文播客的編輯,為播客文字稿生成極簡摘要。
157
+
158
+ 【工作目標】
159
+ - **必須使用繁體中文**給播客文字稿生成極簡摘要
160
+ - 提取最核心的討論重點和見解
161
+ - 適合作為節目介紹或平台描述
162
+
163
+ 【輸出要求】
164
+ - 輸出純文本內容,不要使用 Markdown 格式
165
+ - 只需要返回摘要內容,其他內容都不需要
166
+ - 摘要內容不要超過 200 字
167
+ - 簡潔有力,突出重點
168
 
169
+ 請為以下播客內容生成極簡摘要:
170
 
171
  {content}"""
172
  }