Veda-Labs commited on
Commit
4711ff8
·
verified ·
1 Parent(s): 4061f96

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +129 -91
app.py CHANGED
@@ -1,117 +1,155 @@
1
  import os
2
- import time
3
  import requests
 
4
  import threading
5
- from flask import Flask, request, jsonify
6
 
 
 
 
7
  app = Flask(__name__)
8
 
9
- # आपका दिया गया Google Apps Script URL
 
 
10
  GAS_URL = "https://script.google.com/macros/s/AKfycbwh2d9IZNpcLNbv8aJSSSI4RBTzuoZ5wi7TDHaBMX9BeOm7TjKxcjfaTEPLJi-q8AXyyQ/exec"
 
 
11
 
12
- # बैकग्राउंड में GAS को अपडेट करने का फंक्शन (ताकि API रिस्पॉन्स फास्ट रहे)
13
- def update_gas_usage(api_key, model, tokens_used):
14
- def task():
15
- try:
16
- payload = {
17
- "action": "log_usage",
18
- "api_key": api_key,
19
- "model": model,
20
- "tokens_used": tokens_used,
21
- "timestamp": int(time.time())
22
- }
23
- # GAS को डेटा भेजना (टोकन और रिक्वेस्ट अपडेट करने के लिए)
24
- requests.post(GAS_URL, json=payload)
25
- print(f"✅ GAS Updated: {tokens_used} tokens logged for {api_key}")
26
- except Exception as e:
27
- print(f"❌ Failed to update GAS: {e}")
28
-
29
- threading.Thread(target=task).start()
30
-
31
-
32
- @app.route('/', methods=['GET'])
33
- def home():
34
- return jsonify({"status": "Vedika AI API Gateway is Running!"}), 200
35
-
36
 
37
- @app.route('/v1/models', methods=['GET'])
38
- def get_models():
39
- """GAS URL से मॉडल्स एक्सट्रैक्ट करके OpenAI फॉर्मेट में रिटर्न करना"""
 
40
  try:
41
- response = requests.get(GAS_URL)
42
- data = response.json()
43
-
44
- # मॉडल्स की लिस्ट निकालना (आपके GAS रिस्पॉन्स स्ट्रक्चर के अनुसार)
45
- models_array = data if isinstance(data, list) else data.get("models", [])
46
-
47
- openai_formatted_models = {
48
- "object": "list",
49
- "data": [
50
- {
51
- "id": model.get("id", model) if isinstance(model, dict) else model,
52
- "object": "model",
53
- "created": int(time.time()),
54
- "owned_by": "Vedika AI",
55
- "permission": [],
56
- "root": model.get("id", model) if isinstance(model, dict) else model,
57
- "parent": None
58
- } for model in models_array
59
- ]
60
  }
61
- return jsonify(openai_formatted_models), 200
62
-
63
  except Exception as e:
64
- return jsonify({"error": "Failed to fetch models from GAS"}), 500
65
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
 
 
 
67
  @app.route('/v1/chat/completions', methods=['POST'])
68
  def chat_completions():
69
- """चैट रिक्वेस्ट हैंडल करना और टोकन अपडेट करना"""
70
- # 1. API Key चेक करना
71
- auth_header = request.headers.get("Authorization")
72
- if not auth_header or not auth_header.startswith("Bearer "):
73
- return jsonify({"error": {"message": "Unauthorized: Missing API Key", "type": "invalid_request_error"}}), 401
74
 
75
- user_api_key = auth_header.split(" ")[1]
76
- request_data = request.json
77
- model_name = request_data.get("model", "Vedika-Flash")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
- # ---------------------------------------------------------
80
- # 2. यहाँ आप अपने असली AI प्रोवाइडर (जैसे NVIDIA/OpenRouter)
81
- # को रिक्वेस्ट भेजेंगे। अभी के लिए यह एक डमी रिस्पॉन्स है।
82
- # ---------------------------------------------------------
83
 
84
- # *उदाहरण:* provider_response = requests.post(NVIDIA_URL, headers=..., json=...)
85
- # response_data = provider_response.json()
86
 
