""" AI processor module for FactsDB service Handles communication with OpenAI compatible endpoints """ import requests import json from typing import Dict, Any, Optional from .config import AIEndpointConfig class AIEndpointClient: """Client for communicating with OpenAI compatible endpoint""" def __init__(self, config: AIEndpointConfig): self.config = config self.base_url = config.url.rstrip('/') self.auth_token = config.auth_token def _get_headers(self) -> Dict[str, str]: """Get headers with authentication""" return { 'Authorization': f'Bearer {self.auth_token}', 'Content-Type': 'application/json' } def send_request(self, payload: Dict[str, Any]) -> Dict[str, Any]: """Send request to AI endpoint""" url = f"{self.base_url}/v1/chat/completions" try: response = requests.post( url, headers=self._get_headers(), json=payload, timeout=300 # 5 minute timeout ) response.raise_for_status() return response.json() except requests.exceptions.RequestException as e: raise Exception(f"AI endpoint request failed: {str(e)}") def extract_facts(self, text_content: str, prompt: str, model: str = "gpt-oss") -> Dict[str, Any]: """Extract facts from text using AI""" # Default prompt from requirements default_prompt = """Extract key facts from the following article in structured JSON format. Return only valid JSON without any additional text. Article Title: {title} Article Content: {article_content[:3000]}... Extract the following information: 1. Main topic/subject 2. Key entities (companies, people, locations, organizations) 3. Financial impact or implications 4. Key dates or time periods mentioned 5. Summary of main points Format the response as a JSON object with these fields: { "title": "{title}", "summary": "brief summary", "main_topic": "main topic", "key_entities": ["entity1", "entity2"], "financial_impact": "positive/negative/neutral", "key_dates": ["date1", "date2"], "main_points": ["point1", "point2", "point3"] }""" # Use provided prompt or default final_prompt = prompt if prompt else default_prompt # Create the payload payload = { "model": model, "messages": [ { "role": "user", "content": f"{final_prompt}\n\nArticle Content: {text_content[:3000]}" } ], "temperature": 0.3, "max_tokens": 1000 } try: response = self.send_request(payload) # Extract the response text if 'choices' in response and len(response['choices']) > 0: response_text = response['choices'][0]['message']['content'] # Try to parse JSON try: # Clean up the response to ensure valid JSON response_text = response_text.strip() if response_text.startswith('```json'): response_text = response_text[7:-3].strip() elif response_text.startswith('```'): response_text = response_text[3:-3].strip() return json.loads(response_text) except json.JSONDecodeError: # If JSON parsing fails, return the raw response as a structured format return { "raw_response": response_text, "title": "Unknown", "summary": response_text[:200] + "..." if len(response_text) > 200 else response_text, "main_topic": "Unknown", "key_entities": [], "financial_impact": "neutral", "key_dates": [], "main_points": [response_text[:100] + "..."] if len(response_text) > 100 else [response_text] } else: raise Exception("No response from AI model") except Exception as e: raise Exception(f"Fact extraction failed: {str(e)}") class AIProcessor: """Main AI processor class for FactsDB""" def __init__(self, config: AIEndpointConfig): self.client = AIEndpointClient(config) def extract_facts_from_text(self, text_content: str, prompt: str = "", model: str = "gpt-oss") -> Dict[str, Any]: """Extract facts from text content using AI""" return self.client.extract_facts(text_content, prompt, model) def validate_model_support(self, model: str) -> bool: """Validate if model is supported""" # In a real implementation, this would check against available models supported_models = ["gpt-oss", "qwen3", "qwen3-coder"] return model in supported_models