Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/components/SettingsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ interface TranscriptionSectionProps {
setCustomTranscriptionApiKey: (key: string) => void;
cloudTranscriptionBaseUrl?: string;
setCloudTranscriptionBaseUrl: (url: string) => void;
suppressRepetition: boolean;
setSuppressRepetition: (value: boolean) => void;
toast: (opts: {
title: string;
description: string;
Expand Down Expand Up @@ -218,6 +220,8 @@ function TranscriptionSection({
setCustomTranscriptionApiKey,
cloudTranscriptionBaseUrl,
setCloudTranscriptionBaseUrl,
suppressRepetition,
setSuppressRepetition,
toast,
}: TranscriptionSectionProps) {
const { t } = useTranslation();
Expand Down Expand Up @@ -398,6 +402,18 @@ function TranscriptionSection({
/>
)}
<GpuDeviceSelector purpose="transcription" />

{/* Suppress Repetition */}
<SettingsPanel>
<SettingsPanelRow>
<SettingsRow
label={t("settingsPage.transcription.suppressRepetitionLabel")}
description={t("settingsPage.transcription.suppressRepetitionDescription")}
>
<Toggle checked={suppressRepetition} onChange={setSuppressRepetition} />
</SettingsRow>
</SettingsPanelRow>
</SettingsPanel>
</div>
);
}
Expand Down Expand Up @@ -791,6 +807,8 @@ export default function SettingsPage({ activeSection = "general" }: SettingsPage
setNoteFilesEnabled,
noteFilesPath,
setNoteFilesPath,
suppressRepetition,
setSuppressRepetition,
} = useSettings();

const agentKey = useSettingsStore((s) => s.agentKey);
Expand Down Expand Up @@ -3043,6 +3061,8 @@ EOF`,
setCustomTranscriptionApiKey={setCustomTranscriptionApiKey}
cloudTranscriptionBaseUrl={cloudTranscriptionBaseUrl}
setCloudTranscriptionBaseUrl={setCloudTranscriptionBaseUrl}
suppressRepetition={suppressRepetition}
setSuppressRepetition={setSuppressRepetition}
toast={toast}
/>
);
Expand Down
23 changes: 22 additions & 1 deletion src/helpers/audioManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -919,8 +919,29 @@ registerProcessor("pcm-streaming-processor", PCMStreamingProcessor);
}
}

removeRepetitions(text) {
let result = text;
let prev;
do {
prev = result;
result = result.replace(/(\b.{10,}?)\s+\1(?=\s|$)/g, '$1');
} while (result !== prev);
return result.trim();
}

async processTranscription(text, source) {
const normalizedText = typeof text === "string" ? text.trim() : "";
let normalizedText = typeof text === "string" ? text.trim() : "";

if (normalizedText && getSettings().suppressRepetition) {
const before = normalizedText;
normalizedText = this.removeRepetitions(normalizedText);
if (before !== normalizedText) {
logger.debug("Removed repeated phrases from transcription", {
beforeLength: before.length,
afterLength: normalizedText.length,
}, "transcription");
}
}

if (!normalizedText) {
logger.logReasoning("TRANSCRIPTION_EMPTY_SKIPPING_REASONING", {
Expand Down
8 changes: 7 additions & 1 deletion src/helpers/whisperServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,13 @@ class WhisperServerManager extends EventEmitter {
spawnEnv.CUDA_VISIBLE_DEVICES = process.env.TRANSCRIPTION_GPU_INDEX;
}

const args = ["--model", modelPath, "--host", "127.0.0.1", "--port", String(this.port)];
const args = [
"--model", modelPath,
"--host", "127.0.0.1",
"--port", String(this.port),
"--max-context", "128",
"--entropy-thold", "2.8",
];

// FFmpeg is required for pre-converting audio to 16kHz mono WAV
this.canConvert = !!ffmpegPath;
Expand Down
3 changes: 3 additions & 0 deletions src/hooks/useSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface TranscriptionSettings {
cloudTranscriptionMode: string;
customDictionary: string[];
assemblyAiStreaming: boolean;
suppressRepetition: boolean;
}

export interface ReasoningSettings {
Expand Down Expand Up @@ -181,6 +182,8 @@ function useSettingsInternal() {
customDictionary: store.customDictionary,
assemblyAiStreaming: store.assemblyAiStreaming,
setAssemblyAiStreaming: store.setAssemblyAiStreaming,
suppressRepetition: store.suppressRepetition,
setSuppressRepetition: store.setSuppressRepetition,
useReasoningModel: store.useReasoningModel,
reasoningModel: store.reasoningModel,
reasoningProvider: store.reasoningProvider,
Expand Down
4 changes: 3 additions & 1 deletion src/locales/de/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1398,7 +1398,9 @@
"gpuDevice": {
"title": "Transkriptions-GPU",
"description": "GPU für lokale Spracherkennung"
}
},
"suppressRepetitionLabel": "Wiederholte Phrasen unterdrücken",
"suppressRepetitionDescription": "Automatisch wiederholte Phrasen aus Transkriptionen entfernen. Hilft, Halluzinationsschleifen bei längeren Aufnahmen zu verhindern."
},
"intelligence": {
"gpuDevice": {
Expand Down
4 changes: 3 additions & 1 deletion src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1446,7 +1446,9 @@
"gpuDevice": {
"title": "Transcription GPU",
"description": "GPU used for local speech-to-text"
}
},
"suppressRepetitionLabel": "Suppress repeated phrases",
"suppressRepetitionDescription": "Automatically remove repeated phrases from transcriptions. Helps prevent hallucination loops in longer recordings."
},
"intelligence": {
"gpuDevice": {
Expand Down
4 changes: 3 additions & 1 deletion src/locales/es/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1398,7 +1398,9 @@
"gpuDevice": {
"title": "GPU de transcripción",
"description": "GPU usada para transcripción local"
}
},
"suppressRepetitionLabel": "Suprimir frases repetidas",
"suppressRepetitionDescription": "Eliminar automáticamente frases repetidas de las transcripciones. Ayuda a prevenir bucles de alucinación en grabaciones largas."
},
"intelligence": {
"gpuDevice": {
Expand Down
4 changes: 3 additions & 1 deletion src/locales/fr/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1398,7 +1398,9 @@
"gpuDevice": {
"title": "GPU de transcription",
"description": "GPU pour la transcription locale"
}
},
"suppressRepetitionLabel": "Supprimer les phrases répétées",
"suppressRepetitionDescription": "Supprime automatiquement les phrases répétées des transcriptions. Aide à prévenir les boucles d'hallucination lors d'enregistrements longs."
},
"intelligence": {
"gpuDevice": {
Expand Down
4 changes: 3 additions & 1 deletion src/locales/it/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1398,7 +1398,9 @@
"gpuDevice": {
"title": "GPU trascrizione",
"description": "GPU usata per la trascrizione locale"
}
},
"suppressRepetitionLabel": "Sopprimi frasi ripetute",
"suppressRepetitionDescription": "Rimuovi automaticamente le frasi ripetute dalle trascrizioni. Aiuta a prevenire i loop di allucinazione nelle registrazioni lunghe."
},
"intelligence": {
"gpuDevice": {
Expand Down
4 changes: 3 additions & 1 deletion src/locales/ja/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1398,7 +1398,9 @@
"gpuDevice": {
"title": "文字起こしGPU",
"description": "ローカル音声認識に使用するGPU"
}
},
"suppressRepetitionLabel": "繰り返しフレーズを抑制",
"suppressRepetitionDescription": "文字起こしから繰り返しフレーズを自動的に削除します。長い録音でのハルシネーションループを防ぐのに役立ちます。"
},
"intelligence": {
"gpuDevice": {
Expand Down
4 changes: 3 additions & 1 deletion src/locales/pt/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1370,7 +1370,9 @@
"gpuDevice": {
"title": "GPU de transcrição",
"description": "GPU usada para transcrição local"
}
},
"suppressRepetitionLabel": "Suprimir frases repetidas",
"suppressRepetitionDescription": "Remover automaticamente frases repetidas das transcrições. Ajuda a prevenir loops de alucinação em gravações longas."
},
"intelligence": {
"gpuDevice": {
Expand Down
4 changes: 3 additions & 1 deletion src/locales/ru/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1398,7 +1398,9 @@
"gpuDevice": {
"title": "GPU транскрипции",
"description": "GPU для локального распознавания речи"
}
},
"suppressRepetitionLabel": "Подавление повторов",
"suppressRepetitionDescription": "Автоматически удалять повторяющиеся фразы из транскрипции. Помогает предотвратить зацикливание при длинных записях."
},
"intelligence": {
"gpuDevice": {
Expand Down
4 changes: 3 additions & 1 deletion src/locales/zh-CN/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1393,7 +1393,9 @@
"gpuDevice": {
"title": "转录 GPU",
"description": "用于本地语音识别的 GPU"
}
},
"suppressRepetitionLabel": "抑制重复短语",
"suppressRepetitionDescription": "自动从转录中删除重复的短语。有助于防止长录音中的幻觉循环。"
},
"intelligence": {
"gpuDevice": {
Expand Down
4 changes: 3 additions & 1 deletion src/locales/zh-TW/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1393,7 +1393,9 @@
"gpuDevice": {
"title": "轉錄 GPU",
"description": "用於本機語音辨識的 GPU"
}
},
"suppressRepetitionLabel": "抑制重複短語",
"suppressRepetitionDescription": "自動從轉錄中刪除重複的短語。有助於防止長錄音中的幻覺循環。"
},
"intelligence": {
"gpuDevice": {
Expand Down
3 changes: 3 additions & 0 deletions src/stores/settingsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ const BOOLEAN_SETTINGS = new Set([
"keepTranscriptionInClipboard",
"dataRetentionEnabled",
"noteFilesEnabled",
"suppressRepetition",
]);

const ARRAY_SETTINGS = new Set(["customDictionary", "gcalAccounts"]);
Expand Down Expand Up @@ -250,6 +251,7 @@ export const useSettingsStore = create<SettingsState>()((set, get) => ({
cloudReasoningBaseUrl: readString("cloudReasoningBaseUrl", API_ENDPOINTS.OPENAI_BASE),
customDictionary: readStringArray("customDictionary", []),
assemblyAiStreaming: readBoolean("assemblyAiStreaming", true),
suppressRepetition: readBoolean("suppressRepetition", true),

useReasoningModel: readBoolean("useReasoningModel", true),
reasoningModel: readString("reasoningModel", ""),
Expand Down Expand Up @@ -342,6 +344,7 @@ export const useSettingsStore = create<SettingsState>()((set, get) => ({
setCloudReasoningMode: createStringSetter("cloudReasoningMode"),
setCloudReasoningBaseUrl: createStringSetter("cloudReasoningBaseUrl"),
setAssemblyAiStreaming: createBooleanSetter("assemblyAiStreaming"),
setSuppressRepetition: createBooleanSetter("suppressRepetition"),
setUseReasoningModel: createBooleanSetter("useReasoningModel"),
setReasoningModel: createStringSetter("reasoningModel"),
setReasoningProvider: createStringSetter("reasoningProvider"),
Expand Down
Loading