File size: 5,372 Bytes
4b487ce
 
82b89df
4b487ce
 
927a9d4
ec2e83b
82b89df
4b487ce
 
 
e14a8ca
 
 
 
 
 
4b487ce
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import os
import requests
import streamlit as st
from datetime import datetime
from transformers import pipeline



# Gemma ๋ชจ๋ธ ๋กœ๋”ฉ
@st.cache_resource
def load_model():
    return pipeline(
        "text-generation",
        model="google/gemma-2-2b-it",
        max_new_tokens=512,
        use_auth_token=os.environ.get("HUGGINGFACE_TOKEN")  # โœ… ์ง์ ‘ ์ „๋‹ฌ
    )
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

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()

# Streamlit UI
st.set_page_config(page_title="ํ•™์‚ฌ์ผ์ • ์บ˜๋ฆฐ๋”", layout="centered")
st.title("๐Ÿ“… ํ•™์‚ฌ์ผ์ • ์บ˜๋ฆฐ๋” + AI ์š”์•ฝ")
st.markdown("NEIS API์—์„œ ํ•™์‚ฌ์ผ์ •์„ ๋ถˆ๋Ÿฌ์˜ค๊ณ  FullCalendar๋กœ ์‹œ๊ฐํ™”ํ•ฉ๋‹ˆ๋‹ค.")

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:
                # ์ผ์ • ๋ฐ์ดํ„ฐ๋ฅผ HTML ์บ˜๋ฆฐ๋”์— ๋„ฃ๊ธฐ ์œ„ํ•œ JSON ์ƒ์„ฑ
                events = [
                    {
                        "title": row["EVENT_NM"],
                        "start": datetime.strptime(row["AA_YMD"], "%Y%m%d").strftime("%Y-%m-%d")
                    }
                    for row in schedule_rows
                ]

                import json
                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}")