Download src/core/llm_engine.py from EATosin/Zeta: direct link, hf CLI and curl.
- Browser
- Download file 3.91 kB
-
https://huggingface.co/spaces/EATosin/Zeta/resolve/main/src/core/llm_engine.py
- Command line
-
hf download hf://spaces/EATosin/Zeta/src/core/llm_engine.py
-
curl -L -o llm_engine.py https://huggingface.co/spaces/EATosin/Zeta/resolve/main/src/core/llm_engine.py
3.91 kB
| import os | |
| import json | |
| import yaml | |
| from pathlib import Path | |
| from typing import List, Dict, Any | |
| import google.generativeai as genai | |
| from loguru import logger | |
| from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type | |
| from dotenv import load_dotenv | |
| # Load Env | |
| load_dotenv() | |
| API_KEY = os.getenv("GEMINI_API_KEY") | |
| if not API_KEY: | |
| logger.critical("GEMINI_API_KEY is missing") | |
| raise ValueError("GEMINI_API_KEY not found in environment") | |
| genai.configure(api_key=API_KEY) | |
| class LLMEngine: | |
| """ | |
| LLM Engine with Externalized Configuration. | |
| Loads prompts from config/prompts.yaml to ensure code/data separation. | |
| """ | |
| def __init__(self, model_name: str = "gemini-2.5-flash"): | |
| self.model_name = model_name | |
| self.model = genai.GenerativeModel(model_name) | |
| self.prompts = self._load_prompts() | |
| logger.info(f"LLM Engine initialized with {model_name}") | |
| def _load_prompts(self) -> Dict[str, Any]: | |
| """Loads prompt templates from the config directory.""" | |
| # Resolves path relative to this file: src/core/../../config/prompts.yaml | |
| base_path = Path(__file__).resolve().parent.parent.parent | |
| config_path = base_path / "config" / "prompts.yaml" | |
| if not config_path.exists(): | |
| raise FileNotFoundError(f"Configuration file not found at: {config_path}") | |
| with open(config_path, "r") as f: | |
| return yaml.safe_load(f) | |
| async def generate_test_cases(self, requirements_text: str) -> List[Dict[str, Any]]: | |
| logger.debug("Constructing prompt from configuration...") | |
| try: | |
| # Load config sections | |
| config = self.prompts["test_generation"] | |
| # 1. System Role & Context | |
| system_role = config.get("system_role", "") | |
| # 2. Main Instruction (Injecting the dynamic text) | |
| instruction = config.get("instruction", "").format( | |
| requirements_text=requirements_text[:30000] | |
| ) | |
| # 3. Few-Shot Examples (NEW: Capturing your expanded section) | |
| examples = config.get("few_shot_examples", "") | |
| # 4. Output Schema | |
| fmt = config.get("output_format", "") | |
| # Construct the Full Context Window | |
| # Order matters: Role -> Task -> Examples -> Strict JSON Format | |
| full_prompt = ( | |
| f"{system_role}\n\n" | |
| f"{instruction}\n\n" | |
| f"### REFERENCE EXAMPLES:\n{examples}\n\n" | |
| f"### REQUIRED OUTPUT FORMAT:\n{fmt}" | |
| ) | |
| # Async call | |
| response = await self.model.generate_content_async(full_prompt) | |
| return self._parse_json_response(response.text) | |
| except KeyError as e: | |
| logger.error(f"Missing configuration key in prompts.yaml: {e}") | |
| raise e | |
| except Exception as e: | |
| logger.error(f"LLM Generation Failed: {e}") | |
| raise e | |
| def _parse_json_response(self, text: str) -> List[Dict[str, Any]]: | |
| clean_text = text.strip() | |
| if clean_text.startswith("```json"): | |
| clean_text = clean_text[7:-3] | |
| elif clean_text.startswith("```"): | |
| clean_text = clean_text[3:-3] | |
| try: | |
| data = json.loads(clean_text) | |
| if not isinstance(data, list): | |
| raise ValueError("Output is not a list of test cases") | |
| return data | |
| except json.JSONDecodeError as e: | |
| logger.error("Failed to decode JSON response") | |
| raise ValueError(f"Malformed JSON from LLM: {e}") | |