vectorvein 0.1.94__py3-none-any.whl → 0.2.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.
@@ -0,0 +1,35 @@
1
+ """向量脉络 API 包"""
2
+
3
+ from .client import VectorVeinClient
4
+ from .models import (
5
+ VApp,
6
+ AccessKey,
7
+ WorkflowInputField,
8
+ WorkflowOutput,
9
+ WorkflowRunResult,
10
+ AccessKeyListResponse,
11
+ )
12
+ from .exceptions import (
13
+ VectorVeinAPIError,
14
+ APIKeyError,
15
+ WorkflowError,
16
+ AccessKeyError,
17
+ RequestError,
18
+ TimeoutError,
19
+ )
20
+
21
+ __all__ = [
22
+ "VectorVeinClient",
23
+ "VApp",
24
+ "AccessKey",
25
+ "WorkflowInputField",
26
+ "WorkflowOutput",
27
+ "WorkflowRunResult",
28
+ "AccessKeyListResponse",
29
+ "VectorVeinAPIError",
30
+ "APIKeyError",
31
+ "WorkflowError",
32
+ "AccessKeyError",
33
+ "RequestError",
34
+ "TimeoutError",
35
+ ]
@@ -0,0 +1,426 @@
1
+ """向量脉络 API 客户端"""
2
+
3
+ import time
4
+ import base64
5
+ from urllib.parse import quote
6
+ from typing import List, Optional, Dict, Any, Union, Literal, overload
7
+
8
+ import httpx
9
+ from Crypto.Cipher import AES
10
+ from Crypto.Util.Padding import pad
11
+
12
+ from .exceptions import (
13
+ VectorVeinAPIError,
14
+ APIKeyError,
15
+ WorkflowError,
16
+ AccessKeyError,
17
+ RequestError,
18
+ TimeoutError,
19
+ )
20
+ from .models import (
21
+ AccessKey,
22
+ WorkflowInputField,
23
+ WorkflowOutput,
24
+ WorkflowRunResult,
25
+ AccessKeyListResponse,
26
+ )
27
+
28
+
29
+ class VectorVeinClient:
30
+ """向量脉络 API 客户端类"""
31
+
32
+ API_VERSION = "20240508"
33
+ BASE_URL = "https://vectorvein.com/api/v1/open-api"
34
+
35
+ def __init__(self, api_key: str, base_url: Optional[str] = None):
36
+ """初始化客户端
37
+
38
+ Args:
39
+ api_key: API密钥
40
+ base_url: API基础URL,默认为https://vectorvein.com/api/v1/open-api
41
+
42
+ Raises:
43
+ APIKeyError: API密钥为空或格式不正确
44
+ """
45
+ if not api_key or not isinstance(api_key, str):
46
+ raise APIKeyError("API密钥不能为空且必须是字符串类型")
47
+
48
+ self.api_key = api_key
49
+ self.base_url = base_url or self.BASE_URL
50
+ self._client = httpx.Client(
51
+ headers={
52
+ "VECTORVEIN-API-KEY": api_key,
53
+ "VECTORVEIN-API-VERSION": self.API_VERSION,
54
+ }
55
+ )
56
+
57
+ def __enter__(self):
58
+ return self
59
+
60
+ def __exit__(self, exc_type, exc_val, exc_tb):
61
+ self._client.close()
62
+
63
+ def _request(
64
+ self,
65
+ method: str,
66
+ endpoint: str,
67
+ params: Optional[Dict[str, Any]] = None,
68
+ json: Optional[Dict[str, Any]] = None,
69
+ **kwargs,
70
+ ) -> Dict[str, Any]:
71
+ """发送HTTP请求
72
+
73
+ Args:
74
+ method: HTTP方法
75
+ endpoint: API端点
76
+ params: URL参数
77
+ json: JSON请求体
78
+ **kwargs: 其他请求参数
79
+
80
+ Returns:
81
+ Dict[str, Any]: API响应
82
+
83
+ Raises:
84
+ RequestError: 请求错误
85
+ VectorVeinAPIError: API错误
86
+ APIKeyError: API密钥无效或已过期
87
+ """
88
+ url = f"{self.base_url}/{endpoint}"
89
+ try:
90
+ response = self._client.request(method=method, url=url, params=params, json=json, **kwargs)
91
+ response.raise_for_status()
92
+ result = response.json()
93
+
94
+ if result["status"] in [401, 403]:
95
+ raise APIKeyError("API密钥无效或已过期")
96
+ if result["status"] != 200 and result["status"] != 202:
97
+ raise VectorVeinAPIError(message=result.get("msg", "Unknown error"), status_code=result["status"])
98
+ return result
99
+ except httpx.HTTPError as e:
100
+ raise RequestError(f"Request failed: {str(e)}")
101
+
102
+ @overload
103
+ def run_workflow(
104
+ self,
105
+ wid: str,
106
+ input_fields: List[WorkflowInputField],
107
+ output_scope: Literal["all", "output_fields_only"] = "output_fields_only",
108
+ wait_for_completion: Literal[False] = False,
109
+ timeout: int = 30,
110
+ ) -> str: ...
111
+
112
+ @overload
113
+ def run_workflow(
114
+ self,
115
+ wid: str,
116
+ input_fields: List[WorkflowInputField],
117
+ output_scope: Literal["all", "output_fields_only"] = "output_fields_only",
118
+ wait_for_completion: Literal[True] = True,
119
+ timeout: int = 30,
120
+ ) -> WorkflowRunResult: ...
121
+
122
+ def run_workflow(
123
+ self,
124
+ wid: str,
125
+ input_fields: List[WorkflowInputField],
126
+ output_scope: Literal["all", "output_fields_only"] = "output_fields_only",
127
+ wait_for_completion: bool = False,
128
+ timeout: int = 30,
129
+ ) -> Union[str, WorkflowRunResult]:
130
+ """运行工作流
131
+
132
+ Args:
133
+ wid: 工作流ID
134
+ input_fields: 输入字段列表
135
+ output_scope: 输出范围,可选值:'all' 或 'output_fields_only'
136
+ wait_for_completion: 是否等待完成
137
+ timeout: 超时时间(秒)
138
+
139
+ Returns:
140
+ Union[str, WorkflowRunResult]: 工作流运行ID或运行结果
141
+
142
+ Raises:
143
+ WorkflowError: 工作流运行错误
144
+ TimeoutError: 超时错误
145
+ """
146
+ payload = {
147
+ "wid": wid,
148
+ "output_scope": output_scope,
149
+ "wait_for_completion": wait_for_completion,
150
+ "input_fields": [
151
+ {"node_id": field.node_id, "field_name": field.field_name, "value": field.value}
152
+ for field in input_fields
153
+ ],
154
+ }
155
+
156
+ result = self._request("POST", "workflow/run", json=payload)
157
+
158
+ if not wait_for_completion:
159
+ return result["data"]["rid"]
160
+
161
+ rid = result.get("rid") or (isinstance(result["data"], dict) and result["data"].get("rid")) or ""
162
+ start_time = time.time()
163
+
164
+ while True:
165
+ if time.time() - start_time > timeout:
166
+ raise TimeoutError(f"Workflow execution timed out after {timeout} seconds")
167
+
168
+ status = self.check_workflow_status(rid)
169
+ if status["status"] == 200:
170
+ return WorkflowRunResult(
171
+ rid=rid,
172
+ status=status["status"],
173
+ msg=status["msg"],
174
+ data=[WorkflowOutput(**output) for output in status["data"]],
175
+ )
176
+ elif status["status"] == 500:
177
+ raise WorkflowError(f"Workflow execution failed: {status['msg']}")
178
+
179
+ time.sleep(5)
180
+
181
+ def check_workflow_status(self, rid: str) -> Dict:
182
+ """检查工作流运行状态
183
+
184
+ Args:
185
+ rid: 工作流运行记录ID
186
+
187
+ Returns:
188
+ Dict: 工作流状态信息
189
+ """
190
+ payload = {"rid": rid}
191
+ return self._request("POST", "workflow/check-status", json=payload)
192
+
193
+ def get_access_keys(
194
+ self, access_keys: Optional[List[str]] = None, get_type: Literal["selected", "all"] = "selected"
195
+ ) -> List[AccessKey]:
196
+ """获取访问密钥信息
197
+
198
+ Args:
199
+ access_keys: 访问密钥列表
200
+ get_type: 获取类型,可选值:'selected' 或 'all'
201
+
202
+ Returns:
203
+ List[AccessKey]: 访问密钥信息列表
204
+
205
+ Raises:
206
+ AccessKeyError: 访问密钥不存在或已失效
207
+ """
208
+ params = {"get_type": get_type}
209
+ if access_keys:
210
+ params["access_keys"] = ",".join(access_keys)
211
+
212
+ try:
213
+ result = self._request("GET", "vapp/access-key/get", params=params)
214
+ return [AccessKey(**key) for key in result["data"]]
215
+ except VectorVeinAPIError as e:
216
+ if e.status_code == 404:
217
+ raise AccessKeyError("访问密钥不存在")
218
+ elif e.status_code == 403:
219
+ raise AccessKeyError("访问密钥已失效")
220
+ raise
221
+
222
+ def create_access_keys(
223
+ self,
224
+ access_key_type: Literal["O", "M", "L"],
225
+ app_id: Optional[str] = None,
226
+ app_ids: Optional[List[str]] = None,
227
+ count: int = 1,
228
+ expire_time: Optional[str] = None,
229
+ max_credits: Optional[int] = None,
230
+ max_use_count: Optional[int] = None,
231
+ description: Optional[str] = None,
232
+ ) -> List[AccessKey]:
233
+ """创建访问密钥
234
+
235
+ Args:
236
+ access_key_type: 密钥类型,可选值:'O'(一次性)、'M'(多次)、'L'(长期)
237
+ app_id: 单个应用ID
238
+ app_ids: 多个应用ID列表
239
+ count: 创建数量
240
+ expire_time: 过期时间
241
+ max_credits: 最大积分限制
242
+ max_use_count: 最大使用次数
243
+ description: 描述信息
244
+
245
+ Returns:
246
+ List[AccessKey]: 创建的访问密钥列表
247
+
248
+ Raises:
249
+ AccessKeyError: 创建访问密钥失败,如类型无效、应用不存在等
250
+ """
251
+ if access_key_type not in ["O", "M", "L"]:
252
+ raise AccessKeyError("无效的访问密钥类型,必须是 'O'(一次性)、'M'(多次) 或 'L'(长期)")
253
+
254
+ if app_id and app_ids:
255
+ raise AccessKeyError("不能同时指定 app_id 和 app_ids")
256
+
257
+ payload = {"access_key_type": access_key_type, "count": count}
258
+
259
+ if app_id:
260
+ payload["app_id"] = app_id
261
+ if app_ids:
262
+ payload["app_ids"] = app_ids
263
+ if expire_time:
264
+ payload["expire_time"] = expire_time
265
+ if max_credits is not None:
266
+ payload["max_credits"] = max_credits
267
+ if max_use_count is not None:
268
+ payload["max_use_count"] = max_use_count
269
+ if description:
270
+ payload["description"] = description
271
+
272
+ try:
273
+ result = self._request("POST", "vapp/access-key/create", json=payload)
274
+ return [AccessKey(**key) for key in result["data"]]
275
+ except VectorVeinAPIError as e:
276
+ if e.status_code == 404:
277
+ raise AccessKeyError("指定的应用不存在")
278
+ elif e.status_code == 403:
279
+ raise AccessKeyError("没有权限创建访问密钥")
280
+ raise
281
+
282
+ def list_access_keys(
283
+ self,
284
+ page: int = 1,
285
+ page_size: int = 10,
286
+ sort_field: str = "create_time",
287
+ sort_order: str = "descend",
288
+ app_id: Optional[str] = None,
289
+ status: Optional[List[str]] = None,
290
+ access_key_type: Optional[Literal["O", "M", "L"]] = None,
291
+ ) -> AccessKeyListResponse:
292
+ """列出访问密钥
293
+
294
+ Args:
295
+ page: 页码
296
+ page_size: 每页数量
297
+ sort_field: 排序字段
298
+ sort_order: 排序顺序
299
+ app_id: 应用ID
300
+ status: 状态列表
301
+ access_key_type: 密钥类型列表,可选值:'O'(一次性)、'M'(多次)、'L'(长期)
302
+
303
+ Returns:
304
+ AccessKeyListResponse: 访问密钥列表响应
305
+ """
306
+ payload = {"page": page, "page_size": page_size, "sort_field": sort_field, "sort_order": sort_order}
307
+
308
+ if app_id:
309
+ payload["app_id"] = app_id
310
+ if status:
311
+ payload["status"] = status
312
+ if access_key_type:
313
+ payload["access_key_type"] = access_key_type
314
+
315
+ result = self._request("POST", "vapp/access-key/list", json=payload)
316
+ return AccessKeyListResponse(**result["data"])
317
+
318
+ def delete_access_keys(self, app_id: str, access_keys: List[str]) -> None:
319
+ """删除访问密钥
320
+
321
+ Args:
322
+ app_id: 应用ID
323
+ access_keys: 要删除的访问密钥列表
324
+ """
325
+ payload = {"app_id": app_id, "access_keys": access_keys}
326
+ self._request("POST", "vapp/access-key/delete", json=payload)
327
+
328
+ def update_access_keys(
329
+ self,
330
+ access_key: Optional[str] = None,
331
+ access_keys: Optional[List[str]] = None,
332
+ app_id: Optional[str] = None,
333
+ app_ids: Optional[List[str]] = None,
334
+ expire_time: Optional[str] = None,
335
+ max_use_count: Optional[int] = None,
336
+ max_credits: Optional[int] = None,
337
+ description: Optional[str] = None,
338
+ access_key_type: Optional[Literal["O", "M", "L"]] = None,
339
+ ) -> None:
340
+ """更新访问密钥
341
+
342
+ Args:
343
+ access_key: 单个访问密钥
344
+ access_keys: 多个访问密钥列表
345
+ app_id: 单个应用ID
346
+ app_ids: 多个应用ID列表
347
+ expire_time: 过期时间
348
+ max_use_count: 最大使用次数
349
+ max_credits: 最大积分限制
350
+ description: 描述信息
351
+ access_key_type: 密钥类型,可选值:'O'(一次性)、'M'(多次)、'L'(长期)
352
+ """
353
+ payload = {}
354
+ if access_key:
355
+ payload["access_key"] = access_key
356
+ if access_keys:
357
+ payload["access_keys"] = access_keys
358
+ if app_id:
359
+ payload["app_id"] = app_id
360
+ if app_ids:
361
+ payload["app_ids"] = app_ids
362
+ if expire_time:
363
+ payload["expire_time"] = expire_time
364
+ if max_use_count is not None:
365
+ payload["max_use_count"] = max_use_count
366
+ if max_credits is not None:
367
+ payload["max_credits"] = max_credits
368
+ if description:
369
+ payload["description"] = description
370
+ if access_key_type:
371
+ payload["access_key_type"] = access_key_type
372
+
373
+ self._request("POST", "vapp/access-key/update", json=payload)
374
+
375
+ def add_apps_to_access_keys(self, access_keys: List[str], app_ids: List[str]) -> None:
376
+ """向访问密钥添加应用
377
+
378
+ Args:
379
+ access_keys: 访问密钥列表
380
+ app_ids: 要添加的应用ID列表
381
+ """
382
+ payload = {"access_keys": access_keys, "app_ids": app_ids}
383
+ self._request("POST", "vapp/access-key/add-apps", json=payload)
384
+
385
+ def remove_apps_from_access_keys(self, access_keys: List[str], app_ids: List[str]) -> None:
386
+ """从访问密钥移除应用
387
+
388
+ Args:
389
+ access_keys: 访问密钥列表
390
+ app_ids: 要移除的应用ID列表
391
+ """
392
+ payload = {"access_keys": access_keys, "app_ids": app_ids}
393
+ self._request("POST", "vapp/access-key/remove-apps", json=payload)
394
+
395
+ def generate_vapp_url(
396
+ self,
397
+ app_id: str,
398
+ access_key: str,
399
+ key_id: str,
400
+ timeout: int = 15 * 60,
401
+ base_url: str = "https://vectorvein.com",
402
+ ) -> str:
403
+ """生成VApp访问链接
404
+
405
+ Args:
406
+ app_id: VApp ID
407
+ access_key: 访问密钥
408
+ key_id: 密钥ID
409
+ timeout: 超时时间(秒)
410
+ base_url: 基础URL
411
+
412
+ Returns:
413
+ str: VApp访问链接
414
+ """
415
+ timestamp = int(time.time())
416
+ message = f"{app_id}:{access_key}:{timestamp}:{timeout}"
417
+ encryption_key = self.api_key.encode()
418
+
419
+ cipher = AES.new(encryption_key, AES.MODE_CBC)
420
+ padded_data = pad(message.encode(), AES.block_size)
421
+ encrypted_data = cipher.encrypt(padded_data)
422
+ final_data = bytes(cipher.iv) + encrypted_data
423
+ token = base64.b64encode(final_data).decode("utf-8")
424
+ quoted_token = quote(token)
425
+
426
+ return f"{base_url}/public/v-app/{app_id}?token={quoted_token}&key_id={key_id}"
@@ -0,0 +1,41 @@
1
+ """向量脉络 API 异常类定义"""
2
+
3
+ from typing import Optional
4
+
5
+
6
+ class VectorVeinAPIError(Exception):
7
+ """向量脉络 API 基础异常类"""
8
+
9
+ def __init__(self, message: str, status_code: Optional[int] = None):
10
+ super().__init__(message)
11
+ self.status_code = status_code
12
+
13
+
14
+ class APIKeyError(VectorVeinAPIError):
15
+ """API密钥相关错误"""
16
+
17
+ pass
18
+
19
+
20
+ class WorkflowError(VectorVeinAPIError):
21
+ """工作流相关错误"""
22
+
23
+ pass
24
+
25
+
26
+ class AccessKeyError(VectorVeinAPIError):
27
+ """访问密钥相关错误"""
28
+
29
+ pass
30
+
31
+
32
+ class RequestError(VectorVeinAPIError):
33
+ """请求相关错误"""
34
+
35
+ pass
36
+
37
+
38
+ class TimeoutError(VectorVeinAPIError):
39
+ """超时错误"""
40
+
41
+ pass
@@ -0,0 +1,74 @@
1
+ """向量脉络 API 数据模型定义"""
2
+
3
+ from dataclasses import dataclass
4
+ from typing import List, Dict, Optional, Any
5
+
6
+
7
+ @dataclass
8
+ class VApp:
9
+ """VApp 信息"""
10
+
11
+ app_id: str
12
+ title: str
13
+ description: str
14
+ info: Dict[str, Any]
15
+ images: List[str]
16
+
17
+
18
+ @dataclass
19
+ class AccessKey:
20
+ """访问密钥信息"""
21
+
22
+ access_key: str
23
+ access_key_type: str # O: 一次性, M: 多次, L: 长期
24
+ use_count: int
25
+ max_use_count: Optional[int]
26
+ max_credits: Optional[int]
27
+ used_credits: int
28
+ v_app: Optional[VApp]
29
+ v_apps: List[VApp]
30
+ records: List[Any]
31
+ status: str # AC: 有效, IN: 无效, EX: 已过期, US: 已使用
32
+ access_scope: str # S: 单应用, M: 多应用
33
+ description: str
34
+ create_time: str
35
+ expire_time: str
36
+ last_use_time: Optional[str]
37
+
38
+
39
+ @dataclass
40
+ class WorkflowInputField:
41
+ """工作流输入字段"""
42
+
43
+ node_id: str
44
+ field_name: str
45
+ value: Any
46
+
47
+
48
+ @dataclass
49
+ class WorkflowOutput:
50
+ """工作流输出结果"""
51
+
52
+ type: str
53
+ title: str
54
+ value: Any
55
+
56
+
57
+ @dataclass
58
+ class WorkflowRunResult:
59
+ """工作流运行结果"""
60
+
61
+ rid: str
62
+ status: int
63
+ msg: str
64
+ data: List[WorkflowOutput]
65
+
66
+
67
+ @dataclass
68
+ class AccessKeyListResponse:
69
+ """访问密钥列表响应"""
70
+
71
+ access_keys: List[AccessKey]
72
+ total: int
73
+ page_size: int
74
+ page: int
@@ -562,7 +562,10 @@ def transform_from_openai_message(message: ChatCompletionMessageParam, backend:
562
562
  if isinstance(item, str):
563
563
  formatted_content.append({"type": "text", "text": item})
564
564
  elif isinstance(item, dict) and "type" in item:
565
- formatted_content.append(item)
565
+ if item["type"] == "image_url":
566
+ formatted_content.append(format_image_message(item["image_url"]["url"], backend))
567
+ else:
568
+ formatted_content.append(item)
566
569
  return {"role": role, "content": formatted_content}
567
570
  else:
568
571
  return {"role": role, "content": content}
@@ -32,11 +32,18 @@ class ImageProcessor:
32
32
  self._cached_base64_image = None
33
33
 
34
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, str)):
35
+ if isinstance(self.image_source, str):
36
+ if self.image_source.startswith(("data:image/", "data:application/octet-stream;base64,")):
37
+ base64_data = self.image_source.split(",")[1]
38
+ image_data = base64.b64decode(base64_data)
39
+ return Image.open(BytesIO(image_data))
40
+ elif not self.is_local:
41
+ image_url = self.image_source
42
+ response = httpx.get(image_url)
43
+ return Image.open(BytesIO(response.content))
44
+ else:
45
+ return Image.open(self.image_source)
46
+ elif isinstance(self.image_source, Path):
40
47
  return Image.open(self.image_source)
