Spaces:
Sleeping
Sleeping
Upload app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,432 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
from openpyxl import Workbook
|
| 3 |
+
from openpyxl.styles import Font, Alignment, Border, Side, PatternFill
|
| 4 |
+
from openpyxl.utils import get_column_letter
|
| 5 |
+
from io import BytesIO
|
| 6 |
+
from datetime import date, time
|
| 7 |
+
import sqlite3
|
| 8 |
+
|
| 9 |
+
st.set_page_config(page_title="λ°©λ¬Έλͺ©μ μκΈμ μλ΄μΌμ§ μλμμ±κΈ°", layout="wide")
|
| 10 |
+
|
| 11 |
+
st.title("π λ°©λ¬Έλͺ©μ μκΈμ μλ΄μΌμ§ μλμμ±κΈ° v1")
|
| 12 |
+
st.caption("μλ΄μμ β λ¬Έμ μν© β μμΈ β μ‘°μΉ β κΈμ¬λ°μ β μμ
λ€μ΄λ‘λ")
|
| 13 |
+
st.warning("β οΈ **β» λ³Έ μμ±κΈ°λ ν루 2ν μ΄μ© νλ μ νμ΄ μμ΅λλ€.**")
|
| 14 |
+
|
| 15 |
+
DB_FILE = "usage.db"
|
| 16 |
+
|
| 17 |
+
def init_db():
|
| 18 |
+
conn = sqlite3.connect(DB_FILE)
|
| 19 |
+
cursor = conn.cursor()
|
| 20 |
+
cursor.execute("""
|
| 21 |
+
CREATE TABLE IF NOT EXISTS usage_limit (
|
| 22 |
+
institution TEXT,
|
| 23 |
+
user_id TEXT,
|
| 24 |
+
use_date TEXT,
|
| 25 |
+
count INTEGER,
|
| 26 |
+
PRIMARY KEY (institution, user_id, use_date)
|
| 27 |
+
)
|
| 28 |
+
""")
|
| 29 |
+
conn.commit()
|
| 30 |
+
conn.close()
|
| 31 |
+
|
| 32 |
+
def get_today_usage(institution, user_id):
|
| 33 |
+
if not institution or not user_id:
|
| 34 |
+
return 0
|
| 35 |
+
init_db()
|
| 36 |
+
today_str = date.today().isoformat()
|
| 37 |
+
conn = sqlite3.connect(DB_FILE)
|
| 38 |
+
cursor = conn.cursor()
|
| 39 |
+
cursor.execute(
|
| 40 |
+
"SELECT count FROM usage_limit WHERE institution = ? AND user_id = ? AND use_date = ?",
|
| 41 |
+
(institution.strip(), user_id.strip(), today_str)
|
| 42 |
+
)
|
| 43 |
+
row = cursor.fetchone()
|
| 44 |
+
conn.close()
|
| 45 |
+
return row[0] if row else 0
|
| 46 |
+
|
| 47 |
+
def increase_today_usage(institution, user_id):
|
| 48 |
+
if not institution or not user_id:
|
| 49 |
+
return
|
| 50 |
+
init_db()
|
| 51 |
+
today_str = date.today().isoformat()
|
| 52 |
+
conn = sqlite3.connect(DB_FILE)
|
| 53 |
+
cursor = conn.cursor()
|
| 54 |
+
cursor.execute(
|
| 55 |
+
"SELECT count FROM usage_limit WHERE institution = ? AND user_id = ? AND use_date = ?",
|
| 56 |
+
(institution.strip(), user_id.strip(), today_str)
|
| 57 |
+
)
|
| 58 |
+
row = cursor.fetchone()
|
| 59 |
+
if row:
|
| 60 |
+
cursor.execute(
|
| 61 |
+
"UPDATE usage_limit SET count = count + 1 WHERE institution = ? AND user_id = ? AND use_date = ?",
|
| 62 |
+
(institution.strip(), user_id.strip(), today_str)
|
| 63 |
+
)
|
| 64 |
+
else:
|
| 65 |
+
cursor.execute(
|
| 66 |
+
"INSERT INTO usage_limit (institution, user_id, use_date, count) VALUES (?, ?, ?, 1)",
|
| 67 |
+
(institution.strip(), user_id.strip(), today_str)
|
| 68 |
+
)
|
| 69 |
+
conn.commit()
|
| 70 |
+
conn.close()
|
| 71 |
+
|
| 72 |
+
if "generated_data" not in st.session_state:
|
| 73 |
+
st.session_state.generated_data = None
|
| 74 |
+
|
| 75 |
+
inst_val = st.session_state.get("institution", "").strip()
|
| 76 |
+
user_val = st.session_state.get("user_id", "").strip()
|
| 77 |
+
today_count = get_today_usage(inst_val, user_val)
|
| 78 |
+
|
| 79 |
+
# Sidebar Usage Panel
|
| 80 |
+
st.sidebar.markdown("### π μ¬μ© νλ κ΄λ¦¬")
|
| 81 |
+
if not inst_val or not user_val:
|
| 82 |
+
st.sidebar.warning("β οΈ κΈ°κ΄λͺ
κ³Ό μ¬μ©μ μλ³κ°μ μ
λ ₯ν΄μ£ΌμΈμ.")
|
| 83 |
+
else:
|
| 84 |
+
st.sidebar.write(f"μ€λ μμ± νμ: **{today_count} / 2ν**")
|
| 85 |
+
if today_count >= 2:
|
| 86 |
+
st.sidebar.error("β μμ± νλ μ΄κ³Ό (2/2)")
|
| 87 |
+
else:
|
| 88 |
+
st.sidebar.success(f"β
μμ± κ°λ₯ (λ¨μ νμ: {2 - today_count}ν)")
|
| 89 |
+
|
| 90 |
+
REQUIRED_ITEMS = [
|
| 91 |
+
"μκΈμ μ±λͺ
", "μλ
μμΌ", "μ±λ³", "μ₯κΈ°μμ λ±κΈ", "κ³μ½μΌ/μμμΌ", "λ³ΈμΈλΆλ΄λ₯ ",
|
| 92 |
+
"μλ΄ μΌμ", "μλ΄ κ΅¬λΆ", "μλ΄ μ₯μ", "μλ΄ λ°©λ²", "μλ΄ λμμ μ±λͺ
", "μλ΄μμμ κ΄κ³",
|
| 93 |
+
"κΈ°κ΄ λ΄λΉμ μ§μ±
λ° μ±λͺ
", "λμμ", "μλ΄ λͺ©μ λ° μ¬μ ",
|
| 94 |
+
"μ 체 κΈ°λ₯ μν λ³ν λ° λμ μν", "μΈμ§ κΈ°λ₯ λ° μ¬λ¦¬ μν", "νΌλΆ μν λ° μμ μν",
|
| 95 |
+
"λͺ©μ μ°¨λ/μ₯λΉ μμ μν", "보νΈμμ μμ² μ¬ν",
|
| 96 |
+
"κΈ°κ΄μ μ€λͺ
λ° μλ΄ μ¬ν", "λ¬Έμ ν΄κ²° λλ μ 곡λ μ 보 λ΄μ©", "ν₯ν κΈμ¬ μ 곡 κ³ν",
|
| 97 |
+
"κΈμ¬ λ°μ μ¬λΆ", "μ¬ν μ‘°μΉ λ° λͺ¨λν°λ§ κ³ν", "보νΈμ μ λ¬/곡μ§μ¬ν",
|
| 98 |
+
"μλ΄μ μλͺ
", "λμμ λλ 보νΈμ μλͺ
"
|
| 99 |
+
]
|
| 100 |
+
|
| 101 |
+
AREA_DATA = {
|
| 102 |
+
"λͺ©μ κ±°λΆ/νμ‘°λ": {
|
| 103 |
+
"problems": ["λͺ©μ κ±°λΆ", "νμ κ±°λΆ", "λ¬Όμ λν 곡ν¬μ¬", "νΌλΆ μ μ΄ μλ―Ό", "νΌλ‘κ° νΈμ", "μ€μκΈ° μ리μ λΆμ"],
|
| 104 |
+
"causes": ["μΉλ§€ μΈμ§ μ ν", "μΆμμ λ―Όκ°ν¨", "κ³Όκ±° λΆμ μ κ²½ν", "μ 체 λ
ΈμΆ μμΉμ¬", "νΌλΆ 건쑰 λ° κ°λ €μ", "컨λμ
μ ν"],
|
| 105 |
+
"actions": ["λ°λ»ν μ€λ΄ μ¨λ μ μ§", "μΆ©λΆν μ§μ§μ λν", "νμλ‘ λͺΈμ κ°μΌ μ± μ§ν", "μ νΈνλ μμ
νκΈ°", "κ°νΈμ¬ 곡μ ", "보νΈμ μλ΄"],
|
| 106 |
+
},
|
| 107 |
+
"νΌλΆ μν/λ°μ /μμ²": {
|
| 108 |
+
"problems": ["νΌλΆ 건쑰", "μλ©μ΄ λ°μ ", "κ°λ €μμ¦ νΈμ", "νΌλΆ μ§λ¬΄λ¦", "λ―ΈμΈ μ°°κ³Όμ", "κ°μ§ μ¬ν"],
|
| 109 |
+
"causes": ["νμ‘ μν μ ν", "μ€λ«λμ μμμμ", "κΈ°μ κ· μ₯κΈ° μ°©μ©", "μλΆ μμ·¨ λΆμ‘±", "νΌλΆ μ₯λ²½ μ½ν"],
|
| 110 |
+
"actions": ["λͺ©μ ν 보μ΅μ λν¬", "λ§μ¬μ§ λμ", "νΌλΆ μ μ¬ν κ΄μ°° λ° κΈ°λ‘", "κ°νΈμ¬/보νΈμ λ³΄κ³ ", "κΈ°μ κ· κ΅μ²΄ μ£ΌκΈ° λ¨μΆ κ²ν ", "건쑰 κΈ°λ₯ κ°ν"],
|
| 111 |
+
},
|
| 112 |
+
"체μ¨/λ°μ΄ν λ³ν": {
|
| 113 |
+
"problems": ["λͺ©μ μ ν νμ μμΉ", "λͺ©μ ν νκΈ° νΈμ", "λ―Έμ΄ λ°μ", "μ΄μ§λ¬μ νΈμ", "κΈκ²©ν νΌλ‘κ°"],
|
| 114 |
+
"causes": ["μ€λ΄μΈ μ¨λμ°¨", "μλΆ μμ€", "체λ ₯ μλͺ¨", "μ¨μ μκ·Ή", "κΈ°μ κ±΄κ° μν"],
|
| 115 |
+
"actions": ["λͺ©μ μκ° λ¨μΆ(20~30λΆ μ΄λ΄)", "λͺ©μ ν λ°λ»ν μλ£ μ 곡", "μ²΄μ¨ μμ μΈ‘μ ", "κ°νΈμ¬ λ³΄κ³ λ° μκΈμ‘°μΉ μ€λΉ", "보νΈμ μλ΄"],
|
| 116 |
+
},
|
| 117 |
+
"λμ/μ΄λ λΆμμ ": {
|
| 118 |
+
"problems": ["λ―Έλλ¬μ΄ λ°λ₯ μν", "μμ‘° μΆμ
μ κ· ν μμ€", "λΆμΆ μ μ²΄μ€ μ€λ¦Ό", "ν μ²΄μ΄ μ΄λ μ λΆμμ ", "기립 μ μ΄μ§λ¬μ"],
|
| 119 |
+
"causes": ["νμ§ κ·Όλ ₯ μ½ν", "λ°λ₯ λ¬ΌκΈ° λ° λΉλλ¬Ό", "μΈμ§ κΈ°λ₯ μ ν", "μ΄λ 보쑰기ꡬ λ―ΈλΉ"],
|
| 120 |
+
"actions": ["λ―ΈλλΌ λ°©μ§ λ§€νΈ μΆκ° μ€μΉ", "μμ μμ‘μ΄ νμ© λ³΄μ‘°", "λͺ©μ μμ μμ μ¬μ©", "μ΄λ 보쑰 μΈλ ₯ 2μΈ νμ‘°", "μμ μμΉ κ΅μ‘"],
|
| 121 |
+
},
|
| 122 |
+
"μμ/μΌλ° 건κ°μν": {
|
| 123 |
+
"problems": ["λνΌ κ°μ§/λΉλ¬", "μλ°ν± κ΄λ¦¬ νμ", "λ°°μ€λ¬Ό μ€μΌ", "κ΅¬κ° μμ λΆλ", "체취 μ¬ν"],
|
| 124 |
+
"causes": ["κ°μΈμμ κ΄λ¦¬ λΆμ‘±", "μΈμ§ μ νλ‘ μμ κ±°λΆ", "μ 체 λμ λ²μ μ ν"],
|
| 125 |
+
"actions": ["λνΌ μ§μ€ μΈμ ", "λͺ©μ ν μλ°ν± μ 리", "μμ κ°μ΄λ μ μ©", "κ΅¬κ° μΌμ΄ λ³ν", "μ²κ²° μ©ν μ νΈλ μ‘°μ¬"],
|
| 126 |
+
},
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
def make_sentence(area, problems, causes, actions, age, grade, mobility, cognition):
|
| 130 |
+
problem_text = ", ".join(problems)
|
| 131 |
+
cause_text = ", ".join(causes)
|
| 132 |
+
action_text = ", ".join(actions)
|
| 133 |
+
|
| 134 |
+
consult = (
|
| 135 |
+
f"μκΈμλ λ§ {age}μΈ, μ₯κΈ°μμ {grade}μ΄λ©° νμ¬ μ΄λμνλ '{mobility}', μΈμ§μνλ '{cognition}'μΌλ‘ νμΈλλ€.\n\n"
|
| 136 |
+
f"λ°©λ¬Έλͺ©μ κΈμ¬μ 곡 κ³Όμ λ° {area} κ΄λ ¨ μλ΄μ μ€μν κ²°κ³Ό, μ£Όμ λ¬Έμ μν©μΌλ‘ {problem_text}μ΄/κ° νμΈλμλ€. "
|
| 137 |
+
f"λͺ©μ μλΉμ€ μ§ν μ μκΈμμ νμ¬ μ 체μ κ°λ λ²μ, μΈμ§ λ₯λ ₯, μ¬λ¦¬ μνμ λ°λ₯Έ μΈλΆ κ΄μ°°μ΄ μλ§λλ€.\n\n"
|
| 138 |
+
f"μλ΄ κ³Όμ μμ {cause_text} λ±μ΄ μμΈμΌλ‘ μμ©ν κ°λ₯μ±μ νμΈνμλ€. "
|
| 139 |
+
f"κΈ°κ΄μμλ λͺ©μ μ€ κΈκ²©ν 체λ ₯ μ νλ νμ λ³νκ° λ°μνλμ§ μμ μ£ΌμνκΈ°λ‘ νμλ€."
|
| 140 |
+
)
|
| 141 |
+
|
| 142 |
+
action = (
|
| 143 |
+
f"λ°©λ¬Έλͺ©μ μ§ν μ μκΈμμ μꡬμ μνμ λ§μΆμ΄ {action_text} λ±μ μ‘°μΉλ₯Ό μ€μνκ±°λ κ³ννκΈ°λ‘ νμλ€. "
|
| 144 |
+
f"λͺ©μ μμ보νΈμ¬ λ° λν μ§μμκ² μΈλΆ μ‘°μΉ μ¬νμ μ ννκ³ μμ ν κΈμ¬ μ κ³΅μ΄ μ΄λ£¨μ΄μ§λλ‘ μ‘°μΉνμλ€.\n\n"
|
| 145 |
+
f"ν₯ν λͺ©μ κ±°λΆλ λμ μν λ± νΉμ΄μ¬ν μ§μ μ μꡬμ¬μ μ λ°μνκ³ , νμ μ λ°©λ¬Έμμ/κ°νΈ μλΉμ€ μ°κ³λ₯Ό κ²ν νκΈ°λ‘ νμλ€."
|
| 146 |
+
)
|
| 147 |
+
|
| 148 |
+
reflection = (
|
| 149 |
+
"μλ΄μ ν΅ν΄ νμΈλ μꡬμ¬ν λ° μ‘°μΉ κ³νμ μ₯κΈ°μμ κΈμ¬μ 곡 κ³Όμ μ μ κ·Ή λ°μνλ€. "
|
| 150 |
+
"λ°μ κ°λ₯ν μΈλΆ μ¬νμ λ€μ λ°©λ¬Έλͺ©μ μΌμ μ μ μ©νκ³ , "
|
| 151 |
+
"μ₯κΈ°μμκΈ°κ΄ νκ° κ³ μ κΈ°μ€μ λ§μΆμ΄ κΈμ¬μ 곡κ³νμ 보μμ κ²ν νκΈ°λ‘ νλ€."
|
| 152 |
+
)
|
| 153 |
+
|
| 154 |
+
monitoring = (
|
| 155 |
+
"λͺ©μ λ΄λΉ μμ보νΈμ¬μ μλΉμ€ ν νΌλλ°± λ° νΌλΆ/λ°μ΄ν λͺ¨λν°λ§ κΈ°λ‘μ μ£Ό 1ν μ΄μ κ²ν νλ€. "
|
| 156 |
+
"λ€μ μλ΄ μ λ¬Έμ μν©μ κ²½κ° μ¬λΆμ μ‘°μΉμ ν¨κ³Όμ±μ λͺ¨λν°λ§νμ¬ μ§μμ μΈ μμ κ΄λ¦¬λ₯Ό μ€μνκΈ°λ‘ νλ€."
|
| 157 |
+
)
|
| 158 |
+
|
| 159 |
+
return consult, action, reflection, monitoring
|
| 160 |
+
|
| 161 |
+
def make_excel(data, consult, action, reflection, monitoring, checked_items, missing_items):
|
| 162 |
+
wb = Workbook()
|
| 163 |
+
ws = wb.active
|
| 164 |
+
ws.title = "μκΈμ μλ΄μΌμ§"
|
| 165 |
+
|
| 166 |
+
thin = Side(style="thin", color="000000")
|
| 167 |
+
border = Border(left=thin, right=thin, top=thin, bottom=thin)
|
| 168 |
+
header_fill = PatternFill("solid", fgColor="EAF2F8") # Soft blue
|
| 169 |
+
|
| 170 |
+
for col in range(1, 10):
|
| 171 |
+
ws.column_dimensions[get_column_letter(col)].width = 15
|
| 172 |
+
|
| 173 |
+
current_row = 1
|
| 174 |
+
|
| 175 |
+
ws.merge_cells(start_row=current_row, start_column=1, end_row=current_row, end_column=9)
|
| 176 |
+
ws.cell(current_row, 1).value = f"( {data['κΈ°κ΄λͺ
']} ) λ°©λ¬Έλͺ©μ μλ΄μΌμ§"
|
| 177 |
+
ws.cell(current_row, 1).font = Font(bold=True, size=20)
|
| 178 |
+
ws.cell(current_row, 1).alignment = Alignment(horizontal="center", vertical="center")
|
| 179 |
+
ws.row_dimensions[current_row].height = 36
|
| 180 |
+
current_row += 1
|
| 181 |
+
|
| 182 |
+
info_rows = [
|
| 183 |
+
("μκΈμ μ±λͺ
", data["μκΈμ μ±λͺ
"], "μλ
μμΌ", data["μλ
μμΌ"], "μ±λ³", data["μ±λ³"]),
|
| 184 |
+
("λμ΄", data["λμ΄"], "μ₯κΈ°μμ λ±κΈ", data["μ₯κΈ°μμ λ±κΈ"], "μμμΌ", str(data["μμμΌ"])),
|
| 185 |
+
("λ³ΈμΈλΆλ΄λ₯ ", data["λ³ΈμΈλΆλ΄λ₯ "], "μλ΄μΌμ", str(data["μλ΄μΌμ"]), "μλ΄μκ°", str(data["μλ΄μκ°"])),
|
| 186 |
+
("μλ΄κ΅¬λΆ", data["μλ΄κ΅¬λΆ"], "μλ΄μ₯μ", data["μοΏ½οΏ½μ₯μ"], "μλ΄λ°©λ²", data["μλ΄λ°©λ²"]),
|
| 187 |
+
("μλ΄λμμ", data["μλ΄λμμ"], "κ΄κ³", data["κ΄κ³"], "λμμ", data["λμμ"]),
|
| 188 |
+
("λ΄λΉμ", data["λ΄λΉμ"], "μ§μ±
", data["μ§μ±
"], "μλ΄μμ", data["μλ΄μμ"]),
|
| 189 |
+
("μ΄λμν", data["μ΄λμν"], "μΈμ§μν", data["μΈμ§μν"], "λͺ©μμ ν", data["λͺ©μμ ν"]),
|
| 190 |
+
]
|
| 191 |
+
|
| 192 |
+
for row_data in info_rows:
|
| 193 |
+
ws.cell(current_row, 1).value = row_data[0]
|
| 194 |
+
ws.merge_cells(start_row=current_row, start_column=2, end_row=current_row, end_column=3)
|
| 195 |
+
ws.cell(current_row, 2).value = row_data[1]
|
| 196 |
+
ws.cell(current_row, 4).value = row_data[2]
|
| 197 |
+
ws.merge_cells(start_row=current_row, start_column=5, end_row=current_row, end_column=6)
|
| 198 |
+
ws.cell(current_row, 5).value = row_data[3]
|
| 199 |
+
ws.cell(current_row, 7).value = row_data[4]
|
| 200 |
+
ws.merge_cells(start_row=current_row, start_column=8, end_row=current_row, end_column=9)
|
| 201 |
+
ws.cell(current_row, 8).value = row_data[5]
|
| 202 |
+
|
| 203 |
+
for col in [1, 4, 7]:
|
| 204 |
+
ws.cell(current_row, col).fill = header_fill
|
| 205 |
+
ws.cell(current_row, col).font = Font(bold=True)
|
| 206 |
+
ws.cell(current_row, col).alignment = Alignment(horizontal="center", vertical="center")
|
| 207 |
+
current_row += 1
|
| 208 |
+
|
| 209 |
+
sections = [
|
| 210 |
+
("μλ΄ λ΄μ© (μκΈμ μν λ³ν λ° μꡬμ¬ν)", consult, 3),
|
| 211 |
+
("μ‘°μΉ λ° ν΄κ²° κ³ν", action, 3),
|
| 212 |
+
("κΈμ¬μ 곡κ³ν λ°μ λ΄μ©", reflection, 3),
|
| 213 |
+
("μ¬ν μ‘°μΉ λ° λͺ¨λν°λ§ κ³ν", monitoring, 3),
|
| 214 |
+
]
|
| 215 |
+
|
| 216 |
+
for title, text, height in sections:
|
| 217 |
+
ws.merge_cells(start_row=current_row, start_column=1, end_row=current_row, end_column=9)
|
| 218 |
+
ws.cell(current_row, 1).value = title
|
| 219 |
+
ws.cell(current_row, 1).fill = header_fill
|
| 220 |
+
ws.cell(current_row, 1).font = Font(bold=True)
|
| 221 |
+
ws.cell(current_row, 1).alignment = Alignment(horizontal="center")
|
| 222 |
+
current_row += 1
|
| 223 |
+
|
| 224 |
+
ws.merge_cells(start_row=current_row, start_column=1, end_row=current_row + height - 1, end_column=9)
|
| 225 |
+
ws.cell(current_row, 1).value = text
|
| 226 |
+
ws.cell(current_row, 1).alignment = Alignment(horizontal="left", vertical="top", wrap_text=True)
|
| 227 |
+
|
| 228 |
+
# ν
μ€νΈ κΈΈμ΄μ λ°λΌ λμ΄λ₯Ό λμ μΌλ‘ μλ κ³μ°νμ¬ 3κ° νμ λλμ΄ λ°°μ
|
| 229 |
+
lines = len(text) // 65 + 1 + text.count('\n') if text else 1
|
| 230 |
+
total_height = max(72, lines * 20 + 10)
|
| 231 |
+
single_row_height = total_height / height
|
| 232 |
+
for r_offset in range(height):
|
| 233 |
+
ws.row_dimensions[current_row + r_offset].height = single_row_height
|
| 234 |
+
|
| 235 |
+
current_row += height
|
| 236 |
+
|
| 237 |
+
ws.merge_cells(start_row=current_row, start_column=1, end_row=current_row, end_column=3)
|
| 238 |
+
ws.merge_cells(start_row=current_row, start_column=4, end_row=current_row, end_column=6)
|
| 239 |
+
ws.merge_cells(start_row=current_row, start_column=7, end_row=current_row, end_column=9)
|
| 240 |
+
|
| 241 |
+
ws.cell(current_row, 1).value = "μλ΄μ μλͺ
"
|
| 242 |
+
ws.cell(current_row, 4).value = f"{data['λ΄λΉμ']} (μλͺ
)"
|
| 243 |
+
ws.cell(current_row, 7).value = "λμμ/보νΈμ (μλͺ
)"
|
| 244 |
+
ws.cell(current_row, 1).fill = header_fill
|
| 245 |
+
ws.cell(current_row, 7).fill = header_fill
|
| 246 |
+
|
| 247 |
+
max_row = current_row
|
| 248 |
+
|
| 249 |
+
for row in ws.iter_rows(min_row=1, max_row=max_row, min_col=1, max_col=9):
|
| 250 |
+
for cell in row:
|
| 251 |
+
cell.border = border
|
| 252 |
+
cell.alignment = Alignment(
|
| 253 |
+
horizontal=cell.alignment.horizontal or "left",
|
| 254 |
+
vertical=cell.alignment.vertical or "center",
|
| 255 |
+
wrap_text=True
|
| 256 |
+
)
|
| 257 |
+
|
| 258 |
+
for r in range(1, max_row + 1):
|
| 259 |
+
if ws.row_dimensions[r].height is None:
|
| 260 |
+
ws.row_dimensions[r].height = 24
|
| 261 |
+
|
| 262 |
+
ws.page_setup.paperSize = ws.PAPERSIZE_A4
|
| 263 |
+
ws.page_setup.orientation = "portrait"
|
| 264 |
+
ws.page_setup.fitToWidth = 1
|
| 265 |
+
ws.page_setup.fitToHeight = 0
|
| 266 |
+
ws.sheet_properties.pageSetUpPr.fitToPage = True
|
| 267 |
+
|
| 268 |
+
ws.page_margins.left = 0.3
|
| 269 |
+
ws.page_margins.right = 0.3
|
| 270 |
+
ws.page_margins.top = 0.4
|
| 271 |
+
ws.page_margins.bottom = 0.4
|
| 272 |
+
ws.print_options.horizontalCentered = True
|
| 273 |
+
|
| 274 |
+
output = BytesIO()
|
| 275 |
+
wb.save(output)
|
| 276 |
+
output.seek(0)
|
| 277 |
+
return output
|
| 278 |
+
|
| 279 |
+
col1, col2, col3 = st.columns(3)
|
| 280 |
+
|
| 281 |
+
with col1:
|
| 282 |
+
facility = st.text_input("κΈ°κ΄λͺ
", value="BeeCare μ¬κ°λ³΅μ§μΌν°", key="institution")
|
| 283 |
+
user_id = st.text_input("μ¬μ©μ μλ³κ° (μ: ν΄λν°λ²νΈ λ·μ리 λ±)", value="", key="user_id", help="ν루 2ν μ ν κ΄λ¦¬λ₯Ό μν΄ μ¬μ©λ©λλ€.")
|
| 284 |
+
name = st.text_input("μκΈμ μ±λͺ
", "μ΄κΈΈμ")
|
| 285 |
+
birth = st.text_input("μλ
μμΌ", "1945-05-15")
|
| 286 |
+
gender = st.selectbox("μ±λ³", ["μ¬", "λ¨"])
|
| 287 |
+
age = st.number_input("λμ΄", min_value=60, max_value=110, value=81)
|
| 288 |
+
|
| 289 |
+
with col2:
|
| 290 |
+
grade = st.selectbox("μ₯κΈ°μμ λ±κΈ", ["1λ±κΈ", "2λ±κΈ", "3λ±κΈ", "4λ±κΈ", "5λ±κΈ"])
|
| 291 |
+
admission_date = st.date_input("κ³μ½μΌ/μμμΌ", date.today())
|
| 292 |
+
copay = st.selectbox("λ³ΈμΈλΆλ΄οΏ½οΏ½οΏ½", ["15%", "0%", "6%", "9%", "12%", "20%"])
|
| 293 |
+
consult_date = st.date_input("μλ΄μΌμ", date.today())
|
| 294 |
+
|
| 295 |
+
with col3:
|
| 296 |
+
consult_time = st.time_input("μλ΄μκ°", time(14, 0))
|
| 297 |
+
consult_type = st.selectbox("μλ΄ κ΅¬λΆ", ["μ κΈ° μλ΄", "μμ μλ΄", "μ κ· κ³μ½ μλ΄", "보νΈμ μμ² μλ΄"])
|
| 298 |
+
place = st.selectbox("μλ΄ μ₯μ", ["μκΈμ μν", "μΌν° μ¬λ¬΄μ€", "μ μ μλ΄", "κΈ°ν"])
|
| 299 |
+
method = st.selectbox("μλ΄ λ°©λ²", ["λλ©΄ λ©΄λ΄", "μ μ /μ ν μλ΄", "κΈ°ν"])
|
| 300 |
+
target = st.text_input("μλ΄ λμμ μ±λͺ
", "μλ
")
|
| 301 |
+
|
| 302 |
+
col4, col5, col6 = st.columns(3)
|
| 303 |
+
|
| 304 |
+
with col4:
|
| 305 |
+
relation = st.selectbox("μλ΄μμμ κ΄κ³", ["λΈ", "μλ€", "λ³ΈμΈ", "λ°°μ°μ", "λ©°λ리", "μ¬μ", "κΈ°ν"])
|
| 306 |
+
staff_position = st.selectbox("κΈ°κ΄ λ΄λΉμ μ§μ±
", ["μ¬ν볡μ§μ¬", "μμ보νΈμ¬", "κ°νΈμ¬", "μμ€μ₯"])
|
| 307 |
+
staff_name = st.text_input("κΈ°κ΄ λ΄λΉμ μ±λͺ
", "μ¬ν볡μ§μ¬")
|
| 308 |
+
|
| 309 |
+
with col5:
|
| 310 |
+
companion = st.text_input("λμμ", "μμ")
|
| 311 |
+
mobility = st.selectbox("μ΄λμν", ["λΆμΆ νμ", "λ
립보ν", "μ§ν‘μ΄ λ³΄ν", "μ컀 보ν", "ν μ²΄μ΄ μ΄λ", "μμ μν"])
|
| 312 |
+
cognition = st.selectbox("μΈμ§μν", ["κ²½λ μΉλ§€", "μΈμ§ μνΈ", "μ€λ±λ μΉλ§€", "μ€μ¦ μΉλ§€", "μμ¬μν΅ μ΄λ €μ"])
|
| 313 |
+
|
| 314 |
+
with col6:
|
| 315 |
+
bath_type = st.selectbox("λͺ©μμ ν", ["λ°©λ¬Έλͺ©μ(μ°¨λλ΄)", "λ°©λ¬Έλͺ©μ(κ°μ λ΄μμ‘°)", "κ°μ λ΄μ€μλμ", "κΈ°ν"])
|
| 316 |
+
area = st.selectbox("μλ΄μμ μ ν", list(AREA_DATA.keys()))
|
| 317 |
+
|
| 318 |
+
# --- GENERATION FLOW WITH EXPLICIT LIMIT LIMITATION ---
|
| 319 |
+
st.markdown("---")
|
| 320 |
+
|
| 321 |
+
is_inputs_filled = bool(facility.strip() and user_id.strip())
|
| 322 |
+
today_count = get_today_usage(facility, user_id) if is_inputs_filled else 0
|
| 323 |
+
can_generate = is_inputs_filled and (today_count < 2)
|
| 324 |
+
|
| 325 |
+
if not is_inputs_filled:
|
| 326 |
+
st.warning("β οΈ μμ± κΈ°λ₯μ μ΄μ©νμλ €λ©΄ μλ¨ μ
λ ₯μ°½μμ [κΈ°κ΄λͺ
]κ³Ό [μ¬μ©μ μλ³κ°]μ μ νν μ
λ ₯ν΄ μ£ΌμΈμ.")
|
| 327 |
+
elif today_count >= 2:
|
| 328 |
+
st.error("π¨ μ€λ μ¬μ© κ°λ₯ νμ(2ν)λ₯Ό λͺ¨λ μ¬μ©νμ΅λλ€. μλ‘μ΄ λ¬Έμ μμ±μ λΆκ°νλ©°, μλ κΈ°μ‘΄ μμ±λ λ¬Έμμ μμ λ° λ€μ΄λ‘λλ§ κ°λ₯ν©λλ€.")
|
| 329 |
+
|
| 330 |
+
checked_items = []
|
| 331 |
+
st.subheader("νμ κΈ°μ¬νλͺ© 체ν¬λ¦¬μ€νΈ")
|
| 332 |
+
for item in REQUIRED_ITEMS:
|
| 333 |
+
if st.checkbox(item, value=True, key=f"check_{item}"):
|
| 334 |
+
checked_items.append(item)
|
| 335 |
+
|
| 336 |
+
missing_items = [item for item in REQUIRED_ITEMS if item not in checked_items]
|
| 337 |
+
score = int((len(checked_items) / len(REQUIRED_ITEMS)) * 100)
|
| 338 |
+
|
| 339 |
+
if score == 100:
|
| 340 |
+
st.success(f"μλ΄μΌμ§ μμ±λ: {score}μ / λλ½ νλͺ© μμ")
|
| 341 |
+
elif score >= 85:
|
| 342 |
+
st.warning(f"μλ΄μΌμ§ μμ±λ: {score}μ / μΌλΆ νλͺ© νμΈ νμ")
|
| 343 |
+
else:
|
| 344 |
+
st.error(f"μλ΄μΌμ§ μμ±λ: {score}μ / νμνλͺ© 보μ νμ")
|
| 345 |
+
|
| 346 |
+
data = {
|
| 347 |
+
"κΈ°κ΄λͺ
": facility,
|
| 348 |
+
"μκΈμ μ±λͺ
": name,
|
| 349 |
+
"μλ
μμΌ": birth,
|
| 350 |
+
"μ±λ³": gender,
|
| 351 |
+
"λμ΄": age,
|
| 352 |
+
"μ₯κΈ°μμ λ±κΈ": grade,
|
| 353 |
+
"μμμΌ": admission_date,
|
| 354 |
+
"λ³ΈμΈλΆλ΄λ₯ ": copay,
|
| 355 |
+
"μλ΄μΌμ": consult_date,
|
| 356 |
+
"μλ΄μκ°": consult_time,
|
| 357 |
+
"μλ΄κ΅¬λΆ": consult_type,
|
| 358 |
+
"μλ΄μ₯μ": place,
|
| 359 |
+
"μλ΄λ°©λ²": method,
|
| 360 |
+
"μλ΄λμμ": target,
|
| 361 |
+
"κ΄κ³": relation,
|
| 362 |
+
"λ΄λΉμ": staff_name,
|
| 363 |
+
"μ§μ±
": staff_position,
|
| 364 |
+
"λμμ": companion,
|
| 365 |
+
"μλ΄μμ": area,
|
| 366 |
+
"μ΄λμν": mobility,
|
| 367 |
+
"μΈμ§μν": cognition,
|
| 368 |
+
"λͺ©μμ ν": bath_type,
|
| 369 |
+
}
|
| 370 |
+
|
| 371 |
+
if st.button("π μλ΄μΌμ§ & μμ
μμ±νκΈ°", disabled=not can_generate):
|
| 372 |
+
if not is_inputs_filled:
|
| 373 |
+
st.error("κΈ°κ΄λͺ
κ³Ό μ¬μ©μ μλ³κ°μ μ
λ ₯ν΄μΌ μμ±ν μ μμ΅λλ€.")
|
| 374 |
+
st.stop()
|
| 375 |
+
|
| 376 |
+
if today_count >= 2:
|
| 377 |
+
st.error("μ€λ μ¬μ© κ°λ₯ νμλ₯Ό λͺ¨λ μ¬μ©νμ΅λλ€.")
|
| 378 |
+
st.stop()
|
| 379 |
+
|
| 380 |
+
# μμ± μ±κ³΅ μ DBμ νμ μΆκ°
|
| 381 |
+
increase_today_usage(facility, user_id)
|
| 382 |
+
|
| 383 |
+
# ν
μ€νΈ μλ μμ±
|
| 384 |
+
gen_consult, gen_action, gen_reflection, gen_monitoring = make_sentence(
|
| 385 |
+
area, problems, causes, actions, age, grade, mobility, cognition
|
| 386 |
+
)
|
| 387 |
+
|
| 388 |
+
st.session_state.generated_data = {
|
| 389 |
+
"consult": gen_consult,
|
| 390 |
+
"action": gen_action,
|
| 391 |
+
"reflection": gen_reflection,
|
| 392 |
+
"monitoring": gen_monitoring,
|
| 393 |
+
"data": data,
|
| 394 |
+
"checked_items": checked_items,
|
| 395 |
+
"missing_items": missing_items
|
| 396 |
+
}
|
| 397 |
+
st.success("π μλ΄μΌμ§κ° μ±κ³΅μ μΌλ‘ μμ±λμμ΅λλ€! μλμμ λ΄μ©μ νμΈ λ° μμ ν ν μμ
νμΌμ λ€μ΄λ‘λνμΈμ.")
|
| 398 |
+
st.rerun()
|
| 399 |
+
|
| 400 |
+
# μμ±λ λ°μ΄ν°κ° μμ κ²½μ°μλ§ νλ λ° λ€μ΄λ‘λ μ 곡
|
| 401 |
+
if st.session_state.generated_data is not None:
|
| 402 |
+
g_data = st.session_state.generated_data
|
| 403 |
+
|
| 404 |
+
st.subheader("μλ΄ λ΄μ©")
|
| 405 |
+
ui_consult = st.text_area("μλ΄λ΄μ© μμ κ°λ₯", g_data["consult"], height=220)
|
| 406 |
+
|
| 407 |
+
st.subheader("μ‘°μΉ λ΄μ©")
|
| 408 |
+
ui_action = st.text_area("μ‘°μΉλ΄μ© μμ κ°λ₯", g_data["action"], height=180)
|
| 409 |
+
|
| 410 |
+
st.subheader("κΈμ¬μ 곡 λ°μ μ¬λΆ")
|
| 411 |
+
ui_reflection = st.text_area("κΈμ¬μ 곡 λ°μ λ΄μ© μμ κ°λ₯", g_data["reflection"], height=130)
|
| 412 |
+
|
| 413 |
+
st.subheader("μ¬ν μ‘°μΉ λ° λͺ¨λν°λ§ κ³ν")
|
| 414 |
+
ui_monitoring = st.text_area("λͺ¨λν°λ§ κ³ν μμ κ°λ₯", g_data["monitoring"], height=130)
|
| 415 |
+
|
| 416 |
+
# μμ λ λ΄μ©μΌλ‘ μμ
λΉλ
|
| 417 |
+
excel_file = make_excel(
|
| 418 |
+
g_data["data"],
|
| 419 |
+
ui_consult,
|
| 420 |
+
ui_action,
|
| 421 |
+
ui_reflection,
|
| 422 |
+
ui_monitoring,
|
| 423 |
+
g_data["checked_items"],
|
| 424 |
+
g_data["missing_items"]
|
| 425 |
+
)
|
| 426 |
+
|
| 427 |
+
st.download_button(
|
| 428 |
+
label="π₯ μκΈμ μλ΄μΌμ§ μμ
λ€μ΄λ‘λ",
|
| 429 |
+
data=excel_file,
|
| 430 |
+
file_name=f"{g_data['data']['μκΈμ μ±λͺ
']}_{g_data['data']['μλ΄μμ']}_μκΈμμλ΄μΌμ§.xlsx",
|
| 431 |
+
mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
| 432 |
+
)
|