Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/audiocpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
* - Handles are not thread-safe individually. Separate handles may be used
* concurrently from separate threads.
* - Freeing NULL is a no-op, so cleanup paths need no null checks.
* - Strings passed in, file paths included, are UTF-8 whatever code page
* the host process runs under on Windows. Strings returned are UTF-8.
*
* Lifetime note: handles keep their parents alive internally (a session holds
* its model, a model holds its registry). Freeing out of order is therefore
Expand Down
14 changes: 14 additions & 0 deletions include/engine/framework/io/filesystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@

namespace engine::io {

/// A path from a UTF-8 string.
///
/// On Windows a narrow string handed to std::filesystem::path is decoded with
/// the process code page, which is UTF-8 only when the executable asks for it.
/// A DLL runs under its host's code page, so "Thiền Tâm Đức.wav" would name a
/// file that is not there. Bytes that are not valid UTF-8 are decoded with the
/// process code page instead, as before. Everywhere else this is the identity.
std::filesystem::path path_from_utf8(std::string_view value);

/// A path as UTF-8, for ggml (which opens files by UTF-8 name) and for
/// messages. path::string() uses the process code page on Windows, so it
/// mangles or throws on a name that page cannot hold.
std::string path_to_utf8(const std::filesystem::path & path);

bool is_existing_directory(const std::filesystem::path & path);
bool is_existing_file(const std::filesystem::path & path);

Expand Down
7 changes: 4 additions & 3 deletions src/capi/audiocpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include "engine/framework/core/backend.h"
#include "engine/framework/core/module.h"
#include "engine/framework/io/filesystem.h"
#include "engine/framework/runtime/model.h"
#include "engine/framework/runtime/registry.h"
#include "engine/framework/runtime/session.h"
Expand Down Expand Up @@ -311,7 +312,7 @@ audiocpp_status audiocpp_registry_create(const char * config_path, audiocpp_regi
return guard([&] {
auto handle = std::make_unique<audiocpp_registry>();
auto config = config_path != nullptr
? std::optional<std::filesystem::path>(std::filesystem::path(config_path))
? std::optional<std::filesystem::path>(engine::io::path_from_utf8(config_path))
: std::nullopt;
handle->registry = std::make_shared<rt::ModelRegistry>(rt::make_default_registry(config));
handle->families = handle->registry->families();
Expand Down Expand Up @@ -361,7 +362,7 @@ audiocpp_status audiocpp_model_load(audiocpp_registry * registry,
return guard([&] {
auto handle = std::make_unique<audiocpp_model>();
handle->registry = registry->registry;
handle->load_request.model_path = std::filesystem::path(model_path);
handle->load_request.model_path = engine::io::path_from_utf8(model_path);
if (family_hint != nullptr) {
handle->load_request.family_hint = std::string(family_hint);
}
Expand All @@ -370,7 +371,7 @@ audiocpp_status audiocpp_model_load(audiocpp_registry * registry,
if (config->weight_id != nullptr) handle->load_request.weight_id = std::string(config->weight_id);
if (config->model_spec_override != nullptr) {
handle->load_request.model_spec_override =
std::filesystem::path(config->model_spec_override);
engine::io::path_from_utf8(config->model_spec_override);
}
}
handle->load_request.options = option_map(options);
Expand Down
3 changes: 2 additions & 1 deletion src/community_models/inflect_v2/session.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "engine/community_models/inflect_v2/session.h"

#include "engine/framework/debug/profiler.h"
#include "engine/framework/io/filesystem.h"
#include "engine/framework/runtime/options.h"
#include "engine/framework/runtime/spec_backed_model.h"
#include "engine/framework/text/utf8.h"
Expand Down Expand Up @@ -39,7 +40,7 @@ std::filesystem::path session_path(
const auto found = options.options.find(key);
return found == options.options.end()
? std::filesystem::path{}
: std::filesystem::path(found->second);
: engine::io::path_from_utf8(found->second);
}

void validate_session_options(
Expand Down
3 changes: 2 additions & 1 deletion src/community_models/kitten_tts/session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "engine/framework/debug/profiler.h"
#include "engine/framework/debug/trace.h"
#include "engine/framework/io/filesystem.h"
#include "engine/framework/runtime/options.h"
#include "engine/framework/runtime/spec_backed_model.h"
#include "engine/framework/text/chunking.h"
Expand Down Expand Up @@ -29,7 +30,7 @@ constexpr const char *kModelName = "Kitten TTS";

std::filesystem::path session_path(const runtime::SessionOptions &options, const char *key) {
const auto found = options.options.find(key);
return found == options.options.end() ? std::filesystem::path{} : std::filesystem::path(found->second);
return found == options.options.end() ? std::filesystem::path{} : engine::io::path_from_utf8(found->second);
}

std::string request_cache_key(const runtime::Transcript &text, const KittenFrontendSessionState &state) {
Expand Down
4 changes: 2 additions & 2 deletions src/community_models/lfm2_audio/assets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class GgufMetadata {
params.no_alloc = true;
params.ctx = nullptr;

ctx_.reset(gguf_init_from_file(path.string().c_str(), params));
ctx_.reset(gguf_init_from_file(engine::io::path_to_utf8(path).c_str(), params));
if (ctx_ == nullptr) {
throw std::runtime_error("LFM2-Audio failed to read GGUF metadata: " + path.string());
}
Expand Down Expand Up @@ -173,7 +173,7 @@ std::string join(const std::vector<std::string> & values) {

std::filesystem::path resolve_component(
const std::filesystem::path & root, const char * option_name, const std::string & value) {
const auto relative = std::filesystem::path(value).lexically_normal();
const auto relative = engine::io::path_from_utf8(value).lexically_normal();
if (value.empty() || relative.is_absolute() || (!relative.empty() && *relative.begin() == "..")) {
throw std::runtime_error(std::string(option_name) + " must be a nonempty path inside the model directory");
}
Expand Down
3 changes: 2 additions & 1 deletion src/community_models/moss_ttsd/session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "engine/framework/audio/conversion.h"
#include "engine/framework/audio/wav_reader.h"
#include "engine/framework/debug/profiler.h"
#include "engine/framework/io/filesystem.h"
#include "engine/framework/runtime/options.h"

#include <algorithm>
Expand Down Expand Up @@ -357,7 +358,7 @@ runtime::TaskResult MossTtsdSession::run(const runtime::TaskRequest & request) {
speakers.emplace_back();
continue;
}
const auto wav = engine::audio::read_wav_f32(std::filesystem::path(*path));
const auto wav = engine::audio::read_wav_f32(engine::io::path_from_utf8(*path));
speakers.emplace_back(encode_reference(
runtime::AudioBuffer{wav.sample_rate, wav.channels, wav.samples}));
}
Expand Down
3 changes: 2 additions & 1 deletion src/community_models/outetts/session.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "engine/community_models/outetts/session.h"

#include "engine/framework/audio/fft.h"
#include "engine/framework/io/filesystem.h"
#include "engine/framework/runtime/options.h"
#include "engine/framework/runtime/spec_backed_model.h"
#include "engine/framework/debug/trace.h"
Expand Down Expand Up @@ -486,7 +487,7 @@ resolve_aligner_assets(const runtime::SessionOptions &options,
"outetts.forced_aligner_model_path"});
if (model_path.has_value()) {
return engine::models::qwen3_asr::load_qwen3_asr_assets(
std::filesystem::path(*model_path), "qwen3_forced_aligner");
engine::io::path_from_utf8(*model_path), "qwen3_forced_aligner");
}
return model_assets.embedded_aligner;
}
Expand Down
3 changes: 2 additions & 1 deletion src/community_models/piper_tts/session.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "engine/community_models/piper_tts/session.h"

#include "engine/framework/debug/profiler.h"
#include "engine/framework/io/filesystem.h"
#include "engine/framework/runtime/options.h"
#include "engine/framework/runtime/spec_backed_model.h"
#include "engine/framework/text/chunking.h"
Expand Down Expand Up @@ -40,7 +41,7 @@ std::filesystem::path session_path(
const auto found = options.options.find(key);
return found == options.options.end()
? std::filesystem::path{}
: std::filesystem::path(found->second);
: engine::io::path_from_utf8(found->second);
}

void validate_session_options(
Expand Down
3 changes: 2 additions & 1 deletion src/community_models/sanotts/session.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "engine/community_models/sanotts/session.h"

#include "engine/framework/debug/profiler.h"
#include "engine/framework/io/filesystem.h"
#include "engine/framework/runtime/options.h"
#include "engine/framework/runtime/spec_backed_model.h"

Expand Down Expand Up @@ -40,7 +41,7 @@ std::filesystem::path session_path(
const auto found = options.options.find(key);
return found == options.options.end()
? std::filesystem::path{}
: std::filesystem::path(found->second);
: engine::io::path_from_utf8(found->second);
}

void validate_session_options(
Expand Down
3 changes: 2 additions & 1 deletion src/community_models/sense_asr/assets.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "engine/community_models/sense_asr/assets.h"

#include "engine/framework/assets/tensor_source.h"
#include "engine/framework/io/filesystem.h"
#include "engine/framework/model_spec/package.h"

#include <gguf.h>
Expand Down Expand Up @@ -33,7 +34,7 @@ class GgufMetadataReader {
gguf_init_params params{};
params.no_alloc = false;
params.ctx = nullptr;
gguf_context *gguf = gguf_init_from_file(path.string().c_str(), params);
gguf_context *gguf = gguf_init_from_file(engine::io::path_to_utf8(path).c_str(), params);
if (gguf == nullptr) {
throw std::runtime_error(
"SenseVoice failed to open GGUF metadata at " + path.string());
Expand Down
3 changes: 2 additions & 1 deletion src/community_models/vibeasr/assets.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "engine/community_models/vibeasr/assets.h"

#include "engine/framework/io/filesystem.h"
#include "engine/framework/model_spec/package.h"

#include <gguf.h>
Expand Down Expand Up @@ -127,7 +128,7 @@ class GgufMetadataReader {
gguf_init_params params{};
params.no_alloc = true;
params.ctx = nullptr;
gguf_context * gguf = gguf_init_from_file(path.string().c_str(), params);
gguf_context * gguf = gguf_init_from_file(engine::io::path_to_utf8(path).c_str(), params);
if (gguf == nullptr) {
throw std::runtime_error("Failed to read VibeASR GGUF metadata from " + path.string());
}
Expand Down
3 changes: 2 additions & 1 deletion src/community_models/vieneu_v3_turbo/session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "engine/community_models/vieneu_v3_turbo/orchestration.h"

#include "engine/framework/debug/profiler.h"
#include "engine/framework/io/filesystem.h"
#include "engine/framework/runtime/options.h"
#include "engine/framework/text/chunking.h"

Expand Down Expand Up @@ -36,7 +37,7 @@ std::filesystem::path option_path(
const std::unordered_map<std::string, std::string> & options,
std::initializer_list<std::string_view> keys) {
if (const auto value = runtime::find_option(options, keys)) {
return std::filesystem::path(*value);
return engine::io::path_from_utf8(*value);
}
return {};
}
Expand Down
4 changes: 2 additions & 2 deletions src/framework/assets/resource_bundle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ void ResourceBundle::add_file(std::string id, const std::filesystem::path & path
throw std::runtime_error("asset resource id must not be empty");
}
if (!engine::io::is_existing_file(path)) {
throw std::runtime_error("asset resource file does not exist: " + path.string());
throw std::runtime_error("asset resource file does not exist: " + engine::io::path_to_utf8(path));
}
auto [it, inserted] = files_.emplace(std::move(id), std::filesystem::weakly_canonical(path));
if (!inserted) {
Expand Down Expand Up @@ -138,7 +138,7 @@ std::shared_ptr<const TensorSource> ResourceBundle::open_tensor_source(std::stri
const auto path = resource == tensor_resources_.end()
? require_file(id)
: resource->second.path;
const auto path_key = std::filesystem::weakly_canonical(path).generic_string();
const auto path_key = std::filesystem::weakly_canonical(path).generic_u8string();
auto base = tensor_sources_by_path_.find(path_key);
if (base == tensor_sources_by_path_.end()) {
base = tensor_sources_by_path_.emplace(
Expand Down
Loading
Loading