cstr commited on
Commit
b142a4a
·
verified ·
1 Parent(s): 9144903

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +190 -252
app.py CHANGED
@@ -10,66 +10,16 @@ import time
10
  # Get API key from environment variable for security
11
  OPENROUTER_API_KEY = os.environ.get("OPENROUTER_API_KEY", "")
12
 
13
-
14
- # Model information
15
  free_models = [
16
- ("Google: Gemini Pro 2.0 Experimental (free)", "google/gemini-2.0-pro-exp-02-05:free", 0, 0, 2000000),
17
- ("Google: Gemini 2.0 Flash Thinking Experimental 01-21 (free)", "google/gemini-2.0-flash-thinking-exp:free", 0, 0, 1048576),
18
- ("Google: Gemini Flash 2.0 Experimental (free)", "google/gemini-2.0-flash-exp:free", 0, 0, 1048576),
19
- ("Google: Gemini Pro 2.5 Experimental (free)", "google/gemini-2.5-pro-exp-03-25:free", 0, 0, 1000000),
20
- ("Google: Gemini Flash 1.5 8B Experimental", "google/gemini-flash-1.5-8b-exp", 0, 0, 1000000),
21
- ("DeepSeek: DeepSeek R1 Zero (free)", "deepseek/deepseek-r1-zero:free", 0, 0, 163840),
22
- ("DeepSeek: R1 (free)", "deepseek/deepseek-r1:free", 0, 0, 163840),
23
- ("DeepSeek: DeepSeek V3 Base (free)", "deepseek/deepseek-v3-base:free", 0, 0, 131072),
24
- ("DeepSeek: DeepSeek V3 0324 (free)", "deepseek/deepseek-chat-v3-0324:free", 0, 0, 131072),
25
- ("Google: Gemma 3 4B (free)", "google/gemma-3-4b-it:free", 0, 0, 131072),
26
- ("Google: Gemma 3 12B (free)", "google/gemma-3-12b-it:free", 0, 0, 131072),
27
- ("Nous: DeepHermes 3 Llama 3 8B Preview (free)", "nousresearch/deephermes-3-llama-3-8b-preview:free", 0, 0, 131072),
28
- ("Qwen: Qwen2.5 VL 72B Instruct (free)", "qwen/qwen2.5-vl-72b-instruct:free", 0, 0, 131072),
29
- ("DeepSeek: DeepSeek V3 (free)", "deepseek/deepseek-chat:free", 0, 0, 131072),
30
- ("NVIDIA: Llama 3.1 Nemotron 70B Instruct (free)", "nvidia/llama-3.1-nemotron-70b-instruct:free", 0, 0, 131072),
31
- ("Meta: Llama 3.2 1B Instruct (free)", "meta-llama/llama-3.2-1b-instruct:free", 0, 0, 131072),
32
- ("Meta: Llama 3.2 11B Vision Instruct (free)", "meta-llama/llama-3.2-11b-vision-instruct:free", 0, 0, 131072),
33
- ("Meta: Llama 3.1 8B Instruct (free)", "meta-llama/llama-3.1-8b-instruct:free", 0, 0, 131072),
34
- ("Mistral: Mistral Nemo (free)", "mistralai/mistral-nemo:free", 0, 0, 128000),
35
- ("Mistral: Mistral Small 3.1 24B (free)", "mistralai/mistral-small-3.1-24b-instruct:free", 0, 0, 96000),
36
- ("Google: Gemma 3 27B (free)", "google/gemma-3-27b-it:free", 0, 0, 96000),
37
- ("Qwen: Qwen2.5 VL 3B Instruct (free)", "qwen/qwen2.5-vl-3b-instruct:free", 0, 0, 64000),
38
- ("DeepSeek: R1 Distill Qwen 14B (free)", "deepseek/deepseek-r1-distill-qwen-14b:free", 0, 0, 64000),
39
- ("Qwen: Qwen2.5-VL 7B Instruct (free)", "qwen/qwen-2.5-vl-7b-instruct:free", 0, 0, 64000),
40
- ("Google: LearnLM 1.5 Pro Experimental (free)", "google/learnlm-1.5-pro-experimental:free", 0, 0, 40960),
41
- ("Qwen: QwQ 32B (free)", "qwen/qwq-32b:free", 0, 0, 40000),
42
- ("Google: Gemini 2.0 Flash Thinking Experimental (free)", "google/gemini-2.0-flash-thinking-exp-1219:free", 0, 0, 40000),
43
- ("Bytedance: UI-TARS 72B (free)", "bytedance-research/ui-tars-72b:free", 0, 0, 32768),
44
- ("Qwerky 72b (free)", "featherless/qwerky-72b:free", 0, 0, 32768),
45
- ("OlympicCoder 7B (free)", "open-r1/olympiccoder-7b:free", 0, 0, 32768),
46
- ("OlympicCoder 32B (free)", "open-r1/olympiccoder-32b:free", 0, 0, 32768),
47
- ("Google: Gemma 3 1B (free)", "google/gemma-3-1b-it:free", 0, 0, 32768),
48
- ("Reka: Flash 3 (free)", "rekaai/reka-flash-3:free", 0, 0, 32768),
49
- ("Dolphin3.0 R1 Mistral 24B (free)", "cognitivecomputations/dolphin3.0-r1-mistral-24b:free", 0, 0, 32768),
50
- ("Dolphin3.0 Mistral 24B (free)", "cognitivecomputations/dolphin3.0-mistral-24b:free", 0, 0, 32768),
51
- ("Mistral: Mistral Small 3 (free)", "mistralai/mistral-small-24b-instruct-2501:free", 0, 0, 32768),
52
- ("Qwen2.5 Coder 32B Instruct (free)", "qwen/qwen-2.5-coder-32b-instruct:free", 0, 0, 32768),
53
- ("Qwen2.5 72B Instruct (free)", "qwen/qwen-2.5-72b-instruct:free", 0, 0, 32768),
54
- ("Meta: Llama 3.2 3B Instruct (free)", "meta-llama/llama-3.2-3b-instruct:free", 0, 0, 20000),
55
- ("Qwen: QwQ 32B Preview (free)", "qwen/qwq-32b-preview:free", 0, 0, 16384),
56
- ("DeepSeek: R1 Distill Qwen 32B (free)", "deepseek/deepseek-r1-distill-qwen-32b:free", 0, 0, 16000),
57
- ("Qwen: Qwen2.5 VL 32B Instruct (free)", "qwen/qwen2.5-vl-32b-instruct:free", 0, 0, 8192),
58
- ("Moonshot AI: Moonlight 16B A3B Instruct (free)", "moonshotai/moonlight-16b-a3b-instruct:free", 0, 0, 8192),
59
- ("DeepSeek: R1 Distill Llama 70B (free)", "deepseek/deepseek-r1-distill-llama-70b:free", 0, 0, 8192),
60
- ("Qwen 2 7B Instruct (free)", "qwen/qwen-2-7b-instruct:free", 0, 0, 8192),
61
- ("Google: Gemma 2 9B (free)", "google/gemma-2-9b-it:free", 0, 0, 8192),
62
- ("Mistral: Mistral 7B Instruct (free)", "mistralai/mistral-7b-instruct:free", 0, 0, 8192),
63
- ("Microsoft: Phi-3 Mini 128K Instruct (free)", "microsoft/phi-3-mini-128k-instruct:free", 0, 0, 8192),
64
- ("Microsoft: Phi-3 Medium 128K Instruct (free)", "microsoft/phi-3-medium-128k-instruct:free", 0, 0, 8192),
65
- ("Meta: Llama 3 8B Instruct (free)", "meta-llama/llama-3-8b-instruct:free", 0, 0, 8192),
66
- ("OpenChat 3.5 7B (free)", "openchat/openchat-7b:free", 0, 0, 8192),
67
- ("Meta: Llama 3.3 70B Instruct (free)", "meta-llama/llama-3.3-70b-instruct:free", 0, 0, 8000),
68
- ("AllenAI: Molmo 7B D (free)", "allenai/molmo-7b-d:free", 0, 0, 4096),
69
- ("Rogue Rose 103B v0.2 (free)", "sophosympatheia/rogue-rose-103b-v0.2:free", 0, 0, 4096),
70
- ("Toppy M 7B (free)", "undi95/toppy-m-7b:free", 0, 0, 4096),
71
- ("Hugging Face: Zephyr 7B (free)", "huggingfaceh4/zephyr-7b-beta:free", 0, 0, 4096),
72
- ("MythoMax 13B (free)", "gryphe/mythomax-l2-13b:free", 0, 0, 4096),
73
  ]
