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

78 errors in return value of models json example #79

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
25 changes: 19 additions & 6 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ async def inference_request():
cache_json_result[-1], imageDims, area_ratio, color_format
)

result_json_string = await record_model(pipeline, processed_result_json)
result_json_string = await record_model(pipeline_name, pipeline, processed_result_json)

# upload the inference results to the user's container as async task
app.add_background_task(
Expand All @@ -387,7 +387,7 @@ async def inference_request():
print(f"Took: {'{:10.4f}'.format(time.perf_counter() - seconds)} seconds") # TODO: Transform into logging
return jsonify(processed_result_json), 200

except (KeyError, InferenceRequestError) as error:
except (KeyError, InferenceRequestError, inference.ProcessInferenceResultError) as error:
print(error)
return jsonify(["InferenceRequestError: " + error.args[0]]), 400

Expand Down Expand Up @@ -456,10 +456,24 @@ async def test():

return CACHE["endpoints"], 200


async def record_model(pipeline: namedtuple, result: list):

async def record_model(name: str, pipeline: namedtuple, result: list):
"""
Records the models in the pipeline to the result list.

Args:
name (str): The name of the pipeline.
pipeline (namedtuple): The pipeline containing the models.
result (list): The result list to update.

Returns:
str: The updated result list as a JSON string.
"""
new_entry = [{"name": model.name, "version": model.version} for model in pipeline]
result[0]["models"] = new_entry
result[0].update({
"pipeline": name,
"models": new_entry
})
return json.dumps(result, indent=4)


Expand Down Expand Up @@ -494,7 +508,6 @@ async def get_pipelines(connection_string, pipeline_blob_name, pipeline_version,
app.config["BLOB_CLIENT"] = await azure_storage_api.get_blob_client(connection_string)
result_json = await azure_storage_api.get_pipeline_info(app.config["BLOB_CLIENT"], pipeline_blob_name, pipeline_version)
except (azure_storage_api.AzureAPIErrors) as error:
print(error)
raise ServerError("server errror: could not retrieve the pipelines") from error

models = ()
Expand Down
10 changes: 0 additions & 10 deletions custom_exceptions.py

This file was deleted.

197 changes: 105 additions & 92 deletions docs/nachet-inference-documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ output"|G>"return
result.json to user"]

subgraph SB1[In pipeline]
direction TB
  direction TB

B(model 01)-->|"model output
send to the next one"|C(model 02)-->|can have n models|D(n models)
  B(model 01)-->|"model output
  send to the next one"|C(model 02)-->|can have n models|D(n models)

end
```
Expand All @@ -61,80 +61,83 @@ to a model and receive the result.

```mermaid
sequenceDiagram
title: Sequence Diagram for inference request 1.2.1
actor Client
participant Frontend
participant Backend
participant Blob storage
participant Model

Backend-)+Backend: run()
Note over Backend,Blob storage: initialisation
Backend-)Backend: before_serving()
Backend-)Backend: get_pipelines()
alt
Backend-)+Blob storage: HTTP POST req.
Blob storage--)-Backend: return pipelines_models.json
else
Backend-)Frontend: error 500 Failed to retrieve data from the repository
end
Note over Backend,Blob storage: end of initialisation

Client->>+Frontend: applicationStart()
Frontend-)Backend: HTTP POST req.
Backend-)Backend: get_model_endpoints_metadata()
Backend--)Frontend: Pipelines names res.
Note left of Backend: return pipelines names and metadata

Frontend->>Client: application is ready
Client-->>Frontend: client ask action from specific pipeline
Frontend-)Backend: HTTP POST req.
Backend-)Backend: inference_request(pipeline_name, folder_name, container_name, imageDims, image)
alt missing arguments
Backend-)Frontend: Error 400 missing arguments
end
alt wrong pipeline name
Backend-)Frontend: Error 400 wrong pipeline name
end
alt wrong header
Backend-)Frontend: Error 400 wrong header on file
end

Backend-)Backend: mount_container(connection_string(Environnement Variable, container_name))
Backend-)+Blob storage: HTTP POST req.
Blob storage--)-Backend: container_client

Backend-)Backend: Generate Hash(image_bytes)

Backend-)Backend: upload_image(container_client, folder_name, image_bytes, hash_value)
Backend-)+Blob storage: HTTP POST req.
Blob storage--)-Backend: blob_name

Backend-)Backend: get_blob(container_client, blob_name)
Backend-)+Blob storage: HTTP POST req.
Blob storage--)-Backend: blob

