sdgs / app.py
ll7098ll's picture
Update app.py
ff796c0 verified
import os
import streamlit as st
import google.generativeai as genai
import random
# --- Streamlit ์„ค์ • ---
st.set_page_config(
page_title="SDGs ์ •์ฑ… ๊ฒฐ์ • ๊ฒŒ์ž„",
page_icon="๐ŸŒ",
layout="wide",
initial_sidebar_state="expanded",
)
# --- Custom CSS (๊ฐ„๋‹จํ•˜๊ฒŒ) ---
st.markdown(
"""
<style>
/* ์ „์ฒด ํฐํŠธ */
body {
font-family: 'Nanum Gothic', sans-serif !important;
}
/* ๋ฒ„ํŠผ */
div.stButton > button {
background-color: #007bff;
color: white;
}
</style>
""",
unsafe_allow_html=True,
)
# --- API ํ‚ค ์„ค์ • ---
if "GEMINI_API_KEY" not in os.environ:
st.error(
"GEMINI_API_KEY ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. Hugging Face Secrets ๋˜๋Š” ํ™˜๊ฒฝ ๋ณ€์ˆ˜์— API ํ‚ค๋ฅผ ์„ค์ •ํ•ด์ฃผ์„ธ์š”."
)
st.stop()
genai.configure(api_key=os.environ["GEMINI_API_KEY"])
# --- Gemini ๋ชจ๋ธ ์„ค์ • ---
generation_config = {
"temperature": 1.0,
"top_p": 0.95,
"top_k": 64,
"max_output_tokens": 5000, # ์ค„์ด๊ธฐ
}
model = genai.GenerativeModel(
model_name="gemini-2.0-flash-exp",
generation_config=generation_config,
)
# --- ์„ธ์…˜ ์ƒํƒœ ์ดˆ๊ธฐํ™” ---
if "sdgs_chat_session" not in st.session_state:
st.session_state["sdgs_chat_session"] = model.start_chat(history=[])
if "current_sdg_scenario" not in st.session_state:
st.session_state["current_sdg_scenario"] = None
if "policy_options" not in st.session_state:
st.session_state["policy_options"] = None
if "policy_result" not in st.session_state:
st.session_state["policy_result"] = None
if "selected_sdg" not in st.session_state:
st.session_state["selected_sdg"] = None
if "user_policy_option" not in st.session_state:
st.session_state["user_policy_option"] = ""
if "points" not in st.session_state:
st.session_state["points"] = 0
if "level" not in st.session_state:
st.session_state["level"] = 1
# --- SDGs ๋ชฉํ‘œ ๋ชฉ๋ก ๋ฐ ์„ค๋ช… ---
sdg_goals = {
"SDG 1": "๋นˆ๊ณค ํ‡ด์น˜",
"SDG 2": "๊ธฐ์•„ ์ข…์‹",
"SDG 3": "๊ฑด๊ฐ•๊ณผ ์›ฐ๋น™",
"SDG 4": "์–‘์งˆ์˜ ๊ต์œก",
"SDG 5": "์„ฑํ‰๋“ฑ",
"SDG 6": "๊นจ๋—ํ•œ ๋ฌผ๊ณผ ์œ„์ƒ",
"SDG 7": "๊นจ๋—ํ•œ ์—๋„ˆ์ง€",
"SDG 8": "์–‘์งˆ์˜ ์ผ์ž๋ฆฌ์™€ ๊ฒฝ์ œ ์„ฑ์žฅ",
"SDG 9": "์‚ฐ์—…, ํ˜์‹ , ์‚ฌํšŒ ๊ธฐ๋ฐ˜ ์‹œ์„ค",
"SDG 10": "๋ถˆํ‰๋“ฑ ์™„ํ™”",
"SDG 11": "์ง€์†๊ฐ€๋Šฅํ•œ ๋„์‹œ์™€ ๊ณต๋™์ฒด",
"SDG 12": "์ง€์†๊ฐ€๋Šฅํ•œ ์†Œ๋น„, ์ƒ์‚ฐ",
"SDG 13": "๊ธฐํ›„ ๋ณ€ํ™” ๋Œ€์‘",
"SDG 14": "ํ•ด์–‘ ์ƒํƒœ๊ณ„ ๋ณด์ „",
"SDG 15": "์œก์ƒ ์ƒํƒœ๊ณ„ ๋ณด์ „",
"SDG 16": "ํ‰ํ™”, ์ •์˜, ์ œ๋„",
"SDG 17": "ํŒŒํŠธ๋„ˆ์‹ญ",
}
sdg_descriptions = {
"SDG 1": "๋ชจ๋“  ๊ณณ์—์„œ, ๋ชจ๋“  ํ˜•ํƒœ์˜ ๋นˆ๊ณค์„ ๋๋‚ด๋Š” ๊ฒƒ",
"SDG 2": "๊ธฐ์•„๋ฅผ ์—†์• ๊ณ , ์‹๋Ÿ‰ ์•ˆ๋ณด๋ฅผ ์ด๋ฃจ๋ฉฐ, ์˜์–‘ ์ƒํƒœ๋ฅผ ๊ฐœ์„ ํ•˜๊ณ , ์ง€์†๊ฐ€๋Šฅํ•œ ๋†์—…์„ ๋ฐœ์ „์‹œํ‚ค๋Š” ๊ฒƒ",
"SDG 3": "๋ชจ๋“  ์‚ฌ๋žŒ์˜ ๊ฑด๊ฐ•๊ณผ ์›ฐ๋น™์„ ์ฆ์ง„์‹œํ‚ค๋Š” ๊ฒƒ",
"SDG 4": "๋ชจ๋‘์—๊ฒŒ ์งˆ ์ข‹์€ ๊ต์œก์„ ๋ณด์žฅํ•˜๊ณ , ํ‰์ƒ ํ•™์Šต ๊ธฐํšŒ๋ฅผ ๋Š˜๋ฆฌ๋Š” ๊ฒƒ",
"SDG 5": "์„ฑํ‰๋“ฑ์„ ์ด๋ฃจ๊ณ , ๋ชจ๋“  ์—ฌ์„ฑ๊ณผ ์†Œ๋…€์˜ ๊ถŒํ•œ์„ ๊ฐ•ํ™”ํ•˜๋Š” ๊ฒƒ",
"SDG 6": "๋ชจ๋‘๊ฐ€ ๊นจ๋—ํ•œ ๋ฌผ๊ณผ ์œ„์ƒ ์‹œ์„ค์„ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ",
"SDG 7": "๋ชจ๋‘์—๊ฒŒ ์ €๋ ดํ•˜๊ณ  ๊นจ๋—ํ•œ ์—๋„ˆ์ง€๋ฅผ ๋ณด์žฅํ•˜๋Š” ๊ฒƒ",
"SDG 8": "๋ชจ๋‘๋ฅผ ์œ„ํ•œ ์ง€์†์ ์ด๊ณ  ํฌ์šฉ์ ์ด๋ฉฐ ์ง€์†๊ฐ€๋Šฅํ•œ ๊ฒฝ์ œ ์„ฑ์žฅ, ์ƒ์‚ฐ์ ์ธ ์™„์ „ ๊ณ ์šฉ๊ณผ ์–‘์งˆ์˜ ์ผ์ž๋ฆฌ๋ฅผ ์ฆ์ง„์‹œํ‚ค๋Š” ๊ฒƒ",
"SDG 9": "ํŠผํŠผํ•œ ์‚ฌํšŒ ๊ธฐ๋ฐ˜ ์‹œ์„ค์„ ๊ฑด์„คํ•˜๊ณ , ํฌ์šฉ์ ์ด๊ณ  ์ง€์†๊ฐ€๋Šฅํ•œ ์‚ฐ์—…ํ™”๋ฅผ ์ฆ์ง„ํ•˜๋ฉฐ, ํ˜์‹ ์„ ์žฅ๋ คํ•˜๋Š” ๊ฒƒ",
"SDG 10": "๊ตญ๊ฐ€ ๋‚ด ๊ทธ๋ฆฌ๊ณ  ๊ตญ๊ฐ€ ๊ฐ„ ๋ถˆํ‰๋“ฑ์„ ์ค„์ด๋Š” ๊ฒƒ",
"SDG 11": "์•ˆ์ „ํ•˜๊ณ  ํšŒ๋ณต๋ ฅ ์žˆ๊ณ  ์ง€์†๊ฐ€๋Šฅํ•œ ๋„์‹œ์™€ ์ธ๊ฐ„ ๊ฑฐ์ฃผ์ง€๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ",
"SDG 12": "์ง€์†๊ฐ€๋Šฅํ•œ ์†Œ๋น„์™€ ์ƒ์‚ฐ ํŒจํ„ด์„ ํ™•๋ฆฝํ•˜๋Š” ๊ฒƒ",
"SDG 13": "๊ธฐํ›„ ๋ณ€ํ™”์™€ ๊ทธ ์˜ํ–ฅ์— ๋งž์„œ ์‹ธ์šฐ๊ธฐ ์œ„ํ•œ ๊ธด๊ธ‰ ์กฐ์น˜๋ฅผ ์ทจํ•˜๋Š” ๊ฒƒ",
"SDG 14": "์ง€์†๊ฐ€๋Šฅํ•œ ๋ฐœ์ „์„ ์œ„ํ•ด ํ•ด์–‘๊ณผ ํ•ด์–‘ ์ž์›์„ ๋ณด์กดํ•˜๊ณ  ์ง€์†๊ฐ€๋Šฅํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ",
"SDG 15": "์œก์ง€ ์ƒํƒœ๊ณ„๋ฅผ ๋ณดํ˜ธํ•˜๊ณ  ๋ณต์›ํ•˜๋ฉฐ ์ง€์†๊ฐ€๋Šฅํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ณ , ์‚ฐ๋ฆผ์„ ์ง€์†๊ฐ€๋Šฅํ•˜๊ฒŒ ๊ฒฝ์˜ํ•˜๋ฉฐ, ์‚ฌ๋ง‰ํ™”๋ฅผ ๋ฐฉ์ง€ํ•˜๊ณ , ํ† ์ง€ ํ™ฉํํ™”๋ฅผ ์ค‘์ง€์‹œํ‚ค๊ณ  ๋˜์‚ด๋ฆฌ๋ฉฐ, ์ƒ๋ฌผ ๋‹ค์–‘์„ฑ ์†์‹ค์„ ๋ฉˆ์ถ”๊ฒŒ ํ•˜๋Š” ๊ฒƒ",
"SDG 16": "์ง€์†๊ฐ€๋Šฅํ•œ ๋ฐœ์ „์„ ์œ„ํ•ด ํ‰ํ™”๋กญ๊ณ  ํฌ์šฉ์ ์ธ ์‚ฌํšŒ๋ฅผ ์ฆ์ง„ํ•˜๊ณ , ๋ชจ๋‘์—๊ฒŒ ์ •์˜๋ฅผ ๋ณด์žฅํ•˜๋ฉฐ, ๋ชจ๋“  ์ˆ˜์ค€์—์„œ ํšจ๊ณผ์ ์ด๊ณ  ์ฑ…์ž„๊ฐ ์žˆ๊ณ  ํฌ์šฉ์ ์ธ ์ œ๋„๋ฅผ ๊ตฌ์ถ•ํ•˜๋Š” ๊ฒƒ",
"SDG 17": "์ง€์†๊ฐ€๋Šฅํ•œ ๋ฐœ์ „์„ ์œ„ํ•œ ์ดํ–‰ ์ˆ˜๋‹จ์„ ๊ฐ•ํ™”ํ•˜๊ณ , ๊ธ€๋กœ๋ฒŒ ํŒŒํŠธ๋„ˆ์‹ญ์„ ํ™œ์„ฑํ™”ํ•˜๋Š” ๊ฒƒ",
}
# --- ๋ ˆ๋ฒจ์—… ๊ธฐ์ค€ ํฌ์ธํŠธ ---
level_points = {
2: 20,
3: 50,
4: 100,
5: 200,
}
# --- ๊ธฐ๋ณธ ํฌ์ธํŠธ ๋ถ€์—ฌ ๊ธฐ์ค€ (์ •์ฑ… ๊ฒฐ์ • ์™ธ ํ–‰๋™) ---
base_points_per_action = {
"scenario": 5,
"options": 3,
"retry": 1,
}
# --- ์ •์ฑ… ํ‰๊ฐ€ ํ‚ค์›Œ๋“œ ---
positive_keywords = ["์„ฑ๊ณต", "๊ฐœ์„ ", "ํ–ฅ์ƒ", "๊ธ์ •์ ", "ํšจ๊ณผ์ ", "์ฆ์ง„", "๋ฐœ์ „", "๋„์›€", "๊ธฐ์—ฌ", "ํ•ด๊ฒฐ"]
negative_keywords = ["์–ด๋ ค์›€", "๋ฌธ์ œ", "์•…ํ™”", "๋ถ€์ •์ ", "๋น„ํšจ์œจ์ ", "๋ถ€์กฑ", "์†์‹ค", "์•…์˜ํ–ฅ", "ํ•œ๊ณ„", "์‹คํŒจ"]
point_ranges = { # ์ •์ฑ… ํ‰๊ฐ€์— ๋”ฐ๋ฅธ ํฌ์ธํŠธ ๋ฒ”์œ„
"positive": (10, 15),
"neutral": (5, 10),
"negative": (1, 5),
}
# --- ๋ ˆ๋ฒจ ์—…๋ฐ์ดํŠธ ํ•จ์ˆ˜ ---
def update_level():
current_level = st.session_state["level"]
current_points = st.session_state["points"]
next_level = current_level + 1
if next_level in level_points and current_points >= level_points[next_level]:
st.session_state["level"] = next_level
st.success(f"๐ŸŽ‰ ๋ ˆ๋ฒจ ์—…! Level {next_level} ๋‹ฌ์„ฑ! ๐ŸŽ‰")
st.toast(f"๐ŸŽ‰ ๋ ˆ๋ฒจ ์—…! Level {next_level} ๋‹ฌ์„ฑ! ๐ŸŽ‰", icon="๐Ÿš€")
# --- ์‹œ๋‚˜๋ฆฌ์˜ค ์ƒ์„ฑ ํ•จ์ˆ˜ ---
def generate_sdg_scenario(sdg_goal_name, sdg_goal_text):
prompt = f"""
์ง€์‹œ:
์ดˆ๋“ฑํ•™์ƒ 6ํ•™๋…„ ์ˆ˜์ค€์— ๋งž์ถฐ์„œ, {sdg_goal_text}({sdg_goal_name}) ๋ชฉํ‘œ์™€ ๊ด€๋ จ๋œ ์ •์ฑ… ๊ฒฐ์ • ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”.
์‹œ๋‚˜๋ฆฌ์˜ค๋Š” 8~10๋ฌธ์žฅ ์ •๋„๋กœ ํ˜„์‹ค์ ์ธ ์‚ฌํšŒ ๋ฌธ์ œ ์ƒํ™ฉ์„ ์„ค๋ช…ํ•˜๊ณ , ํ•™์ƒ๋“ค์ด ์ •์ฑ… ๊ฒฐ์ •์˜ ํ•„์š”์„ฑ์„ ๋А๋‚„ ์ˆ˜ ์žˆ๋„๋ก ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”.
"## ์‹œ๋‚˜๋ฆฌ์˜ค" ๋กœ ์‹œ์ž‘ํ•ด์ฃผ์„ธ์š”.
**์ƒ์„ฑ๋œ ์‹œ๋‚˜๋ฆฌ์˜ค:**
"""
chat_session = st.session_state["sdgs_chat_session"]
response = chat_session.send_message(prompt)
scenario_text = response.text.strip()
if scenario_text.startswith("## ์‹œ๋‚˜๋ฆฌ์˜ค"):
scenario_content = scenario_text[len("## ์‹œ๋‚˜๋ฆฌ์˜ค") :].strip()
st.session_state["points"] += base_points_per_action["scenario"] # ๊ธฐ๋ณธ ํฌ์ธํŠธ ์ฆ๊ฐ€
update_level() # ๋ ˆ๋ฒจ ์—…๋ฐ์ดํŠธ
return scenario_content
return scenario_text # ํ˜น์‹œ๋ผ๋„ "## ์‹œ๋‚˜๋ฆฌ์˜ค" ๋กœ ์‹œ์ž‘ ์•ˆํ•˜๋ฉด ๊ทธ๋ƒฅ ๋ฐ˜ํ™˜
# --- ์ •์ฑ… ์˜ต์…˜ ์ƒ์„ฑ ํ•จ์ˆ˜ ---
def generate_policy_options(scenario_text):
prompt = f"""
**์‹œ๋‚˜๋ฆฌ์˜ค:**
{scenario_text}
**์ง€์‹œ:**
์œ„ ์‹œ๋‚˜๋ฆฌ์˜ค์— ์ œ์‹œ๋œ ๋ฌธ์ œ ์ƒํ™ฉ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ์ •์ฑ… ์˜ต์…˜ 3๊ฐ€์ง€ ์ •๋„๋ฅผ ์ดˆ๋“ฑํ•™์ƒ 6ํ•™๋…„ ์ˆ˜์ค€์— ๋งž์ถฐ์„œ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”.
๊ฐ ์˜ต์…˜์€ 2~3๋ฌธ์žฅ์œผ๋กœ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”.
์˜ต์…˜์€ ๋ฒˆํ˜ธ์™€ ํ•จ๊ป˜ "์˜ต์…˜ [๋ฒˆํ˜ธ]: " ๋กœ ์‹œ์ž‘ํ•ด์ฃผ์„ธ์š”. (์˜ˆ: ์˜ต์…˜ 1: , ์˜ต์…˜ 2: ...)
**์ƒ์„ฑ๋œ ์ •์ฑ… ์˜ต์…˜:**
"""
chat_session = st.session_state["sdgs_chat_session"]
response = chat_session.send_message(prompt)
options_text = response.text.strip()
policy_options_list = {}
if options_text:
options_lines = [line.strip() for line in options_text.split('\n') if line.strip()]
for line in options_lines:
if line.startswith("์˜ต์…˜ "):
parts = line.split(":", 1) # ์ฒซ ๋ฒˆ์งธ ":" ๊ธฐ์ค€์œผ๋กœ ๋ถ„๋ฆฌ
if len(parts) == 2:
option_number = parts[0].split(" ")[1] # "์˜ต์…˜ 1" ์—์„œ "1" ์ถ”์ถœ
option_description = parts[1].strip()
policy_options_list[option_number] = option_description
st.session_state["points"] += base_points_per_action["options"] # ๊ธฐ๋ณธ ํฌ์ธํŠธ ์ฆ๊ฐ€
update_level() # ๋ ˆ๋ฒจ ์—…๋ฐ์ดํŠธ
return policy_options_list
# --- ์ •์ฑ… ๊ฒฐ๊ณผ ์ƒ์„ฑ ๋ฐ ํ‰๊ฐ€ ํ•จ์ˆ˜ ---
def generate_policy_result(scenario_text, selected_option_text):
prompt = f"""
**์‹œ๋‚˜๋ฆฌ์˜ค:**
{scenario_text}
**์„ ํƒํ•œ ์ •์ฑ… ์˜ต์…˜:**
{selected_option_text}
**์ง€์‹œ:**
์œ„ ์‹œ๋‚˜๋ฆฌ์˜ค ๋ฌธ์ œ ์ƒํ™ฉ์—์„œ ์„ ํƒํ•œ ์ •์ฑ… ์˜ต์…˜์„ ์‹คํ–‰ํ–ˆ์„ ๋•Œ ์˜ˆ์ƒ๋˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ์ดˆ๋“ฑํ•™์ƒ 6ํ•™๋…„ ์ˆ˜์ค€์— ๋งž์ถฐ์„œ 6~8๋ฌธ์žฅ ์ •๋„๋กœ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”.
์ •์ฑ…์˜ ๊ธ์ •์ ์ธ ํšจ๊ณผ์™€ ํ•จ๊ป˜ ์˜ˆ์ƒ๋˜๋Š” ์–ด๋ ค์›€์ด๋‚˜ ๋ถ€์ž‘์šฉ๋„ **์†”์งํ•˜๊ฒŒ** ํ•จ๊ป˜ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”.
์ •์ฑ… ๊ฒฐ๊ณผ๊ฐ€ ๊ธ์ •์ ์ธ์ง€, ์ค‘๋ฆฝ์ ์ธ์ง€, ๋ถ€์ •์ ์ธ์ง€ ์Šค์Šค๋กœ ํ‰๊ฐ€ํ•˜์—ฌ ํ•จ๊ป˜ ์•Œ๋ ค์ฃผ์„ธ์š”. (์˜ˆ: ๊ธ์ •์  ๊ฒฐ๊ณผ, ์ค‘๋ฆฝ์  ๊ฒฐ๊ณผ, ๋ถ€์ •์  ๊ฒฐ๊ณผ)
"## ์ •์ฑ… ๊ฒฐ๊ณผ" ๋กœ ์‹œ์ž‘ํ•˜๊ณ , ๊ทธ ๋‹ค์Œ์— ์ •์ฑ… ํ‰๊ฐ€(๊ธ์ •์  ๊ฒฐ๊ณผ, ์ค‘๋ฆฝ์  ๊ฒฐ๊ณผ, ๋ถ€์ •์  ๊ฒฐ๊ณผ ์ค‘ ํ•˜๋‚˜)๋ฅผ ๊ด„ํ˜ธ ์•ˆ์— ๋„ฃ์–ด์„œ ํ‘œ์‹œํ•ด์ฃผ์„ธ์š”. (์˜ˆ: ## ์ •์ฑ… ๊ฒฐ๊ณผ (๊ธ์ •์  ๊ฒฐ๊ณผ))
๊ทธ๋ฆฌ๊ณ  ์ •์ฑ… ๊ฒฐ๊ณผ ํ…์ŠคํŠธ๋ฅผ ์ด์–ด์„œ ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”.
**์ƒ์„ฑ๋œ ์ •์ฑ… ๊ฒฐ๊ณผ:**
"""
chat_session = st.session_state["sdgs_chat_session"]
response = chat_session.send_message(prompt)
result_text = response.text.strip()
policy_result_text = ""
policy_evaluation = "neutral" # ๊ธฐ๋ณธ ํ‰๊ฐ€: ์ค‘๋ฆฝ
if result_text.startswith("## ์ •์ฑ… ๊ฒฐ๊ณผ"):
result_content_with_eval = result_text[len("## ์ •์ฑ… ๊ฒฐ๊ณผ") :].strip()
if result_content_with_eval.startswith("(๊ธ์ •์  ๊ฒฐ๊ณผ)"):
policy_result_text = result_content_with_eval[len("(๊ธ์ •์  ๊ฒฐ๊ณผ)") :].strip()
policy_evaluation = "positive"
elif result_content_with_eval.startswith("(๋ถ€์ •์  ๊ฒฐ๊ณผ)"):
policy_result_text = result_content_with_eval[len("(๋ถ€์ •์  ๊ฒฐ๊ณผ)") :].strip()
policy_evaluation = "negative"
elif result_content_with_eval.startswith("(์ค‘๋ฆฝ์  ๊ฒฐ๊ณผ)"):
policy_result_text = result_content_with_eval[len("(์ค‘๋ฆฝ์  ๊ฒฐ๊ณผ)") :].strip()
policy_evaluation = "neutral"
else:
policy_result_text = result_content_with_eval.strip() # ํ‰๊ฐ€ ์ •๋ณด ์—†์„ ๊ฒฝ์šฐ
# ์ •์ฑ… ํ‰๊ฐ€ ๊ธฐ๋ฐ˜ ํฌ์ธํŠธ ๋ถ€์—ฌ
if policy_evaluation == "positive":
points = random.randint(*point_ranges["positive"])
elif policy_evaluation == "negative":
points = random.randint(*point_ranges["negative"])
else: # neutral
points = random.randint(*point_ranges["neutral"])
st.session_state["points"] += points # ์ •์ฑ… ํ‰๊ฐ€ ๊ธฐ๋ฐ˜ ํฌ์ธํŠธ ์ฆ๊ฐ€
update_level() # ๋ ˆ๋ฒจ ์—…๋ฐ์ดํŠธ
return policy_result_text, policy_evaluation, points
# --- ๋ฉ”์ธ ํ™”๋ฉด ---
def main():
st.sidebar.header("๐ŸŒ SDGs ์ •์ฑ… ๊ฒฐ์ • ๊ฒŒ์ž„")
st.sidebar.markdown(f"### ๐Ÿ† Level {st.session_state['level']}") # ๋ ˆ๋ฒจ ํ‘œ์‹œ
st.sidebar.markdown(f"### โญ ํฌ์ธํŠธ: {st.session_state['points']}") # ํฌ์ธํŠธ ํ‘œ์‹œ
st.sidebar.markdown("---")
selected_sdg_name = st.sidebar.selectbox("SDGs ๋ชฉํ‘œ ์„ ํƒ:", list(sdg_goals.keys()))
sdg_goal_text = sdg_goals[selected_sdg_name]
if st.session_state["selected_sdg"] != selected_sdg_name: # ๋ชฉํ‘œ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ์‹œ๋‚˜๋ฆฌ์˜ค, ์˜ต์…˜, ๊ฒฐ๊ณผ ์ดˆ๊ธฐํ™”
st.session_state["current_sdg_scenario"] = None
st.session_state["policy_options"] = None
st.session_state["policy_result"] = None
st.session_state["selected_sdg"] = selected_sdg_name
st.session_state["user_policy_option"] = "" # ์‚ฌ์šฉ์ž ์ž…๋ ฅ ์˜ต์…˜ ์ดˆ๊ธฐํ™”
with st.sidebar.expander("๐Ÿ“– SDGs ๋ชฉํ‘œ ์„ค๋ช…"):
for goal_name, goal_text in sdg_goals.items():
st.markdown(f"**{goal_name}: {goal_text}**")
st.write(sdg_descriptions[goal_name])
st.markdown("---")
with st.sidebar.expander("๐Ÿš€ ์•ฑ ์‚ฌ์šฉ ๊ฐ€์ด๋“œ"):
st.markdown(
"""
**SDGs ์ •์ฑ… ๊ฒฐ์ • ๊ฒŒ์ž„ ๋ฐฉ๋ฒ•**
1. **SDGs ๋ชฉํ‘œ ์„ ํƒ:** ์™ผ์ชฝ ์‚ฌ์ด๋“œ๋ฐ”์—์„œ ์ •์ฑ… ๊ฒฐ์ •์„ ํ•ด๋ณด๊ณ  ์‹ถ์€ SDGs ๋ชฉํ‘œ๋ฅผ ์„ ํƒํ•˜์„ธ์š”.
2. **์‹œ๋‚˜๋ฆฌ์˜ค ์ƒ์„ฑ:** '์‹œ๋‚˜๋ฆฌ์˜ค ์ƒ์„ฑ' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ ์„ ํƒํ•œ ๋ชฉํ‘œ์™€ ๊ด€๋ จ๋œ ๋ฌธ์ œ ์ƒํ™ฉ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋ฐ›์•„๋ณด์„ธ์š”. (โญ **๊ธฐ๋ณธ ํฌ์ธํŠธ +5**)
3. **์ •์ฑ… ์˜ต์…˜ ์ƒ์„ฑ:** ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ฝ๊ณ  '์ •์ฑ… ์˜ต์…˜ ์ƒ์„ฑ' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ AI๊ฐ€ ์ œ์‹œํ•˜๋Š” ์ •์ฑ… ์˜ต์…˜๋“ค์„ ํ™•์ธํ•˜์„ธ์š”. (โญ **๊ธฐ๋ณธ ํฌ์ธํŠธ +3**)
4. **์ •์ฑ… ์˜ต์…˜ ์„ ํƒ ๋˜๋Š” ์ง์ ‘ ์ž…๋ ฅ:**
* **AI ์˜ต์…˜ ์„ ํƒ:** ์ œ์‹œ๋œ ์˜ต์…˜ ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•˜์„ธ์š”.
* **์ง์ ‘ ์ž…๋ ฅ:** '์ง์ ‘ ์ž…๋ ฅ'์„ ์„ ํƒํ•˜๊ณ , ์•„๋ž˜ ํ…์ŠคํŠธ ์ž…๋ ฅ ์ฐฝ์— ์—ฌ๋Ÿฌ๋ถ„์ด ์ƒ๊ฐํ•˜๋Š” ์ •์ฑ… ์•„์ด๋””์–ด๋ฅผ ์ง์ ‘ ์ ์–ด๋ณด์„ธ์š”.
5. **์ •์ฑ… ๊ฒฐ์ • ์‹คํ–‰:** ์˜ต์…˜์„ ์„ ํƒํ•˜๊ฑฐ๋‚˜ ์ง์ ‘ ์ž…๋ ฅํ•œ ํ›„ '์ •์ฑ… ๊ฒฐ์ • ์‹คํ–‰' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์„ธ์š”. (โญ **์ •์ฑ… ํ‰๊ฐ€ ๊ธฐ๋ฐ˜ ํฌ์ธํŠธ**)
6. **์ •์ฑ… ๊ฒฐ๊ณผ ํ™•์ธ:** ์„ ํƒํ•œ ์ •์ฑ…์˜ ์˜ˆ์ƒ ๊ฒฐ๊ณผ์™€ ํ•จ๊ป˜ ํš๋“ํ•œ ํฌ์ธํŠธ๋ฅผ ํ™•์ธํ•˜์„ธ์š”. ์ •์ฑ… ๊ฒฐ๊ณผ๊ฐ€ ์ข‹์„์ˆ˜๋ก ๋” ๋งŽ์€ ํฌ์ธํŠธ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
7. **์ƒˆ๋กœ์šด ์‹œ๋‚˜๋ฆฌ์˜ค:** '์ƒˆ๋กœ์šด ์‹œ๋‚˜๋ฆฌ์˜ค๋กœ ๋‹ค์‹œํ•˜๊ธฐ' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์ƒˆ๋กœ์šด ๋ฌธ์ œ ์ƒํ™ฉ์œผ๋กœ ๋‹ค์‹œ ๊ฒŒ์ž„์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (โญ **์žฌ๋„์ „ ๊ธฐ๋ณธ ํฌ์ธํŠธ +1**)
**ํฌ์ธํŠธ์™€ ๋ ˆ๋ฒจ:**
* ๊ฒŒ์ž„์„ ์ง„ํ–‰ํ•˜๋ฉด์„œ ํฌ์ธํŠธ๋ฅผ ์–ป๊ณ , ๋ ˆ๋ฒจ์„ ์˜ฌ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
* **์ •์ฑ… ๊ฒฐ๊ณผ๊ฐ€ ์ข‹์„์ˆ˜๋ก ๋” ๋งŽ์€ ํฌ์ธํŠธ๋ฅผ ํš๋“**ํ•˜์—ฌ ๋ ˆ๋ฒจ์„ ๋น ๋ฅด๊ฒŒ ์˜ฌ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
* ๋‹ค์–‘ํ•œ SDGs ๋ชฉํ‘œ์— ๋„์ „ํ•˜๊ณ , ์ข‹์€ ์ •์ฑ… ๊ฒฐ์ •์„ ๋งŽ์ด ๋‚ด๋ ค์„œ ๋†’์€ ๋ ˆ๋ฒจ์— ๋„์ „ํ•ด๋ณด์„ธ์š”!
**ํŒ:**
* ๊ฐ SDGs ๋ชฉํ‘œ๊ฐ€ ๋ฌด์—‡์„ ์˜๋ฏธํ•˜๋Š”์ง€ 'SDGs ๋ชฉํ‘œ ์„ค๋ช…'์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.
* ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๊ผผ๊ผผํžˆ ์ฝ๊ณ , ๋ฌธ์ œ์˜ ์›์ธ๊ณผ ์˜ํ–ฅ์„ ํŒŒ์•…ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.
* ์ •์ฑ… ์˜ต์…˜์˜ ๊ธ์ •์  ํšจ๊ณผ์™€ ์˜ˆ์ƒ๋˜๋Š” ์–ด๋ ค์›€์„ ๊ณ ๋ คํ•˜์—ฌ ์‹ ์ค‘ํ•˜๊ฒŒ ์„ ํƒํ•˜์„ธ์š”.
* **๋” ๋‚˜์€ ์ •์ฑ…์„ ์„ ํƒํ•˜๊ฑฐ๋‚˜, ์ฐฝ์˜์ ์ธ ์ •์ฑ… ์•„์ด๋””์–ด๋ฅผ ์ง์ ‘ ์ž…๋ ฅ**ํ•˜์—ฌ ๋†’์€ ์ ์ˆ˜๋ฅผ ํš๋“ํ•ด๋ณด์„ธ์š”!
**์žฌ๋ฏธ์žˆ๊ฒŒ SDGs ์ •์ฑ… ๊ฒฐ์ • ๊ฒŒ์ž„์„ ์ฆ๊ธฐ๋ฉด์„œ ์ง€์†๊ฐ€๋Šฅํ•œ ์‚ฌํšŒ๋ฅผ ์œ„ํ•œ ๋ฌธ์ œ ํ•ด๊ฒฐ ๋Šฅ๋ ฅ์„ ํ‚ค์›Œ๋ณด์„ธ์š”!**
"""
)
st.title(f"๐ŸŽฏ {selected_sdg_name}: {sdg_goal_text} ์ •์ฑ… ๊ฒฐ์ • ์‹œ๋ฎฌ๋ ˆ์ด์…˜")
if not st.session_state["current_sdg_scenario"]:
if st.button("์‹œ๋‚˜๋ฆฌ์˜ค ์ƒ์„ฑ", use_container_width=True):
with st.spinner(f"{selected_sdg_name} ์‹œ๋‚˜๋ฆฌ์˜ค ์ƒ์„ฑ ์ค‘..."):
scenario = generate_sdg_scenario(selected_sdg_name, sdg_goal_text)
st.session_state["current_sdg_scenario"] = scenario
st.session_state["policy_options"] = None # ์‹œ๋‚˜๋ฆฌ์˜ค ์ƒˆ๋กœ ์ƒ์„ฑ์‹œ ์˜ต์…˜ ์ดˆ๊ธฐํ™”
st.session_state["policy_result"] = None # ์‹œ๋‚˜๋ฆฌ์˜ค ์ƒˆ๋กœ ์ƒ์„ฑ์‹œ ๊ฒฐ๊ณผ ์ดˆ๊ธฐํ™”
st.session_state["user_policy_option"] = "" # ์‹œ๋‚˜๋ฆฌ์˜ค ์ƒˆ๋กœ ์ƒ์„ฑ์‹œ ์‚ฌ์šฉ์ž ์ž…๋ ฅ ์˜ต์…˜ ์ดˆ๊ธฐํ™”
st.rerun() # rerun to display scenario immediately
else:
st.subheader("๐Ÿ“œ ์‹œ๋‚˜๋ฆฌ์˜ค")
st.info(st.session_state["current_sdg_scenario"])
if st.session_state["current_sdg_scenario"] and not st.session_state["policy_options"]:
if st.button("์ •์ฑ… ์˜ต์…˜ ์ƒ์„ฑ", use_container_width=True):
with st.spinner("์ •์ฑ… ์˜ต์…˜ ์ƒ์„ฑ ์ค‘..."):
policy_options = generate_policy_options(st.session_state["current_sdg_scenario"])
st.session_state["policy_options"] = policy_options
st.session_state["policy_result"] = None # ์˜ต์…˜ ์ƒˆ๋กœ ์ƒ์„ฑ์‹œ ๊ฒฐ๊ณผ ์ดˆ๊ธฐํ™”
st.session_state["user_policy_option"] = "" # ์˜ต์…˜ ์ƒˆ๋กœ ์ƒ์„ฑ์‹œ ์‚ฌ์šฉ์ž ์ž…๋ ฅ ์˜ต์…˜ ์ดˆ๊ธฐํ™”
st.rerun() # rerun to display options immediately
if st.session_state["policy_options"]:
st.subheader("โš™๏ธ ์ •์ฑ… ์˜ต์…˜ ์„ ํƒ")
policy_option_keys = list(st.session_state["policy_options"].keys())
policy_option_keys_with_input = ["์ง์ ‘ ์ž…๋ ฅ"] + policy_option_keys # "์ง์ ‘ ์ž…๋ ฅ" ์˜ต์…˜ ์ถ”๊ฐ€
selected_option_key = st.radio("์ •์ฑ… ์˜ต์…˜์„ ์„ ํƒํ•˜์„ธ์š”:", policy_option_keys_with_input)
if selected_option_key == "์ง์ ‘ ์ž…๋ ฅ": # "์ง์ ‘ ์ž…๋ ฅ" ์„ ํƒ ์‹œ ํ…์ŠคํŠธ ์ž…๋ ฅ ์ฐฝ ํ‘œ์‹œ
user_input_option = st.text_area("์ง์ ‘ ์ •์ฑ… ์˜ต์…˜ ์ž…๋ ฅ:", value=st.session_state["user_policy_option"])
st.session_state["user_policy_option"] = user_input_option # ์„ธ์…˜ ์ƒํƒœ ์—…๋ฐ์ดํŠธ
selected_option_text = user_input_option # ์ •์ฑ… ๊ฒฐ๊ณผ ์ƒ์„ฑ ์‹œ ์‚ฌ์šฉ์ž ์ž…๋ ฅ ์˜ต์…˜ ์‚ฌ์šฉ
else:
selected_option_text = st.session_state["policy_options"][selected_option_key] # AI ์ƒ์„ฑ ์˜ต์…˜ ์‚ฌ์šฉ
st.info(f"**์„ ํƒํ•œ ์˜ต์…˜ {selected_option_key}:** {selected_option_text}") # AI ์ƒ์„ฑ ์˜ต์…˜ ์ •๋ณด ํ‘œ์‹œ
if st.button("์ •์ฑ… ๊ฒฐ์ • ์‹คํ–‰", use_container_width=True):
with st.spinner("์ •์ฑ… ๊ฒฐ๊ณผ ๋ถ„์„ ์ค‘..."):
policy_result_text, policy_evaluation, points = generate_policy_result(st.session_state["current_sdg_scenario"], selected_option_text)
st.session_state["policy_result"] = (policy_result_text, policy_evaluation, points) # ๊ฒฐ๊ณผ ํŠœํ”Œ๋กœ ์ €์žฅ
st.rerun() # rerun to display result immediately
if st.session_state["policy_result"]:
policy_result_text, policy_evaluation, points = st.session_state["policy_result"] # ๊ฒฐ๊ณผ ํŠœํ”Œ์—์„œ ๊ฐ’ ์ถ”์ถœ
st.subheader("๐Ÿ’ก ์ •์ฑ… ๊ฒฐ๊ณผ")
if policy_evaluation == "positive":
st.success(f"โœ… {policy_result_text}")
elif policy_evaluation == "negative":
st.warning(f"โš ๏ธ {policy_result_text}")
else: # neutral
st.info(f"๐Ÿ˜ {policy_result_text}")
st.markdown(f"ํš๋“ ํฌ์ธํŠธ: โญ **{points}** points ({policy_evaluation} ์ •์ฑ…)") # ํš๋“ ํฌ์ธํŠธ ํ‘œ์‹œ
if st.button("์ƒˆ๋กœ์šด ์‹œ๋‚˜๋ฆฌ์˜ค๋กœ ๋‹ค์‹œํ•˜๊ธฐ", use_container_width=True):
st.session_state["current_sdg_scenario"] = None
st.session_state["policy_options"] = None
st.session_state["policy_result"] = None
st.session_state["user_policy_option"] = "" # ๊ฒฐ๊ณผ ํ™•์ธ ํ›„ ์‚ฌ์šฉ์ž ์ž…๋ ฅ ์˜ต์…˜ ์ดˆ๊ธฐํ™”
st.session_state["points"] += base_points_per_action["retry"] # ์žฌ๋„์ „ ๊ธฐ๋ณธ ํฌ์ธํŠธ ์ฆ๊ฐ€
update_level() # ๋ ˆ๋ฒจ ์—…๋ฐ์ดํŠธ
st.rerun()
if __name__ == "__main__":
main()