Architecture Phase 7 STT implémentée mais bloquée par conflits de macros
entre GroveEngine (JsonDataNode.h) et spdlog/fmt.
## Nouveau contenu
### Interfaces & Services
- ISTTService.hpp: Interface service STT (modes passive/active, callbacks)
- STTService.{hpp,cpp}: Implémentation service STT avec factory pattern
- VoskSTTEngine.{hpp,cpp}: Engine STT local Vosk (~50MB model)
### Factory Pattern
- STTEngineFactory: Support multi-engines (Vosk, Whisper API, auto-select)
- Fallback automatique Vosk -> Whisper API
### Configuration
- config/voice.json: Config Phase 7 (passive_mode, active_mode, whisper_api)
- Support modèles Vosk locaux + fallback cloud
### Intégration
- VoiceService: Nouvelle méthode configureSTT(json) pour Phase 7
- main.cpp: Chargement config STT depuis voice.json
- CMakeLists.txt: Ajout fichiers + dépendance optionnelle Vosk
## Problème de Compilation
**Bloqué par conflits de macros**:
- JsonDataNode.h (GroveEngine) définit des macros qui polluent 'logger' et 'queue'
- Cause erreurs dans VoiceService.cpp et STTService.cpp
- Voir plans/PHASE7_COMPILATION_ISSUE.md pour diagnostic complet
## Fonctionnalités Implémentées
✅ Architecture STT complète (service layer + engines)
✅ Support Vosk local (modèles français)
✅ Factory pattern avec auto-selection
✅ Configuration JSON Phase 7
✅ Callbacks transcription/keywords
❌ Ne compile pas (macro conflicts)
## Prochaines Étapes
1. Résoudre conflits macros (fixer GroveEngine ou isolation namespace)
2. Phase 7.2: PocketSphinxEngine (keyword spotting "Celuna")
3. Tests intégration STT
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
190 lines
4.7 KiB
C++
190 lines
4.7 KiB
C++
// CRITICAL ORDER: Include system headers first
|
|
#include <nlohmann/json.hpp>
|
|
#include <cstdlib>
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
// Include local headers before spdlog
|
|
#include "STTService.hpp"
|
|
#include "../shared/audio/ISTTEngine.hpp"
|
|
|
|
// Include spdlog after local headers
|
|
#include <spdlog/spdlog.h>
|
|
#include <spdlog/sinks/stdout_color_sinks.h>
|
|
|
|
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<std::string>();
|
|
}
|
|
|
|
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<float>& 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
|