youngtsai commited on
Commit
e9e2b32
·
1 Parent(s): 309c78e

with gr.Tab("老師|作業列表") as assignment_list_tab:

Browse files
Files changed (4) hide show
  1. app.py +29 -6
  2. assignment_service.py +38 -4
  3. assignment_ui.py +180 -0
  4. submission_service.py +14 -2
app.py CHANGED
@@ -15,7 +15,11 @@ import urllib.parse
15
  import pandas as pd
16
  import re
17
 
 
18
  from storage_service import GoogleCloudStorage
 
 
 
19
 
20
  is_env_local = os.getenv("IS_ENV_LOCAL", "false") == "true"
21
  print(f"is_env_local: {is_env_local}")
@@ -1353,6 +1357,9 @@ def init_params(request: gr.Request):
1353
  admin_group = gr.update(visible=False)
1354
  english_group = gr.update(visible=True)
1355
  chinese_group = gr.update(visible=True)
 
 
 
1356
 
1357
  # check if origin is from junyiacademy
1358
  query_params = dict(request.query_params)
@@ -1372,19 +1379,27 @@ def init_params(request: gr.Request):
1372
  # admin_group visible in local
1373
  if is_env_local:
1374
  admin_group = gr.update(visible=True)
 
1375
 
1376
  # session timestamp 用 2024-01-01-12-00-00 格式, 要用 UTC+8 時間
1377
  session_timestamp = datetime.now(pytz.utc).astimezone(pytz.timezone('Asia/Taipei')).strftime("%Y-%m-%d-%H-%M-%S")
1378
 
1379
- if "language" in query_params:
1380
- if query_params["language"] == "english":
1381
  print(f"language: english")
1382
  english_group = gr.update(visible=True)
1383
  chinese_group = gr.update(visible=False)
1384
- elif query_params["language"] == "chinese":
 
 
1385
  print(f"language: chinese")
1386
  english_group = gr.update(visible=False)
1387
  chinese_group = gr.update(visible=True)
 
 
 
 
 
 
1388
 
1389
  assignment_id_value = None
1390
  assignment_json_value = None
@@ -1417,10 +1432,11 @@ def init_params(request: gr.Request):
1417
  assignment_id_input = gr.update(value=None)
1418
  assignment_json = gr.update(value=None)
1419
 
1420
- return admin_group, session_timestamp, request_origin, \
 
1421
  assignment_id_input, assignment_json, \
1422
  chinese_assignment_row, chinese_assignment_grade, chinese_assignment_topic, chinese_assignment_introduction, chinese_assignment_description, \
1423
- english_group, chinese_group
1424
 
