youngtsai commited on
Commit
6835560
1 Parent(s): 3a7f306
Files changed (2) hide show
  1. app.py +271 -58
  2. chatbot.py +1 -1
app.py CHANGED
@@ -381,7 +381,7 @@ def extract_youtube_id(url):
381
  return None
382
 
383
  def get_transcript_by_yt_api(video_id):
384
- languages = ['zh-TW', 'zh-Hant', 'zh', 'en'] # 優先順序列表
385
  for language in languages:
386
  try:
387
  transcript = YouTubeTranscriptApi.get_transcript(video_id, languages=[language])
@@ -582,8 +582,8 @@ def process_youtube_link(password, link):
582
 
583
  # 基于逐字稿生成其他所需的输出
584
  source = "gcs"
585
- questions = get_questions(video_id, formatted_simple_transcript, source)
586
- questions_json = json.dumps(questions, ensure_ascii=False, indent=2)
587
  summary_json = get_video_id_summary(video_id, formatted_simple_transcript, source)
588
  summary_text = summary_json["summary"]
589
  summary = summary_json["summary"]
@@ -608,10 +608,7 @@ def process_youtube_link(password, link):
608
 
609
  # 确保返回与 UI 组件预期匹配的输出
610
  return video_id, \
611
- questions_json, \
612
- questions[0] if len(questions) > 0 else "", \
613
- questions[1] if len(questions) > 1 else "", \
614
- questions[2] if len(questions) > 2 else "", \
615
  original_transcript, \
616
  summary_text, \
617
  summary, \
@@ -888,7 +885,8 @@ def get_video_id_summary(video_id, df_string, source):
888
  # 检查 summary_file 是否存在
889
  is_summary_file_exists = GCS_SERVICE.check_file_exists(bucket_name, summary_file_blob_name)
890
  if not is_summary_file_exists:
891
- summary = generate_summarise(df_string)
 
892
  summary_json = {"summary": str(summary)}
893
  summary_text = json.dumps(summary_json, ensure_ascii=False, indent=2)
894
  upload_file_to_gcs_with_json_string(gcs_client, bucket_name, summary_file_blob_name, summary_text)
@@ -909,7 +907,8 @@ def get_video_id_summary(video_id, df_string, source):
909
  # 检查逐字稿是否存在
910
  exists, file_id = check_file_exists(service, folder_id, file_name)
911
  if not exists:
912
- summary = generate_summarise(df_string)
 
913
  summary_json = {"summary": str(summary)}
914
  summary_text = json.dumps(summary_json, ensure_ascii=False, indent=2)
915
 
@@ -930,12 +929,27 @@ def get_video_id_summary(video_id, df_string, source):
930
 
931
  return summary_json
932
 
933
- def generate_summarise(df_string):
934
  # 使用 OpenAI 生成基于上传数据的问题
 
 
 
 
 
 
 
 
 
935
  sys_content = "你是一個擅長資料分析跟影片教學的老師,user 為學生,請精讀資料文本,自行判斷資料的種類,使用 zh-TW"
936
  user_content = f"""
937
- 請根據 {df_string},判斷這份文本
 
 
 
 
 
938
  格式為 Markdown
 
939
  整體摘要在一百字以內
940
  重點概念列出 bullet points,至少三個,最多五個
941
  以及可能的結論與結尾延伸小問題提供學生作反思
@@ -943,6 +957,7 @@ def generate_summarise(df_string):
943
  加減乘除、根號、次方等等的運算式口語也換成 LATEX 數學符號
944
 
945
  整體格式為:
 
946
  ## 📚 整體摘要
947
  - (一個 bullet point....)
948
 
@@ -955,7 +970,7 @@ def generate_summarise(df_string):
955
  - (一個 bullet point....)
956
 
957
  ## ❓ 延伸小問題
958
- - (一個 bullet point....)
959
  """
960
 
961
  # 🗂️ 1. 內容類型:?
@@ -1075,6 +1090,90 @@ def generate_questions(df_string):
1075
 
1076
  return questions
1077
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1078
  def change_questions(password, df_string):
1079
  verify_password(password)
1080
 
@@ -1527,6 +1626,16 @@ def update_LLM_content(video_id, new_content, kind):
1527
  questions_text = json.dumps(questions_json, ensure_ascii=False, indent=2)
1528
  upload_file_to_gcs_with_json_string(gcs_client, bucket_name, blob_name, questions_text)
1529
  updated_content = questions_text
 
 
 
 
 
 
 
 
 
 
1530
 
1531
  print(f"{kind} 已更新到GCS")
1532
  return gr.update(value=updated_content, interactive=False)
@@ -1539,7 +1648,8 @@ def create_LLM_content(video_id, df_string, kind):
1539
  content = generate_reading_passage(df_string)
1540
  update_LLM_content(video_id, content, kind)
1541
  elif kind == "summary_markdown":
1542
- content = generate_summarise(df_string)
 
1543
  update_LLM_content(video_id, content, kind)
1544
  elif kind == "mind_map":
1545
  content = generate_mind_map(df_string)
@@ -1551,17 +1661,26 @@ def create_LLM_content(video_id, df_string, kind):
1551
  transcript = df_string
1552
  formatted_simple_transcript = create_formatted_simple_transcript(transcript)
1553
  formatted_transcript = create_formatted_transcript(video_id, transcript)
1554
- content = generate_key_moments(formatted_simple_transcript, formatted_transcript)
1555
- update_LLM_content(video_id, content, kind)
1556
- content = json.dumps(content, ensure_ascii=False, indent=2)
1557
  elif kind == "transcript":
1558
- content = process_transcript_and_screenshots_on_gcs(video_id)
1559
- update_LLM_content(video_id, content, kind)
1560
- content = json.dumps(content, ensure_ascii=False, indent=2)
1561
  elif kind == "questions":
1562
- content = generate_questions(df_string)
1563
- update_LLM_content(video_id, content, kind)
1564
- content = json.dumps(content, ensure_ascii=False, indent=2)
 
 
 
 
 
 
 
 
 
1565
 
1566
  return gr.update(value=content, interactive=False)
1567
 
@@ -1688,8 +1807,6 @@ def summary_add_markdown_version(video_id):
1688
 
1689
  return new_summary
1690
 
1691
-
1692
-
1693
 
1694
  # AI 生成教學素材
1695
  def get_meta_data(video_id, source="gcs"):
@@ -1838,11 +1955,12 @@ def get_instructions(content_subject, content_grade, key_moments):
1838
  subject: {content_subject}
1839
  grade: {content_grade}
1840
  context: {key_moments}
1841
- Assistant Role: you are a {content_subject} teacher
1842
  User Role: {content_grade} th-grade student.
1843
  Method: Socratic style, guide thinking, no direct answers. this is very important, please be seriously following.
