vectorvein 0.1.0__py3-none-any.whl
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.
- vectorvein/__init__.py +0 -0
- vectorvein/chat_clients/__init__.py +110 -0
- vectorvein/chat_clients/anthropic_client.py +450 -0
- vectorvein/chat_clients/base_client.py +91 -0
- vectorvein/chat_clients/deepseek_client.py +15 -0
- vectorvein/chat_clients/gemini_client.py +317 -0
- vectorvein/chat_clients/groq_client.py +15 -0
- vectorvein/chat_clients/local_client.py +14 -0
- vectorvein/chat_clients/minimax_client.py +315 -0
- vectorvein/chat_clients/mistral_client.py +15 -0
- vectorvein/chat_clients/moonshot_client.py +15 -0
- vectorvein/chat_clients/openai_client.py +15 -0
- vectorvein/chat_clients/openai_compatible_client.py +291 -0
- vectorvein/chat_clients/qwen_client.py +15 -0
- vectorvein/chat_clients/utils.py +635 -0
- vectorvein/chat_clients/yi_client.py +15 -0
- vectorvein/chat_clients/zhipuai_client.py +15 -0
- vectorvein/settings/__init__.py +71 -0
- vectorvein/types/defaults.py +396 -0
- vectorvein/types/enums.py +83 -0
- vectorvein/types/llm_parameters.py +69 -0
- vectorvein/utilities/media_processing.py +70 -0
- vectorvein-0.1.0.dist-info/METADATA +16 -0
- vectorvein-0.1.0.dist-info/RECORD +25 -0
- vectorvein-0.1.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
# @Author: Bi Ying
|
2
|
+
# @Date: 2024-07-26 14:48:55
|
3
|
+
from ..types.enums import BackendType
|
4
|
+
from ..types.defaults import OPENAI_DEFAULT_MODEL
|
5
|
+
from .openai_compatible_client import OpenAICompatibleChatClient, AsyncOpenAICompatibleChatClient
|
6
|
+
|
7
|
+
|
8
|
+
class OpenAIChatClient(OpenAICompatibleChatClient):
|
9
|
+
DEFAULT_MODEL = OPENAI_DEFAULT_MODEL
|
10
|
+
BACKEND_NAME = BackendType.OpenAI
|
11
|
+
|
12
|
+
|
13
|
+
class AsyncOpenAIChatClient(AsyncOpenAICompatibleChatClient):
|
14
|
+
DEFAULT_MODEL = OPENAI_DEFAULT_MODEL
|
15
|
+
BACKEND_NAME = BackendType.OpenAI
|
@@ -0,0 +1,291 @@
|
|
1
|
+
# @Author: Bi Ying
|
2
|
+
# @Date: 2024-07-26 14:48:55
|
3
|
+
import json
|
4
|
+
import random
|
5
|
+
from typing import Union, AsyncGenerator
|
6
|
+
|
7
|
+
from openai._types import NotGiven, NOT_GIVEN
|
8
|
+
from openai._streaming import Stream, AsyncStream
|
9
|
+
from openai.types.chat import ChatCompletion, ChatCompletionChunk
|
10
|
+
from openai import OpenAI, AsyncOpenAI, AzureOpenAI, AsyncAzureOpenAI
|
11
|
+
|
12
|
+
from .base_client import BaseChatClient, BaseAsyncChatClient
|
13
|
+
from .utils import (
|
14
|
+
tool_use_re,
|
15
|
+
cutoff_messages,
|
16
|
+
extract_tool_calls,
|
17
|
+
generate_tool_use_system_prompt,
|
18
|
+
)
|
19
|
+
from ..settings import settings
|
20
|
+
from ..types import defaults as defs
|
21
|
+
from ..types.enums import ContextLengthControlType, BackendType
|
22
|
+
|
23
|
+
|
24
|
+
class OpenAICompatibleChatClient(BaseChatClient):
|
25
|
+
DEFAULT_MODEL: str = ""
|
26
|
+
BACKEND_NAME: BackendType
|
27
|
+
|
28
|
+
def __init__(
|
29
|
+
self,
|
30
|
+
model: str = "",
|
31
|
+
stream: bool = True,
|
32
|
+
temperature: float = 0.7,
|
33
|
+
context_length_control: ContextLengthControlType = defs.CONTEXT_LENGTH_CONTROL,
|
34
|
+
random_endpoint: bool = True,
|
35
|
+
endpoint_id: str = "",
|
36
|
+
**kwargs,
|
37
|
+
):
|
38
|
+
super().__init__(
|
39
|
+
model,
|
40
|
+
stream,
|
41
|
+
temperature,
|
42
|
+
context_length_control,
|
43
|
+
random_endpoint,
|
44
|
+
endpoint_id,
|
45
|
+
**kwargs,
|
46
|
+
)
|
47
|
+
|
48
|
+
def create_completion(
|
49
|
+
self,
|
50
|
+
messages: list = list,
|
51
|
+
model: str | None = None,
|
52
|
+
stream: bool | None = None,
|
53
|
+
temperature: float | None = None,
|
54
|
+
max_tokens: int = 2000,
|
55
|
+
tools: list | NotGiven = NOT_GIVEN,
|
56
|
+
tool_choice: str | NotGiven = NOT_GIVEN,
|
57
|
+
):
|
58
|
+
if model is not None:
|
59
|
+
self.model = model
|
60
|
+
if stream is not None:
|
61
|
+
self.stream = stream
|
62
|
+
if temperature is not None:
|
63
|
+
self.temperature = temperature
|
64
|
+
|
65
|
+
self.model_setting = self.backend_settings.models[self.model]
|
66
|
+
|
67
|
+
if self.random_endpoint:
|
68
|
+
self.random_endpoint = True
|
69
|
+
self.endpoint_id = random.choice(self.backend_settings.models[self.model].endpoints)
|
70
|
+
self.endpoint = settings.get_endpoint(self.endpoint_id)
|
71
|
+
|
72
|
+
if self.endpoint.is_azure:
|
73
|
+
self._client = AzureOpenAI(
|
74
|
+
azure_endpoint=self.endpoint.api_base,
|
75
|
+
api_key=self.endpoint.api_key,
|
76
|
+
api_version="2024-05-01-preview",
|
77
|
+
)
|
78
|
+
else:
|
79
|
+
self._client = OpenAI(
|
80
|
+
api_key=self.endpoint.api_key,
|
81
|
+
base_url=self.endpoint.api_base,
|
82
|
+
)
|
83
|
+
|
84
|
+
if self.context_length_control == ContextLengthControlType.Latest:
|
85
|
+
messages = cutoff_messages(
|
86
|
+
messages,
|
87
|
+
max_count=self.model_setting.context_length,
|
88
|
+
backend=self.BACKEND_NAME,
|
89
|
+
model=self.model_setting.id,
|
90
|
+
)
|
91
|
+
|
92
|
+
if tools:
|
93
|
+
if self.model_setting.function_call_available:
|
94
|
+
tools_params = dict(tools=tools, tool_choice=tool_choice)
|
95
|
+
else:
|
96
|
+
tools_str = json.dumps(tools, ensure_ascii=False, indent=None)
|
97
|
+
additional_system_prompt = generate_tool_use_system_prompt(tools=tools_str)
|
98
|
+
if messages and messages[0].get("role") == "system":
|
99
|
+
messages[0]["content"] += "\n\n" + additional_system_prompt
|
100
|
+
else:
|
101
|
+
messages.insert(0, {"role": "system", "content": additional_system_prompt})
|
102
|
+
tools_params = {}
|
103
|
+
else:
|
104
|
+
tools_params = {}
|
105
|
+
|
106
|
+
response: ChatCompletion | Stream[ChatCompletionChunk] = self._client.chat.completions.create(
|
107
|
+
model=self.model_setting.id,
|
108
|
+
messages=messages,
|
109
|
+
stream=self.stream,
|
110
|
+
temperature=self.temperature,
|
111
|
+
max_tokens=max_tokens,
|
112
|
+
**tools_params,
|
113
|
+
)
|
114
|
+
|
115
|
+
if self.stream:
|
116
|
+
|
117
|
+
def generator():
|
118
|
+
full_content = ""
|
119
|
+
result = {}
|
120
|
+
for chunk in response:
|
121
|
+
if len(chunk.choices) == 0:
|
122
|
+
continue
|
123
|
+
if self.model_setting.function_call_available:
|
124
|
+
yield chunk.choices[0].delta.model_dump()
|
125
|
+
else:
|
126
|
+
message = chunk.choices[0].delta.model_dump()
|
127
|
+
full_content += message["content"] if message["content"] else ""
|
128
|
+
if tools:
|
129
|
+
tool_call_data = extract_tool_calls(full_content)
|
130
|
+
if tool_call_data:
|
131
|
+
message["tool_calls"] = tool_call_data["tool_calls"]
|
132
|
+
if full_content in ("<", "<|", "<|▶", "<|▶|") or full_content.startswith("<|▶|>"):
|
133
|
+
message["content"] = ""
|
134
|
+
result = message
|
135
|
+
continue
|
136
|
+
yield message
|
137
|
+
if result:
|
138
|
+
yield result
|
139
|
+
|
140
|
+
return generator()
|
141
|
+
else:
|
142
|
+
result = {
|
143
|
+
"content": response.choices[0].message.content,
|
144
|
+
"usage": response.usage.model_dump(),
|
145
|
+
}
|
146
|
+
if tools:
|
147
|
+
if self.model_setting.function_call_available and response.choices[0].message.tool_calls:
|
148
|
+
result["tool_calls"] = [
|
149
|
+
tool_call.model_dump() for tool_call in response.choices[0].message.tool_calls
|
150
|
+
]
|
151
|
+
else:
|
152
|
+
tool_call_data = extract_tool_calls(result["content"])
|
153
|
+
if tool_call_data:
|
154
|
+
result["tool_calls"] = tool_call_data["tool_calls"]
|
155
|
+
result["content"] = tool_use_re.sub("", result["content"])
|
156
|
+
return result
|
157
|
+
|
158
|
+
|
159
|
+
class AsyncOpenAICompatibleChatClient(BaseAsyncChatClient):
|
160
|
+
DEFAULT_MODEL: str = ""
|
161
|
+
BACKEND_NAME: BackendType
|
162
|
+
|
163
|
+
def __init__(
|
164
|
+
self,
|
165
|
+
model: str = "",
|
166
|
+
stream: bool = True,
|
167
|
+
temperature: float = 0.7,
|
168
|
+
context_length_control: ContextLengthControlType = defs.CONTEXT_LENGTH_CONTROL,
|
169
|
+
random_endpoint: bool = True,
|
170
|
+
endpoint_id: str = "",
|
171
|
+
**kwargs,
|
172
|
+
):
|
173
|
+
super().__init__(
|
174
|
+
model,
|
175
|
+
stream,
|
176
|
+
temperature,
|
177
|
+
context_length_control,
|
178
|
+
random_endpoint,
|
179
|
+
endpoint_id,
|
180
|
+
**kwargs,
|
181
|
+
)
|
182
|
+
|
183
|
+
async def create_completion(
|
184
|
+
self,
|
185
|
+
messages: list = list,
|
186
|
+
model: str | None = None,
|
187
|
+
stream: bool | None = None,
|
188
|
+
temperature: float | None = None,
|
189
|
+
max_tokens: int = 2000,
|
190
|
+
tools: list | NotGiven = NOT_GIVEN,
|
191
|
+
tool_choice: str | NotGiven = NOT_GIVEN,
|
192
|
+
) -> Union[AsyncGenerator[str, None], str]:
|
193
|
+
if model is not None:
|
194
|
+
self.model = model
|
195
|
+
if stream is not None:
|
196
|
+
self.stream = stream
|
197
|
+
if temperature is not None:
|
198
|
+
self.temperature = temperature
|
199
|
+
|
200
|
+
self.model_setting = self.backend_settings.models[self.model]
|
201
|
+
|
202
|
+
if self.random_endpoint:
|
203
|
+
self.random_endpoint = True
|
204
|
+
self.endpoint_id = random.choice(self.backend_settings.models[self.model].endpoints)
|
205
|
+
self.endpoint = settings.get_endpoint(self.endpoint_id)
|
206
|
+
|
207
|
+
if self.endpoint.is_azure:
|
208
|
+
self._client = AsyncAzureOpenAI(
|
209
|
+
azure_endpoint=self.endpoint.api_base,
|
210
|
+
api_key=self.endpoint.api_key,
|
211
|
+
api_version="2024-05-01-preview",
|
212
|
+
)
|
213
|
+
else:
|
214
|
+
self._client = AsyncOpenAI(
|
215
|
+
api_key=self.endpoint.api_key,
|
216
|
+
base_url=self.endpoint.api_base,
|
217
|
+
)
|
218
|
+
|
219
|
+
if self.context_length_control == ContextLengthControlType.Latest:
|
220
|
+
messages = cutoff_messages(
|
221
|
+
messages,
|
222
|
+
max_count=self.model_setting.context_length,
|
223
|
+
backend=self.BACKEND_NAME,
|
224
|
+
model=self.model_setting.id,
|
225
|
+
)
|
226
|
+
|
227
|
+
if tools:
|
228
|
+
if self.model_setting.function_call_available:
|
229
|
+
tools_params = dict(tools=tools, tool_choice=tool_choice)
|
230
|
+
else:
|
231
|
+
tools_str = json.dumps(tools, ensure_ascii=False, indent=None)
|
232
|
+
additional_system_prompt = generate_tool_use_system_prompt(tools=tools_str)
|
233
|
+
if messages and messages[0].get("role") == "system":
|
234
|
+
messages[0]["content"] += "\n\n" + additional_system_prompt
|
235
|
+
else:
|
236
|
+
messages.insert(0, {"role": "system", "content": additional_system_prompt})
|
237
|
+
tools_params = {}
|
238
|
+
else:
|
239
|
+
tools_params = {}
|
240
|
+
|
241
|
+
response: ChatCompletion | AsyncStream[ChatCompletionChunk] = await self._client.chat.completions.create(
|
242
|
+
model=self.model_setting.id,
|
243
|
+
messages=messages,
|
244
|
+
stream=self.stream,
|
245
|
+
temperature=self.temperature,
|
246
|
+
max_tokens=max_tokens,
|
247
|
+
**tools_params,
|
248
|
+
)
|
249
|
+
|
250
|
+
if self.stream:
|
251
|
+
|
252
|
+
async def generator():
|
253
|
+
full_content = ""
|
254
|
+
result = {}
|
255
|
+
async for chunk in response:
|
256
|
+
if len(chunk.choices) == 0:
|
257
|
+
continue
|
258
|
+
if self.model_setting.function_call_available:
|
259
|
+
yield chunk.choices[0].delta.model_dump()
|
260
|
+
else:
|
261
|
+
message = chunk.choices[0].delta.model_dump()
|
262
|
+
full_content += message["content"] if message["content"] else ""
|
263
|
+
if tools:
|
264
|
+
tool_call_data = extract_tool_calls(full_content)
|
265
|
+
if tool_call_data:
|
266
|
+
message["tool_calls"] = tool_call_data["tool_calls"]
|
267
|
+
if full_content in ("<", "<|", "<|▶", "<|▶|") or full_content.startswith("<|▶|>"):
|
268
|
+
message["content"] = ""
|
269
|
+
result = message
|
270
|
+
continue
|
271
|
+
yield message
|
272
|
+
if result:
|
273
|
+
yield result
|
274
|
+
|
275
|
+
return generator()
|
276
|
+
else:
|
277
|
+
result = {
|
278
|
+
"content": response.choices[0].message.content,
|
279
|
+
"usage": response.usage.model_dump(),
|
280
|
+
}
|
281
|
+
if tools:
|
282
|
+
if self.model_setting.function_call_available and response.choices[0].message.tool_calls:
|
283
|
+
result["tool_calls"] = [
|
284
|
+
tool_call.model_dump() for tool_call in response.choices[0].message.tool_calls
|
285
|
+
]
|
286
|
+
else:
|
287
|
+
tool_call_data = extract_tool_calls(result["content"])
|
288
|
+
if tool_call_data:
|
289
|
+
result["tool_calls"] = tool_call_data["tool_calls"]
|
290
|
+
result["content"] = tool_use_re.sub("", result["content"])
|
291
|
+
return result
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# @Author: Bi Ying
|
2
|
+
# @Date: 2024-07-26 14:48:55
|
3
|
+
from ..types.enums import BackendType
|
4
|
+
from ..types.defaults import QWEN_DEFAULT_MODEL
|
5
|
+
from .openai_compatible_client import OpenAICompatibleChatClient, AsyncOpenAICompatibleChatClient
|
6
|
+
|
7
|
+
|
8
|
+
class QwenChatClient(OpenAICompatibleChatClient):
|
9
|
+
DEFAULT_MODEL = QWEN_DEFAULT_MODEL
|
10
|
+
BACKEND_NAME = BackendType.Qwen
|
11
|
+
|
12
|
+
|
13
|
+
class AsyncQwenChatClient(AsyncOpenAICompatibleChatClient):
|
14
|
+
DEFAULT_MODEL = QWEN_DEFAULT_MODEL
|
15
|
+
BACKEND_NAME = BackendType.Qwen
|