File size: 9,853 Bytes
44b37dc
198dd89
44b37dc
 
1025cee
44b37dc
 
 
 
 
 
1025cee
44b37dc
 
 
 
 
 
1025cee
44b37dc
1025cee
 
44b37dc
 
 
1025cee
44b37dc
 
 
89ea9bf
1025cee
89ea9bf
44b37dc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1025cee
44b37dc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1025cee
44b37dc
 
 
198dd89
 
1025cee
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44b37dc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1025cee
 
 
 
44b37dc
 
1025cee
44b37dc
 
 
198dd89
 
1025cee
 
 
 
 
 
 
 
 
 
 
 
 
 
44b37dc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1025cee
 
 
 
44b37dc
 
1025cee
44b37dc
 
 
1025cee
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44b37dc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1025cee
 
 
 
44b37dc
 
1025cee
44b37dc
 
 
d259ebe
1025cee
bc59c65
 
1025cee
 
bc59c65
 
 
 
 
d259ebe
 
bc59c65
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d259ebe
bc59c65
 
 
 
 
 
 
 
d259ebe
bc59c65
 
 
 
 
 
d259ebe
bc59c65
 
d259ebe
299460f
1025cee
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
import os
import gradio as gr
from datetime import datetime

# Handle notion-client import
try:
    from notion_client import Client
except ImportError:
    os.system('pip install notion-client')
    from notion_client import Client

# Handle groq import
try:
    from groq import Groq
except ImportError:
    os.system('pip install groq')
    from groq import Groq

# Initialize Groq client
client = Groq(api_key=os.getenv('groq_key'))

# Initialize Notion client
notion = Client(auth=os.getenv('NOTION_API_KEY'))
NOTION_DB_ID = os.getenv('NOTION_DB_ID')

# Define custom CSS first
custom_css = """
.math-container .katex { 
    font-size: 1.1em;
    display: inline-block !important;
    white-space: nowrap !important;
}
.input-box {
    font-size: 1.1em;
}
.output-box {
    font-size: 1.1em;
    line-height: 2;
    min-height: 200px;
    padding: 1em;
    border: 1px solid #e2e8f0;
    border-radius: 8px;
    margin-top: 1em;
}
.title {
    text-align: center;
    font-size: 1.8em;
    margin-bottom: 1em;
    color: #2a4365;
}
#chatbot {
    height: 600px;
    overflow-y: auto;
}
.message {
    padding: 1em;
    margin: 0.5em;
    border-radius: 8px;
    white-space: normal !important;
}
.user-message {
    background-color: #e2e8f0;
}
.bot-message {
    background-color: #edf2f7;
}
.contains-math {
    white-space: normal !important;
}
.math-inline {
    display: inline !important;
    white-space: nowrap !important;
}
.gradio-markdown {
    overflow-wrap: normal !important;
    word-break: keep-all !important;
}
"""

def log_to_notion(name, chinese_term="", user_input="", bot_response=""):
    """Log interaction to Notion database"""
    try:
        notion.pages.create(
            parent={"database_id": NOTION_DB_ID},
            properties={
                "Name": {"title": [{"text": {"content": name}}]},
                "Timestamp": {"date": {"start": datetime.now().isoformat()}},
                "Chinese Term": {"rich_text": [{"text": {"content": chinese_term}}]},
                "User Input": {"rich_text": [{"text": {"content": user_input}}]},
                "Bot Response": {"rich_text": [{"text": {"content": bot_response}}]}
            }
        )
    except Exception as e:
        print(f"Error logging to Notion: {e}")

def translate_to_english(name, word):
    """Generate math-related English translation with bilingual explanation"""
    messages = [
        {
            "role": "system",
            "content": """你是一個數學翻譯專家。請用以下規則提供翻譯:

格式規範:
1. 文字和數學式必須在同一行,不得換行
2. 在需要換行處使用 <br> 標記
3. 所有數學式用 $$...$$ 包覆

示例格式:
對數是指若 $$b^y = x$$,則 $$y$$ 稱為 $$x$$ 以 $$b$$ 為底的對數,記為 $$\log_b x$$。<br>
換底公式為 $$\log_a x = \frac{\log_c x}{\log_c a}$$。

請按此格式提供:
1. 英文翻譯:[列出數學相關的英文翻譯]<br>

2. 中文解釋:[連貫的中文解釋,所有數學式與文字在同一行]<br>

3. English Explanation:[連貫的英文解釋,所有數學式與文字在同一行]<br>

4. 數學使用場景:[數學使用場景說明,公式與文字在同一行]<br>

5. Mathematical Context:[英文場景說明,公式與文字在同一行]"""
        },
        {
            "role": "user",
            "content": f"請提供中文詞彙 '{word}' 在數學上的英文翻譯和詳細解釋。"
        }
    ]

    completion = client.chat.completions.create(
        model="llama-3.3-70b-versatile",
        messages=messages,
        temperature=0.7,
        max_tokens=400,
        stream=False
    )
    response = completion.choices[0].message.content

    # Log to Notion
    log_to_notion(name=name, chinese_term=word, bot_response=response)
    return response