41
48
  elif isinstance(self.image_source, Image.Image):
42
49
  return self.image_source
@@ -0,0 +1,170 @@
1
+ Metadata-Version: 2.1
2
+ Name: vectorvein
3
+ Version: 0.2.0
4
+ Summary: VectorVein python SDK
5
+ Author-Email: Anderson <andersonby@163.com>
6
+ License: MIT
7
+ Requires-Python: >=3.10
8
+ Requires-Dist: openai>=1.37.1
9
+ Requires-Dist: tiktoken>=0.7.0
10
+ Requires-Dist: httpx>=0.27.0
11
+ Requires-Dist: anthropic[bedrock,vertex]>=0.31.2
12
+ Requires-Dist: pydantic>=2.8.2
13
+ Requires-Dist: Pillow>=10.4.0
14
+ Requires-Dist: deepseek-tokenizer>=0.1.0
15
+ Requires-Dist: qwen-tokenizer>=0.2.0
16
+ Requires-Dist: google-auth>=2.35.0
17
+ Requires-Dist: pycryptodome>=3.21.0
18
+ Provides-Extra: server
19
+ Requires-Dist: fastapi; extra == "server"
20
+ Requires-Dist: uvicorn; extra == "server"
21
+ Provides-Extra: redis
22
+ Requires-Dist: redis; extra == "redis"
23
+ Provides-Extra: diskcache
24
+ Requires-Dist: diskcache; extra == "diskcache"
25
+ Description-Content-Type: text/markdown
26
+
27
+ # 向量脉络 API 包
28
+
29
+ 这是一个用于调用向量脉络官方API的Python包装器。它提供了简单易用的接口来访问向量脉络的工作流和VApp功能。
30
+
31
+ ## 安装
32
+
33
+ ```bash
34
+ pip install -r requirements.txt
35
+ ```
36
+
37
+ ## 使用示例
38
+
39
+ ### 初始化客户端
40
+
41
+ ```python
42
+ from vectorvein.api import VectorVeinClient
43
+
44
+ # 创建客户端实例
45
+ client = VectorVeinClient(api_key="YOUR_API_KEY")
46
+ ```
47
+
48
+ ### 运行工作流
49
+
50
+ ```python
51
+ from vectorvein.api import WorkflowInputField
52
+
53
+ # 准备工作流输入字段
54
+ input_fields = [
55
+ WorkflowInputField(
56
+ node_id="8fc6eceb-8599-46a7-87fe-58bf7c0b633e",
57
+ field_name="商品名称",
58
+ value="测试商品"
59
+ )
60
+ ]
61
+
62
+ # 异步运行工作流
63
+ rid = client.run_workflow(
64
+ wid="abcde0985736457aa72cc667f17bfc89",
65
+ input_fields=input_fields,
66
+ wait_for_completion=False
67
+ )
68
+ print(f"工作流运行ID: {rid}")
69
+
70
+ # 同步运行工作流
71
+ result = client.run_workflow(
72
+ wid="abcde0985736457aa72cc667f17bfc89",
73
+ input_fields=input_fields,
74
+ wait_for_completion=True
75
+ )
76
+ print(f"工作流运行结果: {result}")
77
+ ```
78
+
79
+ ### 管理访问密钥
80
+
81
+ ```python
82
+ # 创建访问密钥
83
+ keys = client.create_access_keys(
84
+ access_key_type="L", # L: 长期, M: 多次, O: 一次性
85
+ app_id="YOUR_APP_ID",
86
+ count=1,
87
+ max_credits=500,
88
+ description="测试密钥"
89
+ )
90
+ print(f"创建的访问密钥: {keys}")
91
+
92
+ # 获取访问密钥信息
93
+ keys = client.get_access_keys(["ACCESS_KEY_1", "ACCESS_KEY_2"])
94
+ print(f"访问密钥信息: {keys}")
95
+
96
+ # 列出访问密钥
97
+ response = client.list_access_keys(
98
+ page=1,
99
+ page_size=10,
100
+ sort_field="create_time",
101
+ sort_order="descend"
102
+ )
103
+ print(f"访问密钥列表: {response}")
104
+
105
+ # 更新访问密钥
106
+ client.update_access_keys(
107
+ access_key="ACCESS_KEY",
108
+ description="更新的描述"
109
+ )
110
+
111
+ # 删除访问密钥
112
+ client.delete_access_keys(
113
+ app_id="YOUR_APP_ID",
114
+ access_keys=["ACCESS_KEY_1", "ACCESS_KEY_2"]
115
+ )
116
+ ```
117
+
118
+ ### 生成VApp访问链接
119
+
120
+ ```python
121
+ url = client.generate_vapp_url(
122
+ app_id="YOUR_APP_ID",
123
+ access_key="YOUR_ACCESS_KEY",
124
+ key_id="YOUR_KEY_ID"
125
+ )
126
+ print(f"VApp访问链接: {url}")
127
+ ```
128
+
129
+ ## API文档
130
+
131
+ ### VectorVeinClient
132
+
133
+ 主要的API客户端类,提供以下方法:
134
+
135
+ - `run_workflow()` - 运行工作流
136
+ - `check_workflow_status()` - 检查工作流运行状态
137
+ - `get_access_keys()` - 获取访问密钥信息
138
+ - `create_access_keys()` - 创建访问密钥
139
+ - `list_access_keys()` - 列出访问密钥
140
+ - `delete_access_keys()` - 删除访问密钥
141
+ - `update_access_keys()` - 更新访问密钥
142
+ - `add_apps_to_access_keys()` - 向访问密钥添加应用
143
+ - `remove_apps_from_access_keys()` - 从访问密钥移除应用
144
+ - `generate_vapp_url()` - 生成VApp访问链接
145
+
146
+ ### 数据模型
147
+
148
+ - `VApp` - VApp信息
149
+ - `AccessKey` - 访问密钥信息
150
+ - `WorkflowInputField` - 工作流输入字段
151
+ - `WorkflowOutput` - 工作流输出结果
152
+ - `WorkflowRunResult` - 工作流运行结果
153
+ - `AccessKeyListResponse` - 访问密钥列表响应
154
+
155
+ ### 异常类
156
+
157
+ - `VectorVeinAPIError` - API基础异常类
158
+ - `APIKeyError` - API密钥相关错误
159
+ - `WorkflowError` - 工作流相关错误
160
+ - `AccessKeyError` - 访问密钥相关错误
161
+ - `RequestError` - 请求相关错误
162
+ - `TimeoutError` - 超时错误
163
+
164
+ ## 注意事项
165
+
166
+ 1. 请妥善保管您的API密钥,不要将其泄露给他人。
167
+ 2. API调用有速率限制,每分钟最多60次调用。
168
+ 3. 建议在生产环境中使用异步方式运行工作流,避免长时间等待。
169
+ 4. 访问密钥的类型一旦创建就不能更改,请谨慎选择。
170
+ 5. 生成的VApp访问链接有效期默认为15分钟,请及时使用。
@@ -1,7 +1,11 @@
1
- vectorvein-0.1.94.dist-info/METADATA,sha256=GOy1lUZfBXtI3RqRGmAfpT6ju1I1gG94tytmlTbyNt8,775
2
- vectorvein-0.1.94.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
3
- vectorvein-0.1.94.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
1
+ vectorvein-0.2.0.dist-info/METADATA,sha256=zhUJelmK4DH7TnlwJtojTnTP_fyY58Cw6gHuz8ILvgs,4413
2
+ vectorvein-0.2.0.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
3
+ vectorvein-0.2.0.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
4
4
  vectorvein/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ vectorvein/api/__init__.py,sha256=A3TcCxRa-dnVWQ0BQyoO8IuLTO0MStcwIuLkoWsKpB8,685
