Spaces:
Running
Running
update
Browse files- app.py +303 -114
- chatbot.py +1 -1
- educational_material.py +1 -1
- 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 =
|
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 |
-
|
729 |
-
|
730 |
-
|
731 |
-
|
732 |
-
|
733 |
-
|
734 |
-
|
735 |
-
|
736 |
-
|
737 |
-
|
738 |
-
|
739 |
-
|
740 |
-
|
741 |
-
|
742 |
-
|
743 |
-
|
744 |
-
|
745 |
-
|
746 |
-
|
747 |
-
|
748 |
-
|
|
|
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 |
-
|
755 |
-
|
756 |
-
else:
|
757 |
-
|
758 |
-
|
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['
|
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
|
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":
|
2128 |
-
"ai_model_name": "
|
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 |
-
|
2870 |
-
|
2871 |
-
|
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 |
-
|
2877 |
-
|
2878 |
-
|
2879 |
-
|
2880 |
-
|
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 |
-
|
2891 |
-
|
2892 |
-
|
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 |
-
|
2898 |
-
|
2899 |
-
|
2900 |
|
2901 |
-
|
2902 |
-
|
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 |
-
|
2912 |
-
|
2913 |
-
|
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 |
-
|
2919 |
-
|
2920 |
-
|
2921 |
|
2922 |
-
|
2923 |
-
|
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-
|
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": [
|
3473 |
},
|
3474 |
{
|
3475 |
-
"button":
|
3476 |
-
"action":
|
3477 |
-
"inputs": [password,
|
3478 |
-
"outputs": [
|
3479 |
},
|
3480 |
{
|
3481 |
-
"button":
|
3482 |
"action": download_exam_result,
|
3483 |
-
"inputs": [
|
3484 |
-
"outputs": [
|
3485 |
},
|
3486 |
{
|
3487 |
-
"button":
|
3488 |
"action": return_original_exam_result,
|
3489 |
-
"inputs": [
|
3490 |
-
"outputs": [
|
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": [
|
3498 |
},
|
3499 |
{
|
3500 |
-
"button":
|
3501 |
-
"action":
|
3502 |
-
"inputs": [password,
|
3503 |
-
"outputs": [
|
3504 |
},
|
3505 |
{
|
3506 |
-
"button":
|
3507 |
"action": download_exam_result,
|
3508 |
-
"inputs": [
|
3509 |
-
"outputs": [
|
3510 |
},
|
3511 |
{
|
3512 |
-
"button":
|
3513 |
"action": return_original_exam_result,
|
3514 |
-
"inputs": [
|
3515 |
-
"outputs": [
|
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": [
|
3523 |
},
|
3524 |
{
|
3525 |
-
"button":
|
3526 |
-
"action":
|
3527 |
-
"inputs": [password,
|
3528 |
-
"outputs": [
|
3529 |
},
|
3530 |
{
|
3531 |
-
"button":
|
3532 |
"action": download_exam_result,
|
3533 |
-
"inputs": [
|
3534 |
-
"outputs": [
|
3535 |
},
|
3536 |
{
|
3537 |
-
"button":
|
3538 |
"action": return_original_exam_result,
|
3539 |
-
"inputs": [
|
3540 |
-
"outputs": [
|
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-
|
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-
|
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
|