74
 
75
  # Helper functions
@@ -87,65 +37,31 @@ def encode_file(file_path):
87
  except Exception as e:
88
  return f"Error reading file: {str(e)}"
89
 
90
- def process_api_call(messages, model_id, temperature=0.7, top_p=1.0, max_tokens=1000, stream=False):
91
- """Make API call to OpenRouter"""
92
- headers = {
93
- "Content-Type": "application/json",
94
- "Authorization": f"Bearer {OPENROUTER_API_KEY}",
95
- "HTTP-Referer": "https://huggingface.co/spaces",
96
- }
97
 
98
- url = "https://openrouter.ai/api/v1/chat/completions"
99
-
100
- data = {
101
- "model": model_id,
102
- "messages": messages,
103
- "stream": stream,
104
- "temperature": temperature,
105
- "top_p": top_p,
106
- "max_tokens": max_tokens
107
- }
108
-
109
- return requests.post(url, headers=headers, json=data, stream=stream)
110
-
111
- def update_conversation(message, chat_history, model_choice, uploaded_image=None, uploaded_file=None,
112
- temp=0.7, top_p=1.0, max_tokens=1000, stream_response=False):
113
- """Update conversation with new message"""
114
- # Get model ID from model_choice
115
- model_id = None
116
- for name, model_id_value, *_ in free_models:
117
- if name == model_choice or model_id_value == model_choice:
118
- model_id = model_id_value
119
- break
120
-
121
- if not model_id:
122
- # Fallback to a default model
123
- model_id = "google/gemini-2.0-pro-exp-02-05:free"
124
-
125
- # Build messages array from chat history
126
  messages = []
