134 lines
5.0 KiB
Python
134 lines
5.0 KiB
Python
"""
|
|
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 |