vectorvein 0.1.14__tar.gz → 0.1.16__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.
Files changed (38) hide show
  1. {vectorvein-0.1.14 → vectorvein-0.1.16}/PKG-INFO +1 -1
  2. {vectorvein-0.1.14 → vectorvein-0.1.16}/pyproject.toml +6 -1
  3. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/chat_clients/__init__.py +2 -1
  4. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/chat_clients/anthropic_client.py +3 -5
  5. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/chat_clients/openai_compatible_client.py +3 -5
  6. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/chat_clients/utils.py +41 -1
  7. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/types/defaults.py +11 -0
  8. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/types/llm_parameters.py +1 -0
  9. vectorvein-0.1.14/tests/__init__.py +0 -0
  10. vectorvein-0.1.14/tests/cat.png +0 -0
  11. vectorvein-0.1.14/tests/sample_settings.py +0 -614
  12. vectorvein-0.1.14/tests/test_chat_prefix.py +0 -23
  13. vectorvein-0.1.14/tests/test_create_chat_client.py +0 -234
  14. vectorvein-0.1.14/tests/test_format_messages.py +0 -41
  15. vectorvein-0.1.14/tests/test_http_client.py +0 -24
  16. vectorvein-0.1.14/tests/test_image_input_chat_client.py +0 -45
  17. vectorvein-0.1.14/tests/test_stop.py +0 -25
  18. vectorvein-0.1.14/tests/test_tokens_count.py +0 -46
  19. vectorvein-0.1.14/tests/test_tool_use_multi_turns.py +0 -159
  20. {vectorvein-0.1.14 → vectorvein-0.1.16}/README.md +0 -0
  21. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/__init__.py +0 -0
  22. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/chat_clients/baichuan_client.py +0 -0
  23. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/chat_clients/base_client.py +0 -0
  24. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/chat_clients/deepseek_client.py +0 -0
  25. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/chat_clients/gemini_client.py +0 -0
  26. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/chat_clients/groq_client.py +0 -0
  27. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/chat_clients/local_client.py +0 -0
  28. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/chat_clients/minimax_client.py +0 -0
  29. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/chat_clients/mistral_client.py +0 -0
  30. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/chat_clients/moonshot_client.py +0 -0
  31. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/chat_clients/openai_client.py +0 -0
  32. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/chat_clients/qwen_client.py +0 -0
  33. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/chat_clients/yi_client.py +0 -0
  34. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/chat_clients/zhipuai_client.py +0 -0
  35. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/settings/__init__.py +0 -0
  36. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/types/enums.py +0 -0
  37. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/utilities/media_processing.py +0 -0
  38. {vectorvein-0.1.14 → vectorvein-0.1.16}/src/vectorvein/utilities/retry.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vectorvein
3
- Version: 0.1.14
3
+ Version: 0.1.16
4
4
  Summary: Default template for PDM package
5
5
  Author-Email: Anderson <andersonby@163.com>
6
6
  License: MIT
@@ -16,7 +16,7 @@ description = "Default template for PDM package"
16
16
  name = "vectorvein"
17
17
  readme = "README.md"
18
18
  requires-python = ">=3.10"
19
- version = "0.1.14"
19
+ version = "0.1.16"
20
20
 
21
21
  [project.license]
22
22
  text = "MIT"