loop for every model in pipeline
Backend-)Backend: model.entry_function(model, previous_result)
note over Backend, Blob storage: Every model has is own entry_function
Backend-)Backend: request_factory(previous_result, model)
Backend-)Backend: urllib.request.Request(endpoint_url, body, header)
Backend-)+Model: HTTP POST req.
Model--)-Backend: Result res.
alt if model has process_inference_function
Backend-) Backend: model.inference_function(previous_result, result_json)
end
end
note over Backend, Blob storage: End of the loop
par Backend to Frontend
Backend-)Backend: inference.process_inference_results(result_json, imageDims)
Backend--)Frontend: Processed result res.
Frontend--)-Client: display result
and Backend to Blob storage
note over Backend, Blob storage: record the result produced by the model
Backend-)Backend: upload_inference_result(container_client, folder_name, result_json_string, hash_value)
Backend-)-Blob storage: HTTP POST req.
end
 title: Sequence Diagram for inference request 1.2.1
  actor Client
  participant Frontend
  participant Backend
  participant Blob storage
  participant Model

  Backend-)+Backend: run()
  Note over Backend, Blob storage: initialization
  Backend-)Backend: before_serving()
  Backend-)Backend: get_pipelines()
  alt
  Backend-)+Blob storage: HTTP POST req.
  Blob storage--)-Backend: return pipelines_models.json
  else
  Backend-)Frontend: error 500 Failed to retrieve data from the repository
  end
  Note over Backend, Blob storage: end of initialization

  Client->>+Frontend: applicationStart()
  Frontend-)Backend: HTTP POST req.
  Backend-)Backend: get_model_endpoints_metadata()
  Backend--)Frontend: Pipelines names res.
  Note left of Backend: return pipelines names and metadata

  Frontend-->>-Client: application is ready
  Client->>+Frontend: Client asks actions from a specific pipeline
  Frontend-)Backend: HTTP POST req.
  Backend-)Backend: inference_request(pipeline_name, folder_name, container_name, imageDims, image)
  alt missing arguments
  Backend-)Frontend: Error 400 missing arguments
  end
  alt wrong pipeline name
  Backend-)Frontend: Error 400 wrong pipeline name
  end
  alt wrong image
  Backend-)Frontend: Error 400 this picture was not validated
  end

  Backend-)Backend: mount_container(blob_service_client, container_name)
  Backend-)+Blob storage: HTTP POST req.
  Blob storage--)-Backend: container_client

  Backend-)Backend: Generate Hash(image_bytes)

  Backend-)Backend: upload_image(container_client, folder_name, image_bytes, hash_value)

  loop for every model in pipeline
    Backend-)Backend: model.request_function(model, previous_result)
    note over Backend, Blob storage: Every model has its own request_function
    alt Get inference from model
      alt seed detector or nachet-6seeds model
        Backend->>+Model: urlopen(Request(model.endpoint, body, headers))
        Model-->>-Backend: Result res.
      else seed-detector model has a process function
        Backend->>Backend: process(images_bytes, inf_result)
      end
    else swin model inference is requested
      loop for every image in previous_result
        note over Backend, Model: Swin can only accept 1 seed per images
        Backend->>+Model: urlopen(Request(model.endpoint, body, headers))
        Model-->>-Backend: Result res.
        Backend->>Backend: results.append(Result)
      end
      Backend->>Backend: process(previous_result, results)
    end
  end
  note over Backend, Blob storage: End of the loop
  par Backend to Frontend
    Backend-)Backend: inference.process_inference_results(result_json, imageDims)
    Backend--)Frontend: Processed result res.
    Frontend--)-Client: display result
  and Backend to Blob storage
    note over Backend, Blob storage: record the result produced by the model
    Backend-)Backend: upload_inference_result(container_client, folder_name, result_json_string, hash_value)
    Backend-)-Blob storage: HTTP POST req.
  end
