mirror of
https://github.com/zhayujie/chatgpt-on-wechat.git
synced 2026-06-02 00:57:41 +08:00
Merge branch 'master' into feat-knowledge
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
# encoding:utf-8
|
||||
|
||||
import base64
|
||||
import json
|
||||
import re
|
||||
import time
|
||||
from typing import Optional
|
||||
|
||||
import requests
|
||||
|
||||
@@ -224,6 +227,79 @@ class ClaudeAPIBot(Bot, OpenAIImage):
|
||||
return 64000
|
||||
return 8192
|
||||
|
||||
@staticmethod
|
||||
def _parse_data_url(data_url: str):
|
||||
"""Parse a data:<mime>;base64,<data> URL into (media_type, base64_data)."""
|
||||
m = re.match(r"^data:([^;]+);base64,(.+)$", data_url, re.DOTALL)
|
||||
if m:
|
||||
return m.group(1), m.group(2)
|
||||
return None, None
|
||||
|
||||
def call_vision(self, image_url: str, question: str,
|
||||
model: Optional[str] = None,
|
||||
max_tokens: int = 1000) -> dict:
|
||||
"""Analyze an image using Claude Messages API (native image blocks)."""
|
||||
try:
|
||||
actual_model = model or self._model_mapping(conf().get("model"))
|
||||
|
||||
# Build Claude-native image content block
|
||||
if image_url.startswith("data:"):
|
||||
media_type, b64_data = self._parse_data_url(image_url)
|
||||
if not b64_data:
|
||||
return {"error": True, "message": "Invalid base64 data URL"}
|
||||
image_block = {
|
||||
"type": "image",
|
||||
"source": {"type": "base64",
|
||||
"media_type": media_type or "image/jpeg",
|
||||
"data": b64_data},
|
||||
}
|
||||
else:
|
||||
image_block = {
|
||||
"type": "image",
|
||||
"source": {"type": "url", "url": image_url},
|
||||
}
|
||||
|
||||
data = {
|
||||
"model": actual_model,
|
||||
"max_tokens": max_tokens,
|
||||
"messages": [{
|
||||
"role": "user",
|
||||
"content": [
|
||||
image_block,
|
||||
{"type": "text", "text": question},
|
||||
],
|
||||
}],
|
||||
}
|
||||
|
||||
headers = {
|
||||
"x-api-key": self.api_key,
|
||||
"anthropic-version": "2023-06-01",
|
||||
"content-type": "application/json",
|
||||
}
|
||||
proxies = {"http": self.proxy, "https": self.proxy} if self.proxy else None
|
||||
resp = requests.post(f"{self.api_base}/messages",
|
||||
headers=headers, json=data, proxies=proxies)
|
||||
|
||||
if resp.status_code != 200:
|
||||
return {"error": True, "message": f"HTTP {resp.status_code}: {resp.text[:300]}"}
|
||||
|
||||
body = resp.json()
|
||||
text_parts = [b.get("text", "") for b in body.get("content", [])
|
||||
if b.get("type") == "text"]
|
||||
usage = body.get("usage", {})
|
||||
return {
|
||||
"model": actual_model,
|
||||
"content": "".join(text_parts),
|
||||
"usage": {
|
||||
"prompt_tokens": usage.get("input_tokens", 0),
|
||||
"completion_tokens": usage.get("output_tokens", 0),
|
||||
"total_tokens": usage.get("input_tokens", 0) + usage.get("output_tokens", 0),
|
||||
},
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"[CLAUDE] call_vision error: {e}")
|
||||
return {"error": True, "message": str(e)}
|
||||
|
||||
def call_with_tools(self, messages, tools=None, stream=False, **kwargs):
|
||||
"""
|
||||
Call Claude API with tool support for agent integration
|
||||
|
||||
Reference in New Issue
Block a user