giv3me4shot commited on
Commit
f5c6ab0
Β·
verified Β·
1 Parent(s): 08b22f9

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +366 -0
app.py ADDED
@@ -0,0 +1,366 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import requests
3
+ import os
4
+ import json
5
+ from datetime import datetime
6
+ from typing import List, Tuple
7
+
8
+ # Configuration
9
+ OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY", "")
10
+ OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1"
11
+
12
+ # Available models with details
13
+ MODELS = {
14
+ "OpenAI": {
15
+ "gpt-4-turbo-preview": "Latest GPT-4 Turbo",
16
+ "gpt-4": "GPT-4 Standard",
17
+ "gpt-3.5-turbo": "GPT-3.5 Turbo (Fastest)",
18
+ "gpt-3.5-turbo-16k": "GPT-3.5 Turbo 16K"
19
+ },
20
+ "Anthropic": {
21
+ "anthropic/claude-3-opus-20240229": "Claude 3 Opus (Most Powerful)",
22
+ "anthropic/claude-3-sonnet-20240229": "Claude 3 Sonnet (Balanced)",
23
+ "anthropic/claude-3-haiku-20240307": "Claude 3 Haiku (Fastest)",
24
+ "anthropic/claude-2.1": "Claude 2.1",
25
+ "anthropic/claude-instant-1.2": "Claude Instant"
26
+ },
27
+ "Google": {
28
+ "google/gemini-pro": "Gemini Pro",
29
+ "google/palm-2-chat-bison": "PaLM 2 Chat"
30
+ },
31
+ "Meta": {
32
+ "meta-llama/llama-3-70b-instruct": "Llama 3 70B",
33
+ "meta-llama/llama-3-8b-instruct": "Llama 3 8B",
34
+ "meta-llama/llama-2-70b-chat": "Llama 2 70B"
35
+ },
36
+ "Mistral": {
37
+ "mistralai/mistral-7b-instruct": "Mistral 7B",
38
+ "mistralai/mixtral-8x7b-instruct": "Mixtral 8x7B"
39
+ },
40
+ "Others": {
41
+ "databricks/dbrx-instruct": "DBRX Instruct",
42
+ "cohere/command-r-plus": "Command R+",
43
+ "zero-one-ai/yi-34b-chat": "Yi 34B Chat"
44
+ }
45
+ }
46
+
47
+ # Flatten models for dropdown
48
+ MODEL_OPTIONS = []
49
+ for provider, models in MODELS.items():
50
+ for model_id, model_name in models.items():
51
+ MODEL_OPTIONS.append(f"{provider}: {model_name}")
52
+
53
+ # Custom CSS
54
+ custom_css = """
55
+ .gradio-container {
56
+ font-family: 'Inter', sans-serif;
57
+ }
58
+
59
+ .main-container {
60
+ max-width: 1200px;
61
+ margin: 0 auto;
62
+ }
63
+
64
+ /* Chat container styling */
65
+ .chat-container {
66
+ height: 600px !important;
67
+ overflow-y: auto;
68
+ border-radius: 10px;
69
+ padding: 20px;
70
+ background-color: var(--background-fill-secondary);
71
+ }
72
+
73
+ /* Message styling */
74
+ .message {
75
+ margin: 10px 0;
76
+ padding: 15px;
77
+ border-radius: 10px;
78
+ animation: fadeIn 0.3s ease-in;
79
+ }
80
+
81
+ .user-message {
82
+ background-color: var(--primary-500);
83
+ color: white;
84
+ margin-left: 20%;
85
+ }
86
+
87
+ .assistant-message {
88
+ background-color: var(--neutral-100);
89
+ margin-right: 20%;
90
+ }
91
+
92
+ /* Input area styling */
93
+ .input-container {
94
+ border-top: 2px solid var(--border-color-primary);
95
+ padding-top: 20px;
96
+ margin-top: 20px;
97
+ }
98
+
99
+ /* Model selector styling */
100
+ .model-selector {
101
+ background-color: var(--background-fill-secondary);
102
+ padding: 10px;
103
+ border-radius: 8px;
104
+ margin-bottom: 10px;
105
+ }
106
+
107
+ /* Animation */
108
+ @keyframes fadeIn {
109
+ from { opacity: 0; transform: translateY(10px); }
110
+ to { opacity: 1; transform: translateY(0); }
111
+ }
112
+
113
+ /* Status indicator */
114
+ .status-indicator {
115
+ display: inline-block;
116
+ width: 10px;
117
+ height: 10px;
118
+ border-radius: 50%;
119
+ margin-right: 5px;
120
+ }
121
+
122
+ .status-online { background-color: #10b981; }
123
+ .status-offline { background-color: #ef4444; }
124
+ .status-loading { background-color: #f59e0b; }
125
+ """
126
+
127
+ def get_model_id_from_name(model_name: str) -> str:
128
+ """Extract model ID from display name"""
129
+ for provider, models in MODELS.items():
130
+ for model_id, name in models.items():
131
+ if f"{provider}: {name}" == model_name:
132
+ return model_id
133
+ return "gpt-3.5-turbo" # fallback
134
+
135
+ def check_api_status() -> bool:
136
+ """Check if API key is set and valid"""
137
+ return bool(OPENROUTER_API_KEY)
138
+
139
+ def format_message_history(history: List[Tuple[str, str]]) -> List[dict]:
140
+ """Format chat history for API request"""
141
+ messages = []
142
+ for user_msg, assistant_msg in history:
143
+ if user_msg:
144
+ messages.append({"role": "user", "content": user_msg})
145
+ if assistant_msg:
146
+ messages.append({"role": "assistant", "content": assistant_msg})
147
+ return messages
148
+
149
+ def call_openrouter_api(
150
+ message: str,
151
+ history: List[Tuple[str, str]],
152
+ model_name: str,
153
+ temperature: float,
154
+ max_tokens: int,
155
+ system_prompt: str
156
+ ) -> str:
157
+ """Call OpenRouter API"""
158
+
159
+ if not check_api_status():
160
+ return "❌ API Key not set. Please set OPENROUTER_API_KEY in Space Settings > Variables and Secrets"
161
+
162
+ model_id = get_model_id_from_name(model_name)
163
+
164
+ headers = {
165
+ "Authorization": f"Bearer {OPENROUTER_API_KEY}",
166
+ "Content-Type": "application/json",
167
+ "HTTP-Referer": "https://huggingface.co",
168
+ "X-Title": "HuggingFace Space"
169
+ }
170
+
171
+ # Build messages
172
+ messages = []
173
+ if system_prompt:
174
+ messages.append({"role": "system", "content": system_prompt})
175
+
176
+ messages.extend(format_message_history(history))
177
+ messages.append({"role": "user", "content": message})
178
+
179
+ data = {
180
+ "model": model_id,
181
+ "messages": messages,
182
+ "temperature": temperature,
183
+ "max_tokens": max_tokens,
184
+ "stream": True
185
+ }
186
+
187
+ try:
188
+ response = requests.post(
189
+ f"{OPENROUTER_BASE_URL}/chat/completions",
190
+ headers=headers,
191
+ json=data,
192
+ stream=True
193
+ )
194
+
195
+ if response.status_code != 200:
196
+ return f"❌ Error: {response.status_code} - {response.text}"
197
+
198
+ # Handle streaming response
199
+ full_response = ""
200
+ for line in response.iter_lines():
201
+ if line:
202
+ line_str = line.decode('utf-8')
203
+ if line_str.startswith("data: "):
204
+ if line_str == "data: [DONE]":
205
+ break
206
+ try:
207
+ chunk = json.loads(line_str[6:])
208
+ if 'choices' in chunk and chunk['choices']:
209
+ delta = chunk['choices'][0].get('delta', {})
210
+ content = delta.get('content', '')
211
+ full_response += content
212
+ yield full_response
213
+ except json.JSONDecodeError:
214
+ continue
215
+
216
+ except requests.exceptions.RequestException as e:
217
+ yield f"❌ Connection error: {str(e)}"
218
+ except Exception as e:
219
+ yield f"❌ Unexpected error: {str(e)}"
220
+
221
+ # Create Gradio interface
222
+ with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
223
+ # Header
224
+ gr.Markdown(
225
+ """
226
+ # 🌟 OpenRouter Multi-Model Chat
227
+
228
+ <div style='text-align: center; margin-bottom: 20px;'>
229
+ <p>Chat with various AI models including GPT-4, Claude 3, Gemini, and more!</p>
230
+ <p>Powered by <a href='https://openrouter.ai' target='_blank'>OpenRouter</a></p>
231
+ </div>
232
+ """
233
+ )
234
+
235
+ # API Status
236
+ with gr.Row():
237
+ with gr.Column(scale=1):
238
+ api_status = gr.Markdown(
239
+ f"**API Status:** {'🟒 Connected' if check_api_status() else 'πŸ”΄ Not Connected'}"
240
+ )
241
+
242
+ # Main chat interface
243
+ with gr.Row():
244
+ # Left sidebar - Settings
245
+ with gr.Column(scale=3):
246
+ model_dropdown = gr.Dropdown(
247
+ choices=MODEL_OPTIONS,
248
+ value="OpenAI: GPT-3.5 Turbo (Fastest)",
249
+ label="πŸ€– Select Model",
250
+ interactive=True
251
+ )
252
+
253
+ with gr.Accordion("βš™οΈ Advanced Settings", open=False):
254
+ system_prompt = gr.Textbox(
255
+ label="System Prompt",
256
+ placeholder="You are a helpful assistant...",
257
+ lines=3
258
+ )
259
+
260
+ temperature = gr.Slider(
261
+ minimum=0,
262
+ maximum=2,
263
+ value=0.7,
264
+ step=0.1,
265
+ label="Temperature (Creativity)"
266
+ )
267
+
268
+ max_tokens = gr.Slider(
269
+ minimum=50,
270
+ maximum=4096,
271
+ value=1024,
272
+ step=50,
273
+ label="Max Tokens"
274
+ )
275
+
276
+ # Model info
277
+ gr.Markdown(
278
+ """
279
+ ### πŸ“Š Model Categories
280
+ - **OpenAI**: GPT-4, GPT-3.5
281
+ - **Anthropic**: Claude 3 (Opus, Sonnet, Haiku)
282
+ - **Google**: Gemini Pro, PaLM 2
283
+ - **Meta**: Llama 3, Llama 2
284
+ - **Mistral**: Mistral 7B, Mixtral
285
+ """
286
+ )
287
+
288
+ # Right side - Chat
289
+ with gr.Column(scale=7):
290
+ chatbot = gr.Chatbot(
291
+ height=500,
292
+ label="πŸ’¬ Conversation",
293
+ elem_classes="chat-container"
294
+ )
295
+
296
+ with gr.Row():
297
+ msg = gr.Textbox(
298
+ label="Type your message",
299
+ placeholder="Ask me anything...",
300
+ lines=2,
301
+ scale=9
302
+ )
303
+
304
+ with gr.Column(scale=1, min_width=80):
305
+ send_btn = gr.Button("Send πŸ“€", variant="primary")
306
+ clear_btn = gr.Button("Clear πŸ—‘οΈ")
307
+
308
+ # Examples
309
+ gr.Examples(
310
+ examples=[
311
+ "What are the key differences between GPT-4 and Claude 3?",
312
+ "Write a Python function to calculate fibonacci numbers",
313
+ "Explain quantum computing in simple terms",
314
+ "What's the meaning of life?",
315
+ "Help me write a professional email"
316
+ ],
317
+ inputs=msg,
318
+ label="πŸ’‘ Example Prompts"
319
+ )
320
+
321
+ # Event handlers
322
+ def respond(message, chat_history, model, temp, tokens, sys_prompt):
323
+ bot_message = ""
324
+ for response in call_openrouter_api(
325
+ message, chat_history, model, temp, tokens, sys_prompt
326
+ ):
327
+ bot_message = response
328
+ yield chat_history + [(message, bot_message)]
329
+
330
+ def clear_chat():
331
+ return None
332
+
333
+ # Connect events
334
+ msg.submit(
335
+ respond,
336
+ [msg, chatbot, model_dropdown, temperature, max_tokens, system_prompt],
337
+ chatbot
338
+ ).then(
339
+ lambda: "", None, msg
340
+ )
341
+
342
+ send_btn.click(
343
+ respond,
344
+ [msg, chatbot, model_dropdown, temperature, max_tokens, system_prompt],
345
+ chatbot
346
+ ).then(
347
+ lambda: "", None, msg
348
+ )
349
+
350
+ clear_btn.click(clear_chat, None, chatbot)
351
+
352
+ # Footer
353
+ gr.Markdown(
354
+ """
355
+ ---
356
+ <div style='text-align: center; color: gray;'>
357
+ Made with ❀️ using Gradio |
358
+ <a href='https://github.com/yourusername/yourrepo' target='_blank'>GitHub</a> |
359
+ <a href='https://openrouter.ai/docs' target='_blank'>API Docs</a>
360
+ </div>
361
+ """
362
+ )
363
+
364
+ # Launch
365
+ if __name__ == "__main__":
366
+ demo.launch()