aiqcamp commited on
Commit
11ffe40
Β·
verified Β·
1 Parent(s): 3db7444

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +283 -31
app.py CHANGED
@@ -3,9 +3,13 @@ import os
3
  from getpass import getpass
4
  from openai import OpenAI
5
  import gradio as gr
 
 
 
6
 
7
  # β€”β€”β€” Configure your OpenRouter key β€”β€”β€”
8
  OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY")
 
9
 
10
  # Check if the API key was retrieved
11
  if not OPENROUTER_API_KEY:
@@ -17,43 +21,291 @@ else:
17
  api_key=OPENROUTER_API_KEY,
18
  )
19
 
20
- def openrouter_chat(user_message, history):
21
- """Send user_message and history to mistralai/devstral-small:free and append to history."""
22
- history = history or []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
- # Build the messages list from the history and the current user message
25
- # Gradio history is a list of tuples [(user_msg, bot_msg), ...]
26
- # We need to convert it to the OpenAI API format: list of dicts [{"role": "user", "content": ...}, {"role": "assistant", "content": ...}, ...]
27
- messages_for_api = []
28
- for human_message, ai_message in history:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  messages_for_api.append({"role": "user", "content": human_message})
30
- if ai_message is not None: # Only add assistant message if it exists
31
  messages_for_api.append({"role": "assistant", "content": ai_message})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
- # Add the current user message
34
- messages_for_api.append({"role": "user", "content": user_message})
 
 
 
 
 
 
35
 
36
- try:
37
- # Call the model with the mistralai/Devstral-Small-2505 for full conversation history
38
- resp = client.chat.completions.create(
39
- model="mistralai/devstral-small:free",
40
- messages=messages_for_api,
41
- # you can tweak max_tokens, temperature, etc. here
42
- )
43
- bot_reply = resp.choices[0].message.content
44
- # Append the user message and bot reply to the history for Gradio display
45
- history.append((user_message, bot_reply))
46
- except Exception as e:
47
- # Handle potential errors and append an error message to the history
48
- history.append((user_message, f"Error: {e}"))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
 
 
 
 
 
 
 
 
 
 
50
 
51
- return history, ""
 
 
 
52
 
53
- with gr.Blocks() as demo:
54
- gr.Markdown("## πŸ¦œπŸ”— Gradio + OpenRouter Chat with Devstral-Small (with History)")
55
- chatbot = gr.Chatbot(label="Chat")
56
- msg_in = gr.Textbox(placeholder="Type your question here…", label="You")
57
- msg_in.submit(openrouter_chat, inputs=[msg_in, chatbot], outputs=[chatbot, msg_in])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
 
59
- demo.launch()
 
3
  from getpass import getpass
4
  from openai import OpenAI
5
  import gradio as gr
6
+ import requests
7
+ import json
8
+ from datetime import datetime
9
 
10
  # β€”β€”β€” Configure your OpenRouter key β€”β€”β€”
11
  OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY")
12
+ BSEARCH_API = os.getenv("BSEARCH_API")
13
 
14
  # Check if the API key was retrieved
15
  if not OPENROUTER_API_KEY:
 
21
  api_key=OPENROUTER_API_KEY,
22
  )
23
 
24
+ # Brave Search function
25
+ def brave_search(query):
26
+ """Perform a web search using Brave Search API."""
27
+ if not BSEARCH_API:
28
+ return "Error: BSEARCH_API not found in environment. Please set your Brave Search API key."
29
+
30
+ try:
31
+ headers = {
32
+ "Accept": "application/json",
33
+ "X-Subscription-Token": BSEARCH_API
34
+ }
35
+
36
+ # Brave Search API endpoint
37
+ url = "https://api.search.brave.com/res/v1/web/search"
38
+ params = {
39
+ "q": query,
40
+ "count": 5 # Number of results to return
41
+ }
42
+
43
+ response = requests.get(url, headers=headers, params=params)
44
+ response.raise_for_status()
45
+
46
+ data = response.json()
47
+
48
+ # Format the search results
49
+ results = []
50
+ if "web" in data and "results" in data["web"]:
51
+ for idx, result in enumerate(data["web"]["results"][:5], 1):
52
+ title = result.get("title", "No title")
53
+ url = result.get("url", "")
54
+ description = result.get("description", "No description")
55
+ results.append(f"{idx}. **{title}**\n URL: {url}\n {description}\n")
56
+
57
+ if results:
58
+ return "πŸ” **Web Search Results:**\n\n" + "\n".join(results)
59
+ else:
60
+ return "No search results found."
61
+
62
+ except Exception as e:
63
+ return f"Search error: {str(e)}"
64
 
