File size: 8,256 Bytes
11ec56e
 
 
 
272bf64
11ec56e
272bf64
671f063
8ed3ff4
 
11ec56e
53235a0
ed15cb2
 
 
df7475d
1a11184
9684a91
53235a0
 
11ec56e
 
 
 
 
 
 
 
 
 
 
 
 
e06cbc2
475c2b5
8b4a0e6
e06cbc2
 
6defc64
e06cbc2
 
8e98398
 
 
11ec56e
 
 
 
422a4ed
 
 
 
11ec56e
df7475d
fccd578
 
 
5194e18
11ec56e
 
fccd578
11ec56e
422a4ed
11ec56e
 
 
0af21e4
8ed3ff4
11ec56e
 
 
 
5fcd3f4
 
 
e06cbc2
f20c8d1
11ec56e
 
 
 
 
 
 
 
 
 
 
6f8f9ee
11ec56e
 
 
 
 
ddab20c
 
ad5acc0
 
dffef23
 
 
 
 
 
ed15cb2
53575d1
 
 
62dfaa2
 
 
a42be51
6efaff4
d0ff831
 
8e98398
d0ff831
 
6efaff4
07d8380
 
 
 
 
 
 
 
 
53235a0
07d8380
13241e1
 
ad5acc0
11ec56e
 
 
 
e109b5b
 
 
11ec56e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
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 <Enter> 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()