127
- for msg in chat_history:
128
- if isinstance(msg, dict):
129
- messages.append(msg)
130
- elif isinstance(msg, tuple) and len(msg) == 2:
131
- # Handle legacy tuple format
132
- user_msg, ai_msg = msg
133
  messages.append({"role": "user", "content": user_msg})
134
  messages.append({"role": "assistant", "content": ai_msg})
135
 
136
- # Prepare the new user message
137
- content = message
138
-
139
- # Handle file attachment
140
  if uploaded_file:
141
  file_content = encode_file(uploaded_file)
142
- content = f"{message}\n\nFile content:\n```\n{file_content}\n```"
143
 
144
- # Handle image
145
  if uploaded_image:
 
146
  base64_image = encode_image(uploaded_image)
147
- image_content = [
148
- {"type": "text", "text": content},
149
  {
150
  "type": "image_url",
151
  "image_url": {
@@ -153,147 +69,160 @@ def update_conversation(message, chat_history, model_choice, uploaded_image=None
153
  }
154
  }
155
  ]
156
- messages.append({"role": "user", "content": image_content})
157
- else:
158
  messages.append({"role": "user", "content": content})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
 
160
  # Add message to chat history
161
- user_message = {"role": "user", "content": content}
162
- assistant_message = {"role": "assistant", "content": ""}
163
- chat_history.append(user_message)
164
- chat_history.append(assistant_message)
165
 
166
  try:
167
- if stream_response:
168
- # Handle streaming response
169
- response = process_api_call(messages, model_id, temp, top_p, max_tokens, stream=True)
170
-
171
- full_response = ""
172
- buffer = ""
173
-
174
- for chunk in response.iter_content(chunk_size=1024, decode_unicode=False):
175
- if chunk:
176
- buffer += chunk.decode('utf-8')
177
-
178
- while True:
179
- line_end = buffer.find('\n')
180
- if line_end == -1:
181
- break
182
-
183
- line = buffer[:line_end].strip()
184
- buffer = buffer[line_end + 1:]
185
 
186
- if line.startswith('data: '):
187
- data = line[6:]
188
- if data == '[DONE]':
189
- break
190
-
191
- try:
192
- data_obj = json.loads(data)
193
- delta_content = data_obj["choices"][0]["delta"].get("content", "")
194
- if delta_content:
195
- full_response += delta_content
196
- # Update the assistant message
197
- chat_history[-1]["content"] = full_response
198
- yield chat_history
199
- except json.JSONDecodeError:
200
- pass
 
 
 
 
 
 
 
 
 
 
201
  else:
202
- # Handle non-streaming response
203
- response = process_api_call(messages, model_id, temp, top_p, max_tokens, stream=False)
204
  response.raise_for_status()
205
  result = response.json()
206
 
207
  reply = result.get("choices", [{}])[0].get("message", {}).get("content", "No response")
208
- chat_history[-1]["content"] = reply
209
  yield chat_history
210
-
211
  except Exception as e:
212
  error_msg = f"Error: {str(e)}"
213
- chat_history[-1]["content"] = error_msg
214
  yield chat_history
215
 
216
- # Create simpler UI
217
- with gr.Blocks(theme=gr.themes.Soft()) as demo:
218
- gr.Markdown("# 🔆 CrispChat - OpenRouter AI Models")
 
 
 
 
 
 
 
 
219
 
220
  with gr.Row():
221
- with gr.Column(scale=4):
222
  chatbot = gr.Chatbot(
223
  height=500,
 
224
  show_copy_button=True,
225
  show_share_button=False,
226
- layout="bubble",
227
- avatar_images=("👤", "🤖"),
228
- type="messages"
229
  )
230
 
231
- with gr.Row():
232
  user_message = gr.Textbox(
233
  placeholder="Type your message here...",
234
- show_label=False,
235
- lines=3
236
  )
237
 
238
- with gr.Row():
239
- with gr.Column(scale=1):
240
  image_upload = gr.Image(
241
  type="pil",
242
- label="Upload Image",
243
  show_label=True
244
  )
245
-
246
- with gr.Column(scale=1):
247
  file_upload = gr.File(
248
- label="Upload Text File",
249
  file_types=[".txt", ".md", ".py", ".js", ".html", ".css", ".json"]
250
  )
251
-
252
- with gr.Column(scale=1):
253
  submit_btn = gr.Button("Send", variant="primary")
 
254
 
255
- with gr.Column(scale=2):
256
- with gr.Accordion("Model Settings", open=True):
257
- model_selector = gr.Dropdown(
258
- choices=[name for name, _ in free_models],
259
- value=free_models[0][0],
260
- label="Select Model"
261
- )
262
-
263
- temperature = gr.Slider(
264
- minimum=0.1,
265
- maximum=2.0,
266
- value=0.7,
267
- step=0.1,
268
- label="Temperature"
269
- )
270
-
271
- top_p = gr.Slider(
272
- minimum=0.1,
273
- maximum=1.0,
274
- value=1.0,
275
- step=0.1,
276
- label="Top P"
277
- )
278
-
279
- max_tokens = gr.Slider(
280
- minimum=100,
281
- maximum=4000,
282
- value=1000,
283
- step=100,
284
- label="Max Tokens"
285
- )
286
-
287
- streaming = gr.Checkbox(
288
- label="Enable Streaming",
289
- value=True
290
- )
291
-
292
- clear_btn = gr.Button("Clear Chat")
293
 
294
- # Set up event handlers
295
- msg_submit_event = user_message.submit(
296
- fn=update_conversation,
297
  inputs=[
298
  user_message,
299
  chatbot,
@@ -301,15 +230,17 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
301
  image_upload,
302
  file_upload,
303
  temperature,
304
- top_p,
305
  max_tokens,
306
  streaming
307
  ],
308
  outputs=chatbot
 
 
 
309
  )
310
 
311
- btn_submit_event = submit_btn.click(
312
- fn=update_conversation,
313
  inputs=[
314
  user_message,
315
  chatbot,
@@ -317,31 +248,22 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
317
  image_upload,
318
  file_upload,
319
  temperature,
320
- top_p,
321
  max_tokens,
322
  streaming
323
  ],
324
  outputs=chatbot
 
 
 
325
  )
326
 
327
- # Clear chat
328
- clear_btn.click(
329
- fn=lambda: [],
330
- outputs=[chatbot]
331
- )
332
-
333
- # Clear input after submission
334
- msg_submit_event.then(
335
- fn=lambda: "",
336
- outputs=[user_message]
337
- )
338
-
339
- btn_submit_event.then(
340
- fn=lambda: "",
341
- outputs=[user_message]
342
  )
343
 
344
- # Mount FastAPI for external access
345
  from fastapi import FastAPI
346
  from pydantic import BaseModel
347
 
@@ -356,42 +278,58 @@ class GenerateRequest(BaseModel):
356
  async def api_generate(request: GenerateRequest):
357
  """API endpoint for generating responses"""
358
  try:
359
- # Process request
360
- messages = [{"role": "user", "content": request.message}]
361
-
362
- # Handle image if provided
 
 
 
363
  if request.image_data:
364
  try:
365
  image_bytes = base64.b64decode(request.image_data)
366
  image = Image.open(BytesIO(image_bytes))
367
  base64_image = encode_image(image)
368
-
369
- messages = [{
370
- "role": "user",
371
- "content": [
372
- {"type": "text", "text": request.message},
373
- {
374
- "type": "image_url",
375
- "image_url": {
376
- "url": f"data:image/jpeg;base64,{base64_image}"
377
- }
378
  }
379
- ]
380
- }]
 
381
  except Exception as e:
382
  return {"error": f"Image processing error: {str(e)}"}
 
 
 
 
 
 
 
 
 
 
 
383
 
384
- # Get model
385
- model_id = request.model or free_models[0][1]
 
 
 
386
 
387
  # Make API call
388
- response = process_api_call(messages, model_id, stream=False)
389
  response.raise_for_status()
390
- result = response.json()
391
 
 
 
392
  reply = result.get("choices", [{}])[0].get("message", {}).get("content", "No response")
393
- return {"response": reply}
394
 
 
 
395
  except Exception as e:
396
  return {"error": f"Error: {str(e)}"}
397
 
 
10
  # Get API key from environment variable for security
11
  OPENROUTER_API_KEY = os.environ.get("OPENROUTER_API_KEY", "")
12
 
13
+ # Simplified model information with only name and ID
 
14
  free_models = [
15
+ ("Google: Gemini Pro 2.0 Experimental", "google/gemini-2.0-pro-exp-02-05:free"),
16
+ ("Google: Gemini 2.0 Flash", "google/gemini-2.0-flash-exp:free"),
17
+ ("Google: Gemini Pro 2.5 Experimental", "google/gemini-2.5-pro-exp-03-25:free"),
18
+ ("Meta: Llama 3.2 11B Vision", "meta-llama/llama-3.2-11b-vision-instruct:free"),
19
+ ("Qwen: Qwen2.5 VL 72B", "qwen/qwen2.5-vl-72b-instruct:free"),
20
+ ("DeepSeek: DeepSeek R1", "deepseek/deepseek-r1:free"),
21
+ ("Meta: Llama 3.1 8B", "meta-llama/llama-3.1-8b-instruct:free"),
22
+ ("Mistral: Mistral Small 3.1 24B", "mistralai/mistral-small-3.1-24b-instruct:free")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  ]
24
 
25
  # Helper functions
 
37
  except Exception as e:
38
  return f"Error reading file: {str(e)}"
39
 
40
+ def generate_response(message, chat_history, model_name, uploaded_image=None, uploaded_file=None,
41
+ temp=0.7, max_tok=1000, use_stream=True):
42
+ """Process message and get response from API"""
43
+ # Find model ID
44
+ model_id = next((model_id for name, model_id in free_models if name == model_name), free_models[0][1])
 
 
45
 
46
+ # Get context from history
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  messages = []
48
+ for turn in chat_history:
49
+ if isinstance(turn, tuple):
50
+ user_msg, ai_msg = turn
 
 
 
51
  messages.append({"role": "user", "content": user_msg})
52
  messages.append({"role": "assistant", "content": ai_msg})
53
 
54
+ # Process file if provided
 
 
 
55
  if uploaded_file:
56
  file_content = encode_file(uploaded_file)
57
+ message = f"{message}\n\nFile content:\n```\n{file_content}\n```"
58
 
59
+ # Create new message
60
  if uploaded_image:
61
+ # Process image for vision models
62
  base64_image = encode_image(uploaded_image)
63
+ content = [
64
+ {"type": "text", "text": message},
65
  {
66
  "type": "image_url",
67
  "image_url": {
 
69
  }
70
  }
71
  ]
 
 
72
  messages.append({"role": "user", "content": content})
73
+ else:
74
+ messages.append({"role": "user", "content": message})
75
+
76
+ # Setup headers and URL
77
+ headers = {
78
+ "Content-Type": "application/json",
79
+ "Authorization": f"Bearer {OPENROUTER_API_KEY}",
80
+ "HTTP-Referer": "https://huggingface.co/spaces",
81
+ }
82
+
83
+ url = "https://openrouter.ai/api/v1/chat/completions"
84
+
85
+ # Build request data
86
+ data = {
87
+ "model": model_id,
88
+ "messages": messages,
89
+ "stream": use_stream,
90
+ "temperature": temp,
91
+ "max_tokens": max_tok
92
+ }
93
 
94
  # Add message to chat history
95
+ chat_history.append((message, ""))
 
 
 
96
 
97
  try:
98
+ if use_stream:
99
+ # Streaming response
100
+ with requests.post(url, headers=headers, json=data, stream=True) as response:
101
+ response.raise_for_status()
102
+
103
+ full_response = ""
104
+ buffer = ""
105
+
106
+ for chunk in response.iter_content(chunk_size=1024, decode_unicode=False):
107
+ if chunk:
108
+ buffer += chunk.decode('utf-8')
 
 
 
 
 
 
 
109
 
110
+ # Process line by line
111
+ while '\n' in buffer:
112
+ line, buffer = buffer.split('\n', 1)
113
+ line = line.strip()
114
+
115
+ if line.startswith('data: '):
116
+ data = line[6:]
117
+ if data == '[DONE]':
118
+ break
119
+
120
+ try:
121
+ data_obj = json.loads(data)
122
+ delta_content = data_obj["choices"][0]["delta"].get("content", "")
123
+ if delta_content:
124
+ full_response += delta_content
125
+ chat_history[-1] = (message, full_response)
126
+ yield chat_history
127
+ except Exception:
128
+ pass
129
+
130
+ # Final yield to ensure complete message
131
+ if full_response:
132
+ chat_history[-1] = (message, full_response)
133
+ yield chat_history
134
+
135
  else:
136
+ # Non-streaming response
137
+ response = requests.post(url, headers=headers, json=data)
138
  response.raise_for_status()
139
  result = response.json()
140
 
141
  reply = result.get("choices", [{}])[0].get("message", {}).get("content", "No response")
142
+ chat_history[-1] = (message, reply)
143
  yield chat_history
144
+
145
  except Exception as e:
146
  error_msg = f"Error: {str(e)}"
147
+ chat_history[-1] = (message, error_msg)
148
  yield chat_history
149
 
150
+ def clear_chat():
151
+ """Clear the chat history"""
152
+ return []
153
+
154
+ def clear_input():
155
+ """Clear the input field"""
156
+ return "", None, None
157
+
158
+ # Create a very simple UI
159
+ with gr.Blocks(theme=gr.themes.Default()) as demo:
160
+ gr.Markdown("# 🔆 CrispChat")
161
 
162
  with gr.Row():
163
+ with gr.Column(scale=3):
164
  chatbot = gr.Chatbot(
165
  height=500,
166
+ layout="bubble",
167
  show_copy_button=True,
168
  show_share_button=False,
169
+ avatar_images=("👤", "🤖")
 
 
170
  )
171
 
172
+ with gr.Group():
173
  user_message = gr.Textbox(
174
  placeholder="Type your message here...",
175
+ lines=3,
176
+ show_label=False
177
  )
178
 
179
+ with gr.Row():
 
180
  image_upload = gr.Image(
181
  type="pil",
182
+ label="Image (optional)",
183
  show_label=True
184
  )
185
+
 
186
  file_upload = gr.File(
187
+ label="Text File (optional)",
188
  file_types=[".txt", ".md", ".py", ".js", ".html", ".css", ".json"]
189
  )
190
+
191
+ with gr.Row():
192
  submit_btn = gr.Button("Send", variant="primary")
193
+ clear_chat_btn = gr.Button("Clear Chat")
194
 
195
+ with gr.Column(scale=1):
196
+ model_selector = gr.Dropdown(
197
+ choices=[name for name, _ in free_models],
198
+ value=free_models[0][0],
199
+ label="Select Model"
200
+ )
201
+
202
+ temperature = gr.Slider(
203
+ minimum=0.1,
204
+ maximum=2.0,
205
+ value=0.7,
206
+ step=0.1,
207
+ label="Temperature"
208
+ )
209
+
210
+ max_tokens = gr.Slider(
211
+ minimum=100,
212
+ maximum=4000,
213
+ value=1000,
214
+ step=100,
215
+ label="Max Tokens"
216
+ )
217
+
218
+ streaming = gr.Checkbox(
219
+ label="Streaming",
220
+ value=True
221
+ )
 
 
 
 
 
 
 
 
 
 
 
222
 
223
+ # Set up submit events
224
+ submit_btn.click(
225
+ fn=generate_response,
226
  inputs=[
227
  user_message,
228
  chatbot,
 
230
  image_upload,
231
  file_upload,
232
  temperature,
 
233
  max_tokens,
234
  streaming
235
  ],
236
  outputs=chatbot
237
+ ).then(
238
+ fn=clear_input,
239
+ outputs=[user_message, image_upload, file_upload]
240
  )
241
 
242
+ user_message.submit(
243
+ fn=generate_response,
244
  inputs=[
245
  user_message,
246
  chatbot,
 
248
  image_upload,
249
  file_upload,
250
  temperature,
 
251
  max_tokens,
252
  streaming
253
  ],
254
  outputs=chatbot
255
+ ).then(
256
+ fn=clear_input,
257
+ outputs=[user_message, image_upload, file_upload]
258
  )
259
 
260
+ # Clear chat button
261
+ clear_chat_btn.click(
262
+ fn=clear_chat,
263
+ outputs=chatbot
 
 
 
 
 
 
 
 
 
 
 
264
  )
265
 
266
+ # API for external access
267
  from fastapi import FastAPI
268
  from pydantic import BaseModel
269
 
 
278
  async def api_generate(request: GenerateRequest):
279
  """API endpoint for generating responses"""
280
  try:
281
+ # Get model ID
282
+ model_id = request.model
283
+ if not model_id:
284
+ model_id = free_models[0][1]
285
+
286
+ # Process image if provided
287
+ messages = []
288
  if request.image_data:
289
  try:
290
  image_bytes = base64.b64decode(request.image_data)
291
  image = Image.open(BytesIO(image_bytes))
292
  base64_image = encode_image(image)
293
+ content = [
294
+ {"type": "text", "text": request.message},
295
+ {
296
+ "type": "image_url",
297
+ "image_url": {
298
+ "url": f"data:image/jpeg;base64,{base64_image}"
 
 
 
 
299
  }
300
+ }
301
+ ]
302
+ messages.append({"role": "user", "content": content})
303
  except Exception as e:
304
  return {"error": f"Image processing error: {str(e)}"}
305
+ else:
306
+ messages.append({"role": "user", "content": request.message})
307
+
308
+ # Setup API call
309
+ headers = {
310
+ "Content-Type": "application/json",
311
+ "Authorization": f"Bearer {OPENROUTER_API_KEY}",
312
+ "HTTP-Referer": "https://huggingface.co/spaces",
313
+ }
314
+
315
+ url = "https://openrouter.ai/api/v1/chat/completions"
316
 
317
+ data = {
318
+ "model": model_id,
319
+ "messages": messages,
320
+ "temperature": 0.7
321
+ }
322
 
323
  # Make API call
324
+ response = requests.post(url, headers=headers, json=data)
325
  response.raise_for_status()
 
326
 
327
+ # Parse response
328
+ result = response.json()
329
  reply = result.get("choices", [{}])[0].get("message", {}).get("content", "No response")
 
330
 
331
+ return {"response": reply}
332
+
333
  except Exception as e:
334
  return {"error": f"Error: {str(e)}"}
335