youngtsai commited on
Commit
8080a34
1 Parent(s): 834474b
Files changed (4) hide show
  1. app.py +303 -114
  2. chatbot.py +1 -1
  3. educational_material.py +1 -1
  4. requirements.txt +1 -1
app.py CHANGED
@@ -1,7 +1,6 @@
1
  import gradio as gr
2
  import pandas as pd
3
  import requests
4
- from bs4 import BeautifulSoup
5
  from docx import Document
6
  import os
7
  from openai import OpenAI
@@ -22,10 +21,11 @@ import os
22
  import io
23
  import time
24
  import json
25
- from datetime import timedelta
26
  from urllib.parse import urlparse, parse_qs
27
 
28
  from google.cloud import storage
 
29
  from google.oauth2 import service_account
30
  from googleapiclient.discovery import build
31
  from googleapiclient.http import MediaFileUpload
@@ -53,6 +53,7 @@ if is_env_local:
53
  PASSWORD = config["PASSWORD"]
54
  GCS_KEY = json.dumps(config["GOOGLE_APPLICATION_CREDENTIALS_JSON"])
55
  DRIVE_KEY = json.dumps(config["GOOGLE_APPLICATION_CREDENTIALS_JSON"])
 
56
  OPEN_AI_KEY = config["OPEN_AI_KEY"]
57
  OPEN_AI_ASSISTANT_ID_GPT4_BOT1 = config["OPEN_AI_ASSISTANT_ID_GPT4_BOT1"]
58
  OPEN_AI_ASSISTANT_ID_GPT3_BOT1 = config["OPEN_AI_ASSISTANT_ID_GPT3_BOT1"]
@@ -71,6 +72,7 @@ else:
71
  PASSWORD = os.getenv("PASSWORD")
72
  GCS_KEY = os.getenv("GOOGLE_APPLICATION_CREDENTIALS_JSON")
73
  DRIVE_KEY = os.getenv("GOOGLE_APPLICATION_CREDENTIALS_JSON")
 
74
  OPEN_AI_KEY = os.getenv("OPEN_AI_KEY")
75
  OPEN_AI_ASSISTANT_ID_GPT4_BOT1 = os.getenv("OPEN_AI_ASSISTANT_ID_GPT4_BOT1")
76
  OPEN_AI_ASSISTANT_ID_GPT3_BOT1 = os.getenv("OPEN_AI_ASSISTANT_ID_GPT3_BOT1")
@@ -86,9 +88,10 @@ else:
86
 
87
  TRANSCRIPTS = []
88
  CURRENT_INDEX = 0
89
- CHAT_LIMIT = 10
90
 
91
  # CLIENTS CONFIG
 
92
  GROQ_CLIENT = Groq(api_key=GROQ_API_KEY)
93
  GCS_SERVICE = GoogleCloudStorage(GCS_KEY)
94
  GCS_CLIENT = GCS_SERVICE.client
@@ -706,7 +709,9 @@ def split_data(df_string, word_base=100000):
706
  def generate_content_by_open_ai(sys_content, user_content, response_format=None):
707
  print("LLM using OPEN AI")
708
  # model = "gpt-4-turbo"
