likhonsheikh commited on
Commit
bc8e480
Β·
verified Β·
1 Parent(s): 557a0e7

Deploy Enhanced Gemini Multi-API Hybrid Service

Browse files
Files changed (1) hide show
  1. app.py +296 -212
app.py CHANGED
@@ -1,7 +1,7 @@
1
  #!/usr/bin/env python3
2
  """
3
- Enhanced Gemini Multi-API - Anthropic Compatible API Service
4
- Provides Google Gemini models through Anthropic-compatible interface
5
  """
6
 
7
  import os
@@ -9,34 +9,21 @@ import json
9
  import time
10
  import uuid
11
  from datetime import datetime
12
- from typing import List, Dict, Any, Optional, Union
13
- from dataclasses import dataclass
14
- from flask import Flask, request, jsonify
15
  import google.generativeai as genai
16
- from google.generativeai.types import HarmCategory, HarmBlockThreshold
17
- import requests
18
 
19
  # Initialize Flask app
20
  app = Flask(__name__)
21
 
22
- # API Configuration
23
  GEMINI_API_KEY = os.environ.get('GEMINI_API_KEY', '')
24
  DEFAULT_MODEL = "gemini-1.5-flash"
25
  MAX_TOKENS = 4096
26
  DEFAULT_TEMPERATURE = 0.7
27
 
