-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathasync_usage.py
More file actions
155 lines (119 loc) · 5.6 KB
/
async_usage.py
File metadata and controls
155 lines (119 loc) · 5.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
"""Async client — why AsyncClient and when to use it.
AsyncClient has the same API as SyncClient — just add async with,
await, and async for. The real difference is concurrency:
SyncClient: every HTTP request blocks the thread.
Operations are always sequential.
AsyncClient: the event loop handles I/O in the background.
Multiple operations run concurrently on one thread.
This matters when you need to:
- Generate several images at the same time
- Stream responses from multiple characters simultaneously
- Build bots or servers that handle many users at once
In this example, we:
- Generate 3 images concurrently with asyncio.gather()
- Stream 2 character chats at the same time with TaskGroup
See auth.py for authentication examples (works identically with AsyncClient).
Requires:
SEAART_EMAIL and SEAART_PASSWORD environment variables.
"""
from __future__ import annotations
import asyncio
import os
from seaart import AsyncClient
from seaart.helpers import extract_character_link, extract_model_link
from seaart.types import AppId
CHARACTER_URL_A = (
"https://www.seaart.ai/ru/character/chat/d5f5v2te878c73cmjhhg?from=null&s_id=123"
)
CHARACTER_URL_B = (
"https://www.seaart.ai/ru/character/chat/d5f5v2te878c73cmjhhg?from=null&s_id=456"
)
MODEL_URL = "https://www.seaart.ai/create/image?id=cu8d8ble878c738hejd0&model_ver_no=f1ebdcc036b767a672db420eb367688d"
# ---------------------------------------------------------------------------
# Concurrent image generation
# ---------------------------------------------------------------------------
async def concurrent_image_generation() -> None:
"""Generate several images at the same time.
With SyncClient, three text_to_img calls run one after another —
total time = sum of all three generation times.
Here we submit all tasks first (each await is just the short HTTP POST,
not the generation itself), then wait for all of them concurrently.
Total time ≈ time of the slowest single task.
SyncClient has wait_many() for concurrent polling, but the submissions
themselves are still blocking one-by-one. With AsyncClient both
submission and waiting are fully concurrent.
"""
model = extract_model_link(MODEL_URL)
assert model is not None
async with AsyncClient() as client:
await client.auth.login(
email=os.environ["SEAART_EMAIL"],
password=os.environ["SEAART_PASSWORD"],
)
# Submit all three tasks — each await returns immediately
# after the server accepts the request.
t1 = await client.images.text_to_img(
"a serene mountain lake at dawn, oil painting", model.model_no
)
t2 = await client.images.text_to_img(
"cyberpunk city street in heavy rain, neon reflections", model.model_no
)
t3 = await client.images.text_to_img(
"a fox sitting in an autumn forest, watercolor", model.model_no
)
print(f"Tasks submitted: {t1.value.id}, {t2.value.id}, {t3.value.id}")
# Poll all three concurrently — they don't block each other.
results = await asyncio.gather(
t1.wait(timeout=180),
t2.wait(timeout=180),
t3.wait(timeout=180),
)
print("All done:")
for item in results:
print(f" {item.image_url}")
# ---------------------------------------------------------------------------
# Concurrent character streaming
# ---------------------------------------------------------------------------
async def concurrent_character_streams() -> None:
"""Stream responses from two characters at the same time.
This is impossible with SyncClient without threads — a synchronous
SSE stream blocks the thread for its entire duration. You literally
cannot read from two streams at once.
AsyncClient suspends each coroutine while waiting for the next chunk,
so both streams make progress concurrently on a single thread.
"""
link_a = extract_character_link(CHARACTER_URL_A)
link_b = extract_character_link(CHARACTER_URL_B)
assert link_a is not None and link_b is not None
async with AsyncClient(app_id=AppId.APP) as client:
await client.auth.login(
email=os.environ["SEAART_EMAIL"],
password=os.environ["SEAART_PASSWORD"],
)
async def stream_character(character_id: str, question: str) -> None:
"""Open a session, stream the reply, then clean up."""
chat = await client.characters.chats.create(character_id)
session_id = chat.value.session_id
await client.characters.chats.start(session_id)
try:
async for item in client.characters.chats.stream(
question, session_id
):
if item.event == "chunk":
# Prefix so you can tell the characters apart.
tag = character_id[:8]
print(f"[{tag}] {item.content}", end="", flush=True)
elif item.event == "end":
print()
finally:
await client.characters.chats.delete(session_id)
# Both coroutines run concurrently on the same event loop.
async with asyncio.TaskGroup() as tg:
tg.create_task(
stream_character(link_a.character_id, "Tell me about yourself.")
)
tg.create_task(
stream_character(link_b.character_id, "What's your favorite story?")
)
if __name__ == "__main__":
asyncio.run(concurrent_image_generation())