File size: 2,343 Bytes
3947185
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
"""Deterministic detection of e-resource access problems.

Access problems ("I can't access ScienceDirect", "OpenAthens login keeps
failing", "how do I access databases off campus") are routed straight to the
knowledge-base RAG path. Requests for a specific article's full text stay on
the full-text chain. Kept separate from constants.py so it has no dependencies
and can be tested on its own.
"""
import re

# Unambiguous access/authentication cues. Context-dependent words (remote,
# VPN, off campus) only count next to an access or sign-in verb, so research
# topics such as "remote sensing" or "VPN security" are not misrouted.
ACCESS_PROBLEM_RE = re.compile(
    r"\b("
    r"openathens|single sign.?on"
    r"|access (denied|error|issue|problem)s?"
    r"|(asks?|asking|wants?) me to (pay|purchase|buy|subscribe)"
    r"|(log(?:ging)?\s?(?:in|on)|sign(?:ing)?\s?in|sso)\W+(?:\w+\W+){0,4}(fail\w*|error|problem|issue|loop\w*|not working|keeps)"
    r"|(off[\s-]?campus|remote(ly)?|from home|outside (the )?campus|vpn)\W+(?:\w+\W+){0,4}(access\w*|log(?:ging)?\s?(?:in|on)|sign(?:ing)?\s?in)"
    r"|(access\w*|log(?:ging)?\s?(?:in|on)|sign(?:ing)?\s?in)\W+(?:\w+\W+){0,4}(off[\s-]?campus|remote(ly)?|from home|outside (the )?campus)"
    r"|(link|database|platform|e-?resource)s?\W+(?:\w+\W+){0,3}(not working|broken|down|dead)"
    r")\b",
    re.IGNORECASE,
)

# "can't access X", "trouble logging in to X", "problem opening X"
ACCESS_FAIL_RE = re.compile(
    r"\b(can.?t|cannot|unable to|not able to|couldn.?t|trouble|problems?|issues?|lost)\b"
    r"\W+(?:\w+\W+){0,3}(access\w*|log(?:ging)?\s?(?:in|on)|sign(?:ing)?\s?in|connect\w*|open\w*)\b",
    re.IGNORECASE,
)

ARTICLE_CUE_RE = re.compile(r"\b(pdf|full.?text|articles?|papers?|chapters?)\b", re.IGNORECASE)

# Extra tokens appended to the retrieval query so BM25 reliably surfaces the
# access-troubleshooting and remote-access chunks alongside any resource chunk.
ACCESS_RETRIEVAL_HINT = "access troubleshooting sign in remote access electronic resources"


def _is_access_problem(question: str) -> bool:
    q = question or ""
    if ACCESS_PROBLEM_RE.search(q):
        return True
    # "can't access ScienceDirect" is a platform problem;
    # "can't access this article" is a full-text request.
    return bool(ACCESS_FAIL_RE.search(q)) and not ARTICLE_CUE_RE.search(q)