JirasakJo's picture
Update app.py
2adb162 verified
raw
history blame
15.2 kB
import streamlit as st
import json
import os
import subprocess # Added missing import
from datetime import datetime
from calendar_rag import (
create_default_config,
AcademicCalendarRAG,
PipelineConfig
)
# Custom CSS for enhanced styling
def load_custom_css():
st.markdown("""
<style>
/* General body styling */
body {
font-family: "Arial", sans-serif !important; /* Clean and readable font */
color: #000000 !important; /* Black text */
background-color: white !important;
line-height: 1.7 !important; /* Increase line spacing */
}
/* Main container styling */
.main {
padding: 2rem;
color: #000000; /* Ensure all text is black */
background-color: white;
}
/* Headers styling */
h1 {
color: #000000; /* Black headers */
font-size: 2.8rem !important; /* Larger font for headers */
font-weight: 700 !important;
margin-bottom: 1.5rem !important;
text-align: center;
padding: 1rem 0;
border-bottom: 3px solid #1E3A8A; /* Keep a blue line for a clean design */
}
h3, h4 {
color: #000000; /* Black sub-headers */
font-weight: 600 !important;
font-size: 1.6rem !important; /* Increase font size for sub-headers */
margin-top: 1.5rem !important;
}
/* Paragraphs and text */
p, span, li {
font-size: 1.2rem !important; /* Larger font size for regular text */
color: #000000 !important; /* Black text */
}
/* Chat message styling */
.chat-message {
padding: 1.5rem;
border-radius: 10px;
margin: 1rem 0;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
font-size: 1.1rem !important;
line-height: 1.6 !important; /* Better readability */
font-family: "Arial", sans-serif !important;
color: #000000 !important; /* Black text in chat */
}
.user-message {
background-color: #F3F4F6 !important;
}
.assistant-message {
background-color: #EFF6FF !important;
}
/* Input field styling */
.stTextInput input {
border-radius: 8px;
border: 2px solid #E5E7EB;
padding: 0.75rem;
font-size: 1.1rem;
font-family: "Arial", sans-serif !important;
color: #000000; /* Black input text */
}
.stTextInput input:focus {
border-color: #1E3A8A;
box-shadow: 0 0 0 2px rgba(30, 58, 138, 0.1);
}
/* Button styling */
.stButton button {
border-radius: 8px;
font-weight: 600;
font-size: 1.2rem !important; /* Bigger buttons for better interaction */
color: #000000; /* Black text on buttons */
transition: all 0.2s ease;
}
.stButton button:hover {
transform: translateY(-1px);
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
/* List styling */
ul {
font-size: 1.2rem !important;
margin-left: 1rem;
color: #000000; /* Black text in lists */
list-style-type: disc;
}
/* Status indicator styling */
.status-indicator {
padding: 0.5rem 1rem;
border-radius: 6px;
font-weight: 500;
font-size: 1.2rem; /* Larger for better clarity */
color: #000000; /* Black text for status */
}
.status-online {
background-color: #DEF7EC;
color: #03543F;
}
.status-offline {
background-color: #FDE8E8;
color: #9B1C1C;
}
</style>
""", unsafe_allow_html=True)
# Page config
st.set_page_config(
page_title="Academic Calendar Assistant",
page_icon="📅",
layout="wide",
initial_sidebar_state="collapsed"
)
# Load custom CSS
load_custom_css()
# Initialize session state
if 'pipeline' not in st.session_state:
st.session_state.pipeline = None
if 'chat_history' not in st.session_state:
st.session_state.chat_history = []
if 'feedback_data' not in st.session_state:
st.session_state.feedback_data = []
def initialize_pipeline():
"""Initialize RAG pipeline with configurations"""
try:
openai_api_key = os.getenv('OPENAI_API_KEY') or st.secrets['OPENAI_API_KEY']
config = create_default_config(openai_api_key)
config.localization.enable_thai_normalization = True
config.retriever.top_k = 5
config.model.temperature = 0.3
pipeline = AcademicCalendarRAG(config)
with open("calendar.json", "r", encoding="utf-8") as f:
calendar_data = json.load(f)
pipeline.load_data(calendar_data)
return pipeline
except Exception as e:
st.error(f"Error initializing pipeline: {str(e)}")
return None
def save_feedback_to_json():
"""Save feedback data to a JSON file"""
try:
# Get current directory
current_dir = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(current_dir, 'feedback_data.json')
# Save the file
with open(file_path, "w", encoding="utf-8") as f:
json.dump(
st.session_state.feedback_data,
f,
ensure_ascii=False,
indent=2
)
return file_path
except Exception as e:
st.error(f"Error saving feedback: {str(e)}")
return None
def add_feedback(query: str, answer: str, is_correct: bool):
"""Add feedback entry to session state and save to JSON and GitHub"""
feedback_entry = {
"timestamp": (datetime.now() + timedelta(hours=7)).isoformat(),
"query": query,
"answer": answer,
"is_correct": is_correct
}
st.session_state.feedback_data.append(feedback_entry)
file_path = save_feedback_to_json()
if file_path:
if save_feedback_to_repo(file_path):
st.success("Feedback saved successfully")
else:
st.warning("Feedback saved locally but not pushed to repository")
def evaluate_answer(query: str, answer: str):
"""Display evaluation buttons for the answer"""
col1, col2, col3 = st.columns([1, 1, 4])
with col1:
if st.button("✅ Correct", key=f"correct_{len(st.session_state.chat_history)}"):
add_feedback(query, answer, True)
st.success("Feedback recorded")
with col2:
if st.button("❌ Incorrect", key=f"incorrect_{len(st.session_state.chat_history)}"):
add_feedback(query, answer, False)
st.error("Feedback recorded")
def display_chat_history():
"""Display chat history with enhanced styling"""
for i, (role, message) in enumerate(st.session_state.chat_history):
if role == "user":
st.markdown(f"""
<div class="chat-message user-message">
<strong>🧑 คำถาม:</strong><br>
{message}
</div>
""", unsafe_allow_html=True)
else:
st.markdown(f"""
<div class="chat-message assistant-message">
<strong>🤖 คำตอบ:</strong><br>
{message}
</div>
""", unsafe_allow_html=True)
# Add evaluation buttons after each assistant response
if i == len(st.session_state.chat_history) - 1: # Only for the latest answer
user_query = st.session_state.chat_history[i-1][1] # Get the corresponding user query
evaluate_answer(user_query, message)
def add_to_history(role: str, message: str):
"""Add message to chat history"""
st.session_state.chat_history.append((role, message))
def main():
# Header with animation
st.markdown("""
<div style="text-align: center; padding: 2rem 0;">
<h1>🎓 ระบบค้นหาข้อมูลปฏิทินการศึกษา</h1>
</div>
""", unsafe_allow_html=True)
# Initialize pipeline
if st.session_state.pipeline is None:
with st.spinner("กำลังเริ่มต้นระบบ..."):
st.session_state.pipeline = initialize_pipeline()
chat_col, info_col = st.columns([7, 3])
with chat_col:
# Add a subtle container for the chat interface
with st.container():
# Display chat history
display_chat_history()
# Add the styled label using st.markdown
st.markdown("""
<label for="query_input" style="font-size: 1.2rem; font-weight: bold; color: black;">
โปรดระบุคำถามเกี่ยวกับ <span style="color: white; background-color: white; padding: 0 0.2rem;">ปฏิทินการศึกษา:</span>
</label>
""", unsafe_allow_html=True)
# The input box without a label
query = st.text_input(
"",
placeholder="เช่น: วันสุดท้ายของการสอบปากเปล่าในภาคเรียนที่ 1/2567 คือวันที่เท่าไร?",
key="query_input"
)
# Button layout with enhanced styling
col1, col2, col3 = st.columns([1, 1, 4])
with col1:
send_query = st.button("📤 ส่งคำถาม", type="primary", use_container_width=True)
with col2:
if st.button("🗑️ ล้างประวัติ", type="secondary", use_container_width=True):
st.session_state.chat_history = []
st.rerun()
# Process query
if send_query and query:
if st.session_state.pipeline is None:
st.error("❌ ไม่สามารถเชื่อมต่อกับระบบได้ กรุณาลองใหม่อีกครั้ง")
return
add_to_history("user", query)
try:
with st.spinner("🔍 กำลังค้นหาคำตอบ..."):
result = st.session_state.pipeline.process_query(query)
add_to_history("assistant", result["answer"])
# Enhanced expandable sections
with st.expander("📚 แสดงข้อมูลอ้างอิง", expanded=False):
for i, doc in enumerate(result["documents"], 1):
st.markdown(f"""
<div style="padding: 1rem; background-color: #F9FAFB; border-radius: 8px; margin: 0.5rem 0;">
<strong>เอกสารที่ {i}:</strong><br>
{doc.content}
</div>
""", unsafe_allow_html=True)
with st.expander("🔍 รายละเอียดการวิเคราะห์คำถาม", expanded=False):
st.json(result["query_info"])
st.rerun()
except Exception as e:
st.error(f"❌ เกิดข้อผิดพลาด: {str(e)}")
elif send_query and not query:
st.warning("⚠️ กรุณาระบุคำถาม")
with info_col:
# Enhanced system information section
st.markdown("""
<div style="background-color: #F9FAFB; padding: 1.5rem; border-radius: 12px; margin-bottom: 2rem;">
<h3 style="color: #1E3A8A;">ℹ️ เกี่ยวกับระบบ</h3>
<p style="color: #ff0015;">
ระบบนี้ใช้เทคโนโลยี <strong>RAG (Retrieval-Augmented Generation)</strong>
ในการค้นหาและตอบคำถามเกี่ยวกับปฏิทินการศึกษา
</p>
<h4 style="color: #1E3A8A; margin-top: 1rem;">สามารถสอบถามข้อมูลเกี่ยวกับ:</h4>
<ul style="list-style-type: none; padding-left: 0;">
<li>📅 กำหนดการต่างๆ ในปฏิทินการศึกษา</li>
<li>🎯 วันสำคัญและกิจกรรม</li>
<li>📝 การลงทะเบียนเรียน</li>
<li>📚 กำหนดการสอบ</li>
<li>🏖️ วันหยุดการศึกษา</li>
</ul>
</div>
""", unsafe_allow_html=True)
# Enhanced system status section
st.markdown("""
<div style="background-color: #f9fafb; padding: 1.5rem; border-radius: 12px;">
<h3 style="color: #1E3A8A;">🔄 สถานะระบบ</h3>
<div style="margin-top: 1rem;">
<p><strong>⏰ เวลาปัจจุบัน:</strong><br>
{}</p>
<p><strong>📡 สถานะระบบ:</strong><br>
<span class="status-indicator {}">
{} {}
</span></p>
</div>
</div>
""".format(
(datetime.now() + timedelta(hours=7)).strftime('%Y-%m-%d %H:%M:%S'),
"status-online" if st.session_state.pipeline else "status-offline",
"🟢" if st.session_state.pipeline else "🔴",
"พร้อมใช้งาน" if st.session_state.pipeline else "ไม่พร้อมใช้งาน"
), unsafe_allow_html=True)
if __name__ == "__main__":
main()