vectorvein 0.1.40__tar.gz → 0.1.41__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 (35) hide show
  1. {vectorvein-0.1.40 → vectorvein-0.1.41}/PKG-INFO +2 -1
  2. {vectorvein-0.1.40 → vectorvein-0.1.41}/pyproject.toml +2 -1
  3. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/chat_clients/utils.py +8 -0
  4. vectorvein-0.1.41/src/vectorvein/utilities/media_processing.py +148 -0
  5. vectorvein-0.1.41/src/vectorvein/utilities/retry.py +62 -0
  6. vectorvein-0.1.40/src/vectorvein/utilities/media_processing.py +0 -70
  7. vectorvein-0.1.40/src/vectorvein/utilities/retry.py +0 -36
  8. {vectorvein-0.1.40 → vectorvein-0.1.41}/README.md +0 -0
  9. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/__init__.py +0 -0
  10. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/chat_clients/__init__.py +0 -0
  11. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/chat_clients/anthropic_client.py +0 -0
  12. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/chat_clients/baichuan_client.py +0 -0
  13. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/chat_clients/base_client.py +0 -0
  14. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/chat_clients/deepseek_client.py +0 -0
  15. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/chat_clients/gemini_client.py +0 -0
  16. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/chat_clients/groq_client.py +0 -0
  17. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/chat_clients/local_client.py +0 -0
  18. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/chat_clients/minimax_client.py +0 -0
  19. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/chat_clients/mistral_client.py +0 -0
  20. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/chat_clients/moonshot_client.py +0 -0
  21. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/chat_clients/openai_client.py +0 -0
  22. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/chat_clients/openai_compatible_client.py +0 -0
  23. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/chat_clients/py.typed +0 -0
  24. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/chat_clients/qwen_client.py +0 -0
  25. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/chat_clients/stepfun_client.py +0 -0
  26. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/chat_clients/yi_client.py +0 -0
  27. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/chat_clients/zhipuai_client.py +0 -0
  28. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/py.typed +0 -0
  29. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/settings/__init__.py +0 -0
  30. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/settings/py.typed +0 -0
  31. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/types/defaults.py +0 -0
  32. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/types/enums.py +0 -0
  33. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/types/exception.py +0 -0
  34. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/types/llm_parameters.py +0 -0
  35. {vectorvein-0.1.40 → vectorvein-0.1.41}/src/vectorvein/types/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vectorvein
3
- Version: 0.1.40
3
+ Version: 0.1.41
4
4
  Summary: Default template for PDM package
5
5
  Author-Email: Anderson <andersonby@163.com>
6
6
  License: MIT
@@ -13,6 +13,7 @@ Requires-Dist: pydantic>=2.8.2
13
13
  Requires-Dist: Pillow>=10.4.0
14
14
  Requires-Dist: deepseek-tokenizer>=0.1.0
15
15
  Requires-Dist: qwen-tokenizer>=0.2.0
16
+ Requires-Dist: google-auth>=2.35.0
16
17
  Description-Content-Type: text/markdown
17
18
 
18
19
  # vectorvein
@@ -11,12 +11,13 @@ dependencies = [
11
11
  "Pillow>=10.4.0",
12
12
  "deepseek-tokenizer>=0.1.0",
13
13
  "qwen-tokenizer>=0.2.0",
14
+ "google-auth>=2.35.0",
14
15
  ]
15
16
  description = "Default template for PDM package"
16
17
  name = "vectorvein"
17
18
  readme = "README.md"
18
19
  requires-python = ">=3.10"
19
- version = "0.1.40"
20
+ version = "0.1.41"
20
21
 
21
22
  [project.license]
22
23
  text = "MIT"
@@ -128,6 +128,8 @@ def get_token_counts(text: str | dict, model: str = "") -> int:
128
128
  if len(model_setting.endpoints) == 0:
129
129
  return int(len(text) / 1.33)
130
130
  endpoint_id = model_setting.endpoints[0]
131
+ if isinstance(endpoint_id, dict):
132
+ endpoint_id = endpoint_id["endpoint_id"]
131
133
  endpoint = settings.get_endpoint(endpoint_id)
132
134
  tokenize_url = "https://api.minimax.chat/v1/tokenize"
133
135
  headers = {"Authorization": f"Bearer {endpoint.api_key}", "Content-Type": "application/json"}
@@ -156,6 +158,8 @@ def get_token_counts(text: str | dict, model: str = "") -> int:
156
158
  if len(model_setting.endpoints) == 0:
157
159
  return len(get_gpt_35_encoding().encode(text))
158
160
  endpoint_id = model_setting.endpoints[0]
