Skip to content

chore: make path resolution more flexible - #32

Open
Tohrusky wants to merge 1 commit into
nihui:masterfrom
EutropicAI:master
Open

chore: make path resolution more flexible#32
Tohrusky wants to merge 1 commit into
nihui:masterfrom
EutropicAI:master

Conversation

@Tohrusky

Copy link
Copy Markdown

No description provided.

@Tohrusky

Copy link
Copy Markdown
Author

@nihui hi there~

We have developed a convenient frontend based on this repository. https://github.com/EutropicAI/FinalDream

To better support the distribution of downstream application models, we need some upstream improvements regarding path handling.

This PR enables more flexible path resolution, ensuring the application works out-of-the-box in different directory structures.

Could you please take a look? We hope this can be merged or implemented similarly. Thanks~

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request refactors path resolution for model files by introducing a new resolve_path helper function that searches for files by keyword rather than using hardcoded full paths. The goal is to make path resolution more flexible and support different directory structures.

Changes:

  • Added resolve_path function that searches directories for files matching a keyword, with optional fallback directory support
  • Replaced hardcoded model file paths with dynamic path resolution using keyword matching
  • Removed model variant detection logic (z-image vs z-image-turbo) from individual component loaders
Comments suppressed due to low confidence (9)

src/zimage.cpp:536

  • CapEmbedder::load should check if resolve_path returns valid (non-empty) paths before calling load_param and load_model. If resolve_path fails, the function should return an error code instead of returning 0 (success). Currently, it will attempt to load from empty paths and potentially fail silently or crash.
    path_t parampath = resolve_path(model, PATHSTR("transformer_cap_embedder.ncnn.param"));
    path_t modelpath = resolve_path(model, PATHSTR("transformer_cap_embedder.ncnn.bin"));

    cap_embedder.opt = opt;
    cap_embedder.load_param(parampath.c_str());
    cap_embedder.load_model(modelpath.c_str());

    return 0;

src/zimage.cpp:559

  • ContextRefiner::load should check if resolve_path returns valid (non-empty) paths before calling load_param and load_model. If resolve_path fails, the function should return an error code instead of returning 0 (success). Currently, it will attempt to load from empty paths and potentially fail silently or crash.
    path_t parampath = resolve_path(model, PATHSTR("transformer_context_refiner.ncnn.param"));
    path_t modelpath = resolve_path(model, PATHSTR("transformer_context_refiner.ncnn.bin"));

    context_refiner.opt = opt;
    context_refiner.load_param(parampath.c_str());
    context_refiner.load_model(modelpath.c_str());

    return 0;

src/zimage.cpp:617

  • AllXEmbedder::load should check if resolve_path returns valid (non-empty) paths before calling load_param and load_model. If resolve_path fails, the function should return an error code instead of returning 0 (success). Currently, it will attempt to load from empty paths and potentially fail silently or crash.
    path_t parampath = resolve_path(model, PATHSTR("transformer_all_x_embedder.ncnn.param"));
    path_t modelpath = resolve_path(model, PATHSTR("transformer_all_x_embedder.ncnn.bin"));

    all_x_embedder.opt = opt;
    all_x_embedder.load_param(parampath.c_str());
    all_x_embedder.load_model(modelpath.c_str());

    return 0;

src/zimage.cpp:640

  • NoiseRefiner::load should check if resolve_path returns valid (non-empty) paths before calling load_param and load_model. If resolve_path fails, the function should return an error code instead of returning 0 (success). Currently, it will attempt to load from empty paths and potentially fail silently or crash.
    path_t parampath = resolve_path(model, PATHSTR("transformer_noise_refiner.ncnn.param"));
    path_t modelpath = resolve_path(model, PATHSTR("transformer_noise_refiner.ncnn.bin"));

    noise_refiner.opt = opt;
    noise_refiner.load_param(parampath.c_str());
    noise_refiner.load_model(modelpath.c_str());

    return 0;

src/zimage.cpp:666

  • UnifiedRefiner::load should check if resolve_path returns valid (non-empty) paths before calling load_param and load_model. If resolve_path fails, the function should return an error code instead of returning 0 (success). Currently, it will attempt to load from empty paths and potentially fail silently or crash.
    path_t parampath = resolve_path(model, PATHSTR("transformer_unified.ncnn.param"));
    path_t modelpath = resolve_path(model, PATHSTR("transformer_unified.ncnn.bin"));

    unified_refiner.opt = opt;
    unified_refiner.load_param(parampath.c_str());
    unified_refiner.load_model(modelpath.c_str());

    return 0;

