mirror of
https://github.com/mudler/LocalAI.git
synced 2026-10-02 19:14:38 -04:00
fix(huggingface): list repos nested more than one directory deep (#12355)
The HuggingFace tree API returns each entry's path relative to the repo
root ("assets/plots", not "plots"). The recursive listing prefixed the
parent directory again, so it requested "assets/assets/plots", got a
404, and failed the whole listing. The importer then treated the URI as
a non-HF repo and no importer matched.
This broke the import of GGUF repos that keep per-quant subfolders next
to a nested assets tree, such as
ISTA-DASLab/Qwen3.8-Flash-Next-GSQ-RCO-GGUF.
The test mock now returns root-relative directory paths like the real
API and routes on the exact tree path, so a doubled path 404s.
Assisted-by: Claude:claude-opus-5-5 [Claude Code]
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
1 parent
2fe459ca5f
commit
b700da3eb3
2 files changed
+19
-17
No files matched your search
@@ -304,14 +304,12 @@ func (c *Client) listFilesInPath(repoID, path string) ([]FileInfo, error) {
|
||||
switch item.Type {
|
||||
// If it's a directory/folder, recursively list its contents
|
||||
case "directory", "folder":
|
||||
// Build the subfolder path
|
||||
// The tree API returns every entry's path relative to the repo
|
||||
// root ("assets/plots", not "plots"), so it is already the path
|
||||
// to recurse into. Prefixing the parent again requested
|
||||
// "assets/assets/plots", which 404s and failed the whole listing
|
||||
// for any repo nested more than one directory deep.
|
||||
subPath := item.Path
|
||||
if path != "" {
|
||||
subPath = fmt.Sprintf("%s/%s", path, item.Path)
|
||||
}
|
||||
|
||||
// Recursively get files from subfolder
|
||||
// The recursive call will already prepend the subPath to each file's path
|
||||
subFiles, err := c.listFilesInPath(repoID, subPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list files in subfolder %s: %w", subPath, err)
|
||||
@@ -319,10 +317,6 @@ func (c *Client) listFilesInPath(repoID, path string) ([]FileInfo, error) {
|
||||
|
||||
allFiles = append(allFiles, subFiles...)
|
||||
case "file":
|
||||
// It's a file, prepend the current path to make it relative to root
|
||||
// if path != "" {
|
||||
// item.Path = fmt.Sprintf("%s/%s", path, item.Path)
|
||||
// }
|
||||
allFiles = append(allFiles, item)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,7 +459,7 @@ var _ = Describe("HuggingFace API Client", func() {
|
||||
},
|
||||
{
|
||||
"type": "directory",
|
||||
"path": "nested",
|
||||
"path": "subfolder/nested",
|
||||
"size": 0,
|
||||
"oid": "nesteddir123"
|
||||
}
|
||||
@@ -483,15 +483,23 @@ var _ = Describe("HuggingFace API Client", func() {
|
||||
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
urlPath := r.URL.Path
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
if strings.Contains(urlPath, "/tree/main/subfolder/nested") {
|
||||
// Route on the exact tree path: the real API 404s on a wrong
|
||||
// path, and nested entries carry root-relative paths
|
||||
// ("subfolder/nested"), so a prefix match would hide a
|
||||
// doubled "subfolder/subfolder/nested" request.
|
||||
_, treePath, _ := strings.Cut(urlPath, "/tree/main")
|
||||
switch treePath {
|
||||
case "/subfolder/nested":
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(mockNestedResponse))
|
||||
} else if strings.Contains(urlPath, "/tree/main/subfolder") {
|
||||
case "/subfolder":
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(mockSubfolderResponse))
|
||||
} else if strings.Contains(urlPath, "/tree/main") {
|
||||
case "":
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(mockRootResponse))
|
||||
} else {
|
||||
default:
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
}
|
||||
}))
|
||||
|
||||
Reference in new issue
Block a user