161
+ if isinstance(endpoint_id, dict):
162
+ endpoint_id = endpoint_id["endpoint_id"]
159
163
  endpoint = settings.get_endpoint(endpoint_id)
160
164
  tokenize_url = "https://api.moonshot.cn/v1/tokenizers/estimate-token-count"
161
165
  headers = {"Content-Type": "application/json", "Authorization": f"Bearer {endpoint.api_key}"}
@@ -181,6 +185,8 @@ def get_token_counts(text: str | dict, model: str = "") -> int:
181
185
  if len(model_setting.endpoints) == 0:
182
186
  return len(get_gpt_35_encoding().encode(text))
183
187
  endpoint_id = model_setting.endpoints[0]
188
+ if isinstance(endpoint_id, dict):
189
+ endpoint_id = endpoint_id["endpoint_id"]
184
190
  endpoint = settings.get_endpoint(endpoint_id)
185
191
  url = f"{endpoint.api_base}/models/{model_setting.id}:countTokens"
186
192
  params = {"key": endpoint.api_key}
@@ -215,6 +221,8 @@ def get_token_counts(text: str | dict, model: str = "") -> int:
215
221
  if len(model_setting.endpoints) == 0:
216
222
  return len(get_gpt_35_encoding().encode(text))
217
223
  endpoint_id = model_setting.endpoints[0]
224
+ if isinstance(endpoint_id, dict):
225
+ endpoint_id = endpoint_id["endpoint_id"]
218
226
  endpoint = settings.get_endpoint(endpoint_id)
219
227
  tokenize_url = "https://api.stepfun.com/v1/token/count"
220
228
  headers = {"Content-Type": "application/json", "Authorization": f"Bearer {endpoint.api_key}"}
