Skip to content

Commit

Permalink
Merge pull request #356 from roboflow/lean/deploy-versionless-model
Browse files Browse the repository at this point in the history
Versionless model deploy/upload
  • Loading branch information
lrosemberg authored Jan 31, 2025
2 parents b5ed55b + 5bd9b37 commit 01d713f
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 8 deletions.
2 changes: 1 addition & 1 deletion roboflow/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from roboflow.models import CLIPModel, GazeModel # noqa: F401
from roboflow.util.general import write_line

__version__ = "1.1.52"
__version__ = "1.1.53"


def check_key(api_key, model, notebook, num_retries=0):
Expand Down
72 changes: 71 additions & 1 deletion roboflow/core/workspace.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import concurrent.futures
import glob
import json
Expand All @@ -10,11 +12,12 @@

from roboflow.adapters import rfapi
from roboflow.adapters.rfapi import AnnotationSaveError, ImageUploadError, RoboflowError
from roboflow.config import API_URL, CLIP_FEATURIZE_URL, DEMO_KEYS
from roboflow.config import API_URL, APP_URL, CLIP_FEATURIZE_URL, DEMO_KEYS
from roboflow.core.project import Project
from roboflow.util import folderparser
from roboflow.util.active_learning_utils import check_box_size, clip_encode, count_comparisons
from roboflow.util.image_utils import load_labelmap
from roboflow.util.model_processor import process
from roboflow.util.two_stage_utils import ocr_infer


Expand Down Expand Up @@ -566,6 +569,73 @@ def active_learning(
prediction_results if type(raw_data_location) is not np.ndarray else prediction_results[-1]["predictions"]
)

def deploy_model(
self,
model_type: str,
model_path: str,
project_ids: list[str],
model_name: str,
filename: str = "weights/best.pt",
):
"""Uploads provided weights file to Roboflow.
Args:
model_type (str): The type of the model to be deployed.
model_path (str): File path to the model weights to be uploaded.
project_ids (list[str]): List of project IDs to deploy the model to.
filename (str, optional): The name of the weights file. Defaults to "weights/best.pt".
"""

if not project_ids:
raise ValueError("At least one project ID must be provided")

# Validate if provided project URLs belong to user's projects
user_projects = set(project.split("/")[-1] for project in self.projects())
for project_id in project_ids:
if project_id not in user_projects:
raise ValueError(f"Project {project_id} is not accessible in this workspace")

zip_file_name = process(model_type, model_path, filename)

if zip_file_name is None:
raise RuntimeError("Failed to process model")

self._upload_zip(model_type, model_path, project_ids, model_name, zip_file_name)

def _upload_zip(
self,
model_type: str,
model_path: str,
project_ids: list[str],
model_name: str,
model_file_name: str,
):
# This endpoint returns a signed URL to upload the model
res = requests.post(
f"{API_URL}/{self.url}/models/prepareUpload?api_key={self.__api_key}&modelType={model_type}&modelName={model_name}&projectIds={','.join(project_ids)}&nocache=true"
)
try:
res.raise_for_status()
except Exception as e:
print(f"An error occured when getting the model deployment URL: {e}")
return

# Upload the model to the signed URL
res = requests.put(
res.json()["url"],
data=open(os.path.join(model_path, model_file_name), "rb"),
)
try:
res.raise_for_status()

for project_id in project_ids:
print(
f"View the status of your deployment for project {project_id} at:"
f" {APP_URL}/{self.url}/{project_id}/models"
)

except Exception as e:
print(f"An error occured when uploading the model: {e}")

def __str__(self):
projects = self.projects()
json_value = {"name": self.name, "url": self.url, "projects": projects}
Expand Down
29 changes: 23 additions & 6 deletions roboflow/roboflowpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,20 @@ def upload_model(args):
rf = roboflow.Roboflow(args.api_key)
workspace = rf.workspace(args.workspace)

# Deploy to specific version
project = workspace.project(args.project)
version = project.version(args.version_number)
version.deploy(str(args.model_type), str(args.model_path), str(args.filename))
if args.version_number is not None:
# Deploy to specific version
project = workspace.project(args.project)
version = project.version(args.version_number)
version.deploy(str(args.model_type), str(args.model_path), str(args.filename))
else:
# Deploy to multiple projects
workspace.deploy_model(
model_type=str(args.model_type),
model_path=str(args.model_path),
project_ids=args.project,
model_name=str(args.model_name),
filename=str(args.filename),
)


def list_projects(args):
Expand Down Expand Up @@ -479,13 +489,15 @@ def _add_upload_model_parser(subparsers):
upload_model_parser.add_argument(
"-p",
dest="project",
help="project_id to upload the model into",
action="append", # Allow multiple projects
help="project_id to upload the model into (can be specified multiple times)",
)
upload_model_parser.add_argument(
"-v",
dest="version_number",
type=int,
help="version number to upload the model to",
help="version number to upload the model to (optional)",
default=None,
)
upload_model_parser.add_argument(
"-t",
Expand All @@ -503,6 +515,11 @@ def _add_upload_model_parser(subparsers):
default="weights/best.pt",
help="name of the model file",
)
upload_model_parser.add_argument(
"-n",
dest="model_name",
help="name of the model",
)
upload_model_parser.set_defaults(func=upload_model)


Expand Down

0 comments on commit 01d713f

Please sign in to comment.