This commit is contained in:
Josh Hawkins 2026-01-31 11:03:31 -06:00
parent 5e8de5a911
commit 43c7193a3a
3 changed files with 33 additions and 9 deletions

View File

@ -51,17 +51,17 @@ class AudioTranscriptionConfig(FrigateBaseModel):
language: str = Field( language: str = Field(
default="en", default="en",
title="Transcription language", title="Transcription language",
description="Language code used for transcription/translation (for example 'en' for English).", description="Language code used for transcription/translation (for example 'en' for English). See https://whisper-api.com/docs/languages/ for supported language codes.",
) )
device: Optional[EnrichmentsDeviceEnum] = Field( device: Optional[EnrichmentsDeviceEnum] = Field(
default=EnrichmentsDeviceEnum.CPU, default=EnrichmentsDeviceEnum.CPU,
title="Transcription device", title="Transcription device",
description="Device key (CPU/GPU) to run the transcription model on.", description="Device key (CPU/GPU) to run the transcription model on. Only NVIDIA CUDA GPUs are currently supported for transcription.",
) )
model_size: str = Field( model_size: str = Field(
default="small", default="small",
title="Model size", title="Model size",
description="Model size to use for transcription; the small model runs on CPU, large model requires a GPU.", description="Model size to use for offline audio event transcription.",
) )
live_enabled: Optional[bool] = Field( live_enabled: Optional[bool] = Field(
default=False, default=False,

View File

@ -223,6 +223,12 @@ export function createConfigSection({
} }
}, [formKey]); }, [formKey]);
// Build a minimal overrides payload by comparing `current` against `base`
// (existing config) and `defaults` (schema defaults).
// - Returns `undefined` for null/empty values or when `current` equals `base`
// (or equals `defaults` when `base` is undefined).
// - For objects, recurses and returns an object containing only keys that
// are overridden; returns `undefined` if no keys are overridden.
const buildOverrides = useCallback( const buildOverrides = useCallback(
( (
current: unknown, current: unknown,

View File

@ -353,17 +353,17 @@ const systemSections = [
"ffmpeg", "ffmpeg",
"detectors", "detectors",
"model", "model",
"classification",
]; ];
// Integration sections (global only) // Integration sections (global only)
const integrationSections = [ const integrationSections = [
"mqtt", "mqtt",
"audio_transcription",
"genai",
"semantic_search", "semantic_search",
"genai",
"face_recognition", "face_recognition",
"lpr", "lpr",
"classification",
"audio_transcription",
]; ];
interface GlobalConfigSectionProps { interface GlobalConfigSectionProps {
@ -382,7 +382,11 @@ function GlobalConfigSection({
title, title,
}: GlobalConfigSectionProps) { }: GlobalConfigSectionProps) {
const sectionConfig = globalSectionConfigs[sectionKey]; const sectionConfig = globalSectionConfigs[sectionKey];
const { t } = useTranslation(["config/global", "views/settings", "common"]); const { t, i18n } = useTranslation([
"config/global",
"views/settings",
"common",
]);
const [pendingData, setPendingData] = useState<unknown | null>(null); const [pendingData, setPendingData] = useState<unknown | null>(null);
const [isSaving, setIsSaving] = useState(false); const [isSaving, setIsSaving] = useState(false);
const [formKey, setFormKey] = useState(0); const [formKey, setFormKey] = useState(0);
@ -538,7 +542,11 @@ function GlobalConfigSection({
} }
export default function GlobalConfigView() { export default function GlobalConfigView() {
const { t } = useTranslation(["views/settings", "config/global", "common"]); const { t, i18n } = useTranslation([
"views/settings",
"config/global",
"common",
]);
const [activeTab, setActiveTab] = useState("shared"); const [activeTab, setActiveTab] = useState("shared");
const [activeSection, setActiveSection] = useState("detect"); const [activeSection, setActiveSection] = useState("detect");
@ -669,7 +677,7 @@ export default function GlobalConfigView() {
activeSection === section.key ? "block" : "hidden", activeSection === section.key ? "block" : "hidden",
)} )}
> >
<Heading as="h4" className="mb-4"> <Heading as="h4" className="mb-1">
{t(`${section.key}.label`, { {t(`${section.key}.label`, {
ns: "config/global", ns: "config/global",
defaultValue: defaultValue:
@ -677,6 +685,16 @@ export default function GlobalConfigView() {
section.key.slice(1).replace(/_/g, " "), section.key.slice(1).replace(/_/g, " "),
})} })}
</Heading> </Heading>
{i18n.exists(`${section.key}.description`, {
ns: "config/global",
}) && (
<p className="mb-4 text-sm text-muted-foreground">
{t(`${section.key}.description`, {
ns: "config/global",
})}
</p>
)}
<SectionComponent <SectionComponent
level="global" level="global"
onSave={handleSave} onSave={handleSave}