87
- # डमी रिस्पॉन्स (इसे अपने असली प्रोवाइडर के रिस्पॉन्स से बदल दें)
88
- response_data = {
89
- "id": f"chatcmpl-{int(time.time())}",
90
- "object": "chat.completion",
91
- "created": int(time.time()),
92
- "model": model_name,
93
- "choices": [{
94
- "index": 0,
95
- "message": {"role": "assistant", "content": "यह Vedika AI की तरफ से जनरेटेड रिस्पॉन्स है।"},
96
- "finish_reason": "stop"
97
- }],
98
- "usage": {
99
- "prompt_tokens": 10,
100
- "completion_tokens": 25,
101
- "total_tokens": 35 # असली API से मिलने वाला टोकन काउंट
102
- }
103
- }
104
-
105
- # 3. टोकन काउंट निकालना
106
- tokens_used = response_data.get("usage", {}).get("total_tokens", 0)
107
 
108
- # 4. GAS को अपडेट करने के लिए बैकग्राउंड टास्क ट्रिगर करना
109
- update_gas_usage(user_api_key, model_name, tokens_used)
 
 
 
 
 
 
110
 
111
- # 5. यूज़र को तुरंत रिस्पॉन्स भेजना
112
- return jsonify(response_data), 200
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
 
115
  if __name__ == '__main__':
116
- # Hugging Face Spaces डिफ़ॉल्ट रूप से 7860 पोर्ट का उपयोग करता है
117
  app.run(host='0.0.0.0', port=7860)
 
1
  import os
 
2
  import requests
3
+ import json
4
  import threading
5
+ from flask import Flask, request, jsonify, Response, stream_with_context
6
 
7
+ # ================================================================================
8
+ # FLASK APP INITIALIZATION
9
+ # ================================================================================
10
  app = Flask(__name__)
11
 
12
+ # ----------------------------------------------------------------------------
13
+ # CONFIGURATION & URLS
14
+ # ----------------------------------------------------------------------------
15
  GAS_URL = "https://script.google.com/macros/s/AKfycbwh2d9IZNpcLNbv8aJSSSI4RBTzuoZ5wi7TDHaBMX9BeOm7TjKxcjfaTEPLJi-q8AXyyQ/exec"
16
+ NVIDIA_API_KEY = os.environ.get("NVIDIA_API_KEY", "YOUR_NVIDIA_API_KEY_HERE")
17
+ INVOKE_URL = "https://integrate.api.nvidia.com/v1/chat/completions"
18
 
