Feature: Add configurable LLM model name
This commit is contained in:
@@ -27,6 +27,7 @@
|
|||||||
google_client_secret: document.getElementById('google_client_secret').value,
|
google_client_secret: document.getElementById('google_client_secret').value,
|
||||||
google_refresh_token: document.getElementById('google_refresh_token').value,
|
google_refresh_token: document.getElementById('google_refresh_token').value,
|
||||||
llm_api_endpoint: document.getElementById('llm_api_endpoint').value,
|
llm_api_endpoint: document.getElementById('llm_api_endpoint').value,
|
||||||
|
llm_model: document.getElementById('llm_model').value,
|
||||||
anthropic_api_key: document.getElementById('anthropic_api_key').value
|
anthropic_api_key: document.getElementById('anthropic_api_key').value
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -96,6 +97,7 @@
|
|||||||
document.getElementById('google_client_secret').value = '';
|
document.getElementById('google_client_secret').value = '';
|
||||||
document.getElementById('google_refresh_token').value = '';
|
document.getElementById('google_refresh_token').value = '';
|
||||||
document.getElementById('llm_api_endpoint').value = data.data.llm_api_endpoint || '';
|
document.getElementById('llm_api_endpoint').value = data.data.llm_api_endpoint || '';
|
||||||
|
document.getElementById('llm_model').value = data.data.llm_model || '';
|
||||||
document.getElementById('anthropic_api_key').value = '';
|
document.getElementById('anthropic_api_key').value = '';
|
||||||
updateStatus(!!data.data.is_configured);
|
updateStatus(!!data.data.is_configured);
|
||||||
showNotification('Success', 'Configuration loaded');
|
showNotification('Success', 'Configuration loaded');
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ class AdminController {
|
|||||||
$clientId = $this->config->getAppValue('google_client_id', 'analyticshub', '');
|
$clientId = $this->config->getAppValue('google_client_id', 'analyticshub', '');
|
||||||
$apiKey = $this->config->getAppValue('anthropic_api_key', 'analyticshub', '');
|
$apiKey = $this->config->getAppValue('anthropic_api_key', 'analyticshub', '');
|
||||||
$llmEndpoint = $this->config->getAppValue('llm_api_endpoint', 'analyticshub', '');
|
$llmEndpoint = $this->config->getAppValue('llm_api_endpoint', 'analyticshub', '');
|
||||||
|
$llmModel = $this->config->getAppValue('llm_model', 'analyticshub', '');
|
||||||
$refreshToken = $this->config->getAppValue('google_refresh_token', 'analyticshub', '');
|
$refreshToken = $this->config->getAppValue('google_refresh_token', 'analyticshub', '');
|
||||||
|
|
||||||
// Check if configured
|
// Check if configured
|
||||||
@@ -56,6 +57,7 @@ class AdminController {
|
|||||||
'google_client_id' => $clientId,
|
'google_client_id' => $clientId,
|
||||||
'google_refresh_token' => $maskedRefreshToken,
|
'google_refresh_token' => $maskedRefreshToken,
|
||||||
'llm_api_endpoint' => $llmEndpoint,
|
'llm_api_endpoint' => $llmEndpoint,
|
||||||
|
'llm_model' => $llmModel,
|
||||||
'anthropic_api_key' => $maskedApiKey,
|
'anthropic_api_key' => $maskedApiKey,
|
||||||
'is_configured' => $isConfigured,
|
'is_configured' => $isConfigured,
|
||||||
],
|
],
|
||||||
@@ -80,6 +82,7 @@ class AdminController {
|
|||||||
$refreshToken = $data['google_refresh_token'] ?? '';
|
$refreshToken = $data['google_refresh_token'] ?? '';
|
||||||
$apiKey = $data['anthropic_api_key'] ?? '';
|
$apiKey = $data['anthropic_api_key'] ?? '';
|
||||||
$llmEndpoint = $data['llm_api_endpoint'] ?? '';
|
$llmEndpoint = $data['llm_api_endpoint'] ?? '';
|
||||||
|
$llmModel = $data['llm_model'] ?? '';
|
||||||
|
|
||||||
if (empty($clientId) || empty($clientSecret) || empty($apiKey)) {
|
if (empty($clientId) || empty($clientSecret) || empty($apiKey)) {
|
||||||
return new JSONResponse([
|
return new JSONResponse([
|
||||||
@@ -100,6 +103,10 @@ class AdminController {
|
|||||||
$this->config->setAppValue('llm_api_endpoint', 'analyticshub', $llmEndpoint);
|
$this->config->setAppValue('llm_api_endpoint', 'analyticshub', $llmEndpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!empty($llmModel)) {
|
||||||
|
$this->config->setAppValue('llm_model', 'analyticshub', $llmModel);
|
||||||
|
}
|
||||||
|
|
||||||
$this->config->setAppValue('anthropic_api_key', 'analyticshub', $apiKey);
|
$this->config->setAppValue('anthropic_api_key', 'analyticshub', $apiKey);
|
||||||
|
|
||||||
// Check if fully configured
|
// Check if fully configured
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ class PageController extends \OCP\AppFramework\Controller {
|
|||||||
$clientId = $this->config->getAppValue('google_client_id', 'analyticshub', '');
|
$clientId = $this->config->getAppValue('google_client_id', 'analyticshub', '');
|
||||||
$apiKey = $this->config->getAppValue('anthropic_api_key', 'analyticshub', '');
|
$apiKey = $this->config->getAppValue('anthropic_api_key', 'analyticshub', '');
|
||||||
$llmEndpoint = $this->config->getAppValue('llm_api_endpoint', 'analyticshub', '');
|
$llmEndpoint = $this->config->getAppValue('llm_api_endpoint', 'analyticshub', '');
|
||||||
|
$llmModel = $this->config->getAppValue('llm_model', 'analyticshub', '');
|
||||||
|
|
||||||
// Mask API key for display
|
// Mask API key for display
|
||||||
$maskedApiKey = '';
|
$maskedApiKey = '';
|
||||||
@@ -78,6 +79,7 @@ class PageController extends \OCP\AppFramework\Controller {
|
|||||||
'is_llm_configured' => $isLLMConfigured,
|
'is_llm_configured' => $isLLMConfigured,
|
||||||
'google_client_id' => $clientId,
|
'google_client_id' => $clientId,
|
||||||
'llm_api_endpoint' => $llmEndpoint,
|
'llm_api_endpoint' => $llmEndpoint,
|
||||||
|
'llm_model' => $llmModel,
|
||||||
'anthropic_api_key_masked' => $maskedApiKey,
|
'anthropic_api_key_masked' => $maskedApiKey,
|
||||||
'request' => $this->request,
|
'request' => $this->request,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ class LLMService {
|
|||||||
try {
|
try {
|
||||||
$apiKey = $this->config->getAppValue('anthropic_api_key', 'analyticshub');
|
$apiKey = $this->config->getAppValue('anthropic_api_key', 'analyticshub');
|
||||||
$apiEndpoint = $this->config->getAppValue('llm_api_endpoint', 'analyticshub', '');
|
$apiEndpoint = $this->config->getAppValue('llm_api_endpoint', 'analyticshub', '');
|
||||||
|
$model = $this->config->getAppValue('llm_model', 'analyticshub', 'claude-sonnet-4-5-20250929');
|
||||||
|
|
||||||
if (empty($apiKey)) {
|
if (empty($apiKey)) {
|
||||||
throw new \Exception('API key not configured');
|
throw new \Exception('API key not configured');
|
||||||
@@ -58,7 +59,7 @@ class LLMService {
|
|||||||
$userPrompt = $this->buildUserPrompt($processedData);
|
$userPrompt = $this->buildUserPrompt($processedData);
|
||||||
|
|
||||||
// Call with retry
|
// Call with retry
|
||||||
$response = $this->callWithRetry($systemPrompt, $userPrompt, $apiKey, $endpoint);
|
$response = $this->callWithRetry($systemPrompt, $userPrompt, $apiKey, $endpoint, $model);
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
|
|
||||||
@@ -124,12 +125,12 @@ PROMPT;
|
|||||||
/**
|
/**
|
||||||
* Call Claude API with retry logic
|
* Call Claude API with retry logic
|
||||||
*/
|
*/
|
||||||
private function callWithRetry(string $systemPrompt, string $userPrompt, string $apiKey, string $endpoint): string {
|
private function callWithRetry(string $systemPrompt, string $userPrompt, string $apiKey, string $endpoint, string $model): string {
|
||||||
for ($attempt = 0; $attempt < self::MAX_RETRIES; $attempt++) {
|
for ($attempt = 0; $attempt < self::MAX_RETRIES; $attempt++) {
|
||||||
$this->logger->info("LLM API call attempt {$attempt}/" . self::MAX_RETRIES);
|
$this->logger->info("LLM API call attempt {$attempt}/" . self::MAX_RETRIES);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$response = $this->makeLLMRequest($systemPrompt, $userPrompt, $apiKey, $endpoint);
|
$response = $this->makeLLMRequest($systemPrompt, $userPrompt, $apiKey, $endpoint, $model);
|
||||||
|
|
||||||
// Validate response
|
// Validate response
|
||||||
$this->validateResponse($response);
|
$this->validateResponse($response);
|
||||||
@@ -186,11 +187,11 @@ PROMPT;
|
|||||||
/**
|
/**
|
||||||
* Make HTTP request to LLM API
|
* Make HTTP request to LLM API
|
||||||
*/
|
*/
|
||||||
private function makeLLMRequest(string $systemPrompt, string $userPrompt, string $apiKey, string $endpoint): string {
|
private function makeLLMRequest(string $systemPrompt, string $userPrompt, string $apiKey, string $endpoint, string $model): string {
|
||||||
$ch = curl_init();
|
$ch = curl_init();
|
||||||
|
|
||||||
$payload = [
|
$payload = [
|
||||||
'model' => 'claude-sonnet-4-5-20250929',
|
'model' => $model,
|
||||||
'max_tokens' => 2000,
|
'max_tokens' => 2000,
|
||||||
'system' => $systemPrompt,
|
'system' => $systemPrompt,
|
||||||
'messages' => [
|
'messages' => [
|
||||||
|
|||||||
@@ -98,6 +98,24 @@ style('display:none');
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="analytics-hub-settings__field">
|
||||||
|
<label for="llm_model">
|
||||||
|
<?php p($l->t('Model')); ?>
|
||||||
|
<span class="analytics-hub-settings__optional"><?php p($l->t('(Optional - defaults to claude-sonnet-4-5-20250929)')); ?></span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="llm_model"
|
||||||
|
name="llm_model"
|
||||||
|
value="<?php p($_['llm_model']); ?>"
|
||||||
|
placeholder="claude-sonnet-4-5-20250929"
|
||||||
|
autocomplete="off"
|
||||||
|
/>
|
||||||
|
<p class="analytics-hub-settings__hint">
|
||||||
|
<?php p($l->t('Enter the model to use. Examples: claude-sonnet-4-5-20250929, claude-3-5-sonnet-20241022, claude-3-opus-20240229')); ?>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="analytics-hub-settings__field">
|
<div class="analytics-hub-settings__field">
|
||||||
<label for="anthropic_api_key">
|
<label for="anthropic_api_key">
|
||||||
<?php p($l->t('API Key')); ?>
|
<?php p($l->t('API Key')); ?>
|
||||||
|
|||||||
90
oauth-helper.php
Normal file
90
oauth-helper.php
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* OAuth 2.0 Helper for Google Analytics
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* 1. Get authorization code from OAuth flow (see guide)
|
||||||
|
* 2. Run: php oauth-helper.php YOUR_AUTHORIZATION_CODE
|
||||||
|
* 3. Get refresh_token output
|
||||||
|
* 4. Enter refresh_token into Nextcloud plugin settings
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Configuration - Update with your values
|
||||||
|
$CLIENT_ID = 'YOUR_CLIENT_ID.apps.googleusercontent.com';
|
||||||
|
$CLIENT_SECRET = 'GOCSPX-XXXXXXXXXXXXXX'; // From Google Cloud Console
|
||||||
|
$REDIRECT_URI = 'https://teamworkapps.com/index.php/apps/analyticshub/';
|
||||||
|
|
||||||
|
// Get authorization code from command line
|
||||||
|
if ($argc < 2) {
|
||||||
|
echo "Usage: php oauth-helper.php <authorization_code>\n";
|
||||||
|
echo "\n";
|
||||||
|
echo "Get authorization code from:\n";
|
||||||
|
echo "https://accounts.google.com/o/oauth2/v2/auth?\n";
|
||||||
|
echo " client_id=$CLIENT_ID\n";
|
||||||
|
echo " &redirect_uri=" . urlencode($REDIRECT_URI) . "\n";
|
||||||
|
echo " &response_type=code\n";
|
||||||
|
echo " &scope=" . urlencode('https://www.googleapis.com/auth/analytics.readonly https://www.googleapis.com/auth/analytics') . "\n";
|
||||||
|
echo "\n";
|
||||||
|
echo "After granting permissions, copy the 'code' parameter from the redirect URL.\n";
|
||||||
|
echo "\n";
|
||||||
|
die(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$authCode = $argv[1];
|
||||||
|
|
||||||
|
// Exchange authorization code for tokens
|
||||||
|
$tokenUrl = 'https://oauth2.googleapis.com/token';
|
||||||
|
|
||||||
|
$postData = [
|
||||||
|
'code' => $authCode,
|
||||||
|
'client_id' => $CLIENT_ID,
|
||||||
|
'client_secret' => $CLIENT_SECRET,
|
||||||
|
'redirect_uri' => $REDIRECT_URI,
|
||||||
|
'grant_type' => 'authorization_code'
|
||||||
|
];
|
||||||
|
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $tokenUrl);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||||
|
'Content-Type: application/x-www-form-urlencoded'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
|
||||||
|
if (curl_errno($ch)) {
|
||||||
|
echo "Curl error: " . curl_error($ch) . "\n";
|
||||||
|
curl_close($ch);
|
||||||
|
die(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if ($httpCode !== 200) {
|
||||||
|
echo "Error: HTTP $httpCode\n";
|
||||||
|
echo "Response: $response\n";
|
||||||
|
die(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse JSON response
|
||||||
|
$data = json_decode($response, true);
|
||||||
|
|
||||||
|
if (!$data || empty($data['refresh_token'])) {
|
||||||
|
echo "Error: No refresh_token in response\n";
|
||||||
|
echo "Response: " . json_encode($data, JSON_PRETTY_PRINT) . "\n";
|
||||||
|
die(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success!
|
||||||
|
echo "✅ Success! Here are your tokens:\n\n";
|
||||||
|
echo "ACCESS TOKEN (expires in 1 hour):\n";
|
||||||
|
echo $data['access_token'] . "\n\n";
|
||||||
|
echo "REFRESH TOKEN (save this in Nextcloud plugin):\n";
|
||||||
|
echo $data['refresh_token'] . "\n\n";
|
||||||
|
echo "Token type: " . $data['token_type'] . "\n";
|
||||||
|
echo "Expires in: " . $data['expires_in'] . " seconds\n";
|
||||||
|
echo "\n";
|
||||||
|
echo "💡 Now enter the REFRESH TOKEN into the plugin settings!\n";
|
||||||
Reference in New Issue
Block a user