youngtsai commited on
Commit
0fd27d8
·
1 Parent(s): ae82ba8
Files changed (1) hide show
  1. app.py +253 -13
app.py CHANGED
@@ -7,6 +7,10 @@ import os
7
  METABASE_USERNAME = os.getenv('METABASE_USERNAME')
8
  METABASE_PASSWORD = os.getenv('METABASE_PASSWORD')
9
 
 
 
 
 
10
  def query_metabase(username, password, class_code, card_id, user_id):
11
  try:
12
  # 获取会话令牌
@@ -59,16 +63,252 @@ def query_metabase(username, password, class_code, card_id, user_id):
59
  print(f"Error: {str(e)}")
60
  return {"error": str(e)}
61
 
62
- iface = gr.Interface(
63
- fn=query_metabase,
64
- inputs=[
65
- gr.Textbox(label="Metabase Username", value=METABASE_USERNAME),
66
- gr.Textbox(label="Metabase Password", type="password", value=METABASE_PASSWORD),
67
- gr.Textbox(label="Class Code", value="class2"),
68
- gr.Textbox(label="Card ID", value="6267"),
69
- gr.Textbox(label="User ID", value="stu26")
70
- ],
71
- outputs="json"
72
- )
73
-
74
- iface.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  METABASE_USERNAME = os.getenv('METABASE_USERNAME')
8
  METABASE_PASSWORD = os.getenv('METABASE_PASSWORD')
9
 
10
+
11
+
12
+
13
+
14
  def query_metabase(username, password, class_code, card_id, user_id):
15
  try:
16
  # 获取会话令牌
 
63
  print(f"Error: {str(e)}")
64
  return {"error": str(e)}
65
 
