fix: voice status global store, per-view mic reactivity, single-voice preview

- Move voice status into settings store (voiceSttReady, voiceTtsReady),
  checked once at login and refreshed after admin model reload
- ChatView, BriefingView, DashboardChatInput now use computed refs from
  the store — mic buttons appear reactively without needing a page reload
- BriefingView: separate STT-only guard for mic PTT vs TTS-only guard for
  listen mode / speak buttons
- Add ▶ Preview button to Voice & Speed section in Settings for single-
  voice testing without enabling blend mode

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-30 20:53:06 -04:00
parent b4b4b0d9d6
commit 71ca0ecb5c
7 changed files with 70 additions and 37 deletions
+4 -11
View File
@@ -3,7 +3,7 @@ import { onMounted, onUnmounted, ref, computed, watch, nextTick } from "vue";
import { useRoute, useRouter } from "vue-router";
import { useChatStore } from "@/stores/chat";
import { useSettingsStore } from "@/stores/settings";
import { apiGet, getVoiceStatus, transcribeAudio } from "@/api/client";
import { apiGet, transcribeAudio } from "@/api/client";
import { renderMarkdown } from "@/utils/markdown";
import { useVoiceRecorder } from "@/composables/useVoiceRecorder";
import ChatMessage from "@/components/ChatMessage.vue";
@@ -23,17 +23,10 @@ const sending = ref(false);
const summarizing = ref(false);
const sidebarOpen = ref(false);
// Voice PTT
const voiceEnabled = ref(false);
// Voice PTT — use store so status is globally reactive
const transcribingVoice = ref(false);
const recorder = useVoiceRecorder();
async function checkVoice() {
try {
const status = await getVoiceStatus();
voiceEnabled.value = status.enabled && status.stt;
} catch { /* voice absent */ }
}
const voiceEnabled = computed(() => settingsStore.voiceSttReady);
async function startPtt() {
if (!voiceEnabled.value || recorder.recording.value) return;
@@ -178,7 +171,7 @@ const inputPlaceholder = computed(() => {
onMounted(async () => {
document.addEventListener("keydown", onGlobalKeydown);
await Promise.all([store.fetchConversations(), loadProjects(), checkVoice()]);
await Promise.all([store.fetchConversations(), loadProjects()]);
if (convId.value) {
if (store.currentConversation?.id !== convId.value) {
await store.fetchConversation(convId.value);