65
+ def openrouter_chat(user_message, history, use_web_search):
66
+ """Send user_message and history to mistralai/devstral-small:free and append to history."""
67
+ history = history or []
68
+
69
+ # If web search is enabled, perform search first
70
+ search_context = ""
71
+ if use_web_search and user_message.strip():
72
+ search_results = brave_search(user_message)
73
+ search_context = f"\n\n{search_results}\n\nBased on the above search results, please answer the following question:\n"
74
+ # Add search results to history as a system message
75
+ history.append(("πŸ” Web Search Query", user_message))
76
+ history.append(("🌐 Search Results", search_results))
77
+
78
+ # Build the messages list from the history and the current user message
79
+ messages_for_api = []
80
+
81
+ # Add system message if web search was used
82
+ if search_context:
83
+ messages_for_api.append({
84
+ "role": "system",
85
+ "content": "You are a helpful assistant. When web search results are provided, incorporate them into your response to give accurate and up-to-date information."
86
+ })
87
+
88
+ for human_message, ai_message in history[:-2] if use_web_search else history: # Exclude search entries from API messages
89
+ if not human_message.startswith("πŸ”") and not human_message.startswith("🌐"):
90
  messages_for_api.append({"role": "user", "content": human_message})
91
+ if ai_message is not None:
92
  messages_for_api.append({"role": "assistant", "content": ai_message})
93
+
94
+ # Add the current user message with search context if applicable
95
+ current_message = search_context + user_message if search_context else user_message
96
+ messages_for_api.append({"role": "user", "content": current_message})
97
+
98
+ try:
99
+ # Call the model with the mistralai/Devstral-Small-2505 for full conversation history
100
+ resp = client.chat.completions.create(
101
+ model="mistralai/devstral-small:free",
102
+ messages=messages_for_api,
103
+ # you can tweak max_tokens, temperature, etc. here
104
+ )
105
+ bot_reply = resp.choices[0].message.content
106
+ # Append the user message and bot reply to the history for Gradio display
107
+ history.append((user_message, bot_reply))
108
+ except Exception as e:
109
+ # Handle potential errors and append an error message to the history
110
+ history.append((user_message, f"Error: {e}"))
111
+
112
+ return history, ""
113
 
