| import streamlit as st |
| import base64 |
| import os |
|
|
| |
| IMG_PATH = "src/img/mic.png" |
|
|
| |
| 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" |
| ) |
|
|
| |
| 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)}") |