File size: 13,229 Bytes
5720799
86b116d
6015c25
86b116d
0e216c6
89a4312
86b116d
 
2cb4727
a3e0ade
 
86b116d
2665582
857c4c0
73ed159
bed2d0a
fc3fdb8
 
b5d5e39
 
 
 
 
758943e
2cb4727
86b116d
 
e9b4a9e
 
fde6c6f
 
d891499
2cb4727
bed2d0a
 
fc3fdb8
 
cbac037
 
fc3fdb8
 
 
 
 
 
 
 
 
 
bed2d0a
2cb4727
0757010
1949ac7
2cb4727
0757010
2cb4727
0757010
 
a3e0ade
0757010
 
 
 
 
fc3fdb8
 
 
 
0757010
 
 
fc3fdb8
 
 
 
 
2cb4727
fc3fdb8
 
 
 
d891499
0757010
 
2cb4727
0757010
 
 
 
fc3fdb8
 
 
 
0757010
 
 
 
 
fc3fdb8
 
 
2cb4727
0757010
fc3fdb8
 
0757010
a3e0ade
b40bdef
 
fc3fdb8
 
b40bdef
 
fc3fdb8
 
 
 
b40bdef
 
fc3fdb8
 
 
0757010
fc3fdb8
0757010
fc3fdb8
 
 
 
 
2cb4727
0757010
fc3fdb8
0757010
cbac037
a3e0ade
 
0757010
fc3fdb8
2cb4727
0757010
 
a3e0ade
 
2cb4727
 
 
0757010
 
 
 
 
 
 
 
 
2cb4727
8cfe660
a3e0ade
 
 
 
 
 
 
 
 
8cfe660
 
 
a3e0ade
 
 
 
 
 
8cfe660
 
 
 
 
 
 
a3e0ade
fc3fdb8
8cfe660
fc3fdb8
a3e0ade
fc3fdb8
8cfe660
fc3fdb8
 
 
 
8cfe660
a3e0ade
 
fc3fdb8
8cfe660
fc3fdb8
 
 
 
a3e0ade
 
 
fc3fdb8
 
 
 
a3e0ade
2cb4727
a3e0ade
 
 
 
 
 
 
2cb4727
22e5f83
 
fc3fdb8
 
 
 
 
 
 
 
 
 
 
 
 
 
2cb4727
22e5f83
e0ec429
 
fc3fdb8
3c74ffa
0757010
1949ac7
2cb4727
86b116d
2cb4727
bed2d0a
 
aba1e9b
bed2d0a
 
 
a3e0ade
0757010
2cb4727
 
 
a3e0ade
 
809cf6d
a3e0ade
 
e2ee43d
cbac037
 
 
 
 
 
 
bf25842
2cb4727
0757010
052fcc8
0757010
 
1949ac7
0757010
2cb4727
0757010
 
2cb4727
 
 
a3e0ade
0757010
bed2d0a
2cb4727
d891499
0757010
2cb4727
a3e0ade
0757010
 
fc3fdb8
 
 
 
 
 
 
 
 
 
 
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
import streamlit as st
import time
import os
import sys
import json
from datetime import datetime
from pathlib import Path
sys.path.append(str(Path(__file__).parent))

# Import our new handler
from src.ui.chat_handler import chat_handler
from utils.config import config
from core.session import session_manager
from core.memory import check_redis_health
from core.errors import translate_error
from core.personality import personality
from src.analytics.user_logger import user_logger
from src.analytics.session_analytics import session_analytics
import logging

# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Initialize session state
if "messages" not in st.session_state:
    st.session_state.messages = []
if "is_processing" not in st.session_state:
    st.session_state.is_processing = False
if "ngrok_url_temp" not in st.session_state:
    st.session_state.ngrok_url_temp = st.session_state.get("ngrok_url", "https://7bcc180dffd1.ngrok-free.app")
if "cosmic_mode" not in st.session_state:
    st.session_state.cosmic_mode = True
if "show_welcome" not in st.session_state:
    st.session_state.show_welcome = True
if "session_id" not in st.session_state:
    st.session_state.session_id = f"sess_{int(time.time())}_{os.urandom(4).hex()}"
if "last_processed_message" not in st.session_state:
    st.session_state.last_processed_message = ""

# Start session tracking
session_analytics.start_session_tracking("default_user", st.session_state.session_id)

st.set_page_config(page_title="CosmicCat AI Assistant", page_icon="🐱", layout="wide")

# Log page view
session_analytics.track_interaction("default_user", st.session_state.session_id, "page_view", {
    "page": "main_chat"
})