709
- model = "gpt-4o"
 
 
710
  messages = [
711
  {"role": "system", "content": sys_content},
712
  {"role": "user", "content": user_content}
@@ -724,39 +729,40 @@ def generate_content_by_open_ai(sys_content, user_content, response_format=None)
724
  content = response.choices[0].message.content.strip()
725
  return content
726
 
727
- def generate_content_by_bedrock(sys_content, user_content):
728
- print("LLM using REDROCK")
729
- messages = [
730
- {"role": "user", "content": user_content +"(如果是 JSON 格式,value 的引號,請用單引號,或是用反斜線+雙引號,避免 JSON Decoder error )"}
731
- ]
732
- model_id = "anthropic.claude-3-sonnet-20240229-v1:0"
733
- # model_id = "anthropic.claude-3-haiku-20240307-v1:0"
734
- kwargs = {
735
- "modelId": model_id,
736
- "contentType": "application/json",
737
- "accept": "application/json",
738
- "body": json.dumps({
739
- "anthropic_version": "bedrock-2023-05-31",
740
- "max_tokens": 4000,
741
- "system": sys_content,
742
- "messages": messages
743
- })
744
- }
745
- response = BEDROCK_CLIENT.invoke_model(**kwargs)
746
- response_body = json.loads(response.get('body').read())
747
- content = response_body.get('content')[0].get('text')
748
- return content
 
749
 
750
  def generate_content_by_LLM(sys_content, user_content, response_format=None, LLM_model=None):
751
  # 使用 OpenAI 生成基于上传数据的问题
752
 
753
- if LLM_model == "anthropic-claude-3-sonnet":
754
- print(f"LLM: {LLM_model}")
755
- content = generate_content_by_bedrock(sys_content, user_content)
756
- else:
757
- print(f"LLM: {LLM_model}")
758
- content = generate_content_by_open_ai(sys_content, user_content, response_format)
759
-
760
  print("=====content=====")
761
  print(content)
762
  print("=====content=====")
@@ -1221,7 +1227,6 @@ def change_questions(password, df_string):
1221
  def get_key_moments(video_id, formatted_simple_transcript, formatted_transcript, source, LLM_model=None):
1222
  if source == "gcs":
1223
  print("===get_key_moments on gcs===")
1224
- gcs_client = GCS_CLIENT
1225
  bucket_name = 'video_ai_assistant'
1226
  file_name = f'{video_id}_key_moments.json'
1227
  blob_name = f"{video_id}/{file_name}"
@@ -1254,6 +1259,18 @@ def get_key_moments(video_id, formatted_simple_transcript, formatted_transcript,
1254
  GCS_SERVICE.upload_json_string(bucket_name, blob_name, key_moments_text)
1255
  key_moments_text = GCS_SERVICE.download_as_string(bucket_name, blob_name)
1256
  key_moments_json = json.loads(key_moments_text)
 
 
 
 
 
 
 
 
 
 
 
 
1257
 
1258
  elif source == "drive":
1259
  print("===get_key_moments on drive===")
@@ -1329,6 +1346,13 @@ def generate_key_moments(formatted_simple_transcript, formatted_transcript, LLM_
1329
  if start_time <= parse_time(time) <= end_time]
1330
  moment['images'] = moment_images
1331
 
 
 
 
 
 
 
 
1332
  all_content += key_moments
1333
 
1334
  return all_content
@@ -1352,6 +1376,51 @@ def generate_key_moments_keywords(transcript, LLM_model=None):
1352
 
1353
  return all_content
1354
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1355
  def get_key_moments_html(key_moments):
1356
  css = """
1357
  <style>
@@ -1534,7 +1603,7 @@ def get_key_moments_html(key_moments):
1534
  key_moments_html = css
1535
 
1536
  for i, moment in enumerate(key_moments):
1537
- images = moment['images']
1538
  image_elements = ""
1539
 
1540
  for j, image in enumerate(images):
@@ -1909,7 +1978,7 @@ def get_meta_data(video_id, source="gcs"):
1909
 
1910
  return meta_data_json
1911
 
1912
- def get_ai_content(password, video_id, df_string, topic, grade, level, specific_feature, content_type, source="gcs"):
1913
  verify_password(password)
1914
  if source == "gcs":
1915
  print("===get_ai_content on gcs===")
@@ -1955,10 +2024,27 @@ def get_ai_content(password, video_id, df_string, topic, grade, level, specific_
1955
  ai_content_text = json.dumps(ai_content_list, ensure_ascii=False, indent=2)
1956
  GCS_SERVICE.upload_json_string(bucket_name, blob_name, ai_content_text)
1957
  print("ai_content已上傳到GCS")
 
 
 
 
1958
  else:
1959
  ai_content_json = ai_content_json[-1]
1960
  ai_content = ai_content_json["content"]
1961
  prompt = ai_content_json["prompt"]
 
 
 
 
 
 
 
 
 
 
 
 
 
1962
 
1963
  return ai_content, ai_content, prompt, prompt
1964
 
@@ -1977,7 +2063,7 @@ def generate_ai_content(password, df_string, topic, grade, level, specific_featu
1977
 
1978
  return ai_content, prompt
1979
 
1980
- def generate_exam_fine_tune_result(password, exam_result_prompt , df_string_output, exam_result, exam_result_fine_tune_prompt):
1981
  verify_password(password)
1982
  material = EducationalMaterial(df_string_output, "", "", "", "", "")
1983
  try:
@@ -1985,6 +2071,20 @@ def generate_exam_fine_tune_result(password, exam_result_prompt , df_string_outp
1985
  except:
1986
  fine_tuned_ai_content = material.get_fine_tuned_ai_content(BEDROCK_CLIENT, "bedrock", exam_result_prompt, exam_result, exam_result_fine_tune_prompt)
1987
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1988
  return fine_tuned_ai_content
1989
 
1990
  def return_original_exam_result(exam_result_original):
@@ -2059,6 +2159,7 @@ def get_instructions(content_subject, content_grade, key_moments, socratic_mode=
2059
  def chat_with_any_ai(ai_type, password, video_id, user_data, transcript_state, key_moments, user_message, chat_history, content_subject, content_grade, questions_answers_json, socratic_mode=False, thread_id=None, ai_name=None):
2060
  print(f"ai_type: {ai_type}")
2061
  print(f"user_data: {user_data}")
 
2062
  verify_password(password)
2063
  verify_message_length(user_message, max_length=1500)
2064
 
@@ -2076,7 +2177,21 @@ def chat_with_any_ai(ai_type, password, video_id, user_data, transcript_state, k
2076
  chatbot_config = get_chatbot_config(ai_name, transcript_state, key_moments, content_subject, content_grade, video_id, socratic_mode)
2077
  chatbot = Chatbot(chatbot_config)
2078
  response_text = chatbot.chat(user_message, chat_history)
2079
- thread_id = ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2080
  elif ai_type == "assistant":
2081
  client = OPEN_AI_CLIENT
2082
  assistant_id = OPEN_AI_ASSISTANT_ID_GPT4 #GPT 4 turbo
@@ -2109,6 +2224,23 @@ def chat_with_any_ai(ai_type, password, video_id, user_data, transcript_state, k
2109
  chat_history = update_chat_history(user_message, response_text, chat_history)
2110
  send_btn_update, send_feedback_btn_update = update_send_and_feedback_buttons(chat_history, CHAT_LIMIT)
2111
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2112
  # 返回聊天历史和空字符串清空输入框
2113
  return "", chat_history, send_btn_update, send_feedback_btn_update, thread_id
2114
 
@@ -2122,10 +2254,15 @@ def get_chatbot_config(ai_name, transcript_state, key_moments, content_subject,
2122
  "ai_client": GROQ_CLIENT,
2123
  "ai_model_name": "groq_llama3",
2124
  },
 
 
 
 
 
2125
  "lili": {
2126
  "ai_name": "lili",
2127
- "ai_client": BEDROCK_CLIENT,
2128
- "ai_model_name": "claude3",
2129
  },
2130
  "maimai": {
2131
  "ai_name": "maimai",
@@ -2168,7 +2305,7 @@ def get_chatbot_config(ai_name, transcript_state, key_moments, content_subject,
2168
 
2169
  return chatbot_config
2170
 
2171
- def feedback_with_ai(ai_type, chat_history, thread_id=None):
2172
  # prompt: 請依據以上的對話(chat_history),總結我的「提問力」,並給予我是否有「問對問題」的回饋和建議
2173
  system_content = """
2174
  你是一個擅長引導問答素養的老師,user 為學生的提問跟回答,請精讀對話過程,針對 user 給予回饋就好,根據以下 Rule:
@@ -2217,6 +2354,22 @@ def feedback_with_ai(ai_type, chat_history, thread_id=None):
2217
  chat_history = update_chat_history(feedback_request_message, response_text, chat_history)
2218
  feedback_btn_update = gr.update(value="已回饋", interactive=False, variant="secondary")
2219
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2220
  return chat_history, feedback_btn_update
2221
 
2222
  def handle_conversation_by_open_ai_chat_completions(client, model_name, user_content, system_content):
@@ -2264,6 +2417,7 @@ def handle_conversation_by_open_ai_assistant(client, user_message, instructions,
2264
 
2265
  if run_status == "completed":
2266
  messages = client.beta.threads.messages.list(thread_id=thread.id)
 
2267
  response_text = messages.data[0].content[0].text.value
2268
  else:
2269
  response_text = "學習精靈有點累,請稍後再試!"
@@ -2492,17 +2646,17 @@ def chat_with_opan_ai_assistant_streaming(user_message, chat_history, password,
2492
  else:
2493
  thread = client.beta.threads.retrieve(thread_id)
2494
  print(f"old thread_id: {thread_id}")
2495
-
 
 
 
 
 
 
 
2496
  client.beta.threads.update(
2497
  thread_id=thread_id,
2498
- metadata={
2499
- "youtube_id": video_id,
2500
- "user_data": user_data,
2501
- "content_subject": content_subject,
2502
- "content_grade": content_grade,
2503
- "assistant_id": assistant_id,
2504
- "is_streaming": "true",
2505
- }
2506
  )
2507
 
2508
  # 向线程添加用户的消息
@@ -2527,6 +2681,22 @@ def chat_with_opan_ai_assistant_streaming(user_message, chat_history, password,
2527
  except Exception as e:
2528
  print(f"Error: {e}")
2529
  raise gr.Error(f"Error: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2530
 
2531
  def create_thread_id():
2532
  thread = OPEN_AI_CLIENT.beta.threads.create()
@@ -2571,6 +2741,26 @@ def show_all_chatbot_accordion():
2571
  all_chatbot_select_btn_visible = gr.update(visible=False)
2572
  return chatbot_select_accordion_visible, all_chatbot_select_btn_visible
2573
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2574
 
2575
  # --- Init params ---
2576
  def init_params(text, request: gr.Request):
@@ -2866,19 +3056,18 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
2866
  worksheet_algorithm = gr.Dropdown(label="選擇教學策略或理論", choices=["Bloom認知階層理論", "Polya數學解題法", "CRA教學法"], value="Bloom認知階層理論", visible=False)
2867
  worksheet_content_btn = gr.Button("生成學習單 📄", variant="primary", visible=True)
2868
  with gr.Accordion("微調", open=False):
2869
- worksheet_exam_result_fine_tune_prompt = gr.Textbox(label="根據結果,輸入你想更改的想法")
2870
- worksheet_exam_result_fine_tune_btn = gr.Button("微調結果", variant="primary")
2871
- worksheet_exam_result_retrun_original = gr.Button("返回原始結果")
2872
  with gr.Accordion("prompt", open=False) as worksheet_accordion:
2873
  worksheet_prompt = gr.Textbox(label="worksheet_prompt", show_copy_button=True, lines=40)
2874
  with gr.Column(scale=2):
2875
  # 生成對應不同模式的結果
2876
- worksheet_exam_result_prompt = gr.Textbox(visible=False)
2877
- worksheet_exam_result_original = gr.Textbox(visible=False)
2878
- # worksheet_exam_result = gr.Textbox(label="初次生成結果", show_copy_button=True, interactive=True, lines=40)
2879
- worksheet_exam_result = gr.Markdown(label="初次生成結果", latex_delimiters = [{"left": "$", "right": "$", "display": False}])
2880
- worksheet_download_exam_result_button = gr.Button("轉成 word,完成後請點擊右下角 download 按鈕", variant="primary")
2881
- worksheet_exam_result_word_link = gr.File(label="Download Word")
2882
  with gr.Tab("教案"):
2883
  with gr.Row():
2884
  with gr.Column(scale=1):
@@ -2887,19 +3076,19 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
2887
  lesson_plan_time = gr.Slider(label="選擇課程時間(分鐘)", minimum=10, maximum=120, step=5, value=40)
2888
  lesson_plan_btn = gr.Button("生成教案 📕", variant="primary", visible=True)
2889
  with gr.Accordion("微調", open=False):
2890
- lesson_plan_exam_result_fine_tune_prompt = gr.Textbox(label="根據結果,輸入你想更改的想法")
2891
- lesson_plan_exam_result_fine_tune_btn = gr.Button("微調結果", variant="primary")
2892
- lesson_plan_exam_result_retrun_original = gr.Button("返回原始結果")
2893
  with gr.Accordion("prompt", open=False) as lesson_plan_accordion:
2894
  lesson_plan_prompt = gr.Textbox(label="worksheet_prompt", show_copy_button=True, lines=40)
2895
  with gr.Column(scale=2):
2896
  # 生成對應不同模式的結果
2897
- lesson_plan_exam_result_prompt = gr.Textbox(visible=False)
2898
- lesson_plan_exam_result_original = gr.Textbox(visible=False)
2899
- lesson_plan_exam_result = gr.Markdown(label="初次生成結果", latex_delimiters = [{"left": "$", "right": "$", "display": False}])
2900
 
2901
- lesson_plan_download_exam_result_button = gr.Button("轉成 word,完成後請點擊右下角 download 按鈕", variant="primary")
2902
- lesson_plan_exam_result_word_link = gr.File(label="Download Word")
2903
  with gr.Tab("出場券"):
2904
  with gr.Row():
2905
  with gr.Column(scale=1):
@@ -2908,19 +3097,19 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
2908
  exit_ticket_time = gr.Slider(label="選擇出場券時間(分鐘)", minimum=5, maximum=10, step=1, value=8)
2909
  exit_ticket_btn = gr.Button("生成出場券 🎟️", variant="primary", visible=True)
2910
  with gr.Accordion("微調", open=False):
2911
- exit_ticket_exam_result_fine_tune_prompt = gr.Textbox(label="根據結果,輸入你想更改的想法")
2912
- exit_ticket_exam_result_fine_tune_btn = gr.Button("微調結果", variant="primary")
2913
- exit_ticket_exam_result_retrun_original = gr.Button("返回原始結果")
2914
  with gr.Accordion("prompt", open=False) as exit_ticket_accordion:
2915
  exit_ticket_prompt = gr.Textbox(label="worksheet_prompt", show_copy_button=True, lines=40)
2916
  with gr.Column(scale=2):
2917
  # 生成對應不同模式的結果
2918
- exit_ticket_exam_result_prompt = gr.Textbox(visible=False)
2919
- exit_ticket_exam_result_original = gr.Textbox(visible=False)
2920
- exit_ticket_exam_result = gr.Markdown(label="初次生成結果", latex_delimiters = [{"left": "$", "right": "$", "display": False}])
2921
 
2922
- exit_ticket_download_exam_result_button = gr.Button("轉成 word,完成後請點擊右下角 download 按鈕", variant="primary")
2923
- exit_ticket_exam_result_word_link = gr.File(label="Download Word")
2924
 
2925
 
2926
  # with gr.Tab("素養導向閱讀題組"):
@@ -2940,7 +3129,7 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
2940
  with gr.Accordion("See Details", open=False) as see_details:
2941
  with gr.Row():
2942
  is_env_prod = gr.Checkbox(value=False, label="is_env_prod")
2943
- LLM_model = gr.Dropdown(label="LLM Model", choices=["open-ai-gpt-4", "anthropic-claude-3-sonnet"], value="open-ai-gpt-4", visible=True, interactive=True)
2944
  with gr.Tab("逐字稿本文"):
2945
  with gr.Row() as transcript_admmin:
2946
  transcript_kind = gr.Textbox(value="transcript", show_label=False)
@@ -3131,7 +3320,7 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
3131
  )
3132
  ai_send_feedback_btn.click(
3133
  feedback_with_ai,
3134
- inputs=[ai_chatbot_ai_type, ai_chatbot, ai_chatbot_thread_id],
3135
  outputs=[ai_chatbot, ai_send_feedback_btn],
3136
  scroll_to_output=True
3137
  )
@@ -3468,76 +3657,76 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
3468
  {
3469
  "button": worksheet_content_btn,
3470
  "action": get_ai_content,
3471
- "inputs": [password, video_id, df_string_output, content_subject, content_grade, content_level, worksheet_algorithm, worksheet_content_type_name],
3472
- "outputs": [worksheet_exam_result_original, worksheet_exam_result, worksheet_prompt, worksheet_exam_result_prompt]
3473
  },
3474
  {
3475
- "button": worksheet_exam_result_fine_tune_btn,
3476
- "action": generate_exam_fine_tune_result,
3477
- "inputs": [password, worksheet_exam_result_prompt, df_string_output, worksheet_exam_result, worksheet_exam_result_fine_tune_prompt],
3478
- "outputs": [worksheet_exam_result]
3479
  },
3480
  {
3481
- "button": worksheet_download_exam_result_button,
3482
  "action": download_exam_result,
3483
- "inputs": [worksheet_exam_result],
3484
- "outputs": [worksheet_exam_result_word_link]
3485
  },
3486
  {
3487
- "button": worksheet_exam_result_retrun_original,
3488
  "action": return_original_exam_result,
3489
- "inputs": [worksheet_exam_result_original],
3490
- "outputs": [worksheet_exam_result]
3491
  },
3492
  # 教案相關按鈕
3493
  {
3494
  "button": lesson_plan_btn,
3495
  "action": get_ai_content,
3496
- "inputs": [password, video_id, df_string_output, content_subject, content_grade, content_level, lesson_plan_time, lesson_plan_content_type_name],
3497
- "outputs": [lesson_plan_exam_result_original, lesson_plan_exam_result, lesson_plan_prompt, lesson_plan_exam_result_prompt]
3498
  },
3499
  {
3500
- "button": lesson_plan_exam_result_fine_tune_btn,
3501
- "action": generate_exam_fine_tune_result,
3502
- "inputs": [password, lesson_plan_exam_result_prompt, df_string_output, lesson_plan_exam_result, lesson_plan_exam_result_fine_tune_prompt],
3503
- "outputs": [lesson_plan_exam_result]
3504
  },
3505
  {
3506
- "button": lesson_plan_download_exam_result_button,
3507
  "action": download_exam_result,
3508
- "inputs": [lesson_plan_exam_result],
3509
- "outputs": [lesson_plan_exam_result_word_link]
3510
  },
3511
  {
3512
- "button": lesson_plan_exam_result_retrun_original,
3513
  "action": return_original_exam_result,
3514
- "inputs": [lesson_plan_exam_result_original],
3515
- "outputs": [lesson_plan_exam_result]
3516
  },
3517
  # 出場券相關按鈕
3518
  {
3519
  "button": exit_ticket_btn,
3520
  "action": get_ai_content,
3521
- "inputs": [password, video_id, df_string_output, content_subject, content_grade, content_level, exit_ticket_time, exit_ticket_content_type_name],
3522
- "outputs": [exit_ticket_exam_result_original, exit_ticket_exam_result, exit_ticket_prompt, exit_ticket_exam_result_prompt]
3523
  },
3524
  {
3525
- "button": exit_ticket_exam_result_fine_tune_btn,
3526
- "action": generate_exam_fine_tune_result,
3527
- "inputs": [password, exit_ticket_exam_result_prompt, df_string_output, exit_ticket_exam_result, exit_ticket_exam_result_fine_tune_prompt],
3528
- "outputs": [exit_ticket_exam_result]
3529
  },
3530
  {
3531
- "button": exit_ticket_download_exam_result_button,
3532
  "action": download_exam_result,
3533
- "inputs": [exit_ticket_exam_result],
3534
- "outputs": [exit_ticket_exam_result_word_link]
3535
  },
3536
  {
3537
- "button": exit_ticket_exam_result_retrun_original,
3538
  "action": return_original_exam_result,
3539
- "inputs": [exit_ticket_exam_result_original],
3540
- "outputs": [exit_ticket_exam_result]
3541
  }
3542
  ]
3543
  setup_education_buttons(education_buttons_config)
@@ -3564,4 +3753,4 @@ with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, seconda
3564
  outputs = init_outputs
3565
  )
3566
 
3567
- demo.launch(allowed_paths=["videos"])
 
1
  import gradio as gr
2
  import pandas as pd
3
  import requests
 
4
  from docx import Document
5
  import os
6
  from openai import OpenAI
 
21
  import io
22
  import time
23
  import json
24
+ from datetime import datetime, timezone, timedelta
25
  from urllib.parse import urlparse, parse_qs
26
 
27
  from google.cloud import storage
28
+ from google.cloud import bigquery
29
  from google.oauth2 import service_account
30
  from googleapiclient.discovery import build
31
  from googleapiclient.http import MediaFileUpload
 
53
  PASSWORD = config["PASSWORD"]
54
  GCS_KEY = json.dumps(config["GOOGLE_APPLICATION_CREDENTIALS_JSON"])
55
  DRIVE_KEY = json.dumps(config["GOOGLE_APPLICATION_CREDENTIALS_JSON"])
56
+ GBQ_KEY = json.dumps(config["GOOGLE_APPLICATION_CREDENTIALS_JSON"])
57
  OPEN_AI_KEY = config["OPEN_AI_KEY"]
58
  OPEN_AI_ASSISTANT_ID_GPT4_BOT1 = config["OPEN_AI_ASSISTANT_ID_GPT4_BOT1"]
59
  OPEN_AI_ASSISTANT_ID_GPT3_BOT1 = config["OPEN_AI_ASSISTANT_ID_GPT3_BOT1"]
 
72
  PASSWORD = os.getenv("PASSWORD")
73
  GCS_KEY = os.getenv("GOOGLE_APPLICATION_CREDENTIALS_JSON")
74
  DRIVE_KEY = os.getenv("GOOGLE_APPLICATION_CREDENTIALS_JSON")
75
+ GBQ_KEY = os.getenv("GOOGLE_APPLICATION_CREDENTIALS_JSON")
76
  OPEN_AI_KEY = os.getenv("OPEN_AI_KEY")
77
  OPEN_AI_ASSISTANT_ID_GPT4_BOT1 = os.getenv("OPEN_AI_ASSISTANT_ID_GPT4_BOT1")
78
  OPEN_AI_ASSISTANT_ID_GPT3_BOT1 = os.getenv("OPEN_AI_ASSISTANT_ID_GPT3_BOT1")
 
88
 
89
  TRANSCRIPTS = []
90
  CURRENT_INDEX = 0
91
+ CHAT_LIMIT = 5
92
 
93
  # CLIENTS CONFIG
94
+ GBQ_CLIENT = bigquery.Client.from_service_account_info(json.loads(GBQ_KEY))
95
  GROQ_CLIENT = Groq(api_key=GROQ_API_KEY)
96
  GCS_SERVICE = GoogleCloudStorage(GCS_KEY)
97
  GCS_CLIENT = GCS_SERVICE.client
 
709
  def generate_content_by_open_ai(sys_content, user_content, response_format=None):
710
  print("LLM using OPEN AI")
711
  # model = "gpt-4-turbo"
712
+ model = "gpt-4o"
713
+ print(f"model: {model}")
714
+
715
  messages = [
716
  {"role": "system", "content": sys_content},
717
  {"role": "user", "content": user_content}
 
729
  content = response.choices[0].message.content.strip()
730
  return content
731
 
732
+ # def generate_content_by_bedrock(sys_content, user_content):
733
+ # print("LLM using REDROCK")
734
+ # messages = [
735
+ # {"role": "user", "content": user_content +"(如果是 JSON 格式,value 的引號,請用單引號,或是用反斜線+雙引號,避免 JSON Decoder error )"}
736
+ # ]
737
+ # model_id = "anthropic.claude-3-sonnet-20240229-v1:0"
738
+ # print(f"model_id: {model_id}")
739
+ # # model_id = "anthropic.claude-3-haiku-20240307-v1:0"
740
+ # kwargs = {
741
+ # "modelId": model_id,
742
+ # "contentType": "application/json",
743
+ # "accept": "application/json",
744
+ # "body": json.dumps({
745
+ # "anthropic_version": "bedrock-2023-05-31",
746
+ # "max_tokens": 4000,
747
+ # "system": sys_content,
748
+ # "messages": messages
749
+ # })
750
+ # }
751
+ # response = BEDROCK_CLIENT.invoke_model(**kwargs)
752
+ # response_body = json.loads(response.get('body').read())
753
+ # content = response_body.get('content')[0].get('text')
754
+ # return content
755
 
756
  def generate_content_by_LLM(sys_content, user_content, response_format=None, LLM_model=None):
757
  # 使用 OpenAI 生成基于上传数据的问题
758
 
759
+ # if LLM_model == "anthropic-claude-3-sonnet":
760
+ # print(f"LLM: {LLM_model}")
761
+ # content = generate_content_by_bedrock(sys_content, user_content)
762
+ # else:
763
+ print(f"LLM: {LLM_model}")
764
+ content = generate_content_by_open_ai(sys_content, user_content, response_format)
765
+
766
  print("=====content=====")
767
  print(content)
768
  print("=====content=====")
 
1227
  def get_key_moments(video_id, formatted_simple_transcript, formatted_transcript, source, LLM_model=None):
1228
  if source == "gcs":
1229
  print("===get_key_moments on gcs===")
 
1230
  bucket_name = 'video_ai_assistant'
1231
  file_name = f'{video_id}_key_moments.json'
1232
  blob_name = f"{video_id}/{file_name}"
 
1259
  GCS_SERVICE.upload_json_string(bucket_name, blob_name, key_moments_text)
1260
  key_moments_text = GCS_SERVICE.download_as_string(bucket_name, blob_name)
1261
  key_moments_json = json.loads(key_moments_text)
1262
+ # 檢查 key_moments 是否有 suggested_images
1263
+ print("===檢查 key_moments 是否有 suggested_images===")
1264
+ has_suggested_images_added = False
1265
+ for key_moment in key_moments_json["key_moments"]:
1266
+ if "suggested_images" not in key_moment:
1267
+ key_moment["suggested_images"] = generate_key_moments_suggested_images(key_moment)
1268
+ has_suggested_images_added = True
1269
+ if has_suggested_images_added:
1270
+ key_moments_text = json.dumps(key_moments_json, ensure_ascii=False, indent=2)
1271
+ GCS_SERVICE.upload_json_string(bucket_name, blob_name, key_moments_text)
1272
+ key_moments_text = GCS_SERVICE.download_as_string(bucket_name, blob_name)
1273
+ key_moments_json = json.loads(key_moments_text)
1274
 
1275
  elif source == "drive":
1276
  print("===get_key_moments on drive===")
 
1346
  if start_time <= parse_time(time) <= end_time]
1347
  moment['images'] = moment_images
1348
 
1349
+ # 檢查是否有 suggested_images
1350
+ if "suggested_images" not in moment:
1351
+ moment["suggested_images"] = generate_key_moments_suggested_images(moment, LLM_model)
1352
+ print("===moment_suggested_images===")
1353
+ print(moment["suggested_images"])
1354
+ print("===moment_suggested_images===")
1355
+
1356
  all_content += key_moments
1357
 
1358
  return all_content
 
1376
 
1377
  return all_content
1378
 
1379
+ def generate_key_moments_suggested_images(key_moment, LLM_model=None):
1380
+ # Prepare the text and keywords
1381
+ text = key_moment["text"]
1382
+ keywords = ', '.join(key_moment["keywords"])
1383
+ images = key_moment["images"]
1384
+
1385
+ images_list_prompt = ""
1386
+ for i, image_url in enumerate(images):
1387
+ images_list_prompt += f"\n圖片 {i+1}: {image_url}"
1388
+
1389
+ # Prepare the user prompt with text and keywords
1390
+ sys_content = "你是一個擅長資料分析跟影片教學的老師,user 為學生,請精讀資料文本,自行判斷資料的種類,使用 zh-TW"
1391
+ user_content = f"""
1392
+ # Rule:
1393
+ 1. 保留有圖表或是數據的圖片
1394
+ 2.根據以下的文本和關鍵字,選擇出最合適的圖片。
1395
+ - 文本: {text}
1396
+ - 關鍵字: {keywords}
1397
+ 3. 總是保留最後一張,除非他是一張空白圖片,或是一張沒有任何內容的圖片
1398
+
1399
+ # Restrictions:
1400
+ 1. 不要有相似或是概念重複的圖片
1401
+ 2. 移除整張圖片是黑色、藍色或是白色的圖片
1402
+ 3. 移除沒有任何內容的圖片
1403
+ 4. 不需要理會字幕的差益,只需要看圖片的內容
1404
+
1405
+ 請根據這些信息,圖片列表如下:
1406
+ {images_list_prompt}
1407
+
1408
+ 回傳 JSON LIST 就好,不用回傳任何敘述脈絡,也不要 ```json 包覆
1409
+ EXAMPLE:
1410
+ {{
1411
+ "suggested_images": ["圖片1的 image_url", "圖片2 的 image_url", "圖片3的 image_url"]
1412
+ }}
1413
+ """
1414
+
1415
+ response_format = { "type": "json_object" }
1416
+ response = generate_content_by_LLM(sys_content, user_content, response_format, LLM_model)
1417
+ print("===generate_key_moments_suggested_images===")
1418
+ print(response)
1419
+ print("===generate_key_moments_suggested_images===")
1420
+ suggested_images = json.loads(response)["suggested_images"]
1421
+
1422
+ return suggested_images
1423
+
1424
  def get_key_moments_html(key_moments):
1425
  css = """
1426
  <style>
 
1603
  key_moments_html = css
1604
 
1605
  for i, moment in enumerate(key_moments):
1606
+ images = moment['suggested_images']
1607
  image_elements = ""
1608
 
1609
  for j, image in enumerate(images):
 
1978
 
1979
  return meta_data_json
1980
 
1981
+ def get_ai_content(password, user_data, video_id, df_string, topic, grade, level, specific_feature, content_type, source="gcs"):
1982
  verify_password(password)
1983
  if source == "gcs":
1984
  print("===get_ai_content on gcs===")
 
2024
  ai_content_text = json.dumps(ai_content_list, ensure_ascii=False, indent=2)
2025
  GCS_SERVICE.upload_json_string(bucket_name, blob_name, ai_content_text)
2026
  print("ai_content已上傳到GCS")
2027
+
2028
+ # insert_log_to_bigquery usage
2029
+ data_endpoint = "chat_completions"
2030
+
2031
  else:
2032
  ai_content_json = ai_content_json[-1]
2033
  ai_content = ai_content_json["content"]
2034
  prompt = ai_content_json["prompt"]
2035
+ # insert_log_to_bigquery usage
2036
+ data_endpoint = "gcs"
2037
+
2038
+ # send data to GBQ
2039
+ user_id = user_data
2040
+ route = "get_ai_content"
2041
+ endpoint = data_endpoint
2042
+ event_response = {"event_response": str(ai_content)}
2043
+ event_response_json = json.dumps(event_response)
2044
+ prompt = ai_content_json
2045
+ prompt_json = json.dumps(prompt)
2046
+ feature = content_type
2047
+ insert_log_to_bigquery(user_id, route, endpoint, event_response_json, prompt_json, feature)
2048
 
2049
  return ai_content, ai_content, prompt, prompt
2050
 
 
2063
 
2064
  return ai_content, prompt
2065
 
2066
+ def generate_ai_content_fine_tune_result(password, user_data, exam_result_prompt , df_string_output, exam_result, exam_result_fine_tune_prompt, content_type):
2067
  verify_password(password)
2068
  material = EducationalMaterial(df_string_output, "", "", "", "", "")
2069
  try:
 
2071
  except:
2072
  fine_tuned_ai_content = material.get_fine_tuned_ai_content(BEDROCK_CLIENT, "bedrock", exam_result_prompt, exam_result, exam_result_fine_tune_prompt)
2073
 
2074
+ # send data to GBQ
2075
+ user_id = user_data
2076
+ route = "generate_ai_content_fine_tune_result"
2077
+ endpoint = "chat_completions"
2078
+ event_response = {"event_response": str(fine_tuned_ai_content)}
2079
+ event_response_json = json.dumps(event_response)
2080
+ prompt = {
2081
+ "exam_result_prompt": exam_result_prompt,
2082
+ "exam_result_fine_tune_prompt": exam_result_fine_tune_prompt
2083
+ }
2084
+ prompt_json = json.dumps(prompt)
2085
+ feature = content_type
2086
+ insert_log_to_bigquery(user_id, route, endpoint, event_response_json, prompt_json, feature)
2087
+
2088
  return fine_tuned_ai_content
2089
 
2090
  def return_original_exam_result(exam_result_original):
 
2159
  def chat_with_any_ai(ai_type, password, video_id, user_data, transcript_state, key_moments, user_message, chat_history, content_subject, content_grade, questions_answers_json, socratic_mode=False, thread_id=None, ai_name=None):
2160
  print(f"ai_type: {ai_type}")
2161
  print(f"user_data: {user_data}")
2162
+ print(f"===thread_id:{thread_id}===")
2163
  verify_password(password)
2164
  verify_message_length(user_message, max_length=1500)
2165
 
 
2177
  chatbot_config = get_chatbot_config(ai_name, transcript_state, key_moments, content_subject, content_grade, video_id, socratic_mode)
2178
  chatbot = Chatbot(chatbot_config)
2179
  response_text = chatbot.chat(user_message, chat_history)
2180
+ # if thread_id is none, create random thread_id + timestamp
2181
+ if thread_id is None or thread_id == "":
2182
+ thread_id = "thread_" + str(uuid.uuid4()) + str(int(time.time()))
2183
+
2184
+ print(f"===thread_id:{thread_id}===")
2185
+
2186
+ metadata = {
2187
+ "video_id": video_id,
2188
+ "user_data": user_data,
2189
+ "content_subject": content_subject,
2190
+ "content_grade": content_grade,
2191
+ "socratic_mode": str(socratic_mode),
2192
+ "assistant_id": ai_name,
2193
+ "is_streaming": "false",
2194
+ }
2195
  elif ai_type == "assistant":
2196
  client = OPEN_AI_CLIENT
2197
  assistant_id = OPEN_AI_ASSISTANT_ID_GPT4 #GPT 4 turbo
 
2224
  chat_history = update_chat_history(user_message, response_text, chat_history)
2225
  send_btn_update, send_feedback_btn_update = update_send_and_feedback_buttons(chat_history, CHAT_LIMIT)
2226
 
2227
+ user_id = user_data
2228
+ route = "chat_with_any_ai"
2229
+ endpoint = ai_type #chat_completions or assistant
2230
+ event_response = {
2231
+ "event_response": str(response_text),
2232
+ }
2233
+ event_response_json = json.dumps(event_response)
2234
+ prompt = {
2235
+ "thread_id": thread_id,
2236
+ "metadata": metadata,
2237
+ "user_message": user_message
2238
+ }
2239
+ prompt_json = json.dumps(prompt)
2240
+
2241
+ feature = "vaitor_chatbot"
2242
+ insert_log_to_bigquery(user_id, route, endpoint, event_response_json, prompt_json, feature)
2243
+
2244
  # 返回聊天历史和空字符串清空输入框
2245
  return "", chat_history, send_btn_update, send_feedback_btn_update, thread_id
2246
 
 
2254
  "ai_client": GROQ_CLIENT,
2255
  "ai_model_name": "groq_llama3",
2256
  },
2257
+ # "lili": {
2258
+ # "ai_name": "lili",
2259
+ # "ai_client": BEDROCK_CLIENT,
2260
+ # "ai_model_name": "claude3",
2261
+ # },
2262
  "lili": {
2263
  "ai_name": "lili",
2264
+ "ai_client": GROQ_CLIENT,
2265
+ "ai_model_name": "groq_llama3",
2266
  },
2267
  "maimai": {
2268
  "ai_name": "maimai",
 
2305
 
2306
  return chatbot_config
2307
 
2308
+ def feedback_with_ai(user_data, ai_type, chat_history, thread_id=None):
2309
  # prompt: 請依據以上的對話(chat_history),總結我的「提問力」,並給予我是否有「問對問題」的回饋和建議
2310
  system_content = """
2311
  你是一個擅長引導問答素養的老師,user 為學生的提問跟回答,請精讀對話過程,針對 user 給予回饋就好,根據以下 Rule:
 
2354
  chat_history = update_chat_history(feedback_request_message, response_text, chat_history)
2355
  feedback_btn_update = gr.update(value="已回饋", interactive=False, variant="secondary")
2356
 
2357
+ user_id = user_data
2358
+ route = "feedback_with_ai"
2359
+ endpoint = ai_type #chat_completions or assistant
2360
+ event_response = {
2361
+ "event_response": str(response_text),
2362
+ }
2363
+ event_response_json = json.dumps(event_response)
2364
+ prompt = {
2365
+ "thread_id": thread_id,
2366
+ "metadata": None,
2367
+ "user_message": user_content
2368
+ }
2369
+ prompt_json = json.dumps(prompt)
2370
+ feature = "vaitor_chatbot"
2371
+ insert_log_to_bigquery(user_id, route, endpoint, event_response_json, prompt_json, feature)
2372
+
2373
  return chat_history, feedback_btn_update
2374
 
2375
  def handle_conversation_by_open_ai_chat_completions(client, model_name, user_content, system_content):
 
2417
 
2418
  if run_status == "completed":
2419
  messages = client.beta.threads.messages.list(thread_id=thread.id)
2420
+ response = messages
2421
  response_text = messages.data[0].content[0].text.value
2422
  else:
2423
  response_text = "學習精靈有點累,請稍後再試!"
 
2646
  else:
2647
  thread = client.beta.threads.retrieve(thread_id)
2648
  print(f"old thread_id: {thread_id}")
2649
+ metadata = {
2650
+ "youtube_id": video_id,
2651
+ "user_data": user_data,
2652
+ "content_subject": content_subject,
2653
+ "content_grade": content_grade,
2654
+ "assistant_id": assistant_id,
2655
+ "is_streaming": "true",
2656
+ }
2657
  client.beta.threads.update(
2658
  thread_id=thread_id,
2659
+ metadata=metadata
 
 
 
 
 
 
 
2660
  )
2661
 
2662
  # 向线程添加用户的消息
 
2681
  except Exception as e:
2682
  print(f"Error: {e}")
2683
  raise gr.Error(f"Error: {e}")
2684
+
2685
+ user_id = user_data
2686
+ route = "chat_with_opan_ai_assistant_streaming"
2687
+ endpoint = "assistant_streaming"
2688
+ event_response = {
2689
+ "event_response": partial_messages
2690
+ }
2691
+ event_response_json = json.dumps(event_response)
2692
+ prompt = {
2693
+ "thread_id": thread_id,
2694
+ "metadata": metadata,
2695
+ "user_message": user_message
2696
+ }
2697
+ prompt_json = json.dumps(prompt)
2698
+ feature = "vaitor_chatbot"
2699
+ insert_log_to_bigquery(user_id, route, endpoint, event_response_json, prompt_json, feature)
2700
 
2701
  def create_thread_id():
2702
  thread = OPEN_AI_CLIENT.beta.threads.create()
 
2741
  all_chatbot_select_btn_visible = gr.update(visible=False)
2742
  return chatbot_select_accordion_visible, all_chatbot_select_btn_visible
2743
 
2744
+ def insert_log_to_bigquery(user_id, route, endpoint, event_response_json, prompt_json, feature):
2745
+ table_id = "junyiacademy.streaming_log.log_video_ai_usage"
2746
+ rows_to_insert = [
2747
+ {
2748
+ "user_id": user_id,
2749
+ "route": route,
2750
+ "endpoint": endpoint,
2751
+ "event_response": event_response_json,
2752
+ "event_timestamp": datetime.now(timezone.utc).isoformat(),
2753
+ "prompt": prompt_json,
2754
+ "feature": feature
2755
+ }
2756
+ ]
2757
+
2758
+ errors = GBQ_CLIENT.insert_rows_json(table_id, rows_to_insert)
2759
+ if errors:
2760
+ print(f"Encountered errors while inserting rows: {errors}")
2761
+ else:
2762
+ print("Rows have been successfully inserted.")
2763
+
2764
 
2765
  # --- Init params ---
2766
  def init_params(text, request: gr.Request):
 
3056
  worksheet_algorithm = gr.Dropdown(label="選擇教學策略或理論", choices=["Bloom認知階層理論", "Polya數學解題法", "CRA教學法"], value="Bloom認知階層理論", visible=False)
3057
  worksheet_content_btn = gr.Button("生成學習單 📄", variant="primary", visible=True)
3058
  with gr.Accordion("微調", open=False):
3059
+ worksheet_result_fine_tune_prompt = gr.Textbox(label="根據結果,輸入你想更改的想法")
3060
+ worksheet_result_fine_tune_btn = gr.Button("微調結果", variant="primary")
3061
+ worksheet_result_retrun_original = gr.Button("返回原始結果")
3062
  with gr.Accordion("prompt", open=False) as worksheet_accordion:
3063
  worksheet_prompt = gr.Textbox(label="worksheet_prompt", show_copy_button=True, lines=40)
3064
  with gr.Column(scale=2):
3065
  # 生成對應不同模式的結果
3066
+ worksheet_result_prompt = gr.Textbox(visible=False)
3067
+ worksheet_result_original = gr.Textbox(visible=False)
3068
+ worksheet_result = gr.Markdown(label="初次生成結果", latex_delimiters = [{"left": "$", "right": "$", "display": False}])
3069
+ worksheet_download_button = gr.Button("轉成 word,完成後請點擊右下角 download 按鈕", variant="primary")
3070
+ worksheet_result_word_link = gr.File(label="Download Word")
 
3071
  with gr.Tab("教案"):
3072
  with gr.Row():
3073
  with gr.Column(scale=1):
 
3076
  lesson_plan_time = gr.Slider(label="選擇課程時間(分鐘)", minimum=10, maximum=120, step=5, value=40)
3077
  lesson_plan_btn = gr.Button("生成教案 📕", variant="primary", visible=True)
3078
  with gr.Accordion("微調", open=False):
3079
+ lesson_plan_result_fine_tune_prompt = gr.Textbox(label="根據結果,輸入你想更改的想法")
3080
+ lesson_plan_result_fine_tune_btn = gr.Button("微調結果", variant="primary")
3081
+ lesson_plan_result_retrun_original = gr.Button("返回原始結果")
3082
  with gr.Accordion("prompt", open=False) as lesson_plan_accordion:
3083
  lesson_plan_prompt = gr.Textbox(label="worksheet_prompt", show_copy_button=True, lines=40)
3084
  with gr.Column(scale=2):
3085
  # 生成對應不同模式的結果
3086
+ lesson_plan_result_prompt = gr.Textbox(visible=False)
3087
+ lesson_plan_result_original = gr.Textbox(visible=False)
3088
+ lesson_plan_result = gr.Markdown(label="初次生成結果", latex_delimiters = [{"left": "$", "right": "$", "display": False}])
3089
 
3090
+ lesson_plan_download_button = gr.Button("轉成 word,完成後請點擊右下角 download 按鈕", variant="primary")
3091
+ lesson_plan_result_word_link = gr.File(label="Download Word")
3092
  with gr.Tab("出場券"):
3093
  with gr.Row():
3094
  with gr.Column(scale=1):
 
3097
  exit_ticket_time = gr.Slider(label="選擇出場券時間(分鐘)", minimum=5, maximum=10, step=1, value=8)
3098
  exit_ticket_btn = gr.Button("生成出場券 🎟️", variant="primary", visible=True)
3099
  with gr.Accordion("微調", open=False):
3100
+ exit_ticket_result_fine_tune_prompt = gr.Textbox(label="根據結果,輸入你想更改的想法")
3101
+ exit_ticket_result_fine_tune_btn = gr.Button("微調結果", variant="primary")
3102
+ exit_ticket_result_retrun_original = gr.Button("返回原始結果")
3103
  with gr.Accordion("prompt", open=False) as exit_ticket_accordion:
3104
  exit_ticket_prompt = gr.Textbox(label="worksheet_prompt", show_copy_button=True, lines=40)
3105
  with gr.Column(scale=2):
3106
  # 生成對應不同模式的結果
3107
+ exit_ticket_result_prompt = gr.Textbox(visible=False)
3108
+ exit_ticket_result_original = gr.Textbox(visible=False)
3109
+ exit_ticket_result = gr.Markdown(label="初次生成結果", latex_delimiters = [{"left": "$", "right": "$", "display": False}])
3110
 
3111
+ exit_ticket_download_button = gr.Button("轉成 word,完成後請點擊右下角 download 按鈕", variant="primary")
3112
+ exit_ticket_result_word_link = gr.File(label="Download Word")
3113
 
3114
 
3115
  # with gr.Tab("素養導向閱讀題組"):
 
3129
  with gr.Accordion("See Details", open=False) as see_details:
3130
  with gr.Row():
3131
  is_env_prod = gr.Checkbox(value=False, label="is_env_prod")
3132
+ LLM_model = gr.Dropdown(label="LLM Model", choices=["open-ai-gpt-4o", "anthropic-claude-3-sonnet"], value="open-ai-gpt-4o", visible=True, interactive=True)
3133
  with gr.Tab("逐字稿本文"):
3134
  with gr.Row() as transcript_admmin:
3135
  transcript_kind = gr.Textbox(value="transcript", show_label=False)
 
3320
  )
3321
  ai_send_feedback_btn.click(
3322
  feedback_with_ai,
3323
+ inputs=[user_data, ai_chatbot_ai_type, ai_chatbot, ai_chatbot_thread_id],
3324
  outputs=[ai_chatbot, ai_send_feedback_btn],
3325
  scroll_to_output=True
3326
  )
 
3657
  {
3658
  "button": worksheet_content_btn,
3659
  "action": get_ai_content,
3660
+ "inputs": [password, user_data, video_id, df_string_output, content_subject, content_grade, content_level, worksheet_algorithm, worksheet_content_type_name],
3661
+ "outputs": [worksheet_result_original, worksheet_result, worksheet_prompt, worksheet_result_prompt]
3662
  },
3663
  {
3664
+ "button": worksheet_result_fine_tune_btn,
3665
+ "action": generate_ai_content_fine_tune_result,
3666
+ "inputs": [password, user_data, worksheet_result_prompt, df_string_output, worksheet_result, worksheet_result_fine_tune_prompt, worksheet_content_type_name],
3667
+ "outputs": [worksheet_result]
3668
  },
3669
  {
3670
+ "button": worksheet_download_button,
3671
  "action": download_exam_result,
3672
+ "inputs": [worksheet_result],
3673
+ "outputs": [worksheet_result_word_link]
3674
  },
3675
  {
3676
+ "button": worksheet_result_retrun_original,
3677
  "action": return_original_exam_result,
3678
+ "inputs": [worksheet_result_original],
3679
+ "outputs": [worksheet_result]
3680
  },
3681
  # 教案相關按鈕
3682
  {
3683
  "button": lesson_plan_btn,
3684
  "action": get_ai_content,
3685
+ "inputs": [password, user_data, video_id, df_string_output, content_subject, content_grade, content_level, lesson_plan_time, lesson_plan_content_type_name],
3686
+ "outputs": [lesson_plan_result_original, lesson_plan_result, lesson_plan_prompt, lesson_plan_result_prompt]
3687
  },
3688
  {
3689
+ "button": lesson_plan_result_fine_tune_btn,
3690
+ "action": generate_ai_content_fine_tune_result,
3691
+ "inputs": [password, user_data, lesson_plan_result_prompt, df_string_output, lesson_plan_result, lesson_plan_result_fine_tune_prompt, lesson_plan_content_type_name],
3692
+ "outputs": [lesson_plan_result]
3693
  },
3694
  {
3695
+ "button": lesson_plan_download_button,
3696
  "action": download_exam_result,
3697
+ "inputs": [lesson_plan_result],
3698
+ "outputs": [lesson_plan_result_word_link]
3699
  },
3700
  {
3701
+ "button": lesson_plan_result_retrun_original,
3702
  "action": return_original_exam_result,
3703
+ "inputs": [lesson_plan_result_original],
3704
+ "outputs": [lesson_plan_result]
3705
  },
3706
  # 出場券相關按鈕
3707
  {
3708
  "button": exit_ticket_btn,
3709
  "action": get_ai_content,
3710
+ "inputs": [password, user_data, video_id, df_string_output, content_subject, content_grade, content_level, exit_ticket_time, exit_ticket_content_type_name],
3711
+ "outputs": [exit_ticket_result_original, exit_ticket_result, exit_ticket_prompt, exit_ticket_result_prompt]
3712
  },
3713
  {
3714
+ "button": exit_ticket_result_fine_tune_btn,
3715
+ "action": generate_ai_content_fine_tune_result,
3716
+ "inputs": [password, user_data, exit_ticket_result_prompt, df_string_output, exit_ticket_result, exit_ticket_result_fine_tune_prompt, exit_ticket_content_type_name],
3717
+ "outputs": [exit_ticket_result]
3718
  },
3719
  {
3720
+ "button": exit_ticket_download_button,
3721
  "action": download_exam_result,
3722
+ "inputs": [exit_ticket_result],
3723
+ "outputs": [exit_ticket_result_word_link]
3724
  },
3725
  {
3726
+ "button": exit_ticket_result_retrun_original,
3727
  "action": return_original_exam_result,
3728
+ "inputs": [exit_ticket_result_original],
3729
+ "outputs": [exit_ticket_result]
3730
  }
3731
  ]
3732
  setup_education_buttons(education_buttons_config)
 
3753
  outputs = init_outputs
3754
  )
