Spaces:
Running
Running
Patryk Studzinski
commited on
Commit
·
0dfa1e4
1
Parent(s):
2de7977
Improve infill prompt and add fallback for non-JSON model outputs
Browse files- app/domains/cars/prompts.py +14 -30
- app/main.py +30 -1
app/domains/cars/prompts.py
CHANGED
|
@@ -34,8 +34,7 @@ Na podstawie poniższych danych, utwórz krótki, atrakcyjny opis marketingowy t
|
|
| 34 |
def create_infill_prompt(text_with_gaps: str, options: InfillOptions) -> list[dict]:
|
| 35 |
"""
|
| 36 |
Creates the chat prompt for gap-filling in car ads.
|
| 37 |
-
|
| 38 |
-
The LLM must return strict JSON with filled text and per-gap choices.
|
| 39 |
|
| 40 |
Args:
|
| 41 |
text_with_gaps: Ad text with [GAP:n] markers
|
|
@@ -47,41 +46,26 @@ def create_infill_prompt(text_with_gaps: str, options: InfillOptions) -> list[di
|
|
| 47 |
lang_instruction = "po polsku" if options.language == "pl" else "in English"
|
| 48 |
|
| 49 |
system_content = f"""Jesteś ekspertem od uzupełniania tekstów ogłoszeń samochodowych.
|
|
|
|
| 50 |
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
Każda luka powinna być uzupełniona słowem lub krótką frazą (1-4 słowa).
|
| 54 |
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
2. Uzupełnienia muszą pasować kontekstowo I gramatycznie
|
| 58 |
-
3. Używaj słownictwa typowego dla ogłoszeń motoryzacyjnych
|
| 59 |
-
4. Dla każdej luki podaj {options.top_n_per_gap} alternatywne propozycje
|
| 60 |
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
- "ma [GAP:3] przebieg" → uzupełnij BIERNIKIEM (np. "mały", "duży")
|
| 66 |
|
| 67 |
-
|
| 68 |
-
Input: "Mam [GAP:1] Mercedes w kolorze [GAP:2]."
|
| 69 |
-
Output:
|
| 70 |
{{
|
| 71 |
-
"filled_text": "
|
| 72 |
"gaps": [
|
| 73 |
-
{{"index": 1, "
|
| 74 |
-
{{"index": 2, "marker": "[GAP:2]", "choice": "czarnym", "alternatives": ["srebrnym", "białym"]}}
|
| 75 |
]
|
| 76 |
-
}}
|
| 77 |
-
|
| 78 |
-
WYMAGANY FORMAT ODPOWIEDZI - TYLKO JSON, BEZ KOMENTARZY!"""
|
| 79 |
-
|
| 80 |
-
user_content = f"""Uzupełnij luki w poniższym ogłoszeniu samochodowym:
|
| 81 |
-
|
| 82 |
-
{text_with_gaps}
|
| 83 |
-
|
| 84 |
-
Zwróć TYLKO JSON bez żadnych dodatkowych tekstów. Uzupełnij ALL gaps, w filled_text nie powinno być [GAP:n]!"""
|
| 85 |
|
| 86 |
return [
|
| 87 |
{"role": "system", "content": system_content},
|
|
|
|
| 34 |
def create_infill_prompt(text_with_gaps: str, options: InfillOptions) -> list[dict]:
|
| 35 |
"""
|
| 36 |
Creates the chat prompt for gap-filling in car ads.
|
| 37 |
+
Uses function-call format to force structured JSON output.
|
|
|
|
| 38 |
|
| 39 |
Args:
|
| 40 |
text_with_gaps: Ad text with [GAP:n] markers
|
|
|
|
| 46 |
lang_instruction = "po polsku" if options.language == "pl" else "in English"
|
| 47 |
|
| 48 |
system_content = f"""Jesteś ekspertem od uzupełniania tekstów ogłoszeń samochodowych.
|
| 49 |
+
Zawsze odpowiadasz TYLKO prawidłowym JSON-em, bez żadnych innych tekstów."""
|
| 50 |
|
| 51 |
+
# More direct instruction with explicit filling examples
|
| 52 |
+
user_content = f"""ZADANIE: Uzupełnij luki w ogłoszeniu samochodowym {lang_instruction}.
|
|
|
|
| 53 |
|
| 54 |
+
TEKST:
|
| 55 |
+
{text_with_gaps}
|
|
|
|
|
|
|
|
|
|
| 56 |
|
| 57 |
+
INSTRUKCJE:
|
| 58 |
+
1. Zastąp KAŻDY [GAP:n] rzeczywistym słowem/frazą (nie zostawiaj [GAP:n] w tekście!)
|
| 59 |
+
2. Pamiętaj o polskiej gramatyce (deklinacja)
|
| 60 |
+
3. Dla każdej luki podaj {options.top_n_per_gap} alternatywne słowa
|
|
|
|
| 61 |
|
| 62 |
+
ODPOWIEDŹ - TYLKO JSON:
|
|
|
|
|
|
|
| 63 |
{{
|
| 64 |
+
"filled_text": "tekst z uzupełnionymi lukami (BEZ [GAP:n])",
|
| 65 |
"gaps": [
|
| 66 |
+
{{"index": 1, "choice": "słowo1", "alternatives": ["alt1", "alt2"]}}
|
|
|
|
| 67 |
]
|
| 68 |
+
}}"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
|
| 70 |
return [
|
| 71 |
{"role": "system", "content": system_content},
|
app/main.py
CHANGED
|
@@ -422,7 +422,36 @@ async def process_infill_item(
|
|
| 422 |
parsed = parse_infill_json(raw_output)
|
| 423 |
|
| 424 |
if not parsed:
|
| 425 |
-
# JSON parsing failed
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 426 |
return InfillResult(
|
| 427 |
id=item.id,
|
| 428 |
status="error",
|
|
|
|
| 422 |
parsed = parse_infill_json(raw_output)
|
| 423 |
|
| 424 |
if not parsed:
|
| 425 |
+
# JSON parsing failed - try to extract fills from the raw output
|
| 426 |
+
# Model might have filled the text without JSON wrapper
|
| 427 |
+
print(f"[INFILL] JSON parsing failed, attempting fallback extraction")
|
| 428 |
+
print(f"[INFILL] Raw output: {raw_output[:300]}")
|
| 429 |
+
|
| 430 |
+
# If raw output contains the text with gaps filled (no [GAP:n]),
|
| 431 |
+
# it might be a valid response without JSON
|
| 432 |
+
if "[GAP:" not in raw_output:
|
| 433 |
+
# Model filled the gaps! Extract by comparing with original
|
| 434 |
+
filled_text = raw_output.strip()
|
| 435 |
+
|
| 436 |
+
# Try to build gaps list from what we know
|
| 437 |
+
gap_fills = []
|
| 438 |
+
for i, gap in enumerate(gaps, 1):
|
| 439 |
+
gap_fills.append(GapFill(
|
| 440 |
+
index=i,
|
| 441 |
+
marker=gap.marker,
|
| 442 |
+
choice="(model filled)",
|
| 443 |
+
alternatives=[]
|
| 444 |
+
))
|
| 445 |
+
|
| 446 |
+
return InfillResult(
|
| 447 |
+
id=item.id,
|
| 448 |
+
status="ok",
|
| 449 |
+
filled_text=filled_text,
|
| 450 |
+
gaps=gap_fills,
|
| 451 |
+
error=None
|
| 452 |
+
)
|
| 453 |
+
|
| 454 |
+
# Otherwise it's a real error
|
| 455 |
return InfillResult(
|
| 456 |
id=item.id,
|
| 457 |
status="error",
|