Add API key authentication for AI service connections

This commit is contained in:
Jarian Cottingham 2026-02-02 04:29:50 -06:00
parent f6ded4fc14
commit 68704b6edd
8 changed files with 96 additions and 0 deletions

View File

@ -53,6 +53,7 @@ The server supports configuration through environment variables:
- `FLASK_ENV` - Set to 'development' or 'production' (default: 'development') - `FLASK_ENV` - Set to 'development' or 'production' (default: 'development')
- `DATABASE_URL` - URL for database connection (e.g., PostgreSQL) - `DATABASE_URL` - URL for database connection (e.g., PostgreSQL)
- `API_KEY` - API key for external services - `API_KEY` - API key for external services
- `AI_SERVICE_API_KEY` - API key for authenticating with the centralized AI service at http://example.com:4000
- `LOG_LEVEL` - Logging level (DEBUG, INFO, WARNING, ERROR) - `LOG_LEVEL` - Logging level (DEBUG, INFO, WARNING, ERROR)
## Installation ## Installation

View File

@ -106,12 +106,22 @@ def get_embedding(text):
""" """
try: try:
# Using the OpenAI-compatible endpoint for embeddings # Using the OpenAI-compatible endpoint for embeddings
headers = {
"Content-Type": "application/json"
}
# Add API key if available
api_key = os.getenv("AI_SERVICE_API_KEY")
if api_key:
headers["Authorization"] = f"Bearer {api_key}"
response = requests.post( response = requests.post(
"http://example.com:4000/v1/embeddings", "http://example.com:4000/v1/embeddings",
json={ json={
"input": text, "input": text,
"model": "text-embedding-3-small" # or whatever model you're using "model": "text-embedding-3-small" # or whatever model you're using
}, },
headers=headers,
timeout=30 timeout=30
) )
response.raise_for_status() response.raise_for_status()

View File

@ -265,6 +265,12 @@ scraper/
### Environment Variables ### Environment Variables
Each project may require specific environment variables. Check individual `README.md` files for details. Each project may require specific environment variables. Check individual `README.md` files for details.
### Authentication
The system now supports API key authentication for connections to the centralized AI service at `http://example.com:4000`. To enable authentication:
1. Set the `AI_SERVICE_API_KEY` environment variable with your API key
2. All connections to the AI service will automatically include the `Authorization: Bearer {api_key}` header
### Data Storage ### Data Storage
- Articles are stored in the scraper component - Articles are stored in the scraper component
- Processed data flows through the ai_processor - Processed data flows through the ai_processor

View File

@ -12,6 +12,9 @@ AI_SERVER_HOST = os.getenv("AI_SERVER_HOST", "example.com")
AI_SERVER_PORT = os.getenv("AI_SERVER_PORT", "4000") AI_SERVER_PORT = os.getenv("AI_SERVER_PORT", "4000")
AI_SERVER_URL = f"http://{AI_SERVER_HOST}:{AI_SERVER_PORT}" AI_SERVER_URL = f"http://{AI_SERVER_HOST}:{AI_SERVER_PORT}"
# API Key for AI service authentication
AI_SERVICE_API_KEY = os.getenv("AI_SERVICE_API_KEY")
def process_article_content(article_content, filename, source): def process_article_content(article_content, filename, source):
""" """
Process article content and extract key facts using the centralized AI service Process article content and extract key facts using the centralized AI service
@ -21,6 +24,14 @@ def process_article_content(article_content, filename, source):
# Use the gpt-oss model for fact extraction as specified # Use the gpt-oss model for fact extraction as specified
extraction_url = f"{AI_SERVER_URL}/v1/chat/completions" extraction_url = f"{AI_SERVER_URL}/v1/chat/completions"
# Build headers with authentication if available
headers = {
"Content-Type": "application/json"
}
if AI_SERVICE_API_KEY:
headers["Authorization"] = f"Bearer {AI_SERVICE_API_KEY}"
# Create a proper prompt for fact extraction # Create a proper prompt for fact extraction
prompt = f""" prompt = f"""
Extract key facts from the following article in structured JSON format. Extract key facts from the following article in structured JSON format.
@ -65,6 +76,7 @@ def process_article_content(article_content, filename, source):
"temperature": 0.3, "temperature": 0.3,
"max_tokens": 1000 "max_tokens": 1000
}, },
headers=headers,
timeout=60 timeout=60
) )

View File

