Spaces:
Sleeping
Sleeping
File size: 16,681 Bytes
f1b4581 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 |
import json
import requests
import os
from typing import Generator
from openai import OpenAI
from .base import BaseModel
class DeepSeekModel(BaseModel):
def __init__(self, api_key: str, temperature: float = 0.7, system_prompt: str = None, language: str = None, model_name: str = "deepseek-reasoner", api_base_url: str = None):
super().__init__(api_key, temperature, system_prompt, language)
self.model_name = model_name
self.api_base_url = api_base_url # 存储API基础URL
def get_default_system_prompt(self) -> str:
return """You are an expert at analyzing questions and providing detailed solutions. When presented with an image of a question:
1. First read and understand the question carefully
2. Break down the key components of the question
3. Provide a clear, step-by-step solution
4. If relevant, explain any concepts or theories involved
5. If there are multiple approaches, explain the most efficient one first"""
def get_model_identifier(self) -> str:
"""根据模型名称返回正确的API标识符"""
# 通过模型名称来确定实际的API调用标识符
if self.model_name == "deepseek-chat":
return "deepseek-chat"
# 如果是deepseek-reasoner或包含reasoner的模型名称,返回推理模型标识符
if "reasoner" in self.model_name.lower():
return "deepseek-reasoner"
# 对于deepseek-chat也返回对应的模型名称
if "chat" in self.model_name.lower() or self.model_name == "deepseek-chat":
return "deepseek-chat"
# 根据配置中的模型ID来确定实际的模型类型
if self.model_name == "deepseek-reasoner":
return "deepseek-reasoner"
elif self.model_name == "deepseek-chat":
return "deepseek-chat"
# 默认使用deepseek-chat作为API标识符
print(f"未知的DeepSeek模型名称: {self.model_name},使用deepseek-chat作为默认值")
return "deepseek-chat"
def analyze_text(self, text: str, proxies: dict = None) -> Generator[dict, None, None]:
"""Stream DeepSeek's response for text analysis"""
try:
# Initial status
yield {"status": "started", "content": ""}
# 保存原始环境变量
original_env = {
'http_proxy': os.environ.get('http_proxy'),
'https_proxy': os.environ.get('https_proxy')
}
try:
# 如果提供了代理设置,通过环境变量设置
if proxies:
if 'http' in proxies:
os.environ['http_proxy'] = proxies['http']
if 'https' in proxies:
os.environ['https_proxy'] = proxies['https']
# 初始化DeepSeek客户端,不再使用session对象
client = OpenAI(
api_key=self.api_key,
base_url="https://api.deepseek.com"
)
# 使用系统提供的系统提示词,不再自动添加语言指令
system_prompt = self.system_prompt
# 构建请求参数
params = {
"model": self.get_model_identifier(),
"messages": [
{
'role': 'system',
'content': system_prompt
},
{
'role': 'user',
'content': text
}
],
"stream": True
}
# 只有非推理模型才设置temperature参数
if not self.get_model_identifier().endswith('reasoner') and self.temperature is not None:
params["temperature"] = self.temperature
print(f"调用DeepSeek API: {self.get_model_identifier()}, 是否设置温度: {not self.get_model_identifier().endswith('reasoner')}, 温度值: {self.temperature if not self.get_model_identifier().endswith('reasoner') else 'N/A'}")
response = client.chat.completions.create(**params)
# 使用两个缓冲区,分别用于常规内容和思考内容
response_buffer = ""
thinking_buffer = ""
for chunk in response:
# 打印chunk以调试
try:
print(f"DeepSeek API返回chunk: {chunk}")
except:
print("无法打印chunk")
try:
# 同时处理两种不同的内容,确保正确区分思考内容和最终内容
delta = chunk.choices[0].delta
# 处理推理模型的思考内容
if hasattr(delta, 'reasoning_content') and delta.reasoning_content:
content = delta.reasoning_content
thinking_buffer += content
# 发送思考内容更新
if len(content) >= 20 or content.endswith(('.', '!', '?', '。', '!', '?', '\n')):
yield {
"status": "thinking",
"content": thinking_buffer
}
# 处理最终结果内容 - 即使在推理模型中也会有content字段
if hasattr(delta, 'content') and delta.content:
content = delta.content
response_buffer += content
print(f"累积响应内容: '{content}', 当前buffer: '{response_buffer}'")
# 发送结果内容更新
if len(content) >= 10 or content.endswith(('.', '!', '?', '。', '!', '?', '\n')):
yield {
"status": "streaming",
"content": response_buffer
}
# 处理消息结束
if hasattr(chunk.choices[0], 'finish_reason') and chunk.choices[0].finish_reason:
print(f"生成结束,原因: {chunk.choices[0].finish_reason}")
# 注意:不要在这里把思考内容作为正文,因为这可能导致重复内容
except Exception as e:
print(f"解析响应chunk时出错: {str(e)}")
continue
# 确保发送最终的缓冲内容
if thinking_buffer:
yield {
"status": "thinking_complete",
"content": thinking_buffer
}
# 发送最终响应内容
if response_buffer:
yield {
"status": "completed",
"content": response_buffer
}
# 如果没有正常的响应内容,但有思考内容,则将思考内容作为最终结果
elif thinking_buffer:
yield {
"status": "completed",
"content": thinking_buffer
}
else:
# 如果两者都没有,返回一个空结果
yield {
"status": "completed",
"content": "没有获取到内容"
}
except Exception as e:
error_msg = str(e)
print(f"DeepSeek API调用出错: {error_msg}")
# 提供具体的错误信息
if "invalid_api_key" in error_msg.lower():
error_msg = "DeepSeek API密钥无效,请检查您的API密钥"
elif "rate_limit" in error_msg.lower():
error_msg = "DeepSeek API请求频率超限,请稍后再试"
elif "quota_exceeded" in error_msg.lower():
error_msg = "DeepSeek API配额已用完,请续费或等待下个计费周期"
yield {
"status": "error",
"error": f"DeepSeek API错误: {error_msg}"
}
finally:
# 恢复原始环境变量
for key, value in original_env.items():
if value is None:
if key in os.environ:
del os.environ[key]
else:
os.environ[key] = value
except Exception as e:
error_msg = str(e)
print(f"调用DeepSeek模型时发生错误: {error_msg}")
if "invalid_api_key" in error_msg.lower():
error_msg = "API密钥无效,请检查设置"
elif "rate_limit" in error_msg.lower():
error_msg = "API请求频率超限,请稍后再试"
yield {
"status": "error",
"error": f"DeepSeek API错误: {error_msg}"
}
def analyze_image(self, image_data: str, proxies: dict = None) -> Generator[dict, None, None]:
"""Stream DeepSeek's response for image analysis"""
try:
# 检查我们是否有支持图像的模型
if self.model_name == "deepseek-chat" or self.model_name == "deepseek-reasoner":
yield {
"status": "error",
"error": "当前DeepSeek模型不支持图像分析,请使用Anthropic或OpenAI的多模态模型"
}
return
# Initial status
yield {"status": "started", "content": ""}
# 保存原始环境变量
original_env = {
'http_proxy': os.environ.get('http_proxy'),
'https_proxy': os.environ.get('https_proxy')
}
try:
# 如果提供了代理设置,通过环境变量设置
if proxies:
if 'http' in proxies:
os.environ['http_proxy'] = proxies['http']
if 'https' in proxies:
os.environ['https_proxy'] = proxies['https']
# 初始化DeepSeek客户端,不再使用session对象
client = OpenAI(
api_key=self.api_key,
base_url="https://api.deepseek.com"
)
# 使用系统提供的系统提示词,不再自动添加语言指令
system_prompt = self.system_prompt
# 构建请求参数
params = {
"model": self.get_model_identifier(),
"messages": [
{
'role': 'system',
'content': system_prompt
},
{
'role': 'user',
'content': f"Here's an image of a question to analyze: data:image/png;base64,{image_data}"
}
],
"stream": True
}
# 只有非推理模型才设置temperature参数
if not self.get_model_identifier().endswith('reasoner') and self.temperature is not None:
params["temperature"] = self.temperature
response = client.chat.completions.create(**params)
# 使用两个缓冲区,分别用于常规内容和思考内容
response_buffer = ""
thinking_buffer = ""
for chunk in response:
# 打印chunk以调试
try:
print(f"DeepSeek图像API返回chunk: {chunk}")
except:
print("无法打印chunk")
try:
# 同时处理两种不同的内容,确保正确区分思考内容和最终内容
delta = chunk.choices[0].delta
# 处理推理模型的思考内容
if hasattr(delta, 'reasoning_content') and delta.reasoning_content:
content = delta.reasoning_content
thinking_buffer += content
# 发送思考内容更新
if len(content) >= 20 or content.endswith(('.', '!', '?', '。', '!', '?', '\n')):
yield {
"status": "thinking",
"content": thinking_buffer
}
# 处理最终结果内容 - 即使在推理模型中也会有content字段
if hasattr(delta, 'content') and delta.content:
content = delta.content
response_buffer += content
print(f"累积图像响应内容: '{content}', 当前buffer: '{response_buffer}'")
# 发送结果内容更新
if len(content) >= 10 or content.endswith(('.', '!', '?', '。', '!', '?', '\n')):
yield {
"status": "streaming",
"content": response_buffer
}
# 处理消息结束
if hasattr(chunk.choices[0], 'finish_reason') and chunk.choices[0].finish_reason:
print(f"图像生成结束,原因: {chunk.choices[0].finish_reason}")
except Exception as e:
print(f"解析图像响应chunk时出错: {str(e)}")
continue
# 确保发送最终的缓冲内容
if thinking_buffer:
yield {
"status": "thinking_complete",
"content": thinking_buffer
}
# 发送最终响应内容
if response_buffer:
yield {
"status": "completed",
"content": response_buffer
}
except Exception as e:
error_msg = str(e)
print(f"DeepSeek API调用出错: {error_msg}")
# 提供具体的错误信息
if "invalid_api_key" in error_msg.lower():
error_msg = "DeepSeek API密钥无效,请检查您的API密钥"
elif "rate_limit" in error_msg.lower():
error_msg = "DeepSeek API请求频率超限,请稍后再试"
yield {
"status": "error",
"error": f"DeepSeek API错误: {error_msg}"
}
finally:
# 恢复原始环境变量
for key, value in original_env.items():
if value is None:
if key in os.environ:
del os.environ[key]
else:
os.environ[key] = value
except Exception as e:
error_msg = str(e)
if "invalid_api_key" in error_msg.lower():
error_msg = "API密钥无效,请检查设置"
elif "rate_limit" in error_msg.lower():
error_msg = "API请求频率超限,请稍后再试"
yield {
"status": "error",
"error": f"DeepSeek API错误: {error_msg}"
}
|