Spaces:
Running
Running
Download ask.py from DevSchretl/UBCHelper: direct link, hf CLI and curl.
- Browser
- Download file 3.4 kB
-
https://huggingface.co/spaces/DevSchretl/UBCHelper/resolve/main/ask.py
- Command line
-
hf download hf://spaces/DevSchretl/UBCHelper/ask.py
-
curl -L -o ask.py https://huggingface.co/spaces/DevSchretl/UBCHelper/resolve/main/ask.py
3.4 kB
| """ | |
| ask.py — the tiny CLI that runs the whole naive-RAG loop for one question. | |
| retrieve(question) -> generate_answer(question, excerpts) -> print | |
| Usage (from the project root, with the venv active): | |
| python ask.py "What are the prerequisites for CPSC 210?" | |
| python ask.py --top-k 6 "How many credits does the B.Sc. require?" | |
| python ask.py --show-context "What is the academic standing policy?" | |
| Prerequisites: | |
| 1. Keys in `.env` (copy `.env.example`): OPENAI_API_KEY for query embeddings and | |
| ANTHROPIC_API_KEY for generation (the default backend). | |
| 2. The index built once: python -m src.ingest | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| from src import config, generate, pipeline, retrieve, trace | |
| def main() -> None: | |
| parser = argparse.ArgumentParser(description="Ask the UBC academic-calendar RAG advisor a question.") | |
| parser.add_argument("question", help="your calendar question (wrap it in quotes)") | |
| parser.add_argument( | |
| "--top-k", | |
| type=int, | |
| default=config.TOP_K, | |
| help=f"how many calendar excerpts to retrieve (default: {config.TOP_K})", | |
| ) | |
| parser.add_argument( | |
| "--show-context", | |
| action="store_true", | |
| help="also print the full text of the calendar excerpts sent to the model", | |
| ) | |
| parser.add_argument( | |
| "--mode", | |
| choices=["dense", "hybrid", "hybrid_rerank"], | |
| default=config.RETRIEVAL_MODE, | |
| help=f"retrieval pipeline to use (default: {config.RETRIEVAL_MODE})", | |
| ) | |
| parser.add_argument( | |
| "--adaptive", | |
| action="store_true", | |
| help="route the question (Phase 4): simple -> fast retriever, complex -> agent", | |
| ) | |
| parser.add_argument( | |
| "--trace", | |
| action="store_true", | |
| help="print every internal step and the exact prompts sent to the APIs " | |
| "(most informative with --adaptive)", | |
| ) | |
| args = parser.parse_args() | |
| if args.trace: | |
| trace.enable() | |
| # 1. RETRIEVE (+ optionally route). --adaptive sends the question through the Phase-4 | |
| # pipeline, which classifies it and picks the simple or agentic path; otherwise we run | |
| # the plain retrieve -> generate loop with the chosen --mode. | |
| if args.adaptive: | |
| print("\nThinking ...\n") | |
| result = pipeline.answer(args.question, top_k=args.top_k, mode=args.mode) | |
| results, answer = result["results"], result["answer"] | |
| print(f"Route: {result['route']}") | |
| else: | |
| results = retrieve.retrieve(args.question, top_k=args.top_k, mode=args.mode) | |
| answer = None | |
| # Show which excerpts grounded the answer (titles + similarity scores). This makes | |
| # the retrieval step visible, which is the whole point of the learning exercise. | |
| print("\nRetrieved excerpts:") | |
| for r in results: | |
| print(f" [{r.score:.3f}] (id={r.id}) {r.recipe['title']}") | |
| if args.show_context: | |
| print("\n--- context sent to the model ---") | |
| print(generate.format_context(results)) | |
| print("--- end context ---") | |
| # 2. GENERATE — have the LLM answer, grounded in those excerpts (the adaptive path | |
| # already produced the answer above). | |
| if answer is None: | |
| print("\nThinking ...\n") | |
| answer = generate.generate_answer(args.question, results) | |
| print("\nAnswer:") | |
| print(answer) | |
| if __name__ == "__main__": | |
| main() | |