Spaces:
Running
Running
fix: executive report roadmap truncation and markdown leaking
Browse files- executive_report.py: _extract_timeline_from_plan now strips **markdown**
via _clean_text() on title+desc, title capture expanded 80β200 chars,
added table-format detection for pipe-separated AI output
- agents.py: STW Strutturali prompt explicitly forbids MACRO 3/4+
- config.py: promote meta-llama/Llama-3.3-70B-Instruct to primary in
HF_MODEL_CHAIN (confirmed working on together provider)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- agents.py +3 -1
- config.py +2 -2
- executive_report.py +14 -4
agents.py
CHANGED
|
@@ -644,7 +644,9 @@ Sei l'ANALISTA AREA STRUTTURALE STW. Redigi la sezione OBIETTIVI STRUTTURALI sec
|
|
| 644 |
- Budget: [stima]
|
| 645 |
- Beneficiari: [target]
|
| 646 |
|
| 647 |
-
**REGOLE:**
|
|
|
|
|
|
|
| 648 |
- Costi SEMPRE come range con fonte (es. "β¬50.000-80.000 - benchmark club simili")
|
| 649 |
- Dati mancanti: `(dato da acquisire)`
|
| 650 |
- Voce istituzionale
|
|
|
|
| 644 |
- Budget: [stima]
|
| 645 |
- Beneficiari: [target]
|
| 646 |
|
| 647 |
+
**REGOLE ASSOLUTE:**
|
| 648 |
+
- Questa sezione ha ESATTAMENTE 2 MACRO (MACRO 1 e MACRO 2). NON aggiungere MACRO 3, MACRO 4 o altri obiettivi macro.
|
| 649 |
+
- Finanziario e marketing NON appartengono a questa sezione.
|
| 650 |
- Costi SEMPRE come range con fonte (es. "β¬50.000-80.000 - benchmark club simili")
|
| 651 |
- Dati mancanti: `(dato da acquisire)`
|
| 652 |
- Voce istituzionale
|
config.py
CHANGED
|
@@ -136,8 +136,8 @@ OPENROUTER_API_KEY = os.environ.get("OPENROUTER_API_KEY", "")
|
|
| 136 |
HF_TOKEN = os.environ.get("HF_TOKEN", "")
|
| 137 |
HF_MODEL = os.environ.get("HF_MODEL", "Qwen/Qwen2.5-72B-Instruct")
|
| 138 |
HF_MODEL_CHAIN = [
|
| 139 |
-
"
|
| 140 |
-
"
|
| 141 |
"Qwen/Qwen2.5-32B-Instruct", # 32B fallback, fast
|
| 142 |
"mistralai/Mistral-Nemo-Instruct-2407", # 12B, lightweight fallback
|
| 143 |
"Qwen/Qwen2.5-7B-Instruct", # 7B, last resort
|
|
|
|
| 136 |
HF_TOKEN = os.environ.get("HF_TOKEN", "")
|
| 137 |
HF_MODEL = os.environ.get("HF_MODEL", "Qwen/Qwen2.5-72B-Instruct")
|
| 138 |
HF_MODEL_CHAIN = [
|
| 139 |
+
"meta-llama/Llama-3.3-70B-Instruct", # primary: confirmed working on together
|
| 140 |
+
"Qwen/Qwen2.5-72B-Instruct", # 72B fallback, multilingual
|
| 141 |
"Qwen/Qwen2.5-32B-Instruct", # 32B fallback, fast
|
| 142 |
"mistralai/Mistral-Nemo-Instruct-2407", # 12B, lightweight fallback
|
| 143 |
"Qwen/Qwen2.5-7B-Instruct", # 7B, last resort
|
executive_report.py
CHANGED
|
@@ -377,21 +377,31 @@ def _extract_timeline_from_plan(plan_data: Dict) -> list:
|
|
| 377 |
for key in ['roadmap', 'piano_triennale', 'strategic_roadmap', 'timeline']:
|
| 378 |
content = plan_data.get(key, '')
|
| 379 |
if content and len(content) > 100:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 380 |
blocks = re.findall(
|
| 381 |
-
r'(?:Anno|Year)\s*(\d)[:\s\-ββ]*([^\n]{5,
|
| 382 |
content, re.IGNORECASE
|
| 383 |
)
|
| 384 |
if len(blocks) >= 2:
|
| 385 |
-
return [(f'Y{b[0]}', b[1]
|
|
|
|
| 386 |
# Fallback: cerca nell'executive summary
|
| 387 |
exec_s = plan_data.get('executive_summary', '') or plan_data.get('coordinator_summary', '')
|
| 388 |
if exec_s:
|
| 389 |
blocks = re.findall(
|
| 390 |
-
r'(?:Anno|Triennio|Year)\s*(\d)[:\s\-ββ]*([^\n.]{10,
|
| 391 |
exec_s, re.IGNORECASE
|
| 392 |
)
|
| 393 |
if len(blocks) >= 2:
|
| 394 |
-
return [(f'Y{b[0]}', b[1]
|
| 395 |
return []
|
| 396 |
|
| 397 |
|
|
|
|
| 377 |
for key in ['roadmap', 'piano_triennale', 'strategic_roadmap', 'timeline']:
|
| 378 |
content = plan_data.get(key, '')
|
| 379 |
if content and len(content) > 100:
|
| 380 |
+
# Formato markdown table: | Anno 1 | Titolo | Desc |
|
| 381 |
+
table_blocks = re.findall(
|
| 382 |
+
r'\|\s*(?:Anno|Year)\s*(\d)[^|]*\|\s*([^|\n]{5,120})\|(?:\s*([^|\n]{5,250})\|)?',
|
| 383 |
+
content, re.IGNORECASE
|
| 384 |
+
)
|
| 385 |
+
if len(table_blocks) >= 2:
|
| 386 |
+
return [(f'Y{b[0]}', _clean_text(b[1]), _clean_text(b[2] or '')) for b in table_blocks[:3]]
|
| 387 |
+
|
| 388 |
+
# Formato standard: Anno 1: Titolo\nDescrizione
|
| 389 |
blocks = re.findall(
|
| 390 |
+
r'(?:Anno|Year)\s*(\d)[:\s\-ββ]*([^\n]{5,200})(?:\n([^\n]{20,250}))?',
|
| 391 |
content, re.IGNORECASE
|
| 392 |
)
|
| 393 |
if len(blocks) >= 2:
|
| 394 |
+
return [(f'Y{b[0]}', _clean_text(b[1]), _clean_text((b[2] or '').strip())) for b in blocks[:3]]
|
| 395 |
+
|
| 396 |
# Fallback: cerca nell'executive summary
|
| 397 |
exec_s = plan_data.get('executive_summary', '') or plan_data.get('coordinator_summary', '')
|
| 398 |
if exec_s:
|
| 399 |
blocks = re.findall(
|
| 400 |
+
r'(?:Anno|Triennio|Year)\s*(\d)[:\s\-ββ]*([^\n.]{10,200})',
|
| 401 |
exec_s, re.IGNORECASE
|
| 402 |
)
|
| 403 |
if len(blocks) >= 2:
|
| 404 |
+
return [(f'Y{b[0]}', _clean_text(b[1]), '') for b in blocks[:3]]
|
| 405 |
return []
|
| 406 |
|
| 407 |
|