Skip to content

Commit 30a2f08

Browse files
Update
1 parent bb03d8c commit 30a2f08

13 files changed

Lines changed: 612 additions & 487 deletions

File tree

src/config/AppConfig.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ export class AppConfig {
9494
enabled: true,
9595
writingStyle: readPrompt("writing_style"),
9696
baseUrl: "https://api.cerebras.ai/v1/chat/completions",
97-
model: "qwen-3-32b",
97+
model: "qwen-3-235b-a22b-instruct",
9898
maxTokens: 16382,
9999
temperature: 0.3,
100100
topP: 0.95,

src/config/SettingsManager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ export class SettingsManager extends EventEmitter {
401401
"ai.baseUrl",
402402
"https://api.cerebras.ai/v1/chat/completions",
403403
),
404-
model: this.get("ai.model", "qwen-3-32b"),
404+
model: this.get("ai.model", "qwen-3-235b-a22b-instruct"),
405405
maxTokens: this.get("ai.maxTokens", 16382),
406406
temperature: this.get("ai.temperature", 0.6),
407407
topP: this.get("ai.topP", 0.95),

src/config/SettingsSchema.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -153,16 +153,7 @@ export const SETTINGS_SCHEMA: SettingsSection[] = [
153153
type: "select",
154154
label: "Model Name",
155155
description: "AI model to use for text enhancement",
156-
defaultValue: "qwen-3-32b",
157-
options: [
158-
{ value: "gemini-3-pro-preview", label: "Gemini 3 Pro Preview" },
159-
{ value: "gemini-3-flash-preview", label: "Gemini 3 Flash Preview" },
160-
{ value: "gemini-2.5-flash", label: "Gemini 2.5 Flash" },
161-
{ value: "gemini-2.5-flash-lite", label: "Gemini 2.5 Flash Lite" },
162-
{ value: "qwen-3-32b", label: "Qwen 3 32B" },
163-
{ value: "gpt-4", label: "GPT-4" },
164-
{ value: "gpt-3.5-turbo", label: "GPT-3.5 Turbo" },
165-
],
156+
defaultValue: "qwen-3-235b-a22b-instruct",
166157
},
167158
{
168159
key: "ai.maxTokens",
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<template>
2+
<div class="ai-model-selector">
3+
<select v-if="loading" class="form-control" disabled>
4+
<option>Loading models...</option>
5+
</select>
6+
<select
7+
v-else-if="models && models.length > 0"
8+
class="form-control"
9+
:value="modelValue"
10+
@change="$emit('update:modelValue', $event.target.value)"
11+
:disabled="disabled"
12+
>
13+
<option v-for="m in models" :key="m.id" :value="m.id">
14+
{{ m.name || m.id }}
15+
</option>
16+
</select>
17+
<input
18+
v-else
19+
type="text"
20+
class="form-control"
21+
:value="modelValue"
22+
@input="$emit('update:modelValue', $event.target.value)"
23+
placeholder="Enter model name or validate API key"
24+
:disabled="disabled"
25+
/>
26+
</div>
27+
</template>
28+
29+
<script>
30+
export default {
31+
name: "AiModelSelector",
32+
props: {
33+
modelValue: {
34+
type: String,
35+
default: "",
36+
},
37+
models: {
38+
type: Array,
39+
default: () => [],
40+
},
41+
loading: {
42+
type: Boolean,
43+
default: false,
44+
},
45+
disabled: {
46+
type: Boolean,
47+
default: false,
48+
},
49+
},
50+
emits: ["update:modelValue"],
51+
};
52+
</script>
53+
54+
<style scoped>
55+
.ai-model-selector {
56+
width: 100%;
57+
}
58+
59+
.form-control {
60+
width: 100%;
61+
max-width: 400px;
62+
padding: 6px 10px;
63+
border: 1px solid var(--color-border-primary, #e0e0e0);
64+
border-radius: var(--radius-sm, 4px);
65+
font-size: var(--font-size-md, 13px);
66+
background: rgba(255, 255, 255, 0.08);
67+
transition: all var(--transition-fast, 0.15s ease);
68+
font-family: inherit;
69+
color: inherit;
70+
}
71+
72+
.form-control:focus {
73+
outline: none;
74+
border-color: var(--color-border-focus, #007aff);
75+
box-shadow: 0 0 0 2px rgba(0, 122, 255, 0.2);
76+
}
77+
78+
.form-control:disabled {
79+
background: rgba(255, 255, 255, 0.06);
80+
color: var(--color-text-tertiary, #999999);
81+
cursor: not-allowed;
82+
opacity: 0.6;
83+
}
84+
85+
/* Dark mode support */
86+
@media (prefers-color-scheme: dark) {
87+
.form-control {
88+
background: rgba(255, 255, 255, 0.06);
89+
color: #ececec;
90+
border-color: rgba(255, 255, 255, 0.12);
91+
}
92+
93+
.form-control::placeholder {
94+
color: #666666;
95+
}
96+
97+
.form-control:hover {
98+
background: rgba(255, 255, 255, 0.08);
99+
border-color: rgba(255, 255, 255, 0.18);
100+
}
101+
102+
.form-control:focus {
103+
background: rgba(255, 255, 255, 0.08);
104+
border-color: #007aff;
105+
box-shadow: 0 0 0 2px rgba(0, 122, 255, 0.25);
106+
}
107+
108+
.form-control:disabled {
109+
background: rgba(255, 255, 255, 0.02);
110+
color: #666666;
111+
}
112+
113+
select.form-control option {
114+
background: #1c1c1e;
115+
color: #ececec;
116+
}
117+
}
118+
</style>
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<template>
2+
<div class="content">
3+
<div class="step-header">
4+
<span class="step-icn"><i class="ph-duotone ph-sparkle"></i></span>
5+
<h1>Enable AI polishing?</h1>
6+
</div>
7+
<div class="toggle">
8+
<input
9+
id="aiEnabled"
10+
type="checkbox"
11+
:checked="aiEnabled"
12+
@change="$emit('update:aiEnabled', $event.target.checked); $emit('ai-enabled-change')"
13+
/>
14+
<label for="aiEnabled">Use AI to clean up and format dictation</label>
15+
</div>
16+
<div
17+
v-if="aiValidationError"
18+
class="error-message"
19+
style="color: #ef4444; font-size: 14px; margin-top: 8px"
20+
>
21+
{{ aiValidationError }}
22+
</div>
23+
<div class="card" v-show="aiEnabled">
24+
<div class="form-grid">
25+
<div class="field">
26+
<div class="label">API Base URL</div>
27+
<input
28+
class="input"
29+
placeholder="e.g. https://api.example.com/v1"
30+
:value="aiBaseUrl"
31+
@input="$emit('update:aiBaseUrl', $event.target.value)"
32+
/>
33+
</div>
34+
<div class="field">
35+
<AiModelSelector
36+
:modelValue="aiModel"
37+
@update:modelValue="$emit('update:aiModel', $event)"
38+
:models="aiModels"
39+
:loading="savingKey"
40+
/>
41+
</div>
42+
</div>
43+
<div
44+
class="form-row"
45+
style="margin-top: 8px; display: flex; gap: 10px; align-items: center;"
46+
>
47+
<div class="field" style="flex: 1">
48+
<div class="label">API Key</div>
49+
<input
50+
class="input"
51+
placeholder="Paste your API key (stored securely)"
52+
:value="aiApiKey"
53+
@input="$emit('update:aiApiKey', $event.target.value)"
54+
/>
55+
</div>
56+
<button
57+
class="btn btn-primary"
58+
@click="$emit('save-key')"
59+
style="margin-top: 24px"
60+
>
61+
<span v-if="savingKey" class="spinner" aria-hidden="true"></span>
62+
<span v-else>Save Key</span>
63+
</button>
64+
</div>
65+
<div class="hint" style="margin-top: 6px">{{ keyStatus }}</div>
66+
</div>
67+
</div>
68+
</template>
69+
70+
<script setup>
71+
import AiModelSelector from "../../AiModelSelector.vue"
72+
73+
defineProps({
74+
aiEnabled: Boolean,
75+
aiValidationError: String,
76+
aiBaseUrl: String,
77+
aiModel: String,
78+
aiModels: Array,
79+
savingKey: Boolean,
80+
aiApiKey: String,
81+
keyStatus: String
82+
})
83+
84+
defineEmits([
85+
'update:aiEnabled',
86+
'update:aiBaseUrl',
87+
'update:aiModel',
88+
'update:aiApiKey',
89+
'ai-enabled-change',
90+
'save-key'
91+
])
92+
</script>
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<template>
2+
<div class="content hotkey-content">
3+
<div class="step-header compact">
4+
<span class="step-icn small"><i class="ph-duotone ph-keyboard"></i></span>
5+
<h1>Set your hotkey</h1>
6+
</div>
7+
<p class="micro">
8+
Choose how you want to trigger dictation.
9+
</p>
10+
11+
<!-- Mode Selection Cards - Compact -->
12+
<div class="hotkey-mode-cards compact">
13+
<div
14+
class="hotkey-mode-card compact"
15+
:class="{ active: hotkeyMode === 'toggle' }"
16+
@click="$emit('update:hotkeyMode', 'toggle')"
17+
>
18+
<div class="mode-icon small">
19+
<i class="ph-duotone ph-play-pause"></i>
20+
</div>
21+
<div class="mode-content">
22+
<h3>Start / Stop</h3>
23+
<p>Press once to start, again to stop</p>
24+
</div>
25+
<div class="mode-check" v-if="hotkeyMode === 'toggle'">
26+
<i class="ph-fill ph-check-circle"></i>
27+
</div>
28+
</div>
29+
30+
<div
31+
class="hotkey-mode-card compact"
32+
:class="{ active: hotkeyMode === 'push' }"
33+
@click="$emit('update:hotkeyMode', 'push')"
34+
>
35+
<div class="mode-icon small">
36+
<i class="ph-duotone ph-hand-pointing"></i>
37+
</div>
38+
<div class="mode-content">
39+
<h3>Push to Talk</h3>
40+
<p>Hold to record, release to stop</p>
41+
</div>
42+
<div class="mode-check" v-if="hotkeyMode === 'push'">
43+
<i class="ph-fill ph-check-circle"></i>
44+
</div>
45+
</div>
46+
</div>
47+
48+
<!-- Hotkey Input - Inline -->
49+
<div class="hotkey-config-section compact">
50+
<div class="hotkey-label">
51+
<i class="ph-duotone ph-command"></i>
52+
<span>{{ hotkeyMode === "toggle" ? "Hotkey" : "Key" }}</span>
53+
</div>
54+
<OnboardingHotkeyInput
55+
:modelValue="currentHotkey"
56+
@update:modelValue="$emit('update:currentHotkey', $event)"
57+
:placeholder="hotkeyMode === 'toggle' ? 'e.g. ⌃ D' : 'e.g. ⌥ /'"
58+
/>
59+
<button
60+
v-if="!currentHotkey"
61+
class="suggestion-btn"
62+
@click="$emit('apply-suggested')"
63+
:title="hotkeyMode === 'toggle' ? 'Use Control+D' : 'Use Alt+/'"
64+
>
65+
{{ hotkeyMode === "toggle" ? "⌃ D" : "⌥ /" }}
66+
</button>
67+
</div>
68+
</div>
69+
</template>
70+
71+
<script setup>
72+
import OnboardingHotkeyInput from "../OnboardingHotkeyInput.vue"
73+
74+
defineProps({
75+
hotkeyMode: String,
76+
currentHotkey: String
77+
})
78+
79+
defineEmits(['update:hotkeyMode', 'update:currentHotkey', 'apply-suggested'])
80+
</script>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<template>
2+
<div class="content">
3+
<div class="step-header">
4+
<!-- Use the app icon image for the welcome screen -->
5+
<img
6+
class="hero-logo"
7+
src="../../../assets/icon.png"
8+
alt="WhisperMac"
9+
/>
10+
<h1>Welcome to WhisperMac</h1>
11+
</div>
12+
<p class="micro">
13+
Dictate anywhere on macOS. This quick setup will enable
14+
accessibility and microphone permissions, pick a Whisper model,
15+
and optionally enable AI polishing.
16+
</p>
17+
<div class="card">
18+
<div class="hint">
19+
You can change all settings later in Settings.
20+
</div>
21+
</div>
22+
</div>
23+
</template>
24+
25+
<script setup>
26+
</script>

0 commit comments

Comments
 (0)