Files
wp-agentic-writer/views/settings/tab-local-backend.php

418 lines
16 KiB
PHP

<?php
/**
* Settings Tab: Local Backend
*
* @package WP_Agentic_Writer
* @var string $local_backend_url
* @var string $local_backend_key
* @var string $local_backend_model
* @var bool $local_backend_enabled
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
<div class="row g-4">
<!-- Download Package -->
<div class="col-12">
<div class="card border-0">
<div class="card-header border-bottom-0 pt-3">
<div class="d-flex align-items-center">
<div>
<h5 class="card-title mb-1 d-flex align-items-center gap-2">
<i class="bi bi-download text-primary"></i>
<?php esc_html_e( 'Step 1: Download Local Backend Package', 'wp-agentic-writer' ); ?>
</h5>
<p class="text-muted small mb-0">
<?php esc_html_e( 'Run AI inference on your own machine with your Claude CLI + Z.ai account', 'wp-agentic-writer' ); ?>
</p>
</div>
</div>
</div>
<div class="card-body">
<p class="mb-3">
<?php esc_html_e( 'Download the Local Backend proxy to run on your development machine. This allows unlimited, private AI content generation using your existing Claude CLI setup.', 'wp-agentic-writer' ); ?>
</p>
<a href="https://downloads.wpagentic.dev/wp-agentic-writer/agentic-writer-local-backend.zip"
class="btn btn-primary btn-lg" target="_blank" rel="noopener">
<i class="bi bi-download me-2"></i>
<?php esc_html_e( 'Download Local Backend v1.1.0', 'wp-agentic-writer' ); ?>
</a>
<details class="mt-3">
<summary class="fw-semibold" style="cursor: pointer;">
<?php esc_html_e( 'Prerequisites', 'wp-agentic-writer' ); ?>
</summary>
<ul class="mt-2">
<li>
✅ <strong><?php esc_html_e( 'Claude CLI', 'wp-agentic-writer' ); ?></strong> -
<?php esc_html_e( 'Get from', 'wp-agentic-writer' ); ?>
<a href="https://claude.ai/code" target="_blank">claude.ai/code</a>
<?php esc_html_e( 'or', 'wp-agentic-writer' ); ?>
<a href="https://z.ai" target="_blank">z.ai</a>
</li>
<li>
✅ <strong><?php esc_html_e( 'Node.js 18+', 'wp-agentic-writer' ); ?></strong> -
<a href="https://nodejs.org" target="_blank"><?php esc_html_e( 'Download', 'wp-agentic-writer' ); ?></a>
</li>
<li>
✅ <strong><?php esc_html_e( 'Z.ai Coding Plan or Anthropic API key', 'wp-agentic-writer' ); ?></strong> -
<?php esc_html_e( 'Configured in Claude CLI', 'wp-agentic-writer' ); ?>
</li>
</ul>
</details>
</div>
</div>
</div>
<!-- Configuration -->
<div class="col-12">
<div class="card border-0 ">
<div class="card-header border-bottom-0 pt-3">
<div class="d-flex align-items-center">
<div>
<h5 class="card-title mb-1 d-flex align-items-center gap-2">
<i class="bi bi-gear-fill text-success"></i>
<?php esc_html_e( 'Step 2: Configure Connection', 'wp-agentic-writer' ); ?>
</h5>
<p class="text-muted small mb-0">
<?php esc_html_e( 'After starting the proxy, enter the connection details here', 'wp-agentic-writer' ); ?>
</p>
</div>
</div>
</div>
<div class="card-body">
<div class="mb-3">
<label for="local_backend_url" class="form-label fw-semibold">
<?php esc_html_e( 'Base URL', 'wp-agentic-writer' ); ?>
<span class="text-danger ms-2">*</span>
</label>
<input type="url"
class="form-control"
id="local_backend_url"
name="wp_agentic_writer_settings[local_backend_url]"
value="<?php echo esc_attr( $local_backend_url ); ?>"
placeholder="http://192.168.1.105:8080">
<div class="form-text">
<?php esc_html_e( 'Enter the URL from your Local Backend startup message (e.g., http://YOUR-IP:8080)', 'wp-agentic-writer' ); ?>
</div>
</div>
<div class="mb-3">
<label for="local_backend_key" class="form-label fw-semibold">
<?php esc_html_e( 'API Key', 'wp-agentic-writer' ); ?>
</label>
<input type="text"
class="form-control"
id="local_backend_key"
name="wp_agentic_writer_settings[local_backend_key]"
value="<?php echo esc_attr( $local_backend_key ); ?>"
placeholder="dummy">
<div class="form-text">
<?php esc_html_e( 'Use "dummy" for local backend (ignored by proxy)', 'wp-agentic-writer' ); ?>
</div>
</div>
<div class="mb-3">
<label for="local_backend_model" class="form-label fw-semibold">
<?php esc_html_e( 'Model', 'wp-agentic-writer' ); ?>
</label>
<input type="text"
class="form-control"
id="local_backend_model"
name="wp_agentic_writer_settings[local_backend_model]"
value="<?php echo esc_attr( $local_backend_model ); ?>"
placeholder="claude-local">
<div class="form-text">
<?php esc_html_e( 'Model identifier (informational only, proxy uses your Claude CLI default)', 'wp-agentic-writer' ); ?>
</div>
</div>
<div class="d-flex gap-2 align-items-center">
<button type="button" id="test-local-backend" class="btn btn-outline-primary">
<i class="bi bi-plug me-2"></i>
<?php esc_html_e( 'Test Connection', 'wp-agentic-writer' ); ?>
</button>
<span id="connection-status" class="ms-2"></span>
</div>
</div>
</div>
</div>
<!-- Task Routing (Optional) -->
<div class="col-12">
<div class="card border-0 ">
<div class="card-header border-bottom-0 pt-3">
<div class="d-flex align-items-center">
<div>
<h5 class="card-title mb-1 d-flex align-items-center gap-2">
<i class="bi bi-diagram-3 text-warning"></i>
<?php esc_html_e( 'Step 3: Provider Routing (Advanced)', 'wp-agentic-writer' ); ?>
</h5>
<p class="text-muted small mb-0">
<?php esc_html_e( 'Choose which provider to use for each task type', 'wp-agentic-writer' ); ?>
</p>
</div>
</div>
</div>
<div class="card-body">
<div class="alert alert-info mb-3">
<i class="bi bi-info-circle me-2"></i>
<strong><?php esc_html_e( 'Recommended Setup:', 'wp-agentic-writer' ); ?></strong>
<?php esc_html_e( 'Use Local Backend for all text tasks (free, fast, private). Use OpenRouter for images (only option).', 'wp-agentic-writer' ); ?>
</div>
<?php
$task_types = array(
'chat' => __( 'Chat & Discussion', 'wp-agentic-writer' ),
'clarity' => __( 'Clarity Check & Quiz', 'wp-agentic-writer' ),
'planning' => __( 'Outline Planning', 'wp-agentic-writer' ),
'writing' => __( 'Article Writing', 'wp-agentic-writer' ),
'refinement' => __( 'Content Refinement', 'wp-agentic-writer' ),
'image' => __( 'Image Generation', 'wp-agentic-writer' ),
);
$task_providers = $settings['task_providers'] ?? array();
?>
<table class="table">
<thead>
<tr>
<th><?php esc_html_e( 'Task Type', 'wp-agentic-writer' ); ?></th>
<th><?php esc_html_e( 'Provider', 'wp-agentic-writer' ); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ( $task_types as $task_key => $task_label ) : ?>
<tr>
<td><?php echo esc_html( $task_label ); ?></td>
<td>
<select class="form-select form-select-sm"
name="wp_agentic_writer_settings[task_providers][<?php echo esc_attr( $task_key ); ?>]">
<?php
$current_provider = $task_providers[ $task_key ] ?? 'openrouter';
// Available providers per task
$providers = array(
'openrouter' => '☁️ OpenRouter (Cloud)',
);
// Add local backend for text tasks
if ( 'image' !== $task_key ) {
$providers['local_backend'] = '🏠 Local Backend (Free)';
$providers['codex'] = '🔗 Codex (OpenAI)';
}
foreach ( $providers as $provider_key => $provider_label ) :
?>
<option value="<?php echo esc_attr( $provider_key ); ?>"
<?php selected( $current_provider, $provider_key ); ?>>
<?php echo esc_html( $provider_label ); ?>
</option>
<?php endforeach; ?>
</select>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
<!-- Brave Search Configuration -->
<div class="col-12">
<div class="card border-0 border-primary">
<div class="card-header border-bottom-0 pt-3">
<div class="d-flex align-items-center">
<div>
<h5 class="card-title mb-1 d-flex align-items-center gap-2">
<i class="bi bi-search text-primary"></i>
<?php esc_html_e( 'Step 4: Enable Web Search (Optional)', 'wp-agentic-writer' ); ?>
</h5>
<p class="text-muted small mb-0">
<?php esc_html_e( 'Add Brave Search capability to your local backend for real-time web research', 'wp-agentic-writer' ); ?>
</p>
</div>
</div>
</div>
<div class="card-body">
<div class="alert alert-info mb-3">
<i class="bi bi-info-circle me-2"></i>
<strong><?php esc_html_e( 'Requirements:', 'wp-agentic-writer' ); ?></strong>
<?php esc_html_e( 'You need a Brave Search API key (free tier available at', 'wp-agentic-writer' ); ?>
<a href="https://brave.com/search/api/" target="_blank">brave.com/search/api</a>)
</div>
<div class="mb-3">
<label class="form-label fw-semibold">
<?php esc_html_e( '1. Get Brave API Key (if not already configured in General tab)', 'wp-agentic-writer' ); ?>
</label>
<p class="text-muted small">
<?php esc_html_e( 'The API key you configured in Agentic Writer → Settings → General → Search will also be used by the local backend.', 'wp-agentic-writer' ); ?>
</p>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">
<?php esc_html_e( '2. Add API Key to Local Backend Proxy', 'wp-agentic-writer' ); ?>
</label>
<?php
$brave_api_key = $settings['brave_search_api_key'] ?? '';
$masked_key = $brave_api_key ? substr($brave_api_key, 0, 8) . '...' . substr($brave_api_key, -4) : '';
?>
<?php if ( $brave_api_key ) : ?>
<p class="text-muted small mb-2">
<?php esc_html_e( 'Navigate to your extracted folder, then run:', 'wp-agentic-writer' ); ?>
</p>
<div class="d-flex align-items-center gap-2">
<code id="brave-env-command">echo 'BRAVE_SEARCH_API_KEY="<?php echo esc_attr( $brave_api_key ); ?>"' > .env</code>
<button type="button" class="btn btn-sm btn-outline-light" onclick="copyToClipboard(document.getElementById('brave-env-command').textContent)">
<i class="bi bi-clipboard"></i>
</button>
</div>
<?php else : ?>
<div class="alert alert-warning mb-2">
<i class="bi bi-exclamation-triangle me-2"></i>
<?php esc_html_e( 'Brave API key not configured. Add it in Agentic Writer → Settings → General → Search section first.', 'wp-agentic-writer' ); ?>
</div>
<?php endif; ?>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">
<?php esc_html_e( '3. Restart the Proxy', 'wp-agentic-writer' ); ?>
</label>
<div class="d-flex align-items-center gap-2">
<code id="restart-proxy-command">./stop-proxy.sh && ./start-proxy.sh</code>
<button type="button" class="btn btn-sm btn-outline-light" onclick="copyToClipboard(document.getElementById('restart-proxy-command').textContent)">
<i class="bi bi-clipboard"></i>
</button>
</div>
</div>
<div class="alert alert-success">
<i class="bi bi-check-circle me-2"></i>
<strong><?php esc_html_e( 'Verification:', 'wp-agentic-writer' ); ?></strong>
<?php esc_html_e( 'When the proxy starts, you should see "Brave Search: ✅ CONFIGURED" in the output.', 'wp-agentic-writer' ); ?>
</div>
<p class="text-muted small mb-0">
<strong><?php esc_html_e( 'Note:', 'wp-agentic-writer' ); ?></strong>
<?php esc_html_e( 'Also ensure "Search" is enabled in the sidebar settings when using AI features that need web research.', 'wp-agentic-writer' ); ?>
</p>
</div>
</div>
</div>
<!-- Help -->
<div class="col-12">
<div class="card border-0 border-warning">
<div class="card-header border-bottom-0 pt-3">
<h5 class="card-title mb-0 d-flex align-items-center gap-2">
<i class="bi bi-question-circle text-warning"></i>
<?php esc_html_e( 'Troubleshooting', 'wp-agentic-writer' ); ?>
</h5>
</div>
<div class="card-body">
<ul class="mb-0">
<li>
<strong><?php esc_html_e( 'Connection failed?', 'wp-agentic-writer' ); ?></strong>
<?php esc_html_e( 'Ensure proxy is running:', 'wp-agentic-writer' ); ?>
<code>./start-proxy.sh</code>
</li>
<li>
<strong><?php esc_html_e( 'Wrong IP?', 'wp-agentic-writer' ); ?></strong>
<?php esc_html_e( 'Run', 'wp-agentic-writer' ); ?>
<code>./get-local-ip.sh</code>
<?php esc_html_e( 'to find correct address', 'wp-agentic-writer' ); ?>
</li>
<li>
<strong><?php esc_html_e( 'Firewall blocking?', 'wp-agentic-writer' ); ?></strong>
<?php esc_html_e( 'Allow Node.js on port 8080 in your system firewall', 'wp-agentic-writer' ); ?>
</li>
<li>
<strong><?php esc_html_e( 'Claude not found?', 'wp-agentic-writer' ); ?></strong>
<?php esc_html_e( 'Check Claude CLI:', 'wp-agentic-writer' ); ?>
<code>which claude</code>
<?php esc_html_e( 'or', 'wp-agentic-writer' ); ?>
<code>claude --version</code>
</li>
</ul>
<p class="mt-3 mb-0">
<strong><?php esc_html_e( 'Need help?', 'wp-agentic-writer' ); ?></strong>
<?php esc_html_e( 'Check the README.md and TROUBLESHOOTING.md files in the downloaded package.', 'wp-agentic-writer' ); ?>
</p>
</div>
</div>
</div>
</div>
<script>
function copyToClipboard(text) {
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(function() {
alert('Command copied to clipboard!');
}).catch(function(err) {
console.error('Copy failed:', err);
});
} else {
// Fallback for older browsers
var textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.position = 'fixed';
textarea.style.opacity = '0';
document.body.appendChild(textarea);
textarea.select();
try {
document.execCommand('copy');
alert('Command copied to clipboard!');
} catch (err) {
console.error('Copy failed:', err);
}
document.body.removeChild(textarea);
}
}
jQuery(document).ready(function($) {
$('#test-local-backend').on('click', function() {
const btn = $(this);
const status = $('#connection-status');
const url = $('#local_backend_url').val();
if (!url) {
status.html('<span class="text-warning">⚠️ Enter Base URL first</span>');
return;
}
btn.prop('disabled', true).html('<i class="spinner-border spinner-border-sm me-2"></i>Testing...');
status.html('<span class="text-white" style="color:#17a2b8 !important;">⏳ Connecting...</span>');
$.ajax({
url: ajaxurl,
method: 'POST',
data: {
action: 'wpaw_test_local_backend',
url: url,
nonce: '<?php echo esc_js( wp_create_nonce( 'wpaw_test_local_backend' ) ); ?>'
},
success: function(response) {
if (response.success) {
status.html('<span class="text-success">✅ ' + response.data.message + '</span>');
} else {
status.html('<span class="text-danger">❌ ' + (response.data.message || 'Failed') + '</span>');
}
},
error: function(xhr) {
status.html('<span class="text-danger">❌ Connection failed. Check URL and proxy status.</span>');
},
complete: function() {
btn.prop('disabled', false).html('<i class="bi bi-plug me-2"></i><?php esc_html_e( 'Test Connection', 'wp-agentic-writer' ); ?>');
}
});
});
});
</script>