#!/usr/bin/env python3 """ Deployment-Script für trainierte LoRA-Modelle Automatisiert den Upload zu Hugging Face Hub """ import os import shutil from pathlib import Path import subprocess import json import logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) class LoRADeployer: def __init__(self, model_path="../models/lora-checkpoint"): self.model_path = Path(model_path) self.hf_username = None # Wird aus HF_USERNAME env var gelesen def verify_model(self): """Prüft ob trainiertes LoRA-Modell vollständig ist""" required_files = [ "adapter_config.json", "adapter_model.bin", # oder adapter_model.safetensors "README.md" ] missing_files = [] for file in required_files: if not (self.model_path / file).exists(): missing_files.append(file) if missing_files: logger.error(f"Fehlende Dateien: {missing_files}") return False logger.info("✅ LoRA-Modell vollständig") return True def create_model_card(self): """Erstellt eine Model Card für Hugging Face""" model_card = f"""--- library_name: peft base_model: teknium/OpenHermes-2.5-Mistral-7B tags: - generated_from_trainer - horoscope - astrology - german - lora language: - de - en license: apache-2.0 --- # LoRA Adapter für Horoskop-Generierung Dieses LoRA-Adapter wurde für die Generierung von personalisierten Horoskopen trainiert. ## Basis-Modell - **Model**: teknium/OpenHermes-2.5-Mistral-7B - **LoRA Rank**: 16 - **Target Modules**: q_proj, v_proj, k_proj, o_proj ## Verwendung ```python from transformers import AutoTokenizer, AutoModelForCausalLM from peft import PeftModel base_model = "teknium/OpenHermes-2.5-Mistral-7B" tokenizer = AutoTokenizer.from_pretrained(base_model) model = AutoModelForCausalLM.from_pretrained(base_model, load_in_4bit=True) model = PeftModel.from_pretrained(model, "IHR_USERNAME/horoskop-lora") # Beispiel-Prompt prompt = "<|im_start|>system\\nDu bist ein erfahrener Astrologe.<|im_end|>\\n<|im_start|>user\\nErstelle ein Horoskop für Widder heute.<|im_end|>\\n<|im_start|>assistant\\n" ``` ## Training Details - **Training Duration**: {self.get_training_info().get('duration', 'N/A')} - **Dataset Size**: {self.get_training_info().get('dataset_size', 'N/A')} - **Epochs**: {self.get_training_info().get('epochs', 'N/A')} """ readme_path = self.model_path / "README.md" with open(readme_path, 'w', encoding='utf-8') as f: f.write(model_card) logger.info(f"Model Card erstellt: {readme_path}") def get_training_info(self): """Liest Training-Informationen aus logs oder config""" # Placeholder - könnte aus Training-Logs gelesen werden return { "duration": "2-4 Stunden", "dataset_size": "500+ Horoskop-Beispiele", "epochs": "3" } def upload_to_hf(self, repo_name="horoskop-lora"): """Upload zu Hugging Face Hub""" # Hugging Face Username prüfen hf_username = os.getenv("HF_USERNAME") if not hf_username: logger.error("HF_USERNAME environment variable nicht gesetzt") logger.info("Setzen Sie: export HF_USERNAME=ihr_username") return False # Hugging Face CLI prüfen try: subprocess.run(["huggingface-cli", "--version"], check=True, capture_output=True) except subprocess.CalledProcessError: logger.error("Hugging Face CLI nicht installiert") logger.info("Installieren Sie: pip install huggingface_hub") return False # Repository erstellen repo_id = f"{hf_username}/{repo_name}" logger.info(f"Erstelle Repository: {repo_id}") try: # Repository auf HF erstellen cmd = [ "huggingface-cli", "repo", "create", repo_id, "--type", "model", "--private" ] subprocess.run(cmd, check=True) logger.info(f"✅ Repository erstellt: {repo_id}") except subprocess.CalledProcessError as e: if "already exists" in str(e): logger.info(f"Repository existiert bereits: {repo_id}") else: logger.error(f"Repository-Erstellung fehlgeschlagen: {e}") return False # Dateien hochladen try: cmd = [ "huggingface-cli", "upload", repo_id, str(self.model_path), ".", "--recursive" ] subprocess.run(cmd, check=True) logger.info(f"✅ Upload erfolgreich: https://huggingface.co/{repo_id}") return True except subprocess.CalledProcessError as e: logger.error(f"Upload fehlgeschlagen: {e}") return False def prepare_for_space(self): """Bereitet Modell für Hugging Face Space vor""" space_model_path = Path("../models/lora-checkpoint-deployed") space_model_path.mkdir(exist_ok=True) # Kopiere nur notwendige Dateien essential_files = [ "adapter_config.json", "adapter_model.bin", "adapter_model.safetensors" ] for file in essential_files: src = self.model_path / file if src.exists(): dst = space_model_path / file shutil.copy2(src, dst) logger.info(f"Kopiert: {file}") logger.info(f"✅ Space-ready Modell in: {space_model_path}") return space_model_path def main(): """Hauptfunktion für Deployment""" deployer = LoRADeployer() print("🚀 LoRA-Modell Deployment") print("========================") # 1. Modell verifizieren if not deployer.verify_model(): print("❌ Modell-Verifikation fehlgeschlagen") return # 2. Model Card erstellen deployer.create_model_card() # 3. User-Input für Deployment-Optionen print("\n📤 Deployment-Optionen:") print("1. Für Hugging Face Space vorbereiten") print("2. Zu Hugging Face Hub hochladen") print("3. Beides") choice = input("Wählen Sie (1-3): ").strip() if choice in ["1", "3"]: space_path = deployer.prepare_for_space() print(f"✅ Space-ready: {space_path}") if choice in ["2", "3"]: repo_name = input("Repository-Name (Standard: horoskop-lora): ").strip() if not repo_name: repo_name = "horoskop-lora" if deployer.upload_to_hf(repo_name): print("✅ Upload zu Hugging Face erfolgreich!") else: print("❌ Upload fehlgeschlagen") print("\n🎯 Nächste Schritte:") print("1. Aktualisieren Sie config.py mit dem neuen Modell-Pfad") print("2. Testen Sie das Modell lokal") print("3. Deployen Sie zu Hugging Face Space") if __name__ == "__main__": main()