6
+ vectorvein/api/client.py,sha256=8UawPpShCK2wy2RpzvI0h4WHwgb1X6f5JpoP239x20k,14689
7
+ vectorvein/api/exceptions.py,sha256=btfeXfNfc7zLykMKklpJePLnmJie5YSxCYHyMReCC9s,751
8
+ vectorvein/api/models.py,sha256=z5MeXMxWFHlNkP5vjVz6gEn5cxD1FbQ8pQvbx9KtgkE,1422
5
9
  vectorvein/chat_clients/__init__.py,sha256=omQuG4PRRPNflSAgtdU--rwsWG6vMpwMEyIGZyFVHVQ,18596
6
10
  vectorvein/chat_clients/anthropic_client.py,sha256=Zk6X1feIvv7Az5dgyipJXbm9TkgWgpFghSTxLiXKKA8,38405
7
11
  vectorvein/chat_clients/baichuan_client.py,sha256=CVMvpgjdrZGv0BWnTOBD-f2ufZ3wq3496wqukumsAr4,526
@@ -18,7 +22,7 @@ vectorvein/chat_clients/openai_compatible_client.py,sha256=H20SXdvXalf7_jaashff_
18
22
  vectorvein/chat_clients/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
23
  vectorvein/chat_clients/qwen_client.py,sha256=-ryh-m9PgsO0fc4ulcCmPTy1155J8YUy15uPoJQOHA0,513