3755
 
3756
+ demo.launch(allowed_paths=["videos"], server_name="0.0.0.0", server_port=7860)
chatbot.py CHANGED
@@ -87,7 +87,7 @@ class Chatbot:
87
  "Content-Type": "application/json",
88
  "x-api-key": self.jutor_chat_key,
89
  }
90
- model = "gpt-4-turbo"
91
  print("======model======")
92
  print(model)
93
  # model = "gpt-3.5-turbo-0125"
 
87
  "Content-Type": "application/json",
88
  "x-api-key": self.jutor_chat_key,
89
  }
90
+ model = "gpt-4o"
91
  print("======model======")
92
  print(model)
93
  # model = "gpt-3.5-turbo-0125"
educational_material.py CHANGED
@@ -99,7 +99,7 @@ class EducationalMaterial:
99
  OPEN_AI_CLIENT = AI_Client
100
  messages = [{"role": "system", "content": system_content}, {"role": "user", "content": user_content}]
101
  request_payload = {
102
- "model": "gpt-4-turbo",
103
  "messages": messages,
104
  "max_tokens": 4000,
105
  "temperature": 0.9,
 
99
  OPEN_AI_CLIENT = AI_Client
100
  messages = [{"role": "system", "content": system_content}, {"role": "user", "content": user_content}]
101
  request_payload = {
102
+ "model": "gpt-4o",
103
  "messages": messages,
104
  "max_tokens": 4000,
105
  "temperature": 0.9,
requirements.txt CHANGED
@@ -2,7 +2,6 @@ gradio==4.8.0
2
  pandas
3
  openai>=1.16.2
4
  requests
5
- beautifulsoup4
6
  python-docx
7
  youtube-transcript-api
8
  moviepy
@@ -12,6 +11,7 @@ google-api-python-client
12
  google-auth-httplib2
13
  google-auth-oauthlib
14
  google-cloud-storage
 
15
  groq
16
  yt_dlp
17
  uuid
 
2
  pandas
3
  openai>=1.16.2
4
  requests
 
5
  python-docx
6
  youtube-transcript-api
7
  moviepy
 
11
  google-auth-httplib2
12
  google-auth-oauthlib
13
  google-cloud-storage
14
+ google-cloud-bigquery
15
  groq
16
  yt_dlp
17
  uuid