114
+ # Enhanced CSS with gradient background and visual improvements
115
+ custom_css = """
116
+ /* Gradient background */
117
+ .gradio-container {
118
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 25%, #f093fb 50%, #4facfe 75%, #00f2fe 100%);
119
+ min-height: 100vh;
120
+ padding: 20px;
121
+ }
122
 
123
+ /* Main container styling */
124
+ .container {
125
+ max-width: 1200px;
126
+ margin: 0 auto;
127
+ }
128
+
129
+ /* Chat container with glassmorphism effect */
130
+ #component-0 {
131
+ background: rgba(255, 255, 255, 0.1);
132
+ backdrop-filter: blur(10px);
133
+ border-radius: 20px;
134
+ border: 1px solid rgba(255, 255, 255, 0.2);
135
+ box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
136
+ padding: 20px;
137
+ }
138
+
139
+ /* Chatbot styling */
140
+ .chatbot {
141
+ background: rgba(255, 255, 255, 0.9) !important;
142
+ border-radius: 15px !important;
143
+ border: none !important;
144
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1) !important;
145
+ }
146
+
147
+ /* Message bubbles */
148
+ .message {
149
+ border-radius: 10px !important;
150
+ padding: 12px 16px !important;
151
+ margin: 8px 0 !important;
152
+ }
153
+
154
+ .user {
155
+ background-color: #667eea !important;
156
+ color: white !important;
157
+ margin-left: 20% !important;
158
+ }
159
+
160
+ .bot {
161
+ background-color: #f0f0f0 !important;
162
+ color: #333 !important;
163
+ margin-right: 20% !important;
164
+ }
165
+
166
+ /* Input styling */
167
+ .textbox {
168
+ border-radius: 10px !important;
169
+ border: 2px solid #667eea !important;
170
+ background: rgba(255, 255, 255, 0.95) !important;
171
+ font-size: 16px !important;
172
+ }
173
+
174
+ .textbox:focus {
175
+ border-color: #764ba2 !important;
176
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.2) !important;
177
+ }
178
+
179
+ /* Checkbox styling */
180
+ .checkbox-group {
181
+ background: rgba(255, 255, 255, 0.8) !important;
182
+ border-radius: 10px !important;
183
+ padding: 10px !important;
184
+ margin: 10px 0 !important;
185
+ }
186
 
187
+ /* Button styling */
188
+ button {
189
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
190
+ color: white !important;
191
+ border: none !important;
192
+ border-radius: 10px !important;
193
+ padding: 10px 20px !important;
194
+ font-weight: bold !important;
195
+ transition: all 0.3s ease !important;
196
+ }
197
 
198
+ button:hover {
199
+ transform: translateY(-2px) !important;
200
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3) !important;
201
+ }
202
 
203
+ /* Title styling */
204
+ h1, h2 {
205
+ color: white !important;
206
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3) !important;
207
+ }
208
+
209
+ /* Markdown styling */
210
+ .markdown-text {
211
+ color: white !important;
212
+ text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3) !important;
213
+ }
214
+
215
+ /* Web search results styling */
216
+ .message:has(.search-results) {
217
+ background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%) !important;
218
+ border-left: 4px solid #ff6b6b !important;
219
+ }
220
+
221
+ /* Responsive design */
222
+ @media (max-width: 768px) {
223
+ .user {
224
+ margin-left: 10% !important;
225
+ }
226
+ .bot {
227
+ margin-right: 10% !important;
228
+ }
229
+ }
230
+ """
231
+
232
+ with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
233
+ gr.Markdown(
234
+ """
235
+ <div style="text-align: center; padding: 20px;">
236
+ <h1 style="font-size: 3em; margin-bottom: 10px;">πŸ¦œπŸ”— AI Chat Assistant</h1>
237
+ <h2 style="font-size: 1.5em; opacity: 0.9;">Powered by Devstral-Small with Brave Search Integration</h2>
238
+ </div>
239
+ """,
240
+ elem_id="header"
241
+ )
242
+
243
+ with gr.Row():
244
+ with gr.Column(scale=4):
245
+ chatbot = gr.Chatbot(
246
+ label="πŸ’¬ Chat History",
247
+ height=500,
248
+ elem_classes=["chatbot"],
249
+ bubble_full_width=False
250
+ )
251
+
252
+ with gr.Row():
253
+ msg_in = gr.Textbox(
254
+ placeholder="Type your question here… (Press Enter to send)",
255
+ label="✍️ Your Message",
256
+ scale=4,
257
+ lines=2
258
+ )
259
+
260
+ with gr.Row():
261
+ use_web_search = gr.Checkbox(
262
+ label="πŸ” Enable Web Search",
263
+ value=True,
264
+ info="Search the web for current information before answering"
265
+ )
266
+ clear_btn = gr.Button("πŸ—‘οΈ Clear Chat", size="sm")
267
+
268
+ with gr.Column(scale=1):
269
+ gr.Markdown(
270
+ """
271
+ ### πŸ“‹ Features
272
+ - πŸ’¬ Real-time chat with AI
273
+ - πŸ” Web search integration
274
+ - πŸ“œ Conversation history
275
+ - 🎨 Beautiful gradient UI
276
+
277
+ ### πŸ”§ Tips
278
+ - Enable web search for current events
279
+ - Ask follow-up questions
280
+ - Clear chat to start fresh
281
+
282
+ ### ⚑ Shortcuts
283
+ - Enter: Send message
284
+ - Shift+Enter: New line
285
+ """,
286
+ elem_classes=["markdown-text"]
287
+ )
288
+
289
+ # Event handlers
290
+ msg_in.submit(
291
+ openrouter_chat,
292
+ inputs=[msg_in, chatbot, use_web_search],
293
+ outputs=[chatbot, msg_in]
294
+ )
295
+
296
+ clear_btn.click(lambda: ([], ""), outputs=[chatbot, msg_in])
297
+
298
+ # Add example queries
299
+ gr.Examples(
300
+ examples=[
301
+ ["What's the latest news about AI?", True],
302
+ ["Explain quantum computing in simple terms", False],
303
+ ["What's the weather like today?", True],
304
+ ["Write a Python function to sort a list", False],
305
+ ["What are the current stock market trends?", True]
306
+ ],
307
+ inputs=[msg_in, use_web_search],
308
+ label="πŸ’‘ Example Queries"
309
+ )
310
 
311
+ demo.launch()