feat: support cloned voice deletion

This commit is contained in:
2026-06-17 12:03:13 +08:00
parent c4341335d7
commit 6089aa6085
8 changed files with 259 additions and 1 deletions
+62
View File
@@ -308,6 +308,68 @@ ORDER BY effective_priority ASC,
return items, nil
}
func (s *Store) GetRuntimeModelCandidateForVoiceCloneDeletion(ctx context.Context, platformModelID string, platformID string) (RuntimeModelCandidate, bool, error) {
platformModelID = strings.TrimSpace(platformModelID)
platformID = strings.TrimSpace(platformID)
if platformModelID == "" && platformID == "" {
return RuntimeModelCandidate{}, false, nil
}
var item RuntimeModelCandidate
var credentials []byte
var platformConfig []byte
err := s.pool.QueryRow(ctx, `
SELECT p.id::text, p.platform_key, p.name, p.provider,
COALESCE(NULLIF(p.config->>'specType', ''), NULLIF(cp.provider_type, ''), NULLIF(p.config->>'sourceSpecType', ''), p.provider) AS spec_type,
COALESCE(p.base_url, ''), p.auth_type, p.credentials, p.config,
COALESCE(m.id::text, ''), COALESCE(NULLIF(m.provider_model_name, ''), m.model_name, 'voice_clone'),
COALESCE(m.model_name, 'voice_clone'), COALESCE(m.model_alias, '')
FROM integration_platforms p
LEFT JOIN platform_models m
ON m.platform_id = p.id
AND (
(NULLIF($1, '')::uuid IS NOT NULL AND m.id = NULLIF($1, '')::uuid)
OR (
NULLIF($1, '') IS NULL
AND m.model_type @> jsonb_build_array('voice_clone'::text)
)
)
LEFT JOIN model_catalog_providers cp ON cp.provider_key = p.provider OR cp.provider_code = p.provider
WHERE p.deleted_at IS NULL
AND (
(NULLIF($1, '')::uuid IS NOT NULL AND m.id = NULLIF($1, '')::uuid)
OR (NULLIF($2, '')::uuid IS NOT NULL AND p.id = NULLIF($2, '')::uuid)
)
ORDER BY CASE WHEN NULLIF($1, '')::uuid IS NOT NULL AND m.id = NULLIF($1, '')::uuid THEN 0 ELSE 1 END,
m.created_at DESC
LIMIT 1`, platformModelID, platformID).Scan(
&item.PlatformID,
&item.PlatformKey,
&item.PlatformName,
&item.Provider,
&item.SpecType,
&item.BaseURL,
&item.AuthType,
&credentials,
&platformConfig,
&item.PlatformModelID,
&item.ProviderModelName,
&item.ModelName,
&item.ModelAlias,
)
if err != nil {
if IsNotFound(err) {
return RuntimeModelCandidate{}, false, nil
}
return RuntimeModelCandidate{}, false, err
}
item.Credentials = decodeObject(credentials)
item.PlatformConfig = decodeObject(platformConfig)
item.ModelType = "voice_clone"
item.ClientID = item.PlatformKey + ":voice_clone:" + firstNonEmpty(item.ProviderModelName, item.ModelName)
item.QueueKey = item.ClientID
return item, true, nil
}
type runtimeCandidateLoadInput struct {
Policy map[string]any
ConcurrentActive float64
+44
View File
@@ -133,6 +133,7 @@ SELECT `+clonedVoiceColumns+`
FROM gateway_cloned_voices v
LEFT JOIN integration_platforms p ON p.id = v.platform_id
WHERE (
(
NULLIF($1, '')::uuid IS NOT NULL
AND v.gateway_user_id = NULLIF($1, '')::uuid
)
@@ -140,6 +141,8 @@ WHERE (
NULLIF($2, '') IS NOT NULL
AND v.user_id = $2
)
)
AND v.status <> 'deleted'
ORDER BY v.created_at DESC`, gatewayUserID, userID)
if err != nil {
return nil, err
@@ -181,6 +184,7 @@ WHERE (
(NULLIF($3, '')::uuid IS NOT NULL AND v.id = NULLIF($3, '')::uuid)
OR (NULLIF($4, '') IS NOT NULL AND v.voice_id = $4)
)
AND v.status NOT IN ('deleted', 'failed')
ORDER BY CASE WHEN NULLIF($3, '')::uuid IS NOT NULL AND v.id = NULLIF($3, '')::uuid THEN 0 ELSE 1 END,
v.created_at DESC
LIMIT 1`, gatewayUserID, userID, clonedVoiceID, voiceID))
@@ -193,6 +197,46 @@ LIMIT 1`, gatewayUserID, userID, clonedVoiceID, voiceID))
return item, true, nil
}
func (s *Store) DeleteClonedVoiceForUser(ctx context.Context, user *auth.User, clonedVoiceID string, voiceID string) (ClonedVoice, bool, error) {
gatewayUserID, userID := clonedVoiceUserKeys(user)
clonedVoiceID = strings.TrimSpace(clonedVoiceID)
voiceID = strings.TrimSpace(voiceID)
if clonedVoiceID == "" && voiceID == "" {
return ClonedVoice{}, false, nil
}
item, err := scanClonedVoice(s.pool.QueryRow(ctx, `
WITH updated AS (
UPDATE gateway_cloned_voices v
SET status = 'deleted', updated_at = now()
WHERE (
(
NULLIF($1, '')::uuid IS NOT NULL
AND v.gateway_user_id = NULLIF($1, '')::uuid
)
OR (
NULLIF($2, '') IS NOT NULL
AND v.user_id = $2
)
)
AND (
(NULLIF($3, '')::uuid IS NOT NULL AND v.id = NULLIF($3, '')::uuid)
OR (NULLIF($4, '') IS NOT NULL AND v.voice_id = $4)
)
AND v.status <> 'deleted'
RETURNING *
)
SELECT `+clonedVoiceColumns+`
FROM updated v
LEFT JOIN integration_platforms p ON p.id = v.platform_id`, gatewayUserID, userID, clonedVoiceID, voiceID))
if err != nil {
if IsNotFound(err) {
return ClonedVoice{}, false, nil
}
return ClonedVoice{}, false, err
}
return item, true, nil
}
func (s *Store) TouchClonedVoiceUsage(ctx context.Context, clonedVoiceID string) error {
if strings.TrimSpace(clonedVoiceID) == "" {
return nil