```

![footer_for_diagram](https://github.com/ai-cfia/nachet-backend/assets/96267006/cf378d6f-5b20-4e1d-8665-2ba65ed54f8e)
Expand All @@ -146,13 +149,13 @@ backend. It requests actions from selected models or pipelines based on certain
checks. These checks include verifying that all arguments required to find or
initialize the blob container and process the image have been transmitted to the
function. It also checks if the selected pipeline is recognized by the system
and if the image sent for analysis has a valid header.
and if the image sent for analysis has been validated.

If all the above checks pass, the function initializes or finds the user blob
container and uploads the image. Next, it requests an inference from every model
in the pipeline. Each model specifies their `entry_function` (how to call and
retrieve data) and whether they have a `process_inference` function. Based on
these indications, the results are returned and stored in the cache.
in the pipeline. Each model specifies their `request_function` (how to call and
retrieve data). Based on these indications, the results are returned and stored
in the cache.

If no other model is called, the last result is then processed and sent to the frontend.

Expand All @@ -163,10 +166,13 @@ The inference request will process the following parameters:
|Key parameters | Expected Value|
|--|--|
|model_name | The name of the pipeline|
|vallidator| A hash that has been returning to the frontend when the image is valid|
|folder_name | The folder where the image is uploaded in the user's container|
|container_name | The user's container|
|imageDims | The dimension of the image|
|image | The image encoded in b64 (ASCII)|
|area_ratio| The ratio specified by the user, default = 0.5|
|color_format| The ccolor format specified by the frontend, default = "hex"|

Note that since the information is received from the frontend, the model_name is
an abstraction for a pipeline.
Expand All @@ -178,20 +184,23 @@ The inference request will return a list with the following information:
|Boxes | 0 | Contains all the boxes returned by the inference request|
|labelOccurence | 0 | Contains the number of label occurence|
|totalBoxes | 0 | Boxes total number|
|pipeline| 0 | Contains the name of the pipeline that produced the inference|
|models| 0 | Contains the models used by the pipeline|
|Box | 1 | Contains all the information of one seed in the image|
|label | 1 | Contains the top label for the seed|
|score | 1 | Contains the top score for the seed|
|topN | 1 | Contains the top N scores for the seed|
|overlapping | 1 | Contains a boolean to tell if the box overlap with another one|
|overlapping | 1 | Contains a boolean to tell if the box overlaps with another one|
|overlappingIndices | 1 | Contains the index of the overlapping box|
|topX | 2 | The top x value of the box around a seed|
|topY | 2 | The top y value of the box around a seed|
|bottomX | 2 | The bottom x value of the box around a seed|
|bottomY| 2 | The bottom y value of the box around a seed|

*for more look at [nachet-model-documentation](https://github.com/ai-cfia/nachet-backend/blob/51-implementing-2-models/docs/nachet-model-documentation.md#return-value-of-models)*
*for more look at [nachet-model-documentation](nachet-model-documentation.md#return-value-of-models)*

**topN** contains the top 5 predictions of the models:
**topN** contains the top n predictions of a given model. For now, only `Swin`
returns a `topN` key with 5 results:

```json
"topN": [
Expand Down Expand Up @@ -220,19 +229,22 @@ The inference request will return a list with the following information:

### Blob storage and Pipeline versioning

:warning: **This section will need adjustment after the implementation of the
datastore into Nachet**

To keep track of the various pipeline iterations and versions, JSON files are
stored in the blob storage. Users can add the JSON to the blob storage
stored in the blob storage. Datascientists can add the JSON to the blob storage
using the `pipelines_version_insertion.py` script. This allows for easy
management of model and pipeline history.

To use the script, 3 environment variables are necessary:

* NACHET_BLOB_PIPELINE_NAME
* Containing the blob name where the pipelines are stored
* NACHET_BLOB_PIPELINE_VERSION
* Containing the version the user wants to select
* NACHET_BLOB_PIPELINE_DECRYPTION_KEY
* The key to decrypt sensible data such as the API key and the endpoint of a model.
* **NACHET_BLOB_PIPELINE_NAME**
 * Containing the blob name where the pipelines are stored
* **NACHET_BLOB_PIPELINE_VERSION**
 * Containing the version the user wants to select
* **NACHET_BLOB_PIPELINE_DECRYPTION_KEY**
 * The key to decrypt sensible data such as the API key and the endpoint of a model.

#### In the code

Expand All @@ -245,7 +257,6 @@ information and metadata to the frontend.
async def get_pipelines(connection_string, pipeline_blob_name, pipeline_version, cipher_suite):
"""
Retrieves the pipelines from the Azure storage API.

Returns:
- list: A list of dictionaries representing the pipelines.
"""
Expand Down Expand Up @@ -280,6 +291,8 @@ async def get_pipelines(connection_string, pipeline_blob_name, pipeline_version,

### Available Version of the JSON file

***Careful as major update might change pipeline and model attributes***

|Version|Creation Date| Pipelines|
|--|--|--|
|0.1.3 | 2024-03-26 | Swin Transformer and 6 Seeds Detector|
Expand Down
Loading
Loading