Spaces:
Sleeping
Sleeping
Upload app.py
Browse files
app.py
CHANGED
|
@@ -1067,10 +1067,16 @@ async def run_stage2_analysis_v2(
|
|
| 1067 |
semantic_analysis=semantic_analysis,
|
| 1068 |
log_callback=state.log,
|
| 1069 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1070 |
except Exception as e:
|
| 1071 |
-
state.log(f" β οΈ Brand Identifier failed: {str(e)[:
|
| 1072 |
brand_result = BrandIdentification()
|
| 1073 |
-
|
| 1074 |
# Benchmark Advisor
|
| 1075 |
if benchmark_comparisons:
|
| 1076 |
try:
|
|
@@ -1081,20 +1087,38 @@ async def run_stage2_analysis_v2(
|
|
| 1081 |
benchmark_comparisons=benchmark_comparisons,
|
| 1082 |
log_callback=state.log,
|
| 1083 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1084 |
except Exception as e:
|
| 1085 |
-
state.log(f" β οΈ Benchmark Advisor failed: {str(e)[:
|
| 1086 |
benchmark_advice = BenchmarkAdvice()
|
| 1087 |
else:
|
| 1088 |
benchmark_advice = BenchmarkAdvice()
|
| 1089 |
-
|
| 1090 |
# Best Practices Validator
|
| 1091 |
try:
|
| 1092 |
best_practices = await best_practices_agent.analyze(
|
| 1093 |
rule_engine_results=rule_results,
|
| 1094 |
log_callback=state.log,
|
| 1095 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1096 |
except Exception as e:
|
| 1097 |
-
state.log(f" β οΈ Best Practices Validator failed: {str(e)[:
|
| 1098 |
best_practices = BestPracticesResult(overall_score=rule_results.consistency_score)
|
| 1099 |
else:
|
| 1100 |
# No HF client - use defaults
|
|
@@ -1129,8 +1153,21 @@ async def run_stage2_analysis_v2(
|
|
| 1129 |
best_practices=best_practices,
|
| 1130 |
log_callback=state.log,
|
| 1131 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1132 |
except Exception as e:
|
| 1133 |
-
state.log(f" β οΈ HEAD Synthesizer failed: {str(e)[:
|
|
|
|
|
|
|
| 1134 |
final_synthesis = None
|
| 1135 |
|
| 1136 |
# Create fallback synthesis if needed
|
|
@@ -1203,9 +1240,16 @@ async def run_stage2_analysis_v2(
|
|
| 1203 |
|
| 1204 |
# Generate visual previews
|
| 1205 |
typography_preview_html = ""
|
|
|
|
|
|
|
|
|
|
| 1206 |
try:
|
| 1207 |
-
from core.preview_generator import
|
| 1208 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1209 |
primary_font = fonts.get("primary", "Open Sans")
|
| 1210 |
desktop_typo_dict = {
|
| 1211 |
name: {
|
|
@@ -1216,23 +1260,89 @@ async def run_stage2_analysis_v2(
|
|
| 1216 |
for name, t in state.desktop_normalized.typography.items()
|
| 1217 |
}
|
| 1218 |
typography_preview_html = generate_typography_preview_html(desktop_typo_dict, primary_font)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1219 |
except Exception as preview_err:
|
| 1220 |
-
state.log(f" β οΈ Preview generation failed: {str(preview_err)[:
|
| 1221 |
-
typography_preview_html = "<div class='placeholder-msg'>Preview unavailable</div>"
|
| 1222 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1223 |
except Exception as format_err:
|
| 1224 |
state.log(f" β οΈ Formatting failed: {str(format_err)[:100]}")
|
| 1225 |
-
|
|
|
|
|
|
|
| 1226 |
return (
|
| 1227 |
f"β οΈ Analysis completed with formatting errors: {str(format_err)[:50]}",
|
| 1228 |
state.get_logs(),
|
| 1229 |
"*Benchmark comparison unavailable*",
|
| 1230 |
-
"<div>Scores unavailable</div>",
|
| 1231 |
-
"<div>Actions unavailable</div>",
|
| 1232 |
[],
|
| 1233 |
None,
|
| 1234 |
None,
|
| 1235 |
-
"",
|
|
|
|
|
|
|
| 1236 |
)
|
| 1237 |
|
| 1238 |
progress(0.95, desc="β
Complete!")
|
|
@@ -1277,8 +1387,10 @@ async def run_stage2_analysis_v2(
|
|
| 1277 |
typography_desktop_data,
|
| 1278 |
typography_mobile_data,
|
| 1279 |
typography_preview_html,
|
|
|
|
|
|
|
| 1280 |
)
|
| 1281 |
-
|
| 1282 |
except Exception as e:
|
| 1283 |
import traceback
|
| 1284 |
state.log(f"β Critical Error: {str(e)}")
|
|
@@ -1345,17 +1457,19 @@ def create_fallback_synthesis(rule_results, benchmark_comparisons, brand_result,
|
|
| 1345 |
|
| 1346 |
|
| 1347 |
def create_stage2_error_response(error_msg: str):
|
| 1348 |
-
"""Create error response tuple for Stage 2."""
|
| 1349 |
return (
|
| 1350 |
error_msg,
|
| 1351 |
state.get_logs(),
|
| 1352 |
"", # benchmark_md
|
| 1353 |
-
"", # scores_html
|
| 1354 |
"", # actions_html
|
| 1355 |
[], # color_recs_table
|
| 1356 |
None, # typography_desktop
|
| 1357 |
None, # typography_mobile
|
| 1358 |
"", # typography_preview
|
|
|
|
|
|
|
| 1359 |
)
|
| 1360 |
|
| 1361 |
|
|
@@ -3870,15 +3984,17 @@ def create_ui():
|
|
| 3870 |
fn=run_stage2_analysis_v2,
|
| 3871 |
inputs=[benchmark_checkboxes],
|
| 3872 |
outputs=[
|
| 3873 |
-
stage2_status,
|
| 3874 |
-
stage2_log,
|
| 3875 |
benchmark_comparison_md,
|
| 3876 |
scores_dashboard,
|
| 3877 |
priority_actions_html,
|
| 3878 |
color_recommendations_table,
|
| 3879 |
-
typography_desktop,
|
| 3880 |
-
typography_mobile,
|
| 3881 |
stage2_typography_preview,
|
|
|
|
|
|
|
| 3882 |
],
|
| 3883 |
)
|
| 3884 |
|
|
|
|
| 1067 |
semantic_analysis=semantic_analysis,
|
| 1068 |
log_callback=state.log,
|
| 1069 |
)
|
| 1070 |
+
# Log what the LLM contributed
|
| 1071 |
+
if brand_result:
|
| 1072 |
+
state.log(f" ββ Brand Primary: {brand_result.primary_color or 'N/A'} ({brand_result.confidence or 'N/A'} confidence)")
|
| 1073 |
+
state.log(f" ββ Brand Secondary: {brand_result.secondary_color or 'N/A'}")
|
| 1074 |
+
state.log(f" ββ Palette Strategy: {brand_result.palette_strategy or 'N/A'}")
|
| 1075 |
+
state.log(f" ββ Cohesion Score: {brand_result.cohesion_score or 'N/A'}/10")
|
| 1076 |
except Exception as e:
|
| 1077 |
+
state.log(f" β οΈ Brand Identifier failed: {str(e)[:120]}")
|
| 1078 |
brand_result = BrandIdentification()
|
| 1079 |
+
|
| 1080 |
# Benchmark Advisor
|
| 1081 |
if benchmark_comparisons:
|
| 1082 |
try:
|
|
|
|
| 1087 |
benchmark_comparisons=benchmark_comparisons,
|
| 1088 |
log_callback=state.log,
|
| 1089 |
)
|
| 1090 |
+
# Log what the LLM contributed
|
| 1091 |
+
if benchmark_advice:
|
| 1092 |
+
state.log(f" ββ Recommended: {benchmark_advice.recommended_system or 'N/A'}")
|
| 1093 |
+
changes = getattr(benchmark_advice, 'changes_needed', []) or []
|
| 1094 |
+
state.log(f" ββ Changes Needed: {len(changes)}")
|
| 1095 |
+
if changes:
|
| 1096 |
+
state.log(f" ββ Key Change: {changes[0].get('what', 'N/A') if isinstance(changes[0], dict) else changes[0]}")
|
| 1097 |
except Exception as e:
|
| 1098 |
+
state.log(f" β οΈ Benchmark Advisor failed: {str(e)[:120]}")
|
| 1099 |
benchmark_advice = BenchmarkAdvice()
|
| 1100 |
else:
|
| 1101 |
benchmark_advice = BenchmarkAdvice()
|
| 1102 |
+
|
| 1103 |
# Best Practices Validator
|
| 1104 |
try:
|
| 1105 |
best_practices = await best_practices_agent.analyze(
|
| 1106 |
rule_engine_results=rule_results,
|
| 1107 |
log_callback=state.log,
|
| 1108 |
)
|
| 1109 |
+
# Log what the LLM contributed
|
| 1110 |
+
if best_practices:
|
| 1111 |
+
checks = getattr(best_practices, 'checks', []) or []
|
| 1112 |
+
passing = sum(1 for c in checks if c.get('pass', False)) if checks else 0
|
| 1113 |
+
failing = len(checks) - passing if checks else 0
|
| 1114 |
+
state.log(f" ββ Overall Score: {best_practices.overall_score or 'N/A'}/100")
|
| 1115 |
+
state.log(f" ββ Passing: {passing} | Failing: {failing}")
|
| 1116 |
+
if checks:
|
| 1117 |
+
top_fail = next((c for c in checks if not c.get('pass', True)), None)
|
| 1118 |
+
if top_fail:
|
| 1119 |
+
state.log(f" ββ Top Fix: {top_fail.get('fix', top_fail.get('name', 'N/A'))[:60]}")
|
| 1120 |
except Exception as e:
|
| 1121 |
+
state.log(f" β οΈ Best Practices Validator failed: {str(e)[:120]}")
|
| 1122 |
best_practices = BestPracticesResult(overall_score=rule_results.consistency_score)
|
| 1123 |
else:
|
| 1124 |
# No HF client - use defaults
|
|
|
|
| 1153 |
best_practices=best_practices,
|
| 1154 |
log_callback=state.log,
|
| 1155 |
)
|
| 1156 |
+
if final_synthesis:
|
| 1157 |
+
state.log("")
|
| 1158 |
+
state.log(f" β
HEAD Synthesizer: COMPLETE")
|
| 1159 |
+
state.log(f" ββ Scores: {final_synthesis.scores}")
|
| 1160 |
+
if final_synthesis.executive_summary:
|
| 1161 |
+
state.log(f" ββ Summary: {final_synthesis.executive_summary[:100]}...")
|
| 1162 |
+
color_recs = getattr(final_synthesis, 'color_recommendations', {})
|
| 1163 |
+
if color_recs:
|
| 1164 |
+
state.log(f" ββ Color Recommendations: {len(color_recs)} suggested changes")
|
| 1165 |
+
if final_synthesis.top_3_actions:
|
| 1166 |
+
state.log(f" ββ Top Actions: {len(final_synthesis.top_3_actions)} priorities")
|
| 1167 |
except Exception as e:
|
| 1168 |
+
state.log(f" β οΈ HEAD Synthesizer failed: {str(e)[:120]}")
|
| 1169 |
+
import traceback
|
| 1170 |
+
state.log(f" ββ {traceback.format_exc()[:200]}")
|
| 1171 |
final_synthesis = None
|
| 1172 |
|
| 1173 |
# Create fallback synthesis if needed
|
|
|
|
| 1240 |
|
| 1241 |
# Generate visual previews
|
| 1242 |
typography_preview_html = ""
|
| 1243 |
+
color_ramps_preview_html = ""
|
| 1244 |
+
llm_recs_html = ""
|
| 1245 |
+
|
| 1246 |
try:
|
| 1247 |
+
from core.preview_generator import (
|
| 1248 |
+
generate_typography_preview_html,
|
| 1249 |
+
generate_semantic_color_ramps_html,
|
| 1250 |
+
generate_color_ramps_preview_html,
|
| 1251 |
+
)
|
| 1252 |
+
|
| 1253 |
primary_font = fonts.get("primary", "Open Sans")
|
| 1254 |
desktop_typo_dict = {
|
| 1255 |
name: {
|
|
|
|
| 1260 |
for name, t in state.desktop_normalized.typography.items()
|
| 1261 |
}
|
| 1262 |
typography_preview_html = generate_typography_preview_html(desktop_typo_dict, primary_font)
|
| 1263 |
+
|
| 1264 |
+
# Generate color ramps preview (semantic groups)
|
| 1265 |
+
semantic_analysis = getattr(state, 'semantic_analysis', {})
|
| 1266 |
+
desktop_dict_for_colors = normalized_to_dict(state.desktop_normalized)
|
| 1267 |
+
|
| 1268 |
+
if semantic_analysis:
|
| 1269 |
+
color_ramps_preview_html = generate_semantic_color_ramps_html(
|
| 1270 |
+
semantic_analysis=semantic_analysis,
|
| 1271 |
+
color_tokens=desktop_dict_for_colors.get("colors", {}),
|
| 1272 |
+
)
|
| 1273 |
+
else:
|
| 1274 |
+
color_ramps_preview_html = generate_color_ramps_preview_html(
|
| 1275 |
+
color_tokens=desktop_dict_for_colors.get("colors", {}),
|
| 1276 |
+
)
|
| 1277 |
+
|
| 1278 |
+
state.log(" β
Color ramps preview generated")
|
| 1279 |
+
|
| 1280 |
except Exception as preview_err:
|
| 1281 |
+
state.log(f" β οΈ Preview generation failed: {str(preview_err)[:80]}")
|
| 1282 |
+
typography_preview_html = typography_preview_html or "<div class='placeholder-msg'>Preview unavailable</div>"
|
| 1283 |
+
color_ramps_preview_html = "<div class='placeholder-msg'>Color ramps preview unavailable</div>"
|
| 1284 |
+
|
| 1285 |
+
# Generate LLM recommendations HTML
|
| 1286 |
+
try:
|
| 1287 |
+
# Build recs dict in the format expected by the HTML formatter
|
| 1288 |
+
synth_recs = {}
|
| 1289 |
+
if final_synthesis:
|
| 1290 |
+
# Convert list of color recs to dict keyed by role
|
| 1291 |
+
color_recs_dict = {}
|
| 1292 |
+
for rec in (final_synthesis.color_recommendations or []):
|
| 1293 |
+
if isinstance(rec, dict) and rec.get("role"):
|
| 1294 |
+
color_recs_dict[rec["role"]] = rec
|
| 1295 |
+
synth_recs["color_recommendations"] = color_recs_dict
|
| 1296 |
+
|
| 1297 |
+
# Add AA fixes from rule engine
|
| 1298 |
+
aa_fixes = []
|
| 1299 |
+
if rule_results and rule_results.accessibility:
|
| 1300 |
+
for a in rule_results.accessibility:
|
| 1301 |
+
if not a.passes_aa_normal:
|
| 1302 |
+
aa_fixes.append(a.to_dict() if hasattr(a, 'to_dict') else {"color": str(a)})
|
| 1303 |
+
synth_recs["accessibility_fixes"] = aa_fixes
|
| 1304 |
+
|
| 1305 |
+
llm_recs_html = format_llm_color_recommendations_html(
|
| 1306 |
+
final_recs=synth_recs,
|
| 1307 |
+
semantic_analysis=getattr(state, 'semantic_analysis', {}),
|
| 1308 |
+
)
|
| 1309 |
+
except Exception as recs_err:
|
| 1310 |
+
state.log(f" β οΈ LLM recs HTML failed: {str(recs_err)[:120]}")
|
| 1311 |
+
import traceback
|
| 1312 |
+
state.log(f" ββ {traceback.format_exc()[:200]}")
|
| 1313 |
+
llm_recs_html = "<div class='placeholder-msg'>LLM recommendations unavailable</div>"
|
| 1314 |
+
|
| 1315 |
+
# Store upgrade_recommendations for Apply Upgrades button
|
| 1316 |
+
aa_failures_list = []
|
| 1317 |
+
if rule_results and rule_results.accessibility:
|
| 1318 |
+
aa_failures_list = [
|
| 1319 |
+
a.to_dict() for a in rule_results.accessibility
|
| 1320 |
+
if not a.passes_aa_normal
|
| 1321 |
+
]
|
| 1322 |
+
state.upgrade_recommendations = {
|
| 1323 |
+
"color_recommendations": (final_synthesis.color_recommendations if final_synthesis else []),
|
| 1324 |
+
"accessibility_fixes": aa_failures_list,
|
| 1325 |
+
"scores": (final_synthesis.scores if final_synthesis else {}),
|
| 1326 |
+
"top_3_actions": (final_synthesis.top_3_actions if final_synthesis else []),
|
| 1327 |
+
}
|
| 1328 |
+
|
| 1329 |
except Exception as format_err:
|
| 1330 |
state.log(f" β οΈ Formatting failed: {str(format_err)[:100]}")
|
| 1331 |
+
import traceback
|
| 1332 |
+
state.log(traceback.format_exc()[:500])
|
| 1333 |
+
# Return minimal results (must match 11 outputs)
|
| 1334 |
return (
|
| 1335 |
f"β οΈ Analysis completed with formatting errors: {str(format_err)[:50]}",
|
| 1336 |
state.get_logs(),
|
| 1337 |
"*Benchmark comparison unavailable*",
|
| 1338 |
+
"<div class='placeholder-msg'>Scores unavailable</div>",
|
| 1339 |
+
"<div class='placeholder-msg'>Actions unavailable</div>",
|
| 1340 |
[],
|
| 1341 |
None,
|
| 1342 |
None,
|
| 1343 |
+
"<div class='placeholder-msg'>Typography preview unavailable</div>",
|
| 1344 |
+
"<div class='placeholder-msg'>Color ramps preview unavailable</div>",
|
| 1345 |
+
"<div class='placeholder-msg'>LLM recommendations unavailable</div>",
|
| 1346 |
)
|
| 1347 |
|
| 1348 |
progress(0.95, desc="β
Complete!")
|
|
|
|
| 1387 |
typography_desktop_data,
|
| 1388 |
typography_mobile_data,
|
| 1389 |
typography_preview_html,
|
| 1390 |
+
color_ramps_preview_html,
|
| 1391 |
+
llm_recs_html,
|
| 1392 |
)
|
| 1393 |
+
|
| 1394 |
except Exception as e:
|
| 1395 |
import traceback
|
| 1396 |
state.log(f"β Critical Error: {str(e)}")
|
|
|
|
| 1457 |
|
| 1458 |
|
| 1459 |
def create_stage2_error_response(error_msg: str):
|
| 1460 |
+
"""Create error response tuple for Stage 2 (must match 11 outputs)."""
|
| 1461 |
return (
|
| 1462 |
error_msg,
|
| 1463 |
state.get_logs(),
|
| 1464 |
"", # benchmark_md
|
| 1465 |
+
f"<div class='placeholder-msg'>{error_msg}</div>", # scores_html
|
| 1466 |
"", # actions_html
|
| 1467 |
[], # color_recs_table
|
| 1468 |
None, # typography_desktop
|
| 1469 |
None, # typography_mobile
|
| 1470 |
"", # typography_preview
|
| 1471 |
+
"", # color_ramps_preview
|
| 1472 |
+
"", # llm_recs_html
|
| 1473 |
)
|
| 1474 |
|
| 1475 |
|
|
|
|
| 3984 |
fn=run_stage2_analysis_v2,
|
| 3985 |
inputs=[benchmark_checkboxes],
|
| 3986 |
outputs=[
|
| 3987 |
+
stage2_status,
|
| 3988 |
+
stage2_log,
|
| 3989 |
benchmark_comparison_md,
|
| 3990 |
scores_dashboard,
|
| 3991 |
priority_actions_html,
|
| 3992 |
color_recommendations_table,
|
| 3993 |
+
typography_desktop,
|
| 3994 |
+
typography_mobile,
|
| 3995 |
stage2_typography_preview,
|
| 3996 |
+
stage2_color_ramps_preview,
|
| 3997 |
+
llm_color_recommendations,
|
| 3998 |
],
|
| 3999 |
)
|
| 4000 |
|