diff --git a/analyticshub/js/admin.js b/analyticshub/js/admin.js index 5651040..0df1730 100644 --- a/analyticshub/js/admin.js +++ b/analyticshub/js/admin.js @@ -26,6 +26,7 @@ google_client_id: document.getElementById('google_client_id').value, google_client_secret: document.getElementById('google_client_secret').value, google_refresh_token: document.getElementById('google_refresh_token').value, + llm_api_endpoint: document.getElementById('llm_api_endpoint').value, anthropic_api_key: document.getElementById('anthropic_api_key').value }; @@ -94,6 +95,7 @@ document.getElementById('google_client_id').value = data.data.google_client_id || ''; document.getElementById('google_client_secret').value = ''; document.getElementById('google_refresh_token').value = ''; + document.getElementById('llm_api_endpoint').value = data.data.llm_api_endpoint || ''; document.getElementById('anthropic_api_key').value = ''; updateStatus(!!data.data.is_configured); showNotification('Success', 'Configuration loaded'); diff --git a/analyticshub/lib/Controller/AdminController.php b/analyticshub/lib/Controller/AdminController.php index 1998671..d182818 100644 --- a/analyticshub/lib/Controller/AdminController.php +++ b/analyticshub/lib/Controller/AdminController.php @@ -33,6 +33,7 @@ class AdminController { public function load(): JSONResponse { $clientId = $this->config->getAppValue('google_client_id', 'analyticshub', ''); $apiKey = $this->config->getAppValue('anthropic_api_key', 'analyticshub', ''); + $llmEndpoint = $this->config->getAppValue('llm_api_endpoint', 'analyticshub', ''); $refreshToken = $this->config->getAppValue('google_refresh_token', 'analyticshub', ''); // Check if configured @@ -54,6 +55,7 @@ class AdminController { 'data' => [ 'google_client_id' => $clientId, 'google_refresh_token' => $maskedRefreshToken, + 'llm_api_endpoint' => $llmEndpoint, 'anthropic_api_key' => $maskedApiKey, 'is_configured' => $isConfigured, ], @@ -77,6 +79,7 @@ class AdminController { $clientSecret = $data['google_client_secret'] ?? ''; $refreshToken = $data['google_refresh_token'] ?? ''; $apiKey = $data['anthropic_api_key'] ?? ''; + $llmEndpoint = $data['llm_api_endpoint'] ?? ''; if (empty($clientId) || empty($clientSecret) || empty($apiKey)) { return new JSONResponse([ @@ -93,6 +96,10 @@ class AdminController { $this->config->setAppValue('google_refresh_token', 'analyticshub', $refreshToken); } + if (!empty($llmEndpoint)) { + $this->config->setAppValue('llm_api_endpoint', 'analyticshub', $llmEndpoint); + } + $this->config->setAppValue('anthropic_api_key', 'analyticshub', $apiKey); // Check if fully configured diff --git a/analyticshub/lib/Controller/PageController.php b/analyticshub/lib/Controller/PageController.php index ec5cd21..8ad0a64 100644 --- a/analyticshub/lib/Controller/PageController.php +++ b/analyticshub/lib/Controller/PageController.php @@ -61,6 +61,7 @@ class PageController extends \OCP\AppFramework\Controller { // Get configuration values (masked for secrets) $clientId = $this->config->getAppValue('google_client_id', 'analyticshub', ''); $apiKey = $this->config->getAppValue('anthropic_api_key', 'analyticshub', ''); + $llmEndpoint = $this->config->getAppValue('llm_api_endpoint', 'analyticshub', ''); // Mask API key for display $maskedApiKey = ''; @@ -76,6 +77,7 @@ class PageController extends \OCP\AppFramework\Controller { 'is_ga_configured' => $isGAConfigured, 'is_llm_configured' => $isLLMConfigured, 'google_client_id' => $clientId, + 'llm_api_endpoint' => $llmEndpoint, 'anthropic_api_key_masked' => $maskedApiKey, 'request' => $this->request, ]); diff --git a/analyticshub/lib/Service/LLMService.php b/analyticshub/lib/Service/LLMService.php index 6215729..aeb52b3 100644 --- a/analyticshub/lib/Service/LLMService.php +++ b/analyticshub/lib/Service/LLMService.php @@ -17,8 +17,8 @@ class LLMService { private IConfig $config; private ?ILogger $logger; - // Anthropic API endpoint - private const ANTHROPIC_API = 'https://api.anthropic.com/v1/messages'; + // Anthropic API endpoint (default) + private const DEFAULT_API_ENDPOINT = 'https://api.anthropic.com/v1/messages'; private const MAX_RETRIES = 3; private const RATE_LIMIT_DELAY = 12; // Seconds to wait between retries private const TIMEOUT_SECONDS = 30; @@ -44,17 +44,21 @@ class LLMService { try { $apiKey = $this->config->getAppValue('anthropic_api_key', 'analyticshub'); + $apiEndpoint = $this->config->getAppValue('llm_api_endpoint', 'analyticshub', ''); if (empty($apiKey)) { - throw new \Exception('Anthropic API key not configured'); + throw new \Exception('API key not configured'); } + // Use configured endpoint or default to Anthropic + $endpoint = !empty($apiEndpoint) ? $apiEndpoint : self::DEFAULT_API_ENDPOINT; + // Build prompt $systemPrompt = $this->buildSystemPrompt($client); $userPrompt = $this->buildUserPrompt($processedData); // Call with retry - $response = $this->callWithRetry($systemPrompt, $userPrompt, $apiKey); + $response = $this->callWithRetry($systemPrompt, $userPrompt, $apiKey, $endpoint); return $response; @@ -120,12 +124,12 @@ PROMPT; /** * Call Claude API with retry logic */ - private function callWithRetry(string $systemPrompt, string $userPrompt, string $apiKey): string { + private function callWithRetry(string $systemPrompt, string $userPrompt, string $apiKey, string $endpoint): string { for ($attempt = 0; $attempt < self::MAX_RETRIES; $attempt++) { $this->logger->info("LLM API call attempt {$attempt}/" . self::MAX_RETRIES); try { - $response = $this->makeLLMRequest($systemPrompt, $userPrompt, $apiKey); + $response = $this->makeLLMRequest($systemPrompt, $userPrompt, $apiKey, $endpoint); // Validate response $this->validateResponse($response); @@ -180,9 +184,9 @@ PROMPT; } /** - * Make HTTP request to Anthropic API + * Make HTTP request to LLM API */ - private function makeLLMRequest(string $systemPrompt, string $userPrompt, string $apiKey): string { + private function makeLLMRequest(string $systemPrompt, string $userPrompt, string $apiKey, string $endpoint): string { $ch = curl_init(); $payload = [ @@ -197,7 +201,7 @@ PROMPT; ] ]; - curl_setopt($ch, CURLOPT_URL, self::ANTHROPIC_API); + curl_setopt($ch, CURLOPT_URL, $endpoint); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); diff --git a/analyticshub/templates/admin.php b/analyticshub/templates/admin.php index 836c861..399be85 100644 --- a/analyticshub/templates/admin.php +++ b/analyticshub/templates/admin.php @@ -76,9 +76,27 @@ style('display:none'); - +
-

t('Anthropic Claude API')); ?>

+

t('LLM Configuration (Claude-compatible)')); ?>

+ +
+ + +

+ t('Enter a Claude-compatible API endpoint. Leave blank to use Anthropic official API.')); ?> +

+