File size: 5,376 Bytes
1058e3e
 
 
 
 
 
 
ee310ff
1058e3e
664d27e
1058e3e
 
 
 
 
 
 
 
ee310ff
1058e3e
ee310ff
 
1058e3e
ee310ff
1058e3e
664d27e
1058e3e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
664d27e
1058e3e
 
 
 
 
664d27e
1058e3e
 
 
 
 
 
 
 
ee310ff
1058e3e
ee310ff
1058e3e
 
 
ee310ff
1058e3e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c54772b
ee310ff
1058e3e
 
 
 
664d27e
 
 
 
1058e3e
 
 
 
664d27e
e80d7b7
 
664d27e
 
056b4f0
664d27e
 
 
 
 
 
e80d7b7
664d27e
e80d7b7
 
 
664d27e
 
e80d7b7
 
 
 
664d27e
e80d7b7
664d27e
 
e80d7b7
 
664d27e
e80d7b7
664d27e
2bbf3ba
664d27e
6dbb93e
 
 
664d27e
6dbb93e
 
 
664d27e
6dbb93e
 
664d27e
 
 
 
 
 
 
 
1058e3e
 
664d27e
1058e3e
 
ee310ff
 
1058e3e
 
 
664d27e
1058e3e
ee310ff
1058e3e
664d27e
 
1058e3e
664d27e
1058e3e
664d27e
ee310ff
664d27e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
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")