Skip to content

Commit fad6778

Browse files
author
修杰
committed
Merge 'integration_2025-03-27_808630449922' into 'master'
merge branch integration_2025-03-27_808630449922 into master See merge request: !553
2 parents 97e5160 + 341c242 commit fad6778

File tree

63 files changed

+2664
-333
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+2664
-333
lines changed

meta.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"lasted": "1.1.0",
3-
"meta_commit": "fb5ff08e537bd963d0f03359b644c7347f2a0645"
2+
"lasted": "1.1.1",
3+
"meta_commit": "eb656d5036a263d4e68911ee390d36802e05547b"
44
}

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from setuptools import setup, find_packages # noqa: H301
44

55
NAME = "volcengine-python-sdk"
6-
VERSION = "1.0.130"
6+
VERSION = "1.1.1"
77
# To install the library, run the following
88
#
99
# python setup.py install
Lines changed: 75 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,83 @@
1-
from datetime import datetime, timedelta
1+
import asyncio
2+
import time
3+
import uuid
4+
import threading
25

36

4-
class ModelBreaker:
7+
class _QuerySet(object):
8+
def __init__(self):
9+
self._items = list()
10+
self._index = dict()
11+
self._lock = threading.Lock()
12+
13+
def add(self, item: int) -> None:
14+
with self._lock:
15+
if item in self._index:
16+
return
17+
18+
self._items.append(item)
19+
self._index[item] = len(self._items) - 1
20+
21+
def remove(self, item: int) -> None:
22+
with self._lock:
23+
if item not in self._index:
24+
return
25+
26+
index = self._index[item]
27+
self._items[index] = self._items[-1]
28+
self._index[self._items[-1]] = index
29+
self._items.pop()
30+
del self._index[item]
31+
32+
def query(self, item: int) -> int:
33+
with self._lock:
34+
return self._index[item]
35+
36+
37+
class ModelBreaker(object):
538
def __init__(self):
639
# 初始化 allow_time 为当前时间
7-
self.allow_time = datetime.now()
40+
self._allow_time = time.perf_counter()
41+
self._waiters = _QuerySet()
842

9-
def allow(self):
10-
# 检查当前时间是否在 allow_time 之后
11-
return datetime.now() > self.allow_time
43+
def _allow(self, id: int) -> bool:
44+
cur = time.perf_counter()
45+
# 如果当前时间小于等于 allow_time,不允许通过
46+
if cur <= self._allow_time:
47+
return 0
48+
# 如果当前时间与 allow_time 的差值大于 10,允许通过
49+
if cur - self._allow_time > 10:
50+
return True
51+
# 如果当前时间与 allow_time 的差值小于等于 10,慢启动通过
52+
return self._waiters.query(id) < 2 ** (cur - self._allow_time)
1253

13-
def reset(self, duration):
54+
def _get_allowed_duration(self) -> float:
55+
# 计算当前时间与 allow_time 之间的持续时间
56+
allow_duration = self._allow_time - time.perf_counter()
57+
58+
# 至少有 1 秒的等待时间
59+
return max(allow_duration, 1)
60+
61+
def _acquire(self) -> int:
62+
id = uuid.uuid4().int
63+
self._waiters.add(id)
64+
return id
65+
66+
def _release(self, id: int) -> None:
67+
self._waiters.remove(id)
68+
69+
def reset(self, duration: float) -> None:
1470
# 将 allow_time 重置为当前时间加上指定的持续时间
15-
self.allow_time = datetime.now() + timedelta(seconds=duration.total_seconds())
71+
self._allow_time = time.perf_counter() + duration
1672

17-
def get_allowed_duration(self):
18-
# 计算当前时间与 allow_time 之间的持续时间
19-
allow_duration = self.allow_time - datetime.now()
20-
# 如果持续时间为负,则返回一个零时长的 timedelta 对象
21-
if allow_duration.total_seconds() < 0:
22-
return timedelta(0)
23-
return allow_duration
73+
def wait(self) -> None:
74+
id = self._acquire()
75+
while not self._allow(id):
76+
time.sleep(self._get_allowed_duration())
77+
self._release(id)
78+
79+
async def asyncwait(self) -> None:
80+
id = self._acquire()
81+
while not self._allow(id):
82+
await asyncio.sleep(self._get_allowed_duration())
83+
self._release(id)

