// CRITICAL ORDER: Include system headers first #include #include #include #include // Include local headers before spdlog #include "STTService.hpp" #include "../shared/audio/ISTTEngine.hpp" // Include spdlog after local headers #include #include namespace aissia { STTService::STTService(const nlohmann::json& config) : m_config(config) { m_logger = spdlog::get("STTService"); if (!m_logger) { m_logger = spdlog::stdout_color_mt("STTService"); } // Extract language from config if (config.contains("active_mode") && config["active_mode"].contains("language")) { m_language = config["active_mode"]["language"].get(); } m_logger->info("STTService created"); } STTService::~STTService() { stop(); } bool STTService::start() { m_logger->info("Starting STT service"); loadEngines(); if (!m_activeEngine || !m_activeEngine->isAvailable()) { m_logger->error("No active STT engine available"); return false; } m_logger->info("STT service started"); return true; } void STTService::stop() { m_logger->info("Stopping STT service"); stopListening(); m_activeEngine.reset(); } void STTService::setMode(STTMode mode) { if (m_currentMode == mode) { return; } m_logger->info("Switching STT mode"); m_currentMode = mode; } std::string STTService::transcribeFile(const std::string& filePath) { if (!m_activeEngine || !m_activeEngine->isAvailable()) { m_logger->warn("No STT engine available for transcription"); return ""; } m_logger->info("Transcribing file"); try { std::string result = m_activeEngine->transcribeFile(filePath); m_logger->info("Transcription complete"); return result; } catch (const std::exception& e) { m_logger->error("Transcription failed"); return ""; } } std::string STTService::transcribe(const std::vector& audioData) { if (!m_activeEngine || !m_activeEngine->isAvailable()) { return ""; } if (audioData.empty()) { return ""; } try { std::string result = m_activeEngine->transcribe(audioData); if (!result.empty() && m_listening && m_onTranscription) { m_onTranscription(result, m_currentMode); } return result; } catch (const std::exception& e) { m_logger->error("Transcription failed"); return ""; } } void STTService::startListening(TranscriptionCallback onTranscription, KeywordCallback onKeyword) { m_logger->info("Start listening"); m_onTranscription = onTranscription; m_onKeyword = onKeyword; m_listening = true; m_logger->warn("Streaming microphone capture not yet implemented"); } void STTService::stopListening() { if (!m_listening) { return; } m_logger->info("Stop listening"); m_listening = false; } void STTService::setLanguage(const std::string& language) { m_logger->info("Setting language"); m_language = language; if (m_activeEngine) { m_activeEngine->setLanguage(language); } } bool STTService::isAvailable() const { return m_activeEngine && m_activeEngine->isAvailable(); } std::string STTService::getCurrentEngine() const { if (m_activeEngine) { return m_activeEngine->getEngineName(); } return "none"; } void STTService::loadEngines() { m_logger->info("Loading STT engines"); std::string engineType = "auto"; if (m_config.contains("active_mode")) { const auto& activeMode = m_config["active_mode"]; if (activeMode.contains("engine")) { engineType = activeMode["engine"]; } } std::string modelPath; if (m_config.contains("active_mode")) { const auto& activeMode = m_config["active_mode"]; if (activeMode.contains("model_path")) { modelPath = activeMode["model_path"]; } } std::string apiKey; if (m_config.contains("whisper_api")) { const auto& whisperApi = m_config["whisper_api"]; std::string apiKeyEnv = "OPENAI_API_KEY"; if (whisperApi.contains("api_key_env")) { apiKeyEnv = whisperApi["api_key_env"]; } const char* envVal = std::getenv(apiKeyEnv.c_str()); if (envVal) { apiKey = envVal; } } m_activeEngine = STTEngineFactory::create(engineType, modelPath, apiKey); if (m_activeEngine && m_activeEngine->isAvailable()) { m_activeEngine->setLanguage(m_language); m_logger->info("STT engine loaded successfully"); } else { m_logger->warn("No active STT engine available"); } } } // namespace aissia