forked from hungchun0201/NTUclassCrawler
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathapp.py
178 lines (145 loc) · 6.31 KB
/
app.py
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
import pandas as pd
import streamlit as st
import streamlit.components.v1 as components
import numpy as np
import re
import argparse
import json
import pathlib
from bs4 import BeautifulSoup
def _hash_st_secrets(secrets) -> int:
"""
An st.cache hash_func to hash st.secrets objects. The hash should change
whenever the underyling secrets object changes.
"""
hash_just_the_secrets = hash(json.dumps(st.secrets._secrets))
return hash_just_the_secrets
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument(
"-l", "--local", help="Deploy your site locally", action="store_true")
return parser.parse_args()
@st.cache(max_entries=10, ttl=3600, hash_funcs={type(st.secrets): _hash_st_secrets})
def read_df(local=False):
if local:
try:
course_df = pd.read_csv('course.csv', index_col=0)
except pd.errors.EmptyDataError:
print('Local course.csv not found, please try `python run_app.py --force` to fetch all data available.')
else:
course_df = pd.read_csv(
st.secrets['db']['url'], index_col=0)
return course_df
def pre_processing(course_df):
course_df['Time'] = course_df.Time.apply(lambda x: x.strip())
course_df['Classroom'] = course_df.Classroom.apply(lambda x: x.strip())
course_df['raw_day'] = course_df['Time'].apply(
lambda x: (re.findall(r'[\u4e00-\u9fff]+', x)))
course_df['Day'] = course_df['raw_day'].apply(
lambda x: ', '.join(x))
# course_df['Period'] = course_df['Time'].apply(
# lambda x: re.findall(r'[^\u4e00-\u9fff]+', x)[0])
course_df['Title'] = course_df.Title.apply(lambda x: x.strip())
# course_df['Period'] = course_df.Period.apply(lambda x: x.strip())
return course_df
def main(local=False):
st.set_page_config(
page_title="Simple NTU Course Viewer",
page_icon="https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/240/twitter/282/books_1f4da.png",
layout="wide",
initial_sidebar_state="expanded",
)
with st.spinner('讀取資料中⋯'): # read data
course_df = read_df(local)
course_df = pre_processing(course_df.copy())
st.write("""
# 台大 110 年課表查詢""")
col1, col2 = st.beta_columns((7, 4))
with col1:
search_txt = st.text_input(
'輸入課程名稱/ID/老師名稱', '')
need_help = st.beta_expander('需要幫忙嗎 👉')
with need_help:
st.markdown(
"""注意:您只能輸入**課程名稱**或是**課程 ID** 或是**老師名稱**。不能夠同時輸入課程名稱和老師名稱。""", unsafe_allow_html=True)
with col2:
valid_column = course_df.drop('raw_day', axis=1).columns
view_options = st.multiselect(
'選擇檢視欄位',
list(valid_column),
list(valid_column))
days = ['一', '二', '三', '四', '五', '六', '日']
# days_select = [False for i in range(7)]
if 'days_select' not in st.session_state:
st.session_state['days_select'] = [False for i in range(7)]
with st.form("date_picker"):
st.write("選擇上課日")
cols = st.beta_columns(7)
for i, col in enumerate(cols):
st.session_state['days_select'][i] = col.checkbox(
days[i])
date_opt = st.radio("篩選條件", ('Subset', 'All Matched'))
# Every form must have a submit button.
submitted = st.form_submit_button("確認")
if submitted:
# st.write(st.session_state['days_select'])
days_select = st.session_state['days_select']
pass
col3, col4 = st.beta_columns((6, 6))
with col3:
other_info = st.beta_expander('其他資訊 🔗')
with other_info:
st.markdown("""一些常用連結:
+ [PTT NTUcourse 看板](https://www.ptt.cc/bbs/NTUcourse/index.html)
+ [Original Repo](https://github.com/hungchun0201/NTUclassCrawler)
+ [台大課程網](https://nol.ntu.edu.tw/nol/guest/index.php)
<span style="font-size: 10px">* 註:僅為小型試用版,故僅用 Streamlit 簡單製作而已。若有不週全的地方,請自行修正 🙌🏾</span>
""", unsafe_allow_html=True)
with col4:
update_info = st.beta_expander('更新消息 👋🏾')
with update_info:
st.info(
"""[UPDATE] (at **2021-07-18**)
分頁表格 is now available at [React-Table Branch](https://share.streamlit.io/icheft/ntuclasscrawler/react-table/app.py)!""")
df = course_df
def in_list(x, date_opt):
if date_opt == 'Subset':
if set(x).issubset(set(np.array(days)[st.session_state['days_select']])):
return True
else:
return False
else:
if set(x) == set(np.array(days)[st.session_state['days_select']]):
return True
else:
return False
with st.spinner("結果產生中⋯"):
if search_txt == "" and np.sum(st.session_state['days_select']) == 0:
display_df = df[view_options]
else:
if np.sum(st.session_state['days_select']) == 0:
display_df = df[(df['Title'].str.contains(search_txt) | df['Instructor'].str.contains(
search_txt) | df['Id'].str.contains(search_txt))][view_options]
else:
display_df = df[(df['Title'].str.contains(search_txt) | df['Instructor'].str.contains(
search_txt) | df['Id'].str.contains(search_txt)) & course_df['raw_day'].apply(in_list, args=(date_opt,))][view_options]
st.write(
f"<h2>課程搜尋結果 <span style='font-size: 12pt'>({int(display_df.shape[0])}筆結果)</span></h2>", unsafe_allow_html=True)
st.write("""<style>
tr:hover {background-color:#50536b42;
table {
max-width: -moz-fit-content;
max-width: fit-content;
white-space: nowrap;
}
</style>""", unsafe_allow_html=True)
st.write(f"""<div style="overflow:scroll; justify-content: center;">
{display_df.to_html()}
</div>""", unsafe_allow_html=True)
st.balloons()
if __name__ == '__main__':
args = parse_args()
if args.local:
main(local=True)
else:
main()