Fix/upload base64 (#1492)

This commit is contained in:
Koko-ry
2025-09-08 21:20:24 +08:00
committed by GitHub
parent 4733d5374b
commit a197ab02d0
3 changed files with 78 additions and 19 deletions

View File

@@ -288,7 +288,7 @@ class HubApi:
# Add AIGC-specific fields to body
body.update({
'TagShowName': aigc_model.revision,
'TagShowName': aigc_model.tag,
'CoverImages': aigc_model.cover_images,
'AigcType': aigc_model.aigc_type,
'TagDescription': aigc_model.description,
@@ -315,10 +315,9 @@ class HubApi:
raise_on_error(d)
model_repo_url = f'{endpoint}/models/{model_id}'
# TODO: to be aligned with the new api
# Upload model files for AIGC models
# if aigc_model is not None:
# aigc_model.upload_to_repo(self, model_id, token)
if aigc_model is not None:
aigc_model.upload_to_repo(self, model_id, token)
return model_repo_url

View File

@@ -6,7 +6,8 @@ from typing import List, Optional
import requests
from tqdm.auto import tqdm
from modelscope.hub.utils.utils import MODELSCOPE_URL_SCHEME, get_domain
from modelscope.hub.utils.utils import (MODELSCOPE_URL_SCHEME,
encode_image_to_base64, get_domain)
from modelscope.utils.logger import get_logger
logger = get_logger()
@@ -61,7 +62,7 @@ class AigcModel:
base_model_type: str,
model_path: str,
base_model_id: str = '',
revision: Optional[str] = 'v1.0',
tag: Optional[str] = 'v1.0',
description: Optional[str] = 'this is an aigc model',
cover_images: Optional[List[str]] = None,
path_in_repo: Optional[str] = '',
@@ -73,23 +74,46 @@ class AigcModel:
model_path (str): The path of checkpoint/LoRA weight file or folder.
aigc_type (str): AIGC model type. Recommended: 'Checkpoint', 'LoRA', 'VAE'.
base_model_type (str): Vision foundation model type. Recommended values are in BASE_MODEL_TYPES.
revision (str, optional): Revision for the AIGC model. Defaults to 'v1.0'.
tag (str, optional): Tag for the AIGC model. Defaults to 'v1.0'.
description (str, optional): Model description. Defaults to 'this is an aigc model'.
cover_images (List[str], optional): List of cover image URLs.
base_model_id (str, optional): Base model name. e.g., 'AI-ModelScope/FLUX.1-dev'.
path_in_repo (str, optional): Path in the repository.
trigger_words (List[str], optional): Trigger words for the AIGC Lora model.
Note: Auto-upload during AIGC create is temporarily disabled by server. This parameter
will not take effect at creation time.
"""
self.model_path = model_path
self.aigc_type = aigc_type
self.base_model_type = base_model_type
self.revision = revision
self.tag = tag
self.description = description
self.cover_images = cover_images if cover_images is not None else [
DEFAULT_AIGC_COVER_IMAGE
]
# Process cover images - convert local paths to base64 data URLs
if cover_images is not None:
processed_cover_images = []
for img in cover_images:
if isinstance(img, str):
# Check if it's a local file path (not a URL)
if not (img.startswith('http://')
or img.startswith('https://')
or img.startswith('data:')):
try:
# Convert local path to base64 data URL
processed_img = encode_image_to_base64(img)
processed_cover_images.append(processed_img)
logger.info('Converted local image to base64: %s',
os.path.basename(img))
except (FileNotFoundError, ValueError) as e:
logger.warning(
'Failed to process local image %s: %s. Using as-is.',
img, e)
processed_cover_images.append(img)
else:
# Keep URLs and data URLs as-is
processed_cover_images.append(img)
else:
processed_cover_images.append(img)
self.cover_images = processed_cover_images
else:
self.cover_images = [DEFAULT_AIGC_COVER_IMAGE]
self.base_model_id = base_model_id
self.path_in_repo = path_in_repo
self.trigger_words = trigger_words
@@ -216,7 +240,6 @@ class AigcModel:
# Upload entire folder with path_in_repo support
logger.info('Uploading directory: %s', self.model_path)
api.upload_folder(
revision=self.revision,
repo_id=model_id,
folder_path=self.model_path,
path_in_repo=self.path_in_repo,
@@ -226,7 +249,6 @@ class AigcModel:
# Upload single file, target_file is guaranteed to be set by _process_model_path
logger.info('Uploading file: %s', self.target_file)
api.upload_file(
revision=self.revision,
path_or_fileobj=self.target_file,
path_in_repo=self.path_in_repo + '/' + self.weight_filename
if self.path_in_repo else self.weight_filename,
@@ -313,7 +335,7 @@ class AigcModel:
return {
'aigc_type': self.aigc_type,
'base_model_type': self.base_model_type,
'revision': self.revision,
'tag': self.tag,
'description': self.description,
'cover_images': self.cover_images,
'base_model_id': self.base_model_id,

View File

@@ -5,11 +5,11 @@ import hashlib
import os
import sys
import time
import zoneinfo
from datetime import datetime
from pathlib import Path
from typing import Generator, List, Optional, Union
import zoneinfo
from filelock import BaseFileLock, FileLock, SoftFileLock, Timeout
from modelscope.hub.constants import (DEFAULT_MODELSCOPE_DOMAIN,
@@ -305,11 +305,9 @@ def weak_file_lock(lock_file: Union[str, Path],
def convert_timestamp(time_stamp: Union[int, str, datetime],
time_zone: str = 'Asia/Shanghai') -> Optional[datetime]:
"""Convert a UNIX/string timestamp to a timezone-aware datetime object.
Args:
time_stamp: UNIX timestamp (int), ISO string, or datetime object
time_zone: Target timezone for non-UTC timestamps (default: 'Asia/Shanghai')
Returns:
Timezone-aware datetime object or None if input is None
"""
@@ -380,3 +378,43 @@ def convert_timestamp(time_stamp: Union[int, str, datetime],
raise TypeError(
f"Unsupported type '{type(time_stamp)}'. Expected int, str, or datetime."
)
def encode_image_to_base64(image_path: str) -> str:
"""
Encode image file to base64 string.
Args:
image_path (str): Path to the image file
Returns:
str: Base64 encoded string with data URL prefix
Raises:
FileNotFoundError: If image file doesn't exist
ValueError: If file is not a valid image format
"""
import base64
import mimetypes
# Expand user path
image_path = os.path.expanduser(image_path)
if not os.path.exists(image_path):
raise FileNotFoundError(f'Image file not found: {image_path}')
if not os.path.isfile(image_path):
raise ValueError(f'Path is not a file: {image_path}')
# Get MIME type
mime_type, _ = mimetypes.guess_type(image_path)
if not mime_type or not mime_type.startswith('image/'):
raise ValueError(f'File is not a valid image format: {image_path}')
# Read and encode file
with open(image_path, 'rb') as image_file:
image_data = image_file.read()
base64_data = base64.b64encode(image_data).decode('utf-8')
# Return data URL format
return f'data:{mime_type};base64,{base64_data}'