66
+ with gr.Blocks() as app:
67
+ gr.Markdown("# Metabase Query and Visualization")
68
+
69
+ with gr.Row():
70
+ username = gr.Textbox(label="Metabase Username", value=METABASE_USERNAME)
71
+ password = gr.Textbox(label="Metabase Password", type="password", value=METABASE_PASSWORD)
72
+
73
+ with gr.Row():
74
+ class_code = gr.Textbox(label="Class Code", value="class2")
75
+ card_id = gr.Textbox(label="Card ID", value="6267")
76
+ user_id = gr.Textbox(label="User ID", value="stu26")
77
+
78
+ result = gr.JSON(label="Query Result")
79
+
80
+ query_button = gr.Button("Fetch Data")
81
+
82
+ def update_graph(data):
83
+ script = f"""
84
+ <script>
85
+ document.addEventListener("DOMContentLoaded", function() {{
86
+ var knowledge_graph_json = {{
87
+ "entities": [
88
+ {{
89
+ "label": "Node",
90
+ "title": "jnc-4-05-1-1",
91
+ "name": "真分數、假分數與帶分數的命名及說、讀、聽、寫、做",
92
+ "color": "red",
93
+ "display_name": "jnc-4-05-1-1真分數、假分數與帶分數的命名及說、讀、聽、寫、做"
94
+ }},
95
+ {{
96
+ "label": "Node",
97
+ "title": "jnc-4-05-2-1",
98
+ "name": "假分數與帶分數的互換",
99
+ "color": "orange",
100
+ "display_name": "jnc-4-05-2-1假分數與帶分數的互換"
101
+ }},
102
+ {{
103
+ "label": "Node",
104
+ "title": "jnc-4-05-3-1",
105
+ "name": "同分母分數的大小比較",
106
+ "color": "green",
107
+ "display_name": "jnc-4-05-3-1同分母分數的大小比較"
108
+ }},
109
+ {{
110
+ "label": "Node",
111
+ "title": "jnc-4-05-3-2",
112
+ "name": "同分母分數的加減",
113
+ "color": "red",
114
+ "display_name": "jnc-4-05-3-2同分母分數的加減"
115
+ }},
116
+ {{
117
+ "label": "Node",
118
+ "title": "jnc-4-05-3-3",
119
+ "name": "分數的整數倍",
120
+ "color": "orange",
121
+ "display_name": "jnc-4-05-3-3分數的整數倍"
122
+ }},
123
+ {{
124
+ "label": "Node",
125
+ "title": "jnc-4-06-1-1",
126
+ "name": "認識等值分數",
127
+ "color": "green",
128
+ "display_name": "jnc-4-06-1-1認識等值分數"
129
+ }},
130
+ {{
131
+ "label": "Node",
132
+ "title": "jnc-4-06-1-2",
133
+ "name": "找出等值分數",
134
+ "color": "red",
135
+ "display_name": "jnc-4-06-1-2找出等值分數"
136
+ }},
137
+ {{
138
+ "label": "Node",
139
+ "title": "jnc-4-06-2-1",
140
+ "name": "簡單異分母分數的比較",
141
+ "color": "orange",
142
+ "display_name": "jnc-4-06-2-1簡單異分母分數的比較"
143
+ }},
144
+ {{
145
+ "label": "Node",
146
+ "title": "jnc-4-06-2-2",
147
+ "name": "簡單異分母分數的加減",
148
+ "color": "green",
149
+ "display_name": "jnc-4-06-2-2簡單異分母分數的加減"
150
+ }},
151
+ {{
152
+ "label": "Node",
153
+ "title": "jnc-4-06-3-1",
154
+ "name": "分��與一位小數的互換",
155
+ "color": "red",
156
+ "display_name": "jnc-4-06-3-1分數與一位小數的互換"
157
+ }},
158
+ {{
159
+ "label": "Node",
160
+ "title": "jnc-4-06-3-2",
161
+ "name": "分數與二位小數的互換",
162
+ "color": "orange",
163
+ "display_name": "jnc-4-06-3-2分數與二位小數的互換"
164
+ }},
165
+ {{
166
+ "label": "Node",
167
+ "title": "jnc-4-08-2-1",
168
+ "name": "認識分數數線",
169
+ "color": "green",
170
+ "display_name": "jnc-4-08-2-1認識分數數線"
171
+ }},
172
+ {{
173
+ "label": "Node",
174
+ "title": "jnc-4-08-2-2",
175
+ "name": "數線的整數、分數、小數",
176
+ "color": "red",
177
+ "display_name": "jnc-4-08-2-2數線的整數、分數、小數"
178
+ }}
179
+ ],
180
+ "relations": [
181
+ {{"source": "jnc-4-05-1-1", "target": "jnc-4-05-2-1"}},
182
+ {{"source": "jnc-4-05-1-1", "target": "jnc-4-05-3-1"}},
183
+ {{"source": "jnc-4-05-2-1", "target": "jnc-4-05-3-1"}},
184
+ {{"source": "jnc-4-05-1-1", "target": "jnc-4-05-3-2"}},
185
+ {{"source": "jnc-4-05-2-1", "target": "jnc-4-05-3-2"}},
186
+ {{"source": "jnc-4-05-2-1", "target": "jnc-4-05-3-3"}},
187
+ {{"source": "jnc-4-05-3-2", "target": "jnc-4-05-3-3"}},
188
+ {{"source": "jnc-4-05-1-1", "target": "jnc-4-06-1-1"}},
189
+ {{"source": "jnc-4-06-1-1", "target": "jnc-4-06-1-2"}},
190
+ {{"source": "jnc-4-06-1-1", "target": "jnc-4-06-2-1"}},
191
+ {{"source": "jnc-4-06-1-2", "target": "jnc-4-06-2-1"}},
192
+ {{"source": "jnc-4-06-1-1", "target": "jnc-4-06-2-2"}},
193
+ {{"source": "jnc-4-06-1-2", "target": "jnc-4-06-2-2"}},
194
+ {{"source": "jnc-4-06-3-1", "target": "jnc-4-06-3-2"}},
195
+ {{"source": "jnc-4-05-1-1", "target": "jnc-4-08-2-1"}},
196
+ {{"source": "jnc-4-08-2-1", "target": "jnc-4-08-2-2"}},
197
+ {{"source": "jnc-4-05-1-1", "target": "jnc-4-06-3-1"}}
198
+ ]
199
+ }};
200
+
201
+ var nodes = [];
202
+ var edges = [];
203
+
204
+ for (const index in knowledge_graph_json['entities']) {{
205
+ nodes.push({{
206
+ data: {{ id: knowledge_graph_json['entities'][index]['title'], label: knowledge_graph_json['entities'][index]['label'], name: knowledge_graph_json['entities'][index]['name'], color: knowledge_graph_json['entities'][index]['color'], display_name: knowledge_graph_json['entities'][index]['display_name']
207
+ }}
208
+ }});
209
+ }}
210
+
211
+ for (const index in knowledge_graph_json['relations']) {{
212
+ edges.push({{
213
+ data: {{
214
+ id: index,
215
+ source: knowledge_graph_json['relations'][index]['source'],
216
+ target: knowledge_graph_json['relations'][index]['target']
217
+ }}
218
+ }});
219
+ }}
220
+
221
+ var cy = cytoscape({{
222
+ container: document.getElementById('cy'),
223
+ elements: {{
224
+ nodes: nodes,
225
+ edges: edges
226
+ }},
227
+ style: [
228
+ {{
229
+ selector: 'node',
230
+ style: {{
231
+ "text-valign": "center",
232
+ "text-halign": "center",
233
+ "label": 'data(id)',
234
+ "width": 100,
235
+ "height": 100,
236
+ "background-color": "data(color)",
237
+ "color": "#fff",
238
+ "text-wrap": "wrap",
239
+ "text-max-width": 80
240
+ }}
241
+ }},
242
+ {{
243
+ selector: 'edge',
244
+ style: {{
245
+ 'width': 4,
246
+ 'line-color': 'white',
247
+ 'target-arrow-color': 'white',
248
+ 'target-arrow-shape': 'triangle',
249
+ 'curve-style': 'bezier'
250
+ }}
251
+ }}
252
+ ]
253
+ }});
254
+
255
+ cy.layout({{
256
+ name: 'breadthfirst',
257
+ directed: true,
258
+ padding: 10
259
+ }}).run();
260
+
261
+ // Hover and click event handlers for nodes
262
+ cy.nodes().on('mouseover', function(event) {{
263
+ var node = event.target;
264
+ node.addClass('highlight'); // 高亮顯示節點本身
265
+ document.getElementById(node.data('id')).classList.add('highlight');
266
+ }});
267
+
268
+ cy.nodes().on('mouseout', function(event) {{
269
+ var node = event.target;
270
+ node.removeClass('highlight'); // 移除節點本身的高亮顯示
271
+ document.getElementById(node.data('id')).classList.remove('highlight');
272
+ }});
273
+
274
+ // Hover and click event handlers for right side points
275
+ document.querySelectorAll('.point').forEach(function(point) {{
276
+ point.addEventListener('mouseover', function() {{
277
+ var id = this.id;
278
+ var node = cy.getElementById(id);
279
+ node.addClass('highlight');
280
+ }});
281
+
282
+ point.addEventListener('mouseout', function() {{
283
+ var id = this.id;
284
+ var node = cy.getElementById(id);
285
+ node.removeClass('highlight');
286
+ }});
287
+ }});
288
+
289
+ // Style for highlighted nodes
290
+ cy.style().selector('.highlight').style({{
291
+ 'border-width': '10px',
292
+ 'border-color': '#FFD700'
293
+ }}).update();
294
+ }});
295
+ </script>
296
+ """
297
+ return script
298
+
299
+ query_button.click(
300
+ fn=query_metabase,
301
+ inputs=[username, password, class_code, card_id, user_id],
302
+ outputs=result
303
+ )
304
+
305
+ graph_html = gr.HTML()
306
+ graph_html.value = update_graph(None)
307
+
308
+ result.change(
309
+ fn=update_graph,
310
+ inputs=result,
311
+ outputs=graph_html
312
+ )
313
+
314
+ app.launch()