src/zimage.cpp:956

  • VAE::load should check if resolve_path returns valid (non-empty) paths before calling load_param and load_model. If resolve_path fails, the function should return an error code instead of returning 0 (success). Currently, it will attempt to load from empty paths and potentially fail silently or crash.
    path_t parampath = resolve_path(model, PATHSTR("vae.ncnn.param"), PATHSTR("/../z-image-turbo"));
    path_t modelpath = resolve_path(model, PATHSTR("vae.ncnn.bin"), PATHSTR("/../z-image-turbo"));

    vae.opt = opt;
    if (use_vae_tiled)
    {
        vae.register_custom_layer("GroupNorm", VAETiledGroupNorm_layer_creator);
    }
    vae.load_param(parampath.c_str());
    vae.load_model(modelpath.c_str());

src/zimage.cpp:458

  • TextEncoder::load should check if resolve_path returns valid (non-empty) paths before calling load_param and load_model. If resolve_path fails, the function should return an error code instead of returning 0 (success). Currently, it will attempt to load from empty paths and potentially fail silently or crash.
    path_t parampath = resolve_path(model, PATHSTR("text_encoder.ncnn.param"), PATHSTR("/../z-image-turbo"));
    path_t modelpath = resolve_path(model, PATHSTR("text_encoder.ncnn.bin"), PATHSTR("/../z-image-turbo"));

    text_encoder.opt = opt;
    text_encoder.load_param(parampath.c_str());
    text_encoder.load_model(modelpath.c_str());

    return 0;

src/zimage.cpp:692

  • AllFinalLayer::load should check if resolve_path returns valid (non-empty) paths before calling load_param and load_model. If resolve_path fails, the function should return an error code instead of returning 0 (success). Currently, it will attempt to load from empty paths and potentially fail silently or crash.
    path_t parampath = resolve_path(model, PATHSTR("transformer_all_final_layer.ncnn.param"));
    path_t modelpath = resolve_path(model, PATHSTR("transformer_all_final_layer.ncnn.bin"));

    all_final_layer.opt = opt;
    all_final_layer.load_param(parampath.c_str());
    all_final_layer.load_model(modelpath.c_str());

    return 0;

src/zimage.cpp:584

  • TEmbedder::load should check if resolve_path returns valid (non-empty) paths before calling load_param and load_model. If resolve_path fails, the function should return an error code instead of returning 0 (success). Currently, it will attempt to load from empty paths and potentially fail silently or crash.
    path_t parampath = resolve_path(model, PATHSTR("transformer_t_embedder.ncnn.param"));
    path_t modelpath = resolve_path(model, PATHSTR("transformer_t_embedder.ncnn.bin"));

    t_embedder.opt = opt;
    t_embedder.load_param(parampath.c_str());
    t_embedder.load_model(modelpath.c_str());

    return 0;

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/zimage.cpp
Comment on lines +529 to +530
path_t parampath = resolve_path(model, PATHSTR("transformer_cap_embedder.ncnn.param"));
path_t modelpath = resolve_path(model, PATHSTR("transformer_cap_embedder.ncnn.bin"));

Copilot AI Feb 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old code explicitly selected different model files based on whether the model path contained "z-image-turbo" or "z-image". The new code uses substring matching which will select the first alphabetically matching file. If both z_image_transformer_cap_embedder.ncnn.param and z_image_turbo_transformer_cap_embedder.ncnn.param exist in the same directory, this will consistently pick the non-turbo variant regardless of the intended model type. This breaks the model-specific file selection logic and could lead to incorrect model loading.

Copilot uses AI. Check for mistakes.
Comment thread src/zimage.cpp
Comment on lines +633 to 635
path_t parampath = resolve_path(model, PATHSTR("transformer_noise_refiner.ncnn.param"));
path_t modelpath = resolve_path(model, PATHSTR("transformer_noise_refiner.ncnn.bin"));

Copilot AI Feb 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old code explicitly selected different model files based on whether the model path contained "z-image-turbo" or "z-image". The new code uses substring matching which will select the first alphabetically matching file. If both z_image_transformer_noise_refiner.ncnn.param and z_image_turbo_transformer_noise_refiner.ncnn.param exist in the same directory, this will consistently pick the non-turbo variant regardless of the intended model type. This breaks the model-specific file selection logic and could lead to incorrect model loading.