20
24
  vectorvein/chat_clients/stepfun_client.py,sha256=zsD2W5ahmR4DD9cqQTXmJr3txrGuvxbRWhFlRdwNijI,519
21
- vectorvein/chat_clients/utils.py,sha256=Xt-9Dm564SY0jRO4N9ArDcFDKZIdfh9pYMxshLRMfUc,24853
25
+ vectorvein/chat_clients/utils.py,sha256=r8tlt-suUjISSRjc_tCCcBYmQT3zng1YFVnQgeAG1Co,25041
22
26
  vectorvein/chat_clients/xai_client.py,sha256=eLFJJrNRJ-ni3DpshODcr3S1EJQLbhVwxyO1E54LaqM,491
23
27
  vectorvein/chat_clients/yi_client.py,sha256=RNf4CRuPJfixrwLZ3-DEc3t25QDe1mvZeb9sku2f8Bc,484
24
28
  vectorvein/chat_clients/zhipuai_client.py,sha256=Ys5DSeLCuedaDXr3PfG1EW2zKXopt-awO2IylWSwY0s,519
@@ -31,7 +35,7 @@ vectorvein/types/enums.py,sha256=7KTJSVtQueImmbr1fSwv3rQVtc0RyMWXJmoE2tDOaso,166
31
35
  vectorvein/types/exception.py,sha256=gnW4GnJ76jND6UGnodk9xmqkcbeS7Cz2rvncA2HpD5E,69
