feat: migrate from Anthropic API to OpenRouter

Replace direct Anthropic API integration with OpenRouter to enable
more flexible LLM provider access while maintaining Claude 3.5 Sonnet.

Changes:
- Replace anthropic package with openai in requirements.txt
- Update config to use OPENROUTER_API_KEY instead of ANTHROPIC_API_KEY
- Migrate LLMAnalyzer from Anthropic client to OpenAI client with
  OpenRouter base URL (https://openrouter.ai/api/v1)
- Update model identifier to OpenRouter format: anthropic/claude-3.5-sonnet
- Convert API calls from messages.create() to chat.completions.create()
- Update response parsing to match OpenAI format
- Rename API key parameter in CompanyAnalyzer from anthropic_api_key
  to openrouter_api_key
- Update all tests to mock OpenAI client instead of Anthropic
- Fix client initialization to accept direct API key parameter

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-02-22 12:26:56 -05:00
parent 8971ebc913
commit af4114969a
6 changed files with 55 additions and 46 deletions
+3 -3
View File
@@ -13,13 +13,13 @@ from typing import List
class CompanyAnalyzer:
"""Orchestrates end-to-end company performance analysis via patents."""
def __init__(self, anthropic_api_key: str | None = None):
def __init__(self, openrouter_api_key: str | None = None):
"""Initialize the company analyzer.
Args:
anthropic_api_key: Optional Anthropic API key. If None, loads from config.
openrouter_api_key: Optional OpenRouter API key. If None, loads from config.
"""
self.llm_analyzer = LLMAnalyzer(api_key=anthropic_api_key)
self.llm_analyzer = LLMAnalyzer(api_key=openrouter_api_key)
def analyze_company(self, company_name: str) -> str:
"""Analyze a company's performance based on their patent portfolio.
+2 -2
View File
@@ -10,5 +10,5 @@ load_dotenv()
# SerpAPI key for patent search
api_key = os.getenv("API_KEY")
# Anthropic API key for LLM analysis
anthropic_api_key = os.getenv("ANTHROPIC_API_KEY")
# OpenRouter API key for LLM analysis
openrouter_api_key = os.getenv("OPENROUTER_API_KEY")
+13 -10
View File
@@ -1,6 +1,6 @@
"""LLM integration for patent analysis using Anthropic's Claude."""
"""LLM integration for patent analysis using OpenRouter."""
from anthropic import Anthropic
from openai import OpenAI
from SPARC import config
from typing import Dict
@@ -12,14 +12,17 @@ class LLMAnalyzer:
"""Initialize the LLM analyzer.
Args:
api_key: Anthropic API key. If None, will attempt to load from config.
api_key: OpenRouter API key. If None, will attempt to load from config.
test_mode: If True, print prompts instead of making API calls
"""
self.test_mode = test_mode
if config.anthropic_api_key and not test_mode:
self.client = Anthropic(api_key=api_key or config.anthropic_api_key)
self.model = "claude-3-5-sonnet-20241022"
if (api_key or config.openrouter_api_key) and not test_mode:
self.client = OpenAI(
api_key=api_key or config.openrouter_api_key,
base_url="https://openrouter.ai/api/v1"
)
self.model = "anthropic/claude-3.5-sonnet"
else:
self.client = None
@@ -55,12 +58,12 @@ Provide a concise analysis (2-3 paragraphs) focusing on what this patent reveals
return "[TEST MODE - No API call made]"
if self.client:
message = self.client.messages.create(
response = self.client.chat.completions.create(
model=self.model,
max_tokens=1024,
messages=[{"role": "user", "content": prompt}],
)
return message.content[0].text
return response.choices[0].message.content
def analyze_patent_portfolio(
self, patents_data: list[Dict[str, str]], company_name: str
@@ -103,13 +106,13 @@ Provide a comprehensive analysis (4-5 paragraphs) with a final verdict on the co
return "[TEST MODE]"
try:
message = self.client.messages.create(
response = self.client.chat.completions.create(
model=self.model,
max_tokens=2048,
messages=[{"role": "user", "content": prompt}],
)
return message.content[0].text
return response.choices[0].message.content
except AttributeError:
return prompt