Spaces:
Running
on
Zero
Running
on
Zero
Gamahea
commited on
Commit
·
f65e448
1
Parent(s):
2f0c8b4
Fix LoRA import - Handle ZIP files with metadata at root level
Browse files- Support two ZIP structures:
1. metadata.json at root (direct export from training)
2. metadata.json in subfolder (exported via download button)
- Read lora_name from metadata.json when at root level
- Better logging for import process
- Handle duplicate names with timestamp suffix
- Improved error message when no valid LoRA found
Fixes: 'No valid LoRA adapter found in zip file' when uploading
trained LoRAs with metadata.json at root
backend/services/lora_training_service.py
CHANGED
|
@@ -669,16 +669,28 @@ class LoRATrainingService:
|
|
| 669 |
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
| 670 |
zip_ref.extractall(temp_dir)
|
| 671 |
|
| 672 |
-
# Find the LoRA folder (should have metadata.json)
|
| 673 |
temp_path = Path(temp_dir)
|
| 674 |
-
lora_folders = [d for d in temp_path.iterdir() if d.is_dir() and (d / "metadata.json").exists()]
|
| 675 |
|
| 676 |
-
if
|
| 677 |
-
|
| 678 |
-
|
| 679 |
-
|
| 680 |
-
|
| 681 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 682 |
|
| 683 |
# Copy to loras directory
|
| 684 |
dest_path = self.lora_dir / lora_name
|
|
@@ -686,14 +698,24 @@ class LoRATrainingService:
|
|
| 686 |
# If already exists, rename with timestamp
|
| 687 |
if dest_path.exists():
|
| 688 |
timestamp = int(time.time())
|
|
|
|
| 689 |
lora_name = f"{lora_name}_{timestamp}"
|
| 690 |
dest_path = self.lora_dir / lora_name
|
|
|
|
|
|
|
|
|
|
|
|
|
| 691 |
|
| 692 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 693 |
|
| 694 |
-
logger.info(f"Imported LoRA adapter: {lora_name}")
|
| 695 |
return lora_name
|
| 696 |
|
| 697 |
except Exception as e:
|
| 698 |
-
logger.error(f"Failed to import LoRA adapter: {str(e)}")
|
| 699 |
return None
|
|
|
|
| 669 |
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
| 670 |
zip_ref.extractall(temp_dir)
|
| 671 |
|
|
|
|
| 672 |
temp_path = Path(temp_dir)
|
|
|
|
| 673 |
|
| 674 |
+
# Case 1: Check if metadata.json is at root level
|
| 675 |
+
if (temp_path / "metadata.json").exists():
|
| 676 |
+
logger.info("Found metadata.json at root level")
|
| 677 |
+
source_dir = temp_path
|
| 678 |
+
|
| 679 |
+
# Read metadata to get LoRA name
|
| 680 |
+
with open(temp_path / "metadata.json", 'r') as f:
|
| 681 |
+
metadata = json.load(f)
|
| 682 |
+
lora_name = metadata.get('lora_name', 'imported_lora')
|
| 683 |
+
else:
|
| 684 |
+
# Case 2: Look for a subfolder with metadata.json
|
| 685 |
+
lora_folders = [d for d in temp_path.iterdir() if d.is_dir() and (d / "metadata.json").exists()]
|
| 686 |
+
|
| 687 |
+
if not lora_folders:
|
| 688 |
+
logger.error("No valid LoRA adapter found in zip file. Expected metadata.json at root or in a subfolder.")
|
| 689 |
+
return None
|
| 690 |
+
|
| 691 |
+
source_dir = lora_folders[0]
|
| 692 |
+
lora_name = source_dir.name
|
| 693 |
+
logger.info(f"Found LoRA in subfolder: {lora_name}")
|
| 694 |
|
| 695 |
# Copy to loras directory
|
| 696 |
dest_path = self.lora_dir / lora_name
|
|
|
|
| 698 |
# If already exists, rename with timestamp
|
| 699 |
if dest_path.exists():
|
| 700 |
timestamp = int(time.time())
|
| 701 |
+
original_name = lora_name
|
| 702 |
lora_name = f"{lora_name}_{timestamp}"
|
| 703 |
dest_path = self.lora_dir / lora_name
|
| 704 |
+
logger.info(f"LoRA '{original_name}' already exists, importing as '{lora_name}'")
|
| 705 |
+
|
| 706 |
+
# Create destination directory
|
| 707 |
+
dest_path.mkdir(parents=True, exist_ok=True)
|
| 708 |
|
| 709 |
+
# Copy all files from source to destination
|
| 710 |
+
for item in source_dir.iterdir():
|
| 711 |
+
if item.is_file():
|
| 712 |
+
shutil.copy2(item, dest_path / item.name)
|
| 713 |
+
elif item.is_dir():
|
| 714 |
+
shutil.copytree(item, dest_path / item.name)
|
| 715 |
|
| 716 |
+
logger.info(f"✅ Imported LoRA adapter: {lora_name}")
|
| 717 |
return lora_name
|
| 718 |
|
| 719 |
except Exception as e:
|
| 720 |
+
logger.error(f"Failed to import LoRA adapter: {str(e)}", exc_info=True)
|
| 721 |
return None
|