Spaces:
Sleeping
Sleeping
File size: 6,247 Bytes
7cc4611 14738ce 7cc4611 82b89df 7cc4611 14738ce 927a9d4 5236e83 14738ce 7cc4611 14738ce ec2e83b 5236e83 4f42502 7cc4611 14738ce 7cc4611 14738ce 5236e83 bee87b9 5236e83 14738ce 7cc4611 14738ce 7cc4611 14738ce 5236e83 7cc4611 5236e83 7cc4611 5236e83 7cc4611 14738ce 7cc4611 14738ce 7cc4611 5236e83 7cc4611 5236e83 7cc4611 5236e83 7cc4611 5236e83 7cc4611 5236e83 7cc4611 5236e83 |
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 |
import os
import json
import requests
import streamlit as st
from datetime import datetime
from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
# โ
์์ ํ ์บ์ ๊ฒฝ๋ก ์ค์ (์ต์๋จ ํ์)
os.environ["TRANSFORMERS_CACHE"] = "/tmp/hf_cache"
os.environ["HF_HOME"] = "/tmp/hf_cache"
os.environ["HF_DATASETS_CACHE"] = "/tmp/hf_cache"
# โ
Streamlit ๊ธฐ๋ณธ ์ค์
st.set_page_config(page_title="ํ์ฌ์ผ์ ์บ๋ฆฐ๋", layout="centered")
st.title("๐
ํ์ฌ์ผ์ ์บ๋ฆฐ๋ + AI ์์ฝ")
st.markdown("NEIS API์์ ํ์ฌ์ผ์ ์ ๋ถ๋ฌ์ค๊ณ FullCalendar๋ก ์๊ฐํํฉ๋๋ค.")
# โ
๋๋ฒ๊น
์ถ๋ ฅ
token_present = os.environ.get("HUGGINGFACE_TOKEN") is not None
st.write("๐ ํ ํฐ ์์:", token_present)
st.write("โ
์บ์ ๊ฒฝ๋ก:", os.environ.get("TRANSFORMERS_CACHE"))
# โ
Gemma ๋ชจ๋ธ ๋ก๋ฉ ํจ์
@st.cache_resource
def load_model():
token = os.environ.get("HUGGINGFACE_TOKEN")
model_id = "google/gemma-2-2b-it"
cache_dir = "/tmp/hf_cache"
tokenizer = AutoTokenizer.from_pretrained(model_id, use_auth_token=token, cache_dir=cache_dir)
model = AutoModelForCausalLM.from_pretrained(model_id, use_auth_token=token, cache_dir=cache_dir)
return pipeline("text-generation", model=model, tokenizer=tokenizer)
llm = load_model()
# โ
ํ๊ต ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
def get_school_info(region_code, school_name, api_key):
url = f"https://open.neis.go.kr/hub/schoolInfo?KEY={api_key}&Type=json&pIndex=1&pSize=1&SCHUL_NM={school_name}&ATPT_OFCDC_SC_CODE={region_code}"
res = requests.get(url)
data = res.json()
school = data.get("schoolInfo", [{}])[1].get("row", [{}])[0]
return school.get("SD_SCHUL_CODE"), school.get("ATPT_OFCDC_SC_CODE")
# โ
ํ์ฌ์ผ์ ๊ฐ์ ธ์ค๊ธฐ
def get_schedule(region_code, school_code, year, month, api_key):
from_ymd = f"{year}{month:02}01"
to_ymd = f"{year}{month:02}31"
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}"
res = requests.get(url)
data = res.json()
rows = data.get("SchoolSchedule", [{}])[1].get("row", [])
return rows
# โ
์์ฝ ์์ฑ
def summarize_schedule(rows, school_name, year):
if not rows:
return "์ผ์ ์ด ์์ด ์์ฝํ ์ ์์ต๋๋ค."
lines = []
for row in rows:
date = row["AA_YMD"]
dt = datetime.strptime(date, "%Y%m%d").strftime("%-m์ %-d์ผ")
event = row["EVENT_NM"]
lines.append(f"{dt}: {event}")
text = "\n".join(lines)
prompt = f"{school_name}๊ฐ {year}๋
๋์ ๊ฐ์ง๋ ํ์ฌ์ผ์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:\n{text}\n์ฃผ์ ์ผ์ ์ ์์ฝํด์ฃผ์ธ์."
result = llm([{"role": "user", "content": prompt}])
return result[0]["generated_text"].replace(prompt, "").strip()
# โ
์ง์ญ/ํ๊ต/๋
๋/์ ์ ํ UI
region_options = {
"B10": "์์ธ", "C10": "๋ถ์ฐ", "D10": "๋๊ตฌ", "E10": "์ธ์ฒ", "F10": "๊ด์ฃผ", "G10": "๋์ ",
"H10": "์ธ์ฐ", "I10": "์ธ์ข
", "J10": "๊ฒฝ๊ธฐ", "K10": "๊ฐ์", "M10": "์ถฉ๋ถ", "N10": "์ถฉ๋จ",
"P10": "์ ๋ถ", "Q10": "์ ๋จ", "R10": "๊ฒฝ๋ถ", "S10": "๊ฒฝ๋จ", "T10": "์ ์ฃผ"
}
with st.form("query_form"):
region = st.selectbox("์ง์ญ ๊ต์ก์ฒญ", options=list(region_options.keys()), format_func=lambda x: f"{region_options[x]} ({x})")
school_name = st.text_input("ํ๊ต๋ช
", placeholder="์: ์๋ฆฌ์ด๋ฑํ๊ต")
year = st.selectbox("๋
๋", options=[2022, 2023, 2024, 2025], index=2)
month = st.selectbox("์", options=list(range(1, 13)), index=6)
submitted = st.form_submit_button("๐
ํ์ฌ์ผ์ ๋ถ๋ฌ์ค๊ธฐ")
if submitted:
with st.spinner("์ผ์ ๋ถ๋ฌ์ค๋ ์ค..."):
api_key = os.environ.get("NEIS_API_KEY", "a69e08342c8947b4a52cd72789a5ecaf")
school_code, region_code = get_school_info(region, school_name, api_key)
if not school_code:
st.error("ํ๊ต ์ ๋ณด๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.")
else:
schedule_rows = get_schedule(region_code, school_code, year, month, api_key)
if not schedule_rows:
st.info("ํด๋น ์กฐ๊ฑด์ ํ์ฌ์ผ์ ์ด ์์ต๋๋ค.")
else:
# โ
์ผ์ ์ถ๋ ฅ์ฉ FullCalendar ์์ฑ
events = [
{
"title": row["EVENT_NM"],
"start": datetime.strptime(row["AA_YMD"], "%Y%m%d").strftime("%Y-%m-%d")
}
for row in schedule_rows
]
event_json = json.dumps(events, ensure_ascii=False)
st.components.v1.html(f"""
<html>
<head>
<link href='https://cdn.jsdelivr.net/npm/[email protected]/index.global.min.css' rel='stylesheet' />
<script src='https://cdn.jsdelivr.net/npm/[email protected]/index.global.min.js'></script>
<script>
document.addEventListener('DOMContentLoaded', function() {{
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {{
initialView: 'dayGridMonth',
locale: 'ko',
height: 600,
events: {event_json}
}});
calendar.render();
}});
</script>
</head>
<body>
<div id='calendar'></div>
</body>
</html>
""", height=650)
# โ
์์ฝ ์์ฑ ๋ฒํผ ์ถ๊ฐ
with st.expander("โจ 1๋
์น ์์ฝ ๋ณด๊ธฐ", expanded=False):
if st.button("๐ค ์์ฝ ์์ฑํ๊ธฐ"):
with st.spinner("Gemma ๋ชจ๋ธ์ด ์์ฝ ์ค..."):
summary = summarize_schedule(schedule_rows, school_name, year)
st.success("์์ฝ ์๋ฃ!")
st.markdown(f"**{school_name} {year}๋
{month}์ ์ผ์ ์์ฝ:**\n\n{summary}")
|