1425
  CSS = """
1426
  .accordion-prompts {
@@ -3343,10 +3359,16 @@ with gr.Blocks(theme=THEME, css=CSS) as demo:
3343
  outputs=chinese_essay_idea_output
3344
  )
3345
 
 
 
 
 
 
3346
  demo.load(
3347
  init_params,
3348
  inputs =[],
3349
  outputs = [
 
3350
  admin_group,
3351
  session_timestamp,
3352
  request_origin,
@@ -3358,7 +3380,8 @@ with gr.Blocks(theme=THEME, css=CSS) as demo:
3358
  chinese_assignment_introduction,
3359
  chinese_assignment_description,
3360
  english_group,
3361
- chinese_group
 
3362
  ]
3363
  )
3364
 
 
15
  import pandas as pd
16
  import re
17
 
18
+ # From other files
19
  from storage_service import GoogleCloudStorage
20
+ from assignment_ui import create_assignment_ui
21
+ from assignment_service import AssignmentService
22
+ from submission_service import SubmissionService
23
 
24
  is_env_local = os.getenv("IS_ENV_LOCAL", "false") == "true"
25
  print(f"is_env_local: {is_env_local}")
 
1357
  admin_group = gr.update(visible=False)
1358
  english_group = gr.update(visible=True)
1359
  chinese_group = gr.update(visible=True)
1360
+ assignment_tab = gr.update(visible=False)
1361
+
1362
+ user_data = gr.update(value="")
1363
 
1364
  # check if origin is from junyiacademy
1365
  query_params = dict(request.query_params)
 
1379
  # admin_group visible in local
1380
  if is_env_local:
1381
  admin_group = gr.update(visible=True)
1382
+ user_data = gr.update(value="aa")
1383
 
1384
  # session timestamp 用 2024-01-01-12-00-00 格式, 要用 UTC+8 時間
1385
  session_timestamp = datetime.now(pytz.utc).astimezone(pytz.timezone('Asia/Taipei')).strftime("%Y-%m-%d-%H-%M-%S")
1386
 
1387
+ if "language" in query_params and query_params["language"] == "english":
 
1388
  print(f"language: english")
1389
  english_group = gr.update(visible=True)
1390
  chinese_group = gr.update(visible=False)
1391
+ assignment_tab = gr.update(visible=False)
1392
+
1393
+ if "language" in query_params and query_params["language"] == "chinese":
1394
  print(f"language: chinese")
1395
  english_group = gr.update(visible=False)
1396
  chinese_group = gr.update(visible=True)
1397
+ assignment_tab = gr.update(visible=False)
1398
+
1399
+ if "assignment_mode" in query_params and query_params["assignment_mode"] == "true":
1400
+ english_group = gr.update(visible=False)
1401
+ chinese_group = gr.update(visible=False)
1402
+ assignment_tab = gr.update(visible=True)
1403
 
1404
  assignment_id_value = None
1405
  assignment_json_value = None
 
1432
  assignment_id_input = gr.update(value=None)
1433
  assignment_json = gr.update(value=None)
1434
 
1435
+ return user_data, \
1436
+ admin_group, session_timestamp, request_origin, \
1437
  assignment_id_input, assignment_json, \
1438
  chinese_assignment_row, chinese_assignment_grade, chinese_assignment_topic, chinese_assignment_introduction, chinese_assignment_description, \
1439
+ english_group, chinese_group, assignment_tab
1440
 
1441
  CSS = """
1442
  .accordion-prompts {
 
3359
  outputs=chinese_essay_idea_output
3360
  )
3361
 
3362
+ with gr.Tab("作業管理") as assignment_tab:
3363
+ assignment_service = AssignmentService(GCS_SERVICE)
3364
+ submission_service = SubmissionService(GCS_SERVICE)
3365
+ assignment_interface = create_assignment_ui(user_data, assignment_service, submission_service)
3366
+
3367
  demo.load(
3368
  init_params,
3369
  inputs =[],
3370
  outputs = [
3371
+ user_data,
3372
  admin_group,
3373
  session_timestamp,
3374
  request_origin,
 
3380
  chinese_assignment_introduction,
3381
  chinese_assignment_description,
3382
  english_group,
3383
+ chinese_group,
3384
+ assignment_tab
3385
  ]
3386
  )
3387
 
assignment_service.py CHANGED
@@ -1,6 +1,5 @@
1
  import uuid
2
  import json
3
- import datetime
4
  import gradio as gr
5
  from datetime import datetime
6
 
@@ -16,6 +15,21 @@ class AssignmentService:
16
  file_name = f"assignments/{assignment_id}.json"
17
  if not self.gcs_service.check_file_exists(self.bucket_name, file_name):
18
  return assignment_id
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
  def create_assignment(self, user_data, assignment_type, metadata):
21
  assignment_id = self.create_assignment_id()
@@ -55,6 +69,10 @@ class AssignmentService:
55
  print(f"Error: {e}")
56
  return "無效的作業 ID"
57
  return assignment_data
 
 
 
 
58
 
59
  def get_user_assignments(self, user_id):
60
  try:
@@ -68,10 +86,26 @@ class AssignmentService:
68
  def update_assignment_list(self, assigner_data):
69
  choices = []
70
  user_assignments = self.get_user_assignments(assigner_data)
71
- for assignment_id in user_assignments.keys():
72
  assignment_data = self.get_assignment(assignment_id)
73
  metadata = assignment_data.get("metadata", {})
74
- topic = metadata.get("topic", "未命名作业")
75
- choice = (topic, assignment_id)
 
 
 
 
 
 
 
 
76
  choices.append(choice)
 
 
 
 
77
  return gr.update(choices=choices)
 
 
 
 
 
1
  import uuid
2
  import json
 
3
  import gradio as gr
4
  from datetime import datetime
5
 
 
15
  file_name = f"assignments/{assignment_id}.json"
16
  if not self.gcs_service.check_file_exists(self.bucket_name, file_name):
