import gradio as gr import time import openai from pathlib import Path import os OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") MAX_WITHOUT_KEY = 30 MAX_HISTORY_LENGTH = 10 PROMPTS = { "具體範例 Concrete examples": "你是一個樂於助人的AI tutor。你會透過提供具體範例以幫助他們學習新的概念。你總是調整你的範例以符合學生的生活及prior knowledge,你會舉出很多跟舉體且生活相關的範例以幫助學生,並透過一問一答的方式,確認學生的理解程度,請跟我解釋 {}?", "闡述 elaboration": "你是一個樂於助人的AI tutor。你會透過不斷提問的方式以幫助學生學習新的概念。你會問像是為什麼你認為這是對的?如果....會怎樣?這個為什麼有道理?A跟B之間有什麼關係呢?為什麼? 透過問問題的方式幫助學生在腦中思考並且組織答案,你總是調整你的問題以符合學生的程度及理解,你一次只問一個問題,請向我提問關於 {}?", "雙重編碼 Dual-Coding": "你是一個樂於助人的AI tutor。你會透過跟我協作製作心智圖的方式以幫我學習新的概念。 你透過問問題的方式幫助學生在腦中思考並且組織答案,你總是調整你的問題以符合學生的程度及理解,並協助學生將討論的結果輸出成心智圖,你一次只問一個問題,請向我提問關於{}?", "提取練習 Retrieval Practice": "你是一個樂於助人的AI tutor。你會透過不斷提問的方式以確認我對這個主題的理解程度。 你會根據以下的文本資料生成題目,你總是調整你的問題以符合學生的程度及理解,你最多只會問3個問題,一次只問一個問題,並在問完問題後給予學生回饋,分析學生還沒理解的部分,告訴學生如何加強。並將問答的歷程會出成kahoot可用的xlsx檔格式,主題是: {}?", "筆記 Note-taking": "你是一個樂於助人的AI tutor,也是Cornell Note-taking method專家。首先,你會察看我關於{}的筆記,然後透過以下的方式加深我對筆記中涵蓋的核心概念的理解: 1.辨識並解釋我遺漏的任何核心概念 2.提供每個概念可用的具體範例。 3.比較和比對所有核心概念。 4.請幫助我連接<之前學過類似的概念>與筆記中所有的核心概念, 如果你明白,請讓我知道,並請我提交筆記內容", "交錯練習 Interleaving": "你是一個樂於助人的AI tutor,你會透過不斷提問的方式以確認我對這個主題的理解程度,請你透過 interleaving 策略,混合相關的觀念與知識,以幫助我以幫助我更理解及促進不同概念間的連結,你一次只問一個問題,你會先從prior knowledge開始你的問題,請向我提問關於 {} 的問題 " } def transcribe(audio, chatbot_history, openai_key): time.sleep(5) transcript = openai.Audio.transcribe("whisper-1", open(audio, "rb"), api_key=openai_key) content = transcript["text"] if content: if not chatbot_history: return [[content, None]] else: return chatbot_history + [[content, None]] else: return chatbot_history def handle_scenario(topic, scenario, chatbot_history=[]): scenario_name = """【{}】""".format(scenario) prompt = scenario_name + PROMPTS[scenario].format(topic) new_message = [prompt, None] output = chatbot_history + [new_message] # print(output) # Debugging: Print the output format. return output def openai_stream(history, openai_key, chat_model): use_key = bool(openai_key.strip()) if not history or history[-1][1]: return history if not use_key and len(history) >= MAX_WITHOUT_KEY: history[-1][1] = "Sorry, you've reached the maximum number of messages without an OpenAI key." return history history[-1][1] = "" system_instruction = {"role": "system", "content": "You are a helpful AI tutor. Always communicate in Traditional Chinese. zh-TW,並且在反問時,不直接提供答案"} # Transforming history into the format required by OpenAI API messages = [system_instruction] + [{"role": "user", "content": msg[0]} if not msg[1] else {"role": "assistant", "content": msg[1]} for msg in history[:-1]] messages.append({"role": "user", "content": history[-1][0]}) for chunk in openai.ChatCompletion.create( model=chat_model, messages=messages, stream=True, api_key=openai_key if use_key else None, ): content = chunk["choices"][0].get("delta", {}).get("content") if content: history[-1][1] += content history = history[-MAX_HISTORY_LENGTH:] yield history def show_message(user_message, chatbot_history): if not chatbot_history: chatbot_history = [] # initialize if None result = chatbot_history + [[user_message, None]] return "", result theme = gr.themes.Soft( primary_hue="blue", neutral_hue="slate", ) parent_path = Path(__file__).parent with open(parent_path / "header.MD") as fp: header = fp.read() available_models = ['gpt-4','gpt-3.5-turbo'] with gr.Blocks(theme=theme) as demo: header_component = gr.Markdown(header) with gr.Row(): chat_model = gr.Dropdown(choices=available_models, value="gpt-3.5-turbo", allow_custom_value=True) openai_key = gr.Textbox(label="Enter OPENAI API Key", placeholder="Example: sk-AJDKakdAJD...") with gr.Row(): with gr.Column(scale=2): topic_input = gr.Textbox(label="主題", placeholder="輸入主題...") with gr.Column(scale=1): # audio = gr.Audio(label="Talk with ChatGPT", source="microphone", type="filepath", streaming=True) clear = gr.Button("Clear Chat History") dark_mode_btn = gr.Button("Dark Mode", variant="primary") with gr.Row(): with gr.Column(scale=2): chatbot = gr.Chatbot(label="ChatGPT Dialog") msg = gr.Textbox(label="Chat with ChatGPT", placeholder="Press to submit") with gr.Column(scale=1): gr.Markdown("## 學習策略 Learning Strategies") # Define streaming_event_kwargs after the required input components have been defined streaming_event_kwargs = dict( fn=openai_stream, inputs=[chatbot, openai_key, chat_model], outputs=chatbot, ) btn_style = { "background-color": "#FFDAB9", # Light orange background (Peach Puff) "color": "black", # Black text "padding": "10px 15px", # Padding "border": "none", # No border "cursor": "pointer", # Cursor changes on hover "border-radius": "4px", # Rounded corners "margin": "5px", # Margin between buttons } for scenario in PROMPTS.keys(): btn = gr.Button(scenario, style=btn_style) btn.click(lambda topic, chatbot_history, current_scenario=scenario: handle_scenario(topic, current_scenario, chatbot_history), [topic_input, chatbot], [chatbot], queue=False).then(**streaming_event_kwargs) msg.submit(show_message, [msg, chatbot], [msg, chatbot], queue=False).then( **streaming_event_kwargs ) # audio.stream(transcribe, inputs=[audio, chatbot, openai_key], outputs=[chatbot]).then( # **streaming_event_kwargs # ) clear.click(lambda: None, None, chatbot, queue=False) # from gradio.themes.builder toggle_dark_mode_args = dict( fn=None, inputs=None, outputs=None, _js="""() => { if (document.querySelectorAll('.dark').length) { document.querySelectorAll('.dark').forEach(el => el.classList.remove('dark')); } else { document.querySelector('body').classList.add('dark'); } }""", ) demo.load(**toggle_dark_mode_args) dark_mode_btn.click(**toggle_dark_mode_args) demo.queue() demo.launch()