Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Development of Flexible API Layer #4275

Closed
Tracked by #4044
akash5100 opened this issue Sep 11, 2023 · 1 comment · Fixed by #4282
Closed
Tracked by #4044

Development of Flexible API Layer #4275

akash5100 opened this issue Sep 11, 2023 · 1 comment · Fixed by #4282
Assignees
Labels

Comments

@akash5100
Copy link
Contributor

akash5100 commented Sep 11, 2023

Creating a Flexible API layer in the contentcuration app in Studio

Overview

Within the contentcuration app in Studio, we want to build an API layer that acts as a communication bridge with different backends like Docker Images, Google Cloud Platform's Vertex AI, and VM instances, cloud storage services, etc. The goal is to make sure this API layer can work with these backends, regardless of where or how they do the job. As long as the input and output formats stay the same, this setup provides flexibility in choosing and using backend resources.

Description and outcomes

The stand-alone deployed backend service(s) will not have direct access to contentcuration models or the database for that matter, so this API layer facilitates access to these resources by receiving and returning a standardized requests and responses, irrespective of the backend interacted with.

The Architecture

Screenshot 2023-09-11 at 14 50 06

The main components of this API layer are

  1. Backend Interface
  2. Adapter

Creating the Backend Interface

The core Backend class will be an abstract interface that defines the operations that all backends must support. It also implements the Singleton pattern, and provides a make_request method to forward requests to the chosen Backend, whose formats can be specified using the request and response methods.

ABSTRACT CLASS Backend:
	_instance = None # Private variable to hold the instance

	ABSTRACT METHOD connect()
		# Provides blue print to connect
		pass

	ABSTRACT METHOD make_request(params)
		# provide blue print to make request
		pass

        ABSTRACT METHOD request(params)
		# provide blue print for the request object
		pass
	
	ABSTRACT METHOD response(params)
		# provides blue print for the response object
		pass

	CLASS METHOD get_instance(cls)
		IF cls._instance is None:
			cls._instance = cls._create_instance()
		return cls._instance

	CLASS METHOD _create_instance(cls)
		raise NotImplementedError # concrete class must implement

Different backends can now be created by implementing the base Backend class:

# Implement CONCRETE CLASS using ABSTRACT Backend class
CLASS GCS IMPLEMENTS Backend:
	METHOD make_request(params):
		# make request to Google Cloud Storage services

	METHOD connect(params):
		# Implement the connect method for GCS

	CLASS METHOD _create_instance(cls)
		# initialize a GCS Backend instance

CLASS ML IMPLEMENTS Backend:
	METHOD make_request(params):
		# make request to DeepLearning models hosted as service

	METHOD connect(params):
		# Implement the connect method for hosted ML service

	CLASS METHOD _create_instance(cls)
		# initialize a ML Backend instance

CLASS OtherBackend IMPLEMENTS Backend:
	...
	[you get the idea]

To create an instance of a backend, using the ML class as an example, use the get_instance() method:

>>> backend = ML.get_instance()

To centralize the creation of Backend instances based on specific Django settings(e.g. dev vs. production environments), create a base BackendFactory abstract class. This should follow the Factory Design Pattern.

# Abstract class for the Factory to instantiate the Backend based on Django Settings
ABSTRACT CLASS BackendFactory:
	ABSTRACT METHOD create_backend(self) -> Backend
		pass

The BackendFactory's create_backend method optionally allows a Backend instance to be injected into the factory instead of relying solely on Django settings. This is particularly useful if we want to explicitly specify the backend to use.

Creating Adapter that accepts any Backend

The Adapter class can be initialized with a Backend instance which provides a make_request method that forwards requests to the chosen Backend while adhering to its specific request and response formats.

CLASS Adapter:

  METHOD __init__(self, backend)
	# Initialize the Backend with BackendFactory
	SET backend = backend

  METHOD request(self):
	# something
	return self.backend.request()

  METHOD response(self):
	# something
	return self.backend.response()

With this Adapter class in place, we can create Adapter that are able interact with any backend we need.

CLASS Recommendation INHERITS ADAPTER:
	METHOD generateEmbeddings(self, params) -> Boolean
		# [ Implementation ]

	METHOD getRecommendation(self, params) -> Array
		# [ Implementation ]

CLASS Transcription INHERITS ADAPTER:
	METHOD generateCaption(self, params) -> Array
		# [ Implementation ]

CLASS OtherAdapter INHERITS ADAPTER:
	METHOD someOperation(self, params) -> Any
		# Operation that any backend wants

Below is a sample use case, using the ML backend as an example:

>>> backend = ML.get_instance()
>>> adapter =  Transcription(backend)

To access specific methods within the adapter:

>>> adapter.generateCaption(...)

Resources

OOP Design patterns

Acceptance Criteria

  1. A module with an appropriate name is created for the mini-library within the contentcuration app in Studio.
  2. Appropriate folders are created in the created module to clearly distinguish the files(if necessary).
  3. A base abstract Backend class that defines the operation that all backends must support is created.
  4. The Backend class includes relevant abstract methods that allow for specific implementations for the various backends.
  5. The Backend class implements the Singleton pattern.
  6. A base abstract Backend Factory class that centralizes the creation of Backend instances based on Django settings is created.
  7. All Backend instances specified in the BackendFactory follow the singleton pattern, ensuring only one instance of each backend can exist.
  8. A base Adapter class is established, which can be initialized by any Backend.
  9. The Adapter class includes methods that are relevant for interaction with the initialized Backend.
  10. Tests are written to validate the correctness of the base logic implementation.
  11. Documentation is updated to include information about the new mini-library, its usage, and its purpose.

Out of scope

  • This task doesn't include implementation of the the backends and adapters. They were only used to paint a picture of the architecture as a whole and how it works together.

Tasks

Preview Give feedback
No tasks being tracked yet.
@akolson akolson changed the title Development of Flexible API Layer for Contentcuration Django Application Development of Flexible API Layer Sep 11, 2023
@ozer550 ozer550 removed their assignment Sep 12, 2023
@akolson
Copy link
Member

akolson commented Sep 12, 2023

With a considerable amount of actual development work already done by @akash5100 prior to today's iteration planning, @ozer550 has unassigned himself so Akash can proceed to complete the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants