kora / app.py
Ramanjit's picture
chore: update dependencies and add streamlit-autorefresh
664d27e
import logging
import os
import sqlite3
import threading
import urllib.parse
from http.server import BaseHTTPRequestHandler, HTTPServer
import plivo
import streamlit as st
from streamlit_autorefresh import st_autorefresh
from dotenv import load_dotenv
# --- Setup logging ---
logging.basicConfig(level=logging.INFO)
# --- Load environment variables ---
load_dotenv()
# --- Setup plivo ---
try:
PLIVO_AUTH_ID = os.getenv("PLIVO_AUTH_ID")
PLIVO_AUTH_TOKEN = os.getenv("PLIVO_AUTH_TOKEN")
KORA_PHONE_NUMBER = os.getenv("KORA_PHONE_NUMBER")
client = plivo.RestClient(auth_id=PLIVO_AUTH_ID, auth_token=PLIVO_AUTH_TOKEN)
except Exception as e:
st.error(f"Error setting up Plivo: {e}")
# --- Thread lock for SQLite access ---
db_lock = threading.Lock()
# --- Setup SQLite ---
try:
conn = sqlite3.connect("chat.db", check_same_thread=False)
c = conn.cursor()
with db_lock:
c.execute(
"""
CREATE TABLE IF NOT EXISTS messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sender TEXT,
text TEXT,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
)
"""
)
conn.commit()
except sqlite3.Error as e:
st.error(f"Error setting up SQLite: {e}")
# --- Webhook Server (for receiving SMS) ---
class SMSWebhookHandler(BaseHTTPRequestHandler):
def do_POST(self):
try:
length = int(self.headers["Content-Length"])
post_data = self.rfile.read(length)
data = urllib.parse.parse_qs(post_data.decode("utf-8"))
logging.info(f"Webhook received: {data}")
message_text = data.get("Text", [""])[0]
if message_text:
with db_lock:
c.execute(
"INSERT INTO messages (sender, text) VALUES (?, ?)",
(KORA_PHONE_NUMBER, message_text),
)
conn.commit()
self.send_response(200)
self.end_headers()
self.wfile.write(
b"<?xml version='1.0'?><Response><Message>Got it!</Message></Response>"
)
except Exception as e:
logging.error(f"Webhook error: {e}")
self.send_response(500)
self.end_headers()
self.wfile.write(b"Error processing request")
# --- Run webhook server in background ---
def run_webhook_server():
try:
server = HTTPServer(("", 8502), SMSWebhookHandler)
logging.info("Webhook server started on port 8502")
server.serve_forever()
except Exception as e:
logging.error(f"Error starting webhook server: {e}")
# --- Start webhook server thread ---
if not hasattr(st.session_state, "webhook_server_started"):
threading.Thread(target=run_webhook_server, daemon=True).start()
st.session_state.webhook_server_started = True
# --- Streamlit UI ---
st.title("📲 Chat with KORA")
# Initialize session state variables
if "show_confirmation" not in st.session_state:
st.session_state.show_confirmation = False
if "last_message_count" not in st.session_state:
st.session_state.last_message_count = 0
# Phone input
PLIVO_PHONE_NUMBER = st.text_input(
"Enter your phone number to chat with KORA", value="+13602304837", max_chars=15
)
# --- Clear Chat UI ---
if not st.session_state.show_confirmation:
if st.button("Clear Chat"):
st.session_state.show_confirmation = True
st.rerun()
else:
col1, col2 = st.columns(2)
if col1.button("Yes, clear chat"):
try:
with db_lock:
c.execute("DELETE FROM messages")
conn.commit()
st.success("Chat history cleared.")
st.session_state.show_confirmation = False
st.session_state.last_message_count = 0
st.rerun()
except sqlite3.Error as e:
st.error(f"Error clearing chat history: {e}")
elif col2.button("Cancel"):
st.session_state.show_confirmation = False
st.rerun()
# --- Display Chat Messages ---
try:
with db_lock:
messages = c.execute(
"SELECT sender, text FROM messages WHERE sender IN (?, ?) ORDER BY timestamp ASC",
(PLIVO_PHONE_NUMBER, KORA_PHONE_NUMBER),
).fetchall()
except sqlite3.Error as e:
messages = []
st.error(f"Error fetching messages: {e}")
# Display messages
for sender, text in messages:
role = "user" if sender == PLIVO_PHONE_NUMBER else "assistant"
st.chat_message(role).write(text)
st.session_state.last_message_count = len(messages)
# --- Chat Input ---
if prompt := st.chat_input("Type your message..."):
try:
# Save message to DB
with db_lock:
c.execute(
"INSERT INTO messages (sender, text) VALUES (?, ?)",
(PLIVO_PHONE_NUMBER, prompt),
)
conn.commit()
# Send message via Plivo
client.messages.create(
text=prompt, src=PLIVO_PHONE_NUMBER, dst=KORA_PHONE_NUMBER
)
st.rerun() # Refresh to show new message immediately
except sqlite3.Error as e:
st.error(f"Error saving message: {e}")
except Exception as e:
st.error(f"Error sending message via Plivo: {e}")
st_autorefresh(interval=1000, key="auto_refresh")