Commit 4af1723

benny-dou <60535774+benny-dou@users.noreply.github.com>
2026-01-25 02:35:40
fix(ai): refactor placeholder replacement to support nested structures
1 parent 813fe5a
Changed files (3)
src
ai
src/ai/images/post.py
@@ -2,7 +2,6 @@
 # -*- coding: utf-8 -*-
 import asyncio
 import base64
-import json
 from pathlib import Path
 
 import anyio
@@ -12,7 +11,7 @@ from pyrogram.client import Client
 from pyrogram.types import Message
 
 from ai.texts.contexts import base64_media
-from ai.utils import EMOJI_IMG_BOT, clean_cmd_prefix, prettify
+from ai.utils import EMOJI_IMG_BOT, clean_cmd_prefix, prettify, replace_placeholder
 from config import DOWNLOAD_DIR, PROXY
 from messages.progress import modify_progress
 from messages.sender import send2tg
@@ -202,17 +201,3 @@ async def waiting_modelscope_task(task_id: str, params: dict) -> tuple[list[str]
 
         await asyncio.sleep(5)
         resp = await hx_req(url, headers=headers, proxy=params.get("proxy"), check_keys=["task_status"])
-
-
-def replace_placeholder(data: dict, pairs: dict[str, str]) -> dict:
-    """Replace placeholder in data.
-
-    Args:
-        data: dict with placeholder
-    Returns:
-        dict with replaced placeholder
-    """
-    data_str = json.dumps(data, ensure_ascii=False)
-    for key, value in pairs.items():
-        data_str = data_str.replace(key, value)
-    return json.loads(data_str)
src/ai/videos/post.py
@@ -2,7 +2,6 @@
 # -*- coding: utf-8 -*-
 import asyncio
 import base64
-import json
 from pathlib import Path
 from typing import Literal
 
@@ -13,7 +12,7 @@ from pyrogram.client import Client
 from pyrogram.types import Message
 
 from ai.texts.contexts import base64_media
-from ai.utils import EMOJI_VIDEO_BOT, clean_cmd_prefix, prettify
+from ai.utils import EMOJI_VIDEO_BOT, clean_cmd_prefix, prettify, replace_placeholder
 from config import DOWNLOAD_DIR, PROXY
 from messages.progress import modify_progress
 from messages.sender import send2tg
@@ -196,17 +195,3 @@ async def waiting_seedance_task(task_id: str, params: dict) -> tuple[str, str]:
 
         await asyncio.sleep(5)
         resp = await hx_req(url, headers=headers, proxy=params.get("proxy"), check_keys=["status"])
-
-
-def replace_placeholder(data: dict, pairs: dict[str, str]) -> dict:
-    """Replace placeholder in data.
-
-    Args:
-        data: dict with placeholder
-    Returns:
-        dict with replaced placeholder
-    """
-    data_str = json.dumps(data, ensure_ascii=False)
-    for key, value in pairs.items():
-        data_str = data_str.replace(key, value)
-    return json.loads(data_str)
src/ai/utils.py
@@ -142,6 +142,28 @@ def beautify_llm_response(text: str, newline_level: int = 3) -> str:
     return remove_consecutive_newlines(clean_text, newline_level)
 
 
+def replace_placeholder(data: dict | list | str, pairs: dict[str, str]) -> dict | list | str:
+    """Replace placeholder in data.
+
+    Args:
+        data: nested dict with placeholder.
+        pairs: dict of placeholder and value. e.g. {"%PROMPT%": "prompt"}
+
+    Returns:
+        dict with replaced placeholder
+    """
+    if isinstance(data, dict):
+        return {key: replace_placeholder(value, pairs) for key, value in data.items()}
+    if isinstance(data, list):
+        return [replace_placeholder(item, pairs) for item in data]
+    if isinstance(data, str):
+        replaced_str = data
+        for placeholder, value in pairs.items():
+            replaced_str = replaced_str.replace(placeholder, value)
+        return replaced_str
+    return data
+
+
 async def clean_gemini_files():
     """Clean Gemini files.