import streamlit as st st.set_page_config( page_title="Instant - Indonesia Immigration Assistant", layout="centered", initial_sidebar_state="expanded" ) from pymongo import MongoClient from langchain_mongodb import MongoDBAtlasVectorSearch from langchain_openai import OpenAIEmbeddings, ChatOpenAI from langchain.chains import RetrievalQA from langchain.prompts import PromptTemplate from dotenv import load_dotenv from streamlit_option_menu import option_menu import os import re from model import ask from handler import save_feedback, translate_answer, check_question_feedback, translate_text, is_overlimit, refresh_web_counter from text import feedback_instr, no_affiliation, description, no_replacement_for_official_advice, source_of_answer_short, source_of_answer from langdetect import detect from deep_translator import GoogleTranslator from datetime import datetime primary_color = "#ffffff" secondary_color = "#1E1E1E" accent_color = "#FF6B35" sidebar_bg = "#0e1117" sidebar_text = "#ffffff" selected_bg = "#f39c12" selected_text = "#000000" text_color = "#000000" bg_color = "#252422" header = "#1E1E1E" # --- Custom CSS --- st.markdown(f""" """, unsafe_allow_html=True) current_hour = datetime.now().hour local_hour = (current_hour + 7) % 24 working_hours = (8 <= local_hour < 20) extra_remark = " (GMT+7)" # Sidebar Menu with st.sidebar: selected = option_menu( "Menu", ["Chatbot", "About", "Contact"], icons=["chat-dots", "info-circle", "telephone"], menu_icon="cast", default_index=0, styles={ "container": {"padding": "5!important", "background-color": sidebar_bg}, "icon": {"color": accent_color, "font-size": "25px"}, "nav-link": {"color": sidebar_text, "font-size": "16px", "text-align": "left", "margin":"0px"}, "nav-link-selected": {"background-color": selected_bg, "color": selected_text}, } ) def get_second_last_user_message(): count = 0 for msg in reversed(st.session_state.messages): if msg["role"] == "user": count += 1 if count == 2: return msg["content"] return None def get_last_user_message(): for msg in reversed(st.session_state.messages): if msg["role"] == "user" and msg["type"] == "question": return msg["content"] return None def get_last_assistant_message(): for msg in reversed(st.session_state.messages): if msg["role"] == "assistant" and msg["type"] == "answer": return msg["content"] return None def normalize(text): return re.sub(r'[^\w\s]', '', text).strip().lower() def separate_feedback_from_query(user_input, normalized_feedbacks): question = get_last_user_message() answer = get_last_assistant_message() cleaned_input = normalize(user_input) if cleaned_input in normalized_feedbacks: return {"type": "pure_feedback", "feedback": cleaned_input, "comment": "", "question": question, "answer": answer} # Try to match a known feedback prefix for keyword in normalized_feedbacks: if cleaned_input.startswith(keyword): remaining = cleaned_input[len(keyword):].strip() return { "type": "mixed", "feedback": keyword, "comment": remaining, "question": question, "answer": answer } return {"type": "normal_query", "feedback": None, "comment": user_input, "question": question, "answer": answer} def normalize(text): return re.sub(r'[^\w\s]', '', text).strip().lower() # --- Streamlit UI --- if selected == "Chatbot": with st.container(): col1, col2 = st.columns([4, 4]) with col1: st.image("instant.png", width=1000) with col2: st.markdown(f"""

Instant Bot

{no_affiliation}


{source_of_answer_short}

""", unsafe_allow_html=True) st.markdown(f"""
🤖 You can ask in English or Indonesian
✔️ Indonesian Passport & M-Paspor ✔️ Indonesian Citizen Immigration Services ✔️ Foreign Citizen Immigration Services ✔️ Dual Citizenship for Children ✔️ Indonesian Immigration Regulations ❌ Foreign Affairs (Schengen or US Visa)

{feedback_instr}
""", unsafe_allow_html=True) # Initialize Chat History if "messages" not in st.session_state: st.session_state.messages = [{ "role": "assistant", "type": "greeting", "content": "Hello! I'm Instant. How can I help you today?" }] is_limit_exceeded = False refresh = refresh_web_counter() if refresh: is_limit_exceeded = is_overlimit() if working_hours and not is_limit_exceeded: # Display Chat History for message in st.session_state.messages: if message["role"] == "user": st.markdown(f"""
😀 You
{message["content"]}
""", unsafe_allow_html=True) else: st.markdown(f"""
🤖 Instant Bot
{message["content"]}
""", unsafe_allow_html=True) query = st.chat_input("Ask your question here... (Example: How to apply for KITAS?)") if query: lang = detect(query) if len(query) > 150: char_too_long = "Sorry, your message is too long. Please shorten it to less than 150 characters." exceed_length_resp = translate_text(lang, char_too_long) st.session_state.messages.append({ "role": "assistant", "type": "warning", "content": exceed_length_resp }) st.rerun() else: is_feedback = check_question_feedback(query, "anonymous") if is_feedback['is_feedback']: st.session_state.messages.append({"role": "user", "type": "feedback", "content": query}) last_question = is_feedback['last_qna']['question'] if not last_question: resp = "Sorry, you have not asked a question, or the session has been reset. Please ask a question first before providing feedback." st.session_state.messages.append({ "role": "assistant", "type": "warning", "content": resp }) st.rerun() else: feedback_obj = is_feedback['feedback_obj'] last_qna = is_feedback['last_qna'] response = save_feedback(feedback_obj, last_qna) if "error" not in response: st.toast("Feedback recorded!", icon="💾") st.markdown(response) else: st.session_state.messages.append({"role": "user", "type": "question", "content": query}) with st.spinner("Looking up..."): answer = ask(query) st.session_state.messages.append({"role": "assistant", "type": "answer", "content": answer}) st.rerun() elif is_limit_exceeded: st.info("Sorry, due to usage control, the web-based bot is currently paused and will be back on tomorrow.\nFor 24-hour access, you can utilize our WhatsApp Bot at +1 234 423 4277.\n\n") query = None else: st.info(f"Sorry, due to usage control, the web-based bot is only available between 8 AM - 8 PM{extra_remark}.\nFor 24-hour access, you can utilize our WhatsApp Bot at +1 234 423 4277.\n\n") query = None elif selected == "About": st.markdown("### 📟 About Instant") st.markdown(f"""
{description}

Disclaimer: {no_affiliation}

Source of Information: {source_of_answer}

GitHub Repository: Indonesia Immigration Bot """, unsafe_allow_html=True) elif selected == "Contact": st.markdown("### 📩 Contact Us") st.markdown(""" **If you have further question, collaboration proposal, or any other inquiries related to this bot, please contact:** - 📧 [galuh.adika@gmail.com](mailto:galuh.adika@gmail.com) """) # Footer st.markdown(f"""

{no_replacement_for_official_advice}
""", unsafe_allow_html=True)