Suggested change
path_t parampath = resolve_path(model, PATHSTR("transformer_noise_refiner.ncnn.param"));
path_t modelpath = resolve_path(model, PATHSTR("transformer_noise_refiner.ncnn.bin"));
// Select the correct noise refiner model variant (turbo vs non-turbo)
// based on the model path, to avoid ambiguous substring matching in
// resolve_path when multiple variants are present in the same directory.
path_t param_filename;
path_t model_filename;
if (model.find(PATHSTR("z-image-turbo")) != path_t::npos)
{
param_filename = PATHSTR("z_image_turbo_transformer_noise_refiner.ncnn.param");
model_filename = PATHSTR("z_image_turbo_transformer_noise_refiner.ncnn.bin");
}
else
{
param_filename = PATHSTR("z_image_transformer_noise_refiner.ncnn.param");
model_filename = PATHSTR("z_image_transformer_noise_refiner.ncnn.bin");
}
path_t parampath = resolve_path(model, param_filename);
path_t modelpath = resolve_path(model, model_filename);

Copilot uses AI. Check for mistakes.
Comment thread src/zimage.cpp
fprintf(stderr, "resolve_path failed: %s\n", search_keyword.c_str());
#endif

return path_t();

Copilot AI Feb 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing whitespace detected at the end of the line. Remove the trailing space after path_t() for code cleanliness.

Suggested change
return path_t();
return path_t();

Copilot uses AI. Check for mistakes.
Comment thread src/zimage.cpp
Comment on lines +577 to +578
path_t parampath = resolve_path(model, PATHSTR("transformer_t_embedder.ncnn.param"));
path_t modelpath = resolve_path(model, PATHSTR("transformer_t_embedder.ncnn.bin"));

Copilot AI Feb 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old code explicitly selected different model files based on whether the model path contained "z-image-turbo" or "z-image". The new code uses substring matching which will select the first alphabetically matching file. If both z_image_transformer_t_embedder.ncnn.param and z_image_turbo_transformer_t_embedder.ncnn.param exist in the same directory, this will consistently pick the non-turbo variant regardless of the intended model type. This breaks the model-specific file selection logic and could lead to incorrect model loading.

Copilot uses AI. Check for mistakes.
Comment thread src/zimage.cpp
fprintf(stderr, "resolve_path failed: %s\n", search_keyword.c_str());
#endif

return path_t();

Copilot AI Feb 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning an empty path_t() on failure will cause BpeTokenizer::LoadFromFiles and ncnn load methods to fail or crash with an empty path. The function should either throw an exception, return an error code, or use a different mechanism to signal failure. Consider using std::optional<path_t> or checking for empty paths at call sites before using them.

Copilot uses AI. Check for mistakes.
Comment thread src/zimage.cpp
Comment on lines +552 to +553
path_t parampath = resolve_path(model, PATHSTR("transformer_context_refiner.ncnn.param"));
path_t modelpath = resolve_path(model, PATHSTR("transformer_context_refiner.ncnn.bin"));

Copilot AI Feb 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old code explicitly selected different model files based on whether the model path contained "z-image-turbo" or "z-image". The new code uses substring matching which will select the first alphabetically matching file. If both z_image_transformer_context_refiner.ncnn.param and z_image_turbo_transformer_context_refiner.ncnn.param exist in the same directory, this will consistently pick the non-turbo variant regardless of the intended model type. This breaks the model-specific file selection logic and could lead to incorrect model loading.

Copilot uses AI. Check for mistakes.
Comment thread src/zimage.cpp
Comment on lines +659 to 661
path_t parampath = resolve_path(model, PATHSTR("transformer_unified.ncnn.param"));
path_t modelpath = resolve_path(model, PATHSTR("transformer_unified.ncnn.bin"));

Copilot AI Feb 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old code explicitly selected different model files based on whether the model path contained "z-image-turbo" or "z-image". The new code uses substring matching which will select the first alphabetically matching file. If both z_image_transformer_unified.ncnn.param and z_image_turbo_transformer_unified.ncnn.param exist in the same directory, this will consistently pick the non-turbo variant regardless of the intended model type. This breaks the model-specific file selection logic and could lead to incorrect model loading.

Suggested change
path_t parampath = resolve_path(model, PATHSTR("transformer_unified.ncnn.param"));
path_t modelpath = resolve_path(model, PATHSTR("transformer_unified.ncnn.bin"));
path_t param_filename;
path_t model_filename;
if (model.find(PATHSTR("z-image-turbo")) != path_t::npos)
{
// Turbo variant unified transformer
param_filename = PATHSTR("z_image_turbo_transformer_unified.ncnn.param");
model_filename = PATHSTR("z_image_turbo_transformer_unified.ncnn.bin");
}
else if (model.find(PATHSTR("z-image")) != path_t::npos)
{
// Non-turbo z-image unified transformer
param_filename = PATHSTR("z_image_transformer_unified.ncnn.param");
model_filename = PATHSTR("z_image_transformer_unified.ncnn.bin");
}
else
{
// Fallback to generic unified transformer filenames
param_filename = PATHSTR("transformer_unified.ncnn.param");
model_filename = PATHSTR("transformer_unified.ncnn.bin");
}
path_t parampath = resolve_path(model, param_filename);
path_t modelpath = resolve_path(model, model_filename);

