Download rag/generator.py from PranilB/Question_Answering_Classification: direct link, hf CLI and curl.
- Browser
- Download file 3.45 kB
-
https://huggingface.co/spaces/PranilB/Question_Answering_Classification/resolve/main/rag/generator.py
- Command line
-
hf download hf://spaces/PranilB/Question_Answering_Classification/rag/generator.py
-
curl -L -o generator.py https://huggingface.co/spaces/PranilB/Question_Answering_Classification/resolve/main/rag/generator.py
3.45 kB
| import os | |
| from groq import Groq | |
| from dotenv import load_dotenv | |
| # Load .env for local development (Railway injects env vars directly) | |
| _root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | |
| load_dotenv(dotenv_path=os.path.join(_root, '.env'), override=False) | |
| load_dotenv(dotenv_path=os.path.join(_root, 'pdf_to_embedding', '.env'), override=False) | |
| GROQ_API_KEY = os.getenv("GROQ_API_KEY") | |
| GROQ_MODEL = os.getenv("GROQ_MODEL", "llama-3.3-70b-versatile") | |
| _groq_client: Groq = None | |
| def get_groq_client() -> Groq: | |
| global _groq_client | |
| if _groq_client is None: | |
| if not GROQ_API_KEY: | |
| raise ValueError("Missing GROQ_API_KEY in .env file.") | |
| _groq_client = Groq(api_key=GROQ_API_KEY) | |
| return _groq_client | |
| def call_groq(messages: list[dict], temperature: float = 0.2, max_tokens: int = 512, max_retries: int = 5) -> str: | |
| """ | |
| Makes a single Groq chat completion call with exponential backoff for rate limits. | |
| Returns the raw text response from the LLM. | |
| """ | |
| import time | |
| client = get_groq_client() | |
| delay = 5.0 | |
| for attempt in range(max_retries): | |
| try: | |
| response = client.chat.completions.create( | |
| model=GROQ_MODEL, | |
| messages=messages, | |
| temperature=temperature, | |
| max_tokens=max_tokens, | |
| ) | |
| return response.choices[0].message.content.strip() | |
| except Exception as e: | |
| error_msg = str(e).lower() | |
| if "429" in error_msg or "rate limit" in error_msg or "too many requests" in error_msg: | |
| if attempt == max_retries - 1: | |
| print(f"[Groq API] Max retries reached. Failing.") | |
| raise e | |
| print(f"[Groq API] Rate limit hit. Waiting {delay}s before attempt {attempt+2}/{max_retries}...") | |
| time.sleep(delay) | |
| delay *= 1.5 # Exponential backoff | |
| else: | |
| raise e | |
| def generate_answer(messages: list[dict]) -> str: | |
| """ | |
| Calls the Groq LLM to generate the main answer. | |
| Uses low temperature (0.2) for factual consistency. | |
| """ | |
| return call_groq(messages, temperature=0.2, max_tokens=768) | |
| def generate_justification(messages: list[dict]) -> list[str]: | |
| """ | |
| Calls the Groq LLM to generate a step-by-step justification. | |
| Parses numbered lines into a list of strings. | |
| Returns a list like: ["Step 1: ...", "Step 2: ..."] | |
| """ | |
| raw = call_groq(messages, temperature=0.3, max_tokens=512) | |
| lines = raw.strip().split("\n") | |
| steps = [l.strip() for l in lines if l.strip() and ( | |
| l.strip()[0].isdigit() or l.strip().lower().startswith("step") | |
| )] | |
| # Fallback: if no numbered lines, return original text split by newlines | |
| return steps if steps else [l.strip() for l in lines if l.strip()] | |
| def verify_answer_llm(messages: list[dict]) -> dict: | |
| """ | |
| Calls Groq to act as a Faithfulness/NLI judge. | |
| Expects the prompt to dictate a YES/NO verdict followed by an explanation. | |
| """ | |
| raw = call_groq(messages, temperature=0.1, max_tokens=150) | |
| lines = raw.strip().split("\n") | |
| first_line = lines[0].strip().upper() | |
| verified = "YES" in first_line and "NO" not in first_line | |
| explanation = " ".join(lines[1:]).strip() if len(lines) > 1 else first_line | |
| return { | |
| "verified": verified, | |
| "explanation": f"LLM Judge: {explanation}" | |
| } | |