#pragma once #include "config.h" #include "engine/community_models/echo_tts/config.h" #include "engine/framework/assets/resource_bundle.h" #include "engine/framework/model_spec/metadata.h" #include "engine/framework/runtime/cache_slots.h" #include "engine/framework/runtime/session_base.h" #include "engine/framework/codecs/fish_dac_codec_runtime.h" #include #include #include #include namespace engine::models::echo_tts { class EchoDiTRuntime; struct EchoTtsAssets { assets::ResourceBundle resources; EchoTtsConfig config; EchoPcaState pca; std::shared_ptr dit_weights; // The Fish S1-DAC config this GGUF's codec weights were trained with. // The framework owns the graph; Echo only supplies the config and weights. engine::codecs::FishDacCodecConfig codec_config; std::shared_ptr codec_weights; }; // Encoding a speaker reference is linear in its length -- a 4.5-minute clip is // ten Fish encode passes -- and the result depends only on the audio and the // trim length, so it is cached across requests. Servers reusing a handful of // voices then pay it once per voice rather than once per request. struct EchoReferenceIdentity { std::string id; int64_t max_samples = 0; }; struct EchoReferenceIdentityEqual { bool operator()(const EchoReferenceIdentity & a, const EchoReferenceIdentity & b) const { return a.max_samples == b.max_samples && a.id == b.id; } }; struct EchoPreparedSpeaker { std::vector latent; int64_t frames = 0; }; std::shared_ptr make_echo_tts_loader(); class EchoTtsSession final : public runtime::RuntimeSessionBase, public runtime::IOfflineVoiceTaskSession { public: EchoTtsSession( runtime::TaskSpec task, runtime::SessionOptions options, std::shared_ptr assets, std::shared_ptr contract); ~EchoTtsSession() override; std::string family() const override; runtime::VoiceTaskKind task_kind() const override; runtime::RunMode run_mode() const override; void prepare(const runtime::SessionPreparationRequest & request) override; runtime::TaskResult run(const runtime::TaskRequest & request) override; void reset(); private: // Reference trim limit: request option, else session default, else the // trained maximum. Returned in samples at the codec rate. int64_t resolve_reference_max_samples( const std::unordered_map & request_options) const; EchoSamplerOptions parse_sampler_options( const std::unordered_map & options) const; // Encodes reference audio to 80-D PCA latents, mirroring // inference.py::get_speaker_latent_and_mask. void encode_speaker(const runtime::AudioBuffer & audio); runtime::AudioBuffer synthesize_chunk( const std::string & text, const EchoSamplerOptions & sampler); runtime::TaskSpec task_; std::shared_ptr assets_; std::shared_ptr contract_; std::unique_ptr dit_; std::unique_ptr codec_; EchoCfgMode cfg_mode_ = EchoCfgMode::Independent; int64_t reference_max_samples_ = 0; bool mem_saver_ = false; std::vector speaker_latent_; int64_t speaker_frames_ = 0; runtime::CacheSlots reference_cache_; }; } // namespace engine::models::echo_tts