@@ -29,3 +29,8 @@ requires = [
29
29
 
30
30
  [tool.pdm]
31
31
  distribution = true
32
+
33
+ [tool.pdm.build]
34
+ excludes = [
35
+ "tests",
36
+ ]
@@ -20,7 +20,7 @@ from .deepseek_client import DeepSeekChatClient, AsyncDeepSeekChatClient
20
20
  from ..types import defaults as defs
21
21
  from ..types.enums import BackendType, ContextLengthControlType
22
22
  from .anthropic_client import AnthropicChatClient, AsyncAnthropicChatClient
23
- from .utils import format_messages, get_token_counts, ToolCallContentProcessor
23
+ from .utils import format_messages, get_token_counts, get_message_token_counts, ToolCallContentProcessor
24
24
 
25
25
 
26
26
  BackendMap = {
@@ -125,5 +125,6 @@ __all__ = [
125
125
  "get_token_counts",
126
126
  "create_chat_client",
127
127
  "create_async_chat_client",
128
+ "get_message_token_counts",
128
129
  "ToolCallContentProcessor",
129
130
  ]
@@ -21,7 +21,7 @@ from google.auth import _helpers
21
21
 
22
22
  from ..settings import settings
23
23
  from ..types import defaults as defs
24
- from .utils import cutoff_messages, get_token_counts
24
+ from .utils import cutoff_messages, get_message_token_counts
25
25
  from .base_client import BaseChatClient, BaseAsyncChatClient
26
26
  from ..types.enums import ContextLengthControlType, BackendType
27
27
  from ..types.llm_parameters import ChatCompletionMessage, ChatCompletionDeltaMessage
@@ -199,12 +199,11 @@ class AnthropicChatClient(BaseChatClient):
199
199
 
200
200
  if max_tokens is None:
201
201
  max_output_tokens = self.model_setting.max_output_tokens
202
+ token_counts = get_message_token_counts(messages=messages, tools=tools_params, model=self.model_setting.id)
202
203
  if max_output_tokens is not None:
203
- token_counts = get_token_counts({"messages": messages, "tools_params": tools_params})
204
204
  max_tokens = self.model_setting.context_length - token_counts
205
205
  max_tokens = min(max(max_tokens, 1), max_output_tokens)
206
206
  else:
207
- token_counts = get_token_counts({"messages": messages, "tools_params": tools_params})
208
207
  max_tokens = self.model_setting.context_length - token_counts
209
208
 
210
209
  response = self._client.messages.create(
@@ -405,12 +404,11 @@ class AsyncAnthropicChatClient(BaseAsyncChatClient):
405
404
 
406
405
  if max_tokens is None:
407
406
  max_output_tokens = self.model_setting.max_output_tokens
407
+ token_counts = get_message_token_counts(messages=messages, tools=tools_params, model=self.model_setting.id)
408
408
  if max_output_tokens is not None:
409
- token_counts = get_token_counts({"messages": messages, "tools_params": tools_params})
410
409
  max_tokens = self.model_setting.context_length - token_counts
411
410
  max_tokens = min(max(max_tokens, 1), max_output_tokens)
412
411
  else:
413
- token_counts = get_token_counts({"messages": messages, "tools_params": tools_params})
414
412
  max_tokens = self.model_setting.context_length - token_counts
415
413
 
416
414
  response = await self._client.messages.create(
@@ -12,7 +12,7 @@ from openai import OpenAI, AsyncOpenAI, AzureOpenAI, AsyncAzureOpenAI
12
12
  from .base_client import BaseChatClient, BaseAsyncChatClient
13
13
  from .utils import (
14
14
  cutoff_messages,
15
- get_token_counts,
15
+ get_message_token_counts,
16
16
  ToolCallContentProcessor,
17
17
  generate_tool_use_system_prompt,
18
18
  )
@@ -111,12 +111,11 @@ class OpenAICompatibleChatClient(BaseChatClient):
111
111
 
112
112
  if max_tokens is None:
113
113
  max_output_tokens = self.model_setting.max_output_tokens
114
+ token_counts = get_message_token_counts(messages=messages, tools=tools_params, model=self.model_setting.id)
114
115
  if max_output_tokens is not None:
115
- token_counts = get_token_counts({"messages": messages, "tools_params": tools_params})
116
116
  max_tokens = self.model_setting.context_length - token_counts
117
117
  max_tokens = min(max(max_tokens, 1), max_output_tokens)
118
118
  else:
119
- token_counts = get_token_counts({"messages": messages, "tools_params": tools_params})
120
119
  max_tokens = self.model_setting.context_length - token_counts
121
120
 
122
121
  response: ChatCompletion | Stream[ChatCompletionChunk] = self._client.chat.completions.create(
@@ -270,12 +269,11 @@ class AsyncOpenAICompatibleChatClient(BaseAsyncChatClient):
270
269
 
271
270
  if max_tokens is None:
272
271
  max_output_tokens = self.model_setting.max_output_tokens
272
+ token_counts = get_message_token_counts(messages=messages, tools=tools_params, model=self.model_setting.id)
273
273
  if max_output_tokens is not None:
274
- token_counts = get_token_counts({"messages": messages, "tools_params": tools_params})
275
274
  max_tokens = self.model_setting.context_length - token_counts
276
275
  max_tokens = min(max(max_tokens, 1), max_output_tokens)
277
276
  else:
278
- token_counts = get_token_counts({"messages": messages, "tools_params": tools_params})
279
277
  max_tokens = self.model_setting.context_length - token_counts
280
278
 
281
279
  response: ChatCompletion | AsyncStream[ChatCompletionChunk] = await self._client.chat.completions.create(
@@ -2,7 +2,7 @@
2
2
  # @Date: 2024-07-26 14:48:55
3
3
  import re
4
4
  import json
5
-
5
+ from math import ceil
6
6
  import httpx
7
7
  import tiktoken
8
8
  from anthropic import Anthropic
@@ -187,6 +187,46 @@ def get_token_counts(text: str | dict, model: str = "") -> int:
187
187
  return len(chatgpt_encoding.encode(text))
188
188
 
189
189
 
190
+ def calculate_image_tokens(width: int, height: int, model: str = "gpt-4o"):
191
+ if width > 2048 or height > 2048:
192
+ aspect_ratio = width / height
193
+ if aspect_ratio > 1:
194
+ width, height = 2048, int(2048 / aspect_ratio)
195
+ else:
196
+ width, height = int(2048 * aspect_ratio), 2048
197
+
198
+ if width >= height and height > 768:
199
+ width, height = int((768 / height) * width), 768
200
+ elif height > width and width > 768:
201
+ width, height = 768, int((768 / width) * height)
202
+
203
+ tiles_width = ceil(width / 512)
204
+ tiles_height = ceil(height / 512)
205
+ total_tokens = 85 + 170 * (tiles_width * tiles_height)
206
+
207
+ return total_tokens
208
+
209
+
210
+ def get_message_token_counts(messages: list, tools: dict | None = None, model: str = "gpt-4o") -> int:
211
+ tokens = 0
212
+ formatted_messages = format_messages(messages, backend=BackendType.OpenAI, native_multimodal=True)
213
+ for message in formatted_messages:
214
+ content = message["content"]
215
+ if isinstance(content, str):
216
+ tokens += get_token_counts(content, model)
217
+ elif isinstance(content, list):
218
+ for item in content:
219
+ if isinstance(item, dict) and item["type"] == "text":
220
+ tokens += get_token_counts(item["text"], model)
221
+ elif isinstance(item, dict) and item["type"].startswith("image"):
222
+ # TODO: Get real image size
223
+ tokens += calculate_image_tokens(2048, 2048, model)
224
+ if tools is not None:
225
+ tokens += get_token_counts(json.dumps(tools, ensure_ascii=False), model)
226
+
227
+ return tokens
228
+
229
+
190
230
  def cutoff_messages(
191
231
  messages: list,
192
232
  max_count: int = 16000,
@@ -233,6 +233,7 @@ YI_MODELS = {
233
233
  "max_output_tokens": 2000,
234
234
  "function_call_available": False,
235
235
  "response_format_available": False,
236
+ "native_multimodal": True,
236
237
  },
237
238
  }
238
239
 
@@ -301,6 +302,7 @@ ZHIPUAI_MODELS = {
301
302
  "function_call_available": False,
302
303
  "response_format_available": False,
303
304
  "max_output_tokens": 1024,
305
+ "native_multimodal": True,
304
306
  },
305
307
  "glm-4v-plus": {
306
308
  "id": "glm-4v-plus",
@@ -308,6 +310,7 @@ ZHIPUAI_MODELS = {
308
310
  "function_call_available": False,
309
311
  "response_format_available": False,
310
312
  "max_output_tokens": 1024,
313
+ "native_multimodal": True,
311
314
  },
312
315
  }
313
316
 
@@ -394,6 +397,7 @@ OPENAI_MODELS = {
394
397
  "max_output_tokens": 4096,
395
398
  "function_call_available": True,
396
399
  "response_format_available": True,
400
+ "native_multimodal": True,
397
401
  },
398
402
  "gpt-4o-mini": {
399
403
  "id": "gpt-4o-mini",
@@ -401,6 +405,7 @@ OPENAI_MODELS = {
401
405
  "max_output_tokens": 16384,
402
406
  "function_call_available": True,
403
407
  "response_format_available": True,
408
+ "native_multimodal": True,
404
409
  },
405
410
  "gpt-4v": {
406
411
  "id": "gpt-4v",
@@ -420,12 +425,14 @@ ANTHROPIC_MODELS = {
420
425
  "max_output_tokens": 4096,
421
426
  "function_call_available": True,
422
427
  "response_format_available": True,
428
+ "native_multimodal": True,
423
429
  },
424
430
  "claude-3-sonnet-20240229": {
425
431
  "id": "claude-3-sonnet-20240229",
426
432
  "context_length": 200000,
427
433
  "max_output_tokens": 4096,
428
434
  "function_call_available": True,
435
+ "native_multimodal": True,
429
436
  "response_format_available": True,
430
437
  },
431
438
  "claude-3-haiku-20240307": {
@@ -434,6 +441,7 @@ ANTHROPIC_MODELS = {
434
441
  "max_output_tokens": 4096,
435
442
  "function_call_available": True,
436
443
  "response_format_available": True,
444
+ "native_multimodal": True,
437
445
  },
438
446
  "claude-3-5-sonnet-20240620": {
439
447
  "id": "claude-3-5-sonnet-20240620",
@@ -441,6 +449,7 @@ ANTHROPIC_MODELS = {
441
449
  "max_output_tokens": 4096,
442
450
  "function_call_available": True,
443
451
  "response_format_available": True,
452
+ "native_multimodal": True,
444
453
  },
445
454
  }
446
455
 
@@ -485,11 +494,13 @@ GEMINI_MODELS = {
485
494
  "context_length": 1048576,
486
495
  "function_call_available": True,
487
496
  "response_format_available": True,
497
+ "native_multimodal": True,
488
498
  },
489
499
  "gemini-1.5-flash": {
490
500
  "id": "gemini-1.5-flash",
491
501
  "context_length": 1048576,
492
502
  "function_call_available": True,
493
503
  "response_format_available": True,
504
+ "native_multimodal": True,
494
505
  },
495
506
  }
@@ -30,6 +30,7 @@ class ModelSetting(BaseModel):
30
30
  endpoints: List[str] = Field(default_factory=list, description="Available endpoints for the model.")
31
31
  function_call_available: bool = Field(False, description="Indicates if function call is available.")
32
32
  response_format_available: bool = Field(False, description="Indicates if response format is available.")
33
+ native_multimodal: bool = Field(False, description="Indicates if the model is a native multimodal model.")
33
34
  context_length: int = Field(32768, description="The context length for the model.")
34
35
  max_output_tokens: Optional[int] = Field(None, description="Maximum number of output tokens allowed.")
35
36
 
File without changes
Binary file