|
|
import os |
|
|
import time |
|
|
import streamlit as st |
|
|
import google.generativeai as genai |
|
|
from streamlit_extras.colored_header import colored_header |
|
|
from streamlit_extras.add_vertical_space import add_vertical_space |
|
|
import markdown |
|
|
|
|
|
|
|
|
genai.configure(api_key=os.environ["GEMINI_API_KEY"]) |
|
|
|
|
|
|
|
|
generation_config = { |
|
|
"temperature": 0.7, |
|
|
"top_p": 0.85, |
|
|
"top_k": 40, |
|
|
"max_output_tokens": 8192, |
|
|
"response_mime_type": "text/plain", |
|
|
} |
|
|
|
|
|
model = genai.GenerativeModel( |
|
|
model_name="gemini-2.0-flash-thinking-exp-01-21", |
|
|
generation_config=generation_config, |
|
|
) |
|
|
|
|
|
SYSTEM_PROMPT = """ |
|
|
λμ νλ
: {grade} |
|
|
μ±μ·¨κΈ°μ€ λ° μ£Όμ λ΄μ©: {achievement_standard} |
|
|
|
|
|
μ μ 보λ₯Ό λ°νμΌλ‘ ν΅μ¬ μμ΄λμ΄ μ΄ν΄λ₯Ό λͺ©νλ‘ νλ {grade} μμ€μ μ ν©ν κ°λ
κΈ°λ° κ΅μ‘κ³Όμ μ μ€κ³ν΄ μ£ΌμΈμ. λ€μ κ΅¬μ± μμμ λ°λΌ μμΈνκ³ μ²΄κ³μ μΌλ‘ μ€λͺ
ν΄μΌ ν©λλ€. |
|
|
κ° κ΅¬μ± μμλ μλ‘ μ°κ²°λκ³ μ κΈ°μ μΌλ‘ ꡬμ±λμ΄μΌ ν©λλ€. ꡬ체μ μΈ μμλ₯Ό ν¬ν¨νμ¬ μ€λͺ
νκ³ , νμλ€μ ν₯λ―Έμ μ°Έμ¬λ₯Ό μ λν μ μλ μ°½μμ μ΄κ³ νμ μ μΈ νλλ€μ μ μν΄ μ£ΌμΈμ. |
|
|
νΉν, νꡬ νλμ ν΅ν΄ νμλ€μ΄ μ€μ€λ‘ μΌλ°νλ₯Ό λμΆνκ³ ν΅μ¬ κ°λ
μ κΉμ΄ μκ² μ΄ν΄ν μ μλλ‘ μ€κ³ν΄μΌ ν©λλ€. |
|
|
λ¨Όμ μ€νΈλλλ₯Ό 2~3κ°λ‘ μ€μ νμΈμ.μ€νΈλλ(Strand)λ λ¨μμ μμ£Όμ μ κ°μΌλ©°, κ° μ€νΈλλλ μ¬λ¬ μ°¨μμ μμ
μΌλ‘ ꡬμ±λ©λλ€. |
|
|
μ°¨μλ³ νλ λ΄μ©κΉμ§ μμΈν κΈ°μ ν΄ μ£ΌμΈμ. |
|
|
|
|
|
1. ν΅μ¬ μμ΄λμ΄ (Key Ideas & Generalizations): |
|
|
μ΄ μ£Όμ λ₯Ό κ΄μ°°νλ κ°μ₯ μ€μν κ΄μ (Conceptual Lens)μ 무μμΈκ°? |
|
|
μ΄ μ£Όμ λ₯Ό ν΅ν΄ νμλ€μ΄ μ΄ν΄ν΄μΌ ν κ°μ₯ μ€μν μμ΄λμ΄(Key Ideas)λ 무μμΈκ°? 2-3κ°μ λ¬Έμ₯μΌλ‘ λͺ
ννκ² κΈ°μ νμΈμ. |
|
|
μ μμ΄λμ΄λ€μ λ·λ°μΉ¨νλ μΌλ°νλ μ§μ(Generalizations)μ 3-5κ°μ λ¬Έμ₯μΌλ‘ μ€λͺ
νμΈμ. |
|
|
|
|
|
2. λ§€ν¬λ‘ κ°λ
(Macro Concepts) λ° λ§μ΄ν¬λ‘ κ°λ
(Micro Concepts): |
|
|
μ΄ μ£Όμ λ₯Ό μ΄ν΄νλ λ° νμν ν° νμ κ°λ
(λ§€ν¬λ‘ κ°λ
, Conceptual Lens)μ 무μμΈκ°? |
|
|
μ΄ μ£Όμ μ κ΄λ ¨λ ꡬ체μ μΈ κ΅κ³Ό κ°λ
(λ§μ΄ν¬λ‘ κ°λ
, Subject-Specific Concepts)μ 무μμΈκ°? |
|
|
λ§€ν¬λ‘ κ°λ
κ³Ό λ§μ΄ν¬λ‘ κ°λ
μ¬μ΄μ κ΄κ³λ₯Ό μ΄λ»κ² μ€λͺ
ν κ²μΈκ°? ꡬ체μ μΈ μμλ₯Ό μ¬μ©νμ¬ μ€λͺ
νμΈμ. |
|
|
|
|
|
3. μ§μμ λ²μ£Ό (Knowledge Categories - λ¦° μλ¦μ¨μ λΆλ₯ κΈ°μ€): |
|
|
μ¬μ€ (Facts): μ΄ μ£Όμ μ κ΄λ ¨λ μ€μν μ¬μ€λ€μ μ΅μ 10κ° μ΄μ λμ΄νμΈμ. |
|
|
κ°λ
(Concepts): μ΄ μ£Όμ λ₯Ό μ΄ν΄νλ λ° νμν ν΅μ¬ κ°λ
λ€μ μ μνκ³ , κ° κ°λ
μ λν μμλ₯Ό μ μνμΈμ. μ΅μ 3κ° μ΄μ μ μνμΈμ. |
|
|
μΌλ°ν (Generalizations): κ°λ
λ€ μ¬μ΄μ κ΄κ³λ₯Ό μ€λͺ
νλ μΌλ°νλ μ§μ μ μ΅μ 3κ° μ΄μ μ μνμΈμ. |
|
|
μ리 (Principles): μΌλ°νλ₯Ό λ·λ°μΉ¨νλ κ³Όνμ μ리 λλ μ΄λ‘ λ€μ μ€λͺ
νμΈμ. μ΅μ 2κ° μ΄μ μ μνμΈμ. |
|
|
|
|
|
4. νꡬ μ§λ¬Έ (Inquiry Questions): |
|
|
νμλ€μ νꡬλ₯Ό μκ·Ήνκ³ ν΅μ¬ κ°λ
λ° μΌλ°νλ‘ μ λν μ μλ νꡬ μ§λ¬Έλ€μ 5κ° μ΄μ μ μνμΈμ. μ§λ¬Έμ ꡬ체μ μ΄κ³ νꡬ κ°λ₯ν΄μΌ νλ©°, λ€μν μμ€μ μ¬κ³ λ₯Ό μꡬν΄μΌ ν©λλ€. κ° μ§λ¬Έμ΄ μ΄λ€ ν΅μ¬ κ°λ
κ³Ό μ°κ²°λλμ§ λͺ
μνμΈμ. |
|
|
|
|
|
5. νμ΅ νλ (Learning Activities): |
|
|
μ΄ μ£Όμ λ₯Ό κ°λ₯΄μΉκΈ° μν μ£Όμ νμ΅ μμ(μ€νΈλλ, Strand)μ 무μμΈκ°? κ° μ€νΈλλλ μ¬λ¬ μ°¨μμ μμ
μΌλ‘ ꡬμ±λ©λλ€. |
|
|
κ° μ€νΈλλμ νμ΅ λͺ©νλ₯Ό λͺ
ννκ² μ μνκ³ , ν΄λΉ λͺ©νλ₯Ό λ¬μ±νκΈ° μν μ°¨μλ³ νμ΅ νλμ ꡬ체μ μΌλ‘ μ€κ³νμΈμ. (μ: ν λ‘ , μ‘°μ¬, μ€ν, νλ‘μ νΈ, κ²μ, νλ ₯ νμ΅ λ±) |
|
|
κ° νλμμ νμλ€μ΄ μ΄λ€ κ°λ
μ νꡬνκ³ μ΄λ€ κΈ°λ₯μ κ°λ°ν μ μλμ§, κ·Έλ¦¬κ³ μ΄λ»κ² μΌλ°νλ₯Ό λμΆν μ μλλ‘ μ λν κ²μΈμ§ μ€λͺ
νμΈμ. νλμ νμλ€μ ν₯λ―Έμ μ°Έμ¬λ₯Ό μ λν μ μλλ‘ μ°½μμ μ΄κ³ νμ μ μΈ λ°©μμΌλ‘ μ€κ³λμ΄μΌ ν©λλ€. |
|
|
κ° νλμ νμν μλ£, μ μ°¨, μμ μμ μκ° λ±μ λͺ
μνμΈμ. |
|
|
κ° μ°¨μμμ λ€λ£¨λ ν΅μ¬ κ°λ
, νꡬ μ§λ¬Έ, μΌλ°νλ₯Ό λͺ
ννκ² μ°κ²°νμΈμ. |
|
|
|
|
|
6. νκ° (Assessment): |
|
|
κ° μ€νΈλλ λ° ν΅μ¬ κ°λ
μ λν νμλ€μ μ΄ν΄λλ₯Ό νκ°ν μ μλ νκ° λ°©λ² λ° λ£¨λΈλ¦(νλ‘ μ μν κ²)μ μ μνμΈμ. (κ΄μ°°, λ°ν, ν¬νΈν΄λ¦¬μ€, μκΈ° νκ°, λλ£ νκ°, ν΄μ¦, μν λ±) |
|
|
루λΈλ¦μ μ, μ€, νμ λν ꡬ체μ μΈ νκ° κΈ°μ€κ³Ό κ° μμ€μ ν΄λΉνλ νμμ μμ
λλ μν μμλ₯Ό ν¬ν¨ν΄μΌ ν©λλ€. |
|
|
νκ°λ λ¨μν μ§μ μκΈ° μ¬λΆλ₯Ό 묻λ κ²μ΄ μλλΌ, νμλ€μ νꡬ κ³Όμ , μ¬κ³ λ ₯, λ¬Έμ ν΄κ²° λ₯λ ₯, νλ ₯μ νλ, κ°λ
μ μ΄ν΄, μΌλ°ν λμΆ λ₯λ ₯ λ±μ μ’
ν©μ μΌλ‘ νκ°ν΄μΌ ν©λλ€. |
|
|
|
|
|
7. κ°λ
μ μ΄ν΄λ₯Ό μν ν (Tips for Conceptual Understanding): |
|
|
νμλ€μ΄ ν΅μ¬ κ°λ
μ κΉμ΄ μκ² μ΄ν΄νκ³ μ°κ²°νλ©°, μΌλ°νλ₯Ό λμΆνκ³ μ μ©ν μ μλλ‘ λλ ν¨κ³Όμ μΈ κ΅μ μ λ΅μ 무μμΈκ°? |
|
|
μ€κ°λ
μ μλ°©νκ³ ν΄κ²°νλ λ°©λ²μ 무μμΈκ°? |
|
|
νμλ€μ λ€μν νμ΅ μ€νμΌκ³Ό μꡬλ₯Ό μΆ©μ‘±νλ λ°©λ²μ 무μμΈκ°? |
|
|
ν΅μ¬ κ°λ
κ³Ό κ΄λ ¨λ μ€μν μ¬λ‘λ₯Ό μ μνμ¬ νμ΅μ μλ―Έμ κ΄λ ¨μ±μ λμ΄λ λ°©μμ μ μνμΈμ. λ©ν°λ―Έλμ΄, μκ° μλ£, κ²μ, νλ ₯ νμ΅ λ± λ€μν κ΅μλ²μ νμ©νλ λ°©μμ μ μνμΈμ. |
|
|
""" |
|
|
|
|
|
|
|
|
def generate_curriculum(grade, achievement_standard): |
|
|
prompt = [ |
|
|
SYSTEM_PROMPT.format(grade=grade, achievement_standard=achievement_standard), |
|
|
] |
|
|
prompt = "\n".join(prompt) |
|
|
|
|
|
full_text = "" |
|
|
try: |
|
|
response = model.generate_content(prompt, stream=True) |
|
|
for chunk in response: |
|
|
full_text += chunk.text |
|
|
html_text = markdown.markdown(full_text, extensions=['tables', 'fenced_code']) |
|
|
output_area.markdown(html_text, unsafe_allow_html=True) |
|
|
time.sleep(0.05) |
|
|
except Exception as e: |
|
|
st.error(f"κ³νμ μμ± μ€λ₯: {e}") |
|
|
return "" |
|
|
return full_text |
|
|
|
|
|
|
|
|
|
|
|
def chat_with_ai(user_input, context): |
|
|
prompt = f"{context}\nUser: {user_input}\nAI:" |
|
|
full_text = "" |
|
|
try: |
|
|
response = model.generate_content(prompt, stream=True) |
|
|
for chunk in response: |
|
|
full_text += chunk.text |
|
|
except Exception as e: |
|
|
st.error(f"μ±λ΄ μ€λ₯: {e}") |
|
|
return "" |
|
|
return full_text |
|
|
|
|
|
|
|
|
st.set_page_config(page_title="κ°λ
κΈ°λ° κ΅μ‘κ³Όμ AI", page_icon="\U0001F393") |
|
|
|
|
|
|
|
|
st.markdown( |
|
|
""" |
|
|
<style> |
|
|
/* μ 체 λ°°κ²½μ μ€μ */ |
|
|
.stApp { |
|
|
background-color: #fffafa; |
|
|
} |
|
|
/* νμ΄ν μ€νμΌ */ |
|
|
.main-title { |
|
|
font-size: 3rem; |
|
|
color: #000000; |
|
|
font-weight: 700; |
|
|
text-align: center; |
|
|
margin-bottom: 20px; |
|
|
} |
|
|
/* μ±ν
λ©μμ§ μ€νμΌ */ |
|
|
.chat-message { |
|
|
border-radius: 15px; |
|
|
padding: 15px; |
|
|
margin: 10px 0; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
flex-wrap: wrap; |
|
|
word-break: break-word; |
|
|
} |
|
|
.chat-message-user { |
|
|
background-color: #ffebef; |
|
|
color: #8b4513; |
|
|
justify-content: flex-end; |
|
|
} |
|
|
.chat-message-assistant { |
|
|
background-color: #ffe4e6; |
|
|
color: #6b4226; |
|
|
justify-content: flex-start; |
|
|
} |
|
|
.chat-avatar { |
|
|
width: 40px; |
|
|
height: 40px; |
|
|
border-radius: 50%; |
|
|
margin-right: 10px; |
|
|
} |
|
|
.chat-avatar-user { |
|
|
margin-left: 10px; |
|
|
margin-right: 0; |
|
|
} |
|
|
/* λ²νΌ μ€νμΌ */ |
|
|
.stButton button { |
|
|
background-color: #cd857f; |
|
|
color: #fff; |
|
|
border-radius: 15px; |
|
|
padding: 10px 20px; |
|
|
} |
|
|
</style> |
|
|
""", |
|
|
unsafe_allow_html=True |
|
|
) |
|
|
|
|
|
st.markdown("<div class='main-title'>\U0001F393 κ°λ
κΈ°λ° κ΅μ‘κ³Όμ AI</div>", unsafe_allow_html=True) |
|
|
add_vertical_space(1) |
|
|
|
|
|
with st.sidebar: |
|
|
st.markdown("## βοΈ μ
λ ₯ μ€μ ") |
|
|
grade_options = [f"μ΄λ±νκ΅ {i}νλ
" for i in range(1, 7)] + [f"μ€νκ΅ {i}νλ
" for i in range(1, 4)] |
|
|
grade_selected = st.selectbox("π νλ
μ ν", grade_options, index=0) |
|
|
achievement_standard = st.text_area("π μ±μ·¨κΈ°μ€ λ° μ£Όμ λ΄μ©", height=150) |
|
|
generate_button = st.button("π κ³νμ μμ±") |
|
|
|
|
|
|
|
|
output_area = st.empty() |
|
|
|
|
|
|
|
|
if "messages" not in st.session_state: |
|
|
st.session_state.messages = [] |
|
|
st.session_state.chat_mode = False |
|
|
|
|
|
|
|
|
if generate_button: |
|
|
with st.spinner("β³ κ³νμ μμ± μ€..."): |
|
|
result = generate_curriculum(grade_selected, achievement_standard) |
|
|
st.session_state.messages.append({"role": "assistant", "content": result}) |
|
|
st.session_state.chat_mode = True |
|
|
|
|
|
|
|
|
user_icon_url = "https://cdn-icons-png.flaticon.com/512/4323/4323008.png" |
|
|
assistant_icon_url = "https://cdn-icons-png.flaticon.com/512/4712/4712108.png" |
|
|
|
|
|
if st.session_state.chat_mode: |
|
|
if prompt := st.chat_input("κ°λ
κΈ°λ° κ΅μ‘κ³Όμ AIμκ² μμ λ° μΆκ° μμ²μ¬νμ μλ €μ£ΌμΈμ!"): |
|
|
st.session_state.messages.append({"role": "user", "content": prompt}) |
|
|
with st.spinner("π€ λ΅λ³ μμ± μ€..."): |
|
|
context = "\n".join([msg["content"] for msg in st.session_state.messages if msg["role"] == "assistant"]) |
|
|
ai_response = chat_with_ai(prompt, context) |
|
|
st.session_state.messages.append({"role": "assistant", "content": ai_response}) |
|
|
|
|
|
for message in st.session_state.messages: |
|
|
if message["role"] != "system": |
|
|
role_class = "chat-message-user" if message["role"] == "user" else "chat-message-assistant" |
|
|
avatar_url = user_icon_url if message["role"] == "user" else assistant_icon_url |
|
|
avatar_class = "chat-avatar-user" if message["role"] == "user" else "chat-avatar" |
|
|
html_text = markdown.markdown(message['content'], extensions=['tables', 'fenced_code']) |
|
|
st.markdown( |
|
|
f"<div class='chat-message {role_class}'><img src='{avatar_url}' class='chat-avatar {avatar_class}'>{html_text}</div>", |
|
|
unsafe_allow_html=True |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
with st.expander("βκ°λ
κΈ°λ° κ΅μ‘κ³Όμ AI FAQ"): |
|
|
st.write(""" |
|
|
**Q1. κ°λ
κΈ°λ° κ΅μ‘κ³Όμ AIλ μ΄λ€ κΈ°λ₯μ μ 곡νλμ?** |
|
|
|
|
|
A. μ΄ μ±μ μ μλλ€μ κ΅μ‘κ³Όμ μ€κ³λ₯Ό λκΈ° μν΄ κ°λ°λ AI λꡬμ
λλ€. νλ
κ³Ό μ±μ·¨κΈ°μ€μ μ
λ ₯νλ©΄ κ°λ
κΈ°λ° κ΅μ‘κ³Όμ κ³νμμ μ΄μμ μμ±ν΄μ€λλ€. μμ±λ κ³νμλ ν΅μ¬ μμ΄λμ΄, λ§€ν¬λ‘/λ§μ΄ν¬λ‘ κ°λ
, μ§μ λ²μ£Ό, νꡬ μ§λ¬Έ, νμ΅ νλ, νκ° λ°©λ², κ°λ
μ μ΄ν΄λ₯Ό μν ν λ±μ ν¬ν¨νμ¬ κ΅μ‘κ³Όμ μ€κ³μ νμν λ€μν μμλ₯Ό μ 곡ν©λλ€. λ¨μν κ³νμ μμ±λΏλ§ μλλΌ, μμ±λ κ³νμλ₯Ό μμ νκ³ μΆκ°μ μΈ μλ£λ₯Ό μμ±νλ λ°μλ λμμ λ립λλ€. |
|
|
|
|
|
**Q2. κ³νμ μμ± ν μμ μ μ΄λ»κ² νλμ?** |
|
|
|
|
|
A. κ³νμ μμ± ν, νλ¨μ λνλλ μ±λ΄μ μ΄μ©νμ¬ μμ λ° μΆκ° μμ²μ¬νμ μμ λ‘κ² μ
λ ₯ν μ μμ΅λλ€. μμ°μ΄λ‘ μ§λ¬Ένκ±°λ μμ²νλ©΄ AIκ° λ΅λ³μ μ 곡νκ³ κ³νμλ₯Ό μμ ν©λλ€. μλ₯Ό λ€μ΄, "1μ°¨μ κ΅μνμ΅ κ³Όμ μμ μμ±ν΄μ€", "νκ° λ°©λ²μ λ ꡬ체μ μΌλ‘ μμ±ν΄μ€", "ν΅μ¬ μμ΄λμ΄λ₯Ό μμ ν΄μ€" μ κ°μ΄ μ
λ ₯νλ©΄ λ©λλ€. μμ λ λ΄μ©μ μ€μκ°μΌλ‘ κ³νμμ λ°μλ©λλ€. λν, μ±λ΄μ ν΅ν΄ μΆκ°μ μΈ μλ£ μμ±μ μμ²ν μλ μμ΅λλ€. |
|
|
|
|
|
**Q3. μ΄λ€ νλ
μ λν κ³νμλ₯Ό μμ±ν μ μλμ?** |
|
|
|
|
|
A. νμ¬ μ΄λ±νκ΅ 1νλ
λΆν° μ€νκ΅ 3νλ
κΉμ§ λͺ¨λ νλ
μ λν κ³νμ μμ±μ μ§μν©λλ€. ν₯ν λ λμ λ²μμ νλ
μ μ§μν μμ μ
λλ€. νλ
μ ν λ©λ΄μμ μνλ νλ
μ μ ννμΈμ. |
|
|
|
|
|
**Q4. μ±λ΄μ μ΄μ©ν΄μ μ΄λ€ μΆκ° μλ£λ₯Ό μμ±ν μ μλμ?** |
|
|
|
|
|
A. μ±λ΄μ ν΅ν΄ λ€μκ³Ό κ°μ μΆκ° μλ£ μμ±μ μμ²ν μ μμ΅λλ€: |
|
|
* **μ°¨μλ³ κ΅μνμ΅ κ³Όμ μ:** κ° μ°¨μμ νμ΅ λͺ©ν, νλ λ΄μ©, μλ£, νκ° λ°©λ² λ±μ ν¬ν¨ν μμΈν κ³Όμ μμ μμ±ν©λλ€. *μμ: "3μ°¨μ κ΅μνμ΅ κ³Όμ μμ λ§λ€μ΄μ€"* |
|
|
* **μ½κΈ° μλ£:** νμ΅ μ£Όμ μ κ΄λ ¨λ ν₯λ―Έλ‘μ΄ μ½κΈ° μλ£λ₯Ό μ 곡ν©λλ€. *μμ: "λμ
μ°¨μμμ νμ©ν μ½κΈ° μλ£λ₯Ό λ§λ€μ΄μ€"* |
|
|
* **νλμ§:** νμλ€μ΄ μ§μ μ°Έμ¬νκ³ νλν μ μλ μν¬μνΈ, ν΄μ¦, κ²μ λ±μ μμ±ν©λλ€. *μμ: "5μ°¨μμ νμ©ν μ μλ νλμ§λ₯Ό λ§λ€μ΄μ€"* |
|
|
* **νκ° λ¬Έν:** νμ±νκ°, μννκ° λ± λ€μν μ νμ νκ° λ¬Ένμ μ μν©λλ€. *μμ: "μ΄ λ¨μμ ν΅μ¬ κ°λ
μ νκ°νλ 루λΈλ¦μ λ§λ€μ΄μ€"* |
|
|
|
|
|
μ±λ΄μ ꡬ체μ μΈ μμ²μ¬νμ μ
λ ₯ν μλ‘ λμ± μ ννκ³ μ μ©ν κ²°κ³Όλ₯Ό μ»μ μ μμ΅λλ€. μμ²μ¬νμ λͺ
ννκ² μμ±νκ³ , νμν μ 보λ₯Ό μΆ©λΆν μ 곡ν μλ‘ AIκ° λμ± ν¨κ³Όμ μΌλ‘ λμμ μ€ μ μμ΅λλ€. |
|
|
""") |