Skip to content

Commit c9a546e

Browse files
authored
Merge pull request Heavrnl#19 from iCross/feature/async-openai-integration
feat: integrate AsyncOpenAI for improved async handling
2 parents b849680 + 50779af commit c9a546e

5 files changed

Lines changed: 60 additions & 53 deletions

File tree

ai/deepseek_provider.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from typing import Optional
2-
from openai import OpenAI
1+
from typing import Optional, List, Dict
2+
from openai import AsyncOpenAI
33
from .openai_base_provider import OpenAIBaseProvider
44
import os
55
import logging
@@ -11,5 +11,5 @@ def __init__(self):
1111
super().__init__(
1212
env_prefix='DEEPSEEK',
1313
default_model='deepseek-chat',
14-
default_api_base='https://api.deepseek.com'
15-
)
14+
default_api_base='https://api.deepseek.com/v1'
15+
)

ai/grok_provider.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from typing import Optional
2-
from openai import OpenAI
1+
from typing import Optional, List, Dict
2+
from openai import AsyncOpenAI
33
from .openai_base_provider import OpenAIBaseProvider
44
import os
55
import logging

ai/openai_base_provider.py

Lines changed: 50 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,76 @@
11
from typing import Optional, List, Dict
2-
from openai import OpenAI
2+
from openai import AsyncOpenAI
33
from .base import BaseAIProvider
44
import os
55
import logging
66

77
logger = logging.getLogger(__name__)
88

99
class OpenAIBaseProvider(BaseAIProvider):
10-
def __init__(self, env_prefix: str, default_model: str, default_api_base: str):
10+
def __init__(self, env_prefix: str = 'OPENAI', default_model: str = 'gpt-4o-mini',
11+
default_api_base: str = 'https://api.openai.com/v1'):
1112
"""
1213
初始化基础OpenAI格式提供者
13-
14+
1415
Args:
1516
env_prefix: 环境变量前缀,如 'OPENAI', 'GROK', 'DEEPSEEK', 'QWEN'
1617
default_model: 默认模型名称
1718
default_api_base: 默认API基础URL
1819
"""
19-
self.client = None
20-
self.model = None
20+
super().__init__()
2121
self.env_prefix = env_prefix
2222
self.default_model = default_model
23-
24-
# 获取环境变量中的 API_BASE,如果为空或只有空格则使用默认值
25-
api_base = os.getenv(f'{env_prefix}_API_BASE', '').strip()
26-
self.api_base = api_base if api_base else default_api_base
27-
28-
async def initialize(self, **kwargs):
23+
self.default_api_base = default_api_base
24+
self.client = None
25+
self.model = None
26+
27+
async def initialize(self, **kwargs) -> None:
2928
"""初始化OpenAI客户端"""
30-
api_key = os.getenv(f'{self.env_prefix}_API_KEY')
31-
if not api_key:
32-
raise ValueError(f"未设置{self.env_prefix}_API_KEY环境变量")
33-
34-
self.client = OpenAI(
35-
api_key=api_key,
36-
base_url=self.api_base
37-
)
38-
logger.info(f"初始化OpenAI模型: {kwargs.get('model')}")
39-
40-
self.model = kwargs.get('model', self.default_model)
41-
42-
async def process_message(self,
43-
message: str,
29+
try:
30+
api_key = os.getenv(f'{self.env_prefix}_API_KEY')
31+
if not api_key:
32+
raise ValueError(f"未设置 {self.env_prefix}_API_KEY 环境变量")
33+
34+
api_base = os.getenv(f'{self.env_prefix}_API_BASE', '').strip() or self.default_api_base
35+
36+
self.client = AsyncOpenAI(
37+
api_key=api_key,
38+
base_url=api_base
39+
)
40+
41+
self.model = kwargs.get('model', self.default_model)
42+
logger.info(f"初始化OpenAI模型: {self.model}")
43+
44+
except Exception as e:
45+
error_msg = f"初始化 {self.env_prefix} 客户端时出错: {str(e)}"
46+
logger.error(error_msg, exc_info=True)
47+
raise
48+
49+
async def process_message(self,
50+
message: str,
4451
prompt: Optional[str] = None,
4552
images: Optional[List[Dict[str, str]]] = None,
4653
**kwargs) -> str:
4754
"""处理消息"""
4855
try:
4956
if not self.client:
5057
await self.initialize(**kwargs)
51-
58+
5259
messages = []
5360
if prompt:
5461
messages.append({"role": "system", "content": prompt})
55-
62+
5663
# 如果有图片,需要添加到消息中
5764
if images and len(images) > 0:
5865
# 创建包含文本和图片的内容数组
5966
content = []
60-
67+
6168
# 添加文本
6269
content.append({
6370
"type": "text",
6471
"text": message
6572
})
66-
73+
6774
# 添加每张图片
6875
for img in images:
6976
content.append({
@@ -73,46 +80,46 @@ async def process_message(self,
7380
}
7481
})
7582
logger.info(f"已添加一张类型为 {img['mime_type']} 的图片,大小约 {len(img['data']) // 1000} KB")
76-
83+
7784
messages.append({"role": "user", "content": content})
7885
else:
7986
# 没有图片,只添加文本
8087
messages.append({"role": "user", "content": message})
8188

8289
logger.info(f"实际使用的OpenAI模型: {self.model}")
83-
90+
8491
# 所有模型统一使用流式调用
85-
completion = self.client.chat.completions.create(
92+
completion = await self.client.chat.completions.create(
8693
model=self.model,
8794
messages=messages,
8895
stream=True
8996
)
90-
97+
9198
# 收集所有内容
9299
collected_content = ""
93100
collected_reasoning = ""
94-
95-
for chunk in completion:
101+
102+
async for chunk in completion:
96103
if not chunk.choices:
97104
continue
98-
105+
99106
delta = chunk.choices[0].delta
100-
107+
101108
# 处理思考内容(如果存在)
102109
if hasattr(delta, 'reasoning_content') and delta.reasoning_content is not None:
103110
collected_reasoning += delta.reasoning_content
104-
111+
105112
# 处理回答内容
106113
if hasattr(delta, 'content') and delta.content is not None:
107114
collected_content += delta.content
108-
115+
109116
# 如果没有内容但有思考过程,可能是思考模型只返回了思考过程
110117
if not collected_content and collected_reasoning:
111118
logger.warning("模型只返回了思考过程,没有最终回答")
112119
return "模型未能生成有效回答"
113-
120+
114121
return collected_content
115-
122+
116123
except Exception as e:
117-
logger.error(f"{self.env_prefix} API 调用失败: {str(e)}")
118-
return f"AI处理失败: {str(e)}"
124+
logger.error(f"{self.env_prefix} API 调用失败: {str(e)}", exc_info=True)
125+
return f"AI处理失败: {str(e)}"

ai/openai_provider.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from typing import Optional, List, Dict
2-
import openai
2+
from openai import AsyncOpenAI
33
from .base import BaseAIProvider
44
import os
55
import logging
@@ -62,5 +62,5 @@ async def process_message(self,
6262
return response.choices[0].message.content
6363

6464
except Exception as e:
65-
logger.error(f"OpenAI处理消息时出错: {str(e)}")
65+
logger.error(f"OpenAI处理消息时出错: {str(e)}", exc_info=True)
6666
return f"AI处理失败: {str(e)}"

ai/qwen_provider.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from typing import Optional
2-
from openai import OpenAI
1+
from typing import Optional, List, Dict
2+
from openai import AsyncOpenAI
33
from .openai_base_provider import OpenAIBaseProvider
44
import os
55
import logging

0 commit comments

Comments
 (0)