17
  return assignment_id
18
+
19
+ def create_assignment_metadata(self, assignment_type, grade, topic, introduction, description, url, attach_materials, submission_deadline):
20
+ if assignment_type == "中文寫作 AI 批改":
21
+ metadata = {
22
+ "assignment_type": assignment_type,
23
+ "grade": grade,
24
+ "topic": topic,
25
+ "introduction": introduction,
26
+ "description": description,
27
+ "url": url,
28
+ "attach_materials": attach_materials,
29
+ "submission_deadline": submission_deadline
30
+ }
31
+
32
+ return metadata
33
 
34
  def create_assignment(self, user_data, assignment_type, metadata):
35
  assignment_id = self.create_assignment_id()
 
69
  print(f"Error: {e}")
70
  return "無效的作業 ID"
71
  return assignment_data
72
+
73
+ def get_assignment_submissions(self, assignment_id):
74
+ assignment_data = self.get_assignment(assignment_id)
75
+ return assignment_data["submission_ids"]
76
 
77
  def get_user_assignments(self, user_id):
78
  try:
 
86
  def update_assignment_list(self, assigner_data):
87
  choices = []
88
  user_assignments = self.get_user_assignments(assigner_data)
89
+ for assignment_id, assignment_info in user_assignments.items():
90
  assignment_data = self.get_assignment(assignment_id)
91
  metadata = assignment_data.get("metadata", {})
92
+ topic = metadata.get("topic", "未命名作業")
93
+ assignment_type = assignment_data.get("assignment_type", "未知類型")
94
+ timestamp = assignment_data.get("timestamp", "未知日期")
95
+
96
+ # 格式化日期
97
+ date = datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S").strftime("%Y-%m-%d")
98
+
99
+ # 創建格式化的選項
100
+ formatted_choice = f"{date}|{assignment_type}|{topic}"
101
+ choice = (formatted_choice, assignment_id)
102
  choices.append(choice)
103
+
104
+ # 按日期降序排序
105
+ choices.sort(key=lambda x: x[0].split("|")[0], reverse=True)
106
+
107
  return gr.update(choices=choices)
