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 not lora_folders:
677
- logger.error("No valid LoRA adapter found in zip file")
678
- return None
679
-
680
- source_dir = lora_folders[0]
681
- lora_name = source_dir.name
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- shutil.copytree(source_dir, dest_path)
 
 
 
 
 
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