1844
  Language: Traditional Chinese ZH-TW (it's very important), suitable for {content_grade} th-grade level.
1845
  Response:
 
1846
  - Single question, under 100 characters
1847
  - include math symbols (use LaTeX $ to cover before and after, ex: $x^2$)
1848
  - hint with video timestamp which format 【參考:00:00:00】.
@@ -1853,12 +1971,32 @@ def get_instructions(content_subject, content_grade, key_moments):
1853
  """
1854
  return instructions
1855
 
1856
- def chat_with_ai(ai_name, password, video_id, user_data, trascript_state, key_moments, user_message, chat_history, content_subject, content_grade, socratic_mode=False):
1857
  verify_password(password)
1858
 
1859
  print("=====user_data=====")
1860
  print(f"user_data: {user_data}")
1861
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1862
  if chat_history is not None and len(chat_history) > 11:
1863
  error_msg = "此次對話超過上限(對話一輪10次)"
1864
  raise gr.Error(error_msg)
@@ -1927,7 +2065,7 @@ def chat_with_ai(ai_name, password, video_id, user_data, trascript_state, key_mo
1927
  print(f"Error: {e}")
1928
  return "请求失败,请稍后再试!", chat_history
1929
 
1930
- def chat_with_opan_ai_assistant(password, youtube_id, user_data, thread_id, trascript_state, key_moments, user_message, chat_history, content_subject, content_grade, socratic_mode=False):
1931
  verify_password(password)
1932
 
1933
  print("=====user_data=====")
@@ -1938,6 +2076,28 @@ def chat_with_opan_ai_assistant(password, youtube_id, user_data, thread_id, tras
1938
  error_msg = "你的訊息太長了,請縮短訊息長度至五百字以內"
1939
  raise gr.Error(error_msg)
1940
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1941
  # 如果 chat_history 超過 10 則訊息,直接 return "對話超過上限"
1942
  if chat_history is not None and len(chat_history) > 10:
1943
  error_msg = "此次對話超過上限(對話一輪10次)"
@@ -2000,7 +2160,7 @@ def chat_with_opan_ai_assistant(password, youtube_id, user_data, thread_id, tras
2000
  client.beta.threads.messages.create(
2001
  thread_id=thread.id,
2002
  role="user",
2003
- content=user_message + "/n 請嚴格遵循instructions,擔任一位蘇格拉底家教,絕對不要重複 user 的問句,請用引導的方式指引方向,請一定要用繁體中文回答 zh-TW,並用台灣人的禮貌口語表達,回答時不要特別說明這是台灣人的語氣,請在回答的最後標註【參考:(時):(分):(秒)】,(如果是反問學生,就只問一個問題,請幫助學生更好的理解資料,字數在100字以內,回答時請用數學符號代替文字(Latex 用 $ 字號 render, ex: $x^2$)"
2004
  )
2005
 
2006
  # 运行助手,生成响应
@@ -2104,13 +2264,13 @@ def poll_run_status(run_id, thread_id, timeout=600, poll_interval=5):
2104
 
2105
  return run.status
2106
 
2107
- def streaming_chat_with_open_ai(user_message, chat_history, password, video_id, user_data, thread_id, trascript, key_moments, content_subject, content_grade):
2108
  verify_password(password)
2109
 
2110
  print("=====user_data=====")
2111
  print(f"user_data: {user_data}")
2112
 
2113
- print("===streaming_chat_with_open_ai===")
2114
  print(thread_id)
2115
 
2116
  # 先計算 user_message 是否超過 500 個字
@@ -2288,7 +2448,7 @@ def init_params(text, request: gr.Request):
2288
  password_text, youtube_link, \
2289
  chatbot_open_ai, chatbot_open_ai_streaming, chatbot_jutor
2290
 
2291
- def update_state(content_subject, content_grade, trascript, key_moments, question_1, question_2, question_3):
2292
  # inputs=[content_subject, content_grade, df_string_output],
2293
  # outputs=[content_subject_state, content_grade_state, trascript_state]
2294
  content_subject_state = content_subject
@@ -2297,13 +2457,22 @@ def update_state(content_subject, content_grade, trascript, key_moments, questio
2297
  formatted_simple_transcript = create_formatted_simple_transcript(trascript_json)
2298
  trascript_state = formatted_simple_transcript
2299
  key_moments_state = key_moments
2300
- streaming_chat_thread_id_state = create_thread_id()
 
 
 
 
 
 
 
 
2301
  ai_chatbot_question_1 = question_1
2302
  ai_chatbot_question_2 = question_2
2303
  ai_chatbot_question_3 = question_3
2304
 
2305
  return content_subject_state, content_grade_state, trascript_state, key_moments_state, \
2306
  streaming_chat_thread_id_state, \
 
2307
  ai_chatbot_question_1, ai_chatbot_question_2, ai_chatbot_question_3
2308
 
2309
 
@@ -2389,7 +2558,7 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
2389
  with gr.Tab("AI小精靈"):
2390
  with gr.Accordion("選擇 AI 小精靈", open=True) as chatbot_select_accordion:
2391
  with gr.Row():
2392
- with gr.Column(scale=1, variant="panel"):
2393
  chatbot_avatar_url = "https://junyitopicimg.s3.amazonaws.com/s4byy--icon.jpe?v=20200513013523726"
2394
  chatbot_description = """Hi,我是你的AI學伴【飛特精靈】,\n
2395
  我可以陪你一起學習本次的內容,有什麼問題都可以問我喔!\n
@@ -2403,7 +2572,7 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
2403
  gr.Image(value=chatbot_avatar_url, height=100, width=100, show_label=False, show_download_button=False)
2404
  chatbot_open_ai_select_btn = gr.Button("👆選擇【飛特精靈】", elem_id="chatbot_btn", visible=True, variant="primary")
2405
  gr.Markdown(value=chatbot_description, visible=True)
2406
- with gr.Column(scale=1, variant="panel"):
2407
  streaming_chatbot_avatar_url = "https://storage.googleapis.com/wpassets.junyiacademy.org/1/2020/11/1-%E6%98%9F%E7%A9%BA%E9%A0%AD%E8%B2%BC-%E5%A4%AA%E7%A9%BA%E7%8B%90%E7%8B%B8%E8%B2%93-150x150.png"
2408
  streaming_chatbot_description = """Hi,我是【飛特音速】, \n
2409
  說話比較快,但有什麼問題都可以問我喔! \n
@@ -2435,7 +2604,7 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
2435
  bot_avatar = "https://junyitopicimg.s3.amazonaws.com/s4byy--icon.jpe?v=20200513013523726"
2436
  latex_delimiters = [{"left": "$", "right": "$", "display": False}]
2437
  chatbot_greeting = [[
2438
- None,
2439
  """Hi,我是你的AI學伴【飛特精靈】,我可以陪你一起學習本次的內容,有什麼問題都可以問我喔!
2440
  🤔 如果你不知道怎麼發問,可以點擊左下方的問題一、問題二、問題三,我會幫你生成問題!
2441
  🗣️ 也可以點擊右下方用語音輸入,我會幫你轉換成文字,厲害吧!
@@ -2470,7 +2639,7 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
2470
  """
2471
  additional_inputs = [password, video_id, user_data, streaming_chat_thread_id_state, trascript_state, key_moments_state, content_subject_state, content_grade_state]
2472
  streaming_chat = gr.ChatInterface(
2473
- fn=streaming_chat_with_open_ai,
2474
  additional_inputs=additional_inputs,
2475
  submit_btn="送出",
2476
  retry_btn=None,
@@ -2482,7 +2651,7 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
2482
  with gr.Row("其他精靈") as chatbot_jutor:
2483
  with gr.Column():
2484
  ai_chatbot_greeting = [[
2485
- None,
2486
  """Hi,我是飛特精靈的朋友們【梨梨、麥麥、狐狸貓】,也可以陪你一起學習本次的內容,有什麼問題都可以問我喔!
2487
  🤔 如果你不知道怎麼發問,可以點擊左下方的問題一、問題二、問題三,我會幫你生成問題!
2488
  🗣️ 也可以點擊右下方用語音輸入,我會幫你轉換成文字,厲害吧!
@@ -2491,7 +2660,12 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
2491
  """,
2492
  ]]
2493
  ai_chatbot_bot_avatar = "https://storage.googleapis.com/wpassets.junyiacademy.org/1/2019/11/%E5%9B%9B%E6%A0%BC%E6%95%85%E4%BA%8B-04.jpg"
2494
- ai_name = gr.Dropdown(label="選擇 AI 助理", choices=[("梨梨","jutor"), ("麥麥","claude3"), ("狐狸貓","groq")], value="jutor")
 
 
 
 
 
2495
  ai_chatbot = gr.Chatbot(avatar_images=[user_avatar, ai_chatbot_bot_avatar], label="ai_chatbot", show_share_button=False, likeable=True, show_label=False, latex_delimiters=latex_delimiters, value=ai_chatbot_greeting)
2496
  ai_chatbot_socratic_mode_btn = gr.Checkbox(label="蘇格拉底家教助理模式", value=True, visible=False)
2497
  with gr.Row():
@@ -2526,7 +2700,7 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
2526
  with gr.Row():
2527
  worksheet_content_type_name = gr.Textbox(value="worksheet", visible=False)
2528
  worksheet_algorithm = gr.Dropdown(label="選擇教學策略或理論", choices=["Bloom認知階層理論", "Polya數學解題法", "CRA教學法"], value="Bloom認知階層理論", visible=False)
2529
- worksheet_content_btn = gr.Button("生成學習單 📄", variant="primary")
2530
  with gr.Accordion("微調", open=False):
2531
  worksheet_exam_result_fine_tune_prompt = gr.Textbox(label="根據結果,輸入你想更改的想法")
2532
  worksheet_exam_result_fine_tune_btn = gr.Button("微調結果", variant="primary")
@@ -2541,13 +2715,13 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
2541
  worksheet_exam_result = gr.Markdown(label="初次生成結果", latex_delimiters = [{"left": "$", "right": "$", "display": False}])
2542
  worksheet_download_exam_result_button = gr.Button("轉成 word,完成後請點擊右下角 download 按鈕", variant="primary")
2543
  worksheet_exam_result_word_link = gr.File(label="Download Word")
2544
- with gr.Tab("課程計畫"):
2545
  with gr.Row():
2546
  with gr.Column(scale=1):
2547
  with gr.Row():
2548
  lesson_plan_content_type_name = gr.Textbox(value="lesson_plan", visible=False)
2549
  lesson_plan_time = gr.Slider(label="選擇課程時間(分鐘)", minimum=10, maximum=120, step=5, value=40)
2550
- lesson_plan_btn = gr.Button("生成課程計畫 📕", variant="primary")
2551
  with gr.Accordion("微調", open=False):
2552
  lesson_plan_exam_result_fine_tune_prompt = gr.Textbox(label="根據結果,輸入你想更改的想法")
2553
  lesson_plan_exam_result_fine_tune_btn = gr.Button("微調結果", variant="primary")
@@ -2568,7 +2742,7 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
2568
  with gr.Row():
2569
  exit_ticket_content_type_name = gr.Textbox(value="exit_ticket", visible=False)
2570
  exit_ticket_time = gr.Slider(label="選擇出場券時間(分鐘)", minimum=5, maximum=10, step=1, value=8)
2571
- exit_ticket_btn = gr.Button("生成出場券 🎟️", variant="primary")
2572
  with gr.Accordion("微調", open=False):
2573
  exit_ticket_exam_result_fine_tune_prompt = gr.Textbox(label="根據結果,輸入你想更改的想法")
2574
  exit_ticket_exam_result_fine_tune_btn = gr.Button("微調結果", variant="primary")
@@ -2655,9 +2829,19 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
2655
  questions_edit_button = gr.Button("編輯", size="sm", variant="primary")
2656
  questions_update_button = gr.Button("儲存", size="sm", variant="primary")
2657
  questions_delete_button = gr.Button("刪除", size="sm", variant="primary")
2658
- questions_create_button = gr.Button("建立", size="sm", variant="primary")
2659
  with gr.Row():
2660
  questions_json = gr.Textbox(label="Questions", lines=40, interactive=False, show_copy_button=True)
 
 
 
 
 
 
 
 
 
 
2661
  with gr.Tab("逐字稿"):
2662
  simple_html_content = gr.HTML(label="Simple Transcript")
2663
  with gr.Tab("圖文"):
@@ -2687,6 +2871,10 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
2687
  chatbot_select,
2688
  inputs=[chatbot_open_ai_streaming_name],
2689
  outputs=[chatbot_select_accordion, chatbot_open_ai, chatbot_open_ai_streaming, chatbot_jutor]
 
 
 
 
2690
  )
2691
  chatbot_jutor_select_btn.click(
2692
  chatbot_select,
@@ -2697,7 +2885,7 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
2697
  # OPENAI ASSISTANT CHATBOT 模式
2698
  send_button.click(
2699
  chat_with_opan_ai_assistant,
2700
- inputs=[password, video_id, user_data, thread_id, trascript_state, key_moments, msg, chatbot, content_subject, content_grade, socratic_mode_btn],
2701
  outputs=[msg, chatbot, thread_id],
2702
  scroll_to_output=True
2703
  )
@@ -2707,9 +2895,9 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
2707
  outputs=[msg]
2708
  )
2709
  # OPENAI ASSISTANT CHATBOT 連接按鈕點擊事件
2710
- btn_1_chat_with_opan_ai_assistant_input =[password, video_id, user_data, thread_id, trascript_state, key_moments, btn_1, chatbot, content_subject, content_grade, ai_chatbot_socratic_mode_btn]
2711
- btn_2_chat_with_opan_ai_assistant_input =[password, video_id, user_data, thread_id, trascript_state, key_moments, btn_2, chatbot, content_subject, content_grade, ai_chatbot_socratic_mode_btn]
2712
- btn_3_chat_with_opan_ai_assistant_input =[password, video_id, user_data, thread_id, trascript_state, key_moments, btn_3, chatbot, content_subject, content_grade, ai_chatbot_socratic_mode_btn]
2713
  btn_1.click(
2714
  chat_with_opan_ai_assistant,
2715
  inputs=btn_1_chat_with_opan_ai_assistant_input,
@@ -2737,14 +2925,14 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
2737
  # 其他精靈 ai_chatbot 模式
2738
  ai_send_button.click(
2739
  chat_with_ai,
2740
- inputs=[ai_name, password, video_id, user_data, trascript_state, key_moments, ai_msg, ai_chatbot, content_subject, content_grade, ai_chatbot_socratic_mode_btn],
2741
  outputs=[ai_msg, ai_chatbot],
2742
  scroll_to_output=True
2743
  )
2744
  # 其他精靈 ai_chatbot 连接按钮点击事件
2745
- ai_chatbot_question_1_chat_with_ai_input =[ai_name, password, video_id, user_data, trascript_state, key_moments, ai_chatbot_question_1, ai_chatbot, content_subject, content_grade, ai_chatbot_socratic_mode_btn]
2746
- ai_chatbot_question_2_chat_with_ai_input =[ai_name, password, video_id, user_data, trascript_state, key_moments, ai_chatbot_question_2, ai_chatbot, content_subject, content_grade, ai_chatbot_socratic_mode_btn]
2747
- ai_chatbot_question_3_chat_with_ai_input =[ai_name, password, video_id, user_data, trascript_state, key_moments, ai_chatbot_question_3, ai_chatbot, content_subject, content_grade, ai_chatbot_socratic_mode_btn]
2748
  ai_chatbot_question_1.click(
2749
  chat_with_ai,
2750
  inputs=ai_chatbot_question_1_chat_with_ai_input,
@@ -2771,10 +2959,7 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
2771
  process_youtube_link_inputs = [password, youtube_link]
2772
  process_youtube_link_outputs = [
2773
  video_id,
2774
- questions_json,
2775
- btn_1,
2776
- btn_2,
2777
- btn_3,
2778
  df_string_output,
2779
  summary_text,
2780
  df_summarise,
@@ -2796,9 +2981,7 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
2796
  content_grade,
2797
  df_string_output,
2798
  key_moments,
2799
- btn_1,
2800
- btn_2,
2801
- btn_3
2802
  ]
2803
  update_state_outputs = [
2804
  content_subject_state,
@@ -2806,6 +2989,9 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
2806
  trascript_state,
2807
  key_moments_state,
2808
  streaming_chat_thread_id_state,
 
 
 
2809
  ai_chatbot_question_1,
2810
  ai_chatbot_question_2,
2811
  ai_chatbot_question_3
@@ -2979,6 +3165,33 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
2979
  inputs=[video_id, questions_json, questions_kind],
2980
  outputs=[questions_json]
2981
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2982
 
2983
  # 教師版
2984
  worksheet_content_btn.click(
 
381
  return None
382
 
383
  def get_transcript_by_yt_api(video_id):
384
+ languages = ['zh-TW', 'zh-Hant', 'zh', 'en-US'] # 優先順序列表
385
  for language in languages:
386
  try:
387
  transcript = YouTubeTranscriptApi.get_transcript(video_id, languages=[language])
 
582
 
583
  # 基于逐字稿生成其他所需的输出
584
  source = "gcs"
585
+ questions_answers = get_questions_answers(video_id, formatted_simple_transcript, source)
586
+ questions_answers_json = json.dumps(questions_answers, ensure_ascii=False, indent=2)
587
  summary_json = get_video_id_summary(video_id, formatted_simple_transcript, source)
588
  summary_text = summary_json["summary"]
589
  summary = summary_json["summary"]
 
608
 
609
  # 确保返回与 UI 组件预期匹配的输出
610
  return video_id, \
611
+ questions_answers_json, \
 
 
 
612
  original_transcript, \
613
  summary_text, \
614
  summary, \
 
885
  # 检查 summary_file 是否存在
886
  is_summary_file_exists = GCS_SERVICE.check_file_exists(bucket_name, summary_file_blob_name)
887
  if not is_summary_file_exists:
888
+ meta_data = get_meta_data(video_id)
889
+ summary = generate_summarise(df_string, meta_data)
890
  summary_json = {"summary": str(summary)}
891
  summary_text = json.dumps(summary_json, ensure_ascii=False, indent=2)
892
  upload_file_to_gcs_with_json_string(gcs_client, bucket_name, summary_file_blob_name, summary_text)
 
907
  # 检查逐字稿是否存在
908
  exists, file_id = check_file_exists(service, folder_id, file_name)
909
  if not exists:
910
+ meta_data = get_meta_data(video_id)
911
+ summary = generate_summarise(df_string, meta_data)
912
  summary_json = {"summary": str(summary)}
913
  summary_text = json.dumps(summary_json, ensure_ascii=False, indent=2)
914
 
 
929
 
930
  return summary_json
931
 
932
+ def generate_summarise(df_string, metadata=None):
933
  # 使用 OpenAI 生成基于上传数据的问题
934
+ if metadata:
935
+ title = metadata.get("title", "")
936
+ subject = metadata.get("subject", "")
937
+ grade = metadata.get("grade", "")
938
+ else:
939
+ title = ""
940
+ subject = ""
941
+ grade = ""
942
+
943
  sys_content = "你是一個擅長資料分析跟影片教學的老師,user 為學生,請精讀資料文本,自行判斷資料的種類,使用 zh-TW"
944
  user_content = f"""
945
+ 課程名稱:{title}
946
+ 科目:{subject}
947
+ 年級:{grade}
948
+
949
+ 請根據內文: {df_string}
950
+
951
  格式為 Markdown
952
+ 如果有課程名稱,請圍繞「課程名稱」為學習重點,進行重點整理,不要整理跟情境故事相關的問題
953
  整體摘要在一百字以內
954
  重點概念列出 bullet points,至少三個,最多五個
955
  以及可能的結論與結尾延伸小問題提供學生作反思
 
957
  加減乘除、根號、次方等等的運算式口語也換成 LATEX 數學符號
958
 
959
  整體格式為:
960
+ ## 🌟 主題:{{title}} (如果沒有 title 就省略)
961
  ## 📚 整體摘要
962
  - (一個 bullet point....)
963
 
 
970
  - (一個 bullet point....)
971
 
972
  ## ❓ 延伸小問題
973
+ - (一個 bullet point....請圍繞「課程名稱」為學習重點,進行重點整理,不要整理跟情境故事相關的問題)
974
  """
975
 
976
  # 🗂️ 1. 內容類型:?
 
1090
 
1091
  return questions
1092
 
1093
+ def get_questions_answers(video_id, df_string, source="gcs"):
1094
+ if source == "gcs":
1095
+ try:
1096
+ print("===get_questions_answers on gcs===")
1097
+ gcs_client = GCS_CLIENT
1098
+ bucket_name = 'video_ai_assistant'
1099
+ file_name = f'{video_id}_questions_answers.json'
1100
+ blob_name = f"{video_id}/{file_name}"
1101
+ # 检查檔案是否存在
1102
+ is_questions_answers_exists = GCS_SERVICE.check_file_exists(bucket_name, blob_name)
1103
+ if not is_questions_answers_exists:
1104
+ questions_answers = generate_questions_answers(df_string)
1105
+ questions_answers_text = json.dumps(questions_answers, ensure_ascii=False, indent=2)
1106
+ upload_file_to_gcs_with_json_string(gcs_client, bucket_name, blob_name, questions_answers_text)
1107
+ print("questions_answers已上傳到GCS")
1108
+ else:
1109
+ # questions_answers已存在,下载内容
1110
+ print("questions_answers已存在于GCS中")
1111
+ questions_answers_text = download_blob_to_string(gcs_client, bucket_name, blob_name)
1112
+ questions_answers = json.loads(questions_answers_text)
1113
+ except:
1114
+ questions = get_questions(video_id, df_string, source)
1115
+ questions_answers = [{"question": q, "answer": ""} for q in questions]
1116
+
1117
+ return questions_answers
1118
+
1119
+ def generate_questions_answers(df_string):
1120
+ content_text = str(df_string)
1121
+ sys_content = "你是一個擅長資料分析跟影片教學的老師,user 為學生,請精讀資料文本,自行判斷資料的種類,並用既有資料為本質猜測用戶可能會問的問題,使用 zh-TW"
1122
+ user_content = f"""
1123
+ 請根據 {content_text} 生成三個問題跟答案,主要與學科有關,不要問跟情節故事相關的問題
1124
+ 答案要在最後標示出處【參考:00:01:05】,請根據時間軸 start_time 來標示
1125
+ 請確保問題跟答案都是繁體中文 zh-TW
1126
+ 答案不用是標準答案,而是帶有啟發性的蘇格拉底式問答,讓學生思考本來的問題,以及該去參考的時間點
1127
+ 並用 JSON 格式返回 questions_answers: [{{question: q1的敘述text, answer: q1的答案text}}, ...]
1128
+ k-v pair 的 key 是 question, value 是 answer
1129
+ """
1130
+
1131
+ try:
1132
+ # OPENAI
1133
+ messages = [
1134
+ {"role": "system", "content": sys_content},
1135
+ {"role": "user", "content": user_content}
1136
+ ]
1137
+ response_format = { "type": "json_object" }
1138
+ request_payload = {
1139
+ "model": "gpt-4-turbo",
1140
+ "messages": messages,
1141
+ "max_tokens": 4000,
1142
+ "response_format": response_format
1143
+ }
1144
+
1145
+ response = OPEN_AI_CLIENT.chat.completions.create(**request_payload)
1146
+ questions_answers = json.loads(response.choices[0].message.content)["questions_answers"]
1147
+ except:
1148
+ # REDROCK_CLIENT
1149
+ messages = [
1150
+ {"role": "user", "content": user_content}
1151
+ ]
1152
+ model_id = "anthropic.claude-3-sonnet-20240229-v1:0"
1153
+ # model_id = "anthropic.claude-3-haiku-20240307-v1:0"
1154
+ kwargs = {
1155
+ "modelId": model_id,
1156
+ "contentType": "application/json",
1157
+ "accept": "application/json",
1158
+ "body": json.dumps({
1159
+ "anthropic_version": "bedrock-2023-05-31",
1160
+ "max_tokens": 4000,
1161
+ "system": sys_content,
1162
+ "messages": messages
1163
+ })
1164
+ }
1165
+ response = BEDROCK_CLIENT.invoke_model(**kwargs)
1166
+ response_body = json.loads(response.get('body').read())
1167
+ response_completion = response_body.get('content')[0].get('text')
1168
+ questions_answers = json.loads(response_completion)["questions_answers"]
1169
+
1170
+ print("=====json_response=====")
1171
+ print(questions_answers)
1172
+ print("=====json_response=====")
1173
+
1174
+ return questions_answers
1175
+
1176
+
1177
  def change_questions(password, df_string):
1178
  verify_password(password)
1179
 
 
1626
  questions_text = json.dumps(questions_json, ensure_ascii=False, indent=2)
1627
  upload_file_to_gcs_with_json_string(gcs_client, bucket_name, blob_name, questions_text)
1628
  updated_content = questions_text
1629
+ elif kind == "questions_answers":
1630
+ # from update_LLM_btn -> new_content is a string
1631
+ # create_LLM_content -> new_content is a list
1632
+ if isinstance(new_content, str):
1633
+ questions_answers_json = json.loads(new_content)
1634
+ else:
1635
+ questions_answers_json = new_content
1636
+ questions_answers_text = json.dumps(questions_answers_json, ensure_ascii=False, indent=2)
1637
+ upload_file_to_gcs_with_json_string(gcs_client, bucket_name, blob_name, questions_answers_text)
1638
+ updated_content = questions_answers_text
1639
 
1640
  print(f"{kind} 已更新到GCS")
1641
  return gr.update(value=updated_content, interactive=False)
 
1648
  content = generate_reading_passage(df_string)
1649
  update_LLM_content(video_id, content, kind)
1650
  elif kind == "summary_markdown":
1651
+ meta_data = get_meta_data(video_id)
1652
+ content = generate_summarise(df_string, meta_data)
1653
  update_LLM_content(video_id, content, kind)
1654
  elif kind == "mind_map":
1655
  content = generate_mind_map(df_string)
 
1661
  transcript = df_string
1662
  formatted_simple_transcript = create_formatted_simple_transcript(transcript)
1663
  formatted_transcript = create_formatted_transcript(video_id, transcript)
1664
+ gen_content = generate_key_moments(formatted_simple_transcript, formatted_transcript)
1665
+ update_LLM_content(video_id, gen_content, kind)
1666
+ content = json.dumps(gen_content, ensure_ascii=False, indent=2)
1667
  elif kind == "transcript":
1668
+ gen_content = process_transcript_and_screenshots_on_gcs(video_id)
1669
+ update_LLM_content(video_id, gen_content, kind)
1670
+ content = json.dumps(gen_content, ensure_ascii=False, indent=2)
1671
  elif kind == "questions":
1672
+ gen_content = generate_questions(df_string)
1673
+ update_LLM_content(video_id, gen_content, kind)
1674
+ content = json.dumps(gen_content, ensure_ascii=False, indent=2)
1675
+ elif kind == "questions_answers":
1676
+ if isinstance(df_string, str):
1677
+ transcript = json.loads(df_string)
1678
+ else:
1679
+ transcript = df_string
1680
+ formatted_simple_transcript = create_formatted_simple_transcript(transcript)
1681
+ gen_content = generate_questions_answers(formatted_simple_transcript)
1682
+ update_LLM_content(video_id, gen_content, kind)
1683
+ content = json.dumps(gen_content, ensure_ascii=False, indent=2)
1684
 
1685
  return gr.update(value=content, interactive=False)
1686
 
 
1807
 
1808
  return new_summary
1809
 
 
 
1810
 
1811
  # AI 生成教學素材
1812
  def get_meta_data(video_id, source="gcs"):
 
1955
  subject: {content_subject}
1956
  grade: {content_grade}
1957
  context: {key_moments}
1958
+ Assistant Role: you are a {content_subject} assistant. you can call yourself as {content_subject} 學伴
1959
  User Role: {content_grade} th-grade student.
1960
  Method: Socratic style, guide thinking, no direct answers. this is very important, please be seriously following.
1961
  Language: Traditional Chinese ZH-TW (it's very important), suitable for {content_grade} th-grade level.
1962
  Response:
1963
+ - if user say hi or hello or any greeting, just say hi back and introduce yourself. Then ask user to ask question in context.
1964
  - Single question, under 100 characters
1965
  - include math symbols (use LaTeX $ to cover before and after, ex: $x^2$)
1966
  - hint with video timestamp which format 【參考:00:00:00】.
 
1971
  """
1972
  return instructions
1973
 
1974
+ def chat_with_ai(ai_name, password, video_id, user_data, trascript_state, key_moments, user_message, chat_history, content_subject, content_grade, questions_answers_json, socratic_mode=False):
1975
  verify_password(password)
1976
 
1977
  print("=====user_data=====")
1978
  print(f"user_data: {user_data}")
1979
 
1980
+ questions_answers_json = json.loads(questions_answers_json)
1981
+ for qa in questions_answers_json:
1982
+ question = qa["question"]
1983
+ answer = qa["answer"]
1984
+ if user_message == question and answer != "":
1985
+ print("=== in questions_answers_json==")
1986
+ print(f"question: {question}")
1987
+ print(f"answer: {answer}")
1988
+ # 更新聊天历史
1989
+ new_chat_history = (user_message, answer)
1990
+ if chat_history is None:
1991
+ chat_history = [new_chat_history]
1992
+ else:
1993
+ chat_history.append(new_chat_history)
1994
+
1995
+ # 等待 3 秒
1996
+ time.sleep(3)
1997
+
1998
+ return "", chat_history
1999
+
2000
  if chat_history is not None and len(chat_history) > 11:
2001
  error_msg = "此次對話超過上限(對話一輪10次)"
2002
  raise gr.Error(error_msg)
 
2065
  print(f"Error: {e}")
2066
  return "请求失败,请稍后再试!", chat_history
2067
 
2068
+ def chat_with_opan_ai_assistant(password, youtube_id, user_data, thread_id, trascript_state, key_moments, user_message, chat_history, content_subject, content_grade, questions_answers_json, socratic_mode=False):
2069
  verify_password(password)
2070
 
2071
  print("=====user_data=====")
 
2076
  error_msg = "你的訊息太長了,請縮短訊息長度至五百字以內"
2077
  raise gr.Error(error_msg)
2078
 
2079
+ questions_answers_json = json.loads(questions_answers_json)
2080
+ for qa in questions_answers_json:
2081
+ question = qa["question"]
2082
+ answer = qa["answer"]
2083
+ if user_message == question and answer != "":
2084
+ print("=== in questions_answers_json==")
2085
+ print(f"question: {question}")
2086
+ print(f"answer: {answer}")
2087
+ print(f"thread_id: {thread_id}")
2088
+ # 更新聊天历史
2089
+ new_chat_history = (user_message, answer)
2090
+ if chat_history is None:
2091
+ chat_history = [new_chat_history]
2092
+ else:
2093
+ chat_history.append(new_chat_history)
2094
+
2095
+ # 等待 3 秒
2096
+ time.sleep(3)
2097
+
2098
+ return "", chat_history, thread_id
2099
+
2100
+
2101
  # 如果 chat_history 超過 10 則訊息,直接 return "對話超過上限"
2102
  if chat_history is not None and len(chat_history) > 10:
2103
  error_msg = "此次對話超過上限(對話一輪10次)"
 
2160
  client.beta.threads.messages.create(
2161
  thread_id=thread.id,
2162
  role="user",
2163
+ content=user_message + "/n 請嚴格遵循instructions,擔任一位蘇格拉底家教,絕對不要重複 user 的問句,請用引導的方式指引方向,請一定要用繁體中文回答 zh-TW,並用台灣人的禮貌口語表達,回答時不要特別說明這是台灣人的語氣,請在回答的最後標註【參考:(時):(分):(秒)】,(如果是反問學生,就只問一個問題,請幫助學生更好的理解資料,字數在100字以內,回答時如果講到數學專有名詞,請用數學符號代替文字(Latex 用 $ 字號 render, ex: $x^2$)"
2164
  )
2165
 
2166
  # 运行助手,生成响应
 
2264
 
2265
  return run.status
2266
 
2267
+ def chat_with_opan_ai_assistant_streaming(user_message, chat_history, password, video_id, user_data, thread_id, trascript, key_moments, content_subject, content_grade):
2268
  verify_password(password)
2269
 
2270
  print("=====user_data=====")
2271
  print(f"user_data: {user_data}")
2272
 
2273
+ print("===chat_with_opan_ai_assistant_streaming===")
2274
  print(thread_id)
2275
 
2276
  # 先計算 user_message 是否超過 500 個字
 
2448
  password_text, youtube_link, \
2449
  chatbot_open_ai, chatbot_open_ai_streaming, chatbot_jutor
2450
 
2451
+ def update_state(content_subject, content_grade, trascript, key_moments, questions_answers):
2452
  # inputs=[content_subject, content_grade, df_string_output],
2453
  # outputs=[content_subject_state, content_grade_state, trascript_state]
2454
  content_subject_state = content_subject
 
2457
  formatted_simple_transcript = create_formatted_simple_transcript(trascript_json)
2458
  trascript_state = formatted_simple_transcript
2459
  key_moments_state = key_moments
2460
+
2461
+ streaming_chat_thread_id_state = ""
2462
+ questions_answers_json = json.loads(questions_answers)
2463
+ question_1 = questions_answers_json[0]["question"]
2464
+ question_2 = questions_answers_json[1]["question"]
2465
+ question_3 = questions_answers_json[2]["question"]
2466
+ btn_1 = question_1
2467
+ btn_2 = question_2
2468
+ btn_3 = question_3
2469
  ai_chatbot_question_1 = question_1
2470
  ai_chatbot_question_2 = question_2
2471
  ai_chatbot_question_3 = question_3
2472
 
2473
  return content_subject_state, content_grade_state, trascript_state, key_moments_state, \
2474
  streaming_chat_thread_id_state, \
2475
+ btn_1, btn_2, btn_3, \
2476
  ai_chatbot_question_1, ai_chatbot_question_2, ai_chatbot_question_3
2477
 
2478
 
 
2558
  with gr.Tab("AI小精靈"):
2559
  with gr.Accordion("選擇 AI 小精靈", open=True) as chatbot_select_accordion:
2560
  with gr.Row():
2561
+ with gr.Column(scale=1, variant="panel", visible=False):
2562
  chatbot_avatar_url = "https://junyitopicimg.s3.amazonaws.com/s4byy--icon.jpe?v=20200513013523726"
2563
  chatbot_description = """Hi,我是你的AI學伴【飛特精靈】,\n
2564
  我可以陪你一起學習本次的內容,有什麼問題都可以問我喔!\n
 
2572
  gr.Image(value=chatbot_avatar_url, height=100, width=100, show_label=False, show_download_button=False)
2573
  chatbot_open_ai_select_btn = gr.Button("👆選擇【飛特精靈】", elem_id="chatbot_btn", visible=True, variant="primary")
2574
  gr.Markdown(value=chatbot_description, visible=True)
2575
+ with gr.Column(scale=1, variant="panel", visible=False):
2576
  streaming_chatbot_avatar_url = "https://storage.googleapis.com/wpassets.junyiacademy.org/1/2020/11/1-%E6%98%9F%E7%A9%BA%E9%A0%AD%E8%B2%BC-%E5%A4%AA%E7%A9%BA%E7%8B%90%E7%8B%B8%E8%B2%93-150x150.png"
2577
  streaming_chatbot_description = """Hi,我是【飛特音速】, \n
2578
  說話比較快,但有什麼問題都可以問我喔! \n
 
2604
  bot_avatar = "https://junyitopicimg.s3.amazonaws.com/s4byy--icon.jpe?v=20200513013523726"
2605
  latex_delimiters = [{"left": "$", "right": "$", "display": False}]
2606
  chatbot_greeting = [[
2607
+ "請問你是誰?",
2608
  """Hi,我是你的AI學伴【飛特精靈】,我可以陪你一起學習本次的內容,有什麼問題都可以問我喔!
2609
  🤔 如果你不知道怎麼發問,可以點擊左下方的問題一、問題二、問題三,我會幫你生成問題!
2610
  🗣️ 也可以點擊右下方用語音輸入,我會幫你轉換成文字,厲害吧!
 
2639
  """
2640
  additional_inputs = [password, video_id, user_data, streaming_chat_thread_id_state, trascript_state, key_moments_state, content_subject_state, content_grade_state]
2641
  streaming_chat = gr.ChatInterface(
2642
+ fn=chat_with_opan_ai_assistant_streaming,
2643
  additional_inputs=additional_inputs,
2644
  submit_btn="送出",
2645
  retry_btn=None,
 
2651
  with gr.Row("其他精靈") as chatbot_jutor:
2652
  with gr.Column():
2653
  ai_chatbot_greeting = [[
2654
+ "請問你是誰?",
2655
  """Hi,我是飛特精靈的朋友們【梨梨、麥麥、狐狸貓】,也可以陪你一起學習本次的內容,有什麼問題都可以問我喔!
2656
  🤔 如果你不知道怎麼發問,可以點擊左下方的問題一、問題二、問題三,我會幫你生成問題!
2657
  🗣️ 也可以點擊右下方用語音輸入,我會幫你轉換成文字,厲害吧!
 
2660
  """,
2661
  ]]
2662
  ai_chatbot_bot_avatar = "https://storage.googleapis.com/wpassets.junyiacademy.org/1/2019/11/%E5%9B%9B%E6%A0%BC%E6%95%85%E4%BA%8B-04.jpg"
2663
+ ai_name = gr.Dropdown(label="選擇 AI 助理", choices=[
2664
+ # ("梨梨","jutor"),
2665
+ ("麥麥","claude3"),
2666
+ ("狐狸貓","groq")],
2667
+ value="claude3"
2668
+ )
2669
  ai_chatbot = gr.Chatbot(avatar_images=[user_avatar, ai_chatbot_bot_avatar], label="ai_chatbot", show_share_button=False, likeable=True, show_label=False, latex_delimiters=latex_delimiters, value=ai_chatbot_greeting)
2670
  ai_chatbot_socratic_mode_btn = gr.Checkbox(label="蘇格拉底家教助理模式", value=True, visible=False)
2671
  with gr.Row():
 
2700
  with gr.Row():
2701
  worksheet_content_type_name = gr.Textbox(value="worksheet", visible=False)
2702
  worksheet_algorithm = gr.Dropdown(label="選擇教學策略或理論", choices=["Bloom認知階層理論", "Polya數學解題法", "CRA教學法"], value="Bloom認知階層理論", visible=False)
2703
+ worksheet_content_btn = gr.Button("生成學習單 📄", variant="primary", visible=False)
2704
  with gr.Accordion("微調", open=False):
2705
  worksheet_exam_result_fine_tune_prompt = gr.Textbox(label="根據結果,輸入你想更改的想法")
2706
  worksheet_exam_result_fine_tune_btn = gr.Button("微調結果", variant="primary")
 
2715
  worksheet_exam_result = gr.Markdown(label="初次生成結果", latex_delimiters = [{"left": "$", "right": "$", "display": False}])
2716
  worksheet_download_exam_result_button = gr.Button("轉成 word,完成後請點擊右下角 download 按鈕", variant="primary")
2717
  worksheet_exam_result_word_link = gr.File(label="Download Word")
2718
+ with gr.Tab("教案"):
2719
  with gr.Row():
2720
  with gr.Column(scale=1):
2721
  with gr.Row():
2722
  lesson_plan_content_type_name = gr.Textbox(value="lesson_plan", visible=False)
2723
  lesson_plan_time = gr.Slider(label="選擇課程時間(分鐘)", minimum=10, maximum=120, step=5, value=40)
2724
+ lesson_plan_btn = gr.Button("生成教案 📕", variant="primary", visible=False)
2725
  with gr.Accordion("微調", open=False):
2726
  lesson_plan_exam_result_fine_tune_prompt = gr.Textbox(label="根據結果,輸入你想更改的想法")
2727
  lesson_plan_exam_result_fine_tune_btn = gr.Button("微調結果", variant="primary")
 
2742
  with gr.Row():
2743
  exit_ticket_content_type_name = gr.Textbox(value="exit_ticket", visible=False)
2744
  exit_ticket_time = gr.Slider(label="選擇出場券時間(分鐘)", minimum=5, maximum=10, step=1, value=8)
2745
+ exit_ticket_btn = gr.Button("生成出場券 🎟️", variant="primary", visible=False)
2746
  with gr.Accordion("微調", open=False):
2747
  exit_ticket_exam_result_fine_tune_prompt = gr.Textbox(label="根據結果,輸入你想更改的想法")
2748
  exit_ticket_exam_result_fine_tune_btn = gr.Button("微調結果", variant="primary")
 
2829
  questions_edit_button = gr.Button("編輯", size="sm", variant="primary")
2830
  questions_update_button = gr.Button("儲存", size="sm", variant="primary")
2831
  questions_delete_button = gr.Button("刪除", size="sm", variant="primary")
2832
+ questions_create_button = gr.Button("重建", size="sm", variant="primary")
2833
  with gr.Row():
2834
  questions_json = gr.Textbox(label="Questions", lines=40, interactive=False, show_copy_button=True)
2835
+ with gr.Tab("問題答案本文"):
2836
+ with gr.Row() as questions_answers_admin:
2837
+ questions_answers_kind = gr.Textbox(value="questions_answers", show_label=False)
2838
+ questions_answers_get_button = gr.Button("取得", size="sm", variant="primary")
2839
+ questions_answers_edit_button = gr.Button("編輯", size="sm", variant="primary")
2840
+ questions_answers_update_button = gr.Button("儲存", size="sm", variant="primary")
2841
+ questions_answers_delete_button = gr.Button("刪除", size="sm", variant="primary")
2842
+ questions_answers_create_button = gr.Button("重建", size="sm", variant="primary")
2843
+ with gr.Row():
2844
+ questions_answers_json = gr.Textbox(label="Questions Answers", lines=40, interactive=False, show_copy_button=True)
2845
  with gr.Tab("逐字稿"):
2846
  simple_html_content = gr.HTML(label="Simple Transcript")
2847
  with gr.Tab("圖文"):
 
2871
  chatbot_select,
2872
  inputs=[chatbot_open_ai_streaming_name],
2873
  outputs=[chatbot_select_accordion, chatbot_open_ai, chatbot_open_ai_streaming, chatbot_jutor]
2874
+ ).then(
2875
+ create_thread_id,
2876
+ inputs=[],
2877
+ outputs=[streaming_chat_thread_id_state]
2878
  )
2879
  chatbot_jutor_select_btn.click(
2880
  chatbot_select,
 
2885
  # OPENAI ASSISTANT CHATBOT 模式
2886
  send_button.click(
2887
  chat_with_opan_ai_assistant,
2888
+ inputs=[password, video_id, user_data, thread_id, trascript_state, key_moments, msg, chatbot, content_subject, content_grade, questions_answers_json, socratic_mode_btn],
2889
  outputs=[msg, chatbot, thread_id],
2890
  scroll_to_output=True
2891
  )
 
2895
  outputs=[msg]
2896
  )
2897
  # OPENAI ASSISTANT CHATBOT 連接按鈕點擊事件
2898
+ btn_1_chat_with_opan_ai_assistant_input =[password, video_id, user_data, thread_id, trascript_state, key_moments, btn_1, chatbot, content_subject, content_grade, questions_answers_json, ai_chatbot_socratic_mode_btn]
2899
+ btn_2_chat_with_opan_ai_assistant_input =[password, video_id, user_data, thread_id, trascript_state, key_moments, btn_2, chatbot, content_subject, content_grade, questions_answers_json, ai_chatbot_socratic_mode_btn]
2900
+ btn_3_chat_with_opan_ai_assistant_input =[password, video_id, user_data, thread_id, trascript_state, key_moments, btn_3, chatbot, content_subject, content_grade, questions_answers_json, ai_chatbot_socratic_mode_btn]
2901
  btn_1.click(
2902
  chat_with_opan_ai_assistant,
2903
  inputs=btn_1_chat_with_opan_ai_assistant_input,
 
2925
  # 其他精靈 ai_chatbot 模式
2926
  ai_send_button.click(
2927
  chat_with_ai,
2928
+ inputs=[ai_name, password, video_id, user_data, trascript_state, key_moments, ai_msg, ai_chatbot, content_subject, content_grade, questions_answers_json, ai_chatbot_socratic_mode_btn],
2929
  outputs=[ai_msg, ai_chatbot],
2930
  scroll_to_output=True
2931
  )
2932
  # 其他精靈 ai_chatbot 连接按钮点击事件
2933
+ ai_chatbot_question_1_chat_with_ai_input =[ai_name, password, video_id, user_data, trascript_state, key_moments, ai_chatbot_question_1, ai_chatbot, content_subject, content_grade, questions_answers_json, ai_chatbot_socratic_mode_btn]
2934
+ ai_chatbot_question_2_chat_with_ai_input =[ai_name, password, video_id, user_data, trascript_state, key_moments, ai_chatbot_question_2, ai_chatbot, content_subject, content_grade, questions_answers_json, ai_chatbot_socratic_mode_btn]
2935
+ ai_chatbot_question_3_chat_with_ai_input =[ai_name, password, video_id, user_data, trascript_state, key_moments, ai_chatbot_question_3, ai_chatbot, content_subject, content_grade, questions_answers_json, ai_chatbot_socratic_mode_btn]
2936
  ai_chatbot_question_1.click(
2937
  chat_with_ai,
2938
  inputs=ai_chatbot_question_1_chat_with_ai_input,
 
2959
  process_youtube_link_inputs = [password, youtube_link]
2960
  process_youtube_link_outputs = [
2961
  video_id,
2962
+ questions_answers_json,
 
 
 
2963
  df_string_output,
2964
  summary_text,
2965
  df_summarise,
 
2981
  content_grade,
2982
  df_string_output,
2983
  key_moments,
2984
+ questions_answers_json,
 
 
2985
  ]
2986
  update_state_outputs = [
2987
  content_subject_state,
 
2989
  trascript_state,
2990
  key_moments_state,
2991
  streaming_chat_thread_id_state,
2992
+ btn_1,
2993
+ btn_2,
2994
+ btn_3,
2995
  ai_chatbot_question_1,
2996
  ai_chatbot_question_2,
2997
  ai_chatbot_question_3
 
3165
  inputs=[video_id, questions_json, questions_kind],
3166
  outputs=[questions_json]
3167
  )
3168
+ # questions_answers event
3169
+ questions_answers_get_button.click(
3170
+ get_LLM_content,
3171
+ inputs=[video_id, questions_answers_kind],
3172
+ outputs=[questions_answers_json]
3173
+ )
3174
+ questions_answers_create_button.click(
3175
+ create_LLM_content,
3176
+ inputs=[video_id, df_string_output, questions_answers_kind],
3177
+ outputs=[questions_answers_json]
3178
+ )
3179
+ questions_answers_delete_button.click(
3180
+ delete_LLM_content,
3181
+ inputs=[video_id, questions_answers_kind],
3182
+ outputs=[questions_answers_json]
3183
+ )
3184
+ questions_answers_edit_button.click(
3185
+ enable_edit_mode,
3186
+ inputs=[],
3187
+ outputs=[questions_answers_json]
3188
+ )
3189
+ questions_answers_update_button.click(
3190
+ update_LLM_content,
3191
+ inputs=[video_id, questions_answers_json, questions_answers_kind],
3192
+ outputs=[questions_answers_json]
3193
+ )
3194
+
3195
 
3196
  # 教師版
3197
  worksheet_content_btn.click(
chatbot.py CHANGED
@@ -61,7 +61,7 @@ class Chatbot:
61
  messages.append({"role": "assistant", "content": assistant_msg})
62
 
63
  if user_message:
64
- user_message += "/n (請一定要用繁體中文回答 zh-TW,並用台灣人的禮貌口語表達,回答時不要特別說明這是台灣人的語氣,不用提到「逐字稿」這個詞,用「內容」代替),回答時請用數學符號代替文字(Latex 用 $ 字號 render)"
65
  messages.append({"role": "user", "content": user_message})
66
  return messages
67
 
 
61
  messages.append({"role": "assistant", "content": assistant_msg})
62
 
63
  if user_message:
64
+ user_message += "/n (請一定要用繁體中文回答 zh-TW,並用台灣人的禮貌口語表達,回答時不要特別說明這是台灣人的語氣,不用提到「逐字稿」這個詞,用「內容」代替),回答時如果有用到數學式,請用數學符號代替純文字(Latex 用 $ 字號 render)"
65
  messages.append({"role": "user", "content": user_message})
66
  return messages
67