Copilot uses AI. Check for mistakes.
Comment thread src/zimage.cpp
Comment on lines +610 to 612
path_t parampath = resolve_path(model, PATHSTR("transformer_all_x_embedder.ncnn.param"));
path_t modelpath = resolve_path(model, PATHSTR("transformer_all_x_embedder.ncnn.bin"));

Copilot AI Feb 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old code explicitly selected different model files based on whether the model path contained "z-image-turbo" or "z-image". The new code uses substring matching which will select the first alphabetically matching file. If both z_image_transformer_all_x_embedder.ncnn.param and z_image_turbo_transformer_all_x_embedder.ncnn.param exist in the same directory, this will consistently pick the non-turbo variant regardless of the intended model type. This breaks the model-specific file selection logic and could lead to incorrect model loading.

Suggested change
path_t parampath = resolve_path(model, PATHSTR("transformer_all_x_embedder.ncnn.param"));
path_t modelpath = resolve_path(model, PATHSTR("transformer_all_x_embedder.ncnn.bin"));
// Select the correct model variant (turbo vs non-turbo) based on the model path.
const path_t turbo_marker = PATHSTR("z-image-turbo");
const bool is_turbo = model.find(turbo_marker) != path_t::npos;
const path_t param_name = is_turbo
? PATHSTR("turbo_transformer_all_x_embedder.ncnn.param")
: PATHSTR("transformer_all_x_embedder.ncnn.param");
const path_t model_name = is_turbo
? PATHSTR("turbo_transformer_all_x_embedder.ncnn.bin")
: PATHSTR("transformer_all_x_embedder.ncnn.bin");
path_t parampath = resolve_path(model, param_name);
path_t modelpath = resolve_path(model, model_name);

Copilot uses AI. Check for mistakes.
Comment thread src/zimage.cpp
Comment on lines +685 to 687
path_t parampath = resolve_path(model, PATHSTR("transformer_all_final_layer.ncnn.param"));
path_t modelpath = resolve_path(model, PATHSTR("transformer_all_final_layer.ncnn.bin"));

Copilot AI Feb 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old code explicitly selected different model files based on whether the model path contained "z-image-turbo" or "z-image". The new code uses substring matching which will select the first alphabetically matching file. If both z_image_transformer_all_final_layer.ncnn.param and z_image_turbo_transformer_all_final_layer.ncnn.param exist in the same directory, this will consistently pick the non-turbo variant regardless of the intended model type. This breaks the model-specific file selection logic and could lead to incorrect model loading.

Suggested change
path_t parampath = resolve_path(model, PATHSTR("transformer_all_final_layer.ncnn.param"));
path_t modelpath = resolve_path(model, PATHSTR("transformer_all_final_layer.ncnn.bin"));
// Select the correct all-final-layer model variant explicitly based on the model path,
// to avoid ambiguous substring matching inside resolve_path.
path_t param_filename;
path_t bin_filename;
if (model.find(PATHSTR("z-image-turbo")) != path_t::npos)
{
// Turbo variant
param_filename = PATHSTR("z_image_turbo_transformer_all_final_layer.ncnn.param");
bin_filename = PATHSTR("z_image_turbo_transformer_all_final_layer.ncnn.bin");
}
else if (model.find(PATHSTR("z-image")) != path_t::npos)
{
// Non-turbo z-image variant
param_filename = PATHSTR("z_image_transformer_all_final_layer.ncnn.param");
bin_filename = PATHSTR("z_image_transformer_all_final_layer.ncnn.bin");
}
else
{
// Fallback to the generic filenames used previously
param_filename = PATHSTR("transformer_all_final_layer.ncnn.param");
bin_filename = PATHSTR("transformer_all_final_layer.ncnn.bin");
}
path_t parampath = resolve_path(model, param_filename);
path_t modelpath = resolve_path(model, bin_filename);

Copilot uses AI. Check for mistakes.
Comment thread src/zimage.cpp

if (!fallback_dir.empty())
{
path_t parent = root + fallback_dir;

Copilot AI Feb 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The filenames vector is reused for both the root directory search and the fallback directory search without being cleared. If the first list_directory succeeds but doesn't find a match, filenames will contain stale entries when searching the fallback directory. This could lead to incorrect path resolution. The vector should be cleared before the second list_directory call or a fresh vector should be used.

Suggested change
path_t parent = root + fallback_dir;
path_t parent = root + fallback_dir;
filenames.clear();

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants