yongyeol commited on
Commit
5236e83
ยท
verified ยท
1 Parent(s): e73ab95

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +23 -31
src/streamlit_app.py CHANGED
@@ -1,43 +1,34 @@
1
  import os
2
- os.environ["TRANSFORMERS_CACHE"] = "/tmp/hf_cache"
3
- os.environ["HF_HOME"] = "/tmp/hf_cache"
4
- os.environ["HF_DATASETS_CACHE"] = "/tmp/hf_cache"
5
  import json
6
  import requests
7
  import streamlit as st
8
  from datetime import datetime
9
  from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
10
 
11
-
 
 
 
12
 
13
  # โœ… Streamlit ๊ธฐ๋ณธ ์„ค์ •
14
  st.set_page_config(page_title="ํ•™์‚ฌ์ผ์ • ์บ˜๋ฆฐ๋”", layout="centered")
15
  st.title("๐Ÿ“… ํ•™์‚ฌ์ผ์ • ์บ˜๋ฆฐ๋” + AI ์š”์•ฝ")
16
  st.markdown("NEIS API์—์„œ ํ•™์‚ฌ์ผ์ •์„ ๋ถˆ๋Ÿฌ์˜ค๊ณ  FullCalendar๋กœ ์‹œ๊ฐํ™”ํ•ฉ๋‹ˆ๋‹ค.")
17
 
18
- # โœ… ๋””๋ฒ„๊น…์šฉ ํ† ํฐ ํ™•์ธ
 
 
19
  st.write("โœ… ์บ์‹œ ๊ฒฝ๋กœ:", os.environ.get("TRANSFORMERS_CACHE"))
20
- st.write("๐Ÿ” ํ† ํฐ ์žˆ์Œ:", os.environ.get("HUGGINGFACE_TOKEN") is not None)
21
 
22
  # โœ… Gemma ๋ชจ๋ธ ๋กœ๋”ฉ ํ•จ์ˆ˜
23
  @st.cache_resource
24
  def load_model():
25
  token = os.environ.get("HUGGINGFACE_TOKEN")
26
  model_id = "google/gemma-2-2b-it"
27
- cache_dir = "/tmp/hf_cache" # โœ… Hugging Face Spaces์—์„œ ํ—ˆ์šฉ๋œ ๋””๋ ‰ํ† ๋ฆฌ
28
-
29
- tokenizer = AutoTokenizer.from_pretrained(
30
- model_id,
31
- use_auth_token=token,
32
- cache_dir=cache_dir
33
- )
34
-
35
- model = AutoModelForCausalLM.from_pretrained(
36
- model_id,
37
- use_auth_token=token,
38
- cache_dir=cache_dir
39
- )
40
 
 
 
41
  return pipeline("text-generation", model=model, tokenizer=tokenizer)
42
 
43
  llm = load_model()
@@ -51,17 +42,19 @@ def get_school_info(region_code, school_name, api_key):
51
  return school.get("SD_SCHUL_CODE"), school.get("ATPT_OFCDC_SC_CODE")
52
 
53
  # โœ… ํ•™์‚ฌ์ผ์ • ๊ฐ€์ ธ์˜ค๊ธฐ
54
- def get_schedule(region_code, school_code, year, api_key):
55
- from_ymd = f"{year}0101"
56
- to_ymd = f"{year}1231"
57
- url = f"https://open.neis.go.kr/hub/SchoolSchedule?KEY={api_key}&Type=json&pIndex=1&pSize=500&ATPT_OFCDC_SC_CODE={region_code}&SD_SCHUL_CODE={school_code}&AA_FROM_YMD={from_ymd}&AA_TO_YMD={to_ymd}"
58
  res = requests.get(url)
59
  data = res.json()
60
  rows = data.get("SchoolSchedule", [{}])[1].get("row", [])
61
  return rows
62
 
63
- # โœ… AI ์š”์•ฝ ํ•จ์ˆ˜
64
  def summarize_schedule(rows, school_name, year):
 
 
65
  lines = []
66
  for row in rows:
67
  date = row["AA_YMD"]
@@ -73,7 +66,7 @@ def summarize_schedule(rows, school_name, year):
73
  result = llm([{"role": "user", "content": prompt}])
74
  return result[0]["generated_text"].replace(prompt, "").strip()
75
 
76
- # โœ… UI: ์ง€์—ญ / ํ•™๊ต / ์—ฐ๋„ ์„ ํƒ
77
  region_options = {
78
  "B10": "์„œ์šธ", "C10": "๋ถ€์‚ฐ", "D10": "๋Œ€๊ตฌ", "E10": "์ธ์ฒœ", "F10": "๊ด‘์ฃผ", "G10": "๋Œ€์ „",
79
  "H10": "์šธ์‚ฐ", "I10": "์„ธ์ข…", "J10": "๊ฒฝ๊ธฐ", "K10": "๊ฐ•์›", "M10": "์ถฉ๋ถ", "N10": "์ถฉ๋‚จ",
@@ -84,9 +77,9 @@ with st.form("query_form"):
84
  region = st.selectbox("์ง€์—ญ ๊ต์œก์ฒญ", options=list(region_options.keys()), format_func=lambda x: f"{region_options[x]} ({x})")
85
  school_name = st.text_input("ํ•™๊ต๋ช…", placeholder="์˜ˆ: ์ƒ๋ฆฌ์ดˆ๋“ฑํ•™๊ต")
86
  year = st.selectbox("๋…„๋„", options=[2022, 2023, 2024, 2025], index=2)
 
87
  submitted = st.form_submit_button("๐Ÿ“… ํ•™์‚ฌ์ผ์ • ๋ถˆ๋Ÿฌ์˜ค๊ธฐ")
88
 
89
- # โœ… ์ œ์ถœ ์‹œ ์ฒ˜๋ฆฌ
90
  if submitted:
91
  with st.spinner("์ผ์ • ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘..."):
92
  api_key = os.environ.get("NEIS_API_KEY", "a69e08342c8947b4a52cd72789a5ecaf")
@@ -94,11 +87,11 @@ if submitted:
94
  if not school_code:
95
  st.error("ํ•™๊ต ์ •๋ณด๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
96
  else:
97
- schedule_rows = get_schedule(region_code, school_code, year, api_key)
98
  if not schedule_rows:
99
  st.info("ํ•ด๋‹น ์กฐ๊ฑด์˜ ํ•™์‚ฌ์ผ์ •์ด ์—†์Šต๋‹ˆ๋‹ค.")
100
  else:
101
- # ์บ˜๋ฆฐ๋”์šฉ JSON ์ƒ์„ฑ
102
  events = [
103
  {
104
  "title": row["EVENT_NM"],
@@ -108,7 +101,6 @@ if submitted:
108
  ]
109
  event_json = json.dumps(events, ensure_ascii=False)
110
 
111
- # FullCalendar ์‚ฝ์ž…
112
  st.components.v1.html(f"""
113
  <html>
114
  <head>
@@ -133,10 +125,10 @@ if submitted:
133
  </html>
134
  """, height=650)
135
 
136
- # ์š”์•ฝ ๋ฒ„ํŠผ
137
  with st.expander("โœจ 1๋…„์น˜ ์š”์•ฝ ๋ณด๊ธฐ", expanded=False):
138
  if st.button("๐Ÿค– ์š”์•ฝ ์ƒ์„ฑํ•˜๊ธฐ"):
139
  with st.spinner("Gemma ๋ชจ๋ธ์ด ์š”์•ฝ ์ค‘..."):
140
  summary = summarize_schedule(schedule_rows, school_name, year)
141
  st.success("์š”์•ฝ ์™„๋ฃŒ!")
142
- st.markdown(f"**{school_name} {year}๋…„ ํ•™์‚ฌ์ผ์ • ์š”์•ฝ:**\n\n{summary}")
 
1
  import os
 
 
 
2
  import json
3
  import requests
4
  import streamlit as st
5
  from datetime import datetime
6
  from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
7
 
8
+ # โœ… ์•ˆ์ „ํ•œ ์บ์‹œ ๊ฒฝ๋กœ ์„ค์ • (์ตœ์ƒ๋‹จ ํ•„์ˆ˜)
9
+ os.environ["TRANSFORMERS_CACHE"] = "/tmp/hf_cache"
10
+ os.environ["HF_HOME"] = "/tmp/hf_cache"
11
+ os.environ["HF_DATASETS_CACHE"] = "/tmp/hf_cache"
12
 
13
  # โœ… Streamlit ๊ธฐ๋ณธ ์„ค์ •
14
  st.set_page_config(page_title="ํ•™์‚ฌ์ผ์ • ์บ˜๋ฆฐ๋”", layout="centered")
15
  st.title("๐Ÿ“… ํ•™์‚ฌ์ผ์ • ์บ˜๋ฆฐ๋” + AI ์š”์•ฝ")
16
  st.markdown("NEIS API์—์„œ ํ•™์‚ฌ์ผ์ •์„ ๋ถˆ๋Ÿฌ์˜ค๊ณ  FullCalendar๋กœ ์‹œ๊ฐํ™”ํ•ฉ๋‹ˆ๋‹ค.")
17
 
18
+ # โœ… ๋””๋ฒ„๊น… ์ถœ๋ ฅ
19
+ token_present = os.environ.get("HUGGINGFACE_TOKEN") is not None
20
+ st.write("๐Ÿ” ํ† ํฐ ์žˆ์Œ:", token_present)
21
  st.write("โœ… ์บ์‹œ ๊ฒฝ๋กœ:", os.environ.get("TRANSFORMERS_CACHE"))
 
22
 
23
  # โœ… Gemma ๋ชจ๋ธ ๋กœ๋”ฉ ํ•จ์ˆ˜
24
  @st.cache_resource
25
  def load_model():
26
  token = os.environ.get("HUGGINGFACE_TOKEN")
27
  model_id = "google/gemma-2-2b-it"
28
+ cache_dir = "/tmp/hf_cache"
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
+ tokenizer = AutoTokenizer.from_pretrained(model_id, use_auth_token=token, cache_dir=cache_dir)
31
+ model = AutoModelForCausalLM.from_pretrained(model_id, use_auth_token=token, cache_dir=cache_dir)
32
  return pipeline("text-generation", model=model, tokenizer=tokenizer)
33
 
34
  llm = load_model()
 
42
  return school.get("SD_SCHUL_CODE"), school.get("ATPT_OFCDC_SC_CODE")
43
 
44
  # โœ… ํ•™์‚ฌ์ผ์ • ๊ฐ€์ ธ์˜ค๊ธฐ
45
+ def get_schedule(region_code, school_code, year, month, api_key):
46
+ from_ymd = f"{year}{month:02}01"
47
+ to_ymd = f"{year}{month:02}31"
48
+ url = f"https://open.neis.go.kr/hub/SchoolSchedule?KEY={api_key}&Type=json&pIndex=1&pSize=100&ATPT_OFCDC_SC_CODE={region_code}&SD_SCHUL_CODE={school_code}&AA_FROM_YMD={from_ymd}&AA_TO_YMD={to_ymd}"
49
  res = requests.get(url)
50
  data = res.json()
51
  rows = data.get("SchoolSchedule", [{}])[1].get("row", [])
52
  return rows
53
 
54
+ # โœ… ์š”์•ฝ ์ƒ์„ฑ
55
  def summarize_schedule(rows, school_name, year):
56
+ if not rows:
57
+ return "์ผ์ •์ด ์—†์–ด ์š”์•ฝํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."
58
  lines = []
59
  for row in rows:
60
  date = row["AA_YMD"]
 
66
  result = llm([{"role": "user", "content": prompt}])
67
  return result[0]["generated_text"].replace(prompt, "").strip()
68
 
69
+ # โœ… ์ง€์—ญ/ํ•™๊ต/๋…„๋„/์›” ์„ ํƒ UI
70
  region_options = {
71
  "B10": "์„œ์šธ", "C10": "๋ถ€์‚ฐ", "D10": "๋Œ€๊ตฌ", "E10": "์ธ์ฒœ", "F10": "๊ด‘์ฃผ", "G10": "๋Œ€์ „",
72
  "H10": "์šธ์‚ฐ", "I10": "์„ธ์ข…", "J10": "๊ฒฝ๊ธฐ", "K10": "๊ฐ•์›", "M10": "์ถฉ๋ถ", "N10": "์ถฉ๋‚จ",
 
77
  region = st.selectbox("์ง€์—ญ ๊ต์œก์ฒญ", options=list(region_options.keys()), format_func=lambda x: f"{region_options[x]} ({x})")
78
  school_name = st.text_input("ํ•™๊ต๋ช…", placeholder="์˜ˆ: ์ƒ๋ฆฌ์ดˆ๋“ฑํ•™๊ต")
79
  year = st.selectbox("๋…„๋„", options=[2022, 2023, 2024, 2025], index=2)
80
+ month = st.selectbox("์›”", options=list(range(1, 13)), index=6)
81
  submitted = st.form_submit_button("๐Ÿ“… ํ•™์‚ฌ์ผ์ • ๋ถˆ๋Ÿฌ์˜ค๊ธฐ")
82
 
 
83
  if submitted:
84
  with st.spinner("์ผ์ • ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘..."):
85
  api_key = os.environ.get("NEIS_API_KEY", "a69e08342c8947b4a52cd72789a5ecaf")
 
87
  if not school_code:
88
  st.error("ํ•™๊ต ์ •๋ณด๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
89
  else:
90
+ schedule_rows = get_schedule(region_code, school_code, year, month, api_key)
91
  if not schedule_rows:
92
  st.info("ํ•ด๋‹น ์กฐ๊ฑด์˜ ํ•™์‚ฌ์ผ์ •์ด ์—†์Šต๋‹ˆ๋‹ค.")
93
  else:
94
+ # โœ… ์ผ์ • ์ถœ๋ ฅ์šฉ FullCalendar ์ƒ์„ฑ
95
  events = [
96
  {
97
  "title": row["EVENT_NM"],
 
101
  ]
102
  event_json = json.dumps(events, ensure_ascii=False)
103
 
 
104
  st.components.v1.html(f"""
105
  <html>
106
  <head>
 
125
  </html>
126
  """, height=650)
127
 
128
+ # โœ… ์š”์•ฝ ์ƒ์„ฑ ๋ฒ„ํŠผ ์ถ”๊ฐ€
129
  with st.expander("โœจ 1๋…„์น˜ ์š”์•ฝ ๋ณด๊ธฐ", expanded=False):
130
  if st.button("๐Ÿค– ์š”์•ฝ ์ƒ์„ฑํ•˜๊ธฐ"):
131
  with st.spinner("Gemma ๋ชจ๋ธ์ด ์š”์•ฝ ์ค‘..."):
132
  summary = summarize_schedule(schedule_rows, school_name, year)
133
  st.success("์š”์•ฝ ์™„๋ฃŒ!")
134
+ st.markdown(f"**{school_name} {year}๋…„ {month}์›” ์ผ์ • ์š”์•ฝ:**\n\n{summary}")