volcenginesdkarkruntime/resources/batch_chat/completions.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,7 @@ def create(
149149
last_time = self._get_request_last_time(timeout)
150150
model_breaker = self._client.get_model_breaker(model)
151151
while True:
152-
while not model_breaker.allow():
153-
if datetime.now() + timedelta(seconds=model_breaker.get_allowed_duration().total_seconds()) > last_time:
154-
raise ArkAPITimeoutError()
155-
time.sleep(model_breaker.get_allowed_duration().total_seconds())
152+
model_breaker.wait()
156153
if datetime.now() > last_time:
157154
raise ArkAPITimeoutError()
158155
try:
@@ -198,7 +195,7 @@ def create(
198195
except ArkAPIStatusError as err:
199196
retry_after = _get_retry_after(err.response)
200197
if retry_after is not None:
201-
model_breaker.reset(timedelta(seconds=retry_after))
198+
model_breaker.reset(retry_after)
202199
if _should_retry(err.response):
203200
continue
204201
else:
@@ -295,10 +292,7 @@ async def create(
295292
last_time = self._get_request_last_time(timeout)
296293
model_breaker = await self._client.get_model_breaker(model)
297294
while True:
298-
while not model_breaker.allow():
299-
if datetime.now() + timedelta(seconds=model_breaker.get_allowed_duration().total_seconds()) > last_time:
300-
raise ArkAPITimeoutError()
301-
await asyncio.sleep(model_breaker.get_allowed_duration().total_seconds())
295+
await model_breaker.asyncwait()
302296
if datetime.now() > last_time:
303297
raise ArkAPITimeoutError()
304298
try:
@@ -344,7 +338,7 @@ async def create(
344338
except ArkAPIStatusError as err:
345339
retry_after = _get_retry_after(err.response)
346340
if retry_after is not None:
347-
model_breaker.reset(timedelta(seconds=retry_after))
341+
model_breaker.reset(retry_after)
348342
if _should_retry(err.response):
349343
continue
350344
else:

volcenginesdkcore/api_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def __init__(self, configuration=None, header_name=None, header_value=None,
6767
self.default_headers[header_name] = header_value
6868
self.cookie = cookie
6969
# Set default User-Agent.
70-
self.user_agent = 'volcstack-python-sdk/1.0.130'
70+
self.user_agent = 'volcstack-python-sdk/1.1.1'
7171
self.client_side_validation = configuration.client_side_validation
7272

7373
def __del__(self):

volcenginesdkcore/configuration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,5 +221,5 @@ def to_debug_report(self):
221221
"OS: {env}\n"\
222222
"Python Version: {pyversion}\n"\
223223
"Version of the API: 0.1.0\n"\
224-
"SDK Package Version: 1.0.130".\
224+
"SDK Package Version: 1.1.1".\
225225
format(env=sys.platform, pyversion=sys.version)

volcenginesdkexamples/volcenginesdkarkruntime/async_batch_chat_completions.py

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,8 @@
22
import sys
33
from datetime import datetime
44

5-
import uvloop
6-
75
from volcenginesdkarkruntime import AsyncArk
86

9-
107
# Authentication
118
# 1.If you authorize your endpoint using an API key, you can set your api key to environment variable "ARK_API_KEY"
129
# or specify api key by Ark(api_key="${YOUR_API_KEY}").
@@ -18,45 +15,67 @@
1815
# To get your ak&sk, please refer to this document(https://www.volcengine.com/docs/6291/65568)
1916
# For more information,please check this document(https://www.volcengine.com/docs/82379/1263279)
2017

21-
async def worker(worker_id, task_num):
22-
client = AsyncArk()
18+
19+
async def worker(
20+
worker_id: int,
21+
client: AsyncArk,
22+
requests: asyncio.Queue[dict],
23+
):
2324
print(f"Worker {worker_id} is starting.")
24-
for i in range(task_num):
25-
print(f"Worker {worker_id} task {i} is running.")
25+
26+
while True:
27+
request = await requests.get()
2628
try:
27-
completion = await client.batch_chat.completions.create(
28-
model="${YOUR_ENDPOINT_ID}",
29-
messages=[
30-
{"role": "system", "content": "你是豆包,是由字节跳动开发的 AI 人工智能助手"},
31-
{"role": "user", "content": "常见的十字花科植物有哪些?"},
32-
],
33-
)
34-
print(completion.choices[0].message.content)
29+
completion = await client.batch_chat.completions.create(**request)
30+
print(completion)
3531
except Exception as e:
36-
print(f"Worker {worker_id} task {i} failed with error: {e}")
37-
else:
38-
print(f"Worker {worker_id} task {i} is completed.")
39-
print(f"Worker {worker_id} is completed.")
32+
print(e, file=sys.stderr)
33+
finally:
34+
requests.task_done()
4035

4136

4237
async def main():
4338
start = datetime.now()
44-
max_concurrent_tasks = 1000
45-
task_num = 5
39+
max_concurrent_tasks, task_num = 1000, 10000
40+
41+
requests = asyncio.Queue()
42+
client = AsyncArk(timeout=24 * 3600)
43+
44+
# mock `task_num` tasks
45+
for _ in range(task_num):
46+
await requests.put(
47+
{
48+
"model": "${YOUR_ENDPOINT_ID}",
49+
"messages": [
50+
{
51+
"role": "system",
52+
"content": "你是豆包,是由字节跳动开发的 AI 人工智能助手",
53+
},
54+
{"role": "user", "content": "常见的十字花科植物有哪些?"},
55+
],
56+
}
57+
)
58+
59+
# create `max_concurrent_tasks` workers and start them
60+
tasks = [
61+
asyncio.create_task(worker(i, client, requests))
62+
for i in range(max_concurrent_tasks)
63+
]
64+
65+
# wait for all requests is done
66+
await requests.join()
67+
68+
# stop workers
69+
for task in tasks:
70+
task.cancel()
4671

47-
# 创建任务列表
48-
tasks = [worker(i, task_num) for i in range(max_concurrent_tasks)]
72+
# wait for all workers is canceled
73+
await asyncio.gather(*tasks, return_exceptions=True)
74+
await client.close()
4975

50-
# 等待所有任务完成
51-
await asyncio.gather(*tasks)
5276
end = datetime.now()
53-
print(f"Total time: {end - start}, Total task: {max_concurrent_tasks * task_num}")
77+
print(f"Total time: {end - start}, Total task: {task_num}")
5478

5579

5680
if __name__ == "__main__":
57-
if sys.version_info >= (3, 11):
58-
with asyncio.Runner(loop_factory=uvloop.new_event_loop) as runner:
59-
runner.run(main())
60-
else:
61-
uvloop.install()
62-
asyncio.run(main())
81+
asyncio.run(main())
Lines changed: 74 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
import queue
2+
import sys
3+
from datetime import datetime
4+
from multiprocessing.pool import ThreadPool
5+
16
from volcenginesdkarkruntime import Ark
27

38
# Authentication
@@ -10,16 +15,74 @@
1015
# or specify ak&sk by Ark(ak="${YOUR_AK}", sk="${YOUR_SK}").
1116
# To get your ak&sk, please refer to this document(https://www.volcengine.com/docs/6291/65568)
1217
# For more information,please check this document(https://www.volcengine.com/docs/82379/1263279)
13-
client = Ark()
18+
19+
20+
def worker(
21+
worker_id: int,
22+
client: Ark,
23+
requests: queue.Queue[dict],
24+
):
25+
print(f"Worker {worker_id} is starting.")
26+
27+
while True:
28+
request = requests.get()
29+
30+
# check for signal of no more request
31+
if not request:
32+
# put back on the queue for other workers
33+
requests.put(request)
34+
return
35+
36+
try:
37+
# do request
38+
completion = client.batch_chat.completions.create(**request)
39+
print(completion)
40+
except Exception as e:
41+
print(e, file=sys.stderr)
42+
finally:
43+
requests.task_done()
44+
45+
46+
def main():
47+
start = datetime.now()
48+
max_concurrent_tasks, task_num = 1000, 10000
49+
50+
requests = queue.Queue()
51+
client = Ark(timeout=24 * 3600)
52+
53+
# mock `task_num` tasks
54+
for _ in range(task_num):
55+
requests.put(
56+
{
57+
"model": "${YOUR_ENDPOINT_ID}",
58+
"messages": [
59+
{
60+
"role": "system",
61+
"content": "你是豆包,是由字节跳动开发的 AI 人工智能助手",
62+
},
63+
{"role": "user", "content": "常见的十字花科植物有哪些?"},
64+
],
65+
}
66+
)
67+
68+
# put a signal of no more request
69+
requests.put(None)
70+
71+
# create `max_concurrent_tasks` workers and start them
72+
with ThreadPool(max_concurrent_tasks) as pool:
73+
for i in range(max_concurrent_tasks):
74+
pool.apply_async(worker, args=(i, client, requests))
75+
pool.apply_async(worker, args=(i, client, requests))
76+
77+
# wait for all request to done
78+
pool.close()
79+
pool.join()
80+
81+
client.close()
82+
83+
end = datetime.now()
84+
print(f"Total time: {end - start}, Total task: {task_num}")
85+
1486

1587
if __name__ == "__main__":
16-
# Non-streaming:
17-
print("----- standard request -----")
18-
completion = client.batch_chat.completions.create(
19-
model="${YOUR_ENDPOINT_ID}",
20-
messages=[
21-
{"role": "system", "content": "你是豆包,是由字节跳动开发的 AI 人工智能助手"},
22-
{"role": "user", "content": "常见的十字花科植物有哪些?"},
23-
],
24-
)
25-
print(completion.choices[0].message.content)
88+
main()

0 commit comments

Comments
 (0)