diff --git "a/app.py" "b/app.py" --- "a/app.py" +++ "b/app.py" @@ -1,4 +1,39 @@ +import urllib.parse + import gradio as gr +from starlette.middleware.base import BaseHTTPMiddleware +from starlette.responses import Response +from starlette.types import ASGIApp +from fastapi import status, FastAPI + +class BlockFileRedirectMiddleware(BaseHTTPMiddleware): + def __init__(self, app: ASGIApp): + super().__init__(app) + + async def dispatch(self, request, call_next): + # URL decode the path first + path = urllib.parse.unquote(request.url.path) + + # Check all possible file endpoint patterns + if any( + pattern in path + for pattern in [ + "/gradio_api/file=", + "/gradio/api/file=", + "/api/file=", + "/file=", + ] + ): + # Extract everything after file= + file_part = path.split("file=", 1)[1] + # Block if it's a URL (starts with http:// or https://) + if file_part.lower().startswith(("http://", "https://")): + return Response( + status_code=status.HTTP_403_FORBIDDEN, + content="Direct URL redirects are not allowed", + ) + return await call_next(request) + import pandas as pd import requests from docx import Document @@ -3224,918 +3259,932 @@ streaming_ai_chatbot = gr.Chatbot( show_copy_button=True, ) -with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, secondary_hue=gr.themes.colors.amber, text_size = gr.themes.sizes.text_lg), head=HEAD, js=JS, css=CSS) as demo: - with gr.Row() as admin: - password = gr.Textbox(label="Password", type="password", elem_id="password_input", visible=True) - youtube_link = gr.Textbox(label="Enter YouTube Link", elem_id="youtube_link_input", visible=True) - video_id = gr.Textbox(label="video_id", visible=True) - # file_upload = gr.File(label="Upload your CSV or Word file", visible=False) - # web_link = gr.Textbox(label="Enter Web Page Link", visible=False) - user_data = gr.Textbox(label="User Data", elem_id="user_data_input", visible=True) - # block_ready_flag: 讓主站的 Vaitor component 知道 Blocks.load 已經執行完成(當 block_ready_flag = "READY" 時) - block_ready_flag = gr.Textbox(label="Block Ready Flag", elem_id="block_ready_flag", visible=False, value="LOADING") - youtube_link_btn = gr.Button("Submit_YouTube_Link", elem_id="youtube_link_btn", visible=True) - with gr.Row() as data_state: - content_subject_state = gr.State() # 使用 gr.State 存储 content_subject - content_grade_state = gr.State() # 使用 gr.State 存储 content_grade - trascript_state = gr.State() # 使用 gr.State 存储 trascript - key_moments_state = gr.State() # 使用 gr.State 存储 key_moments - streaming_chat_thread_id_state = gr.State() # 使用 gr.State 存储 streaming_chat_thread_id - with gr.Tab("AI小精靈"): - with gr.Row(): - all_chatbot_select_btn = gr.Button("選擇 AI 小精靈 👈", elem_id="all_chatbot_select_btn", visible=False, variant="secondary", size="sm") - with gr.Row() as ai_chatbot_params: - ai_name = gr.Dropdown( - label="選擇 AI 助理", - choices=[ - ("飛特精靈","chatbot_open_ai"), - ("飛特音速","chatbot_open_ai_streaming"), - ("梨梨","lili"), - ("麥麥","maimai"), - ("狐狸貓","foxcat") - ], - value="foxcat", - visible=True - ) - ai_chatbot_ai_type = gr.Textbox(value="chat_completions", visible=True) - ai_chatbot_thread_id = gr.Textbox(label="thread_id", visible=True) - ai_chatbot_socratic_mode_btn = gr.Checkbox(label="蘇格拉底家教助理模式", value=False, visible=True) - latex_delimiters = [{"left": "$", "right": "$", "display": False}] - with gr.Accordion("選擇 AI 小精靈", elem_id="chatbot_select_accordion") as chatbot_select_accordion: +def create_app(): + + app = FastAPI() + app.add_middleware(BlockFileRedirectMiddleware) + + with gr.Blocks(theme=gr.themes.Base(primary_hue=gr.themes.colors.orange, secondary_hue=gr.themes.colors.amber, text_size = gr.themes.sizes.text_lg), head=HEAD, js=JS, css=CSS) as demo: + with gr.Row() as admin: + password = gr.Textbox(label="Password", type="password", elem_id="password_input", visible=True) + youtube_link = gr.Textbox(label="Enter YouTube Link", elem_id="youtube_link_input", visible=True) + video_id = gr.Textbox(label="video_id", visible=True) + # file_upload = gr.File(label="Upload your CSV or Word file", visible=False) + # web_link = gr.Textbox(label="Enter Web Page Link", visible=False) + user_data = gr.Textbox(label="User Data", elem_id="user_data_input", visible=True) + # block_ready_flag: 讓主站的 Vaitor component 知道 Blocks.load 已經執行完成(當 block_ready_flag = "READY" 時) + block_ready_flag = gr.Textbox(label="Block Ready Flag", elem_id="block_ready_flag", visible=False, value="LOADING") + youtube_link_btn = gr.Button("Submit_YouTube_Link", elem_id="youtube_link_btn", visible=True) + with gr.Row() as data_state: + content_subject_state = gr.State() # 使用 gr.State 存储 content_subject + content_grade_state = gr.State() # 使用 gr.State 存储 content_grade + trascript_state = gr.State() # 使用 gr.State 存储 trascript + key_moments_state = gr.State() # 使用 gr.State 存储 key_moments + streaming_chat_thread_id_state = gr.State() # 使用 gr.State 存储 streaming_chat_thread_id + with gr.Tab("AI小精靈"): with gr.Row(): - # 飛特音速 - with gr.Column(scale=1, variant="panel", visible=True): - 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" - streaming_chatbot_description = """Hi,我是【飛特音速】, \n - 說話比較快,但有什麼問題都可以問我喔! \n - 🚀 我沒有預設問題、也沒有語音輸入,適合快問快答,一起練習問出好問題吧 \n - 🔠 擅長用文字表達的你,可以用鍵盤輸入你的問題,我會盡力回答你的問題喔\n - 💤 我還在成長,體力有限,每一次學習只能回答十個問題,請讓我休息一下再問問題喔~ - """ - chatbot_open_ai_streaming_name = gr.State("chatbot_open_ai_streaming") - gr.Image(value=streaming_chatbot_avatar_url, height=100, width=100, show_label=False, show_download_button=False) - chatbot_open_ai_streaming_select_btn = gr.Button("👆選擇【飛特音速】", elem_id="streaming_chatbot_btn", visible=True, variant="primary") - with gr.Accordion("🚀 飛特音速 敘述", open=False): - gr.Markdown(value=streaming_chatbot_description, visible=True) - user_avatar = "https://em-content.zobj.net/source/google/263/flushed-face_1f633.png" - # 飛特精靈 - with gr.Column(scale=1, variant="panel", visible=True): - vaitor_chatbot_avatar_url = "https://junyitopicimg.s3.amazonaws.com/s4byy--icon.jpe" - vaitor_chatbot_avatar_images = gr.State([user_avatar, vaitor_chatbot_avatar_url]) - vaitor_chatbot_description = """Hi,我是你的AI學伴【飛特精靈】,\n - 我可以陪你一起學習本次的內容,有什麼問題都可以問我喔!\n - 🤔 如果你不知道怎麼發問,可以點擊左下方的問題一、問題二、問題三,我會幫你生成問題!\n - 🗣️ 也可以點擊右下方用語音輸入,我會幫你轉換成文字,厲害吧!\n - 🔠 或是直接鍵盤輸入你的問題,我會盡力回答你的問題喔!\n - 💤 但我還在成長,體力有限,每一次學習只能回答十個問題,請讓我休息一下再問問題喔!\n - 🦄 如果達到上限,或是遇到精靈很累,請問問其他朋友,像是飛特音速說話的速度比較快,你是否跟得上呢?你也可以和其他精靈互動看看喔!\n - """ - chatbot_open_ai_name = gr.State("chatbot_open_ai") - gr.Image(value=vaitor_chatbot_avatar_url, height=100, width=100, show_label=False, show_download_button=False) - vaitor_chatbot_select_btn = gr.Button("👆選擇【飛特精靈】", elem_id="chatbot_btn", visible=True, variant="primary") - with gr.Accordion("🦄 飛特精靈 敘述", open=False): - vaitor_chatbot_description_value = gr.Markdown(value=vaitor_chatbot_description, visible=True) - # 狐狸貓 - with gr.Column(scale=1, variant="panel"): - foxcat_chatbot_avatar_url = "https://storage.googleapis.com/wpassets.junyiacademy.org/1/2020/06/%E7%A7%91%E5%AD%B8%E5%BE%BD%E7%AB%A0-2-150x150.png" - foxcat_avatar_images = gr.State([user_avatar, foxcat_chatbot_avatar_url]) - foxcat_chatbot_description = """Hi,我是【狐狸貓】,可以陪你一起學習本次的內容,有什麼問題都可以問我喔!\n - 🤔 三年級學生|10 歲|男\n - 🗣️ 口頭禪:「感覺好好玩喔!」「咦?是這樣嗎?」\n - 🔠 興趣:看知識型書籍、熱血的動漫卡通、料理、爬山、騎腳踏車。因為太喜歡吃魚了,正努力和爸爸學習���魚、料理魚及各種有關魚的知識,最討厭的食物是青椒。\n - 💤 個性:喜歡學習新知,擁有最旺盛的好奇心,家裡堆滿百科全書,例如:國家地理頻道出版的「終極魚百科」,雖都沒有看完,常常被梨梨唸是三分鐘熱度,但是也一點一點學習到不同領域的知識。雖然有時會忘東忘西,但認真起來也是很可靠,答應的事絕對使命必達。遇到挑戰時,勇於跳出舒適圈,追求自我改變,視困難為成長的機會。 - """ - foxcat_chatbot_name = gr.State("foxcat") - gr.Image(value=foxcat_chatbot_avatar_url, height=100, width=100, show_label=False, show_download_button=False) - foxcat_chatbot_select_btn = gr.Button("👆選擇【狐狸貓】", visible=True, variant="primary", elem_classes="chatbot_select_btn") - with gr.Accordion("💜 狐狸貓 敘述", open=False): - foxcat_chatbot_description_value = gr.Markdown(value=foxcat_chatbot_description, visible=True) - # 梨梨 - with gr.Column(scale=1, variant="panel"): - lili_chatbot_avatar_url = "https://junyitopicimg.s3.amazonaws.com/live/v1283-new-topic-44-icon.png" - lili_avatar_images = gr.State([user_avatar, lili_chatbot_avatar_url]) - lili_chatbot_description = """你好,我是溫柔的【梨梨】,很高興可以在這裡陪伴你學習。如果你有任何疑問,請隨時向我提出哦! \n - 🤔 三年級學生|10 歲|女\n - 🗣️ 口頭禪:「真的假的?!」「讓我想一想喔」「你看吧!大問題拆解成小問題,就變得簡單啦!」「混混噩噩的生活不值得過」\n - 🔠 興趣:烘焙餅乾(父母開糕餅店)、畫畫、聽流行音樂、收納。\n - 💤 個性: - - 內向害羞,比起出去玩更喜歡待在家(除非是跟狐狸貓出去玩) - - 數理邏輯很好;其實覺得麥麥連珠炮的提問有點煩,但還是會耐心地回答 - - 有驚人的眼力,總能觀察到其他人沒有察覺的細節 - - 喜歡整整齊齊的環境,所以一到麥麥家就受不了 - """ - lili_chatbot_name = gr.State("lili") - gr.Image(value=lili_chatbot_avatar_url, height=100, width=100, show_label=False, show_download_button=False) - lili_chatbot_select_btn = gr.Button("👆選擇【梨梨】", visible=True, variant="primary", elem_classes="chatbot_select_btn") - with gr.Accordion("🧡 梨梨 敘述", open=False): - lili_chatbot_description_value = gr.Markdown(value=lili_chatbot_description, visible=True) - # 麥麥 - with gr.Column(scale=1, variant="panel"): - maimai_chatbot_avatar_url = "https://storage.googleapis.com/wpassets.junyiacademy.org/1/2020/07/%E6%80%9D%E8%80%83%E5%8A%9B%E8%B6%85%E4%BA%BA%E5%BE%BD%E7%AB%A0_%E5%B7%A5%E4%BD%9C%E5%8D%80%E5%9F%9F-1-%E8%A4%87%E6%9C%AC-150x150.png" - maimai_avatar_images = gr.State([user_avatar, maimai_chatbot_avatar_url]) - maimai_chatbot_description = """Hi,我是迷人的【麥麥】,我在這裡等著和你一起探索新知,任何疑問都可以向我提出!\n - 🤔 三年級學生|10 歲|男\n - 🗣️ 口頭禪:「Oh My God!」「好奇怪喔!」「喔!原來是這樣啊!」\n - 🔠 興趣:最愛去野外玩耍(心情好時會順便捕魚送給狐狸貓),喜歡講冷笑話、惡作劇。因為太喜歡玩具,而開始自己做玩具,家裡就好像他的遊樂場。\n - 💤 個性:喜歡問問題,就算被梨梨ㄘㄟ,也還是照問|憨厚,外向好動,樂天開朗,不會被難題打敗|喜歡收集各式各樣的東西;房間只有在整理的那一天最乾淨 - """ - maimai_chatbot_name = gr.State("maimai") - gr.Image(value=maimai_chatbot_avatar_url, height=100, width=100, show_label=False, show_download_button=False) - maimai_chatbot_select_btn = gr.Button("👆選擇【麥麥】", visible=True, variant="primary", elem_classes="chatbot_select_btn") - with gr.Accordion("💙 麥麥 敘述", open=False): - maimai_chatbot_description_value = gr.Markdown(value=maimai_chatbot_description, visible=True) - # 尚未開放 - with gr.Column(scale=1, variant="panel"): - gr.Markdown(value="### 尚未開放", visible=True) - - with gr.Row("飛特音速") as chatbot_open_ai_streaming: - with gr.Column(): - streaming_chat_greeting = """ - Hi,我是【飛特音速】,說話比較快,但有什麼問題都可以問我喔! \n - 🚀 我沒有預設問題、也沒有語音輸入,適合快問快答的你 \n - 🔠 鍵盤輸入你的問題,我會盡力回答你的問題喔!\n - 💤 我還在成長,體力有限,每一次學習只能回答十個問題,請讓我休息一下再問問題喔! - """ - additional_inputs = [password, video_id, user_data, streaming_chat_thread_id_state, trascript_state, key_moments_state, content_subject_state, content_grade_state, ai_chatbot_socratic_mode_btn] - streaming_chat = gr.ChatInterface( - fn=chat_with_opan_ai_assistant_streaming, - chatbot=streaming_ai_chatbot, - additional_inputs=additional_inputs, - submit_btn="送出", - stop_btn=None, - description=streaming_chat_greeting + all_chatbot_select_btn = gr.Button("選擇 AI 小精靈 👈", elem_id="all_chatbot_select_btn", visible=False, variant="secondary", size="sm") + with gr.Row() as ai_chatbot_params: + ai_name = gr.Dropdown( + label="選擇 AI 助理", + choices=[ + ("飛特精靈","chatbot_open_ai"), + ("飛特音速","chatbot_open_ai_streaming"), + ("梨梨","lili"), + ("麥麥","maimai"), + ("狐狸貓","foxcat") + ], + value="foxcat", + visible=True ) - with gr.Row("一般精靈") as chatbot_ai: - with gr.Column(): - ai_chatbot_greeting = [[ - "請問你是誰?", - """Hi,我是飛特精靈的朋友們【梨梨、麥麥、狐狸貓】,也可以陪你一起學習本次的內容,有什麼問題都可以問我喔! - 🤔 如果你不知道怎麼發問,可以點擊左下方的問題一、問題二、問題三,我會幫你生成問題! - 🗣️ 也可以點擊右下方用語音輸入,我會幫你轉換成文字,厲害吧! - 🔠 或是直接鍵盤輸入你的問題,我會盡力回答你的問題喔! - 💤 精靈們體力都有限,每一次學習只能回答十個問題,請讓我休息一下再問問題喔! - """, - ]] - with gr.Row(): - ai_chatbot = gr.Chatbot(label="ai_chatbot", show_share_button=False, show_label=False, latex_delimiters=latex_delimiters, value=ai_chatbot_greeting) + ai_chatbot_ai_type = gr.Textbox(value="chat_completions", visible=True) + ai_chatbot_thread_id = gr.Textbox(label="thread_id", visible=True) + ai_chatbot_socratic_mode_btn = gr.Checkbox(label="蘇格拉底家教助理模式", value=False, visible=True) + latex_delimiters = [{"left": "$", "right": "$", "display": False}] + with gr.Accordion("選擇 AI 小精靈", elem_id="chatbot_select_accordion") as chatbot_select_accordion: with gr.Row(): - with gr.Accordion("你也有類似的問題想問嗎? 請按下 ◀︎", open=False) as ask_questions_accordion_2: - ai_chatbot_question_1 = gr.Button("問題一") - ai_chatbot_question_2 = gr.Button("問題一") - ai_chatbot_question_3 = gr.Button("問題一") - create_questions_btn = gr.Button("生成問題", variant="primary") - ai_chatbot_audio_input = gr.Audio(sources=["microphone"], type="filepath", max_length=60, label="語音輸入") - with gr.Row(): - ai_msg = gr.Textbox(label="訊息輸入",scale=3) - ai_send_button = gr.Button("送出", variant="primary",scale=1) - ai_send_feedback_btn = gr.Button("提問力回饋", variant="primary", scale=1, visible=False) - with gr.Tab("文章模式"): - with gr.Row(): - reading_passage = gr.Markdown(show_label=False, latex_delimiters = [{"left": "$", "right": "$", "display": False}]) - reading_passage_speak_button = gr.Button("Speak", visible=False) - reading_passage_audio_output = gr.Audio(label="Audio Output", visible=False) - with gr.Tab("重點摘要"): - with gr.Row(): - df_summarise = gr.Markdown(show_label=False, latex_delimiters = [{"left": "$", "right": "$", "display": False}]) - with gr.Tab("心智圖",elem_id="mind_map_tab"): - with gr.Row(): - mind_map_html = gr.HTML() - with gr.Tab("關鍵時刻"): - with gr.Row(): - key_moments_html = gr.HTML(value="") - with gr.Tab("教���備課"): - with gr.Row(): - content_subject = gr.Dropdown(label="選擇主題", choices=["數學", "自然", "國文", "英文", "社會","物理", "化學", "生物", "地理", "歷史", "公民"], value="", visible=False) - content_grade = gr.Dropdown(label="選擇年級", choices=["一年級", "二年級", "三年級", "四年級", "五年級", "六年級", "七年級", "八年級", "九年級", "十年級", "十一年級", "十二年級"], value="", visible=False) - content_level = gr.Dropdown(label="差異化教學", choices=["基礎", "中級", "進階"], value="基礎") - with gr.Row(): - with gr.Tab("學習單"): - with gr.Row(): - with gr.Column(scale=1): - with gr.Row(): - worksheet_content_type_name = gr.Textbox(value="worksheet", visible=False) - worksheet_algorithm = gr.Dropdown(label="選擇教學策略或理論", choices=["Bloom認知階層理論", "Polya數學解題法", "CRA教學法"], value="Bloom認知階層理論", visible=False) - worksheet_content_btn = gr.Button("生成學習單 📄", variant="primary", visible=True) - with gr.Accordion("微調", open=False): - worksheet_result_fine_tune_prompt = gr.Textbox(label="根據結果,輸入你想更改的想法") - worksheet_result_fine_tune_btn = gr.Button("微調結果", variant="primary") - worksheet_result_retrun_original = gr.Button("返回原始結果") - with gr.Accordion("prompt", open=False) as worksheet_accordion: - worksheet_prompt = gr.Textbox(label="worksheet_prompt", show_copy_button=True, lines=40) - with gr.Column(scale=2): - # 生成對應不同模式的結果 - worksheet_result_prompt = gr.Textbox(visible=False) - worksheet_result_original = gr.Textbox(visible=False) - worksheet_result = gr.Markdown(label="初次生成結果", latex_delimiters = [{"left": "$", "right": "$", "display": False}]) - worksheet_download_button = gr.Button("轉成 word,完成後請點擊右下角 download 按鈕", variant="primary") - worksheet_result_word_link = gr.File(label="Download Word") - with gr.Tab("教案"): - with gr.Row(): - with gr.Column(scale=1): - with gr.Row(): - lesson_plan_content_type_name = gr.Textbox(value="lesson_plan", visible=False) - lesson_plan_time = gr.Slider(label="選擇課程時間(分鐘)", minimum=10, maximum=120, step=5, value=40) - lesson_plan_btn = gr.Button("生成教案 📕", variant="primary", visible=True) - with gr.Accordion("微調", open=False): - lesson_plan_result_fine_tune_prompt = gr.Textbox(label="根據結果,輸入你想更改的想法") - lesson_plan_result_fine_tune_btn = gr.Button("微調結果", variant="primary") - lesson_plan_result_retrun_original = gr.Button("返回原始結果") - with gr.Accordion("prompt", open=False) as lesson_plan_accordion: - lesson_plan_prompt = gr.Textbox(label="worksheet_prompt", show_copy_button=True, lines=40) - with gr.Column(scale=2): - # 生成對應不同模式的結果 - lesson_plan_result_prompt = gr.Textbox(visible=False) - lesson_plan_result_original = gr.Textbox(visible=False) - lesson_plan_result = gr.Markdown(label="初次生成結果", latex_delimiters = [{"left": "$", "right": "$", "display": False}]) - - lesson_plan_download_button = gr.Button("轉成 word,完成後請點擊右下角 download 按鈕", variant="primary") - lesson_plan_result_word_link = gr.File(label="Download Word") - with gr.Tab("出場券"): - with gr.Row(): - with gr.Column(scale=1): - with gr.Row(): - exit_ticket_content_type_name = gr.Textbox(value="exit_ticket", visible=False) - exit_ticket_time = gr.Slider(label="選擇出場券時間(分鐘)", minimum=5, maximum=10, step=1, value=8) - exit_ticket_btn = gr.Button("生成出場券 🎟️", variant="primary", visible=True) - with gr.Accordion("微調", open=False): - exit_ticket_result_fine_tune_prompt = gr.Textbox(label="根據結果,輸入你想更改的想法") - exit_ticket_result_fine_tune_btn = gr.Button("微調結果", variant="primary") - exit_ticket_result_retrun_original = gr.Button("返回原始結果") - with gr.Accordion("prompt", open=False) as exit_ticket_accordion: - exit_ticket_prompt = gr.Textbox(label="worksheet_prompt", show_copy_button=True, lines=40) - with gr.Column(scale=2): - # 生成對應不同模式的結果 - exit_ticket_result_prompt = gr.Textbox(visible=False) - exit_ticket_result_original = gr.Textbox(visible=False) - exit_ticket_result = gr.Markdown(label="初次生成結果", latex_delimiters = [{"left": "$", "right": "$", "display": False}]) - - exit_ticket_download_button = gr.Button("轉成 word,完成後請點擊右下角 download 按鈕", variant="primary") - exit_ticket_result_word_link = gr.File(label="Download Word") - - - # with gr.Tab("素養導向閱讀題組"): - # literacy_oriented_reading_content = gr.Textbox(label="輸入閱讀材料") - # literacy_oriented_reading_content_btn = gr.Button("生成閱讀理解題") - - # with gr.Tab("自我評估"): - # self_assessment_content = gr.Textbox(label="輸入自評問卷或檢查表") - # self_assessment_content_btn = gr.Button("生成自評問卷") - # with gr.Tab("自我反思評量"): - # self_reflection_content = gr.Textbox(label="輸入自我反思活動") - # self_reflection_content_btn = gr.Button("生成自我反思活動") - # with gr.Tab("後設認知"): - # metacognition_content = gr.Textbox(label="輸入後設認知相關問題") - # metacognition_content_btn = gr.Button("生成後設認知問題") - - with gr.Accordion("免責聲明", open=True): - gr.Markdown(""" - 本內容由AI解析並自動生成,均一平台與影片作者不對內容的準確性做出保證。建議在學習或應用前,先行查證並確認相關資訊的正確性。 - 相關規範請參考:https://www.junyiacademy.org/event/jutor-policy/ - """) - - with gr.Accordion("See Details", open=False) as see_details: - with gr.Row(): - is_env_prod = gr.Checkbox(value=False, label="is_env_prod") - LLM_model = gr.Dropdown(label="LLM Model", choices=["open-ai-gpt-4o", "anthropic-claude-3-sonnet", "gemini-1.5-pro", "gemini-1.5-flash"], value="open-ai-gpt-4o", visible=True, interactive=True) - with gr.Tab("逐字稿本文"): - with gr.Row() as transcript_admmin: - transcript_kind = gr.Textbox(value="transcript", show_label=False) - transcript_get_button = gr.Button("取得", size="sm", variant="primary") - transcript_edit_button = gr.Button("編輯", size="sm", variant="primary") - transcript_update_button = gr.Button("儲存", size="sm", variant="primary") - transcript_delete_button = gr.Button("刪除", size="sm", variant="primary") - transcript_create_button = gr.Button("重建", size="sm", variant="primary") - with gr.Row(): - df_string_output = gr.Textbox(lines=40, label="Data Text", interactive=False, show_copy_button=True) - with gr.Tab("文章本文"): - with gr.Row() as reading_passage_admin: + # 飛特音速 + with gr.Column(scale=1, variant="panel", visible=True): + 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" + streaming_chatbot_description = """Hi,我是【飛特音速】, \n + 說話比較快,但有什麼問題都可以問我喔! \n + 🚀 我沒有預設問題、也沒有語音輸入,適合快問快答,一起練習問出好問題吧 \n + 🔠 擅長用文字表達的你,可以用鍵盤輸入你的問題,我會盡力回答你的問題喔\n + 💤 我還在成長,體力有限,每一次學習只能回答十個問題,請讓我休息一下再問問題喔~ + """ + chatbot_open_ai_streaming_name = gr.State("chatbot_open_ai_streaming") + gr.Image(value=streaming_chatbot_avatar_url, height=100, width=100, show_label=False, show_download_button=False, show_share_button=False, show_fullscreen_button=False) + chatbot_open_ai_streaming_select_btn = gr.Button("👆選擇【飛特音速】", elem_id="streaming_chatbot_btn", visible=True, variant="primary") + with gr.Accordion("🚀 飛特音速 敘述", open=False): + gr.Markdown(value=streaming_chatbot_description, visible=True) + user_avatar = "https://em-content.zobj.net/source/google/263/flushed-face_1f633.png" + # 飛特精靈 + with gr.Column(scale=1, variant="panel", visible=True): + vaitor_chatbot_avatar_url = "https://junyitopicimg.s3.amazonaws.com/s4byy--icon.jpe" + vaitor_chatbot_avatar_images = gr.State([user_avatar, vaitor_chatbot_avatar_url]) + vaitor_chatbot_description = """Hi,我是你的AI學伴【飛特精靈】,\n + 我可以陪你一起學習本次的內容,有什麼問題都可以問我喔!\n + 🤔 如果你不知道怎麼發問,可以點擊左下方的問題一、問題二、問題三,我會幫你生成問題!\n + 🗣️ 也可以點擊右下方用語音輸入,我會幫你轉換成文字,厲害吧!\n + 🔠 或是直接鍵盤輸入你的問題,我會盡力回答你的問題喔!\n + 💤 但我還在成長,體力有限,每一次學習只能回答十個問題,請讓我休息一下再問問題喔!\n + 🦄 如果達到上限,或是遇到精靈很累,請問問其他朋友,像是飛特音速說話的速度比較快,你是否跟得上呢?你也可以和其他精靈互動看看喔!\n + """ + chatbot_open_ai_name = gr.State("chatbot_open_ai") + gr.Image(value=vaitor_chatbot_avatar_url, height=100, width=100, show_label=False, show_download_button=False, show_share_button=False, show_fullscreen_button=False) + vaitor_chatbot_select_btn = gr.Button("👆選擇【飛特精靈】", elem_id="chatbot_btn", visible=True, variant="primary") + with gr.Accordion("🦄 飛特精靈 敘述", open=False): + vaitor_chatbot_description_value = gr.Markdown(value=vaitor_chatbot_description, visible=True) + # 狐狸貓 + with gr.Column(scale=1, variant="panel"): + foxcat_chatbot_avatar_url = "https://storage.googleapis.com/wpassets.junyiacademy.org/1/2020/06/%E7%A7%91%E5%AD%B8%E5%BE%BD%E7%AB%A0-2-150x150.png" + foxcat_avatar_images = gr.State([user_avatar, foxcat_chatbot_avatar_url]) + foxcat_chatbot_description = """Hi,我是【狐狸貓】,可以陪你一起學習本次的內容,有什麼問題都可以問我喔!\n + 🤔 三年級學生|10 歲|男\n + 🗣️ 口頭禪:「感覺好好玩喔!」「咦?是這樣嗎?」\n + 🔠 興趣:看知識型書籍、熱血的動漫卡通、料理、爬山、騎腳踏車。因為太喜歡吃魚了,正努力和爸爸學習釣魚、料理魚及各種有關魚的知識,最討厭的食物是青椒。\n + 💤 個性:喜歡學習新知,擁有最旺盛的好奇心,家裡堆滿百科全書,例如:國家地理頻道出版的「終極魚百科」,雖都沒有看完,常常被梨梨唸是三分鐘熱度,但是也一點一點學習到不同領域的知識。雖然有時會忘東忘西,但認真起來也是很可靠,答應的事絕對使命必達。遇到挑戰時,勇於跳出舒適圈,追求自我改變,視困難為成長的機會。 + """ + foxcat_chatbot_name = gr.State("foxcat") + gr.Image(value=foxcat_chatbot_avatar_url, height=100, width=100, show_label=False, show_download_button=False, show_share_button=False, show_fullscreen_button=False) + foxcat_chatbot_select_btn = gr.Button("👆選擇【狐狸貓】", visible=True, variant="primary", elem_classes="chatbot_select_btn") + with gr.Accordion("💜 狐狸貓 敘述", open=False): + foxcat_chatbot_description_value = gr.Markdown(value=foxcat_chatbot_description, visible=True) + # 梨梨 + with gr.Column(scale=1, variant="panel"): + lili_chatbot_avatar_url = "https://junyitopicimg.s3.amazonaws.com/live/v1283-new-topic-44-icon.png" + lili_avatar_images = gr.State([user_avatar, lili_chatbot_avatar_url]) + lili_chatbot_description = """你好,我是溫柔的【梨梨】,很高興可以在這裡陪伴你學習。如果你有任何疑問,請隨時向我提出哦! \n + 🤔 三年級學生|10 歲|女\n + 🗣️ 口頭禪:「真的假的?!」「讓我想一想喔」「你看吧!大問題拆解成小問題,就變得簡單啦!」「混混噩噩的生活不值得過」\n + 🔠 興趣:烘焙餅乾(父母開糕餅店)、畫畫、聽流行音樂、收納。\n + 💤 個性: + - 內向害羞,比起出去玩更喜歡待在家(除非是跟狐狸貓出去玩) + - 數理邏輯很好;其實覺得麥麥連珠炮的提問有點煩,但還是會耐心地回答 + - 有驚人的眼力,總能觀察到其他人沒有察覺的細節 + - 喜歡整整齊齊的環境,所以一到麥麥家就受不了 + """ + lili_chatbot_name = gr.State("lili") + gr.Image(value=lili_chatbot_avatar_url, height=100, width=100, show_label=False, show_download_button=False, show_share_button=False, show_fullscreen_button=False) + lili_chatbot_select_btn = gr.Button("👆選擇【梨梨】", visible=True, variant="primary", elem_classes="chatbot_select_btn") + with gr.Accordion("🧡 梨梨 敘述", open=False): + lili_chatbot_description_value = gr.Markdown(value=lili_chatbot_description, visible=True) + # 麥麥 + with gr.Column(scale=1, variant="panel"): + maimai_chatbot_avatar_url = "https://storage.googleapis.com/wpassets.junyiacademy.org/1/2020/07/%E6%80%9D%E8%80%83%E5%8A%9B%E8%B6%85%E4%BA%BA%E5%BE%BD%E7%AB%A0_%E5%B7%A5%E4%BD%9C%E5%8D%80%E5%9F%9F-1-%E8%A4%87%E6%9C%AC-150x150.png" + maimai_avatar_images = gr.State([user_avatar, maimai_chatbot_avatar_url]) + maimai_chatbot_description = """Hi,我是迷人的【麥麥】,我在這裡等著和你一起探索新知,任何疑問都可以向我提出!\n + 🤔 三年級學生|10 歲|男\n + 🗣️ 口頭禪:「Oh My God!」「好奇怪喔!」「喔!原來是這樣啊!」\n + 🔠 興趣:最愛去野外玩耍(心情好時會順便捕魚送給狐狸貓),喜歡講冷笑話、惡作劇。因為太喜歡玩具,而開始自己做玩具,家裡就好像他的遊樂場。\n + 💤 個性:喜歡問問題,就算被梨梨ㄘㄟ,也還是照問|憨厚,外向好動,樂天開朗,不會被難題打敗|喜歡收集各式各樣的東西;房間只有在整理的那一天最乾淨 + """ + maimai_chatbot_name = gr.State("maimai") + gr.Image(value=maimai_chatbot_avatar_url, height=100, width=100, show_label=False, show_download_button=False, show_share_button=False, show_fullscreen_button=False) + maimai_chatbot_select_btn = gr.Button("👆選擇【麥麥】", visible=True, variant="primary", elem_classes="chatbot_select_btn") + with gr.Accordion("💙 麥麥 敘述", open=False): + maimai_chatbot_description_value = gr.Markdown(value=maimai_chatbot_description, visible=True) + # 尚未開放 + with gr.Column(scale=1, variant="panel"): + gr.Markdown(value="### 尚未開放", visible=True) + + with gr.Row("飛特音速") as chatbot_open_ai_streaming: with gr.Column(): - with gr.Row(): - reading_passage_kind = gr.Textbox(value="reading_passage_latex", show_label=False) - with gr.Row(): - # reading_passage_text_to_latex = gr.Button("新增 LaTeX", size="sm", variant="primary") - reading_passage_get_button = gr.Button("取得", size="sm", variant="primary") - reading_passage_edit_button = gr.Button("編輯", size="sm", variant="primary") - reading_passage_update_button = gr.Button("儲存", size="sm", variant="primary") - reading_passage_delete_button = gr.Button("刪除", size="sm", variant="primary") - reading_passage_create_button = gr.Button("重建", size="sm", variant="primary") - with gr.Row(): - reading_passage_text = gr.Textbox(label="reading_passage_latex", lines=40, interactive=False, show_copy_button=True) - with gr.Tab("重點摘要本文"): - with gr.Row() as summary_admmin: + streaming_chat_greeting = """ + Hi,我是【飛特音速】,說話比較快,但有什麼問題都可以問我喔! \n + 🚀 我沒有預設問題、也沒有語音輸入,適合快問快答的你 \n + 🔠 鍵盤輸入你的問題,我會盡力回答你的問題喔!\n + 💤 我還在成長,體力有限,每一次學習只能回答十個問題,請讓我休息一下再問問題喔! + """ + additional_inputs = [password, video_id, user_data, streaming_chat_thread_id_state, trascript_state, key_moments_state, content_subject_state, content_grade_state, ai_chatbot_socratic_mode_btn] + streaming_chat = gr.ChatInterface( + fn=chat_with_opan_ai_assistant_streaming, + chatbot=streaming_ai_chatbot, + additional_inputs=additional_inputs, + submit_btn="送出", + stop_btn=None, + description=streaming_chat_greeting + ) + with gr.Row("一般精靈") as chatbot_ai: with gr.Column(): + ai_chatbot_greeting = [[ + "請問你是誰?", + """Hi,我是飛特精靈的朋友們【梨梨、麥麥、狐狸貓】,也可以陪你一起學習本次的內容,有什麼問題都可以問我喔! + 🤔 如果你不知道怎麼發問,可以點擊左下方的問題一、問題二、問題三,我會幫你生成問題! + 🗣️ 也可以點擊右下方用語音輸入,我會幫你轉換成文字,厲害吧! + 🔠 或是直接鍵盤輸入你的問題,我會盡力回答你的問題喔! + 💤 精靈們體力都有限,每一次學習只能回答十個問題,請讓我休息一下再問問題喔! + """, + ]] + with gr.Row(): + ai_chatbot = gr.Chatbot(label="ai_chatbot", show_share_button=False, show_label=False, latex_delimiters=latex_delimiters, value=ai_chatbot_greeting) with gr.Row(): - summary_kind = gr.Textbox(value="summary_markdown", show_label=False) + with gr.Accordion("你也有類似的問題想問嗎? 請按下 ◀︎", open=False) as ask_questions_accordion_2: + ai_chatbot_question_1 = gr.Button("問題一") + ai_chatbot_question_2 = gr.Button("問題一") + ai_chatbot_question_3 = gr.Button("問題一") + create_questions_btn = gr.Button("生成問題", variant="primary") + ai_chatbot_audio_input = gr.Audio(sources=["microphone"], type="filepath", max_length=60, label="語音輸入") with gr.Row(): - # summary_to_markdown = gr.Button("新增 Markdown", size="sm", variant="primary") - summary_get_button = gr.Button("取得", size="sm", variant="primary") - summary_edit_button = gr.Button("編輯", size="sm", variant="primary") - summary_update_button = gr.Button("儲存", size="sm", variant="primary") - summary_delete_button = gr.Button("刪除", size="sm", variant="primary") - summary_create_button = gr.Button("重建", size="sm", variant="primary") + ai_msg = gr.Textbox(label="訊息輸入",scale=3) + ai_send_button = gr.Button("送出", variant="primary",scale=1) + ai_send_feedback_btn = gr.Button("提問力回饋", variant="primary", scale=1, visible=False) + with gr.Tab("文章模式"): with gr.Row(): - summary_text = gr.Textbox(label="summary_markdown", lines=40, interactive=False, show_copy_button=True) - with gr.Tab("關鍵時刻本文"): - with gr.Row() as key_moments_admin: - key_moments_kind = gr.Textbox(value="key_moments", show_label=False) - key_moments_get_button = gr.Button("取得", size="sm", variant="primary") - key_moments_edit_button = gr.Button("編輯", size="sm", variant="primary") - key_moments_update_button = gr.Button("儲存", size="sm", variant="primary") - key_moments_delete_button = gr.Button("刪除", size="sm", variant="primary") - key_moments_create_button = gr.Button("重建", size="sm", variant="primary") + reading_passage = gr.Markdown(show_label=False, latex_delimiters = [{"left": "$", "right": "$", "display": False}]) + reading_passage_speak_button = gr.Button("Speak", visible=False) + reading_passage_audio_output = gr.Audio(label="Audio Output", visible=False) + with gr.Tab("重點摘要"): with gr.Row(): - key_moments = gr.Textbox(label="Key Moments", lines=40, interactive=False, show_copy_button=True) - with gr.Tab("問題本文"): - with gr.Row() as question_list_admin: - questions_kind = gr.Textbox(value="questions", show_label=False) - questions_get_button = gr.Button("取得", size="sm", variant="primary") - questions_edit_button = gr.Button("編輯", size="sm", variant="primary") - questions_update_button = gr.Button("儲存", size="sm", variant="primary") - questions_delete_button = gr.Button("刪除", size="sm", variant="primary") - questions_create_button = gr.Button("重建", size="sm", variant="primary") + df_summarise = gr.Markdown(show_label=False, latex_delimiters = [{"left": "$", "right": "$", "display": False}]) + with gr.Tab("心智圖",elem_id="mind_map_tab"): with gr.Row(): - questions_json = gr.Textbox(label="Questions", lines=40, interactive=False, show_copy_button=True) - with gr.Tab("問題答案本文"): - with gr.Row() as questions_answers_admin: - questions_answers_kind = gr.Textbox(value="questions_answers", show_label=False) - questions_answers_get_button = gr.Button("取得", size="sm", variant="primary") - questions_answers_edit_button = gr.Button("編輯", size="sm", variant="primary") - questions_answers_update_button = gr.Button("儲存", size="sm", variant="primary") - questions_answers_delete_button = gr.Button("刪除", size="sm", variant="primary") - questions_answers_create_button = gr.Button("重建", size="sm", variant="primary") + mind_map_html = gr.HTML() + with gr.Tab("關鍵時刻"): with gr.Row(): - questions_answers_json = gr.Textbox(label="Questions Answers", lines=40, interactive=False, show_copy_button=True) + key_moments_html = gr.HTML(value="") with gr.Tab("教學備課"): - with gr.Row() as worksheet_admin: - worksheet_kind = gr.Textbox(value="ai_content_list", show_label=False) - worksheet_get_button = gr.Button("取得", size="sm", variant="primary") - worksheet_edit_button = gr.Button("編輯", size="sm", variant="primary") - worksheet_update_button = gr.Button("儲存", size="sm", variant="primary") - worksheet_delete_button = gr.Button("刪除", size="sm", variant="primary") - worksheet_create_button = gr.Button("重建(X)", size="sm", variant="primary", interactive=False) with gr.Row(): - worksheet_json = gr.Textbox(label="worksheet", lines=40, interactive=False, show_copy_button=True) - with gr.Tab("逐字稿"): - simple_html_content = gr.HTML(label="Simple Transcript") - with gr.Tab("圖文"): - transcript_html = gr.HTML(label="YouTube Transcript and Video") - with gr.Tab("markdown"): - gr.Markdown("## 請複製以下 markdown 並貼到你的心智圖工具中,建議使用:https://markmap.js.org/repl") - mind_map = gr.Textbox(container=True, show_copy_button=True, lines=40, elem_id="mind_map_markdown") - with gr.Accordion("refresh all", open=False): + content_subject = gr.Dropdown(label="選擇主題", choices=["數學", "自然", "國文", "英文", "社會","物理", "化學", "生物", "地理", "歷史", "公民"], value="", visible=False) + content_grade = gr.Dropdown(label="選擇年級", choices=["一年級", "二年級", "三年級", "四年級", "五年級", "六年級", "七年級", "八年級", "九年級", "十年級", "十一年級", "十二年級"], value="", visible=False) + content_level = gr.Dropdown(label="差異化教學", choices=["基礎", "中級", "進階"], value="基礎") with gr.Row(): - gr.Markdown("## 清單影片:重新生成所有內容") - with gr.Row(): - refresh_video_ids = gr.Textbox(label="輸入影片 id,以 , 逗號分隔") - refresh_btn = gr.Button("refresh", variant="primary") + with gr.Tab("學習單"): + with gr.Row(): + with gr.Column(scale=1): + with gr.Row(): + worksheet_content_type_name = gr.Textbox(value="worksheet", visible=False) + worksheet_algorithm = gr.Dropdown(label="選擇教學策略或理論", choices=["Bloom認知階層理論", "Polya數學解題法", "CRA教學法"], value="Bloom認知階層理論", visible=False) + worksheet_content_btn = gr.Button("生成學習單 📄", variant="primary", visible=True) + with gr.Accordion("微調", open=False): + worksheet_result_fine_tune_prompt = gr.Textbox(label="根據結果,輸入你想更改的想法") + worksheet_result_fine_tune_btn = gr.Button("微調結果", variant="primary") + worksheet_result_retrun_original = gr.Button("返回原始結果") + with gr.Accordion("prompt", open=False) as worksheet_accordion: + worksheet_prompt = gr.Textbox(label="worksheet_prompt", show_copy_button=True, lines=40) + with gr.Column(scale=2): + # 生成對應不同模式的結果 + worksheet_result_prompt = gr.Textbox(visible=False) + worksheet_result_original = gr.Textbox(visible=False) + worksheet_result = gr.Markdown(label="初次生成結果", latex_delimiters = [{"left": "$", "right": "$", "display": False}]) + worksheet_download_button = gr.Button("轉成 word,完成後請點擊右下角 download 按鈕", variant="primary") + worksheet_result_word_link = gr.File(label="Download Word") + with gr.Tab("教案"): + with gr.Row(): + with gr.Column(scale=1): + with gr.Row(): + lesson_plan_content_type_name = gr.Textbox(value="lesson_plan", visible=False) + lesson_plan_time = gr.Slider(label="選擇課程時間(分鐘)", minimum=10, maximum=120, step=5, value=40) + lesson_plan_btn = gr.Button("生成教案 📕", variant="primary", visible=True) + with gr.Accordion("微調", open=False): + lesson_plan_result_fine_tune_prompt = gr.Textbox(label="根據結果,輸入你想更改的想法") + lesson_plan_result_fine_tune_btn = gr.Button("微調結果", variant="primary") + lesson_plan_result_retrun_original = gr.Button("返回原始結果") + with gr.Accordion("prompt", open=False) as lesson_plan_accordion: + lesson_plan_prompt = gr.Textbox(label="worksheet_prompt", show_copy_button=True, lines=40) + with gr.Column(scale=2): + # 生成對應不同模式的結果 + lesson_plan_result_prompt = gr.Textbox(visible=False) + lesson_plan_result_original = gr.Textbox(visible=False) + lesson_plan_result = gr.Markdown(label="初次生成結果", latex_delimiters = [{"left": "$", "right": "$", "display": False}]) + + lesson_plan_download_button = gr.Button("轉成 word,完成後請點擊右下角 download 按鈕", variant="primary") + lesson_plan_result_word_link = gr.File(label="Download Word") + with gr.Tab("出場券"): + with gr.Row(): + with gr.Column(scale=1): + with gr.Row(): + exit_ticket_content_type_name = gr.Textbox(value="exit_ticket", visible=False) + exit_ticket_time = gr.Slider(label="選擇出場券時間(分鐘)", minimum=5, maximum=10, step=1, value=8) + exit_ticket_btn = gr.Button("生成出場券 🎟️", variant="primary", visible=True) + with gr.Accordion("微調", open=False): + exit_ticket_result_fine_tune_prompt = gr.Textbox(label="根據結果,輸入你想更改的想法") + exit_ticket_result_fine_tune_btn = gr.Button("微調結果", variant="primary") + exit_ticket_result_retrun_original = gr.Button("返回原始結果") + with gr.Accordion("prompt", open=False) as exit_ticket_accordion: + exit_ticket_prompt = gr.Textbox(label="worksheet_prompt", show_copy_button=True, lines=40) + with gr.Column(scale=2): + # 生成對應不同模式的結果 + exit_ticket_result_prompt = gr.Textbox(visible=False) + exit_ticket_result_original = gr.Textbox(visible=False) + exit_ticket_result = gr.Markdown(label="初次生成結果", latex_delimiters = [{"left": "$", "right": "$", "display": False}]) + + exit_ticket_download_button = gr.Button("轉成 word,完成後請點擊右下角 download 按鈕", variant="primary") + exit_ticket_result_word_link = gr.File(label="Download Word") + + + # with gr.Tab("素養導向閱讀題組"): + # literacy_oriented_reading_content = gr.Textbox(label="輸入閱讀材料") + # literacy_oriented_reading_content_btn = gr.Button("生成閱讀理解題") + + # with gr.Tab("自我評估"): + # self_assessment_content = gr.Textbox(label="輸入自評問卷或檢查表") + # self_assessment_content_btn = gr.Button("生成自評問卷") + # with gr.Tab("自我反思評量"): + # self_reflection_content = gr.Textbox(label="輸入自我反思活動") + # self_reflection_content_btn = gr.Button("生��自我反思活動") + # with gr.Tab("後設認知"): + # metacognition_content = gr.Textbox(label="輸入後設認知相關問題") + # metacognition_content_btn = gr.Button("生成後設認知問題") + + with gr.Accordion("免責聲明", open=True): + gr.Markdown(""" + 本內容由AI解析並自動生成,均一平台與影片作者不對內容的準確性做出保證。建議在學習或應用前,先行查證並確認相關資訊的正確性。 + 相關規範請參考:https://www.junyiacademy.org/event/jutor-policy/ + """) + + with gr.Accordion("See Details", open=False) as see_details: with gr.Row(): - refresh_result = gr.JSON() - - refresh_btn.click( - lambda: gr.update(interactive=False), - inputs=[], - outputs=[refresh_btn] - ).then( - refresh_video_LLM_all_content, - inputs=[refresh_video_ids], - outputs=[refresh_result] - ) + is_env_prod = gr.Checkbox(value=False, label="is_env_prod") + LLM_model = gr.Dropdown(label="LLM Model", choices=["open-ai-gpt-4o", "anthropic-claude-3-sonnet", "gemini-1.5-pro", "gemini-1.5-flash"], value="open-ai-gpt-4o", visible=True, interactive=True) + with gr.Tab("逐字稿本文"): + with gr.Row() as transcript_admmin: + transcript_kind = gr.Textbox(value="transcript", show_label=False) + transcript_get_button = gr.Button("取得", size="sm", variant="primary") + transcript_edit_button = gr.Button("編輯", size="sm", variant="primary") + transcript_update_button = gr.Button("儲存", size="sm", variant="primary") + transcript_delete_button = gr.Button("刪除", size="sm", variant="primary") + transcript_create_button = gr.Button("重建", size="sm", variant="primary") + with gr.Row(): + df_string_output = gr.Textbox(lines=40, label="Data Text", interactive=False, show_copy_button=True) + with gr.Tab("文章本文"): + with gr.Row() as reading_passage_admin: + with gr.Column(): + with gr.Row(): + reading_passage_kind = gr.Textbox(value="reading_passage_latex", show_label=False) + with gr.Row(): + # reading_passage_text_to_latex = gr.Button("新增 LaTeX", size="sm", variant="primary") + reading_passage_get_button = gr.Button("取得", size="sm", variant="primary") + reading_passage_edit_button = gr.Button("編輯", size="sm", variant="primary") + reading_passage_update_button = gr.Button("儲存", size="sm", variant="primary") + reading_passage_delete_button = gr.Button("刪除", size="sm", variant="primary") + reading_passage_create_button = gr.Button("重建", size="sm", variant="primary") + with gr.Row(): + reading_passage_text = gr.Textbox(label="reading_passage_latex", lines=40, interactive=False, show_copy_button=True) + with gr.Tab("重點摘要本文"): + with gr.Row() as summary_admmin: + with gr.Column(): + with gr.Row(): + summary_kind = gr.Textbox(value="summary_markdown", show_label=False) + with gr.Row(): + # summary_to_markdown = gr.Button("新增 Markdown", size="sm", variant="primary") + summary_get_button = gr.Button("取得", size="sm", variant="primary") + summary_edit_button = gr.Button("編輯", size="sm", variant="primary") + summary_update_button = gr.Button("儲存", size="sm", variant="primary") + summary_delete_button = gr.Button("刪除", size="sm", variant="primary") + summary_create_button = gr.Button("重建", size="sm", variant="primary") + with gr.Row(): + summary_text = gr.Textbox(label="summary_markdown", lines=40, interactive=False, show_copy_button=True) + with gr.Tab("關鍵時刻本文"): + with gr.Row() as key_moments_admin: + key_moments_kind = gr.Textbox(value="key_moments", show_label=False) + key_moments_get_button = gr.Button("取得", size="sm", variant="primary") + key_moments_edit_button = gr.Button("編輯", size="sm", variant="primary") + key_moments_update_button = gr.Button("儲存", size="sm", variant="primary") + key_moments_delete_button = gr.Button("刪除", size="sm", variant="primary") + key_moments_create_button = gr.Button("重建", size="sm", variant="primary") + with gr.Row(): + key_moments = gr.Textbox(label="Key Moments", lines=40, interactive=False, show_copy_button=True) + with gr.Tab("問題本文"): + with gr.Row() as question_list_admin: + questions_kind = gr.Textbox(value="questions", show_label=False) + questions_get_button = gr.Button("取得", size="sm", variant="primary") + questions_edit_button = gr.Button("編輯", size="sm", variant="primary") + questions_update_button = gr.Button("儲存", size="sm", variant="primary") + questions_delete_button = gr.Button("刪除", size="sm", variant="primary") + questions_create_button = gr.Button("重建", size="sm", variant="primary") + with gr.Row(): + questions_json = gr.Textbox(label="Questions", lines=40, interactive=False, show_copy_button=True) + with gr.Tab("問題答案本文"): + with gr.Row() as questions_answers_admin: + questions_answers_kind = gr.Textbox(value="questions_answers", show_label=False) + questions_answers_get_button = gr.Button("取得", size="sm", variant="primary") + questions_answers_edit_button = gr.Button("編輯", size="sm", variant="primary") + questions_answers_update_button = gr.Button("儲存", size="sm", variant="primary") + questions_answers_delete_button = gr.Button("刪除", size="sm", variant="primary") + questions_answers_create_button = gr.Button("重建", size="sm", variant="primary") + with gr.Row(): + questions_answers_json = gr.Textbox(label="Questions Answers", lines=40, interactive=False, show_copy_button=True) + with gr.Tab("教學備課"): + with gr.Row() as worksheet_admin: + worksheet_kind = gr.Textbox(value="ai_content_list", show_label=False) + worksheet_get_button = gr.Button("取得", size="sm", variant="primary") + worksheet_edit_button = gr.Button("編輯", size="sm", variant="primary") + worksheet_update_button = gr.Button("儲存", size="sm", variant="primary") + worksheet_delete_button = gr.Button("刪除", size="sm", variant="primary") + worksheet_create_button = gr.Button("重建(X)", size="sm", variant="primary", interactive=False) + with gr.Row(): + worksheet_json = gr.Textbox(label="worksheet", lines=40, interactive=False, show_copy_button=True) + with gr.Tab("逐字稿"): + simple_html_content = gr.HTML(label="Simple Transcript") + with gr.Tab("圖文"): + transcript_html = gr.HTML(label="YouTube Transcript and Video") + with gr.Tab("markdown"): + gr.Markdown("## 請複製以下 markdown 並貼到你的心智圖工具中,建議使用:https://markmap.js.org/repl") + mind_map = gr.Textbox(container=True, show_copy_button=True, lines=40, elem_id="mind_map_markdown") + with gr.Accordion("refresh all", open=False): + with gr.Row(): + gr.Markdown("## 清單影片:重新生成所有內容") + with gr.Row(): + refresh_video_ids = gr.Textbox(label="輸入影片 id,以 , 逗號分隔") + refresh_btn = gr.Button("refresh", variant="primary") + with gr.Row(): + refresh_result = gr.JSON() + + refresh_btn.click( + lambda: gr.update(interactive=False), + inputs=[], + outputs=[refresh_btn] + ).then( + refresh_video_LLM_all_content, + inputs=[refresh_video_ids], + outputs=[refresh_result] + ) + - - # OPEN AI CHATBOT SELECT - chatbot_select_outputs=[ - chatbot_select_accordion, - all_chatbot_select_btn, - chatbot_open_ai_streaming, - chatbot_ai, - ai_name, - ai_chatbot_ai_type, - ai_chatbot_thread_id - ] - # 聊天机器人的配置数据 - chatbots = [ - { - "button": vaitor_chatbot_select_btn, - "name_state": chatbot_open_ai_name, - "avatar_images": vaitor_chatbot_avatar_images, - "description_value": vaitor_chatbot_description_value, - "chatbot_select_outputs": chatbot_select_outputs, - "chatbot_output": ai_chatbot - }, - { - "button": foxcat_chatbot_select_btn, - "name_state": foxcat_chatbot_name, - "avatar_images": foxcat_avatar_images, - "description_value": foxcat_chatbot_description_value, - "chatbot_select_outputs": chatbot_select_outputs, - "chatbot_output": ai_chatbot - }, - { - "button": lili_chatbot_select_btn, - "name_state": lili_chatbot_name, - "avatar_images": lili_avatar_images, - "description_value": lili_chatbot_description_value, - "chatbot_select_outputs": chatbot_select_outputs, - "chatbot_output": ai_chatbot - }, - { - "button": maimai_chatbot_select_btn, - "name_state": maimai_chatbot_name, - "avatar_images": maimai_avatar_images, - "description_value": maimai_chatbot_description_value, - "chatbot_select_outputs": chatbot_select_outputs, - "chatbot_output": ai_chatbot - } - ] - - def setup_chatbot_select_button(chatbot_dict): - button = chatbot_dict["button"] - chatbot_name_state = chatbot_dict["name_state"] - avatar_images = chatbot_dict["avatar_images"] - description_value = chatbot_dict["description_value"] - chatbot_select_outputs = chatbot_dict["chatbot_select_outputs"] - chatbot_output = chatbot_dict["chatbot_output"] - button.click( - chatbot_select, # 你可能需要修改这个函数以适应当前的逻辑 - inputs=[chatbot_name_state], + # OPEN AI CHATBOT SELECT + chatbot_select_outputs=[ + chatbot_select_accordion, + all_chatbot_select_btn, + chatbot_open_ai_streaming, + chatbot_ai, + ai_name, + ai_chatbot_ai_type, + ai_chatbot_thread_id + ] + # 聊天机器人的配置数据 + chatbots = [ + { + "button": vaitor_chatbot_select_btn, + "name_state": chatbot_open_ai_name, + "avatar_images": vaitor_chatbot_avatar_images, + "description_value": vaitor_chatbot_description_value, + "chatbot_select_outputs": chatbot_select_outputs, + "chatbot_output": ai_chatbot + }, + { + "button": foxcat_chatbot_select_btn, + "name_state": foxcat_chatbot_name, + "avatar_images": foxcat_avatar_images, + "description_value": foxcat_chatbot_description_value, + "chatbot_select_outputs": chatbot_select_outputs, + "chatbot_output": ai_chatbot + }, + { + "button": lili_chatbot_select_btn, + "name_state": lili_chatbot_name, + "avatar_images": lili_avatar_images, + "description_value": lili_chatbot_description_value, + "chatbot_select_outputs": chatbot_select_outputs, + "chatbot_output": ai_chatbot + }, + { + "button": maimai_chatbot_select_btn, + "name_state": maimai_chatbot_name, + "avatar_images": maimai_avatar_images, + "description_value": maimai_chatbot_description_value, + "chatbot_select_outputs": chatbot_select_outputs, + "chatbot_output": ai_chatbot + } + ] + + def setup_chatbot_select_button(chatbot_dict): + button = chatbot_dict["button"] + chatbot_name_state = chatbot_dict["name_state"] + avatar_images = chatbot_dict["avatar_images"] + description_value = chatbot_dict["description_value"] + chatbot_select_outputs = chatbot_dict["chatbot_select_outputs"] + chatbot_output = chatbot_dict["chatbot_output"] + button.click( + chatbot_select, # 你可能需要修改这个函数以适应当前的逻辑 + inputs=[chatbot_name_state], + outputs=chatbot_select_outputs + ).then( + update_avatar_images, + inputs=[avatar_images, description_value], + outputs=[chatbot_output], + scroll_to_output=True + ) + + for chatbot_dict in chatbots: + setup_chatbot_select_button(chatbot_dict) + + # STREAMING CHATBOT SELECT + chatbot_open_ai_streaming_select_btn.click( + chatbot_select, + inputs=[chatbot_open_ai_streaming_name], outputs=chatbot_select_outputs ).then( - update_avatar_images, - inputs=[avatar_images, description_value], - outputs=[chatbot_output], + create_thread_id, + inputs=[], + outputs=[streaming_chat_thread_id_state] + ) + + # ALL CHATBOT SELECT LIST + all_chatbot_select_btn.click( + show_all_chatbot_accordion, + inputs=[], + outputs=[chatbot_select_accordion, all_chatbot_select_btn] + ) + # OPENAI ASSISTANT CHATBOT 連接按鈕點擊事件 + def setup_question_button_click(button, inputs_list, outputs_list, chat_func, scroll_to_output=True): + button.click( + chat_func, + inputs=inputs_list, + outputs=outputs_list, + scroll_to_output=scroll_to_output + ) + + # 其他精靈 ai_chatbot 模式 + ai_send_button.click( + chat_with_any_ai, + inputs=[ai_chatbot_ai_type, 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, ai_chatbot_thread_id, ai_name], + outputs=[ai_msg, ai_chatbot, ai_send_button, ai_send_feedback_btn, ai_chatbot_thread_id], scroll_to_output=True ) + ai_send_feedback_btn.click( + feedback_with_ai, + inputs=[user_data, ai_chatbot_ai_type, ai_chatbot, ai_chatbot_thread_id], + outputs=[ai_chatbot, ai_send_feedback_btn], + scroll_to_output=True + ) + # 其他精靈 ai_chatbot 连接 QA 按钮点击事件 + ai_chatbot_question_buttons = [ai_chatbot_question_1, ai_chatbot_question_2, ai_chatbot_question_3] + for question_btn in ai_chatbot_question_buttons: + inputs_list = [ai_chatbot_ai_type, password, video_id, user_data, trascript_state, key_moments, question_btn, ai_chatbot, content_subject, content_grade, questions_answers_json, ai_chatbot_socratic_mode_btn, ai_chatbot_thread_id, ai_name] + outputs_list = [ai_msg, ai_chatbot, ai_send_button, ai_send_feedback_btn, ai_chatbot_thread_id] + setup_question_button_click(question_btn, inputs_list, outputs_list, chat_with_any_ai) + + # 為生成問題按鈕設定特殊的點擊事件 + question_buttons = [ + ai_chatbot_question_1, + ai_chatbot_question_2, + ai_chatbot_question_3 + ] + create_questions_btn.click( + change_questions, + inputs=[password, df_string_output], + outputs=question_buttons + ) + ai_chatbot_audio_input.change( + process_open_ai_audio_to_chatbot, + inputs=[password, ai_chatbot_audio_input], + outputs=[ai_msg] + ) + + # 当输入 YouTube 链接时触发 + process_youtube_link_inputs = [password, youtube_link, LLM_model] + process_youtube_link_outputs = [ + video_id, + questions_answers_json, + df_string_output, + summary_text, + df_summarise, + key_moments, + key_moments_html, + mind_map, + mind_map_html, + transcript_html, + simple_html_content, + reading_passage_text, + reading_passage, + content_subject, + content_grade, + ] + update_state_inputs = [ + content_subject, + content_grade, + df_string_output, + key_moments, + questions_answers_json, + ] + update_state_outputs = [ + content_subject_state, + content_grade_state, + trascript_state, + key_moments_state, + streaming_chat_thread_id_state, + ai_chatbot_question_1, + ai_chatbot_question_2, + ai_chatbot_question_3 + ] + + youtube_link.input( + process_youtube_link, + inputs=process_youtube_link_inputs, + outputs=process_youtube_link_outputs + ).then( + update_state, + inputs=update_state_inputs, + outputs=update_state_outputs + ) + + youtube_link_btn.click( + process_youtube_link, + inputs=process_youtube_link_inputs, + outputs=process_youtube_link_outputs + ).then( + update_state, + inputs=update_state_inputs, + outputs=update_state_outputs + ) + + + # --- CRUD admin --- + def setup_content_buttons(buttons_config): + for config in buttons_config: + button = config['button'] + action = config['action'] + inputs = config['inputs'] + outputs = config['outputs'] + button.click( + fn=action, + inputs=inputs, + outputs=outputs + ) + + content_buttons_config = [ + # Transcript actions + { + 'button': transcript_get_button, + 'action': get_LLM_content, + 'inputs': [video_id, transcript_kind], + 'outputs': [df_string_output] + }, + { + 'button': transcript_create_button, + 'action': create_LLM_content, + 'inputs': [video_id, df_string_output, transcript_kind, LLM_model], + 'outputs': [df_string_output] + }, + { + 'button': transcript_delete_button, + 'action': delete_LLM_content, + 'inputs': [video_id, transcript_kind], + 'outputs': [df_string_output] + }, + { + 'button': transcript_edit_button, + 'action': enable_edit_mode, + 'inputs': [], + 'outputs': [df_string_output] + }, + { + 'button': transcript_update_button, + 'action': update_LLM_content, + 'inputs': [video_id, df_string_output, transcript_kind], + 'outputs': [df_string_output] + }, + # Reading passage actions + { + 'button': reading_passage_get_button, + 'action': get_LLM_content, + 'inputs': [video_id, reading_passage_kind], + 'outputs': [reading_passage_text] + }, + { + 'button': reading_passage_create_button, + 'action': create_LLM_content, + 'inputs': [video_id, df_string_output, reading_passage_kind, LLM_model], + 'outputs': [reading_passage_text] + }, + { + 'button': reading_passage_delete_button, + 'action': delete_LLM_content, + 'inputs': [video_id, reading_passage_kind], + 'outputs': [reading_passage_text] + }, + { + 'button': reading_passage_edit_button, + 'action': enable_edit_mode, + 'inputs': [], + 'outputs': [reading_passage_text] + }, + { + 'button': reading_passage_update_button, + 'action': update_LLM_content, + 'inputs': [video_id, reading_passage_text, reading_passage_kind], + 'outputs': [reading_passage_text] + }, + # Summary actions + { + 'button': summary_get_button, + 'action': get_LLM_content, + 'inputs': [video_id, summary_kind], + 'outputs': [summary_text] + }, + { + 'button': summary_create_button, + 'action': create_LLM_content, + 'inputs': [video_id, df_string_output, summary_kind, LLM_model], + 'outputs': [summary_text] + }, + { + 'button': summary_delete_button, + 'action': delete_LLM_content, + 'inputs': [video_id, summary_kind], + 'outputs': [summary_text] + }, + { + 'button': summary_edit_button, + 'action': enable_edit_mode, + 'inputs': [], + 'outputs': [summary_text] + }, + { + 'button': summary_update_button, + 'action': update_LLM_content, + 'inputs': [video_id, summary_text, summary_kind], + 'outputs': [summary_text] + }, + # Key moments actions + { + 'button': key_moments_get_button, + 'action': get_LLM_content, + 'inputs': [video_id, key_moments_kind], + 'outputs': [key_moments] + }, + { + 'button': key_moments_create_button, + 'action': create_LLM_content, + 'inputs': [video_id, df_string_output, key_moments_kind, LLM_model], + 'outputs': [key_moments] + }, + { + 'button': key_moments_delete_button, + 'action': delete_LLM_content, + 'inputs': [video_id, key_moments_kind], + 'outputs': [key_moments] + }, + { + 'button': key_moments_edit_button, + 'action': enable_edit_mode, + 'inputs': [], + 'outputs': [key_moments] + }, + { + 'button': key_moments_update_button, + 'action': update_LLM_content, + 'inputs': [video_id, key_moments, key_moments_kind], + 'outputs': [key_moments] + }, + # Questions actions + { + 'button': questions_get_button, + 'action': get_LLM_content, + 'inputs': [video_id, questions_kind], + 'outputs': [questions_json] + }, + { + 'button': questions_create_button, + 'action': create_LLM_content, + 'inputs': [video_id, df_string_output, questions_kind, LLM_model], + 'outputs': [questions_json] + }, + { + 'button': questions_delete_button, + 'action': delete_LLM_content, + 'inputs': [video_id, questions_kind], + 'outputs': [questions_json] + }, + { + 'button': questions_edit_button, + 'action': enable_edit_mode, + 'inputs': [], + 'outputs': [questions_json] + }, + { + 'button': questions_update_button, + 'action': update_LLM_content, + 'inputs': [video_id, questions_json, questions_kind], + 'outputs': [questions_json] + }, + # Questions answers actions + { + 'button': questions_answers_get_button, + 'action': get_LLM_content, + 'inputs': [video_id, questions_answers_kind], + 'outputs': [questions_answers_json] + }, + { + 'button': questions_answers_create_button, + 'action': create_LLM_content, + 'inputs': [video_id, df_string_output, questions_answers_kind, LLM_model], + 'outputs': [questions_answers_json] + }, + { + 'button': questions_answers_delete_button, + 'action': delete_LLM_content, + 'inputs': [video_id, questions_answers_kind], + 'outputs': [questions_answers_json] + }, + { + 'button': questions_answers_edit_button, + 'action': enable_edit_mode, + 'inputs': [], + 'outputs': [questions_answers_json] + }, + { + 'button': questions_answers_update_button, + 'action': update_LLM_content, + 'inputs': [video_id, questions_answers_json, questions_answers_kind], + 'outputs': [questions_answers_json] + }, + # Worksheet actions + { + 'button': worksheet_get_button, + 'action': get_LLM_content, + 'inputs': [video_id, worksheet_kind], + 'outputs': [worksheet_json] + }, + { + 'button': worksheet_create_button, + 'action': create_LLM_content, + 'inputs': [video_id, df_string_output, worksheet_kind, LLM_model], + 'outputs': [worksheet_json] + }, + { + 'button': worksheet_delete_button, + 'action': delete_LLM_content, + 'inputs': [video_id, worksheet_kind], + 'outputs': [worksheet_json] + }, + { + 'button': worksheet_edit_button, + 'action': enable_edit_mode, + 'inputs': [], + 'outputs': [worksheet_json] + }, + { + 'button': worksheet_update_button, + 'action': update_LLM_content, + 'inputs': [video_id, worksheet_json, worksheet_kind], + 'outputs': [worksheet_json] + }, + ] + setup_content_buttons(content_buttons_config) + + # --- Education Material --- + def setup_education_buttons(buttons_config): + for config in buttons_config: + button = config["button"] + action = config["action"] + inputs = config["inputs"] + outputs = config["outputs"] + button.click( + fn=action, + inputs=inputs, + outputs=outputs + ) + education_buttons_config = [ + # 學習單相關按鈕 + { + "button": worksheet_content_btn, + "action": get_ai_content, + "inputs": [password, user_data, video_id, df_string_output, content_subject, content_grade, content_level, worksheet_algorithm, worksheet_content_type_name], + "outputs": [worksheet_result_original, worksheet_result, worksheet_prompt, worksheet_result_prompt] + }, + { + "button": worksheet_result_fine_tune_btn, + "action": generate_ai_content_fine_tune_result, + "inputs": [password, user_data, worksheet_result_prompt, df_string_output, worksheet_result, worksheet_result_fine_tune_prompt, worksheet_content_type_name], + "outputs": [worksheet_result] + }, + { + "button": worksheet_download_button, + "action": download_exam_result, + "inputs": [worksheet_result], + "outputs": [worksheet_result_word_link] + }, + { + "button": worksheet_result_retrun_original, + "action": return_original_exam_result, + "inputs": [worksheet_result_original], + "outputs": [worksheet_result] + }, + # 教案相關按鈕 + { + "button": lesson_plan_btn, + "action": get_ai_content, + "inputs": [password, user_data, video_id, df_string_output, content_subject, content_grade, content_level, lesson_plan_time, lesson_plan_content_type_name], + "outputs": [lesson_plan_result_original, lesson_plan_result, lesson_plan_prompt, lesson_plan_result_prompt] + }, + { + "button": lesson_plan_result_fine_tune_btn, + "action": generate_ai_content_fine_tune_result, + "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], + "outputs": [lesson_plan_result] + }, + { + "button": lesson_plan_download_button, + "action": download_exam_result, + "inputs": [lesson_plan_result], + "outputs": [lesson_plan_result_word_link] + }, + { + "button": lesson_plan_result_retrun_original, + "action": return_original_exam_result, + "inputs": [lesson_plan_result_original], + "outputs": [lesson_plan_result] + }, + # 出場券相關按鈕 + { + "button": exit_ticket_btn, + "action": get_ai_content, + "inputs": [password, user_data, video_id, df_string_output, content_subject, content_grade, content_level, exit_ticket_time, exit_ticket_content_type_name], + "outputs": [exit_ticket_result_original, exit_ticket_result, exit_ticket_prompt, exit_ticket_result_prompt] + }, + { + "button": exit_ticket_result_fine_tune_btn, + "action": generate_ai_content_fine_tune_result, + "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], + "outputs": [exit_ticket_result] + }, + { + "button": exit_ticket_download_button, + "action": download_exam_result, + "inputs": [exit_ticket_result], + "outputs": [exit_ticket_result_word_link] + }, + { + "button": exit_ticket_result_retrun_original, + "action": return_original_exam_result, + "inputs": [exit_ticket_result_original], + "outputs": [exit_ticket_result] + } + ] + setup_education_buttons(education_buttons_config) + + # init_params + init_outputs = [ + admin, + reading_passage_admin, + summary_admmin, + see_details, + worksheet_accordion, + lesson_plan_accordion, + exit_ticket_accordion, + password, + youtube_link, + block_ready_flag, + chatbot_open_ai_streaming, + chatbot_ai, + ai_chatbot_params, + is_env_prod, + ] + demo.load( + init_params, + inputs =[youtube_link], + outputs = init_outputs + ) - for chatbot_dict in chatbots: - setup_chatbot_select_button(chatbot_dict) - - # STREAMING CHATBOT SELECT - chatbot_open_ai_streaming_select_btn.click( - chatbot_select, - inputs=[chatbot_open_ai_streaming_name], - outputs=chatbot_select_outputs - ).then( - create_thread_id, - inputs=[], - outputs=[streaming_chat_thread_id_state] - ) - - # ALL CHATBOT SELECT LIST - all_chatbot_select_btn.click( - show_all_chatbot_accordion, - inputs=[], - outputs=[chatbot_select_accordion, all_chatbot_select_btn] - ) - # OPENAI ASSISTANT CHATBOT 連接按鈕點擊事件 - def setup_question_button_click(button, inputs_list, outputs_list, chat_func, scroll_to_output=True): - button.click( - chat_func, - inputs=inputs_list, - outputs=outputs_list, - scroll_to_output=scroll_to_output - ) - - # 其他精靈 ai_chatbot 模式 - ai_send_button.click( - chat_with_any_ai, - inputs=[ai_chatbot_ai_type, 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, ai_chatbot_thread_id, ai_name], - outputs=[ai_msg, ai_chatbot, ai_send_button, ai_send_feedback_btn, ai_chatbot_thread_id], - scroll_to_output=True - ) - ai_send_feedback_btn.click( - feedback_with_ai, - inputs=[user_data, ai_chatbot_ai_type, ai_chatbot, ai_chatbot_thread_id], - outputs=[ai_chatbot, ai_send_feedback_btn], - scroll_to_output=True - ) - # 其他精靈 ai_chatbot 连接 QA 按钮点击事件 - ai_chatbot_question_buttons = [ai_chatbot_question_1, ai_chatbot_question_2, ai_chatbot_question_3] - for question_btn in ai_chatbot_question_buttons: - inputs_list = [ai_chatbot_ai_type, password, video_id, user_data, trascript_state, key_moments, question_btn, ai_chatbot, content_subject, content_grade, questions_answers_json, ai_chatbot_socratic_mode_btn, ai_chatbot_thread_id, ai_name] - outputs_list = [ai_msg, ai_chatbot, ai_send_button, ai_send_feedback_btn, ai_chatbot_thread_id] - setup_question_button_click(question_btn, inputs_list, outputs_list, chat_with_any_ai) - - # 為生成問題按鈕設定特殊的點擊事件 - question_buttons = [ - ai_chatbot_question_1, - ai_chatbot_question_2, - ai_chatbot_question_3 - ] - create_questions_btn.click( - change_questions, - inputs=[password, df_string_output], - outputs=question_buttons - ) - ai_chatbot_audio_input.change( - process_open_ai_audio_to_chatbot, - inputs=[password, ai_chatbot_audio_input], - outputs=[ai_msg] - ) - - # 当输入 YouTube 链接时触发 - process_youtube_link_inputs = [password, youtube_link, LLM_model] - process_youtube_link_outputs = [ - video_id, - questions_answers_json, - df_string_output, - summary_text, - df_summarise, - key_moments, - key_moments_html, - mind_map, - mind_map_html, - transcript_html, - simple_html_content, - reading_passage_text, - reading_passage, - content_subject, - content_grade, - ] - update_state_inputs = [ - content_subject, - content_grade, - df_string_output, - key_moments, - questions_answers_json, - ] - update_state_outputs = [ - content_subject_state, - content_grade_state, - trascript_state, - key_moments_state, - streaming_chat_thread_id_state, - ai_chatbot_question_1, - ai_chatbot_question_2, - ai_chatbot_question_3 - ] - - youtube_link.input( - process_youtube_link, - inputs=process_youtube_link_inputs, - outputs=process_youtube_link_outputs - ).then( - update_state, - inputs=update_state_inputs, - outputs=update_state_outputs - ) - - youtube_link_btn.click( - process_youtube_link, - inputs=process_youtube_link_inputs, - outputs=process_youtube_link_outputs - ).then( - update_state, - inputs=update_state_inputs, - outputs=update_state_outputs + app = gr.mount_gradio_app( + app, demo, "/", server_name="0.0.0.0", server_port=7860, show_error=True ) + return app +if __name__ == "__main__": + import uvicorn - # --- CRUD admin --- - def setup_content_buttons(buttons_config): - for config in buttons_config: - button = config['button'] - action = config['action'] - inputs = config['inputs'] - outputs = config['outputs'] - button.click( - fn=action, - inputs=inputs, - outputs=outputs - ) - - content_buttons_config = [ - # Transcript actions - { - 'button': transcript_get_button, - 'action': get_LLM_content, - 'inputs': [video_id, transcript_kind], - 'outputs': [df_string_output] - }, - { - 'button': transcript_create_button, - 'action': create_LLM_content, - 'inputs': [video_id, df_string_output, transcript_kind, LLM_model], - 'outputs': [df_string_output] - }, - { - 'button': transcript_delete_button, - 'action': delete_LLM_content, - 'inputs': [video_id, transcript_kind], - 'outputs': [df_string_output] - }, - { - 'button': transcript_edit_button, - 'action': enable_edit_mode, - 'inputs': [], - 'outputs': [df_string_output] - }, - { - 'button': transcript_update_button, - 'action': update_LLM_content, - 'inputs': [video_id, df_string_output, transcript_kind], - 'outputs': [df_string_output] - }, - # Reading passage actions - { - 'button': reading_passage_get_button, - 'action': get_LLM_content, - 'inputs': [video_id, reading_passage_kind], - 'outputs': [reading_passage_text] - }, - { - 'button': reading_passage_create_button, - 'action': create_LLM_content, - 'inputs': [video_id, df_string_output, reading_passage_kind, LLM_model], - 'outputs': [reading_passage_text] - }, - { - 'button': reading_passage_delete_button, - 'action': delete_LLM_content, - 'inputs': [video_id, reading_passage_kind], - 'outputs': [reading_passage_text] - }, - { - 'button': reading_passage_edit_button, - 'action': enable_edit_mode, - 'inputs': [], - 'outputs': [reading_passage_text] - }, - { - 'button': reading_passage_update_button, - 'action': update_LLM_content, - 'inputs': [video_id, reading_passage_text, reading_passage_kind], - 'outputs': [reading_passage_text] - }, - # Summary actions - { - 'button': summary_get_button, - 'action': get_LLM_content, - 'inputs': [video_id, summary_kind], - 'outputs': [summary_text] - }, - { - 'button': summary_create_button, - 'action': create_LLM_content, - 'inputs': [video_id, df_string_output, summary_kind, LLM_model], - 'outputs': [summary_text] - }, - { - 'button': summary_delete_button, - 'action': delete_LLM_content, - 'inputs': [video_id, summary_kind], - 'outputs': [summary_text] - }, - { - 'button': summary_edit_button, - 'action': enable_edit_mode, - 'inputs': [], - 'outputs': [summary_text] - }, - { - 'button': summary_update_button, - 'action': update_LLM_content, - 'inputs': [video_id, summary_text, summary_kind], - 'outputs': [summary_text] - }, - # Key moments actions - { - 'button': key_moments_get_button, - 'action': get_LLM_content, - 'inputs': [video_id, key_moments_kind], - 'outputs': [key_moments] - }, - { - 'button': key_moments_create_button, - 'action': create_LLM_content, - 'inputs': [video_id, df_string_output, key_moments_kind, LLM_model], - 'outputs': [key_moments] - }, - { - 'button': key_moments_delete_button, - 'action': delete_LLM_content, - 'inputs': [video_id, key_moments_kind], - 'outputs': [key_moments] - }, - { - 'button': key_moments_edit_button, - 'action': enable_edit_mode, - 'inputs': [], - 'outputs': [key_moments] - }, - { - 'button': key_moments_update_button, - 'action': update_LLM_content, - 'inputs': [video_id, key_moments, key_moments_kind], - 'outputs': [key_moments] - }, - # Questions actions - { - 'button': questions_get_button, - 'action': get_LLM_content, - 'inputs': [video_id, questions_kind], - 'outputs': [questions_json] - }, - { - 'button': questions_create_button, - 'action': create_LLM_content, - 'inputs': [video_id, df_string_output, questions_kind, LLM_model], - 'outputs': [questions_json] - }, - { - 'button': questions_delete_button, - 'action': delete_LLM_content, - 'inputs': [video_id, questions_kind], - 'outputs': [questions_json] - }, - { - 'button': questions_edit_button, - 'action': enable_edit_mode, - 'inputs': [], - 'outputs': [questions_json] - }, - { - 'button': questions_update_button, - 'action': update_LLM_content, - 'inputs': [video_id, questions_json, questions_kind], - 'outputs': [questions_json] - }, - # Questions answers actions - { - 'button': questions_answers_get_button, - 'action': get_LLM_content, - 'inputs': [video_id, questions_answers_kind], - 'outputs': [questions_answers_json] - }, - { - 'button': questions_answers_create_button, - 'action': create_LLM_content, - 'inputs': [video_id, df_string_output, questions_answers_kind, LLM_model], - 'outputs': [questions_answers_json] - }, - { - 'button': questions_answers_delete_button, - 'action': delete_LLM_content, - 'inputs': [video_id, questions_answers_kind], - 'outputs': [questions_answers_json] - }, - { - 'button': questions_answers_edit_button, - 'action': enable_edit_mode, - 'inputs': [], - 'outputs': [questions_answers_json] - }, - { - 'button': questions_answers_update_button, - 'action': update_LLM_content, - 'inputs': [video_id, questions_answers_json, questions_answers_kind], - 'outputs': [questions_answers_json] - }, - # Worksheet actions - { - 'button': worksheet_get_button, - 'action': get_LLM_content, - 'inputs': [video_id, worksheet_kind], - 'outputs': [worksheet_json] - }, - { - 'button': worksheet_create_button, - 'action': create_LLM_content, - 'inputs': [video_id, df_string_output, worksheet_kind, LLM_model], - 'outputs': [worksheet_json] - }, - { - 'button': worksheet_delete_button, - 'action': delete_LLM_content, - 'inputs': [video_id, worksheet_kind], - 'outputs': [worksheet_json] - }, - { - 'button': worksheet_edit_button, - 'action': enable_edit_mode, - 'inputs': [], - 'outputs': [worksheet_json] - }, - { - 'button': worksheet_update_button, - 'action': update_LLM_content, - 'inputs': [video_id, worksheet_json, worksheet_kind], - 'outputs': [worksheet_json] - }, - ] - setup_content_buttons(content_buttons_config) - - # --- Education Material --- - def setup_education_buttons(buttons_config): - for config in buttons_config: - button = config["button"] - action = config["action"] - inputs = config["inputs"] - outputs = config["outputs"] - button.click( - fn=action, - inputs=inputs, - outputs=outputs - ) - education_buttons_config = [ - # 學習單相關按鈕 - { - "button": worksheet_content_btn, - "action": get_ai_content, - "inputs": [password, user_data, video_id, df_string_output, content_subject, content_grade, content_level, worksheet_algorithm, worksheet_content_type_name], - "outputs": [worksheet_result_original, worksheet_result, worksheet_prompt, worksheet_result_prompt] - }, - { - "button": worksheet_result_fine_tune_btn, - "action": generate_ai_content_fine_tune_result, - "inputs": [password, user_data, worksheet_result_prompt, df_string_output, worksheet_result, worksheet_result_fine_tune_prompt, worksheet_content_type_name], - "outputs": [worksheet_result] - }, - { - "button": worksheet_download_button, - "action": download_exam_result, - "inputs": [worksheet_result], - "outputs": [worksheet_result_word_link] - }, - { - "button": worksheet_result_retrun_original, - "action": return_original_exam_result, - "inputs": [worksheet_result_original], - "outputs": [worksheet_result] - }, - # 教案相關按鈕 - { - "button": lesson_plan_btn, - "action": get_ai_content, - "inputs": [password, user_data, video_id, df_string_output, content_subject, content_grade, content_level, lesson_plan_time, lesson_plan_content_type_name], - "outputs": [lesson_plan_result_original, lesson_plan_result, lesson_plan_prompt, lesson_plan_result_prompt] - }, - { - "button": lesson_plan_result_fine_tune_btn, - "action": generate_ai_content_fine_tune_result, - "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], - "outputs": [lesson_plan_result] - }, - { - "button": lesson_plan_download_button, - "action": download_exam_result, - "inputs": [lesson_plan_result], - "outputs": [lesson_plan_result_word_link] - }, - { - "button": lesson_plan_result_retrun_original, - "action": return_original_exam_result, - "inputs": [lesson_plan_result_original], - "outputs": [lesson_plan_result] - }, - # 出場券相關按鈕 - { - "button": exit_ticket_btn, - "action": get_ai_content, - "inputs": [password, user_data, video_id, df_string_output, content_subject, content_grade, content_level, exit_ticket_time, exit_ticket_content_type_name], - "outputs": [exit_ticket_result_original, exit_ticket_result, exit_ticket_prompt, exit_ticket_result_prompt] - }, - { - "button": exit_ticket_result_fine_tune_btn, - "action": generate_ai_content_fine_tune_result, - "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], - "outputs": [exit_ticket_result] - }, - { - "button": exit_ticket_download_button, - "action": download_exam_result, - "inputs": [exit_ticket_result], - "outputs": [exit_ticket_result_word_link] - }, - { - "button": exit_ticket_result_retrun_original, - "action": return_original_exam_result, - "inputs": [exit_ticket_result_original], - "outputs": [exit_ticket_result] - } - ] - setup_education_buttons(education_buttons_config) - - # init_params - init_outputs = [ - admin, - reading_passage_admin, - summary_admmin, - see_details, - worksheet_accordion, - lesson_plan_accordion, - exit_ticket_accordion, - password, - youtube_link, - block_ready_flag, - chatbot_open_ai_streaming, - chatbot_ai, - ai_chatbot_params, - is_env_prod, - ] - demo.load( - init_params, - inputs =[youtube_link], - outputs = init_outputs - ) - -demo.launch(allowed_paths=["videos"], server_name="0.0.0.0", server_port=7860, show_error=True) \ No newline at end of file + app = create_app() + uvicorn.run(app, host="0.0.0.0", port=7860) \ No newline at end of file