diff --git a/MCP/gemini_image_test.py b/MCP/gemini_image_test.py new file mode 100644 index 00000000..55a31aa4 --- /dev/null +++ b/MCP/gemini_image_test.py @@ -0,0 +1,108 @@ +import json +import requests +import re + +# ================= 配置区域 ================= + +# 1. 认证令牌 (Authorization Token) +# 每次运行前,请确保从浏览器开发者工具中获取一个新的令牌 +AUTH_TOKEN = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IldBQS5BY2c4ZXVIWHo0NkI4SkctTFNCb1BwaEwzWEVCclczQXoxUWtSRDhXb1FITzV1aVY5a3lySHFUTldyWHE3Z3FGQkFNWDlCUXc3RWd3RnBXRXJFY3BER3NTSU43T1M3c3ppTHd5YXNUTXVfd0l1S0s4VGlFc2tGcE5haTZzcW1mX0RFQlJWN2VCSFZ3ZHhqR2hqMjN4WlVXeHhEbUZ0b3R4dkFwT2ZQNTlvMHplUzRTek1XeVNuRWFwUWJtNmVJZHdtRUZwZF9iTi1tU01IQWNaU0RjTHhrR1k3bVJmSXNVejhsT1MxR3NrNzZ4N0pfZnZyRGUzRm95X1VHSWdmcmcyYXlJNDBFVlpfZ2t2Y1pKbk5nMHdDbG95d1pjYWVNUno0UVZjcnZJR0d0Mm05RlgxdEJwNTBZa3ZMdFNBQ1NzX0E5N2pPTTFGQkROcHc5VHFWWmY2eUlwRW1xNnVDSVlsekxyQy13ZDJ5QTNZbjRiSW5sV0FrNnFyMXRLY1RWU0FTZ3dOYjV1Wl94YmFTRXFCdy15RkhRQm1zOUgwcF8xZnJqS1R3bG53Wkl3UjlXU1pUSkMxY3gwWVFfeTBDTlBzeWxDR3JNWEZEbzBmRFFHV3hzd21lT2xqZWd3SzBjdlRPX3hUVk04NzZWRVk0R3o2b0pDTmFMSSJ9.eyJpc3MiOiJodHRwczovL2J1c2luZXNzLmdlbWluaS5nb29nbGUiLCJhdWQiOiJodHRwczovL2Jpei1kaXNjb3ZlcnllbmdpbmUuZ29vZ2xlYXBpcy5jb20iLCJzdWIiOiJjc2VzaWR4LzMyNjAzOTY4OCIsImlhdCI6MTc2NTE2NzM4NiwiZXhwIjoxNzY1MTY3Njg2LCJuYmYiOjE3NjUxNjczODZ9.urQLDoUDAEjQhX8c42hJfKU28WoKn8-0tGjgX5RqhtY" + +# 2. 接口地址 +TARGET_URL = "https://biz-discoveryengine.googleapis.com/v1alpha/locations/global/widgetStreamAssist" + +# 3. 会话 ID 和 Config ID (使用图片生成时的固定值) +SESSION_ID = "collections/default_collection/engines/agentspace-engine/sessions/16190456916940072265" +CONFIG_ID = "36cc1840-8078-4a90-ad0a-6f995a52af32" + +# =============================================================== + +def parse_gemini_response(text): + """ + 根据真实的流式响应,精确解析并拼接 Gemini 的文本和图片文件回复。 + """ + print("------ 原始响应 ------") + print(text) + print("--------------------") + try: + full_response_parts = [] + # 响应体是由换行符分隔的一系列JSON对象 + lines = text.strip().split('\n') + for line in lines: + try: + data = json.loads(line) + replies = data.get("streamAssistResponse", {}).get("answer", {}).get("replies", []) + + for reply in replies: + content = reply.get("groundedContent", {}).get("content", {}) + + # 检查并提取文本内容 + if "text" in content: + full_response_parts.append(content["text"]) + + # 检查并提取文件(图片)内容 + if "file" in content and "fileId" in content["file"]: + file_id = content["file"]["fileId"] + # 将 fileId 构造成一个 Markdown 图片链接。 + image_markdown = f"\n![Generated Image](https://business.gemini.google.com/file/{file_id})\n" + full_response_parts.append(image_markdown) + + except (json.JSONDecodeError): + # 忽略无法解析为JSON的行 + continue + + if full_response_parts: + return "".join(full_response_parts) + + return "未能从响应流中提取有效内容。" + except Exception as e: + return f"解析响应时发生未知错误: {e}" + +def send_test_request(prompt: str): + """ + 发送一次测试请求并返回结果。 + """ + if "在此处粘贴" in AUTH_TOKEN: + return "错误: 请在脚本中填入真实的 AUTH_TOKEN" + + payload = { + "configId": CONFIG_ID, + "additionalParams": {"token": "-"}, + "streamAssistRequest": { + "session": SESSION_ID, + "query": {"parts": [{"text": "\n" + prompt}]}, + "answerGenerationMode": "NORMAL", + "assistGenerationConfig": {"modelId": "gemini-3-pro-preview"}, + "assistSkippingMode": "REQUEST_ASSIST", + "languageCode": "zh-CN", + "userMetadata": {"timeZone": "Asia/Shanghai"} + } + } + + headers = { + "accept": "*/*", + "authorization": AUTH_TOKEN, + "content-type": "application/json", + "origin": "https://business.gemini.google", + "referer": "https://business.gemini.google/", + "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0", + } + + try: + print(f"正在发送图片生成测试请求: {prompt[:100]}...") + resp = requests.post(TARGET_URL, headers=headers, json=payload) + + if resp.status_code != 200: + return f"请求失败! 状态码: {resp.status_code}\n响应内容:\n{resp.text}" + + return parse_gemini_response(resp.text) + + except Exception as e: + return f"发生异常: {e}" + +if __name__ == '__main__': + test_prompt = "画一只戴着宇航员头盔的猫" + result = send_test_request(test_prompt) + print("\n====== 图片生成测试结果 ======") + print(result) + print("==============================") \ No newline at end of file diff --git a/MCP/gemini_proxy.py b/MCP/gemini_proxy.py new file mode 100644 index 00000000..253ca663 --- /dev/null +++ b/MCP/gemini_proxy.py @@ -0,0 +1,123 @@ +import json +import requests +from flask import Flask, request, Response +import re + +# ================= 配置区域 ================= + +AUTH_TOKEN = "Bearer 在此处粘贴您的最新Authorization令牌" +TARGET_URL = "https://biz-discoveryengine.googleapis.com/v1alpha/locations/global/widgetStreamAssist" +SESSION_ID = "collections/default_collection/engines/agentspace-engine/sessions/16190456916940072265" +CONFIG_ID = "36cc1840-8078-4a90-ad0a-6f995a52af32" + +# =============================================================== + +app = Flask(__name__) + +def parse_gemini_response(text): + """ + 最终版精确解析器。 + """ + try: + full_response_parts = [] + lines = text.strip().split('\n') + for line in lines: + try: + if line.strip().startswith('{') and line.strip().endswith('}'): + data = json.loads(line) + replies = data.get("streamAssistResponse", {}).get("answer", {}).get("replies", []) + + for reply in replies: + content = reply.get("groundedContent", {}).get("content", {}) + + if isinstance(content, dict) and "text" in content: + full_response_parts.append(content["text"]) + + if isinstance(content, dict) and "file" in content and "fileId" in content.get("file", {}): + file_id = content["file"]["fileId"] + image_markdown = f"\n![Generated Image](https://business.gemini.google.com/file/{file_id})\n" + full_response_parts.append(image_markdown) + + except (json.JSONDecodeError): + continue + + if full_response_parts: + return "".join(full_response_parts) + + return "未能从响应流中提取有效内容。" + except Exception as e: + return f"解析响应时发生未知错误: {e}" + +@app.route('/v1/chat/completions', methods=['POST']) +def proxy(): + if "在此处粘贴" in AUTH_TOKEN: + return Response('{"error": "请在 gemini_proxy.py 脚本中配置 AUTH_TOKEN"}', status=500, mimetype='application/json') + + openai_request = request.json + messages = openai_request.get('messages', []) + + # 恢复到原始状态:简单拼接所有消息内容 + prompt = "" + for msg in messages: + role = msg.get('role', 'user') + content = msg.get('content', '') + prompt += f"{role}: {str(content)}\n" + + print(f"收到请求: {prompt[:100]}...") + + payload = { + "configId": CONFIG_ID, + "additionalParams": {"token": "-"}, + "streamAssistRequest": { + "session": SESSION_ID, + "query": {"parts": [{"text": "\n" + prompt}]}, + "answerGenerationMode": "NORMAL", + "assistGenerationConfig": {"modelId": "gemini-3-pro-preview"}, + "assistSkippingMode": "REQUEST_ASSIST", + "languageCode": "zh-CN", + "userMetadata": {"timeZone": "Asia/Shanghai"} + } + } + + headers = { + "accept": "*/*", + "authorization": AUTH_TOKEN, + "content-type": "application/json", + "origin": "https://business.gemini.google", + "referer": "https://business.gemini.google/", + "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0", + } + + try: + resp = requests.post(TARGET_URL, headers=headers, json=payload) + + if resp.status_code != 200: + return Response(f'{{"error": "Gemini 请求失败", "status_code": {resp.status_code}, "details": "{resp.text}"}}', status=500, mimetype='application/json') + + gemini_text = parse_gemini_response(resp.text) + + openai_resp = { + "id": "chatcmpl-gemini-enterprise-proxy", + "object": "chat.completion", + "created": 0, + "choices": [{ + "index": 0, + "message": { + "role": "assistant", + "content": gemini_text + }, + "finish_reason": "stop" + }], + "usage": {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0} + } + + return Response(json.dumps(openai_resp), mimetype='application/json') + + except Exception as e: + return Response(f'{{"error": "代理服务器内部错误", "details": "{str(e)}"}}', status=500, mimetype='application/json') + +if __name__ == '__main__': + print("Gemini Enterprise to OpenAI Proxy") + print("服务已启动: http://localhost:5000/v1/chat/completions") + print("请注意:每次启动前,您可能都需要更新脚本中的 AUTH_TOKEN。") + app.run(port=5000, debug=False) \ No newline at end of file diff --git a/MCP/gemini_proxy_test.py b/MCP/gemini_proxy_test.py new file mode 100644 index 00000000..c3337b7f --- /dev/null +++ b/MCP/gemini_proxy_test.py @@ -0,0 +1,113 @@ +import json +import requests + +# ================= 配置区域 ================= + +# 1. 认证令牌 (Authorization Token) +# 从 widgetStreamAssist 请求的 "Request Headers" -> "Authorization" 复制 +AUTH_TOKEN = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IldBQS5BY2c4ZXVIa0xsOXFiN1BobzBtRS04YzJpV0FqSlY1dHFuZGdhTE9LNmpyeGRadmFvVG9tZjN2aG1vRlBjVVFtN1N5T1NwYm1GVUNKZU5qRkdqNG50c3dxeXphVGNEZHR1UEpwY3EzQUpidV9LV0I1N1Zmb1phWWQ2ay1VMHNUX3lPNWs4T1hIUHZaSGRpWm9xSmlIVWNNM2ZpbFNnYU9UWVJWT2dBNGFSeExMckNCTHRPNjV4WERaTGVzeFJKNmpFM3FISTBNQjYxeG1hTG5WYTNOUEhGYkI4WnhXcHA3M212SXdnQVhYU1k2RlU1SnQ1LWdKSUlxTXV4WVZ5dXlxVTNodV9iREF3enBvaVBaSU1nVi02ZE5LdWc3SlJfMWNJUTdhZE91YnlpdVA0Q0hqLV9za0haUzgweGd2aXA4S3Z1Ui1lRnppRWlPXzRmMGxoYjlrQk5tYzQ0RkxRQ2ZXVC1YTi1JTG1uNC1LcjgxMFNreDc0a3dVMUZjRWw2dkZJYnI1VmlrRnpIdlNJUkNxakFyX0x3TzFUN3ZMbDd5LXNiSHlJWWN4OUdNd3dhSnZIYy11YlhnUkl4cm1vdG1IUTlYLXd6UEpRTnpxQlVrOHRHSVdiNGxaQ2ZsZjh4Rk5IQ3R3YVFNdVNtZGZzc1ByT0NUN2d2YyJ9.eyJpc3MiOiJodHRwczovL2J1c2luZXNzLmdlbWluaS5nb29nbGUiLCJhdWQiOiJodHRwczovL2Jpei1kaXNjb3ZlcnllbmdpbmUuZ29vZ2xlYXBpcy5jb20iLCJzdWIiOiJjc2VzaWR4LzMyNjAzOTY4OCIsImlhdCI6MTc2NTE2NjUwMSwiZXhwIjoxNzY1MTY2ODAxLCJuYmYiOjE3NjUxNjY1MDF9.g_pzR-3_OaL8eXHh_5alAuJeMKL56O5rS1JcX63Twmw" + +# 2. 接口地址 +TARGET_URL = "https://biz-discoveryengine.googleapis.com/v1alpha/locations/global/widgetStreamAssist" + +# 3. 会话 ID 和 Config ID (从真实 Payload 复制) +SESSION_ID = "collections/default_collection/engines/agentspace-engine/sessions/16611680310063068731" +CONFIG_ID = "36cc1840-8078-4a90-ad0a-6f995a52af32" + +# =============================================================== + +def parse_gemini_response(text): + """ + 根据您提供的真实响应体,更新解析器。 + """ + print("------ 原始响应 ------") + print(text) + print("--------------------") + try: + full_response = "" + # 响应体可能是一系列由换行符分隔的JSON对象 + # 我们需要找到包含有效文本块的部分 + # 注意:真实的流式响应可能更复杂,这里是一个简化版解析 + lines = text.strip().split('\n') + for line in lines: + try: + data = json.loads(line) + # 根据您提供的响应体,路径是 streamAssistResponse -> answer -> replies -> [0] -> groundedContent -> content -> text + text_chunk = data["streamAssistResponse"]["answer"]["replies"][0]["groundedContent"]["content"]["text"] + full_response += text_chunk + except (KeyError, IndexError, TypeError, json.JSONDecodeError): + continue + if full_response: + return full_response + return "未能从响应流中提取有效文本。" + except Exception as e: + return f"解析响应失败: {e}" + +def send_test_request(prompt: str): + """ + 发送一次测试请求并返回结果。 + """ + if "在此处粘贴" in AUTH_TOKEN: + return "错误: 请在脚本中填入真实的 AUTH_TOKEN" + + # 使用您提供的真实Payload结构,并动态插入prompt + # 关键修正:在prompt前添加 '\n' 以完全模拟浏览器行为 + payload = { + "configId": CONFIG_ID, + "additionalParams": {"token": "-"}, + "streamAssistRequest": { + "session": SESSION_ID, + "query": {"parts": [{"text": "\n" + prompt}]}, # <--- 关键修正 + "filter": "", + "fileIds": [], + "answerGenerationMode": "NORMAL", + "toolsSpec": { + "webGroundingSpec": {}, + "toolRegistry": "default_tool_registry", + "imageGenerationSpec": {}, + "videoGenerationSpec": {} + }, + "languageCode": "zh-CN", + "userMetadata": {"timeZone": "Asia/Shanghai"}, + "assistSkippingMode": "REQUEST_ASSIST", + "assistGenerationConfig": {"modelId": "gemini-3-pro-preview"} + } + } + + # 使用您提供的完整请求头 + headers = { + "accept": "*/*", + "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", + "authorization": AUTH_TOKEN, + "content-type": "application/json", + "origin": "https://business.gemini.google", + "priority": "u=1, i", + "referer": "https://business.gemini.google/", + "sec-ch-ua": '"Microsoft Edge";v="143", "Chromium";v="143", "Not A(Brand";v="24"', + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": '"Windows"', + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "cross-site", + "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0", + "x-server-timeout": "1800", + } + + try: + print(f"正在发送测试请求: {prompt[:100]}...") + resp = requests.post(TARGET_URL, headers=headers, json=payload) + + if resp.status_code != 200: + return f"请求失败! 状态码: {resp.status_code}\n响应内容:\n{resp.text}" + + return parse_gemini_response(resp.text) + + except Exception as e: + return f"发生异常: {e}" + +if __name__ == '__main__': + test_prompt = "你好世界" + result = send_test_request(test_prompt) + print("\n====== 测试结果 ======") + print(result) + print("======================") \ No newline at end of file