Spaces:
Sleeping
Sleeping
Download src/routing_agent/solvers/strings.py from SebAustin/amd-routing-agent-demo: direct link, hf CLI and curl.
- Browser
- Download file 4.51 kB
-
https://huggingface.co/spaces/SebAustin/amd-routing-agent-demo/resolve/main/src/routing_agent/solvers/strings.py
- Command line
-
hf download hf://spaces/SebAustin/amd-routing-agent-demo/src/routing_agent/solvers/strings.py
-
curl -L -o strings.py https://huggingface.co/spaces/SebAustin/amd-routing-agent-demo/resolve/main/src/routing_agent/solvers/strings.py
4.51 kB
| """String operation solver: reverse, case conversion, length, counting, | |
| substring extraction, and letter sorting on a quoted or clearly-delimited | |
| target string. | |
| Only fires when the operand string can be unambiguously extracted (quoted, | |
| or following a clear "the string X" / "of X" marker) and the operation is one | |
| of the supported shapes; otherwise falls through with confident=False. | |
| """ | |
| from __future__ import annotations | |
| import re | |
| from routing_agent.classifier import TaskType | |
| from routing_agent.models import Task | |
| from routing_agent.solvers import SolverResult | |
| _QUOTED_RE = re.compile(r"[\"'ββ](?P<value>[^\"'ββ]*)[\"'ββ]") | |
| def _all_quoted_spans(prompt: str) -> list[str]: | |
| return [m.group("value") for m in _QUOTED_RE.finditer(prompt)] | |
| def _extract_target(prompt: str) -> str | None: | |
| """Extract the operand string: the *last* quoted span. | |
| Most operations have exactly one quoted span (the operand itself). The | |
| count-char-occurrences shape has two ("l" ... "hello") β the character | |
| to search for, then the source string to search in β so the last quoted | |
| span is always the operand being operated on. | |
| """ | |
| spans = _all_quoted_spans(prompt) | |
| if not spans: | |
| return None | |
| return spans[-1] | |
| # "reverse the order of the words" (or "word order") means token-reversal, | |
| # not character-reversal β checked before the generic _REVERSE_RE so the | |
| # more specific shape always wins. | |
| _REVERSE_WORD_ORDER_RE = re.compile( | |
| r"\breverse\b.*\b(order of the words|word order)\b", re.IGNORECASE | |
| ) | |
| _REVERSE_RE = re.compile(r"\breverse\b", re.IGNORECASE) | |
| _UPPER_RE = re.compile(r"\buppercase\b|\bupper[- ]?case\b", re.IGNORECASE) | |
| _LOWER_RE = re.compile(r"\blowercase\b|\blower[- ]?case\b", re.IGNORECASE) | |
| _LENGTH_RE = re.compile(r"how many (?P<unit>letters|characters)\b|\blength of\b", re.IGNORECASE) | |
| _COUNT_CHAR_RE = re.compile( | |
| r"how many (?:times does |occurrences of )?.*(?:occur|appear)", re.IGNORECASE | |
| ) | |
| _COUNT_WORD_RE = re.compile(r"how many words\b", re.IGNORECASE) | |
| _FIRST_N_RE = re.compile(r"first (?P<n>\d+) characters", re.IGNORECASE) | |
| _LAST_N_RE = re.compile(r"last (?P<n>\d+) characters", re.IGNORECASE) | |
| _SORT_RE = re.compile(r"sort the letters", re.IGNORECASE) | |
| def try_solve(task: Task, task_type: TaskType) -> SolverResult: | |
| """Attempt to solve a string-operation task on a quoted operand. | |
| Requires the target string to be explicitly quoted in the prompt (no | |
| heuristic "the rest of the sentence is the string" guessing) so the | |
| solver never mis-segments prose from the operand. | |
| """ | |
| if task_type != TaskType.STRING_OP: | |
| return SolverResult(answer=None, confident=False) | |
| prompt = task.prompt.strip() | |
| # Count-char-occurrences has two quoted spans (character, source string) | |
| # and must be checked before generic target extraction picks the wrong one. | |
| if _COUNT_CHAR_RE.search(prompt): | |
| spans = _all_quoted_spans(prompt) | |
| if len(spans) == 2 and len(spans[0]) == 1: | |
| char, source = spans | |
| return SolverResult(answer=str(source.count(char)), confident=True) | |
| return SolverResult(answer=None, confident=False) | |
| target = _extract_target(prompt) | |
| if target is None: | |
| return SolverResult(answer=None, confident=False) | |
| if _REVERSE_WORD_ORDER_RE.search(prompt): | |
| return SolverResult(answer=" ".join(reversed(target.split())), confident=True) | |
| if _REVERSE_RE.search(prompt): | |
| return SolverResult(answer=target[::-1], confident=True) | |
| if _UPPER_RE.search(prompt): | |
| return SolverResult(answer=target.upper(), confident=True) | |
| if _LOWER_RE.search(prompt): | |
| return SolverResult(answer=target.lower(), confident=True) | |
| first_n_match = _FIRST_N_RE.search(prompt) | |
| if first_n_match: | |
| n = int(first_n_match.group("n")) | |
| return SolverResult(answer=target[:n], confident=True) | |
| last_n_match = _LAST_N_RE.search(prompt) | |
| if last_n_match: | |
| n = int(last_n_match.group("n")) | |
| return SolverResult(answer=target[-n:] if n > 0 else "", confident=True) | |
| if _COUNT_WORD_RE.search(prompt): | |
| word_count = len(target.split()) | |
| return SolverResult(answer=str(word_count), confident=True) | |
| if _LENGTH_RE.search(prompt): | |
| return SolverResult(answer=str(len(target)), confident=True) | |
| if _SORT_RE.search(prompt): | |
| return SolverResult(answer="".join(sorted(target)), confident=True) | |
| return SolverResult(answer=None, confident=False) | |