Spaces:
Runtime error
Runtime error
| # ui/components.py | |
| """PROBIN UI ์ปดํฌ๋ํธ""" | |
| import streamlit as st | |
| from typing import List, Dict | |
| def render_header(): | |
| """ํค๋ ๋ ๋๋ง (PROBIN ๋ฒ์ )""" | |
| st.markdown( | |
| """ | |
| <div style="text-align: center; padding: 2rem 0;"> | |
| <h1 style="color: #2196F3; font-size: 3rem;">๐ง PROBIN</h1> | |
| <p style="font-size: 1.2rem; color: #666;">Intelligent Document Analysis System</p> | |
| <p style="font-size: 0.9rem; color: #999;">์ ํ๋ ์ฐ์ RAG ์์คํ </p> | |
| </div> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |
| def render_sources_with_relevance(sources: List[Dict], message_idx: int, move_to_page_callback): | |
| """ | |
| ์ถ์ฒ ๋ ๋๋ง (๊ฐ์ฅ ๊ด๋ จ๋ ๋์ ๊ฒ ์ฐ์ ) | |
| Args: | |
| sources: ์ถ์ฒ ๋ฆฌ์คํธ (์ด๋ฏธ ๊ด๋ จ๋ ์์ผ๋ก ์ ๋ ฌ๋จ) | |
| message_idx: ๋ฉ์์ง ์ธ๋ฑ์ค (ํค ์ค๋ณต ๋ฐฉ์ง์ฉ) | |
| move_to_page_callback: ํ์ด์ง ์ด๋ ์ฝ๋ฐฑ ํจ์ | |
| ๊ตฌ์กฐ: | |
| ๐ฏ ํต์ฌ ๊ทผ๊ฑฐ (1๊ฐ) - sources[0]: ๊ฐ์ฅ ๊ด๋ จ๋ ๋์ ์ถ์ฒ | |
| ๐ ์ถ๊ฐ ์ฐธ๊ณ ๋ฌธ์ (๋๋จธ์ง) - Expander ๋ด๋ถ | |
| """ | |
| if not sources: | |
| return | |
| # ์ฒซ ๋ฒ์งธ ์ถ์ฒ = ๊ฐ์ฅ ๊ด๋ จ๋ ๋์ | |
| st.markdown("---") | |
| st.markdown("**๐ฏ ํต์ฌ ๊ทผ๊ฑฐ:**") | |
| primary_source = sources[0] | |
| if st.button( | |
| f"๐ ํ์ด์ง {primary_source['page_num']} ํ์ธ", | |
| key=f"primary_{message_idx}", | |
| type="primary", | |
| use_container_width=True | |
| ): | |
| move_to_page_callback(primary_source['page_num'], primary_source['text']) | |
| # ๋ฏธ๋ฆฌ๋ณด๊ธฐ | |
| st.caption(f"๐ฌ \"{primary_source['text'][:100]}...\"") | |
| # ์ถ๊ฐ ์ฐธ๊ณ ๋ฌธ์ (๋๋จธ์ง) | |
| if len(sources) > 1: | |
| additional_sources = sources[1:] | |
| with st.expander(f"๐ ์ถ๊ฐ ์ฐธ๊ณ ๋ฌธ์ ({min(2, len(additional_sources))}๊ฐ)"): | |
| cols = st.columns(2) | |
| for i, src in enumerate(additional_sources[:2]): # ์ต๋ 2๊ฐ๋ง | |
| with cols[i]: | |
| if st.button( | |
| f"p.{src['page_num']}", | |
| key=f"additional_{message_idx}_{i}", | |
| use_container_width=True | |
| ): | |
| move_to_page_callback(src['page_num'], src['text']) | |
| st.caption(f"\"{src['text'][:60]}...\"") | |
| def render_answer(answer: str, sources: List[Dict]): | |
| """๋ต๋ณ ๋ฐ ์ถ์ฒ ๋ ๋๋ง (Legacy - ์ฌ์ฉ ์ ํจ)""" | |
| # ๋ต๋ณ | |
| st.markdown("### ๐ก ๋ต๋ณ") | |
| st.markdown( | |
| f""" | |
| <div class="answer-box"> | |
| {answer} | |
| </div> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |
| # ์ถ์ฒ | |
| if sources: | |
| st.markdown("### ๐ ์ถ์ฒ") | |
| for i, source in enumerate(sources, 1): | |
| with st.expander(f"์ถ์ฒ {i} - ํ์ด์ง {source['page_num']}"): | |
| st.text(source['text']) | |
| def render_file_uploader(): | |
| """ํ์ผ ์ ๋ก๋ ๋ ๋๋ง""" | |
| st.markdown("### ๐ค PDF ์ ๋ก๋") | |
| uploaded_file = st.file_uploader( | |
| "RFP PDF ํ์ผ์ ์ ๋ก๋ํ์ธ์", | |
| type=["pdf"], | |
| help="PDF ํ์์ RFP ๋ฌธ์๋ฅผ ์ ๋ก๋ํ์ธ์" | |
| ) | |
| return uploaded_file | |
| def render_query_input(): | |
| """์ง๋ฌธ ์ ๋ ฅ ๋ ๋๋ง (Deprecated: st.chat_input ์ฌ์ฉ ๊ถ์ฅ)""" | |
| st.markdown("### ๐ฌ ์ง๋ฌธํ๊ธฐ") | |
| query = st.text_input( | |
| "์ง๋ฌธ์ ์ ๋ ฅํ์ธ์", | |
| placeholder="์: ์ด ํ๋ก์ ํธ์ ์์ฐ์ ์ผ๋ง์ธ๊ฐ์?", | |
| help="RFP ๋ฌธ์์ ๋ํด ์ง๋ฌธํ์ธ์" | |
| ) | |
| return query | |
| def render_chat_history(messages: list): | |
| """์ฑํ ํ์คํ ๋ฆฌ ๋ ๋๋ง (ํ๋์ ๋ฐฉ์)""" | |
| for message in messages: | |
| with st.chat_message(message["role"]): | |
| st.markdown(message["content"]) | |
| # ์ถ์ฒ ํ์ | |
| if message["role"] == "assistant" and "sources" in message: | |
| with st.expander("๐ ์ถ์ฒ ๋ณด๊ธฐ"): | |
| for i, src in enumerate(message["sources"], 1): | |
| st.markdown(f"**์ถ์ฒ {i} - [ํ์ด์ง {src['page_num']}]**") | |
| st.caption(src["text"]) | |
| def render_sidebar(): | |
| """์ฌ์ด๋๋ฐ ๋ ๋๋ง""" | |
| with st.sidebar: | |
| st.markdown("## โ๏ธ ์ค์ ") | |
| # ๊ฒ์ ์ค์ | |
| st.markdown("### ๐ ๊ฒ์ ์ค์ ") | |
| top_k = st.slider("๊ฒ์ํ ์ฒญํฌ ์", 5, 20, 10) | |
| # ์ฒญํน ์ค์ | |
| st.markdown("### โ๏ธ ์ฒญํน ์ค์ ") | |
| chunk_size = st.number_input("์ฒญํฌ ํฌ๊ธฐ", 400, 1200, 800, step=100) | |
| chunk_overlap = st.number_input("์ค๋ฒ๋ฉ ํฌ๊ธฐ", 50, 300, 150, step=50) | |
| st.markdown("---") | |
| # ์ ๋ณด | |
| st.markdown("### โน๏ธ ์ ๋ณด") | |
| st.info( | |
| """ | |
| **PROBIN v2.0** | |
| - PDF ์ ๋ก๋ โ | |
| - ์ง๋ฌธ-๋ต๋ณ โ | |
| - ์ถ์ฒ ํ์ โ | |
| - ๋ฒกํฐ ๊ฒ์ โ | |
| - ํ์ด๋ผ์ดํธ โ | |
| """ | |
| ) | |
| # ์ด๊ธฐํ ๋ฒํผ | |
| if st.button("๐๏ธ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๊ธฐํ", type="secondary"): | |
| return True, top_k, chunk_size, chunk_overlap | |
| return False, top_k, chunk_size, chunk_overlap | |
| def render_processing_status(status: str): | |
| """์ฒ๋ฆฌ ์ํ ๋ ๋๋ง""" | |
| status_icons = { | |
| "uploading": "๐ค", | |
| "extracting": "๐", | |
| "chunking": "โ๏ธ", | |
| "embedding": "๐ข", | |
| "storing": "๐พ", | |
| "complete": "โ " | |
| } | |
| icon = status_icons.get(status, "โณ") | |
| st.info(f"{icon} {status}") | |
| def render_welcome_message(): | |
| """์ฐ์ปด ๋ฉ์์ง (์ฌ์ฉ ์๋ด)""" | |
| st.markdown(""" | |
| <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 12px; margin-bottom: 20px; text-align: center;"> | |
| <h2 style="margin: 0 0 10px 0;">๐ง PROBIN์ ์ค์ ๊ฒ์ ํ์ํฉ๋๋ค!</h2> | |
| <p style="margin: 0; opacity: 0.9;">Intelligent Document Analysis System</p> | |
| </div> | |
| <div style="background-color: #f0f7ff; border-left: 4px solid #2196F3; padding: 15px; border-radius: 8px; margin-bottom: 15px;"> | |
| <h4 style="margin-top: 0; color: #1976D2;">๐ ์ด์ฉ ๋ฐฉ๋ฒ</h4> | |
| <ol style="line-height: 1.8; margin: 0;"> | |
| <li><strong>PDF ์ ๋ก๋:</strong> ์ผ์ชฝ ์ฌ์ด๋๋ฐ์์ ๋ฌธ์๋ฅผ ์ ๋ก๋ํ์ธ์</li> | |
| <li><strong>๋ฌธ์ ์ฒ๋ฆฌ:</strong> 30์ด~1๋ถ ์ ๋ ๊ธฐ๋ค๋ฆฝ๋๋ค</li> | |
| <li><strong>์ง๋ฌธ ์ ๋ ฅ:</strong> ์ฑํ ์ฐฝ์ ์ง๋ฌธ์ ์ ๋ ฅํ์ธ์</li> | |
| <li><strong>๊ทผ๊ฑฐ ํ์ธ:</strong> <span style="background-color: rgba(255,255,0,0.5); padding: 2px 6px; border-radius: 3px;">๋ ธ๋์ ํ์ด๋ผ์ดํธ</span>๋ก ๊ทผ๊ฑฐ๋ฅผ ํ์ธํ์ธ์</li> | |
| </ol> | |
| </div> | |
| <div style="text-align: center; margin-top: 20px;"> | |
| <span style="display: inline-block; margin: 5px; padding: 8px 16px; background-color: #e8f5e9; border-radius: 20px; font-size: 0.9rem;">๐บ Split View</span> | |
| <span style="display: inline-block; margin: 5px; padding: 8px 16px; background-color: #fff3e0; border-radius: 20px; font-size: 0.9rem;">๐๏ธ Highlighting</span> | |
| <span style="display: inline-block; margin: 5px; padding: 8px 16px; background-color: #f3e5f5; border-radius: 20px; font-size: 0.9rem;">๐ฏ High Accuracy</span> | |
| </div> | |
| """, unsafe_allow_html=True) |