108
+
109
+
110
+
111
+
assignment_ui.py ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+
3
+ def create_assignment_ui(user_data, assignment_service, submission_service):
4
+ with gr.Blocks() as assignment_interface:
5
+ with gr.Tab("老師|建立作業"):
6
+ with gr.Row():
7
+ with gr.Column():
8
+ assignment_type_list = [
9
+ "中文寫作 AI 批改",
10
+ "英文寫作 AI 批改"
11
+ ]
12
+ assignment_type = gr.Radio(choices=assignment_type_list, label="選擇類型")
13
+ grade = gr.Radio(["一年級", "二年級", "三年級", "四年級", "五年級", "六年級"], label="選擇年級")
14
+ topic = gr.Textbox(label="題目")
15
+ introduction = gr.Textbox(label="寫作引文(非必填)")
16
+ description = gr.Textbox(label="作業說明")
17
+ url = gr.Textbox(label="作業链接")
18
+ attach_materials = gr.Textbox(label="附加材料 (JSON 格式)", placeholder='[{"type": "video", "url": "link1", "description": "描述"}]')
19
+ submission_deadline = gr.Textbox(label="提交截止日期", placeholder="2024-09-01T23:59:59Z")
20
+ create_button = gr.Button("建立作業")
21
+ assignment_id_display_teacher = gr.Textbox(label="作業 ID", interactive=False)
22
+ assignment_metadata = gr.JSON(label="作業元數據")
23
+
24
+ create_button.click(
25
+ assignment_service.create_assignment_metadata,
26
+ inputs=[assignment_type, grade, topic, introduction, description, url, attach_materials, submission_deadline],
27
+ outputs=[assignment_metadata]
28
+ ).then(
29
+ assignment_service.create_assignment,
30
+ inputs=[user_data, assignment_type, assignment_metadata],
31
+ outputs=[assignment_id_display_teacher]
32
+ )
33
+
34
+ with gr.Tab("老師|作業列表") as assignment_list_tab:
35
+ with gr.Row():
36
+ with gr.Column(scale=1):
37
+ get_all_assignments_button = gr.Button("獲取所有作業")
38
+ assignment_list = gr.Radio([], label="作業列表", interactive=True)
39
+ with gr.Column(scale=2):
40
+ assignment_data = gr.JSON(label="作業內容", visible=False)
41
+ assignment_data_markdown = gr.Markdown(label="作業內容", show_label=True)
42
+ with gr.Row():
43
+ with gr.Column(scale=1):
44
+ submissions_list_json = gr.JSON(visible=False)
45
+ submissions_list_radio = gr.Radio([], label="已提交的作業學生", interactive=True)
46
+ with gr.Column(scale=2):
47
+ submission_data_json = gr.JSON(label="提交內容", visible=False)
48
+ submission_data_markdown = gr.Markdown(label="提交內容")
49
+
50
+ def init_assignment_list_data(assignment_list_value=None):
51
+ assignment_list = gr.update(value=assignment_list_value)
52
+ assignment_data = gr.update(value=None)
53
+ assignment_data_markdown = gr.update(value=None)
54
+ submissions_list_json = gr.update(value=None)
55
+ submissions_list_radio = gr.update(choices=[], value=None)
56
+ submission_data_json = gr.update(value=None)
57
+ submission_data_markdown = gr.update(value=None)
58
+ return assignment_list, assignment_data, assignment_data_markdown, submissions_list_json, submissions_list_radio, submission_data_json, submission_data_markdown
59
+
60
+ def update_assignment_data_markdown(assignment_data):
61
+ markdown_value = f"""
62
+ ### 作業類型: {assignment_data['assignment_type']}
63
+ ### 作業年級: {assignment_data['metadata']['grade']}
64
+ ### 作業題目: {assignment_data['metadata']['topic']}
65
+ ### 日期: {assignment_data['timestamp']}
66
+ ### 作業引文
67
+ {assignment_data['metadata']['introduction']}
68
+ ### 作業說明:
69
+ {assignment_data['metadata']['description']}
70
+ ### 作業連結: {assignment_data['metadata']['url']}
71
+ ### 附加材料:
72
+ {assignment_data['metadata']['attach_materials']}
73
+ """
74
+ return gr.update(value=markdown_value)
75
+
76
+ def update_submissions_list_radio(submission_ids):
77
+ choices = []
78
+ for submission_id in submission_ids:
79
+ submission_data = submission_service.get_submission_from_gcs(submission_id)
80
+ choice_text = f"{submission_data['student_name']}"
81
+ choice = (choice_text, submission_id)
82
+ choices.append(choice)
83
+ return gr.update(choices=choices)
84
+
85
+ def update_submission_data_markdown(submission_json):
86
+ markdown_value = f"""
87
+ ### 提交內容
88
+ {submission_json['submission_data']['content']}
89
+ ### 提交日期
90
+ {submission_json['timestamp']}
91
+ """
92
+ return gr.update(value=markdown_value)
93
+
94
+ get_all_assignments_button.click(
95
+ assignment_service.update_assignment_list,
96
+ inputs=[user_data],
97
+ outputs=assignment_list
98
+ ).then(
99
+ fn=init_assignment_list_data,
100
+ inputs=[],
101
+ outputs=[assignment_list, assignment_data, assignment_data_markdown, submissions_list_json, submissions_list_radio, submission_data_json, submission_data_markdown]
102
+ )
103
+
104
+ assignment_list.select(
105
+ fn=init_assignment_list_data,
106
+ inputs=[assignment_list],
107
+ outputs=[assignment_list, assignment_data, assignment_data_markdown, submissions_list_json, submissions_list_radio, submission_data_json, submission_data_markdown]
108
+ ).then(
109
+ assignment_service.get_assignment,
110
+ inputs=[assignment_list],
111
+ outputs=[assignment_data]
112
+ ).then(
113
+ fn=update_assignment_data_markdown,
114
+ inputs=[assignment_data],
115
+ outputs=[assignment_data_markdown]
116
+ ).then(
117
+ assignment_service.get_assignment_submissions,
118
+ inputs=[assignment_list],
119
+ outputs=[submissions_list_json]
120
+ ).then(
121
+ fn=update_submissions_list_radio,
122
+ inputs=[submissions_list_json],
123
+ outputs=[submissions_list_radio]
124
+ )
125
+
126
+ submissions_list_radio.select(
127
+ submission_service.get_submission_from_gcs,
128
+ inputs=[submissions_list_radio],
129
+ outputs=submission_data_json
130
+ ).then(
131
+ fn=update_submission_data_markdown,
132
+ inputs=[submission_data_json],
133
+ outputs=[submission_data_markdown]
134
+ )
135
+
136
+ with gr.Tab("學生"):
137
+ with gr.Row():
138
+ with gr.Column():
139
+ assignment_id_input_student = gr.Textbox(label="作業 ID")
140
+ get_assignment_button = gr.Button("獲取作業")
141
+ assignment_display = gr.JSON(label="作業內容")
142
+
143
+ get_assignment_button.click(
144
+ assignment_service.get_assignment,
145
+ inputs=[assignment_id_input_student],
146
+ outputs=assignment_display
147
+ )
148
+
149
+ with gr.Row():
150
+ with gr.Column():
151
+ student_name_input = gr.Textbox(label="學生姓名")
152
+ submission_input = gr.Textbox(label="文字輸入")
153
+ submit_button = gr.Button("繳交作業")
154
+ submission_status = gr.Textbox(label="繳交狀態", interactive=False)
155
+
156
+ submit_button.click(
157
+ submission_service.submit_assignment,
158
+ inputs=[assignment_id_input_student, user_data, student_name_input, submission_input],
159
+ outputs=submission_status
160
+ )
161
+
162
+ with gr.Row():
163
+ with gr.Column():
164
+ load_submissions_button = gr.Button("獲取提交的作業")
165
+ submissions_radio = gr.Radio([], label="提交的作業", interactive=True)
166
+ submission_display = gr.JSON(label="作業內容")
167
+
168
+ load_submissions_button.click(
169
+ submission_service.update_submission_list,
170
+ inputs=[user_data],
171
+ outputs=submissions_radio
172
+ )
173
+
174
+ submissions_radio.select(
175
+ submission_service.get_submission_from_gcs,
176
+ inputs=[submissions_radio],
177
+ outputs=submission_display
178
+ )
179
+
180
+ return assignment_interface
submission_service.py CHANGED
@@ -1,6 +1,5 @@
1
  import uuid
