Skip to content

Commit 277207a

Browse files
author
kevin
committed
fix: fix image synthesis parameter passing and resource leak issues#156
1 parent 9ad7bd9 commit 277207a

3 files changed

Lines changed: 98 additions & 4 deletions

File tree

dashscope/aigc/image_synthesis.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,8 @@ def async_call( # pylint: disable=arguments-renamed # type: ignore[override] #
464464
if color_palette is not None:
465465
kwargs["color_palette"] = color_palette
466466
task_group, f = _get_task_group_and_task(__name__)
467-
inputs, kwargs, task = cls._get_input(
467+
# pylint: disable=protected-access
468+
inputs, kwargs, task = ImageSynthesis._get_input(
468469
model,
469470
prompt,
470471
negative_prompt,
@@ -785,6 +786,30 @@ async def sync_call(
785786
Note: This method currently now only supports wan2.2-t2i-flash and wan2.2-t2i-plus. # noqa: E501 # pylint: disable=line-too-long
786787
Using other models will result in an error,More raw image models may be added for use later # pylint: disable=line-too-long
787788
"""
789+
if size is not None:
790+
kwargs["size"] = size
791+
if n is not None:
792+
kwargs["n"] = n
793+
if seed is not None:
794+
kwargs["seed"] = seed
795+
if style is not None:
796+
kwargs["style"] = style
797+
if ref_strength is not None:
798+
kwargs["ref_strength"] = ref_strength
799+
if ref_mode is not None:
800+
kwargs["ref_mode"] = ref_mode
801+
if prompt_extend is not None:
802+
kwargs["prompt_extend"] = prompt_extend
803+
if watermark is not None:
804+
kwargs["watermark"] = watermark
805+
if bbox_list is not None:
806+
kwargs["bbox_list"] = bbox_list
807+
if enable_sequential is not None:
808+
kwargs["enable_sequential"] = enable_sequential
809+
if thinking_mode is not None:
810+
kwargs["thinking_mode"] = thinking_mode
811+
if color_palette is not None:
812+
kwargs["color_palette"] = color_palette
788813
task_group, f = _get_task_group_and_task(__name__)
789814
# pylint: disable=protected-access
790815
inputs, kwargs, task = ImageSynthesis._get_input(
@@ -886,6 +911,30 @@ async def async_call( # type: ignore[override] # pylint: disable=arguments-ren
886911
DashScopeAPIResponse: The image synthesis
887912
task id in the response.
888913
"""
914+
if size is not None:
915+
kwargs["size"] = size
916+
if n is not None:
917+
kwargs["n"] = n
918+
if seed is not None:
919+
kwargs["seed"] = seed
920+
if style is not None:
921+
kwargs["style"] = style
922+
if ref_strength is not None:
923+
kwargs["ref_strength"] = ref_strength
924+
if ref_mode is not None:
925+
kwargs["ref_mode"] = ref_mode
926+
if prompt_extend is not None:
927+
kwargs["prompt_extend"] = prompt_extend
928+
if watermark is not None:
929+
kwargs["watermark"] = watermark
930+
if bbox_list is not None:
931+
kwargs["bbox_list"] = bbox_list
932+
if enable_sequential is not None:
933+
kwargs["enable_sequential"] = enable_sequential
934+
if thinking_mode is not None:
935+
kwargs["thinking_mode"] = thinking_mode
936+
if color_palette is not None:
937+
kwargs["color_palette"] = color_palette
889938
task_group, f = _get_task_group_and_task(__name__)
890939
# pylint: disable=protected-access
891940
inputs, kwargs, task = ImageSynthesis._get_input(

dashscope/api_entities/aio_session.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,46 @@ async def get_shared_aio_session() -> aiohttp.ClientSession:
4646

4747
connector = aiohttp.TCPConnector(ssl=get_ssl_context())
4848
session = aiohttp.ClientSession(connector=connector, trust_env=True)
49+
50+
# Register finalizer to close session when it's garbage collected.
51+
# This prevents resource leaks even if
52+
# close_shared_aio_session() is not called.
53+
weakref.finalize(session, _sync_close_session, id(session))
54+
4955
_aio_sessions[loop] = session
5056
return session
5157

5258

59+
def _sync_close_session(session_id: int) -> None:
60+
"""Synchronous callback when session is garbage collected.
61+
62+
Note: This runs during GC, so we cannot await. We try to close
63+
synchronously if possible, otherwise log a warning.
64+
"""
65+
try:
66+
loop = asyncio.get_event_loop()
67+
if not loop.is_closed() and not loop.is_running():
68+
# Loop exists and is not running, we can use it
69+
# Find the session in our cache
70+
with _lock:
71+
for stored_session in _aio_sessions.values():
72+
if (
73+
id(stored_session) == session_id
74+
and not stored_session.closed
75+
):
76+
try:
77+
loop.run_until_complete(stored_session.close())
78+
except Exception:
79+
pass
80+
break
81+
except RuntimeError:
82+
# No event loop available, can't close asynchronously
83+
pass
84+
except Exception:
85+
# Ignore errors during cleanup
86+
pass
87+
88+
5389
async def close_shared_aio_session() -> None:
5490
"""Close the shared session for the current event loop."""
5591
loop = asyncio.get_running_loop()

dashscope/audio/qwen_tts_realtime/qwen_tts_realtime.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -377,9 +377,18 @@ def on_message( # pylint: disable=unused-argument
377377
self.last_first_audio_delay,
378378
)
379379
except json.JSONDecodeError:
380-
logger.error("Failed to parse message as JSON.")
381-
# pylint: disable=broad-exception-raised,raise-missing-from
382-
raise Exception("Failed to parse message as JSON.")
380+
logger.error(
381+
"Failed to parse message as JSON: %s",
382+
message[:200],
383+
)
384+
# Do not raise exception here, let the connection stay alive.
385+
# Raising exception in callback can cause unexpected thread
386+
# termination.
387+
except Exception as e:
388+
logger.error("Error processing message: %s", str(e))
389+
# Do not raise exception here, let the connection stay alive.
390+
# Raising exception in callback can cause unexpected thread
391+
# termination.
383392
elif isinstance(message, (bytes, bytearray)):
384393
# If parsing fails, treat as binary message
385394
logger.error(

0 commit comments

Comments
 (0)