Skip to content

# How to create a GreatAI service

The core value of `great-ai` lies in its GreatAI class. In order to take advantage of it, you need to create an instance wrapping your code.

Let's say that you have the following greeter function:

greeter.py

    def my_greeter_function(your_name):
        return f'Hi {your_name}!'

You can simply decorate (wrap) this function using the @GreatAI.create factory.

greeter.py

    from great_ai import GreatAI

    @GreatAI.create
    def greeter(your_name):
        return f'Hi {your_name}!'

Why not simply use `@GreatAI?`

The purpose of the @GreatAI.create is simply to provide you with type-checking through MyPy, Pylance, and similar libraries. However, the overloading support for `__new__` is lacking in MyPy, thus, a static factory method is used instead.

## With types

Even though it's not required by GreatAI, type annotating your codebase can save you from lots of trivial mistakes, that's why it's highly advised. Simply add the expected types to your function's signature.

type_safe_greeter.py

    from great_ai import GreatAI

    @GreatAI.create
    def type_safe_greeter(your_name: str) -> str:
        return f'Hi {your_name}!'

This not only allows you to statically typecheck your code, but by default, GreatAI will check it during runtime as well using typeguard.

## With async

Asynchronous code can result in immense performance gains in certain cases. For example, you might rely on a third-party service, do database access, or call a remote GreatAI instance. In these cases, you can simply make your function `async` without any other changes.

async_greeter.py

    from great_ai import GreatAI
    from asyncio import sleep

    @GreatAI.create
    async def async_greeter(your_name: str) -> str:
        await sleep(2)  # simulate IO-heavy operation
        return f'Hi {your_name}!'

## With decorators

GreatAI can decorate already decorated functions. The only restriction is that @GreatAI.create always has to come last. There are two built-in decorators that you can use to customise your function but you can you use any third-party decorator as well.

### Using `@use_model`

If you have previously saved a model with save_model, you can inject it into your function by calling @use_model.

greeter_with_model.py

    from great_ai import GreatAI, use_model

    @GreatAI.create
    @use_model('name_of_my_model', version='latest')  #(1)
    def type_safe_greeter(your_name: str, model) -> str:
        return f'Hi {your_name}!'

    assert type_safe_greeter('Andras').output == 'Hi Andras'

1. By default, the parameter named `model` will be replaced by the loaded model. This behaviour can be customised by setting the `model_kwarg_name`. This way, even multiple models can be injected into a single function.

Important

You must call @use_model before @GreatAI.create. Feel free to use @use_model in other places of the codebase, it works equally well outside of GreatAI services.

### Using `@parameter`

If you wish to turn of logging or specify custom validation for your parameters, you can use the @parameter decorator.

Note

By default, all parameters that are not affected by an explicit @parameter or @use_model are automatically decorated with @parameter when @GreatAI.create is called.

greeter_with_validation.py

    from great_ai import GreatAI, use_model

    @GreatAI.create
    @use_model('name_of_my_model', version='latest')
    def type_safe_greeter(your_name: str, model) -> str:
        return f'Hi {your_name}!'

    assert type_safe_greeter('Andras').output == 'Hi Andras'

Important

You must call @parameter before @GreatAI.create. Feel free to use @parameter in other places of the codebase, it works equally well outside of GreatAI services.

## Complex example

Refer to the following example summarising the options you have when instantiating a GreatAI service.

complex.py

    from great_ai import save_model, GreatAI, parameter, use_model, log_metric

    save_model(4, 'secret-number')  #(1)

    @GreatAI.create
    @parameter('positive_number', validator=lambda n: n > 0, disable_logging=True)
    @use_model('secret-number', version='latest', model_kwarg_name='secret')
    def add_number(positive_number: int, secret: int) -> int:
        log_metric(
            'log directly into the returned Trace',
            positive_number * 2
        )
        return positive_number + secret

    assert add_number(1).output == 5

1. Refer to storing models for specifying where to store your models.

Last update: July 12, 2022