2
  import json
3
- import datetime
4
  import gradio as gr
5
  from datetime import datetime
6
 
@@ -36,8 +35,21 @@ class SubmissionService:
36
 
37
  self.save_submission_to_gcs(submission_data)
38
  self.save_user_submissions_to_gcs(student_id, submission_data)
 
39
 
40
  return f"作業已收到,學生ID:{student_id}"
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
  def get_assignment_data(self, assignment_id):
43
  try:
@@ -111,7 +123,7 @@ class SubmissionService:
111
  choices.append(choice)
112
  return gr.update(choices=choices)
113
 
114
- def get_student_submission(self, student_id):
115
  submission_ids = self.list_submissions()
116
  for submission_id in submission_ids:
117
  submission_data = self.get_submission_from_gcs(submission_id)
 
1
  import uuid
2
  import json
 
3
  import gradio as gr
4
  from datetime import datetime
5
 
 
35
 
36
  self.save_submission_to_gcs(submission_data)
37
  self.save_user_submissions_to_gcs(student_id, submission_data)
38
+ self.update_assignment_submission_ids(assignment_id, submission_id)
39
 
40
  return f"作業已收到,學生ID:{student_id}"
41
+
42
+ def update_assignment_submission_ids(self, assignment_id, submission_id):
43
+ try:
44
+ assignment_data = self.get_assignment_data(assignment_id)
45
+ if assignment_data:
46
+ if "submission_ids" not in assignment_data:
47
+ assignment_data["submission_ids"] = []
48
+ assignment_data["submission_ids"].append(submission_id)
49
+ file_name = f"assignments/{assignment_id}.json"
50
+ self.gcs_service.upload_json_string(self.bucket_name, file_name, json.dumps(assignment_data))
51
+ except Exception as e:
52
+ print(f"更新作業提交ID時出錯:{e}")
53
 
54
  def get_assignment_data(self, assignment_id):
55
  try:
 
123
  choices.append(choice)
124
  return gr.update(choices=choices)
125
 
126
+ def get_student_submissions(self, student_id):
127
  submission_ids = self.list_submissions()
128
  for submission_id in submission_ids:
129
  submission_data = self.get_submission_from_gcs(submission_id)