Spaces:
Running
Running
ming
commited on
Commit
Β·
d112a13
1
Parent(s):
17499f7
Fix buffer parsing and strengthen brevity constraints
Browse filesBuffer parsing fix:
- Parse remaining buffer content after streamer loop ends
- Fixes issue where {"op": "done"} was left unparsed
- Now properly detects completion signal from model
Brevity improvements:
- Reduced title limit: 8-12 words β 6-10 words MAX
- Reduced key points: 10-15 words β 8-12 words MAX
- Added explicit examples of SHORT titles
- Added CRITICAL BREVITY RULES section with caps warnings
- Emphasized 'BE SHORT!' throughout prompt
Expected results:
- Shorter, punchier titles (6-10 words)
- More concise key points
- Proper detection of completion signal
app/services/structured_summarizer.py
CHANGED
|
@@ -196,10 +196,10 @@ Do NOT add markdown code fences, comments, or explanations.
|
|
| 196 |
|
| 197 |
Your goal is to produce a BRIEF, CONCISE structured summary of an article in the following logical shape:
|
| 198 |
{
|
| 199 |
-
"title": string, //
|
| 200 |
-
"main_summary": string, // 2
|
| 201 |
-
"key_points": string[], // 3-5 items, each
|
| 202 |
-
"category": string, // 1-2 words (e.g. "Tech", "Politics")
|
| 203 |
"sentiment": string, // one of ["positive", "negative", "neutral"]
|
| 204 |
"read_time_min": number
|
| 205 |
}
|
|
@@ -210,28 +210,30 @@ Patch formats:
|
|
| 210 |
|
| 211 |
1) Set or overwrite a scalar field (title, main_summary, category, sentiment, read_time_min):
|
| 212 |
{"op": "set", "field": "<field_name>", "value": <value>}
|
| 213 |
-
Examples:
|
|
|
|
| 214 |
{"op": "set", "field": "title", "value": "AI Model Breakthrough"}
|
| 215 |
-
{"op": "set", "field": "category", "value": "
|
| 216 |
{"op": "set", "field": "sentiment", "value": "neutral"}
|
| 217 |
{"op": "set", "field": "read_time_min", "value": 3}
|
| 218 |
|
| 219 |
2) Append a key point to the key_points array:
|
| 220 |
{"op": "append", "field": "key_points", "value": "<one concise key fact>"}
|
| 221 |
-
|
| 222 |
-
{"op": "append", "field": "key_points", "value": "
|
|
|
|
| 223 |
|
| 224 |
3) At the very end, output exactly one final line to signal completion:
|
| 225 |
{"op": "done"}
|
| 226 |
|
| 227 |
Rules:
|
| 228 |
- You MUST always set all scalar fields before finishing:
|
| 229 |
-
1) First patch: {"op": "set", "field": "title", ...} [
|
| 230 |
-
2) Second patch: {"op": "set", "field": "main_summary", ...} [2
|
| 231 |
-
3) Third patch: {"op": "set", "field": "category", ...} [1-2 words]
|
| 232 |
4) Fourth patch: {"op": "set", "field": "sentiment", ...}
|
| 233 |
5) Fifth patch: {"op": "set", "field": "read_time_min", ...}
|
| 234 |
-
6) Then emit {"op": "append", "field": "key_points", ...} patches (3-5 items, each
|
| 235 |
7) Only AFTER all fields are set and 3-5 key_points have been appended,
|
| 236 |
output exactly one final line: {"op": "done"}.
|
| 237 |
- NEVER output {"op": "done"} if any of title, main_summary, category,
|
|
@@ -239,7 +241,12 @@ Rules:
|
|
| 239 |
- Output ONLY these JSON patch objects, one per line (NDJSON).
|
| 240 |
- Never wrap them in an outer array.
|
| 241 |
- Do NOT output the final combined object; only the patches.
|
| 242 |
-
- CRITICAL
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 243 |
|
| 244 |
def _build_style_instruction(self, style: str) -> str:
|
| 245 |
"""Build the style-specific instruction."""
|
|
@@ -637,9 +644,34 @@ Rules:
|
|
| 637 |
# Wait for generation to complete
|
| 638 |
generation_thread.join()
|
| 639 |
|
| 640 |
-
#
|
| 641 |
if buffer.strip():
|
| 642 |
-
logger.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 643 |
else:
|
| 644 |
logger.info("β
Buffer was fully consumed (no partial lines)")
|
| 645 |
|
|
|
|
| 196 |
|
| 197 |
Your goal is to produce a BRIEF, CONCISE structured summary of an article in the following logical shape:
|
| 198 |
{
|
| 199 |
+
"title": string, // 6-10 words MAX (e.g. "Couple Found Not Guilty in Homicide Case")
|
| 200 |
+
"main_summary": string, // 2 sentences MAX (be extremely brief)
|
| 201 |
+
"key_points": string[], // 3-5 items, each 8-12 words MAX
|
| 202 |
+
"category": string, // 1-2 words ONLY (e.g. "Crime", "Tech", "Politics")
|
| 203 |
"sentiment": string, // one of ["positive", "negative", "neutral"]
|
| 204 |
"read_time_min": number
|
| 205 |
}
|
|
|
|
| 210 |
|
| 211 |
1) Set or overwrite a scalar field (title, main_summary, category, sentiment, read_time_min):
|
| 212 |
{"op": "set", "field": "<field_name>", "value": <value>}
|
| 213 |
+
Examples (NOTE: Keep titles SHORT):
|
| 214 |
+
{"op": "set", "field": "title", "value": "Couple Acquitted in Homicide Case"}
|
| 215 |
{"op": "set", "field": "title", "value": "AI Model Breakthrough"}
|
| 216 |
+
{"op": "set", "field": "category", "value": "Crime"}
|
| 217 |
{"op": "set", "field": "sentiment", "value": "neutral"}
|
| 218 |
{"op": "set", "field": "read_time_min", "value": 3}
|
| 219 |
|
| 220 |
2) Append a key point to the key_points array:
|
| 221 |
{"op": "append", "field": "key_points", "value": "<one concise key fact>"}
|
| 222 |
+
Examples (NOTE: Keep each point SHORT):
|
| 223 |
+
{"op": "append", "field": "key_points", "value": "Couple found not guilty of murder charges."}
|
| 224 |
+
{"op": "append", "field": "key_points", "value": "New model optimized for efficiency."}
|
| 225 |
|
| 226 |
3) At the very end, output exactly one final line to signal completion:
|
| 227 |
{"op": "done"}
|
| 228 |
|
| 229 |
Rules:
|
| 230 |
- You MUST always set all scalar fields before finishing:
|
| 231 |
+
1) First patch: {"op": "set", "field": "title", ...} [6-10 words MAX - be SHORT!]
|
| 232 |
+
2) Second patch: {"op": "set", "field": "main_summary", ...} [2 sentences MAX]
|
| 233 |
+
3) Third patch: {"op": "set", "field": "category", ...} [1-2 words ONLY]
|
| 234 |
4) Fourth patch: {"op": "set", "field": "sentiment", ...}
|
| 235 |
5) Fifth patch: {"op": "set", "field": "read_time_min", ...}
|
| 236 |
+
6) Then emit {"op": "append", "field": "key_points", ...} patches (3-5 items, each 8-12 words MAX).
|
| 237 |
7) Only AFTER all fields are set and 3-5 key_points have been appended,
|
| 238 |
output exactly one final line: {"op": "done"}.
|
| 239 |
- NEVER output {"op": "done"} if any of title, main_summary, category,
|
|
|
|
| 241 |
- Output ONLY these JSON patch objects, one per line (NDJSON).
|
| 242 |
- Never wrap them in an outer array.
|
| 243 |
- Do NOT output the final combined object; only the patches.
|
| 244 |
+
- CRITICAL BREVITY RULES:
|
| 245 |
+
* Title MUST be 6-10 words. If longer, shorten it!
|
| 246 |
+
* Main summary MUST be 2 sentences maximum.
|
| 247 |
+
* Each key point MUST be 8-12 words maximum.
|
| 248 |
+
* Category MUST be 1-2 words only.
|
| 249 |
+
* NO verbose explanations. NO long descriptions. BE BRIEF!"""
|
| 250 |
|
| 251 |
def _build_style_instruction(self, style: str) -> str:
|
| 252 |
"""Build the style-specific instruction."""
|
|
|
|
| 644 |
# Wait for generation to complete
|
| 645 |
generation_thread.join()
|
| 646 |
|
| 647 |
+
# Process any remaining buffer content (might contain {"op": "done"})
|
| 648 |
if buffer.strip():
|
| 649 |
+
logger.info(f"π¦ Processing remaining buffer: {repr(buffer[:200])}")
|
| 650 |
+
# Try to parse the remaining buffer as a complete JSON object
|
| 651 |
+
buffer_cleaned = buffer.strip()
|
| 652 |
+
if buffer_cleaned.startswith("{") and "op" in buffer_cleaned:
|
| 653 |
+
try:
|
| 654 |
+
patch = json.loads(buffer_cleaned)
|
| 655 |
+
is_done = self._apply_patch(state, patch)
|
| 656 |
+
if is_done:
|
| 657 |
+
done_received = True
|
| 658 |
+
yield {
|
| 659 |
+
"delta": patch,
|
| 660 |
+
"state": dict(state),
|
| 661 |
+
"done": True,
|
| 662 |
+
"tokens_used": token_count,
|
| 663 |
+
}
|
| 664 |
+
else:
|
| 665 |
+
yield {
|
| 666 |
+
"delta": patch,
|
| 667 |
+
"state": dict(state),
|
| 668 |
+
"done": False,
|
| 669 |
+
"tokens_used": token_count,
|
| 670 |
+
}
|
| 671 |
+
except json.JSONDecodeError:
|
| 672 |
+
logger.warning(f"β οΈ Could not parse remaining buffer as JSON: {buffer_cleaned[:100]}")
|
| 673 |
+
else:
|
| 674 |
+
logger.warning(f"ποΈ Unparsed buffer remaining (not JSON): {repr(buffer[:200])}")
|
| 675 |
else:
|
| 676 |
logger.info("β
Buffer was fully consumed (no partial lines)")
|
| 677 |
|