# Sidebar
with st.sidebar:
    st.title("🐱 CosmicCat AI Assistant")
    st.markdown("Your personal AI-powered assistant with a cosmic twist.")
    
    # Model selection
    model_options = {
        "Mistral 7B (Local)": "mistral:latest",
        "Llama 2 7B (Local)": "llama2:latest", 
        "OpenChat 3.5 (Local)": "openchat:latest"
    }
    selected_model_name = st.selectbox(
        "Select Model",
        options=list(model_options.keys()),
        index=0,
        on_change=lambda: session_analytics.track_interaction("default_user", st.session_state.session_id, "model_selection", {
            "selected_model": st.session_state.selected_model if 'selected_model' in st.session_state else model_options[list(model_options.keys())[0]]
        })
    )
    st.session_state.selected_model = model_options[selected_model_name]
    
    # Log model selection
    session_analytics.track_interaction("default_user", st.session_state.session_id, "model_selection", {
        "selected_model": st.session_state.selected_model
    })
    
    # Cosmic mode toggle
    st.session_state.cosmic_mode = st.checkbox("Enable Cosmic Mode", value=st.session_state.cosmic_mode,
                                              on_change=lambda: session_analytics.track_interaction("default_user", st.session_state.session_id, "cosmic_mode_toggle", {
                                                  "enabled": st.session_state.cosmic_mode
                                              }))
    
    st.divider()
    
    # Configuration
    st.subheader("βš™οΈ Configuration")
    ngrok_url_input = st.text_input(
        "Ollama Server URL",
        value=st.session_state.ngrok_url_temp,
        help="Enter your ngrok URL",
        on_change=lambda: session_analytics.track_interaction("default_user", st.session_state.session_id, "url_update", {
            "url_changed": ngrok_url_input != st.session_state.ngrok_url_temp
        })
    )
    
    if ngrok_url_input != st.session_state.ngrok_url_temp:
        st.session_state.ngrok_url_temp = ngrok_url_input
        st.success("βœ… URL updated!")
        session_analytics.track_interaction("default_user", st.session_state.session_id, "url_updated", {
            "new_url": ngrok_url_input
        })
    
    if st.button("πŸ“‘ Test Connection"):
        start_time = time.time()
        session_analytics.track_interaction("default_user", st.session_state.session_id, "test_connection_click")
        try:
            from core.providers.ollama import OllamaProvider
            ollama_provider = OllamaProvider(st.session_state.selected_model)
            is_valid = ollama_provider.validate_model()
            end_time = time.time()
            
            if is_valid:
                st.success("βœ… Connection successful!")
                session_analytics.track_interaction("default_user", st.session_state.session_id, "connection_success", {
                    "response_time": end_time - start_time
                })
                user_logger.log_performance_metric("default_user", "connection_test", end_time - start_time)
            else:
                st.error("❌ Model validation failed")
                session_analytics.track_interaction("default_user", st.session_state.session_id, "connection_failed", {
                    "error": "model_validation_failed"
                })
        except Exception as e:
            end_time = time.time()
            st.error(f"❌ Error: {str(e)[:50]}...")
            session_analytics.track_interaction("default_user", st.session_state.session_id, "connection_error", {
                "error": str(e)[:100],
                "response_time": end_time - start_time
            })
            user_logger.log_error("default_user", "connection_test", str(e))
    
    if st.button("πŸ—‘οΈ Clear History"):
        session_analytics.track_interaction("default_user", st.session_state.session_id, "clear_history_click")
        st.session_state.messages = []
        st.session_state.last_processed_message = ""
        # Also clear backend session
        session_manager.clear_session("default_user")
        st.success("History cleared!")
        session_analytics.track_interaction("default_user", st.session_state.session_id, "history_cleared")
    
    st.divider()
    
    # System Status with enhanced HF monitoring
    with st.expander("πŸ” System Status", expanded=True):
        st.subheader("πŸ“Š Status")
        
        # Ollama Status
        try:
            from services.ollama_monitor import check_ollama_status
            ollama_status = check_ollama_status()
            if ollama_status.get("running"):
                st.success("πŸ¦™ Ollama: Running")
            else:
                st.warning("πŸ¦™ Ollama: Not running")
        except:
            st.info("πŸ¦™ Ollama: Unknown")
        
        # HF Endpoint Status (Enhanced with initialization info)
        try:
            from src.services.hf_monitor import hf_monitor
            status_message = hf_monitor.get_human_readable_status()
            
            # Display appropriate status icon
            if "🟒" in status_message:
                st.success(status_message)
            elif "🟑" in status_message:
                st.warning(status_message)
            elif "πŸ”΄" in status_message:
                st.error(status_message)
            elif "❌" in status_message:
                st.error(status_message)
            elif "⏳" in status_message:
                st.info(status_message)
            else:
                st.info(status_message)
                
            # Show initialization progress if applicable
            init_progress = hf_monitor.get_initialization_progress()
            if init_progress:
                st.info(init_progress)
                
            # Add wake-up button if scaled to zero or initializing
            if "scaled to zero" in status_message.lower() or "initializing" in status_message.lower():
                if st.button("⚑ Wake Up HF Endpoint", key="wake_up_hf"):
                    session_analytics.track_interaction("default_user", st.session_state.session_id, "wake_up_hf_click")
                    with st.spinner("Attempting to wake up HF endpoint... This may take 2-4 minutes during initialization..."):
                        start_time = time.time()
                        if hf_monitor.attempt_wake_up():
                            end_time = time.time()
                            st.success("βœ… Wake-up request sent! The endpoint should be initializing now. Try your request again in a moment.")
                            session_analytics.track_interaction("default_user", st.session_state.session_id, "hf_wake_up_success", {
                                "response_time": end_time - start_time
                            })
                            user_logger.log_performance_metric("default_user", "hf_wake_up", end_time - start_time)
                            time.sleep(3)
                            st.experimental_rerun()
                        else:
                            end_time = time.time()
                            st.error("❌ Failed to send wake-up request. Please try again or wait for initialization to complete.")
                            session_analytics.track_interaction("default_user", st.session_state.session_id, "hf_wake_up_failed", {
                                "response_time": end_time - start_time
                            })
                            user_logger.log_error("default_user", "hf_wake_up", "Failed to wake up HF endpoint")
                            
        except Exception as e:
            st.info(f"πŸ€— HF Endpoint: Error checking status - {str(e)}")
            session_analytics.track_interaction("default_user", st.session_state.session_id, "hf_status_error", {
                "error": str(e)
            })
            user_logger.log_error("default_user", "hf_status_check", str(e))
        
        # Redis Status
        try:
            if check_redis_health():
                st.success("πŸ’Ύ Redis: Connected")
            else:
                st.error("πŸ’Ύ Redis: Disconnected")
        except:
            st.info("πŸ’Ύ Redis: Unknown")
    
    st.divider()
    
    # Feedback Section
    st.subheader("⭐ Feedback")
    rating = st.radio("How would you rate your experience?", [1, 2, 3, 4, 5], horizontal=True)
    feedback_comment = st.text_area("Additional comments (optional):")
    if st.button("Submit Feedback"):
        user_logger.log_feedback("default_user", rating, feedback_comment)
        session_analytics.track_interaction("default_user", st.session_state.session_id, "feedback_submitted", {
            "rating": rating,
            "has_comment": bool(feedback_comment)
        })
        st.success("Thank you for your feedback! πŸ™")
    
    st.divider()
    
    # Debug Info
    st.subheader("πŸ› Debug Info")
    st.markdown(f"**Environment:** {'HF Space' if config.is_hf_space else 'Local'}")
    st.markdown(f"**Model:** {st.session_state.selected_model}")
    st.markdown(f"**Session ID:** {st.session_state.session_id}")

