Spaces:
Sleeping
Sleeping
File size: 6,139 Bytes
7cc4611 e89abe5 bee87b9 14738ce 7cc4611 82b89df 7cc4611 14738ce 927a9d4 e89abe5 14738ce 7cc4611 14738ce ec2e83b 14738ce 4f42502 7cc4611 14738ce 7cc4611 14738ce bee87b9 14738ce 7cc4611 14738ce 7cc4611 14738ce 7cc4611 14738ce 7cc4611 14738ce 7cc4611 14738ce 7cc4611 14738ce 7cc4611 14738ce 7cc4611 14738ce 7cc4611 14738ce 7cc4611 |
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 |
import os
os.environ["TRANSFORMERS_CACHE"] = "/tmp/hf_cache"
os.environ["HF_HOME"] = "/tmp/hf_cache"
os.environ["HF_DATASETS_CACHE"] = "/tmp/hf_cache"
import json
import requests
import streamlit as st
from datetime import datetime
from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
# โ
Streamlit ๊ธฐ๋ณธ ์ค์
st.set_page_config(page_title="ํ์ฌ์ผ์ ์บ๋ฆฐ๋", layout="centered")
st.title("๐
ํ์ฌ์ผ์ ์บ๋ฆฐ๋ + AI ์์ฝ")
st.markdown("NEIS API์์ ํ์ฌ์ผ์ ์ ๋ถ๋ฌ์ค๊ณ FullCalendar๋ก ์๊ฐํํฉ๋๋ค.")
# โ
๋๋ฒ๊น
์ฉ ํ ํฐ ํ์ธ
st.write("โ
์บ์ ๊ฒฝ๋ก:", os.environ.get("TRANSFORMERS_CACHE"))
st.write("๐ ํ ํฐ ์์:", os.environ.get("HUGGINGFACE_TOKEN") is not None)
# โ
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" # โ
Hugging Face Spaces์์ ํ์ฉ๋ ๋๋ ํ ๋ฆฌ
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, api_key):
from_ymd = f"{year}0101"
to_ymd = f"{year}1231"
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}"
res = requests.get(url)
data = res.json()
rows = data.get("SchoolSchedule", [{}])[1].get("row", [])
return rows
# โ
AI ์์ฝ ํจ์
def summarize_schedule(rows, school_name, year):
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)
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, api_key)
if not schedule_rows:
st.info("ํด๋น ์กฐ๊ฑด์ ํ์ฌ์ผ์ ์ด ์์ต๋๋ค.")
else:
# ์บ๋ฆฐ๋์ฉ JSON ์์ฑ
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)
# FullCalendar ์ฝ์
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}๋
ํ์ฌ์ผ์ ์์ฝ:**\n\n{summary}")
|