def generate_example(name, word):
    """Generate math-related example sentence for Chinese word"""
    messages = [
        {
            "role": "system",
            "content": """你是一個數學教師。請用以下規則提供例句:

1. 英文例句:[寫出一個數學相關的英文例句]
- 數學公式必須用 $$...$$ 包覆,並與文字在同一行
- 例如:The solution of $$\log_2 x = 3$$ is $$x = 8$$<br>

2. 中文翻譯:[該例句的中文翻譯]
- 保持相同的 LaTeX 數學式格式,確保與文字在同一行
- 例如:方程式 $$\log_2 x = 3$$ 的解為 $$x = 8$$<br>

3. 句子解釋:[用中文解釋這個例句中的數學概念]
- 所有數學符號和公式都需要用 LaTeX 格式,並與文字在同一行
- 例如:因為 $$2^3 = 8$$,所以 $$\log_2 8 = 3$$<br>

4. Sentence Explanation:[用英文重述上述解釋]
- 保持相同的 LaTeX 數學式格式,確保與文字在同一行"""
        },
        {
            "role": "user",
            "content": f"請用中文詞彙 '{word}' 的英文翻譯造一個數學相關的例句。"
        }
    ]

    completion = client.chat.completions.create(
        model="llama-3.3-70b-versatile",
        messages=messages,
        temperature=0.7,
        max_tokens=400,
        stream=False
    )
    response = completion.choices[0].message.content

    # Log to Notion
    log_to_notion(name=name, chinese_term=word, bot_response=response)
    return response

def chat_response(name, message, chat_history):
    """Generate response for chatbot"""
    messages = [
        {
            "role": "system",
            "content": """你是一個高中數學老師,使用的語言是英文。學生用中文問妳任何字彙,你都可以告訴他那個中文對應的英文和例句,以及在數學上的可能用法以及數學例題和解法。

格式要求:
1. 所有數學公式都要用 LaTeX 格式書寫(使用 $$...$$ 符號包覆)
2. 數學式必須與文字在同一行,中間使用 <br> 換行
3. 變數使用 $$x$$, $$y$$, $$a$$, $$b$$ 等格式
4. 運算符號使用 $$+$$, $$-$$, $$\times$$, $$\div$$ 等格式
5. 分數使用 $$\frac{分子}{分母}$$ 格式
6. 示範解題時,每個步驟的說明文字和數學式要在同一行

示例格式:
讓我們來看一道對數方程式:$$\log_2 x = 3$$<br>
解題步驟:<br>
1. 利用指數的定義:$$2^3 = x$$<br>
2. 計算得到:$$x = 8$$<br>
因此,方程式 $$\log_2 x = 3$$ 的解為 $$x = 8$$。"""
        }
    ]

    for msg in chat_history:
        messages.append({"role": "user", "content": msg[0]})
        if msg[1]:
            messages.append({"role": "assistant", "content": msg[1]})

    messages.append({"role": "user", "content": message})

    completion = client.chat.completions.create(
        model="llama-3.3-70b-versatile",
        messages=messages,
        temperature=1,
        max_tokens=1024,
        stream=False
    )
    response = completion.choices[0].message.content

    # Log to Notion
    log_to_notion(name=name, user_input=message, bot_response=response)
    return response

def respond(name, message, history):
    """Process chatbot response and update history"""
    response = chat_response(name, message, history)
    history.append((message, response))
    return "", history

# Create Gradio interface
with gr.Blocks(css=custom_css) as demo:
    gr.Markdown("# 雙語數學詞彙學習系統 | Bilingual Mathematics Learning System", elem_classes=["title"])

    # Add name input at the top
    name_input = gr.Textbox(
        label="請輸入您的名字 | Enter Your Name",
        placeholder="請輸入您的名字... | Please enter your name...",
        lines=1,
        elem_classes=["input-box"]
    )

    with gr.Tab("📚 單字英譯系統"):
        with gr.Row():
            word_input = gr.Textbox(
                label="請輸入中文詞彙 | Enter Chinese Term",
                placeholder="輸入中文詞彙(例如:向量、函數、極限)...",
                lines=1,
                elem_classes=["input-box"]
            )
        
        with gr.Row():
            with gr.Column(scale=1):
                translate_btn = gr.Button("🔄 英譯 | Translate", variant="primary", size="lg")
                translate_output = gr.Markdown(
                    label="英譯結果 | Translation Result",
                    value="英譯結果將在這裡顯示... | Translation results will be displayed here...",
                    elem_classes=["output-box", "math-container", "contains-math", "gradio-markdown"]
                )
            
            with gr.Column(scale=1):
                example_btn = gr.Button("📝 例句 | Example", size="lg")
                example_output = gr.Markdown(
                    label="例句結果 | Example Result",
                    value="例句結果將在這裡顯示... | Example results will be displayed here...",
                    elem_classes=["output-box", "math-container", "contains-math", "gradio-markdown"]
                )

        translate_btn.click(translate_to_english, inputs=[name_input, word_input], outputs=translate_output)
        example_btn.click(generate_example, inputs=[name_input, word_input], outputs=example_output)

    with gr.Tab("💬 數學對話系統"):
        chatbot = gr.Chatbot(
            [],
            elem_id="chatbot",
            bubble_full_width=False,
            avatar_images=("👨‍🎓", "👨‍🏫"),
            elem_classes=["math-container", "contains-math"]
        )

        msg = gr.Textbox(
            label="發送訊息 | Send Message",
            placeholder="請輸入您的問題... | Enter your question...",
            show_label=False,
            elem_classes=["input-box"]
        )

        clear = gr.ClearButton([msg, chatbot], value="🗑️ 清除對話 | Clear Chat")
        msg.submit(respond, [name_input, msg, chatbot], [msg, chatbot])

if __name__ == "__main__":
    demo.launch()