## Phase 8: Enterprise Extractor Improvements ✅ - 14 security extractors (TLS, JWT, SQL injection, XSS, etc.) - 10 framework-specific extractors (Spring, Django, Rails, etc.) - Config file security detection (YAML, TOML) ## Phase 9: Autonomous Extractor Generation ✅ - Shadow mode executor with TP/FP tracking - Graduation pipeline with confidence thresholds - Auto-rollback on regression detection - Cross-project pattern syncing ## UAT Suite Complete (14 scripts, 90 tests) - test-core-detection.sh (6 tests) - test-declarative-extractors.sh (5 tests) - test-domain-frameworks.sh (5 tests) - test-domain-unreal.sh (3 tests) - test-llm-extraction.sh (6 tests) - test-eval-harness.sh (5 tests) - test-cross-language.sh (3 tests) - test-precommit-performance.sh (4 tests) - test-output-formats.sh (8 tests) - test-drift-detection.sh (6 tests) - test-exit-codes.sh (12 tests) + 3 more scripts ## Other Changes - Updated roadmap to mark Phase 8-9 complete - Added .gitignore entries for build artifacts - Updated pre-commit: 800 line limit, exclude tests/data/cmd Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
97 lines
2.7 KiB
Go
97 lines
2.7 KiB
Go
package elevenlabs
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
)
|
|
|
|
const (
|
|
// DefaultVoiceDesignModel is the default model for voice design.
|
|
DefaultVoiceDesignModel = "eleven_multilingual_ttv_v2"
|
|
|
|
// DefaultGuidanceScale balances prompt adherence with audio quality.
|
|
DefaultGuidanceScale = 5.0
|
|
|
|
// DefaultLoudness is the default volume level.
|
|
DefaultLoudness = 0.5
|
|
)
|
|
|
|
// DesignVoice generates voice previews from a text description.
|
|
// Returns typically 3 voice previews to choose from.
|
|
func (c *Client) DesignVoice(ctx context.Context, req VoiceDesignRequest) (*VoiceDesignResponse, error) {
|
|
if req.VoiceDescription == "" {
|
|
return nil, fmt.Errorf("%w: voice description is required", ErrInvalidConfig)
|
|
}
|
|
if len(req.VoiceDescription) < 20 || len(req.VoiceDescription) > 1000 {
|
|
return nil, fmt.Errorf("%w: voice description must be 20-1000 characters", ErrInvalidConfig)
|
|
}
|
|
|
|
// Set defaults
|
|
if req.ModelID == "" {
|
|
req.ModelID = DefaultVoiceDesignModel
|
|
}
|
|
if req.GuidanceScale == 0 {
|
|
req.GuidanceScale = DefaultGuidanceScale
|
|
}
|
|
if req.Loudness == 0 {
|
|
req.Loudness = DefaultLoudness
|
|
}
|
|
|
|
// If no text provided, enable auto-generation
|
|
if req.Text == "" {
|
|
req.AutoGenerateText = true
|
|
}
|
|
|
|
respBody, err := c.doRequest(ctx, http.MethodPost, "/text-to-voice/design", req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("design voice: %w", err)
|
|
}
|
|
|
|
var resp VoiceDesignResponse
|
|
if err := json.Unmarshal(respBody, &resp); err != nil {
|
|
return nil, fmt.Errorf("unmarshal voice design response: %w", err)
|
|
}
|
|
|
|
return &resp, nil
|
|
}
|
|
|
|
// SaveDesignedVoice saves a voice preview as a permanent voice.
|
|
// The GeneratedVoiceID comes from a VoicePreview returned by DesignVoice.
|
|
func (c *Client) SaveDesignedVoice(ctx context.Context, req SaveVoiceRequest) (*SaveVoiceResponse, error) {
|
|
if req.VoiceName == "" {
|
|
return nil, fmt.Errorf("%w: voice name is required", ErrInvalidConfig)
|
|
}
|
|
if req.GeneratedVoiceID == "" {
|
|
return nil, fmt.Errorf("%w: generated voice ID is required", ErrInvalidConfig)
|
|
}
|
|
|
|
respBody, err := c.doRequest(ctx, http.MethodPost, "/text-to-voice/create-voice-from-preview", req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("save designed voice: %w", err)
|
|
}
|
|
|
|
var resp SaveVoiceResponse
|
|
if err := json.Unmarshal(respBody, &resp); err != nil {
|
|
return nil, fmt.Errorf("unmarshal save voice response: %w", err)
|
|
}
|
|
|
|
return &resp, nil
|
|
}
|
|
|
|
// DeleteVoice removes a voice from the account.
|
|
func (c *Client) DeleteVoice(ctx context.Context, voiceID string) error {
|
|
if voiceID == "" {
|
|
return fmt.Errorf("%w: voice ID is required", ErrInvalidConfig)
|
|
}
|
|
|
|
path := fmt.Sprintf("/voices/%s", voiceID)
|
|
_, err := c.doRequest(ctx, http.MethodDelete, path, nil)
|
|
if err != nil {
|
|
return fmt.Errorf("delete voice: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|