@@ -0,0 +1,148 @@
1
+ # @Author: Bi Ying
2
+ # @Date: 2024-07-27 12:03:49
3
+ import base64
4
+ from io import BytesIO
5
+ from pathlib import Path
6
+ from functools import cached_property
7
+
8
+ import httpx
9
+ from PIL import Image
10
+ from PIL.ImageFile import ImageFile
11
+
12
+
13
+ class ImageProcessor:
14
+ def __init__(
15
+ self,
16
+ image_source: Image.Image | str | Path,
17
+ max_size: int | None = 5 * 1024 * 1024,
18
+ max_width: int | None = None,
19
+ max_height: int | None = None,
20
+ ):
21
+ self.image_source = image_source
22
+ if isinstance(image_source, (Image.Image, Path)):
23
+ self.is_local = True
24
+ else:
25
+ self.is_local = not image_source.startswith("http")
26
+ self.max_size = max_size
27
+ self.max_width = max_width
28
+ self.max_height = max_height
29
+ self._image = self._load_image()
30
+ self._image_format = self._image.format or "JPEG"
31
+ self._cached_bytes = None
32
+ self._cached_base64_image = None
33
+
34
+ def _load_image(self):
35
+ if not self.is_local and isinstance(self.image_source, str):
36
+ image_url = self.image_source
37
+ response = httpx.get(image_url)
38
+ return Image.open(BytesIO(response.content))
39
+ elif isinstance(self.image_source, Path):
40
+ return Image.open(self.image_source)
41
+ elif isinstance(self.image_source, Image.Image):
42
+ return self.image_source
43
+ else:
44
+ raise ValueError(f"Unsupported image source type: {type(self.image_source)}")
45
+
46
+ def _resize_image(
47
+ self,
48
+ img: ImageFile | Image.Image,
49
+ max_size: int | None = None,
50
+ max_width: int | None = None,
51
+ max_height: int | None = None,
52
+ ):
53
+ img_bytes = BytesIO()
54
+ image_format = img.format or "JPEG"
55
+ _img = img.copy()
56
+ _img.save(img_bytes, format=image_format, optimize=True)
57
+
58
+ if max_width is not None and _img.width > max_width:
59
+ new_size = (max_width, int(max_width * _img.height / _img.width))
60
+ _img = _img.resize(new_size, Image.Resampling.LANCZOS)
61
+
62
+ if max_height is not None and _img.height > max_height:
63
+ new_size = (int(max_height * _img.width / _img.height), max_height)
64
+ _img = _img.resize(new_size, Image.Resampling.LANCZOS)
65
+
66
+ img_bytes = BytesIO()
67
+ _img.save(img_bytes, format=image_format, optimize=True)
68
+
69
+ if max_size is not None and img_bytes.getbuffer().nbytes <= max_size:
70
+ return img_bytes
71
+
72
+ original_size = _img.size
73
+ scale_factor = 0.9
74
+
75
+ while True:
76
+ new_size = (int(original_size[0] * scale_factor), int(original_size[1] * scale_factor))
77
+ img_resized = _img.resize(new_size, Image.Resampling.LANCZOS)
78
+
79
+ img_bytes_resized = BytesIO()
80
+ img_resized.save(img_bytes_resized, format=image_format, optimize=True)
81
+
82
+ if max_size is not None and img_bytes_resized.getbuffer().nbytes <= max_size:
83
+ return img_bytes_resized
84
+
85
+ scale_factor -= 0.1
86
+ if scale_factor < 0.1:
87
+ return img_bytes_resized
88
+
89
+ @property
90
+ def bytes(self):
91
+ if self._cached_bytes is not None:
92
+ return self._cached_bytes
93
+ if self.max_size is None and self.max_width is None and self.max_height is None:
94
+ if isinstance(self._image, Image.Image):
95
+ img_bytes = BytesIO()
96
+
97
+ # 检查图像是否有透明通道
98
+ has_transparency = self._image.mode in ("RGBA", "LA") or (
99
+ self._image.mode == "P" and "transparency" in self._image.info
100
+ )
101
+
102
+ if has_transparency:
103
+ # 如果有透明通道,使用PNG格式
104
+ save_format = "PNG"
105
+ self._image_format = "PNG"
106
+ else:
107
+ # 如果没有透明通道,使用原始格式或默认为JPEG
108
+ save_format = self._image.format or self._image_format or "JPEG"
109
+
110
+ # 如果图像模式不是RGB(例如RGBA),转换为RGB
111
+ if self._image.mode != "RGB":
112
+ self._image = self._image.convert("RGB")
113
+
114
+ self._image.save(img_bytes, format=save_format, optimize=True)
115
+ self._cached_bytes = img_bytes.getvalue()
116
+ return self._cached_bytes
117
+ elif isinstance(self._image, BytesIO):
118
+ self._cached_bytes = self._image.getvalue()
119
+ return self._cached_bytes
120
+ elif isinstance(self._image, ImageFile):
121
+ if self._image.fp is None:
122
+ raise ValueError("Image file is not open")
123
+ self._cached_bytes = self._image.fp.read()
124
+ return self._cached_bytes
125
+
126
+ self._cached_bytes = self._image.getvalue()
127
+ return self._cached_bytes
128
+
129
+ img_bytes_resized = self._resize_image(self._image, self.max_size, self.max_width, self.max_height)
130
+ return img_bytes_resized.getvalue()
131
+
132
+ @property
133
+ def base64_image(self):
134
+ if self.max_size is None and self.max_width is None and self.max_height is None:
135
+ self._cached_base64_image = base64.b64encode(self.bytes).decode()
136
+ return self._cached_base64_image
137
+
138
+ img_bytes_resized = self._resize_image(self._image, self.max_size, self.max_width, self.max_height)
139
+ self._cached_base64_image = base64.b64encode(img_bytes_resized.getvalue()).decode()
140
+ return self._cached_base64_image
141
+
142
+ @property
143
+ def mime_type(self):
144
+ return Image.MIME[self._image_format]
145
+
146
+ @cached_property
147
+ def data_url(self):
148
+ return f"data:{self.mime_type};base64,{self.base64_image}"
@@ -0,0 +1,62 @@
1
+ # @Author: Bi Ying
2
+ # @Date: 2024-06-07 16:16:49
3
+ import time
4
+ from typing import Optional, Any, Callable, Tuple, Union, TypeVar, Generic
5
+
6
+
7
+ ResultType = TypeVar("ResultType")
8
+
9
+
10
+ class Retry(Generic[ResultType]):
11
+ def __init__(self, function: Callable[..., ResultType]):
12
+ self.function: Callable[..., ResultType] = function
13
+ self.__retry_times: int = 3
14
+ self.__sleep_time: Union[int, float] = 1
15
+ self.__timeout: int = 180
16
+ self.__result_check: Optional[Callable[[ResultType], bool]] = None
17
+ self.pargs: list = []
18
+ self.kwargs: dict = {}
19
+
20
+ def args(self, *args: Any, **kwargs: Any) -> "Retry[ResultType]":
21
+ self.pargs = list(args)
22
+ self.kwargs = kwargs
23
+ return self
24
+
25
+ def retry_times(self, retry_times: int) -> "Retry[ResultType]":
26
+ self.__retry_times = retry_times
27
+ return self
28
+
29
+ def sleep_time(self, sleep_time: Union[int, float]) -> "Retry[ResultType]":
30
+ self.__sleep_time = sleep_time
31
+ return self
32
+
33
+ def result_check(self, check_function: Callable[[ResultType], bool]) -> "Retry[ResultType]":
34
+ self.__result_check = check_function
35
+ return self
36
+
37
+ def _check_result(self, result: ResultType) -> bool:
38
+ try:
39
+ if self.__result_check is None:
40
+ return True
41
+ return self.__result_check(result)
42
+ except Exception as e:
43
+ print(f"Retry result check error: {e}")
44
+ return False
45
+
46
+ def run(self) -> Tuple[bool, Optional[ResultType]]:
47
+ try_times = 0
48
+ start_time = time.time()
49
+
50
+ while try_times <= self.__retry_times and time.time() - start_time < self.__timeout:
51
+ try:
52
+ result: ResultType = self.function(*self.pargs, **self.kwargs)
53
+ if self._check_result(result):
54
+ return True, result
55
+ try_times += 1
56
+ time.sleep(self.__sleep_time)
57
+ except Exception as e:
58
+ print(f"{self.function.__name__} function error: {e}")
59
+ try_times += 1
60
+ time.sleep(self.__sleep_time)
61
+
62
+ return False, None
@@ -1,70 +0,0 @@
1
- # @Author: Bi Ying
2
- # @Date: 2024-07-27 12:03:49
3
- import base64
4
- from io import BytesIO
5
- from pathlib import Path
6
- from functools import cached_property
7
-
8
- import httpx
9
- from PIL import Image
10
-
11
-
12
-
13
- class ImageProcessor:
14
- def __init__(self, image_source: Image.Image | str | Path, max_size: int | None = 5 * 1024 * 1024):
15
- self.image_source = image_source
16
- if isinstance(image_source, (Image.Image, Path)):
17
- self.is_local = True
18
- else:
19
- self.is_local = not image_source.startswith("http")
20
- self.max_size = max_size
21
- self._image = self._load_image()
22
-
23
- def _load_image(self):
24
- if not self.is_local:
25
- image_url = self.image_source
26
- response = httpx.get(image_url)
27
- return Image.open(BytesIO(response.content))
28
- else:
29
- return Image.open(self.image_source)
30
-
31
- def _resize_image(self, img, max_size):
32
- img_bytes = BytesIO()
33
- img.save(img_bytes, format=img.format, optimize=True)
34
-
35
- if img_bytes.getbuffer().nbytes <= max_size:
36
- return img_bytes
37
-
38
- original_size = img.size
39
- scale_factor = 0.9
40
-
41
- while True:
42
- new_size = (int(original_size[0] * scale_factor), int(original_size[1] * scale_factor))
43
- img_resized = img.resize(new_size, Image.Resampling.LANCZOS)
44
-
45
- img_bytes_resized = BytesIO()
46
- img_resized.save(img_bytes_resized, format=img.format, optimize=True)
47
-
48
- if img_bytes_resized.getbuffer().nbytes <= max_size:
49
- return img_bytes_resized
50
-
51
- scale_factor -= 0.1
52
- if scale_factor < 0.1:
53
- return img_bytes_resized
54
-
55
- @cached_property
56
- def base64_image(self):
57
- if self.max_size is None:
58
- return base64.b64encode(self._image.getvalue()).decode()
59
-
60
- img_bytes_resized = self._resize_image(self._image, self.max_size)
61
- return base64.b64encode(img_bytes_resized.getvalue()).decode()
62
-
63
- @cached_property
64
- def mime_type(self):
65
- return Image.MIME[self._image.format]
66
-
67
- @cached_property
68
- def data_url(self):
69
- return f"data:{self.mime_type};base64,{self.base64_image}"
70
-
@@ -1,36 +0,0 @@
1
- # @Author: Bi Ying
2
- # @Date: 2024-08-14 13:03:10
3
- import time
4
-
5
-
6
- class Retry:
7
- def __init__(self, function):
8
- self.function = function
9
- self.__retry_times = 3
10
- self.__sleep_time = 1
11
- self.pargs = []
12
- self.kwargs = {}
13
-
14
- def args(self, *args, **kwargs):
15
- self.pargs = args
16
- self.kwargs = kwargs
17
- return self
18
-
19
- def retry_times(self, retry_times: int):
20
- self.__retry_times = retry_times
21
- return self
22
-
23
- def sleep_time(self, sleep_time):
24
- self.__sleep_time = sleep_time
25
- return self
26
-
27
- def run(self):
28
- try_times = 0
29
- while try_times < self.__retry_times:
30
- try:
31
- return True, self.function(*self.pargs, **self.kwargs)
32
- except Exception as e:
33
- print(f"{self.function.__name__} 函数出错:{e}")
34
- try_times += 1
35
- time.sleep(self.__sleep_time)
36
- return False, None
File without changes