aisuite4cn 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aisuite4cn-0.1.0/LICENSE +18 -0
- aisuite4cn-0.1.0/PKG-INFO +40 -0
- aisuite4cn-0.1.0/README.md +20 -0
- aisuite4cn-0.1.0/aisuite4cn/__init__.py +1 -0
- aisuite4cn-0.1.0/aisuite4cn/client.py +117 -0
- aisuite4cn-0.1.0/aisuite4cn/framework/__init__.py +2 -0
- aisuite4cn-0.1.0/aisuite4cn/framework/chat_completion_response.py +8 -0
- aisuite4cn-0.1.0/aisuite4cn/framework/choice.py +6 -0
- aisuite4cn-0.1.0/aisuite4cn/framework/message.py +6 -0
- aisuite4cn-0.1.0/aisuite4cn/framework/provider_interface.py +25 -0
- aisuite4cn-0.1.0/aisuite4cn/provider.py +53 -0
- aisuite4cn-0.1.0/aisuite4cn/providers/__init__.py +0 -0
- aisuite4cn-0.1.0/aisuite4cn/providers/moonshot_provider.py +37 -0
- aisuite4cn-0.1.0/aisuite4cn/providers/qwen_provider.py +36 -0
- aisuite4cn-0.1.0/aisuite4cn/providers/volcengine_provider.py +46 -0
- aisuite4cn-0.1.0/pyproject.toml +33 -0
aisuite4cn-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Huwei
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
6
|
+
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
|
9
|
+
following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
12
|
+
portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|
15
|
+
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
16
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
17
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
18
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: aisuite4cn
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary:
|
|
5
|
+
Author: 胡伟
|
|
6
|
+
Author-email: 3314672@qq.com
|
|
7
|
+
Requires-Python: >=3.10,<4.0
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Provides-Extra: moonshot
|
|
14
|
+
Provides-Extra: qwen
|
|
15
|
+
Provides-Extra: volcengine
|
|
16
|
+
Requires-Dist: httpx (>=0.27.0,<0.28.0)
|
|
17
|
+
Requires-Dist: openai (>=1.35.8,<2.0.0) ; extra == "moonshot" or extra == "volcengine" or extra == "qwen"
|
|
18
|
+
Requires-Dist: pydantic (>=2.10.3,<3.0.0)
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# aisuite4cn
|
|
22
|
+
|
|
23
|
+
简单、统一的接口,可连接多个生成式人工智能提供商。
|
|
24
|
+
|
|
25
|
+
`aisuite4cn` 针对于中国的各类大模型厂商提供通用的支持。学习了`aisuite`方案,并开发了该库。
|
|
26
|
+
|
|
27
|
+
`aisuite4cn` 使得开发者能够通过标准化的接口轻松使用多个大型语言模型(LLM)。使用类似于OpenAI的接口,`aisuite4cn` 使得与最受欢迎的LLM互动并比较结果变得简单。它是Python客户端库的轻量级包装器,允许创造者在不改变代码的情况下无缝切换并测试来自不同LLM提供商的响应。我们将在不久的将来扩展它以覆盖更多的用例。
|
|
28
|
+
|
|
29
|
+
当前支持的提供商包括:
|
|
30
|
+
moonshot(月之暗面)、Doubao(火山引擎)、Qwen(阿里云千问大模型)。
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
## Integrated Open source project
|
|
34
|
+
Special thanks to all contributors
|
|
35
|
+
|
|
36
|
+
### aisuite
|
|
37
|
+
https://github.com/andrewyng/aisuite
|
|
38
|
+
|
|
39
|
+
### openai-python
|
|
40
|
+
https://github.com/openai/openai-python
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# aisuite4cn
|
|
2
|
+
|
|
3
|
+
简单、统一的接口,可连接多个生成式人工智能提供商。
|
|
4
|
+
|
|
5
|
+
`aisuite4cn` 针对于中国的各类大模型厂商提供通用的支持。学习了`aisuite`方案,并开发了该库。
|
|
6
|
+
|
|
7
|
+
`aisuite4cn` 使得开发者能够通过标准化的接口轻松使用多个大型语言模型(LLM)。使用类似于OpenAI的接口,`aisuite4cn` 使得与最受欢迎的LLM互动并比较结果变得简单。它是Python客户端库的轻量级包装器,允许创造者在不改变代码的情况下无缝切换并测试来自不同LLM提供商的响应。我们将在不久的将来扩展它以覆盖更多的用例。
|
|
8
|
+
|
|
9
|
+
当前支持的提供商包括:
|
|
10
|
+
moonshot(月之暗面)、Doubao(火山引擎)、Qwen(阿里云千问大模型)。
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## Integrated Open source project
|
|
14
|
+
Special thanks to all contributors
|
|
15
|
+
|
|
16
|
+
### aisuite
|
|
17
|
+
https://github.com/andrewyng/aisuite
|
|
18
|
+
|
|
19
|
+
### openai-python
|
|
20
|
+
https://github.com/openai/openai-python
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .client import Client
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
from .provider import ProviderFactory
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Client:
|
|
5
|
+
def __init__(self, provider_configs: dict = {}):
|
|
6
|
+
"""
|
|
7
|
+
Initialize the client with provider configurations.
|
|
8
|
+
Use the ProviderFactory to create provider instances.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
provider_configs (dict): A dictionary containing provider configurations.
|
|
12
|
+
Each key should be a provider string (e.g., "google" or "aws-bedrock"),
|
|
13
|
+
and the value should be a dictionary of configuration options for that provider.
|
|
14
|
+
For example:
|
|
15
|
+
{
|
|
16
|
+
"openai": {"api_key": "your_openai_api_key"},
|
|
17
|
+
"aws-bedrock": {
|
|
18
|
+
"aws_access_key": "your_aws_access_key",
|
|
19
|
+
"aws_secret_key": "your_aws_secret_key",
|
|
20
|
+
"aws_region": "us-west-2"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
"""
|
|
24
|
+
self.providers = {}
|
|
25
|
+
self.provider_configs = provider_configs
|
|
26
|
+
self._chat = None
|
|
27
|
+
self._initialize_providers()
|
|
28
|
+
|
|
29
|
+
def _initialize_providers(self):
|
|
30
|
+
"""Helper method to initialize or update providers."""
|
|
31
|
+
for provider_key, config in self.provider_configs.items():
|
|
32
|
+
provider_key = self._validate_provider_key(provider_key)
|
|
33
|
+
self.providers[provider_key] = ProviderFactory.create_provider(
|
|
34
|
+
provider_key, config
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
def _validate_provider_key(self, provider_key):
|
|
38
|
+
"""
|
|
39
|
+
Validate if the provider key corresponds to a supported provider.
|
|
40
|
+
"""
|
|
41
|
+
supported_providers = ProviderFactory.get_supported_providers()
|
|
42
|
+
|
|
43
|
+
if provider_key not in supported_providers:
|
|
44
|
+
raise ValueError(
|
|
45
|
+
f"Invalid provider key '{provider_key}'. Supported providers: {supported_providers}. "
|
|
46
|
+
"Make sure the model string is formatted correctly as 'provider:model'."
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
return provider_key
|
|
50
|
+
|
|
51
|
+
def configure(self, provider_configs: dict = None):
|
|
52
|
+
"""
|
|
53
|
+
Configure the client with provider configurations.
|
|
54
|
+
"""
|
|
55
|
+
if provider_configs is None:
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
self.provider_configs.update(provider_configs)
|
|
59
|
+
self._initialize_providers() # NOTE: This will override existing provider instances.
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def chat(self):
|
|
63
|
+
"""Return the chat API interface."""
|
|
64
|
+
if not self._chat:
|
|
65
|
+
self._chat = Chat(self)
|
|
66
|
+
return self._chat
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class Chat:
|
|
70
|
+
def __init__(self, client: "Client"):
|
|
71
|
+
self.client = client
|
|
72
|
+
self._completions = Completions(self.client)
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def completions(self):
|
|
76
|
+
"""Return the completions interface."""
|
|
77
|
+
return self._completions
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class Completions:
|
|
81
|
+
def __init__(self, client: "Client"):
|
|
82
|
+
self.client = client
|
|
83
|
+
|
|
84
|
+
def create(self, model: str, messages: list, **kwargs):
|
|
85
|
+
"""
|
|
86
|
+
Create chat completion based on the model, messages, and any extra arguments.
|
|
87
|
+
"""
|
|
88
|
+
# Check that correct format is used
|
|
89
|
+
if ":" not in model:
|
|
90
|
+
raise ValueError(
|
|
91
|
+
f"Invalid model format. Expected 'provider:model', got '{model}'"
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# Extract the provider key from the model identifier, e.g., "google:gemini-xx"
|
|
95
|
+
provider_key, model_name = model.split(":", 1)
|
|
96
|
+
|
|
97
|
+
# Validate if the provider is supported
|
|
98
|
+
supported_providers = ProviderFactory.get_supported_providers()
|
|
99
|
+
if provider_key not in supported_providers:
|
|
100
|
+
raise ValueError(
|
|
101
|
+
f"Invalid provider key '{provider_key}'. Supported providers: {supported_providers}. "
|
|
102
|
+
"Make sure the model string is formatted correctly as 'provider:model'."
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Initialize provider if not already initialized
|
|
106
|
+
if provider_key not in self.client.providers:
|
|
107
|
+
config = self.client.provider_configs.get(provider_key, {})
|
|
108
|
+
self.client.providers[provider_key] = ProviderFactory.create_provider(
|
|
109
|
+
provider_key, config
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
provider = self.client.providers.get(provider_key)
|
|
113
|
+
if not provider:
|
|
114
|
+
raise ValueError(f"Could not load provider for '{provider_key}'.")
|
|
115
|
+
|
|
116
|
+
# Delegate the chat completion to the correct provider's implementation
|
|
117
|
+
return provider.chat_completions_create(model_name, messages, **kwargs)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""The shared interface for model providers."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ProviderInterface:
|
|
5
|
+
"""Defines the expected behavior for provider-specific interfaces."""
|
|
6
|
+
|
|
7
|
+
def chat_completion_create(self, messages=None, model=None, temperature=0) -> None:
|
|
8
|
+
"""Create a chat completion using the specified messages, model, and temperature.
|
|
9
|
+
|
|
10
|
+
This method must be implemented by subclasses to perform completions.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
----
|
|
14
|
+
messages (list): The chat history.
|
|
15
|
+
model (str): The identifier of the model to be used in the completion.
|
|
16
|
+
temperature (float): The temperature to use in the completion.
|
|
17
|
+
|
|
18
|
+
Raises:
|
|
19
|
+
------
|
|
20
|
+
NotImplementedError: If this method has not been implemented by a subclass.
|
|
21
|
+
|
|
22
|
+
"""
|
|
23
|
+
raise NotImplementedError(
|
|
24
|
+
"Provider Interface has not implemented chat_completion_create()"
|
|
25
|
+
)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import importlib
|
|
4
|
+
import os
|
|
5
|
+
import functools
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class LLMError(Exception):
|
|
9
|
+
"""Custom exception for LLM errors."""
|
|
10
|
+
|
|
11
|
+
def __init__(self, message):
|
|
12
|
+
super().__init__(message)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Provider(ABC):
|
|
16
|
+
@abstractmethod
|
|
17
|
+
def chat_completions_create(self, model, messages):
|
|
18
|
+
"""Abstract method for chat completion calls, to be implemented by each provider."""
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ProviderFactory:
|
|
23
|
+
"""Factory to dynamically load provider instances based on naming conventions."""
|
|
24
|
+
|
|
25
|
+
PROVIDERS_DIR = Path(__file__).parent / "providers"
|
|
26
|
+
|
|
27
|
+
@classmethod
|
|
28
|
+
def create_provider(cls, provider_key, config):
|
|
29
|
+
"""Dynamically load and create an instance of a provider based on the naming convention."""
|
|
30
|
+
# Convert provider_key to the expected module and class names
|
|
31
|
+
provider_class_name = f"{provider_key.capitalize()}Provider"
|
|
32
|
+
provider_module_name = f"{provider_key}_provider"
|
|
33
|
+
|
|
34
|
+
module_path = f"aisuite.providers.{provider_module_name}"
|
|
35
|
+
|
|
36
|
+
# Lazily load the module
|
|
37
|
+
try:
|
|
38
|
+
module = importlib.import_module(module_path)
|
|
39
|
+
except ImportError as e:
|
|
40
|
+
raise ImportError(
|
|
41
|
+
f"Could not import module {module_path}: {str(e)}. Please ensure the provider is supported by doing ProviderFactory.get_supported_providers()"
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# Instantiate the provider class
|
|
45
|
+
provider_class = getattr(module, provider_class_name)
|
|
46
|
+
return provider_class(**config)
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
@functools.cache
|
|
50
|
+
def get_supported_providers(cls):
|
|
51
|
+
"""List all supported provider names based on files present in the providers directory."""
|
|
52
|
+
provider_files = Path(cls.PROVIDERS_DIR).glob("*_provider.py")
|
|
53
|
+
return {file.stem.replace("_provider", "") for file in provider_files}
|
|
File without changes
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import openai
|
|
2
|
+
import os
|
|
3
|
+
from aisuite4cn.provider import Provider, LLMError
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class MoonshotProvider(Provider):
|
|
7
|
+
"""
|
|
8
|
+
月之暗面提供者
|
|
9
|
+
"""
|
|
10
|
+
def __init__(self, **config):
|
|
11
|
+
"""
|
|
12
|
+
Initialize the Moonshot provider with the given configuration.
|
|
13
|
+
Pass the entire configuration dictionary to the Moonshot client constructor.
|
|
14
|
+
"""
|
|
15
|
+
# Ensure API key is provided either in config or via environment variable
|
|
16
|
+
self.api_key = config.get("api_key") or os.getenv("MOONSHOT_API_KEY")
|
|
17
|
+
if not self.api_key:
|
|
18
|
+
raise ValueError(
|
|
19
|
+
"Moonshot API key is missing. Please provide it in the config or set the MOONSHOT_API_KEY environment variable."
|
|
20
|
+
)
|
|
21
|
+
kvargs = dict(config)
|
|
22
|
+
kvargs.pop("api_key")
|
|
23
|
+
# Pass the entire config to the Moonshot client constructor
|
|
24
|
+
self.client = openai.OpenAI(
|
|
25
|
+
api_key = self.api_key,
|
|
26
|
+
base_url = "https://api.moonshot.cn/v1",
|
|
27
|
+
**kvargs)
|
|
28
|
+
|
|
29
|
+
def chat_completions_create(self, model, messages, **kwargs):
|
|
30
|
+
# Any exception raised by Moonshot will be returned to the caller.
|
|
31
|
+
# Maybe we should catch them and raise a custom LLMError.
|
|
32
|
+
return self.client.chat.completions.create(
|
|
33
|
+
model=model,
|
|
34
|
+
messages=messages,
|
|
35
|
+
**kwargs # Pass any additional arguments to the Moonshot API
|
|
36
|
+
)
|
|
37
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import openai
|
|
2
|
+
import os
|
|
3
|
+
from aisuite4cn.provider import Provider, LLMError
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class QwenProvider(Provider):
|
|
7
|
+
"""
|
|
8
|
+
阿里云大模型服务平台针对于千问大模型的提供者,使用了千问大模型兼容OpenAI的接口
|
|
9
|
+
"""
|
|
10
|
+
def __init__(self, **config):
|
|
11
|
+
"""
|
|
12
|
+
Initialize the Qwen shot provider with the given configuration.
|
|
13
|
+
Pass the entire configuration dictionary to the Qwen client constructor.
|
|
14
|
+
"""
|
|
15
|
+
# Ensure API key is provided either in config or via environment variable
|
|
16
|
+
self.api_key = config.get("api_key") or os.getenv("DASHSCOPE_API_KEY")
|
|
17
|
+
if not self.api_key:
|
|
18
|
+
raise ValueError(
|
|
19
|
+
"Dashscope API key is missing. Please provide it in the config or set the DASHSCOPE_API_KEY environment variable."
|
|
20
|
+
)
|
|
21
|
+
kvargs = dict(config)
|
|
22
|
+
kvargs.pop("api_key")
|
|
23
|
+
# Pass the entire config to the Qwen client constructor
|
|
24
|
+
self.client = openai.OpenAI(
|
|
25
|
+
api_key=self.api_key,
|
|
26
|
+
base_url='https://dashscope.aliyuncs.com/compatible-mode/v1',
|
|
27
|
+
**kvargs)
|
|
28
|
+
|
|
29
|
+
def chat_completions_create(self, model, messages, **kwargs):
|
|
30
|
+
# Any exception raised by Qwen will be returned to the caller.
|
|
31
|
+
# Maybe we should catch them and raise a custom LLMError.
|
|
32
|
+
return self.client.chat.completions.create(
|
|
33
|
+
model=model,
|
|
34
|
+
messages=messages,
|
|
35
|
+
**kwargs # Pass any additional arguments to the Qwen API
|
|
36
|
+
)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from argparse import ArgumentError
|
|
2
|
+
|
|
3
|
+
import openai
|
|
4
|
+
import os
|
|
5
|
+
from aisuite4cn.provider import Provider, LLMError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class VolcengineProvider(Provider):
|
|
9
|
+
"""
|
|
10
|
+
火山引擎方舟大模型服务平台提供者
|
|
11
|
+
"""
|
|
12
|
+
def __init__(self, **config):
|
|
13
|
+
"""
|
|
14
|
+
Initialize the Volcengine provider with the given configuration.
|
|
15
|
+
Pass the entire configuration dictionary to the Volcengine client constructor.
|
|
16
|
+
"""
|
|
17
|
+
# Ensure API key is provided either in config or via environment variable
|
|
18
|
+
self.api_key = config.get("api_key") or os.getenv("ARK_API_KEY")
|
|
19
|
+
|
|
20
|
+
if not self.api_key:
|
|
21
|
+
raise ValueError(
|
|
22
|
+
"Ark API key is missing. Please provide it in the config or set the OPENAI_API_KEY environment variable."
|
|
23
|
+
)
|
|
24
|
+
self.config = config
|
|
25
|
+
|
|
26
|
+
kvargs = dict(config)
|
|
27
|
+
kvargs.pop("api_key")
|
|
28
|
+
# Pass the entire config to the Ark client constructor
|
|
29
|
+
|
|
30
|
+
self.client = openai.OpenAI(
|
|
31
|
+
api_key=self.api_key,
|
|
32
|
+
base_url="https://ark.cn-beijing.volces.com/api/v3",
|
|
33
|
+
**kvargs)
|
|
34
|
+
|
|
35
|
+
def chat_completions_create(self, model, messages, **kwargs):
|
|
36
|
+
|
|
37
|
+
# Any exception raised by Ark will be returned to the caller.
|
|
38
|
+
# Maybe we should catch them and raise a custom LLMError.
|
|
39
|
+
|
|
40
|
+
if not model.startswith("ep-"):
|
|
41
|
+
raise ValueError("The model name must be the endpoint ID of the model.")
|
|
42
|
+
return self.client.chat.completions.create(
|
|
43
|
+
model=model,
|
|
44
|
+
messages=messages,
|
|
45
|
+
**kwargs # Pass any additional arguments to the Ark API
|
|
46
|
+
)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "aisuite4cn"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = ""
|
|
5
|
+
authors = ["胡伟 <3314672@qq.com>"]
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
|
|
8
|
+
[tool.poetry.dependencies]
|
|
9
|
+
python = "^3.10"
|
|
10
|
+
pydantic = "^2.10.3"
|
|
11
|
+
openai = { version = "^1.35.8", optional = true }
|
|
12
|
+
|
|
13
|
+
# Optional dependencies for different providers
|
|
14
|
+
httpx = "~0.27.0"
|
|
15
|
+
|
|
16
|
+
[tool.poetry.extras]
|
|
17
|
+
moonshot = ["openai"]
|
|
18
|
+
volcengine = ["openai"]
|
|
19
|
+
qwen = ["openai"]
|
|
20
|
+
|
|
21
|
+
[tool.poetry.group.dev.dependencies]
|
|
22
|
+
openai = "^1.35.8"
|
|
23
|
+
|
|
24
|
+
[tool.poetry.group.test]
|
|
25
|
+
optional = true
|
|
26
|
+
|
|
27
|
+
[tool.poetry.group.test.dependencies]
|
|
28
|
+
pytest = "^8.2.2"
|
|
29
|
+
pytest-cov = "^6.0.0"
|
|
30
|
+
|
|
31
|
+
[build-system]
|
|
32
|
+
requires = ["poetry-core"]
|
|
33
|
+
build-backend = "poetry.core.masonry.api"
|