Keeby-smilyai commited on
Commit
cf601e9
Β·
verified Β·
1 Parent(s): ec25395

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +333 -0
app.py ADDED
@@ -0,0 +1,333 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import requests
3
+ import json
4
+ import hashlib
5
+ import time
6
+ from datetime import datetime
7
+
8
+ # Simple in-memory database
9
+ users_db = {}
10
+ usage_db = {}
11
+
12
+ # Configuration
13
+ API_URL = "https://smilyai-labs-sam-z-api.hf.space/v1/chat"
14
+ DAILY_MESSAGE_LIMIT = 50
15
+ RATE_LIMIT_SECONDS = 2
16
+
17
+ def hash_password(password):
18
+ return hashlib.sha256(password.encode()).hexdigest()
19
+
20
+ def check_user_exists(username):
21
+ return username in users_db
22
+
23
+ def register_user(username, password):
24
+ if check_user_exists(username):
25
+ return False, "Username already exists"
26
+
27
+ users_db[username] = {
28
+ 'password': hash_password(password),
29
+ 'created_at': datetime.now()
30
+ }
31
+ usage_db[username] = {
32
+ 'messages_today': 0,
33
+ 'last_reset': datetime.now().date(),
34
+ 'last_message_time': 0
35
+ }
36
+ return True, "Account created successfully!"
37
+
38
+ def login_user(username, password):
39
+ if not check_user_exists(username):
40
+ return False, "Username not found"
41
+
42
+ if users_db[username]['password'] != hash_password(password):
43
+ return False, "Incorrect password"
44
+
45
+ return True, "Login successful!"
46
+
47
+ def check_usage_limits(username):
48
+ if username not in usage_db:
49
+ usage_db[username] = {
50
+ 'messages_today': 0,
51
+ 'last_reset': datetime.now().date(),
52
+ 'last_message_time': 0
53
+ }
54
+
55
+ user_usage = usage_db[username]
56
+
57
+ # Reset daily counter
58
+ if user_usage['last_reset'] != datetime.now().date():
59
+ user_usage['messages_today'] = 0
60
+ user_usage['last_reset'] = datetime.now().date()
61
+
62
+ # Check daily limit
63
+ if user_usage['messages_today'] >= DAILY_MESSAGE_LIMIT:
64
+ return False, f"Daily limit of {DAILY_MESSAGE_LIMIT} messages reached. Try again tomorrow."
65
+
66
+ # Check rate limit
67
+ time_since_last = time.time() - user_usage['last_message_time']
68
+ if time_since_last < RATE_LIMIT_SECONDS:
69
+ wait_time = RATE_LIMIT_SECONDS - time_since_last
70
+ return False, f"Please wait {wait_time:.1f} seconds before sending another message."
71
+
72
+ return True, ""
73
+
74
+ def update_usage(username):
75
+ usage_db[username]['messages_today'] += 1
76
+ usage_db[username]['last_message_time'] = time.time()
77
+
78
+ def get_usage_info(username):
79
+ if username not in usage_db:
80
+ return f"Messages today: 0/{DAILY_MESSAGE_LIMIT}"
81
+
82
+ user_usage = usage_db[username]
83
+ if user_usage['last_reset'] != datetime.now().date():
84
+ return f"Messages today: 0/{DAILY_MESSAGE_LIMIT}"
85
+
86
+ return f"Messages today: {user_usage['messages_today']}/{DAILY_MESSAGE_LIMIT}"
87
+
88
+ def chat_function(message, history, username):
89
+ """Non-streaming chat function that yields incrementally"""
90
+ if not username:
91
+ history.append([message, "⚠️ Please log in first"])
92
+ return history
93
+
94
+ # Check usage limits
95
+ can_send, error_msg = check_usage_limits(username)
96
+ if not can_send:
97
+ history.append([message, f"⚠️ {error_msg}"])
98
+ return history
99
+
100
+ # Update usage
101
+ update_usage(username)
102
+
103
+ # Prepare messages for API
104
+ messages = []
105
+ for user_msg, assistant_msg in history:
106
+ if user_msg:
107
+ messages.append({"role": "user", "content": user_msg})
108
+ if assistant_msg:
109
+ messages.append({"role": "assistant", "content": assistant_msg})
110
+ messages.append({"role": "user", "content": message})
111
+
112
+ # Add user message to history
113
+ history.append([message, ""])
114
+
115
+ try:
116
+ # Make streaming request
117
+ response = requests.post(
118
+ API_URL,
119
+ json={
120
+ "messages": messages,
121
+ "max_tokens": 1000,
122
+ "stream": True
123
+ },
124
+ stream=True,
125
+ timeout=60
126
+ )
127
+
128
+ if response.status_code != 200:
129
+ history[-1][1] = f"❌ Error: Server returned status {response.status_code}"
130
+ return history
131
+
132
+ full_response = ""
133
+ buffer = ""
134
+
135
+ # Stream the response
136
+ for chunk in response.iter_content(chunk_size=1):
137
+ if chunk:
138
+ buffer += chunk.decode('utf-8', errors='ignore')
139
+
140
+ # Process complete lines
141
+ while '\n' in buffer:
142
+ line, buffer = buffer.split('\n', 1)
143
+ line = line.strip()
144
+
145
+ if line.startswith('data: '):
146
+ data = line[6:]
147
+
148
+ if data == '[DONE]':
149
+ break
150
+
151
+ try:
152
+ parsed = json.loads(data)
153
+ content = parsed.get('choices', [{}])[0].get('delta', {}).get('content', '')
154
+
155
+ if content:
156
+ full_response += content
157
+ history[-1][1] = full_response
158
+ yield history
159
+ except json.JSONDecodeError:
160
+ continue
161
+
162
+ # Final yield
163
+ if full_response:
164
+ history[-1][1] = full_response
165
+ else:
166
+ history[-1][1] = "❌ No response received from server"
167
+
168
+ return history
169
+
170
+ except requests.exceptions.Timeout:
171
+ history[-1][1] = "❌ Request timed out. Please try again."
172
+ return history
173
+ except requests.exceptions.RequestException as e:
174
+ history[-1][1] = f"❌ Connection error: {str(e)}"
175
+ return history
176
+ except Exception as e:
177
+ history[-1][1] = f"❌ Unexpected error: {str(e)}"
178
+ return history
179
+
180
+ def handle_auth(username, password):
181
+ """Handle authentication - auto-detect sign in or sign up"""
182
+ if not username or not password:
183
+ return None, "❌ Please enter both username and password", gr.update(visible=True), gr.update(visible=False), "", []
184
+
185
+ if len(username) < 3:
186
+ return None, "❌ Username must be at least 3 characters", gr.update(visible=True), gr.update(visible=False), "", []
187
+
188
+ if len(password) < 6:
189
+ return None, "❌ Password must be at least 6 characters", gr.update(visible=True), gr.update(visible=False), "", []
190
+
191
+ # Check if user exists
192
+ if check_user_exists(username):
193
+ # Try to login
194
+ success, message = login_user(username, password)
195
+ if success:
196
+ return username, f"βœ… Welcome back, {username}!", gr.update(visible=False), gr.update(visible=True), get_usage_info(username), []
197
+ else:
198
+ return None, f"❌ {message}", gr.update(visible=True), gr.update(visible=False), "", []
199
+ else:
200
+ # Auto-register new user
201
+ success, message = register_user(username, password)
202
+ if success:
203
+ return username, f"βœ… Welcome, {username}! Your account has been created.", gr.update(visible=False), gr.update(visible=True), get_usage_info(username), []
204
+ else:
205
+ return None, f"❌ {message}", gr.update(visible=True), gr.update(visible=False), "", []
206
+
207
+ def logout_user():
208
+ """Logout current user"""
209
+ return None, "πŸ‘‹ Logged out successfully", gr.update(visible=True), gr.update(visible=False), "", []
210
+
211
+ def refresh_usage(username):
212
+ """Refresh usage display"""
213
+ if username:
214
+ return get_usage_info(username)
215
+ return ""
216
+
217
+ # Custom CSS
218
+ custom_css = """
219
+ .auth-container {
220
+ max-width: 500px;
221
+ margin: 0 auto;
222
+ }
223
+ .chat-container {
224
+ max-width: 900px;
225
+ margin: 0 auto;
226
+ }
227
+ """
228
+
229
+ # Create Gradio interface
230
+ with gr.Blocks(theme=gr.themes.Soft(), css=custom_css, title="AI Chatbot") as demo:
231
+ current_user = gr.State(None)
232
+
233
+ gr.Markdown("# πŸ€– AI Chatbot with Authentication & Limits")
234
+
235
+ with gr.Row():
236
+ with gr.Column(scale=2):
237
+ auth_status = gr.Markdown("### Please log in or create an account")
238
+ with gr.Column(scale=1):
239
+ usage_display = gr.Markdown("")
240
+
241
+ # Authentication section
242
+ with gr.Group(visible=True, elem_classes="auth-container") as auth_section:
243
+ gr.Markdown("### πŸ” Login or Sign Up")
244
+ gr.Markdown("*Enter your credentials. New username? Account will be created automatically!*")
245
+ username_input = gr.Textbox(label="Username", placeholder="Enter username (min 3 chars)")
246
+ password_input = gr.Textbox(label="Password", type="password", placeholder="Enter password (min 6 chars)")
247
+ auth_button = gr.Button("πŸš€ Login / Sign Up", variant="primary", size="lg")
248
+
249
+ # Chat section
250
+ with gr.Group(visible=False, elem_classes="chat-container") as chat_section:
251
+ chatbot = gr.Chatbot(height=500, show_label=False, bubble_full_width=False)
252
+ with gr.Row():
253
+ msg_input = gr.Textbox(
254
+ label="Message",
255
+ placeholder="Type your message here and press Enter...",
256
+ scale=9,
257
+ show_label=False
258
+ )
259
+ send_button = gr.Button("Send", variant="primary", scale=1)
260
+ with gr.Row():
261
+ clear_button = gr.ClearButton([chatbot], value="πŸ—‘οΈ Clear Chat", size="sm")
262
+ refresh_button = gr.Button("πŸ”„ Refresh Usage", size="sm")
263
+ logout_button = gr.Button("πŸšͺ Logout", size="sm", variant="stop")
264
+
265
+ # Info section
266
+ with gr.Accordion("ℹ️ Information & Limits", open=False):
267
+ gr.Markdown(f"""
268
+ **Usage Limits:**
269
+ - πŸ“Š Daily message limit: {DAILY_MESSAGE_LIMIT} messages per user
270
+ - ⏱️ Rate limit: 1 message every {RATE_LIMIT_SECONDS} seconds
271
+ - πŸ”„ Limits reset daily at midnight
272
+
273
+ **Features:**
274
+ - 🎯 Auto-detect login/signup (creates account if username doesn't exist)
275
+ - 🌊 Real-time streaming responses from AI
276
+ - πŸ’Ύ Conversation history tracking
277
+ - πŸ“ˆ Usage monitoring and enforcement
278
+ - πŸ”’ Secure password hashing
279
+
280
+ **How to use:**
281
+ 1. Enter a username and password
282
+ 2. Click "Login / Sign Up" - if the username is new, an account will be created
283
+ 3. Start chatting! Watch your usage limits in the top right
284
+ """)
285
+
286
+ # Event handlers
287
+ def submit_auth(username, password):
288
+ return handle_auth(username, password)
289
+
290
+ auth_button.click(
291
+ submit_auth,
292
+ inputs=[username_input, password_input],
293
+ outputs=[current_user, auth_status, auth_section, chat_section, usage_display, chatbot]
294
+ )
295
+
296
+ # Chat submit with streaming
297
+ msg_input.submit(
298
+ chat_function,
299
+ inputs=[msg_input, chatbot, current_user],
300
+ outputs=[chatbot]
301
+ ).then(
302
+ lambda: "", None, msg_input
303
+ ).then(
304
+ refresh_usage,
305
+ inputs=[current_user],
306
+ outputs=[usage_display]
307
+ )
308
+
309
+ send_button.click(
310
+ chat_function,
311
+ inputs=[msg_input, chatbot, current_user],
312
+ outputs=[chatbot]
313
+ ).then(
314
+ lambda: "", None, msg_input
315
+ ).then(
316
+ refresh_usage,
317
+ inputs=[current_user],
318
+ outputs=[usage_display]
319
+ )
320
+
321
+ refresh_button.click(
322
+ refresh_usage,
323
+ inputs=[current_user],
324
+ outputs=[usage_display]
325
+ )
326
+
327
+ logout_button.click(
328
+ logout_user,
329
+ outputs=[current_user, auth_status, auth_section, chat_section, usage_display, chatbot]
330
+ )
331
+
332
+ if __name__ == "__main__":
333
+ demo.launch(server_name="0.0.0.0", server_port=7860, share=False)