32
36
  vectorvein/types/llm_parameters.py,sha256=9KJ8z_7xVa0JsV0YPxRKz5n8Eb8PfvB9Y89e6ahjmjw,5989
33
37
  vectorvein/types/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
- vectorvein/utilities/media_processing.py,sha256=CTRq-lGlFkFgP_FSRhNwF_qUgmOrXPf2_1Ok9HY42_g,5887
38
+ vectorvein/utilities/media_processing.py,sha256=7KtbLFzOYIn1e9QTN9G6C76NH8CBlV9kfAgiRKEIeXY,6263
35
39
  vectorvein/utilities/rate_limiter.py,sha256=dwolIUVw2wP83Odqpx0AAaE77de1GzxkYDGH4tM_u_4,10300
36
40
  vectorvein/utilities/retry.py,sha256=6KFS9R2HdhqM3_9jkjD4F36ZSpEx2YNFGOVlpOsUetM,2208
37
41
  vectorvein/workflow/graph/edge.py,sha256=xLZEJmBjAfVB53cd7CuRcKhgE6QqXv9nz32wJn8cmyk,1064
@@ -55,4 +59,4 @@ vectorvein/workflow/nodes/vector_db.py,sha256=t6I17q6iR3yQreiDHpRrksMdWDPIvgqJs0
55
59
  vectorvein/workflow/nodes/video_generation.py,sha256=qmdg-t_idpxq1veukd-jv_ChICMOoInKxprV9Z4Vi2w,4118
