166 lines
5.2 KiB
Go
166 lines
5.2 KiB
Go
package config
|
||
|
||
import (
|
||
"os"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
type Config struct {
|
||
HTTPHost string
|
||
HTTPPort int
|
||
DatabaseURL string
|
||
MigrateOnStart bool
|
||
APIAuthToken string
|
||
|
||
LLMBaseURL string
|
||
LLMAPIKey string
|
||
LLMModel string
|
||
LLMTimeout time.Duration
|
||
TranscriptionProviders []string
|
||
WhisperXURL string
|
||
WhisperXTimeout time.Duration
|
||
WhisperXLeadSilence time.Duration
|
||
QwenAudioBaseURL string
|
||
QwenAudioAPIKey string
|
||
QwenAudioModel string
|
||
QwenAudioTimeout time.Duration
|
||
VoxtralBaseURL string
|
||
VoxtralAPIKey string
|
||
VoxtralModel string
|
||
VoxtralTimeout time.Duration
|
||
AudioLLMMaxTokens int
|
||
AudioLLMPrompt string
|
||
FfmpegPath string
|
||
AIStatsSidecarURL string
|
||
AIStatsTimeout time.Duration
|
||
|
||
WorkerID string
|
||
WorkerHTTPHost string
|
||
WorkerHTTPPort int
|
||
WorkerPollInterval time.Duration
|
||
WorkerClaimLimit int
|
||
WorkerLeaseTimeout time.Duration
|
||
WorkerTaskTypes []string
|
||
WorkerModelProfiles []string
|
||
}
|
||
|
||
func Load() Config {
|
||
return Config{
|
||
HTTPHost: envString("HTTP_HOST", "0.0.0.0"),
|
||
HTTPPort: envInt("HTTP_PORT", 8080),
|
||
DatabaseURL: envString("DATABASE_URL", ""),
|
||
MigrateOnStart: envBool("MIGRATE_ON_START", true),
|
||
APIAuthToken: envString("AI_SERVICE_TOKEN", ""),
|
||
|
||
LLMBaseURL: envString("LLM_BASE_URL", ""),
|
||
LLMAPIKey: envString("LLM_API_KEY", ""),
|
||
LLMModel: envString("LLM_MODEL", "qwen2.5-14b"),
|
||
LLMTimeout: envDuration("LLM_TIMEOUT", 5*time.Minute),
|
||
TranscriptionProviders: envCSVDefault("TRANSCRIPTION_PROVIDERS", []string{"whisperx"}),
|
||
WhisperXURL: envString("WHISPERX_URL", ""),
|
||
WhisperXTimeout: envDuration("WHISPERX_TIMEOUT", 10*time.Minute),
|
||
WhisperXLeadSilence: envDuration("WHISPERX_LEAD_SILENCE", 800*time.Millisecond),
|
||
QwenAudioBaseURL: envString("QWEN_AUDIO_BASE_URL", envString("AUDIO_LLM_BASE_URL", "")),
|
||
QwenAudioAPIKey: envString("QWEN_AUDIO_API_KEY", envString("AUDIO_LLM_API_KEY", envString("LLM_API_KEY", ""))),
|
||
QwenAudioModel: envString("QWEN_AUDIO_MODEL", "Qwen/Qwen2-Audio-7B-Instruct"),
|
||
QwenAudioTimeout: envDuration("QWEN_AUDIO_TIMEOUT", envDuration("AUDIO_LLM_TIMEOUT", 10*time.Minute)),
|
||
VoxtralBaseURL: envString("VOXTRAL_BASE_URL", envString("AUDIO_LLM_BASE_URL", "")),
|
||
VoxtralAPIKey: envString("VOXTRAL_API_KEY", envString("AUDIO_LLM_API_KEY", envString("LLM_API_KEY", ""))),
|
||
VoxtralModel: envString("VOXTRAL_MODEL", "mistralai/Voxtral-Small-24B-2507"),
|
||
VoxtralTimeout: envDuration("VOXTRAL_TIMEOUT", envDuration("AUDIO_LLM_TIMEOUT", 10*time.Minute)),
|
||
AudioLLMMaxTokens: envInt("AUDIO_LLM_MAX_TOKENS", 4096),
|
||
AudioLLMPrompt: envString("AUDIO_LLM_PROMPT", defaultAudioLLMPrompt()),
|
||
FfmpegPath: envString("FFMPEG_PATH", "/usr/bin/ffmpeg"),
|
||
AIStatsSidecarURL: envString("AI_STATS_SIDECAR_URL", ""),
|
||
AIStatsTimeout: envDuration("AI_STATS_TIMEOUT", 8*time.Second),
|
||
|
||
WorkerID: envString("WORKER_ID", hostname()),
|
||
WorkerHTTPHost: envString("WORKER_HTTP_HOST", "0.0.0.0"),
|
||
WorkerHTTPPort: envInt("WORKER_HTTP_PORT", 8081),
|
||
WorkerPollInterval: envDuration("WORKER_POLL_INTERVAL", 2*time.Second),
|
||
WorkerClaimLimit: envInt("WORKER_CLAIM_LIMIT", 4),
|
||
WorkerLeaseTimeout: envDuration("WORKER_LEASE_TIMEOUT", 15*time.Minute),
|
||
WorkerTaskTypes: envCSV("WORKER_TASK_TYPES"),
|
||
WorkerModelProfiles: envCSV("WORKER_MODEL_PROFILES"),
|
||
}
|
||
}
|
||
|
||
func envString(key, fallback string) string {
|
||
if v := os.Getenv(key); v != "" {
|
||
return v
|
||
}
|
||
return fallback
|
||
}
|
||
|
||
func envInt(key string, fallback int) int {
|
||
raw := os.Getenv(key)
|
||
if raw == "" {
|
||
return fallback
|
||
}
|
||
v, err := strconv.Atoi(raw)
|
||
if err != nil {
|
||
return fallback
|
||
}
|
||
return v
|
||
}
|
||
|
||
func envBool(key string, fallback bool) bool {
|
||
raw := os.Getenv(key)
|
||
if raw == "" {
|
||
return fallback
|
||
}
|
||
v, err := strconv.ParseBool(raw)
|
||
if err != nil {
|
||
return fallback
|
||
}
|
||
return v
|
||
}
|
||
|
||
func envDuration(key string, fallback time.Duration) time.Duration {
|
||
raw := os.Getenv(key)
|
||
if raw == "" {
|
||
return fallback
|
||
}
|
||
v, err := time.ParseDuration(raw)
|
||
if err != nil {
|
||
return fallback
|
||
}
|
||
return v
|
||
}
|
||
|
||
func envCSV(key string) []string {
|
||
raw := strings.TrimSpace(os.Getenv(key))
|
||
if raw == "" {
|
||
return nil
|
||
}
|
||
parts := strings.Split(raw, ",")
|
||
out := make([]string, 0, len(parts))
|
||
for _, part := range parts {
|
||
if v := strings.TrimSpace(part); v != "" {
|
||
out = append(out, v)
|
||
}
|
||
}
|
||
return out
|
||
}
|
||
|
||
func envCSVDefault(key string, fallback []string) []string {
|
||
if values := envCSV(key); len(values) > 0 {
|
||
return values
|
||
}
|
||
return fallback
|
||
}
|
||
|
||
func defaultAudioLLMPrompt() string {
|
||
return "Расшифруй речь из аудио максимально точно. Сохрани русский язык, имена, телефоны, суммы и смысловые паузы. Не добавляй комментарии, анализ, Markdown или JSON. Верни только чистый текст расшифровки."
|
||
}
|
||
|
||
func hostname() string {
|
||
h, err := os.Hostname()
|
||
if err != nil || h == "" {
|
||
return "ai-service-worker"
|
||
}
|
||
return h
|
||
}
|