Enhance recipe metadata handling in RecipeRoutes and ExifUtils

- Added functionality to extract and process existing recipe metadata from images, including LoRA details and Civitai information.
- Updated ExifUtils to manage recipe metadata more effectively, including appending and removing metadata from user comments.
- Improved the ImportManager to utilize recipe metadata for setting default recipe names and tags when importing shared recipes.
This commit is contained in:
Will Miao
2025-03-18 16:49:04 +08:00
parent 78f8d4ecc7
commit 4264dd19a8
3 changed files with 167 additions and 34 deletions

View File

@@ -220,7 +220,85 @@ class RecipeRoutes:
"loras": [] # Return empty loras array to prevent client-side errors
}, status=200) # Return 200 instead of 400 to handle gracefully
# Parse the recipe metadata
# First, check if this image has recipe metadata from a previous share
recipe_metadata = ExifUtils.extract_recipe_metadata(user_comment)
if recipe_metadata:
logger.info("Found existing recipe metadata in image")
# Process the recipe metadata
loras = []
for lora in recipe_metadata.get('loras', []):
# Convert recipe lora format to frontend format
lora_entry = {
'id': lora.get('modelVersionId', ''),
'name': lora.get('modelName', ''),
'version': lora.get('modelVersionName', ''),
'type': 'lora',
'weight': lora.get('strength', 1.0),
'file_name': lora.get('file_name', ''),
'hash': lora.get('hash', '')
}
# Check if this LoRA exists locally by SHA256 hash
if lora.get('hash'):
exists_locally = self.recipe_scanner._lora_scanner.has_lora_hash(lora['hash'])
if exists_locally:
lora_entry['existsLocally'] = True
lora_cache = await self.recipe_scanner._lora_scanner.get_cached_data()
lora_item = next((item for item in lora_cache.raw_data if item['sha256'] == lora['hash']), None)
if lora_item:
lora_entry['localPath'] = lora_item['file_path']
lora_entry['file_name'] = lora_item['file_name']
lora_entry['size'] = lora_item['size']
lora_entry['thumbnailUrl'] = config.get_preview_static_url(lora_item['preview_url'])
else:
lora_entry['existsLocally'] = False
lora_entry['localPath'] = None
# Try to get additional info from Civitai if we have a model version ID
if lora.get('modelVersionId'):
try:
civitai_info = await self.civitai_client.get_model_version_info(lora['modelVersionId'])
if civitai_info and civitai_info.get("error") != "Model not found":
# Get thumbnail URL from first image
if 'images' in civitai_info and civitai_info['images']:
lora_entry['thumbnailUrl'] = civitai_info['images'][0].get('url', '')
# Get base model
lora_entry['baseModel'] = civitai_info.get('baseModel', '')
# Get download URL
lora_entry['downloadUrl'] = civitai_info.get('downloadUrl', '')
# Get size from files if available
if 'files' in civitai_info:
model_file = next((file for file in civitai_info.get('files', [])
if file.get('type') == 'Model'), None)
if model_file:
lora_entry['size'] = model_file.get('sizeKB', 0) * 1024
else:
lora_entry['isDeleted'] = True
lora_entry['thumbnailUrl'] = '/loras_static/images/no-preview.png'
except Exception as e:
logger.error(f"Error fetching Civitai info for LoRA: {e}")
lora_entry['thumbnailUrl'] = '/loras_static/images/no-preview.png'
loras.append(lora_entry)
logger.info(f"Found {len(loras)} loras in recipe metadata")
return web.json_response({
'base_model': recipe_metadata.get('base_model', ''),
'loras': loras,
'gen_params': recipe_metadata.get('gen_params', {}),
'tags': recipe_metadata.get('tags', []),
'title': recipe_metadata.get('title', ''),
'from_recipe_metadata': True
})
# If no recipe metadata, parse the standard metadata
metadata = ExifUtils.parse_recipe_metadata(user_comment)
# Look for Civitai resources in the metadata
@@ -233,10 +311,6 @@ class RecipeRoutes:
"loras": [] # Return empty loras array
}, status=200) # Return 200 instead of 400
# Process the resources to get LoRA information
loras = []
base_model = None
# Process LoRAs and collect base models
base_model_counts = {}
loras = []
@@ -248,9 +322,6 @@ class RecipeRoutes:
if not model_version_id:
continue
# Get additional info from Civitai
civitai_info = await self.civitai_client.get_model_version_info(model_version_id)
# Initialize lora entry with default values
lora_entry = {
'id': model_version_id,
@@ -269,6 +340,9 @@ class RecipeRoutes:
'isDeleted': False # New flag to indicate if the LoRA is deleted from Civitai
}
# Get additional info from Civitai
civitai_info = await self.civitai_client.get_model_version_info(model_version_id)
# Check if this LoRA exists locally by SHA256 hash
if civitai_info and civitai_info.get("error") != "Model not found":
# LoRA exists on Civitai, process its information
@@ -314,6 +388,7 @@ class RecipeRoutes:
loras.append(lora_entry)
# Set base_model to the most common one from civitai_info
base_model = None
if base_model_counts:
base_model = max(base_model_counts.items(), key=lambda x: x[1])[0]
@@ -641,7 +716,6 @@ class RecipeRoutes:
# Create a URL for the processed image
# Use a timestamp to prevent caching
timestamp = int(time.time())
filename = os.path.basename(processed_path)
url_path = f"/api/recipe/{recipe_id}/share/download?t={timestamp}"
# Store the temp path in a dictionary to serve later