56
60
  vectorvein/workflow/nodes/web_crawlers.py,sha256=LsqomfXfqrXfHJDO1cl0Ox48f4St7X_SL12DSbAMSOw,5415
57
61
  vectorvein/workflow/utils/json_to_code.py,sha256=F7dhDy8kGc8ndOeihGLRLGFGlquoxVlb02ENtxnQ0C8,5914
58
- vectorvein-0.1.94.dist-info/RECORD,,
62
+ vectorvein-0.2.0.dist-info/RECORD,,
@@ -1,26 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: vectorvein
3
- Version: 0.1.94
4
- Summary: VectorVein python SDK
5
- Author-Email: Anderson <andersonby@163.com>
6
- License: MIT
7
- Requires-Python: >=3.10
8
- Requires-Dist: openai>=1.37.1
9
- Requires-Dist: tiktoken>=0.7.0
10
- Requires-Dist: httpx>=0.27.0
11
- Requires-Dist: anthropic[bedrock,vertex]>=0.31.2
12
- Requires-Dist: pydantic>=2.8.2
13
- Requires-Dist: Pillow>=10.4.0
14
- Requires-Dist: deepseek-tokenizer>=0.1.0
15
- Requires-Dist: qwen-tokenizer>=0.2.0
16
- Requires-Dist: google-auth>=2.35.0
17
- Provides-Extra: server
18
- Requires-Dist: fastapi; extra == "server"
19
- Requires-Dist: uvicorn; extra == "server"
20
- Provides-Extra: redis
21
- Requires-Dist: redis; extra == "redis"
22
- Provides-Extra: diskcache
23
- Requires-Dist: diskcache; extra == "diskcache"
24
- Description-Content-Type: text/markdown
25
-
26
- # vectorvein