wellog / src /streamlit_app.py
cksleigen's picture
Update src/streamlit_app.py
92f8d84 verified
import streamlit as st
import base64
import os
# 1. ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ ์„ค์ • (app.py์™€ ๊ฐ™์€ ์œ„์น˜์— img ํด๋”๊ฐ€ ์žˆ์–ด์•ผ ํ•จ)
IMG_PATH = "src/img/mic.png"
# 2. ์ด๋ฏธ์ง€๋ฅผ Base64 ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜
def get_image_base64(path):
if os.path.exists(path):
with open(path, "rb") as f:
data = f.read()
return base64.b64encode(data).decode()
return None
# ์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹œ๋„
mic_icon_base64 = get_image_base64(IMG_PATH)
# ์ด๋ฏธ์ง€๊ฐ€ ์—†์„ ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•œ ๋Œ€์ฒด ํ…์ŠคํŠธ ํ˜น์€ ๋นˆ ๊ฐ’
if mic_icon_base64:
img_src = f"data:image/png;base64,{mic_icon_base64}"
else:
# ์ด๋ฏธ์ง€๊ฐ€ ์—†์œผ๋ฉด ๊นจ์ง„ ์ด๋ฏธ์ง€ ์•„์ด์ฝ˜ ๋Œ€์‹  ํˆฌ๋ช…ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜ ๊ฒฝ๊ณ  ํ‘œ์‹œ
img_src = ""
# ============
# ํŽ˜์ด์ง€ ์„ค์ •
st.set_page_config(
page_title="๊ฑด๊ฐ• ๊ด€๋ฆฌ ์•ฑ",
page_icon="๐Ÿ’ช",
layout="centered",
initial_sidebar_state="collapsed"
)
# CSS ์Šคํƒ€์ผ๋ง (f-string์œผ๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ๋ณ€์ˆ˜ ์ฃผ์ž… ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•จ)
st.markdown(f"""
<style>
/* ์ „์ฒด ๋ฐฐ๊ฒฝ */
.stApp {{
background-color: #ffffff;
}}
/* ํ—ค๋” ์˜์—ญ */
.header {{
padding: 20px 0;
text-align: left;
}}
.menu-icon {{
font-size: 32px;
font-weight: 300;
color: #333;
cursor: pointer;
}}
/* ์นด๋“œ ์ปจํ…Œ์ด๋„ˆ - ๊ฐ€๋กœ ์Šคํฌ๋กค */
.card-container {{
position: fixed;
bottom: 80px;
left: 0;
right: 0;
display: flex;
flex-direction: row;
gap: 15px;
overflow-x: auto;
overflow-y: hidden;
padding: 0 20px;
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE/Edge */
}}
/* ์Šคํฌ๋กค๋ฐ” ์ˆจ๊ธฐ๊ธฐ (Webkit) */
.card-container::-webkit-scrollbar {{
display: none;
}}
/* ๊ฐœ๋ณ„ ์นด๋“œ */
.card {{
background: #f5f5f5;
padding: 15px 18px;
border-radius: 20px;
cursor: pointer;
transition: all 0.2s;
font-size: 13px;
color: #333;
font-weight: 400;
flex-shrink: 0;
max-width: 140px;
white-space: normal;
}}
.card:hover {{
transform: translateY(-2px);
}}
/* ํ•˜๋‹จ ์ž…๋ ฅ ์˜์—ญ */
.input-container {{
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: white;
padding: 15px 20px 15px 20px;
}}
.input-box {{
display: flex;
align-items: center;
background: #f0f0f0;
border-radius: 40px;
padding: 1px 10px;
}}
.plus-btn {{
font-size: 26px;
color: #666;
cursor: pointer;
user-select: none;
}}
.input-text {{
flex: 1;
font-size: 15px;
color: #999;
}}
.voice-btn {{
width: 20px; /* ๋ฒ„ํŠผ ์ „์ฒด ํฌ๊ธฐ */
height: 20px;
cursor: pointer;
box-sizing: border-box; /* ํŒจ๋”ฉ์„ ํฌํ•จํ•ด์„œ 40px๋กœ ๊ณ ์ • */
object-fit: contain; /* ์ด๋ฏธ์ง€๊ฐ€ ์ฐŒ๊ทธ๋Ÿฌ์ง€์ง€ ์•Š๊ฒŒ */
}}
/* Streamlit ๊ธฐ๋ณธ ์š”์†Œ ์ˆจ๊ธฐ๊ธฐ */
#MainMenu {{visibility: hidden;}}
footer {{visibility: hidden;}}
header {{visibility: hidden;}}
/* ์—ฌ๋ฐฑ ์กฐ์ • */
.block-container {{
padding-top: 2rem;
padding-bottom: 8rem;
}}
</style>
""", unsafe_allow_html=True)
# ํ—ค๋” (ํ–„๋ฒ„๊ฑฐ ๋ฉ”๋‰ด)
st.markdown("""
<div class="header">
<div class="menu-icon">โ˜ฐ</div>
</div>
""", unsafe_allow_html=True)
# ์ค‘๊ฐ„ ์นด๋“œ ์˜์—ญ (๊ฐ€๋กœ ์Šคํฌ๋กค)
st.markdown("""
<div class="card-container">
<div class="card">์ด๋ฒˆ์ฃผ์˜ ๊ฑด๊ฐ• ๋ถ„์„ ๋ฆฌํฌํŠธ๋ฅผ ์จ์ค˜</div>
<div class="card">๋‚˜์—๊ฒŒ ๋งž๋Š” ์‹๋‹จ ์ถ”์ฒœํ•ด์ค˜</div>
<div class="card">์ƒˆ๋กญ๊ฒŒ ํ•ด๋ณผ๋งŒํ•œ ์šด๋™ ์ถ”์ฒœํ•ด์ค˜</div>
</div>
""", unsafe_allow_html=True)
# ํ•˜๋‹จ ์ž…๋ ฅ ์˜์—ญ (์ด๋ฏธ์ง€ ๊ฒฝ๋กœ๊ฐ€ ์ฃผ์ž…๋จ)
st.markdown(f"""
<div class="input-container">
<div class="input-box">
<div class="plus-btn">๏ผ‹</div>
<div class="input-text">๋ฌด์—‡์ด๋“  ๋ถ€ํƒํ•˜์„ธ์š”</div>
<img src="{img_src}" class="voice-btn" alt="๋งˆ์ดํฌ"></div>
</div>
""", unsafe_allow_html=True)
# ๋””๋ฒ„๊น…์šฉ: ์ด๋ฏธ์ง€๊ฐ€ ๋กœ๋“œ๋˜์ง€ ์•Š์•˜์„ ๋•Œ๋งŒ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ
if not mic_icon_base64:
st.error(f"์ด๋ฏธ์ง€๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ฒฝ๋กœ๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”: {os.path.abspath(IMG_PATH)}")