From e7e03901eecddb657ddaa22ea14f5cb72956016f Mon Sep 17 00:00:00 2001 From: Steve Tietze Date: Fri, 9 Jan 2026 16:04:33 +0700 Subject: [PATCH] changed timeout value and some other fixes --- README.md | 5 +-- kie_api/jobs.py | 7 +++- kie_api/kling26_i2v.py | 4 +- kie_api/kling26_t2v.py | 2 +- kie_api/kling26motion_i2v.py | 4 +- kie_api/prompt_lists.py | 62 ++++++++++++++++++++++++++++++- kie_api/seedance15pro_i2v.py | 2 +- kie_api/seedancev1pro_fast_i2v.py | 2 +- nodes.py | 6 +-- 9 files changed, 77 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index dd3346d..653ea7d 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ This node pack currently includes the following nodes: ### Generation Nodes -- **NanoBanana Image** +- **Nano Banana Pro Image** - Image generation node using the Googles Nano Banana Pro model via the Kie.ai API. - **Seedream Text-to-Image / Edit** @@ -56,7 +56,7 @@ Kie.ai is a unified API and model marketplace for image, video, and audio genera Kie.ai uses a credit-based model for requests. There is no subscription requirement, and pay-as-you-go usage is supported. ## Debugging and job visibility -You can review request history and results at https://kie.ai/logs. +You can review request history and results at https://kie.ai/logs. Some models can take longer to finish; the default timeout has been increased to reduce false failures. ## Disclaimer This software is provided as-is. You are responsible for managing your own API usage and credits. @@ -83,4 +83,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/kie_api/jobs.py b/kie_api/jobs.py index 2bf0c88..dee5946 100644 --- a/kie_api/jobs.py +++ b/kie_api/jobs.py @@ -19,6 +19,7 @@ from .log import _log RECORD_INFO_URL = "https://api.kie.ai/api/v1/jobs/recordInfo" +DEFAULT_TIMEOUT_S = 1000 def _fetch_task_record(api_key: str, task_id: str) -> tuple[dict[str, Any], str, Any]: @@ -108,16 +109,18 @@ def _poll_task_until_complete( """ # Ensure we never poll faster than once per second to reduce server load. interval = poll_interval_s if poll_interval_s > 0 else 1.0 + effective_timeout_s = timeout_s if timeout_s >= DEFAULT_TIMEOUT_S else DEFAULT_TIMEOUT_S last_state = None last_log_time = start_time while True: now = time.time() elapsed = now - start_time - if elapsed > timeout_s: + if elapsed > effective_timeout_s: last_state_text = last_state if last_state is not None else "unknown" raise RuntimeError( - f"Task {task_id} timed out after {timeout_s}s (last state={last_state_text}, elapsed={elapsed:.1f}s). " + f"Task {task_id} timed out after {effective_timeout_s}s " + f"(last state={last_state_text}, elapsed={elapsed:.1f}s). " "Try increasing timeout or retry." ) diff --git a/kie_api/kling26_i2v.py b/kie_api/kling26_i2v.py index 975efac..cc6c50a 100644 --- a/kie_api/kling26_i2v.py +++ b/kie_api/kling26_i2v.py @@ -78,7 +78,7 @@ def run_kling26_i2v_video( duration: str = "5", sound: bool = False, poll_interval_s: float = 10.0, - timeout_s: int = 900, + timeout_s: int = 1000, log: bool = True, ) -> dict: _validate_prompt(prompt, max_length=PROMPT_MAX_LENGTH) @@ -137,7 +137,7 @@ def run_kling26_i2v( duration: str = "5", sound: bool = False, poll_interval_s: float = 10.0, - timeout_s: int = 900, + timeout_s: int = 1000, log: bool = True, ) -> dict: """Backward-compatible alias for existing imports.""" diff --git a/kie_api/kling26_t2v.py b/kie_api/kling26_t2v.py index 6befccc..08bea23 100644 --- a/kie_api/kling26_t2v.py +++ b/kie_api/kling26_t2v.py @@ -79,7 +79,7 @@ def run_kling26_t2v( aspect_ratio: str = "9:16", duration: str = "5", poll_interval_s: float = 10.0, - timeout_s: int = 900, + timeout_s: int = 1000, log: bool = True, ) -> dict: """Backward-compatible alias for existing imports.""" diff --git a/kie_api/kling26motion_i2v.py b/kie_api/kling26motion_i2v.py index 14a566a..3270259 100644 --- a/kie_api/kling26motion_i2v.py +++ b/kie_api/kling26motion_i2v.py @@ -88,7 +88,7 @@ def run_kling26motion_i2v_video( character_orientation: str = "video", mode: str = "720p", poll_interval_s: float = 10.0, - timeout_s: int = 900, + timeout_s: int = 1000, log: bool = True, ) -> Any: # Validate prompt length and required inputs. @@ -167,7 +167,7 @@ def run_kling26motion_i2v( character_orientation: str = "video", mode: str = "720p", poll_interval_s: float = 10.0, - timeout_s: int = 900, + timeout_s: int = 1000, log: bool = True, ) -> Any: """Backward-compatible alias for existing imports.""" diff --git a/kie_api/prompt_lists.py b/kie_api/prompt_lists.py index 327c7be..0d00b95 100644 --- a/kie_api/prompt_lists.py +++ b/kie_api/prompt_lists.py @@ -46,10 +46,68 @@ def parse_prompts_json(text: str, max_items: int = 9, strict: bool = False) -> l raise ValueError("json_text is empty.") return [] + def _strip_code_fences(value: str) -> str: + stripped = value.strip() + if stripped.startswith("```"): + lines = stripped.splitlines() + if len(lines) >= 2 and lines[0].startswith("```") and lines[-1].strip().startswith("```"): + return "\n".join(lines[1:-1]).strip() + return stripped + + def _extract_first_json(value: str) -> str | None: + start = None + opening = None + for idx, ch in enumerate(value): + if ch == "{" or ch == "[": + start = idx + opening = ch + break + if start is None or opening is None: + return None + + closing = "}" if opening == "{" else "]" + depth = 0 + in_string = False + escape = False + for idx in range(start, len(value)): + ch = value[idx] + if in_string: + if escape: + escape = False + elif ch == "\\": + escape = True + elif ch == "\"": + in_string = False + continue + + if ch == "\"": + in_string = True + continue + if ch == opening: + depth += 1 + elif ch == closing: + depth -= 1 + if depth == 0: + return value[start:idx + 1] + return None + + payload = None try: payload = json.loads(raw) - except json.JSONDecodeError as exc: - raise ValueError("Failed to parse JSON from json_text.") from exc + except json.JSONDecodeError: + cleaned = _strip_code_fences(raw) + try: + payload = json.loads(cleaned) + except json.JSONDecodeError: + extracted = _extract_first_json(cleaned) + if extracted is not None: + try: + payload = json.loads(extracted) + except json.JSONDecodeError: + payload = None + + if payload is None: + raise ValueError("Failed to parse JSON from json_text. Ensure the input contains a JSON object or array.") prompts: list[str] = [] diff --git a/kie_api/seedance15pro_i2v.py b/kie_api/seedance15pro_i2v.py index 62521cf..fc56753 100644 --- a/kie_api/seedance15pro_i2v.py +++ b/kie_api/seedance15pro_i2v.py @@ -239,7 +239,7 @@ Outputs: generate_audio: bool = False, log: bool = True, poll_interval_s: float = 10.0, - timeout_s: int = 900, + timeout_s: int = 1000, ): video_output = run_seedance15pro_i2v_video( prompt=prompt, diff --git a/kie_api/seedancev1pro_fast_i2v.py b/kie_api/seedancev1pro_fast_i2v.py index 04b4543..11e2655 100644 --- a/kie_api/seedancev1pro_fast_i2v.py +++ b/kie_api/seedancev1pro_fast_i2v.py @@ -200,7 +200,7 @@ Outputs: duration: str = "5", log: bool = True, poll_interval_s: float = 10.0, - timeout_s: int = 900, + timeout_s: int = 1000, ): video_output = run_seedancev1pro_fast_i2v_video( prompt=prompt, diff --git a/nodes.py b/nodes.py index 8175e3a..72b0a26 100644 --- a/nodes.py +++ b/nodes.py @@ -295,7 +295,7 @@ Outputs: sound: bool = False, log: bool = True, poll_interval_s: float = 10.0, - timeout_s: int = 900, + timeout_s: int = 1000, retry_on_fail: bool = True, max_retries: int = 2, retry_backoff_s: float = 3.0, @@ -368,7 +368,7 @@ Outputs: duration: str = "5", log: bool = True, poll_interval_s: float = 10.0, - timeout_s: int = 900, + timeout_s: int = 1000, retry_on_fail: bool = True, max_retries: int = 2, retry_backoff_s: float = 3.0, @@ -447,7 +447,7 @@ Outputs: mode: str = "720p", log: bool = True, poll_interval_s: float = 10.0, - timeout_s: int = 900, + timeout_s: int = 1000, retry_on_fail: bool = True, max_retries: int = 2, retry_backoff_s: float = 3.0,