Files

117 lines
4.2 KiB
Python

import traceback
import requests
from typing import Tuple
from .llm_client import LLMClient
from .llm_connectors import GeneralLLMServiceConnector
class GeminiConnector(GeneralLLMServiceConnector):
"""Google Gemini API 连接器"""
def __init__(self, api_token, model):
# Gemini API URL 格式特殊,需要包含 API key
url = f"https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent?key={api_token}"
super().__init__(url, api_token, model)
def generate_payload(self, messages, **kwargs):
# 将 messages 转换为 Gemini 格式
contents = []
for msg in messages:
role = "user" if msg["role"] == "user" else "model"
contents.append({"role": role, "parts": [{"text": msg["content"]}]})
return {
"contents": contents,
"generationConfig": {
"maxOutputTokens": kwargs.get("max_tokens", 512),
"temperature": kwargs.get("temperature", 0.7),
"topP": kwargs.get("top_p", 0.9),
}
}
def invoke(self, messages, **kwargs):
"""Gemini API 使用不同的请求格式"""
payload = self.generate_payload(messages, **kwargs)
headers = {
"Content-Type": "application/json"
}
try:
response = requests.post(self.api_url, json=payload, headers=headers, timeout=self.timeout)
if response.status_code == 200:
response_data = response.json()
try:
return response_data["candidates"][0]["content"]["parts"][0]["text"]
except KeyError:
raise ValueError("Unexpected response format: missing 'candidates[0].content.parts[0].text'.")
elif response.status_code == 401:
raise Exception("Unauthorized: invalid or missing API key.")
else:
raise Exception(f"Request failed with status code {response.status_code}: {response.text}")
except requests.exceptions.Timeout:
raise Exception(f"Request timed out after {self.timeout} seconds.")
except requests.exceptions.RequestException as e:
raise Exception(f"Request error: {str(e)}")
class GeminiServiceConnectorNode:
NODE_NAME = "Gemini Service Connector 🦉| OwlV"
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"api_key": ("STRING", {"default": "", "password": True}),
"model_select": (
[
"gemini-1.5-pro",
"gemini-1.5-flash",
"gemini-2.0-flash-exp",
"Custom",
],
{"default": "gemini-1.5-flash"},
),
},
"optional": {
"custom_model_id": (
"STRING",
{
"default": "",
"placeholder": "Enter custom model ID (used when model_select is 'Custom')",
},
),
},
}
RETURN_TYPES = ("LLM",)
RETURN_NAMES = ("llm",)
FUNCTION = "execute"
CATEGORY = "Text Processing/LLM"
def execute(self, api_key: str, model_select: str, custom_model_id: str = "") -> Tuple[object]:
try:
# 确定最终使用的模型
model = custom_model_id if model_select == "Custom" and custom_model_id.strip() else model_select
# 创建 Gemini Connector
connector = GeminiConnector(api_key, model)
# 封装到 LLMClient
config = {
"provider": "Gemini",
"model": model,
"api_key": api_key,
"connector": connector,
}
client = LLMClient(kind="service", config=config)
return (client,)
except Exception as e:
print("GeminiServiceConnectorNode error:", e)
print(traceback.format_exc())
client = LLMClient(kind="service", config={"provider": "Gemini", "model": model_select, "error": str(e)})
return (client,)