Files
Memoh/internal/audio/bootstrap.go
T
Acbox 925fdee478 feat: transcription support (#394)
* feat: expand speech provider support with new client types and configuration schema

* feat: add icon support for speech providers and update related configurations

* feat: add SVG support for Deepgram and Elevenlabs with Vue components

* feat: except *-speech client type in llm provider

* feat: enhance speech provider functionality with advanced settings and model import capabilities

* chore: remove go.mod replace

* feat: enhance speech provider functionality with advanced settings and model import capabilities

* chore: update go module dependencies

* feat: Ear and Mouth

* fix: separate ear/mouth page

* fix: separate audio domain and restore transcription templates

Move speech and transcription internals into the audio domain, restore template-driven transcription providers, and regenerate Swagger/SDK so the frontend can stop hand-calling /transcription-* APIs.

---------

Co-authored-by: aki <arisu@ieee.org>
2026-04-22 00:12:01 +08:00

101 lines
3.3 KiB
Go

package audio
import (
"context"
"encoding/json"
"errors"
"fmt"
"log/slog"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype"
"github.com/memohai/memoh/internal/db/sqlc"
"github.com/memohai/memoh/internal/models"
)
func SyncRegistry(ctx context.Context, logger *slog.Logger, queries *sqlc.Queries, registry *Registry) error {
for _, def := range registry.List() {
provider, err := queries.GetProviderByClientType(ctx, string(def.ClientType))
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
if logger != nil {
logger.Warn("audio registry skipped provider without template",
slog.String("provider", string(def.ClientType)),
slog.String("display_name", def.DisplayName))
}
continue
}
if logger != nil {
logger.Warn("audio registry failed to load provider template",
slog.String("provider", string(def.ClientType)),
slog.String("display_name", def.DisplayName),
slog.Any("error", err))
}
return fmt.Errorf("get provider by client type %s: %w", def.ClientType, err)
}
synced := 0
if !isTranscriptionClientType(def.ClientType) {
for _, model := range def.Models {
if shouldHideTemplateModel(def, models.ModelTypeSpeech, model.ID) {
if err := queries.DeleteModelByProviderAndType(ctx, sqlc.DeleteModelByProviderAndTypeParams{
ProviderID: provider.ID,
ModelID: model.ID,
Type: string(models.ModelTypeSpeech),
}); err != nil {
return fmt.Errorf("delete hidden speech template model %s: %w", model.ID, err)
}
continue
}
modelConfigJSON, err := json.Marshal(map[string]any{})
if err != nil {
return fmt.Errorf("marshal speech model config: %w", err)
}
name := pgtype.Text{String: model.Name, Valid: model.Name != ""}
if _, err := queries.UpsertRegistryModel(ctx, sqlc.UpsertRegistryModelParams{
ModelID: model.ID,
Name: name,
ProviderID: provider.ID,
Type: string(models.ModelTypeSpeech),
Config: modelConfigJSON,
}); err != nil {
return fmt.Errorf("upsert speech model %s: %w", model.ID, err)
}
synced++
}
}
for _, model := range def.TranscriptionModels {
if shouldHideTemplateModel(def, models.ModelTypeTranscription, model.ID) {
if err := queries.DeleteModelByProviderAndType(ctx, sqlc.DeleteModelByProviderAndTypeParams{
ProviderID: provider.ID,
ModelID: model.ID,
Type: string(models.ModelTypeTranscription),
}); err != nil {
return fmt.Errorf("delete hidden transcription template model %s: %w", model.ID, err)
}
continue
}
modelConfigJSON, err := json.Marshal(map[string]any{})
if err != nil {
return fmt.Errorf("marshal transcription model config: %w", err)
}
name := pgtype.Text{String: model.Name, Valid: model.Name != ""}
if _, err := queries.UpsertRegistryModel(ctx, sqlc.UpsertRegistryModelParams{
ModelID: model.ID,
Name: name,
ProviderID: provider.ID,
Type: string(models.ModelTypeTranscription),
Config: modelConfigJSON,
}); err != nil {
return fmt.Errorf("upsert transcription model %s: %w", model.ID, err)
}
}
if logger != nil {
logger.Info("speech registry synced", slog.String("provider", string(def.ClientType)), slog.Int("models", synced))
}
}
return nil
}