# Main interface
st.title("🐱 CosmicCat AI Assistant")
st.markdown("Ask me anything!")

# Welcome message
if st.session_state.show_welcome:
    with st.chat_message("assistant"):
        greeting = personality.get_greeting(cosmic_mode=st.session_state.cosmic_mode)
        st.markdown(greeting)
    st.session_state.show_welcome = False

# Display conversation history
for message in st.session_state.messages:
    with st.chat_message(message["role"]):
        st.markdown(message["content"])
        if "timestamp" in message:
            provider_info = f" (via {message.get('provider', 'unknown')})" if message["role"] == "assistant" else ""
            st.caption(f"πŸ•’ {message['timestamp']}{provider_info}")

# Chat input with enhanced processing
user_input = st.chat_input("Type your message here...", key="chat_input")

# Process message when received
if user_input and user_input.strip():
    # Prevent processing if already processing
    if not getattr(chat_handler, 'is_processing', False):
        chat_handler.process_user_message(user_input, selected_model_name)
    else:
        st.warning("Still processing your previous request...")

# About tab
st.divider()
tab1, = st.tabs(["ℹ️ About"])

with tab1:
    st.header("ℹ️ About CosmicCat AI Assistant")
    st.markdown("""
    The CosmicCat AI Assistant is a sophisticated conversational AI with a cosmic theme.
    
    ### 🧠 Core Features
    - **Local AI processing** with Ollama models
    - **Persistent memory** using Redis
    - **Space-themed personality** for fun interactions
    - **HF Endpoint integration** for advanced capabilities
    
    ### πŸš€ Cosmic Mode
    When enabled, the AI responds with space-themed language and metaphors.
    
    ### πŸ› οΈ Technical Architecture
    - **Primary model**: Ollama (local processing)
    - **Secondary model**: HF Endpoint (advanced processing)
    - **Memory system**: Redis-based session management
    """)
    
    # Log about page view
    session_analytics.track_interaction("default_user", st.session_state.session_id, "about_page_view")

# End session tracking when app closes
def on_session_end():
    session_analytics.end_session_tracking("default_user", st.session_state.session_id)

# Register cleanup function
import atexit
atexit.register(on_session_end)