MOAI / css.py
wenbemi
Upload 13 files
78b06b9 verified
raw
history blame
4.36 kB
import streamlit as st
import streamlit.components.v1 as components
import re
import uuid
import pandas as pd
# ────────────────── 말풍선 생성 ν•¨μˆ˜
# 색상 μ •μ˜
PRIMARY_USER = "#e2f6e8"
PRIMARY_BOT = "#f6f6f6"
def render_message(
message: str,
sender: str = "bot",
chips: list[str] | None = None,
key: str | None = None,
) -> str | None:
"""
- `message` : ν‘œμ‹œν•  ν…μŠ€νŠΈ (HTML ν—ˆμš©)
- `sender` : "user" | "bot"
- `chips` : λ²„νŠΌ ν˜•νƒœλ‘œ 보여 쀄 λ¬Έμžμ—΄ 리슀트
- return : μ‚¬μš©μžκ°€ ν΄λ¦­ν•œ μΉ©(λ¬Έμžμ—΄) λ˜λŠ” None
"""
# 1) 말풍선 κΈ°λ³Έ 속성
color = PRIMARY_USER if sender == "user" else PRIMARY_BOT
align = "right" if sender == "user" else "left"
# κ°œν–‰ κΌ¬λ¦¬ν‘œ 제거
message = str(message).rstrip()
# 2) 풍선 좜λ ₯
st.markdown(
f'''<div style="text-align:{align}; margin:6px 0;">
<p style = "font-size:13px;"></p>
<span style="background:{color}; padding:10px 14px; border-radius:12px;
display:inline-block; max-width:80%; font-size:13px; line-height:1.45;
word-break:break-word; ">{message}</span>
</div>''',
unsafe_allow_html=True,
)
# 3) μΉ© λ²„νŠΌμ΄ μžˆμ„ 경우
if chips:
prefix = f"{key or 'chips'}_{abs(hash(message))}"
clicked = render_chip_buttons(chips, key_prefix=prefix)
return clicked
return None
# ────────────────── μΉ©λ²„νŠΌ 생성 ν•¨μˆ˜
def render_chip_buttons(options, key_prefix="chip", selected_value=None):
def slugify(text):
return re.sub(r"[^a-zA-Z0-9]+", "-", str(text)).strip("-").lower() or "empty"
session_key = f"{key_prefix}_selected"
selected_value = st.session_state.get(session_key)
# μŠ€νƒ€μΌ 적용
st.markdown(f"""
<style>
div[data-testid="stHorizontalBlock"]{{
display:block !important;
}}
button[data-testid="stBaseButton-secondary"] {{
background-color: white;
border: 1px solid #e3e8e7;
border-radius: 20px;
padding: 6px 14px;
font-size: 14px;
cursor: pointer;
transition: 0.2s ease-in-out;
margin-bottom: -2px;
width: 230px;
text-align:center;
}}
button[data-testid="stBaseButton-secondary"]:hover {{
background-color: #e8f0ef;
border-color: #009c75;
color: #009c75;
}}
button[data-testid="baseButton-secondary"][disabled]{{
background-color: white;
border-color: #009c75; !important;
color: #009c75; !important;
}}
</style>
""", unsafe_allow_html=True)
clicked_val = None
#cols = st.columns(len(options))
for idx, opt in enumerate(options):
if opt is None or (isinstance(opt, float) and pd.isna(opt)) or str(opt).strip()=="":
continue
is_selected = (opt == selected_value)
is_refresh_btn = "λ‹€λ₯Έ μ—¬ν–‰μ§€ 보기" in str(opt)
disabled = (opt == selected_value) and not is_refresh_btn
label = f"{opt}" if is_selected else opt
# stable key
safe_opt = slugify(opt)
stable_key = f"{key_prefix}_{idx}_{safe_opt}"
if st.button(label, key=stable_key, disabled=disabled):
clicked_val = opt
return clicked_val
# ────────────────── λ©”μ‹œμ§€ λ¦¬ν”Œλ ˆμ΄ ν•¨μˆ˜
def replay_log(chat_container=None):
with chat_container:
for sender, msg in st.session_state.chat_log:
render_message(msg, sender=sender)
# ────────────────── λ©”μ‹œμ§€ λ‘œκΉ…&생성 ν•¨μˆ˜
def log_and_render(msg, sender, chat_container=None, key=None, chips=None):
# 쀑볡 λ°©μ§€ 둜직
sent_once = st.session_state.setdefault("sent_once", {})
if key and sent_once.get(key):
return
if key:
sent_once[key] = True
if st.session_state.chat_log and st.session_state.chat_log[-1] == (sender, msg):
return
# λ‘œκ·Έμ— μ €μž₯
st.session_state.chat_log.append((sender, msg))
# λ©”μ‹œμ§€ 좜λ ₯
with chat_container:
rendered = render_message(msg, sender=sender, chips=chips, key=key)
return rendered