mirror of
https://github.com/jahruz67/wisp-open.git
synced 2026-08-08 18:14:08 +00:00
feat: add backend configuration and windows utilities, and initialize frontend dependencies
This commit is contained in:
+84
-89
@@ -4,23 +4,26 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport">
|
||||
<title>wis-free-v3 Settings</title>
|
||||
<title>Wisp Settings</title>
|
||||
<link rel="stylesheet" href="./src/style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app" class="container">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="flex-between" style="margin-bottom: 30px;">
|
||||
<h1 style="margin: 0;">wis-free-v3 Settings</h1>
|
||||
<div id="appVersion" style="color: var(--text-muted); font-size: 12px;">—</div>
|
||||
<div class="flex-between" style="margin-bottom: 28px;">
|
||||
<h1>Settings</h1>
|
||||
<div id="appVersion" style="color: var(--text-2); font-size: 12px; font-weight: 500;">—</div>
|
||||
</div>
|
||||
|
||||
<div id="saveStatus" class="save-status">Settings Saved!</div>
|
||||
<div id="saveStatus" class="save-status">Saved</div>
|
||||
|
||||
<!-- Settings Form -->
|
||||
<div id="settingsForm">
|
||||
|
||||
<div class="section-group-label">Authentication</div>
|
||||
|
||||
<!-- API Key -->
|
||||
<div class="section">
|
||||
<label>Groq API Key</label>
|
||||
@@ -33,15 +36,14 @@
|
||||
<button onclick="saveApiKey()">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
<p style="font-size: 12px; color: var(--text-muted); margin-top: 8px;">
|
||||
Get your free API key at <a href="https://console.groq.com/keys" target="_blank"
|
||||
style="color: var(--primary);">console.groq.com/keys</a>
|
||||
</p>
|
||||
<p class="hint">Get your free key at <a href="https://console.groq.com/keys" target="_blank" style="color: var(--accent);">console.groq.com/keys</a></p>
|
||||
</div>
|
||||
|
||||
<div class="section-group-label">Input</div>
|
||||
|
||||
<!-- Shortcut -->
|
||||
<div class="section">
|
||||
<label>Shortcut (Hold to Record)</label>
|
||||
<label>Hotkey</label>
|
||||
<div class="form-control">
|
||||
<div class="flex-row">
|
||||
<div class="input-wrapper">
|
||||
@@ -50,11 +52,19 @@
|
||||
<button onclick="recordShortcut()" id="recordBtn">Record</button>
|
||||
</div>
|
||||
</div>
|
||||
<p style="font-size: 12px; color: var(--text-muted); margin-top: 8px;">
|
||||
Click Record, then press your desired key combination (e.g., Ctrl+X)
|
||||
</p>
|
||||
<p class="hint">Click Record, then press your desired key combination (e.g. Ctrl+X).</p>
|
||||
</div>
|
||||
|
||||
<!-- Microphone -->
|
||||
<div class="section">
|
||||
<label>Microphone</label>
|
||||
<select id="micDevice" onchange="saveMicDevice()" class="form-control">
|
||||
<option value="default">System Default</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="section-group-label">Transcription</div>
|
||||
|
||||
<!-- Whisper Model -->
|
||||
<div class="section">
|
||||
<label>Whisper Model</label>
|
||||
@@ -66,19 +76,22 @@
|
||||
|
||||
<!-- Language -->
|
||||
<div class="section">
|
||||
<label>Transcription Language</label>
|
||||
<label>Language</label>
|
||||
<select id="language" onchange="saveLanguage()" class="form-control">
|
||||
<option value="auto">Auto-Detect</option>
|
||||
<option value="en">English (en)</option>
|
||||
<option value="es">Spanish (es)</option>
|
||||
</select>
|
||||
<p style="font-size: 11px; color: var(--text-muted); margin-top: 5px;">Specifying language reduces latency and improves accuracy.</p>
|
||||
<p class="hint">Specifying language reduces latency and improves accuracy.</p>
|
||||
</div>
|
||||
|
||||
<div class="section-group-label">AI Refinement</div>
|
||||
|
||||
<!-- AI Model -->
|
||||
<div class="section">
|
||||
<label>AI Model (Text Refinement)</label>
|
||||
<label>AI Model</label>
|
||||
<select id="aiModel" onchange="saveAiModel()" class="form-control">
|
||||
<option value="None">None (Skip Refinement)</option>
|
||||
<option value="None">None — skip refinement</option>
|
||||
<option value="openai/gpt-oss-120b-high">openai/gpt-oss-120b (high reasoning)</option>
|
||||
<option value="openai/gpt-oss-120b">openai/gpt-oss-120b (low reasoning)</option>
|
||||
<option value="openai/gpt-oss-20b-high">openai/gpt-oss-20b (high reasoning)</option>
|
||||
@@ -88,91 +101,80 @@
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Microphone -->
|
||||
<div class="section">
|
||||
<label>Microphone</label>
|
||||
<select id="micDevice" onchange="saveMicDevice()" class="form-control">
|
||||
<option value="default">System Default</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- AI Prompt -->
|
||||
<div class="section">
|
||||
<label>AI Prompt (System Message)</label>
|
||||
<textarea id="aiPrompt" rows="3" placeholder="Custom instructions for text refinement..."
|
||||
class="form-control"></textarea>
|
||||
<label>System Prompt</label>
|
||||
<textarea id="aiPrompt" rows="3" placeholder="Custom instructions for text refinement..." class="form-control"></textarea>
|
||||
<div style="text-align: right; margin-top: 10px;">
|
||||
<button onclick="savePrompt()">Save Prompt</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-group-label">System</div>
|
||||
|
||||
<!-- Startup -->
|
||||
<div class="section flex-between">
|
||||
<span id="startupLabel" style="font-weight: 500;">Run on System Startup</span>
|
||||
<div>
|
||||
<span id="startupLabel" style="font-weight: 500;">Run on System Startup</span>
|
||||
<p class="hint" style="margin-top: 4px; margin-bottom: 0;">Launch automatically when you log in.</p>
|
||||
</div>
|
||||
<label class="flex-row" style="margin: 0; cursor: pointer;">
|
||||
<input type="checkbox" id="startupToggle" onchange="toggleStartup()" style="width: auto;">
|
||||
<span>Enable</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- History -->
|
||||
<div class="section">
|
||||
<div class="flex-between" style="margin-bottom: 10px;">
|
||||
<div class="flex-between" style="margin-bottom: 12px;">
|
||||
<label style="margin: 0;">Transcription History</label>
|
||||
<button onclick="clearHistory()"
|
||||
style="background: transparent; color: #f87171; padding: 0; font-size: 12px;">Clear</button>
|
||||
<button onclick="clearHistory()" class="btn-link">Clear all</button>
|
||||
</div>
|
||||
<div id="historyList" class="history-list">
|
||||
<div style="text-align: center; color: var(--text-muted); padding: 20px;">No history yet.</div>
|
||||
<div style="text-align: center; color: var(--text-2); padding: 24px 0; font-size: 13px;">No history yet.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Offline Mode -->
|
||||
<div id="offlineWhisperSection" class="section"
|
||||
style="margin-top: 30px; padding-top: 20px; border-top: 1px solid var(--border-color);">
|
||||
<!-- Offline Whisper -->
|
||||
<div id="offlineWhisperSection" class="section" style="margin-top: 20px; padding-top: 20px; border-top: 1px solid var(--border);">
|
||||
<label>Offline Whisper</label>
|
||||
|
||||
<!-- Online/Offline Status -->
|
||||
<div id="connectionStatus"
|
||||
style="margin-bottom: 15px; padding: 10px; border-radius: 8px; text-align: center;">
|
||||
<!-- Connection Status -->
|
||||
<div id="connectionStatus" style="margin-bottom: 14px; padding: 9px 14px; border-radius: 7px; text-align: center; font-size: 13px;">
|
||||
Checking connection...
|
||||
</div>
|
||||
|
||||
<!-- Whisper Status -->
|
||||
<div id="whisperSection">
|
||||
<div id="whisperNotInstalled">
|
||||
<p style="font-size: 13px; color: var(--text-muted); margin-bottom: 15px;">
|
||||
<p class="hint" style="margin-bottom: 14px;">
|
||||
Install offline transcription for use without internet. Uses GPU acceleration if available.
|
||||
</p>
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label style="font-size: 12px;">Model Size:</label>
|
||||
<select id="whisperModelSelect" style="margin-top: 5px;" class="form-control">
|
||||
<option value="tiny">Tiny (75 MB) - Fastest</option>
|
||||
<option value="base">Base (150 MB) - Fast</option>
|
||||
<option value="small" selected>Small (500 MB) - Recommended</option>
|
||||
<option value="medium">Medium (1.5 GB) - High Quality</option>
|
||||
<div style="margin-bottom: 14px;">
|
||||
<label style="font-size: 12px; color: var(--text-2); margin-bottom: 6px;">Model Size</label>
|
||||
<select id="whisperModelSelect" class="form-control">
|
||||
<option value="tiny">Tiny (75 MB) — Fastest</option>
|
||||
<option value="base">Base (150 MB) — Fast</option>
|
||||
<option value="small" selected>Small (500 MB) — Recommended</option>
|
||||
<option value="medium">Medium (1.5 GB) — Best Quality</option>
|
||||
</select>
|
||||
</div>
|
||||
<button onclick="installWhisper()" id="installBtn"
|
||||
style="background: linear-gradient(135deg, #6366f1, #8b5cf6); padding: 12px 24px; font-size: 14px; width: 100%;">
|
||||
🚀 Install Offline Whisper
|
||||
<button onclick="installWhisper()" id="installBtn">
|
||||
Install Offline Whisper
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="whisperInstalled" style="display: none;">
|
||||
<div
|
||||
style="background: rgba(34, 197, 94, 0.1); border: 1px solid rgba(34, 197, 94, 0.3); border-radius: 8px; padding: 15px; margin-bottom: 15px;">
|
||||
<div style="color: #22c55e; font-weight: 500;">✓ Offline Whisper Installed</div>
|
||||
<div style="font-size: 12px; color: var(--text-muted); margin-top: 5px;">
|
||||
Model: <span id="installedModel">-</span>
|
||||
<div style="background: var(--green-dim); border: 1px solid rgba(61, 186, 110, 0.25); border-radius: 7px; padding: 13px 16px; margin-bottom: 14px;">
|
||||
<div style="color: var(--green); font-weight: 500; font-size: 13px;">✓ Offline Whisper installed</div>
|
||||
<div style="font-size: 12px; color: var(--text-2); margin-top: 4px;">
|
||||
Model: <span id="installedModel">—</span>
|
||||
</div>
|
||||
</div>
|
||||
<p style="font-size: 12px; color: var(--text-muted); margin-bottom: 15px;">
|
||||
Select "Local - Whisper" in the Whisper Model dropdown above to use offline transcription.
|
||||
<p class="hint" style="margin-bottom: 14px;">
|
||||
Select "Local — Whisper" in the Whisper Model dropdown above to use offline transcription.
|
||||
</p>
|
||||
<button onclick="uninstallWhisper()"
|
||||
style="background: transparent; border: 1px solid #f87171; color: #f87171; padding: 10px 20px; font-size: 13px;">
|
||||
🗑️ Uninstall Offline Whisper
|
||||
<button onclick="uninstallWhisper()" class="btn-danger">
|
||||
Uninstall Offline Whisper
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -292,7 +294,7 @@
|
||||
function renderHistoryList(history) {
|
||||
const container = document.getElementById('historyList');
|
||||
if (!history || history.length === 0) {
|
||||
container.innerHTML = '<div style="text-align: center; color: var(--text-muted); padding: 20px;">No history yet.</div>';
|
||||
container.innerHTML = '<div style="text-align: center; color: var(--text-2); padding: 24px 0; font-size: 13px;">No history yet.</div>';
|
||||
return;
|
||||
}
|
||||
container.innerHTML = '';
|
||||
@@ -371,7 +373,7 @@
|
||||
showSaveStatus();
|
||||
};
|
||||
|
||||
function showSaveStatus(message = 'Settings Saved!') {
|
||||
function showSaveStatus(message = 'Saved') {
|
||||
const el = document.getElementById('saveStatus');
|
||||
el.textContent = message;
|
||||
el.classList.add('show');
|
||||
@@ -390,7 +392,7 @@
|
||||
|
||||
window.saveLanguage = async function () {
|
||||
await window.go.main.App.SaveSettings({ language: document.getElementById('language').value });
|
||||
showSaveStatus('Language Saved!');
|
||||
showSaveStatus();
|
||||
};
|
||||
|
||||
window.saveMicDevice = async function () {
|
||||
@@ -401,7 +403,7 @@
|
||||
|
||||
window.savePrompt = async function () {
|
||||
await window.go.main.App.SaveSettings({ ai_prompt: document.getElementById('aiPrompt').value.trim() });
|
||||
showSaveStatus('Prompt Saved!');
|
||||
showSaveStatus('Prompt saved');
|
||||
};
|
||||
|
||||
window.toggleStartup = async function () {
|
||||
@@ -409,7 +411,7 @@
|
||||
};
|
||||
|
||||
window.clearHistory = async function () {
|
||||
if (confirm('Clear all history?')) {
|
||||
if (confirm('Clear all transcription history?')) {
|
||||
await window.go.main.App.ClearHistory();
|
||||
renderHistoryList([]);
|
||||
}
|
||||
@@ -422,19 +424,19 @@
|
||||
const statusEl = document.getElementById('connectionStatus');
|
||||
|
||||
if (isOnline) {
|
||||
statusEl.innerHTML = '🟢 Online - Cloud transcription available';
|
||||
statusEl.style.background = 'rgba(34, 197, 94, 0.1)';
|
||||
statusEl.style.color = '#22c55e';
|
||||
statusEl.innerHTML = '● Online';
|
||||
statusEl.style.background = 'var(--green-dim)';
|
||||
statusEl.style.color = 'var(--green)';
|
||||
statusEl.style.border = '1px solid rgba(61, 186, 110, 0.2)';
|
||||
} else {
|
||||
statusEl.innerHTML = '🔴 Offline - Install local Whisper for transcription';
|
||||
statusEl.style.background = 'rgba(239, 68, 68, 0.1)';
|
||||
statusEl.style.color = '#ef4444';
|
||||
statusEl.innerHTML = '● Offline — install local Whisper for transcription';
|
||||
statusEl.style.background = 'var(--red-dim)';
|
||||
statusEl.style.color = 'var(--red)';
|
||||
statusEl.style.border = '1px solid rgba(224, 82, 82, 0.2)';
|
||||
|
||||
// Disable cloud AI options when offline
|
||||
const aiSelect = document.getElementById('aiModel');
|
||||
const whisperSelect = document.getElementById('whisperModel');
|
||||
|
||||
// Add offline notice to options
|
||||
for (let opt of aiSelect.options) {
|
||||
if (opt.value !== 'None' && !opt.value.startsWith('local-')) {
|
||||
opt.disabled = true;
|
||||
@@ -467,7 +469,7 @@
|
||||
// Add local option to whisper dropdown
|
||||
const localOption = document.createElement('option');
|
||||
localOption.value = 'local-' + info.model;
|
||||
localOption.textContent = '🖥️ Local - ' + info.model + ' (offline)';
|
||||
localOption.textContent = '⬡ Local — ' + info.model + ' (offline)';
|
||||
localOption.style.fontWeight = 'bold';
|
||||
whisperSelect.insertBefore(localOption, whisperSelect.firstChild);
|
||||
} else {
|
||||
@@ -498,12 +500,12 @@
|
||||
}
|
||||
|
||||
btn.disabled = false;
|
||||
btn.textContent = '🚀 Install Offline Whisper';
|
||||
btn.textContent = 'Install Offline Whisper';
|
||||
};
|
||||
|
||||
// Uninstall whisper
|
||||
window.uninstallWhisper = async function () {
|
||||
if (!confirm('Are you sure you want to uninstall offline Whisper? This will delete the downloaded model.')) {
|
||||
if (!confirm('Uninstall offline Whisper? This will delete the downloaded model.')) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -518,21 +520,14 @@
|
||||
|
||||
// Init
|
||||
async function initialize() {
|
||||
// Check platform definitively using userAgent to guarantee it fires immediately without Wails timing issues
|
||||
try {
|
||||
const isLinux = navigator.userAgent.toLowerCase().includes('linux');
|
||||
if (isLinux) {
|
||||
// Hide Offline Whisper section
|
||||
const offlineSection = document.getElementById('offlineWhisperSection');
|
||||
if (offlineSection) {
|
||||
offlineSection.style.display = 'none';
|
||||
}
|
||||
|
||||
// Clean up 'Windows' reference in startup text specifically for Linux OS
|
||||
if (offlineSection) offlineSection.style.display = 'none';
|
||||
|
||||
const startupLabel = document.getElementById('startupLabel');
|
||||
if (startupLabel) {
|
||||
startupLabel.innerText = 'Run on Linux OS Startup';
|
||||
}
|
||||
if (startupLabel) startupLabel.innerText = 'Run on Startup';
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Failed to get environment:', err);
|
||||
@@ -548,8 +543,8 @@
|
||||
refreshHistoryFromBackend();
|
||||
});
|
||||
}
|
||||
|
||||
// If Linux, ensure Local Whisper option is removed from Whisper Select as a secondary guard
|
||||
|
||||
// If Linux, ensure Local Whisper option is removed
|
||||
if (navigator.userAgent.toLowerCase().includes('linux')) {
|
||||
const whisperSelect = document.getElementById('whisperModel');
|
||||
if (whisperSelect) {
|
||||
|
||||
Reference in New Issue
Block a user