Skip to content

Commit 8e1add3

Browse files
committed
fix(llm): use non-greedy quantifier when stripping bracket and paren groups from script
format_response used re.sub(r"\[.*\]", ...) and re.sub(r"\(.*\)", ...). The greedy .* matches from the first opener to the *last* closer on the same line, silently deleting all intervening content. Examples of silent data loss: "[Intro] Great content [end]" → "." "Save (at least) 10% (monthly)." → "Save ." Replacing .* with .*? makes each substitution non-greedy so that every bracket/paren group is removed individually, leaving surrounding words intact. Add a unit test that feeds a two-group input through generate_script and asserts the text between groups is preserved.
1 parent 465b8b3 commit 8e1add3

2 files changed

Lines changed: 40 additions & 3 deletions

File tree

app/services/llm.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -536,9 +536,11 @@ def format_response(response):
536536
response = response.replace("*", "")
537537
response = response.replace("#", "")
538538

539-
# Remove markdown syntax
540-
response = re.sub(r"\[.*\]", "", response)
541-
response = re.sub(r"\(.*\)", "", response)
539+
# Remove markdown syntax. Use non-greedy .*? so each bracket/paren
540+
# group is removed independently; the greedy form would eat all text
541+
# between the first opener and the last closer on the same line.
542+
response = re.sub(r"\[.*?\]", "", response)
543+
response = re.sub(r"\(.*?\)", "", response)
542544

543545
# Split the script into paragraphs
544546
paragraphs = response.split("\n\n")

test/services/test_llm.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,41 @@ def fake_generate_response(prompt, app_config=None):
155155
self.assertIs(captured["app_config"], app_config)
156156
self.assertEqual(captured["app_config"]["openai_api_key"], "snapshot-key")
157157

158+
def test_generate_script_strips_each_bracket_group_independently(self):
159+
"""
160+
format_response must remove each [bracket] and (paren) group in
161+
isolation. The greedy form [.*] matches from the first opener to
162+
the *last* closer on the line, silently deleting all text in between.
163+
164+
Example – greedy bug:
165+
"[Intro] Great content [end]" → "." (all inner text lost)
166+
Expected with non-greedy fix:
167+
"[Intro] Great content [end]" → " Great content "
168+
"""
169+
170+
def fake_generate_response(prompt):
171+
# Two bracket groups and two paren groups on the same line.
172+
return (
173+
"[Scene: Beach] A beautiful day at the [location: ocean].\n\n"
174+
"Save (at least) 10% of your income (monthly)."
175+
)
176+
177+
with patch.object(
178+
llm, "_generate_response", side_effect=fake_generate_response
179+
):
180+
result = llm.generate_script(
181+
video_subject="savings tips", language="en-US"
182+
)
183+
184+
# Each bracket / paren group should be gone, but the surrounding words
185+
# must survive.
186+
self.assertNotIn("[", result)
187+
self.assertNotIn("]", result)
188+
self.assertNotIn("(", result)
189+
self.assertNotIn(")", result)
190+
self.assertIn("A beautiful day at the", result)
191+
self.assertIn("10% of your income", result)
192+
158193
def test_generate_terms_can_request_script_ordered_keywords(self):
159194
"""
160195
按文案顺序匹配素材依赖 LLM 返回有序关键词。这里不调用真实模型,

0 commit comments

Comments
 (0)