Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -1492,9 +1492,7 @@ async def browse_subject(req: SubjectRequest, request: Request):
|
|
| 1492 |
}}
|
| 1493 |
|
| 1494 |
# Hard-filter against the real vocabulary. A name the model invented is
|
| 1495 |
-
# discarded here rather than
|
| 1496 |
-
# fail the category test and fall through to a broad area match that looks
|
| 1497 |
-
# like a real answer.
|
| 1498 |
bad_category = bool(category) and not is_real_category(category)
|
| 1499 |
bad_area = bool(area) and not is_real_area(area)
|
| 1500 |
if bad_category:
|
|
@@ -1506,27 +1504,54 @@ async def browse_subject(req: SubjectRequest, request: Request):
|
|
| 1506 |
area, req.subject)
|
| 1507 |
area = ""
|
| 1508 |
|
| 1509 |
-
|
| 1510 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1511 |
request.state.usage_recorded = True
|
| 1512 |
-
|
| 1513 |
-
|
| 1514 |
-
|
|
|
|
|
|
|
| 1515 |
return {"result": {
|
| 1516 |
-
"confidence":
|
| 1517 |
-
"
|
| 1518 |
-
|
| 1519 |
-
|
| 1520 |
-
"journals":
|
| 1521 |
}}
|
| 1522 |
|
| 1523 |
journals, match_level = search_by_subject(category, area, top_n=30, with_level=True)
|
| 1524 |
|
| 1525 |
-
#
|
| 1526 |
-
#
|
| 1527 |
-
#
|
| 1528 |
-
#
|
| 1529 |
-
#
|
| 1530 |
fallback_used = (match_level == 1)
|
| 1531 |
|
| 1532 |
if not journals:
|
|
@@ -1561,9 +1586,10 @@ async def browse_subject(req: SubjectRequest, request: Request):
|
|
| 1561 |
|
| 1562 |
msg = user_message
|
| 1563 |
if fallback_used:
|
| 1564 |
-
warn = (f"
|
| 1565 |
-
f"These are the highest-ranked journals across the
|
| 1566 |
-
f"'{area.title()}'
|
|
|
|
| 1567 |
msg = f"{msg} {warn}" if msg else warn
|
| 1568 |
usage.usage.record_gap("journal_subject", "area_fallback")
|
| 1569 |
request.state.usage_recorded = True
|
|
|
|
| 1492 |
}}
|
| 1493 |
|
| 1494 |
# Hard-filter against the real vocabulary. A name the model invented is
|
| 1495 |
+
# discarded here rather than handed to the search.
|
|
|
|
|
|
|
| 1496 |
bad_category = bool(category) and not is_real_category(category)
|
| 1497 |
bad_area = bool(area) and not is_real_area(area)
|
| 1498 |
if bad_category:
|
|
|
|
| 1504 |
area, req.subject)
|
| 1505 |
area = ""
|
| 1506 |
|
| 1507 |
+
# Suggestions the user can act on: the model's nearest names, hard-filtered
|
| 1508 |
+
# to real ones, topped up deterministically. Never invented.
|
| 1509 |
+
def _suggestions() -> list:
|
| 1510 |
+
out, seen = [], set()
|
| 1511 |
+
for n in (parsed.get("nearest_categories") or []):
|
| 1512 |
+
n = str(n).strip().lower()
|
| 1513 |
+
if n and n not in seen and is_real_category(n):
|
| 1514 |
+
seen.add(n); out.append(n)
|
| 1515 |
+
for n in suggest_categories(req.subject.strip(), limit=6):
|
| 1516 |
+
if n not in seen:
|
| 1517 |
+
seen.add(n); out.append(n)
|
| 1518 |
+
counts = subject_vocabulary()["categories"]
|
| 1519 |
+
return [{"category": n.title(), "n_journals": counts.get(n, 0)} for n in out[:6]]
|
| 1520 |
+
|
| 1521 |
+
# An AREA is only a legitimate answer when the user asked for one. If the
|
| 1522 |
+
# model named a category and that category was not real, the user asked for
|
| 1523 |
+
# something specific that this taxonomy does not have — and answering with
|
| 1524 |
+
# 30 top journals from the surrounding area is a confidently wrong answer,
|
| 1525 |
+
# not a partial one. "Crime" is not served by showing Tourism Management.
|
| 1526 |
+
#
|
| 1527 |
+
# Refusing and naming the nearest real categories is both the honest answer
|
| 1528 |
+
# and the more useful one: Law, Sociology and Political Science, and
|
| 1529 |
+
# Pathology and Forensic Medicine are where criminology research is indexed.
|
| 1530 |
+
if bad_category or (not category and not area):
|
| 1531 |
+
usage.usage.record_gap(
|
| 1532 |
+
"journal_subject",
|
| 1533 |
+
"category_invented" if bad_category else "subject_unrecognised")
|
| 1534 |
request.state.usage_recorded = True
|
| 1535 |
+
sugg = _suggestions()
|
| 1536 |
+
base = (f"SCImago and Scopus have no subject category for "
|
| 1537 |
+
f"'{req.subject.strip()}'.")
|
| 1538 |
+
hint = (" The closest indexed categories are: "
|
| 1539 |
+
+ ", ".join(s["category"] for s in sugg) + ".") if sugg else ""
|
| 1540 |
return {"result": {
|
| 1541 |
+
"confidence": "not_found",
|
| 1542 |
+
"normalised": normalised,
|
| 1543 |
+
"user_message": (user_message + " " if user_message else "") + base + hint,
|
| 1544 |
+
"suggestions": sugg,
|
| 1545 |
+
"journals": [],
|
| 1546 |
}}
|
| 1547 |
|
| 1548 |
journals, match_level = search_by_subject(category, area, top_n=30, with_level=True)
|
| 1549 |
|
| 1550 |
+
# Reaching here with match_level 1 now means only one thing: the model
|
| 1551 |
+
# named NO category and a real area, i.e. the user asked for the area.
|
| 1552 |
+
# "Show me top Engineering journals" is a legitimate request and this is
|
| 1553 |
+
# the correct answer to it — still labelled, because 30 rows out of
|
| 1554 |
+
# thousands ranked by h-index is a browsing aid, not a recommendation.
|
| 1555 |
fallback_used = (match_level == 1)
|
| 1556 |
|
| 1557 |
if not journals:
|
|
|
|
| 1586 |
|
| 1587 |
msg = user_message
|
| 1588 |
if fallback_used:
|
| 1589 |
+
warn = (f"'{req.subject.strip()}' is a subject AREA, not a specific "
|
| 1590 |
+
f"category. These are the highest-ranked journals across the "
|
| 1591 |
+
f"whole of '{area.title()}' by h-index — narrow to a category "
|
| 1592 |
+
f"for a subject-specific list.")
|
| 1593 |
msg = f"{msg} {warn}" if msg else warn
|
| 1594 |
usage.usage.record_gap("journal_subject", "area_fallback")
|
| 1595 |
request.state.usage_recorded = True
|