19
+ MODEL_MAPPING = {
20
+ "Vedika-4.1-Flash": "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning",
21
+ "Vedika-2.5-Balanced": "meta/llama-3.2-90b-vision-instruct",
22
+ "Vedika-5.6-Pro": "stepfun-ai/step-3.7-flash"
23
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
+ # ----------------------------------------------------------------------------
26
+ # BACKGROUND LOGGING (Does not slow down user response)
27
+ # ----------------------------------------------------------------------------
28
+ def log_usage_to_gas(api_key, email, model_name):
29
  try:
30
+ payload = {
31
+ "action": "log_api_usage",
32
+ "apiKey": api_key,
33
+ "email": email,
34
+ "model": model_name
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  }
36
+ # Sends data to Google Apps Script in the background
37
+ requests.post(GAS_URL, json=payload, timeout=5)
38
  except Exception as e:
39
+ pass # Ignore errors in background logging to keep system stable
40
 
41
+ # ----------------------------------------------------------------------------
42
+ # SYSTEM PROMPT ENGINE
43
+ # ----------------------------------------------------------------------------
44
+ def get_base_prompt(model_name):
45
+ base = f"[CRITICAL IDENTITY OVERRIDE]\nName: {model_name}\nCreator/Engineer: Divy Patel\n\n"
46
+ if "4.1" in model_name:
47
+ base += "You are Vedika 4.1 Flash, a fast Omni-modal AI. Answer directly. Write clean code.\n"
48
+ elif "2.5" in model_name:
49
+ base += "You are Vedika 2.5 Balanced, an advanced Vision AI. Maintain a helpful, professional tone.\n"
50
+ elif "5.6" in model_name:
51
+ base += "You are Vedika 5.6 Pro, an elite enterprise AI architect. Provide highly optimized solutions.\n"
52
+ return base
53
 
54
+ # ================================================================================
55
+ # PURE OPENAI COMPATIBLE ENDPOINT (WITH AUTH & LOGGING)
56
+ # ================================================================================
57
  @app.route('/v1/chat/completions', methods=['POST'])
58
  def chat_completions():
59
+ # 1. Extract API Key from Request Header
60
+ auth_header = request.headers.get("Authorization", "")
61
+ if not auth_header.startswith("Bearer "):
62
+ return jsonify({"error": {"message": "Missing or invalid API Key format.", "type": "auth_error"}}), 401
 
63
 
64
+ user_api_key = auth_header.split("Bearer ")[1].strip()
65
+
66
+ # 2. Authenticate with Google Apps Script (The Gateway Logic)
67
+ try:
68
+ gas_auth_response = requests.post(GAS_URL, json={"action": "hf_verify_key", "apiKey": user_api_key}, timeout=5)
69
+ gas_data = gas_auth_response.json()
70
+
71
+ if gas_data.get("status") != "authorized":
72
+ return jsonify({"error": {"message": gas_data.get("message", "Invalid or Blocked API Key."), "type": "auth_error"}}), 403
73
+
74
+ user_email = gas_data.get("user", "Unknown User")
75
+ except Exception as e:
76
+ return jsonify({"error": {"message": "Auth Server Offline. Please try again later.", "type": "server_error"}}), 500
77
+
78
+ # 3. Process Request Details
79
+ data = request.get_json() or {}
80
+ requested_model = data.get("model", "Vedika-4.1-Flash")
81
+ api_model_id = MODEL_MAPPING.get(requested_model, MODEL_MAPPING["Vedika-4.1-Flash"])
82
 
83
+ messages = data.get("messages", [])
84
+ stream = data.get("stream", False)
85
+ enable_thinking = data.get("enable_thinking", True)
 
86
 
87
+ custom_system_content = ""
88
+ filtered_messages = []
89
 
90
+ for msg in messages:
91
+ if msg.get("role") == "system":
92
+ custom_system_content += msg.get("content", "") + "\n"
93
+ else:
94
+ filtered_messages.append(msg)
95
+
96
+ final_system_content = get_base_prompt(requested_model)
97
+ if custom_system_content.strip():
98
+ final_system_content += "\n[CUSTOM SYSTEM INSTRUCTIONS]\n" + custom_system_content.strip()
99
+
100
+ final_messages = [{"role": "system", "content": final_system_content}] + filtered_messages
 
 
 
 
 
 
 
 
 
101
 
102
+ payload = {
103
+ "model": api_model_id,
104
+ "messages": final_messages,
105
+ "stream": stream,
106
+ "temperature": data.get("temperature", 0.7),
107
+ "max_tokens": data.get("max_tokens", 4096),
108
+ "top_p": data.get("top_p", 1.0)
109
+ }
110
 
111
+ if "4.1" in requested_model and enable_thinking:
112
+ payload["chat_template_kwargs"] = {"enable_thinking": True}
113
+ if isinstance(payload["max_tokens"], int) and payload["max_tokens"] > 1024:
114
+ payload["reasoning_budget"] = min(16384, int(payload["max_tokens"] * 0.5))
115
+
116
+ headers = {
117
+ "Authorization": f"Bearer {NVIDIA_API_KEY}",
118
+ "Content-Type": "application/json"
119
+ }
120
+
121
+ try:
122
+ response = requests.post(INVOKE_URL, headers=headers, json=payload, stream=stream, timeout=60)
123
+
124
+ if response.status_code != 200:
125
+ return jsonify({"error": {"message": f"Upstream API Error: {response.text}", "code": response.status_code}}), response.status_code
126
+
127
+ # Trigger background logging to GAS (won't slow down the response)
128
+ threading.Thread(target=log_usage_to_gas, args=(user_api_key, user_email, requested_model)).start()
129
+
130
+ if not stream:
131
+ nvidia_json = response.json()
132
+ nvidia_json["model"] = requested_model
133
+ return jsonify(nvidia_json)
134
 
135
+ def generate():
136
+ for line in response.iter_lines():
137
+ if line:
138
+ decoded = line.decode("utf-8")
139
+ if decoded.startswith("data: ") and "[DONE]" not in decoded:
140
+ try:
141
+ data_json = json.loads(decoded[6:])
142
+ data_json["model"] = requested_model
143
+ yield "data: " + json.dumps(data_json) + "\n\n"
144
+ except Exception:
145
+ yield decoded + "\n\n"
146
+ else:
147
+ yield decoded + "\n\n"
148
+
149
+ return Response(stream_with_context(generate()), mimetype='text/event-stream')
150
+
151
+ except Exception as e:
152
+ return jsonify({"error": {"message": str(e), "type": "internal_server_error"}}), 500
153
 
154
  if __name__ == '__main__':
 
155
  app.run(host='0.0.0.0', port=7860)