@ -35,6 +35,7 @@ services:
- ./ai_processor/output:/app/output - ./ai_processor/output:/app/output
environment: environment:
- AI_SERVICE_URL=http://example.com:4000 - AI_SERVICE_URL=http://example.com:4000
- AI_SERVICE_API_KEY=${AI_SERVICE_API_KEY}
embedder: embedder:
build: ./embedding build: ./embedding
platform: linux/amd64 platform: linux/amd64
@ -52,6 +53,7 @@ services:
- AI_SERVER_PORT=4000 - AI_SERVER_PORT=4000
- CACHE_FILE=/app/processed_articles_cache.json - CACHE_FILE=/app/processed_articles_cache.json
- LOG_LEVEL=INFO - LOG_LEVEL=INFO
- AI_SERVICE_API_KEY=${AI_SERVICE_API_KEY}
networks: networks:
ainetwork: ainetwork:

View File

@ -65,6 +65,9 @@ CACHE_FILE = os.getenv("CACHE_FILE", "processed_articles_cache.json")
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "placeholder-key") OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "placeholder-key")
OPENAI_BASE_URL = os.getenv("OPENAI_BASE_URL", f"http://{AI_SERVER_HOST}:{AI_SERVER_PORT}") OPENAI_BASE_URL = os.getenv("OPENAI_BASE_URL", f"http://{AI_SERVER_HOST}:{AI_SERVER_PORT}")
# API Key for AI service authentication
AI_SERVICE_API_KEY = os.getenv("AI_SERVICE_API_KEY")
# Batch processing configuration # Batch processing configuration
BATCH_SIZE = int(os.getenv("EMBEDDING_BATCH_SIZE", "50")) BATCH_SIZE = int(os.getenv("EMBEDDING_BATCH_SIZE", "50"))
@ -74,12 +77,22 @@ def get_embedding(text):
""" """
try: try:
embedding_url = f"{AI_SERVER_URL}/v1/embeddings" embedding_url = f"{AI_SERVER_URL}/v1/embeddings"
# Build headers with authentication if available
headers = {
"Content-Type": "application/json"
}
if AI_SERVICE_API_KEY:
headers["Authorization"] = f"Bearer {AI_SERVICE_API_KEY}"
response = requests.post( response = requests.post(
embedding_url, embedding_url,
json={ json={
"input": text, "input": text,
"model": "qwen3:8b" "model": "qwen3:8b"
}, },
headers=headers,
timeout=60 timeout=60
) )
response.raise_for_status() response.raise_for_status()
@ -97,6 +110,14 @@ def extract_facts_from_article(article_content, title):
# Use the centralized AI endpoint for fact extraction # Use the centralized AI endpoint for fact extraction
extraction_url = f"{AI_SERVER_URL}/v1/chat/completions" extraction_url = f"{AI_SERVER_URL}/v1/chat/completions"
# Build headers with authentication if available
headers = {
"Content-Type": "application/json"
}
if AI_SERVICE_API_KEY:
headers["Authorization"] = f"Bearer {AI_SERVICE_API_KEY}"
# Create a proper prompt for fact extraction # Create a proper prompt for fact extraction
prompt = f""" prompt = f"""
Extract key facts from the following article in structured JSON format. Extract key facts from the following article in structured JSON format.
@ -136,6 +157,7 @@ def extract_facts_from_article(article_content, title):
"temperature": 0.3, "temperature": 0.3,
"max_tokens": 1000 "max_tokens": 1000
}, },
headers=headers,
timeout=60 timeout=60
) )

43
test_implementation.py Normal file
View File

@ -0,0 +1,43 @@
#!/usr/bin/env python3
"""
Test script to verify the enhanced cache system implementation
"""
import json
import os
import datetime
from scraper.scraper import load_processed_cache, save_processed_cache, get_processing_progress
def test_cache_system():
"""Test the enhanced cache system"""
print("Testing enhanced cache system...")
# Test loading cache (should work even if file doesn't exist)
cache = load_processed_cache()
print(f"Initial cache loaded: {len(cache)} entries")
# Test saving cache
test_entry = {
"test_article_path": {
"processed_date": datetime.datetime.now().isoformat(),
"status": "completed",
"embedding_status": "pending",
"last_updated": datetime.datetime.now().isoformat()
}
}
save_processed_cache(test_entry)
print("Cache saved successfully")
# Test loading again
cache = load_processed_cache()
print(f"Cache loaded after save: {len(cache)} entries")
# Test progress tracking
progress = get_processing_progress()
print(f"Progress tracking: {progress}")
print("Cache system test completed successfully!")
if __name__ == "__main__":
test_cache_system()