Spaces:
Sleeping
Sleeping
Replace "tie" logic with "ambiguous" logic so that daily brief manual reviews happen when there is more than 1 doc type that meets confidence threshold
Browse files- app/lib/utils/classifier.py +4 -4
- app/processor.py +3 -3
- app/scheduler.py +6 -6
app/lib/utils/classifier.py
CHANGED
|
@@ -148,12 +148,12 @@ def classify(
|
|
| 148 |
if max_score < weights.min_threshold:
|
| 149 |
return ClassifyResult(doc_type="unknown", reason="below_threshold", scores=scores, breakdown=breakdown)
|
| 150 |
|
| 151 |
-
|
| 152 |
|
| 153 |
-
if len(
|
| 154 |
-
return ClassifyResult(doc_type="
|
| 155 |
|
| 156 |
-
winner =
|
| 157 |
if winner not in _ROUTABLE:
|
| 158 |
return ClassifyResult(doc_type=winner, reason="not_routable", scores=scores, breakdown=breakdown)
|
| 159 |
|
|
|
|
| 148 |
if max_score < weights.min_threshold:
|
| 149 |
return ClassifyResult(doc_type="unknown", reason="below_threshold", scores=scores, breakdown=breakdown)
|
| 150 |
|
| 151 |
+
above_threshold = [t for t, s in scores.items() if s >= weights.min_threshold]
|
| 152 |
|
| 153 |
+
if len(above_threshold) > 1:
|
| 154 |
+
return ClassifyResult(doc_type="ambiguous", reason="ambiguous", scores=scores, breakdown=breakdown)
|
| 155 |
|
| 156 |
+
winner = above_threshold[0]
|
| 157 |
if winner not in _ROUTABLE:
|
| 158 |
return ClassifyResult(doc_type=winner, reason="not_routable", scores=scores, breakdown=breakdown)
|
| 159 |
|
app/processor.py
CHANGED
|
@@ -151,11 +151,11 @@ async def _process_notification(dbx: DropboxClient, notif: dict) -> None:
|
|
| 151 |
email_identifier=email_identifier,
|
| 152 |
)
|
| 153 |
|
| 154 |
-
elif result.reason == "
|
| 155 |
async with get_db(settings.database_path) as conn:
|
| 156 |
from app.database import insert_daily_brief
|
| 157 |
await log_routing_result(
|
| 158 |
-
conn, notif_id, filename, "
|
| 159 |
email_identifier=email_identifier,
|
| 160 |
confidence_scores=result.scores,
|
| 161 |
)
|
|
@@ -166,7 +166,7 @@ async def _process_notification(dbx: DropboxClient, notif: dict) -> None:
|
|
| 166 |
sender_email=sender_email,
|
| 167 |
subject=subject,
|
| 168 |
filename=filename,
|
| 169 |
-
reason="
|
| 170 |
confidence_scores=result.scores,
|
| 171 |
)
|
| 172 |
final_status = "brief_pending"
|
|
|
|
| 151 |
email_identifier=email_identifier,
|
| 152 |
)
|
| 153 |
|
| 154 |
+
elif result.reason == "ambiguous":
|
| 155 |
async with get_db(settings.database_path) as conn:
|
| 156 |
from app.database import insert_daily_brief
|
| 157 |
await log_routing_result(
|
| 158 |
+
conn, notif_id, filename, "ambiguous", "brief_pending",
|
| 159 |
email_identifier=email_identifier,
|
| 160 |
confidence_scores=result.scores,
|
| 161 |
)
|
|
|
|
| 166 |
sender_email=sender_email,
|
| 167 |
subject=subject,
|
| 168 |
filename=filename,
|
| 169 |
+
reason="ambiguous",
|
| 170 |
confidence_scores=result.scores,
|
| 171 |
)
|
| 172 |
final_status = "brief_pending"
|
app/scheduler.py
CHANGED
|
@@ -174,14 +174,14 @@ class RenewalScheduler:
|
|
| 174 |
|
| 175 |
|
| 176 |
def _build_brief_html(items: list[dict]) -> str:
|
| 177 |
-
|
| 178 |
errors = [i for i in items if i["reason"] == "error"]
|
| 179 |
|
| 180 |
sections: list[str] = []
|
| 181 |
|
| 182 |
-
if
|
| 183 |
rows = ""
|
| 184 |
-
for item in
|
| 185 |
scores: dict = json.loads(item["confidence_scores"]) if item["confidence_scores"] else {}
|
| 186 |
score_cols = "".join(
|
| 187 |
f"<td>{doc_type}: {score:.2%}</td>"
|
|
@@ -198,12 +198,12 @@ def _build_brief_html(items: list[dict]) -> str:
|
|
| 198 |
score_headers = "".join(
|
| 199 |
f"<th>{doc_type}</th>"
|
| 200 |
for doc_type in sorted(
|
| 201 |
-
json.loads(
|
| 202 |
-
if
|
| 203 |
)
|
| 204 |
)
|
| 205 |
sections.append(
|
| 206 |
-
f"<h2>Ambiguous Routings
|
| 207 |
f"<table border='1' cellpadding='4' cellspacing='0'>"
|
| 208 |
f"<tr><th>Sender</th><th>Subject</th><th>Attachment</th>{score_headers}</tr>"
|
| 209 |
f"{rows}"
|
|
|
|
| 174 |
|
| 175 |
|
| 176 |
def _build_brief_html(items: list[dict]) -> str:
|
| 177 |
+
ambiguous = [i for i in items if i["reason"] == "ambiguous"]
|
| 178 |
errors = [i for i in items if i["reason"] == "error"]
|
| 179 |
|
| 180 |
sections: list[str] = []
|
| 181 |
|
| 182 |
+
if ambiguous:
|
| 183 |
rows = ""
|
| 184 |
+
for item in ambiguous:
|
| 185 |
scores: dict = json.loads(item["confidence_scores"]) if item["confidence_scores"] else {}
|
| 186 |
score_cols = "".join(
|
| 187 |
f"<td>{doc_type}: {score:.2%}</td>"
|
|
|
|
| 198 |
score_headers = "".join(
|
| 199 |
f"<th>{doc_type}</th>"
|
| 200 |
for doc_type in sorted(
|
| 201 |
+
json.loads(ambiguous[0]["confidence_scores"]).keys()
|
| 202 |
+
if ambiguous[0]["confidence_scores"] else []
|
| 203 |
)
|
| 204 |
)
|
| 205 |
sections.append(
|
| 206 |
+
f"<h2>Ambiguous Routings</h2>"
|
| 207 |
f"<table border='1' cellpadding='4' cellspacing='0'>"
|
| 208 |
f"<tr><th>Sender</th><th>Subject</th><th>Attachment</th>{score_headers}</tr>"
|
| 209 |
f"{rows}"
|