Front end APIs
- Protocol: HTTP
- Interface: RESTful API
- Base URL:
http://10.0.13.134:3824
The API {{base_url}}/v1/similarity/batch
submits a form containing multiple tasks, uploads the necessary files at the
same time, and then waits for the results of multiple task executions.
Method: POST
Body: form(data)
KEY | TYPE | REQUIRED | DESCRIPTION |
---|---|---|---|
file_1 | file |
NO | NPU model, image or dumped data package (zip) |
file_2 | file |
NO | NPU model, image or dumped data package (zip) |
file_3 | file |
NO | NPU model, image or dumped data package (zip) |
... | file |
NO | NPU model, image or dumped data package (zip) |
json_data | text |
YES | The text should conform to the JSON specification, and the field points to the KEY of the above file |
The following are the details of the field json_data
:
KEY | TYPE | REQUIRED | DESCRIPTION |
---|---|---|---|
items | object array |
YES | array of JSON objects |
id | string |
YES | uuid of task |
project | string |
YES | vc0728 or vc0768 |
npu_model | string |
YES | KEY of NPU model file |
input_data | string |
YES | KEY of image |
dumped_data | string |
YES | KEY of dumped data compressed package |
The following is an examples of the field json_data
:
{
"items": [
{
"id": "7892f81f-891a-49ec-871a-58ffdee52442",
"project": "vc0728",
"npu_model": "file_1",
"input_data": "file_2",
"dumped_data": "file_3"
}
]
}
curl --location 'http://10.0.13.134:3824/v1/similarity/batch' \
--form 'input_1=@/home/duruyao/test/input.jpeg' \
--form 'model_1=@/home/duruyao/test/AlexNet-8.npumodel' \
--form 'model_2=@/home/duruyao/test/AlexNet-16.npumodel' \
--form 'package_1=@/home/duruyao/test/AlexNet-8-dump.zip' \
--form 'package_2=@/home/duruyao/test/AlexNet-16-dump.zip' \
--form 'json_data={
"items": [
{
"id": "7892f81f-891a-49ec-871a-58ffdee52442",
"project": "vc0728",
"npu_model": "model_1",
"input_data": "input_1",
"dumped_data": "package_1"
},
{
"id": "571f4201-3844-44fe-8e94-a2ea9602ea78",
"project": "vc0728",
"npu_model": "model_2",
"input_data": "input_1",
"dumped_data": "package_2"
}
]
}' --verbose | json_pp
The data responded by the web service conforms to the JSON specification and has the following format:
KEY | TYPE | REQUIRED | DESCRIPTION |
---|---|---|---|
error | string |
NO | error message |
items | object array |
YES | array of JSON objects |
id | string |
YES | uuid of task |
results | number array |
YES | array of similarities |
The following is an example response when a task fails:
{
"error": "json_data field is required but not found"
}
The following is an example response when the task is successful:
{
"items": [
{
"id": "7892f81f-891a-49ec-871a-58ffdee52442",
"results": [
0.114285095335321,
0.313045494414164
]
},
{
"id": "571f4201-3844-44fe-8e94-a2ea9602ea78",
"results": [
0.0723396900147865,
0.282645558215649
]
}
]
}
import os
import json
import shutil
import random
import datetime
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/v1/similarity/batch', methods=['POST'])
def calculate_similarity():
if 'json_data' not in request.form:
return jsonify({'error': 'json_data field is required but not found'}), 400
try:
req_data = json.loads(request.form.get('json_data'))
except json.JSONDecodeError:
return jsonify({'error': 'invalid JSON data in json_data field'}), 400
if 'items' not in req_data:
return jsonify({'items': None}), 200
resp_items = []
saved_files = {}
work_dir = os.getcwd()
upload_date = datetime.datetime.now().isoformat()
for item in req_data['items']:
for key in ['npu_model', 'input_data', 'dumped_data']:
if key not in item:
return jsonify({'error': f'missing {key} in item'}), 400
for key in ['npu_model', 'input_data', 'dumped_data']:
file = request.files.get(item[key])
if file:
save_path = os.path.join(work_dir, 'upload', upload_date, item['id'], file.filename)
os.makedirs(os.path.dirname(save_path), exist_ok=True)
if file.filename not in saved_files:
saved_files[file.filename] = save_path
file.save(save_path)
else:
shutil.copy(saved_files[file.filename], save_path)
else:
return jsonify({'error': f'missing file for {key}'}), 400
# TODO: calculate similarity
#
resp_items.append({'id': item['id'], 'results': [random.random(), random.random()]})
#
#
return jsonify({'items': resp_items}), 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=3824)
package main
import (
"encoding/json"
"github.com/gin-gonic/gin"
"log"
"math/rand"
"net/http"
"os"
"time"
)
func main() {
router := gin.Default()
router.POST("/v1/similarity/batch", func(c *gin.Context) {
reqData := struct {
Items []struct {
Id string `json:"id" binding:"required"`
Project string ` json:"project" binding:"required"`
NpuModel string ` json:"npu_model" binding:"required"`
InputData string ` json:"input_data" binding:"required"`
DumpedData string ` json:"dumped_data" binding:"required"`
} `json:"items" binding:"required"`
}{}
jsonData, ok := c.GetPostForm("json_data")
if !ok {
c.JSON(http.StatusBadRequest, gin.H{"error": "json_data field is required but not found"})
return
}
if err := json.Unmarshal([]byte(jsonData), &reqData); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
type RespItem struct {
Id string `json:"id" binding:"required"`
Results []float64 ` json:"results" binding:"required"`
}
respBody := struct {
Items []RespItem `json:"items" binding:"required"`
}{}
workDir, _ := os.Getwd()
uploadDate := time.Now().Format(time.RFC3339)
for _, it := range reqData.Items {
for _, key := range []string{it.NpuModel, it.InputData, it.DumpedData} {
file, err := c.FormFile(key)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if err := c.SaveUploadedFile(file,
workDir+"/upload/"+uploadDate+"/"+it.Id+"/"+file.Filename); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
}
// TODO: calculate similarity
//
respBody.Items = append(respBody.Items,
RespItem{Id: it.Id, Results: []float64{rand.Float64(), rand.Float64()}})
//
//
}
c.JSON(http.StatusOK, respBody)
})
log.Fatalln(router.Run("0.0.0.0:3824"))
}
The API {{base_url}}/v1/update/:project
submits multiple files in order to update them on the board.
Method: POST
Body: form(data)
KEY | TYPE | REQUIRED | DESCRIPTION |
---|---|---|---|
upload | file array |
YES | shared objects, kernel objects, executable files and others |
curl --location 'http://10.0.13.134:3824/v1/update/vc0728' \
--form 'upload[]=@/home/duruyao/test/02.DebugTools/arm/libnpu.so' \
--form 'upload[]=@/home/duruyao/test/02.DebugTools/arm/npu_test' \
--form 'upload[]=@/home/duruyao/test/02.DebugTools/arm/npu_test_d_half' \
--form 'upload[]=@/home/duruyao/test/02.DebugTools/ko/base.ko' \
--form 'upload[]=@/home/duruyao/test/02.DebugTools/ko/nmz.ko' \
--form 'upload[]=@/home/duruyao/test/02.DebugTools/ko/npu.ko' --verbose | json_pp
The data responded by the web service conforms to the JSON specification and has the following format:
KEY | TYPE | REQUIRED | DESCRIPTION |
---|---|---|---|
error | string |
NO | error message |
result | string |
NO | some information |
The following is an example response when a task fails:
{
"error": "Unknown project: vc0778"
}
The following is an example response when the task is successful:
{
"result": "6 files uploaded"
}
import datetime
import os
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/v1/update/<project>', methods=['POST'])
def update(project):
if project not in ['vc0728', 'vc0768']:
return jsonify({"error": f"Unknown project: {project}"}), 500
files = request.files.getlist('upload[]')
work_dir = os.getcwd()
upload_date = datetime.datetime.now().isoformat()
for file in files:
save_path = os.path.join(work_dir, "upload", upload_date, project, file.filename)
os.makedirs(os.path.dirname(save_path), exist_ok=True)
file.save(save_path)
# TODO: update *.so and *.ko files
#
entries = os.listdir(os.path.join(work_dir, "upload", upload_date, project))
for entry in entries:
print(os.path.join(work_dir, "upload", upload_date, project, entry))
#
#
return jsonify({"result": f"{len(files)} files uploaded"}), 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=3824)
package main
import (
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"log"
"math/rand"
"net/http"
"os"
"time"
)
func main() {
router := gin.Default()
router.POST("/v1/update/:project", func(c *gin.Context) {
project := c.Param("project")
if project != "vc0728" && project != "vc0768" {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Unknown project: " + project})
return
}
form, _ := c.MultipartForm()
files := form.File["upload[]"]
workDir, _ := os.Getwd()
uploadDate := time.Now().Format(time.RFC3339)
for _, file := range files {
if err := c.SaveUploadedFile(file,
workDir+"/upload/"+uploadDate+"/"+project+"/"+file.Filename); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
}
// TODO: update *.so and *.ko files
//
entries, _ := os.ReadDir(workDir + "/upload/" + uploadDate + "/" + project)
for _, entry := range entries {
fmt.Println(workDir + "/upload/" + uploadDate + "/" + project + "/" + entry.Name())
}
//
//
c.JSON(http.StatusOK, gin.H{"result": fmt.Sprintf("%d files uploaded", len(files))})
})
log.Fatalln(router.Run("0.0.0.0:3824"))
}