Files
LocalAI/pkg/mcp/localaitools/tools_voice_profiles.go
LocalAI [bot] 4056283aa4 [voice] feat: add managed voice cloning profiles (#10799)
* feat(ui): add voice library workflow

Give administrators a production-ready flow to record or upload consented reference audio, manage reusable profiles, inspect API usage, discover compatible models, and hand a saved voice directly to text-to-speech.

Assisted-by: Codex:gpt-5

* feat(voice): add managed voice cloning profiles

Make reusable reference voices manageable through the admin API instead of requiring model-directory and YAML edits. Discover compatible installed and gallery models from server-side backend capabilities, retain explicit model configuration controls, and stage saved references for supported backends.

Expose profile management through REST and MCP, document backend-specific behavior, and cover the workflow from profile creation through real Qwen3-TTS synthesis. Harden the agent-job HTTP test against completion racing cancellation.

Assisted-by: Codex:gpt-5

---------

Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
2026-07-13 09:54:46 +02:00

55 lines
2.1 KiB
Go

package localaitools
import (
"context"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
func registerVoiceProfileTools(s *mcp.Server, client LocalAIClient, opts Options) {
mcp.AddTool(s, &mcp.Tool{
Name: ToolListVoiceProfiles,
Description: "List reusable voice-cloning profiles. Returns stable voice URI values suitable for TTSRequest.voice; filesystem paths are never exposed.",
}, func(ctx context.Context, _ *mcp.CallToolRequest, _ struct{}) (*mcp.CallToolResult, any, error) {
profiles, err := client.ListVoiceProfiles(ctx)
if err != nil {
return errorResult(err), nil, nil
}
return jsonResult(profiles), nil, nil
})
if opts.DisableMutating {
return
}
mcp.AddTool(s, &mcp.Tool{
Name: ToolCreateVoiceProfile,
Description: "Create a reusable voice-cloning profile from a base64 16-bit PCM WAV (mono 24 kHz recommended) and its exact transcript. consent_confirmed must be true. Requires user confirmation per safety rule 1.",
}, func(ctx context.Context, _ *mcp.CallToolRequest, args CreateVoiceProfileRequest) (*mcp.CallToolResult, any, error) {
if args.Name == "" || args.Transcript == "" || args.AudioBase64 == "" {
return errorResultf("name, transcript, and audio_base64 are required"), nil, nil
}
if !args.ConsentConfirmed {
return errorResultf("consent_confirmed must be true"), nil, nil
}
profile, err := client.CreateVoiceProfile(ctx, args)
if err != nil {
return errorResult(err), nil, nil
}
return jsonResult(profile), nil, nil
})
mcp.AddTool(s, &mcp.Tool{
Name: ToolDeleteVoiceProfile,
Description: "Permanently delete a reusable voice-cloning profile by opaque UUID. Requires user confirmation per safety rule 1.",
}, func(ctx context.Context, _ *mcp.CallToolRequest, args DeleteVoiceProfileRequest) (*mcp.CallToolResult, any, error) {
if args.ID == "" {
return errorResultf("id is required"), nil, nil
}
if err := client.DeleteVoiceProfile(ctx, args.ID); err != nil {
return errorResult(err), nil, nil
}
return jsonResult(map[string]any{"deleted": true, "id": args.ID}), nil, nil
})
}