JirasakJo's picture
Update app.py
c602184 verified
raw
history blame
14.4 kB
import streamlit as st
import json
import os
from datetime import datetime, timedelta
import subprocess
from huggingface_hub import HfApi
from pathlib import Path
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;
color: #000000 !important;
background-color: white !important;
line-height: 1.7 !important;
}
/* Main container styling */
.main {
padding: 2rem;
color: #000000;
background-color: white;
}
/* Headers styling */
h1 {
color: #000000;
font-size: 2.8rem !important;
font-weight: 700 !important;
margin-bottom: 1.5rem !important;
text-align: center;
padding: 1rem 0;
border-bottom: 3px solid #1E3A8A;
}
h3, h4 {
color: #000000;
font-weight: 600 !important;
font-size: 1.6rem !important;
margin-top: 1.5rem !important;
}
/* 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;
font-family: "Arial", sans-serif !important;
color: #000000 !important;
}
.user-message {
background-color: #F3F4F6 !important;
}
.assistant-message {
background-color: #EFF6FF !important;
}
/* Status indicators */
.status-indicator {
padding: 0.5rem 1rem;
border-radius: 6px;
font-weight: 500;
font-size: 1.2rem;
color: #000000;
}
.status-online {
background-color: #DEF7EC;
color: #03543F;
}
.status-offline {
background-color: #FDE8E8;
color: rgb(255, 255, 255);
}
</style>
""", unsafe_allow_html=True)
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 load_qa_history():
"""Load QA history from local JSON file"""
try:
history_file = Path("qa_history.json")
if history_file.exists():
with open(history_file, "r", encoding="utf-8") as f:
return json.load(f)
return []
except Exception as e:
st.error(f"Error loading QA history: {str(e)}")
return []
def save_qa_history(history_entry):
"""Save QA history entry to local JSON file and push to Hugging Face"""
try:
history_file = Path("qa_history.json")
# Initialize or load existing history
if history_file.exists():
with open(history_file, "r", encoding="utf-8") as f:
try:
history_data = json.load(f)
except json.JSONDecodeError:
history_data = []
else:
history_data = []
# Append new entry
history_data.append(history_entry)
# Save updated history
with open("qa_history.json", "w", encoding="utf-8") as f:
json.dump(history_data, f, ensure_ascii=False, indent=2)
# Push to Hugging Face
hf_token = os.getenv('HF_TOKEN') or st.secrets['HF_TOKEN']
api = HfApi(token=hf_token)
api.upload_file(
path_or_fileobj="qa_history.json",
path_in_repo="qa_history.json",
repo_id="JirasakJo/Questions_Graduate_Studies_Calendar_2024",
repo_type="space"
)
except Exception as e:
st.error(f"Error saving QA history: {str(e)}")
def add_to_qa_history(query: str, answer: str):
"""Add new QA pair to history"""
history_entry = {
"timestamp": (datetime.now() + timedelta(hours=7)).isoformat(),
"query": query,
"answer": answer
}
save_qa_history(history_entry)
return history_entry
def clear_qa_history():
"""Clear QA history file"""
try:
# Write empty list to history file
with open("qa_history.json", "w", encoding="utf-8") as f:
json.dump([], f, ensure_ascii=False, indent=2)
# Push to Hugging Face
hf_token = os.getenv('HF_TOKEN') or st.secrets['HF_TOKEN']
api = HfApi(token=hf_token)
api.upload_file(
path_or_fileobj="qa_history.json",
path_in_repo="qa_history.json",
repo_id="JirasakJo/Questions_Graduate_Studies_Calendar_2024",
repo_type="space"
)
except Exception as e:
st.error(f"Error clearing QA history: {str(e)}")
def add_to_history(role: str, message: str):
"""Add message to chat history and save if it's a complete QA pair"""
st.session_state.chat_history.append((role, message))
# If this is an assistant response, save the QA pair
if role == "assistant" and len(st.session_state.chat_history) >= 2:
# Get the corresponding user query (previous message)
user_query = st.session_state.chat_history[-2][1]
add_to_qa_history(user_query, message)
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)
def main():
# 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 = []
# Load QA history at startup
if 'qa_history_loaded' not in st.session_state:
st.session_state.qa_history_loaded = True
load_qa_history()
# Header
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:
with st.container():
# Display chat history
display_chat_history()
# Query input section
st.markdown("""
<label for="query_input" style="font-size: 1.2rem; font-weight: bold; color: black;">
<span style="color: white; background-color: yellow; padding: 0 0.2rem;">โปรดระบุคำถามเกี่ยวกับ ปฏิทินการศึกษา:</span>
</label>
""", unsafe_allow_html=True)
query = st.text_input(
"",
placeholder="เช่น: วันสุดท้ายของการสอบปากเปล่าในภาคเรียนที่ 1/2567 คือวันที่เท่าไร?",
key="query_input"
)
# Button layout inside main() function
col1, col2, col3 = st.columns([1, 1, 4])
with col1:
send_query = st.button(
"📤 ส่งคำถาม",
type="primary",
use_container_width=True,
key="send_query_button"
)
with col2:
clear_history = st.button(
"🗑️ ล้างประวัติ",
type="secondary",
use_container_width=True,
key="clear_history_button"
)
# 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"])
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("⚠️ กรุณาระบุคำถาม")
# Handle clear history action
if clear_history:
st.session_state.chat_history = []
clear_qa_history()
st.rerun()
with info_col:
# System information
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)
# System status
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=6)).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()