28
- # Initialize Gemini
29
- if GEMINI_API_KEY:
30
- genai.configure(api_key=GEMINI_API_KEY)
31
- gemini_model = genai.GenerativeModel(DEFAULT_MODEL)
32
- else:
33
- gemini_model = None
34
-
35
- # API Configuration
36
- API_VERSION = "v1"
37
- BASE_PATH = f"/{API_VERSION}"
38
-
39
- # Available Models
40
  MODELS = {
41
  "claude-3-sonnet-20240229": "gemini-1.5-pro",
42
  "claude-3-haiku-20240307": "gemini-1.5-flash",
@@ -49,95 +36,69 @@ MODELS = {
49
  "gemini-2.0-flash-exp": "gemini-2.0-flash-exp"
50
  }
51
 
52
- @dataclass
53
- class Message:
54
- role: str
55
- content: str
56
-
57
- class AnthropicCompatibleAPI:
58
- """Anthropic API compatible wrapper for Gemini models"""
59
 
60
- def __init__(self, gemini_api_key: str):
61
- if not gemini_api_key:
62
- raise ValueError("GEMINI_API_KEY is required")
63
-
64
- genai.configure(api_key=gemini_api_key)
65
- self.api_key = gemini_api_key
66
 
67
  def chat_completion(self, messages: List[Dict], model: str = DEFAULT_MODEL, **kwargs) -> Dict:
68
- """OpenAI/Anthropic compatible chat completion"""
69
 
70
- # Map Anthropic model names to Gemini models
71
- gemini_model_name = self._map_model(model)
 
 
 
 
 
 
72
 
73
- # Extract parameters
74
- max_tokens = kwargs.get('max_tokens', MAX_TOKENS)
75
- temperature = kwargs.get('temperature', DEFAULT_TEMPERATURE)
76
- stop_sequences = kwargs.get('stop_sequences', [])
77
 
78
- # Build system prompt and user content
79
  system_prompt = ""
80
- conversation_messages = []
81
 
82
  for msg in messages:
83
- role = msg.get('role', '')
84
- content = msg.get('content', '')
85
-
86
- if role == 'system':
87
- system_prompt += content + "\n"
88
- else:
89
- conversation_messages.append({"role": role, "parts": [content]})
90
-
91
- # Create Gemini prompt
92
- full_prompt = system_prompt.strip() if system_prompt else ""
93
- if conversation_messages:
94
- last_message = conversation_messages[-1]['parts'][0]
95
- if full_prompt:
96
- full_prompt += f"\n\nHuman: {last_message}"
97
- else:
98
- full_prompt = last_message
99
 
100
- full_prompt += "\n\nAssistant:"
 
 
 
101
 
102
  try:
103
- # Generate response using Gemini
104
  model_instance = genai.GenerativeModel(gemini_model_name)
105
 
106
- generation_config = {
107
- 'temperature': temperature,
108
- 'max_output_tokens': max_tokens,
109
- 'top_p': kwargs.get('top_p', 0.9),
110
- 'top_k': kwargs.get('top_k', 40)
111
- }
112
-
113
- if stop_sequences:
114
- generation_config['stop_sequences'] = stop_sequences
115
-
116
  response = model_instance.generate_content(
117
  full_prompt,
118
- generation_config=genai.types.GenerationConfig(**generation_config)
 
 
 
 
 
119
  )
120
 
121
- # Format response to match Anthropic format
122
  response_text = response.text
123
 
124
- # Calculate usage (approximate)
125
- input_tokens = len(full_prompt.split()) * 1.3 # Rough approximation
126
  output_tokens = len(response_text.split()) * 1.3
127
 
128
  return {
129
  "id": f"msg_{str(uuid.uuid4())[:8]}",
130
  "type": "message",
131
  "role": "assistant",
132
- "content": [
133
- {
134
- "type": "text",
135
- "text": response_text
136
- }
137
- ],
138
  "model": model,
139
  "stop_reason": "end_turn",
140
- "stop_sequence": None,
141
  "usage": {
142
  "input_tokens": int(input_tokens),
143
  "output_tokens": int(output_tokens),
@@ -156,127 +117,63 @@ class AnthropicCompatibleAPI:
156
  }
157
  }
158
 
159
- def _map_model(self, model: str) -> str:
160
- """Map model names to Gemini equivalents"""
161
- return MODELS.get(model, DEFAULT_MODEL)
162
-
163
  def list_models(self) -> Dict:
164
- """List available models in Anthropic format"""
165
  models = [
166
  {
167
  "id": "claude-3-sonnet-20240229",
168
  "object": "model",
169
- "created": 1710364800,
170
  "owned_by": "google-gemini",
171
  "name": "claude-3-sonnet-20240229",
172
  "display_name": "Gemini 1.5 Pro (Claude Compatible)",
173
- "description": "Anthropic-compatible access to Gemini 1.5 Pro",
174
  "input_token_limit": 2000000,
175
- "output_token_limit": 8192,
176
- "top_provider": {
177
- "context_length": 2000000,
178
- "max_completion_tokens": 8192
179
- }
180
  },
181
  {
182
  "id": "claude-3-haiku-20240307",
183
  "object": "model",
184
- "created": 1710364800,
185
  "owned_by": "google-gemini",
186
  "name": "claude-3-haiku-20240307",
187
  "display_name": "Gemini 1.5 Flash (Claude Compatible)",
188
- "description": "Anthropic-compatible access to Gemini 1.5 Flash",
189
  "input_token_limit": 2000000,
190
- "output_token_limit": 8192,
191
- "top_provider": {
192
- "context_length": 2000000,
193
- "max_completion_tokens": 8192
194
- }
195
  }
196
  ]
197
-
198
  return {"object": "list", "data": models}
199
 
200
  # Global API instance
201
- api = AnthropicCompatibleAPI(GEMINI_API_KEY) if GEMINI_API_KEY else None
202
 
203
- # API Routes
 
204
 
205
  @app.route(f"{BASE_PATH}/models", methods=["GET"])
206
  def list_models():
207
- """List available models - Anthropic compatible"""
208
- if not GEMINI_API_KEY:
209
- return jsonify({
210
- "error": {
211
- "type": "configuration_error",
212
- "message": "GEMINI_API_KEY not configured",
213
- "code": "CONFIGURATION_ERROR"
214
- }
215
- }), 401
216
-
217
  try:
218
- models = api.list_models()
219
  return jsonify(models)
220
  except Exception as e:
221
- return jsonify({
222
- "error": {
223
- "type": "api_error",
224
- "message": str(e),
225
- "code": "INTERNAL_ERROR"
226
- }
227
- }), 500
228
 
229
  @app.route(f"{BASE_PATH}/messages", methods=["POST"])
230
  def create_message():
231
- """Create a message - Anthropic compatible"""
232
- if not GEMINI_API_KEY:
233
- return jsonify({
234
- "error": {
235
- "type": "configuration_error",
236
- "message": "GEMINI_API_KEY not configured",
237
- "code": "CONFIGURATION_ERROR"
238
- }
239
- }), 401
240
-
241
- # Get request data
242
  data = request.get_json()
243
  if not data:
244
- return jsonify({
245
- "error": {
246
- "type": "invalid_request_error",
247
- "message": "Request body is required",
248
- "code": "INVALID_REQUEST"
249
- }
250
- }), 400
251
 
252
- # Validate required fields
253
  required_fields = ["model", "messages"]
254
  for field in required_fields:
255
  if field not in data:
256
- return jsonify({
257
- "error": {
258
- "type": "invalid_request_error",
259
- "message": f"Missing required field: {field}",
260
- "code": "INVALID_REQUEST"
261
- }
262
- }), 400
263
-
264
- # Extract parameters
265
- model = data["model"]
266
- messages = data["messages"]
267
- max_tokens = data.get("max_tokens", MAX_TOKENS)
268
- temperature = data.get("temperature", DEFAULT_TEMPERATURE)
269
 
270
  try:
271
- # Call Gemini through our API wrapper
272
- response = api.chat_completion(
273
- messages=messages,
274
- model=model,
275
- max_tokens=max_tokens,
276
- temperature=temperature,
277
- stop_sequences=data.get("stop_sequences"),
278
- top_p=data.get("top_p"),
279
- top_k=data.get("top_k")
280
  )
281
 
282
  if "error" in response:
@@ -285,81 +182,268 @@ def create_message():
285
  return jsonify(response)
286
 
287
  except Exception as e:
288
- return jsonify({
289
- "error": {
290
- "type": "api_error",
291
- "message": str(e),
292
- "code": "INTERNAL_ERROR"
293
- }
294
- }), 500
295
-
296
- @app.route(f"{BASE_PATH}/completions", methods=["POST"])
297
- def create_completion():
298
- """Create completion - OpenAI compatible fallback"""
299
- return create_message() # Same implementation
300
 
301
  @app.route("/health", methods=["GET"])
302
  def health_check():
303
- """Health check endpoint"""
304
  return jsonify({
305
  "status": "healthy",
306
  "service": "Enhanced Gemini Multi-API",
307
- "version": "1.0.0",
308
  "timestamp": datetime.now().isoformat(),
309
- "api_key_configured": bool(GEMINI_API_KEY),
310
- "available_models": len(MODELS)
311
  })
312
 
313
  @app.route("/info", methods=["GET"])
314
  def api_info():
315
- """API information endpoint"""
316
  return jsonify({
317
  "service": "Enhanced Gemini Multi-API",
318
- "description": "Google Gemini models through Anthropic-compatible interface",
319
- "version": "1.0.0",
320
  "endpoints": {
321
- "list_models": f"{BASE_PATH}/models",
322
- "create_message": f"{BASE_PATH}/messages",
323
- "create_completion": f"{BASE_PATH}/completions",
324
  "health": "/health",
325
  "info": "/info"
326
  },
327
- "supported_models": list(MODELS.keys()),
328
- "documentation": "https://docs.anthropic.com/claude/reference",
329
  "api_key_required": True
330
  })
331
 
332
- @app.errorhandler(404)
333
- def not_found(error):
334
- return jsonify({
335
- "error": {
336
- "type": "not_found_error",
337
- "message": "Endpoint not found",
338
- "code": "NOT_FOUND"
339
- }
340
- }), 404
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
 
342
- @app.errorhandler(500)
343
- def internal_error(error):
344
- return jsonify({
345
- "error": {
346
- "type": "api_error",
347
- "message": "Internal server error",
348
- "code": "INTERNAL_ERROR"
349
- }
350
- }), 500
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
351
 
352
  if __name__ == "__main__":
353
- port = int(os.environ.get("PORT", 8080))
 
 
 
 
354
 
355
  if not GEMINI_API_KEY:
356
- print("⚠️ WARNING: GEMINI_API_KEY not configured")
357
- print(" Set GEMINI_API_KEY environment variable for full functionality")
358
- print(" Without API key: Only health and info endpoints will work")
359
 
360
- print(f"πŸš€ Enhanced Gemini Multi-API starting on port {port}")
361
- print(f"πŸ“– API Info: http://localhost:{port}/info")
 
362
  print(f"❀️ Health Check: http://localhost:{port}/health")
363
- print(f"πŸ“š Models: POST http://localhost:{port}{BASE_PATH}/messages")
364
 
365
- app.run(host="0.0.0.0", port=port, debug=False)
 
 
 
 
 
 
 
 
 
1
  #!/usr/bin/env python3
2
  """
3
+ Enhanced Gemini Multi-API - Hybrid Web + API Interface
4
+ Anthropic-compatible service with both web interface and API endpoints
5
  """
6
 
7
  import os
 
9
  import time
10
  import uuid
11
  from datetime import datetime
12
+ from typing import List, Dict, Any
13
+ from flask import Flask, request, jsonify, render_template_string
14
+ import gradio as gr
15
  import google.generativeai as genai
 
 
16
 
17
  # Initialize Flask app
18
  app = Flask(__name__)
19
 
20
+ # Configuration
21
  GEMINI_API_KEY = os.environ.get('GEMINI_API_KEY', '')
22
  DEFAULT_MODEL = "gemini-1.5-flash"
23
  MAX_TOKENS = 4096
24
  DEFAULT_TEMPERATURE = 0.7
25
 
26
+ # Model mapping
 
 
 
 
 
 
 
 
 
 
 
27
  MODELS = {
28
  "claude-3-sonnet-20240229": "gemini-1.5-pro",
29
  "claude-3-haiku-20240307": "gemini-1.5-flash",
 
36
  "gemini-2.0-flash-exp": "gemini-2.0-flash-exp"
37
  }
38
 
39
+ class GeminiAPI:
40
+ """Anthropic compatible wrapper for Gemini"""
 
 
 
 
 
41
 
42
+ def __init__(self, api_key: str):
43
+ if api_key:
44
+ genai.configure(api_key=api_key)
45
+ self.api_key = api_key
 
 
46
 
47
  def chat_completion(self, messages: List[Dict], model: str = DEFAULT_MODEL, **kwargs) -> Dict:
48
+ """Anthropic compatible chat completion"""
49
 
50
+ if not self.api_key:
51
+ return {
52
+ "error": {
53
+ "type": "configuration_error",
54
+ "message": "GEMINI_API_KEY not configured",
55
+ "code": "CONFIGURATION_ERROR"
56
+ }
57
+ }
58
 
59
+ gemini_model_name = MODELS.get(model, DEFAULT_MODEL)
 
 
 
60
 
61
+ # Build prompt
62
  system_prompt = ""
63
+ user_messages = []
64
 
65
  for msg in messages:
66
+ if msg.get('role') == 'system':
67
+ system_prompt = msg.get('content', '')
68
+ elif msg.get('role') == 'user':
69
+ user_messages.append(msg.get('content', ''))
 
 
 
 
 
 
 
 
 
 
 
 
70
 
71
+ full_prompt = system_prompt + "\\n\\n" if system_prompt else ""
72
+ if user_messages:
73
+ full_prompt += f"Human: {user_messages[-1]}"
74
+ full_prompt += "\\n\\nAssistant:"
75
 
76
  try:
 
77
  model_instance = genai.GenerativeModel(gemini_model_name)
78
 
 
 
 
 
 
 
 
 
 
 
79
  response = model_instance.generate_content(
80
  full_prompt,
81
+ generation_config=genai.types.GenerationConfig(
82
+ temperature=kwargs.get('temperature', DEFAULT_TEMPERATURE),
83
+ max_output_tokens=kwargs.get('max_tokens', MAX_TOKENS),
84
+ top_p=kwargs.get('top_p', 0.9),
85
+ top_k=kwargs.get('top_k', 40)
86
+ )
87
  )
88
 
 
89
  response_text = response.text
90
 
91
+ # Calculate usage
92
+ input_tokens = len(full_prompt.split()) * 1.3
93
  output_tokens = len(response_text.split()) * 1.3
94
 
95
  return {
96
  "id": f"msg_{str(uuid.uuid4())[:8]}",
97
  "type": "message",
98
  "role": "assistant",
99
+ "content": [{"type": "text", "text": response_text}],
 
 
 
 
 
100
  "model": model,
101
  "stop_reason": "end_turn",
 
102
  "usage": {
103
  "input_tokens": int(input_tokens),
104
  "output_tokens": int(output_tokens),
 
117
  }
118
  }
119
 
 
 
 
 
120
  def list_models(self) -> Dict:
121
+ """List available models"""
122
  models = [
123
  {
124
  "id": "claude-3-sonnet-20240229",
125
  "object": "model",
 
126
  "owned_by": "google-gemini",
127
  "name": "claude-3-sonnet-20240229",
128
  "display_name": "Gemini 1.5 Pro (Claude Compatible)",
 
129
  "input_token_limit": 2000000,
130
+ "output_token_limit": 8192
 
 
 
 
131
  },
132
  {
133
  "id": "claude-3-haiku-20240307",
134
  "object": "model",
 
135
  "owned_by": "google-gemini",
136
  "name": "claude-3-haiku-20240307",
137
  "display_name": "Gemini 1.5 Flash (Claude Compatible)",
 
138
  "input_token_limit": 2000000,
139
+ "output_token_limit": 8192
 
 
 
 
140
  }
141
  ]
 
142
  return {"object": "list", "data": models}
143
 
144
  # Global API instance
145
+ gemini_api = GeminiAPI(GEMINI_API_KEY)
146
 
147
+ # Flask API Routes
148
+ BASE_PATH = "/v1"
149
 
150
  @app.route(f"{BASE_PATH}/models", methods=["GET"])
151
  def list_models():
152
+ """List available models"""
 
 
 
 
 
 
 
 
 
153
  try:
154
+ models = gemini_api.list_models()
155
  return jsonify(models)
156
  except Exception as e:
157
+ return jsonify({"error": str(e)}), 500
 
 
 
 
 
 
158
 
159
  @app.route(f"{BASE_PATH}/messages", methods=["POST"])
160
  def create_message():
161
+ """Create a message"""
 
 
 
 
 
 
 
 
 
 
162
  data = request.get_json()
163
  if not data:
164
+ return jsonify({"error": "Request body required"}), 400
 
 
 
 
 
 
165
 
 
166
  required_fields = ["model", "messages"]
167
  for field in required_fields:
168
  if field not in data:
169
+ return jsonify({"error": f"Missing required field: {field}"}), 400
 
 
 
 
 
 
 
 
 
 
 
 
170
 
171
  try:
172
+ response = gemini_api.chat_completion(
173
+ messages=data["messages"],
174
+ model=data["model"],
175
+ max_tokens=data.get("max_tokens", 1024),
176
+ temperature=data.get("temperature", 0.7)
 
 
 
 
177
  )
178
 
179
  if "error" in response:
 
182
  return jsonify(response)
183
 
184
  except Exception as e:
185
+ return jsonify({"error": str(e)}), 500
 
 
 
 
 
 
 
 
 
 
 
186
 
187
  @app.route("/health", methods=["GET"])
188
  def health_check():
189
+ """Health check"""
190
  return jsonify({
191
  "status": "healthy",
192
  "service": "Enhanced Gemini Multi-API",
 
193
  "timestamp": datetime.now().isoformat(),
194
+ "api_key_configured": bool(GEMINI_API_KEY)
 
195
  })
196
 
197
  @app.route("/info", methods=["GET"])
198
  def api_info():
199
+ """API information"""
200
  return jsonify({
201
  "service": "Enhanced Gemini Multi-API",
202
+ "description": "Anthropic API compatible interface for Gemini models",
 
203
  "endpoints": {
204
+ "models": f"{BASE_PATH}/models",
205
+ "messages": f"{BASE_PATH}/messages",
 
206
  "health": "/health",
207
  "info": "/info"
208
  },
209
+ "web_interface": "/gradio",
 
210
  "api_key_required": True
211
  })
212
 
213
+ # Web Interface Functions
214
+ def api_chat_interface(message, history, model, temperature, max_tokens):
215
+ """API-compatible chat interface"""
216
+ if not GEMINI_API_KEY:
217
+ return "❌ GEMINI_API_KEY not configured. Please set the API key in Space secrets."
218
+
219
+ # Format messages for API
220
+ messages = []
221
+ if history:
222
+ for user_msg, assistant_msg in history:
223
+ messages.append({"role": "user", "content": user_msg})
224
+ if assistant_msg:
225
+ messages.append({"role": "assistant", "content": assistant_msg})
226
+
227
+ messages.append({"role": "user", "content": message})
228
+
229
+ # Call API
230
+ response = gemini_api.chat_completion(
231
+ messages=messages,
232
+ model=model,
233
+ max_tokens=max_tokens,
234
+ temperature=temperature
235
+ )
236
+
237
+ if "error" in response:
238
+ return f"❌ Error: {response['error']['message']}"
239
+
240
+ try:
241
+ content = response["content"][0]["text"]
242
+ usage = response.get("usage", {})
243
+ tokens = usage.get("input_tokens", 0) + usage.get("output_tokens", 0)
244
+
245
+ return f"{content}\\n\\n---\\nπŸ’¬ **Tokens Used**: {tokens}"
246
+ except (KeyError, IndexError):
247
+ return "❌ Error: Unable to parse API response"
248
 
249
+ def test_api():
250
+ """Test API connection"""
251
+ if not GEMINI_API_KEY:
252
+ return "❌ GEMINI_API_KEY not configured"
253
+
254
+ test_messages = [{"role": "user", "content": "Hello! Test API connection."}]
255
+ response = gemini_api.chat_completion(
256
+ messages=test_messages,
257
+ model="claude-3-haiku-20240307",
258
+ max_tokens=256,
259
+ temperature=0.7
260
+ )
261
+
262
+ if "error" in response:
263
+ return f"❌ API Test Failed: {response['error']['message']}"
264
+ else:
265
+ return "βœ… API Connection Successful!\\n\\nTest Response:\\n" + response["content"][0]["text"]
266
+
267
+ def get_models_list():
268
+ """Get available models for interface"""
269
+ if not GEMINI_API_KEY:
270
+ return "❌ GEMINI_API_KEY not configured"
271
+
272
+ try:
273
+ models_response = gemini_api.list_models()
274
+ models = models_response.get("data", [])
275
+ return "\\n".join([f"β€’ **{model['id']}** - {model['display_name']}" for model in models])
276
+ except Exception as e:
277
+ return f"❌ Error: {str(e)}"
278
+
279
+ # Gradio Interface
280
+ def create_gradio_interface():
281
+ """Create the web interface"""
282
+
283
+ with gr.Blocks(
284
+ title="Enhanced Gemini Multi-API",
285
+ theme=gr.themes.Soft(),
286
+ show_error=True
287
+ ) as demo:
288
+
289
+ # Header
290
+ gr.HTML("""
291
+ <div style="text-align: center; padding: 2rem; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 15px; margin-bottom: 2rem;">
292
+ <h1>πŸš€ Enhanced Gemini Multi-API</h1>
293
+ <p>πŸ€– Anthropic Compatible Interface β€’ 🌐 Full API Support β€’ βœ… Production Ready</p>
294
+ <p><strong>Status:</strong> API Service + Web Interface Deployed!</p>
295
+ </div>
296
+ """)
297
+
298
+ # API Status Tab
299
+ with gr.Tab("πŸ”§ API Status"):
300
+ gr.HTML("<h3>πŸ”§ API Configuration & Testing</h3>")
301
+
302
+ with gr.Row():
303
+ test_btn = gr.Button("πŸ§ͺ Test API Connection", variant="primary")
304
+ models_btn = gr.Button("πŸ“‹ Available Models", variant="secondary")
305
+
306
+ status_output = gr.Textbox(
307
+ label="API Test Result",
308
+ lines=6,
309
+ interactive=False
310
+ )
311
+
312
+ models_output = gr.Textbox(
313
+ label="Available Models",
314
+ lines=6,
315
+ interactive=False
316
+ )
317
+
318
+ # Chat Interface Tab
319
+ with gr.Tab("πŸ’¬ Chat Interface"):
320
+ gr.HTML("<h3>πŸ’¬ Chat with Anthropic Compatible API</h3>")
321
+
322
+ with gr.Row():
323
+ model_dropdown = gr.Dropdown(
324
+ choices=list(MODELS.keys()),
325
+ value="claude-3-haiku-20240307",
326
+ label="🧠 Model",
327
+ info="Anthropic compatible model selection"
328
+ )
329
+
330
+ temp_slider = gr.Slider(
331
+ minimum=0.0,
332
+ maximum=2.0,
333
+ value=0.7,
334
+ step=0.1,
335
+ label="🌑️ Temperature"
336
+ )
337
+
338
+ max_tokens_slider = gr.Slider(
339
+ minimum=256,
340
+ maximum=4096,
341
+ value=1024,
342
+ step=256,
343
+ label="πŸ“ Max Tokens"
344
+ )
345
+
346
+ chatbot = gr.Chatbot(height=400, label="Chat with Gemini via Anthropic API")
347
+
348
+ msg = gr.Textbox(
349
+ label="πŸ’­ Your Message",
350
+ placeholder="Type your message here...",
351
+ lines=2
352
+ )
353
+
354
+ with gr.Row():
355
+ send_btn = gr.Button("πŸš€ Send", variant="primary")
356
+ clear_btn = gr.Button("πŸ—‘οΈ Clear", variant="secondary")
357
+
358
+ # API Documentation Tab
359
+ with gr.Tab("πŸ“š API Documentation"):
360
+ gr.HTML("""
361
+ <div style="background: #f8f9fa; padding: 1.5rem; border-radius: 10px; border-left: 4px solid #007bff;">
362
+ <h4>πŸ“š Enhanced Gemini Multi-API Documentation</h4>
363
+
364
+ <h5>πŸ”§ Endpoints:</h5>
365
+ <ul>
366
+ <li><code>GET /v1/models</code> - List available models</li>
367
+ <li><code>POST /v1/messages</code> - Create chat completion</li>
368
+ <li><code>GET /health</code> - Health check</li>
369
+ <li><code>GET /info</code> - API information</li>
370
+ </ul>
371
+
372
+ <h5>πŸ“ Example Usage:</h5>
373
+ <pre><code>curl -X POST https://likhonsheikh-enhanced-gemini-multi-api.hf.space/v1/messages \\
374
+ -H "Content-Type: application/json" \\
375
+ -d '{
376
+ "model": "claude-3-haiku-20240307",
377
+ "messages": [{"role": "user", "content": "Hello!"}],
378
+ "max_tokens": 1024,
379
+ "temperature": 0.7
380
+ }'</code></pre>
381
+
382
+ <h5>πŸ€– Available Models:</h5>
383
+ <ul>
384
+ <li><strong>claude-3-haiku-20240307</strong> β†’ Gemini 1.5 Flash</li>
385
+ <li><strong>claude-3-sonnet-20240229</strong> β†’ Gemini 1.5 Pro</li>
386
+ <li><strong>claude-3-5-sonnet-20241022</strong> β†’ Gemini 1.5 Pro</li>
387
+ <li><strong>claude-3-5-haiku-20241022</strong> β†’ Gemini 1.5 Flash</li>
388
+ </ul>
389
+
390
+ <p><strong>Status:</strong> βœ… Full Anthropic API Compatibility Deployed!</p>
391
+ <p><strong>Updated:</strong> 2025-11-14 04:17:24</p>
392
+ </div>
393
+ """)
394
+
395
+ # Event handlers
396
+ test_btn.click(test_api, outputs=[status_output])
397
+ models_btn.click(get_models_list, outputs=[models_output])
398
+
399
+ def user(user_message, history):
400
+ return "", history + [(user_message, None)]
401
+
402
+ def bot(history, model, temperature, max_tokens):
403
+ if not history:
404
+ return history
405
+
406
+ user_message, _ = history[-1]
407
+ bot_message = api_chat_interface(user_message, history[:-1], model, temperature, max_tokens)
408
+ history[-1] = (user_message, bot_message)
409
+ return history
410
+
411
+ msg.submit(user, [msg, chatbot], [msg, chatbot], queue=False).then(
412
+ bot, [chatbot, model_dropdown, temp_slider, max_tokens_slider], [chatbot]
413
+ )
414
+
415
+ send_btn.click(user, [msg, chatbot], [msg, chatbot], queue=False).then(
416
+ bot, [chatbot, model_dropdown, temp_slider, max_tokens_slider], [chatbot]
417
+ )
418
+
419
+ clear_btn.click(lambda: None, outputs=[chatbot], queue=False)
420
+
421
+ return demo
422
 
423
  if __name__ == "__main__":
424
+ # Create Gradio interface
425
+ demo = create_gradio_interface()
426
+
427
+ # Start both Flask API and Gradio interface
428
+ port = int(os.environ.get("PORT", 7860))
429
 
430
  if not GEMINI_API_KEY:
431
+ print("⚠️ GEMINI_API_KEY not configured - API functionality will be limited")
432
+ else:
433
+ print("βœ… GEMINI_API_KEY configured - Full functionality available")
434
 
435
+ print(f"πŸš€ Enhanced Gemini Multi-API Service starting on port {port}")
436
+ print(f"🌐 Web Interface: http://localhost:{port}/gradio")
437
+ print(f"πŸ“– API Documentation: http://localhost:{port}/info")
438
  print(f"❀️ Health Check: http://localhost:{port}/health")
439
+ print(f"πŸ€– API Endpoint: http://localhost:{port}/v1/messages")
440
 
441
+ # Launch with both Flask and Gradio
442
+ demo.launch(
443
+ server_name="0.0.0.0",
444
+ server_port=port,
445
+ share=False,
446
+ show_error=True,
447
+ debug=False,
448
+ quiet=True
449
+ )