Skip to content

Commit 0a473e4

Browse files
committed
sample to demo passing images to skills
1 parent 68bbc09 commit 0a473e4

File tree

13 files changed

+901
-0
lines changed

13 files changed

+901
-0
lines changed

Image-Processing/BFR_Sample_Rest.ipynb

Lines changed: 576 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.git*
2+
.vscode
3+
local.settings.json
4+
test
5+
.venv
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# C extensions
7+
*.so
8+
9+
# Distribution / packaging
10+
.Python
11+
build/
12+
develop-eggs/
13+
dist/
14+
downloads/
15+
eggs/
16+
.eggs/
17+
lib/
18+
lib64/
19+
parts/
20+
sdist/
21+
var/
22+
wheels/
23+
pip-wheel-metadata/
24+
share/python-wheels/
25+
*.egg-info/
26+
.installed.cfg
27+
*.egg
28+
MANIFEST
29+
30+
# PyInstaller
31+
# Usually these files are written by a python script from a template
32+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
33+
*.manifest
34+
*.spec
35+
36+
# Installer logs
37+
pip-log.txt
38+
pip-delete-this-directory.txt
39+
40+
# Unit test / coverage reports
41+
htmlcov/
42+
.tox/
43+
.nox/
44+
.coverage
45+
.coverage.*
46+
.cache
47+
nosetests.xml
48+
coverage.xml
49+
*.cover
50+
.hypothesis/
51+
.pytest_cache/
52+
53+
# Translations
54+
*.mo
55+
*.pot
56+
57+
# Django stuff:
58+
*.log
59+
local_settings.py
60+
db.sqlite3
61+
62+
# Flask stuff:
63+
instance/
64+
.webassets-cache
65+
66+
# Scrapy stuff:
67+
.scrapy
68+
69+
# Sphinx documentation
70+
docs/_build/
71+
72+
# PyBuilder
73+
target/
74+
75+
# Jupyter Notebook
76+
.ipynb_checkpoints
77+
78+
# IPython
79+
profile_default/
80+
ipython_config.py
81+
82+
# pyenv
83+
.python-version
84+
85+
# pipenv
86+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
87+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
88+
# having no cross-platform support, pipenv may install dependencies that don’t work, or not
89+
# install all needed dependencies.
90+
#Pipfile.lock
91+
92+
# celery beat schedule file
93+
celerybeat-schedule
94+
95+
# SageMath parsed files
96+
*.sage.py
97+
98+
# Environments
99+
.env
100+
.venv
101+
env/
102+
venv/
103+
ENV/
104+
env.bak/
105+
venv.bak/
106+
107+
# Spyder project settings
108+
.spyderproject
109+
.spyproject
110+
111+
# Rope project settings
112+
.ropeproject
113+
114+
# mkdocs documentation
115+
/site
116+
117+
# mypy
118+
.mypy_cache/
119+
.dmypy.json
120+
dmypy.json
121+
122+
# Pyre type checker
123+
.pyre/
124+
125+
# Azure Functions artifacts
126+
bin
127+
obj
128+
appsettings.json
129+
local.settings.json
130+
.python_packages
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"recommendations": [
3+
"ms-azuretools.vscode-azurefunctions",
4+
"ms-python.python"
5+
]
6+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"version": "0.2.0",
3+
"configurations": [
4+
{
5+
"name": "Attach to Python Functions",
6+
"type": "python",
7+
"request": "attach",
8+
"port": 9091,
9+
"preLaunchTask": "func: host start"
10+
}
11+
]
12+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"azureFunctions.deploySubpath": ".",
3+
"azureFunctions.scmDoBuildDuringDeployment": true,
4+
"azureFunctions.pythonVenv": ".venv",
5+
"azureFunctions.projectLanguage": "Python",
6+
"azureFunctions.projectRuntime": "~2",
7+
"debug.internalConsoleOptions": "neverOpen"
8+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"version": "2.0.0",
3+
"tasks": [
4+
{
5+
"type": "func",
6+
"command": "host start",
7+
"problemMatcher": "$func-python-watch",
8+
"isBackground": true,
9+
"dependsOn": "pipInstall"
10+
},
11+
{
12+
"label": "pipInstall",
13+
"type": "shell",
14+
"osx": {
15+
"command": "${config:azureFunctions.pythonVenv}/bin/python -m pip install -r requirements.txt"
16+
},
17+
"windows": {
18+
"command": "${config:azureFunctions.pythonVenv}\\Scripts\\python -m pip install -r requirements.txt"
19+
},
20+
"linux": {
21+
"command": "${config:azureFunctions.pythonVenv}/bin/python -m pip install -r requirements.txt"
22+
},
23+
"problemMatcher": []
24+
}
25+
]
26+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import logging
2+
import cv2
3+
import numpy as np
4+
import json
5+
import os
6+
import base64
7+
import logging
8+
import azure.functions as func
9+
10+
11+
def main(req: func.HttpRequest) -> func.HttpResponse:
12+
logging.info('Python HTTP trigger function processed a request.')
13+
14+
try:
15+
body = json.dumps(req.get_json())
16+
except ValueError:
17+
return func.HttpResponse(
18+
"Invalid body",
19+
status_code=400
20+
)
21+
22+
if body:
23+
logging.info(body)
24+
result = compose_response(body)
25+
return func.HttpResponse(result, mimetype="application/json")
26+
else:
27+
return func.HttpResponse(
28+
"Invalid body",
29+
status_code=400
30+
)
31+
32+
33+
def compose_response(json_data):
34+
values = json.loads(json_data)['values']
35+
36+
# Prepare the Output before the loop
37+
results = {}
38+
results["values"] = []
39+
40+
for value in values:
41+
output_record = transform_value(value)
42+
if output_record != None:
43+
results["values"].append(output_record)
44+
return json.dumps(results, ensure_ascii=False)
45+
46+
## Perform an operation on a record
47+
def transform_value(value):
48+
try:
49+
recordId = value['recordId']
50+
except AssertionError as error:
51+
return None
52+
53+
# Validate the inputs
54+
try:
55+
assert ('data' in value), "'data' field is required."
56+
data = value['data']
57+
base64String = data["image"]["data"]
58+
base64Bytes = base64String.encode('utf-8')
59+
inputBytes = base64.b64decode(base64Bytes)
60+
jpg_as_np = np.frombuffer(inputBytes, dtype=np.uint8)
61+
originalImage = cv2.imdecode(jpg_as_np, flags=1)
62+
slices = []
63+
for line in data["layoutText"]["lines"]:
64+
slicedImage = originalImage[line["boundingBox"][0]["x"]:line["boundingBox"][0]["y"], line["boundingBox"][3]["x"]:line["boundingBox"][3]["y"]]
65+
if(slicedImage.size >0):
66+
is_success, im_buf_arr = cv2.imencode(".jpg", slicedImage)
67+
byte_im = im_buf_arr.tobytes()
68+
base64Bytes = base64.b64encode(byte_im)
69+
base64String = base64Bytes.decode('utf-8')
70+
aslice = { "$type": "file",
71+
"data": base64String
72+
}
73+
slices.append(aslice)
74+
75+
76+
except AssertionError as error:
77+
return (
78+
{
79+
"recordId": recordId,
80+
"errors": [ { "message": "Error:" + error.args[0] } ]
81+
})
82+
83+
84+
85+
return ({
86+
"recordId": recordId,
87+
"data": {
88+
"slices": slices
89+
}
90+
})
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"scriptFile": "__init__.py",
3+
"bindings": [
4+
{
5+
"authLevel": "function",
6+
"type": "httpTrigger",
7+
"direction": "in",
8+
"name": "req",
9+
"methods": [
10+
"get",
11+
"post"
12+
]
13+
},
14+
{
15+
"type": "http",
16+
"direction": "out",
17+
"name": "$return"
18+
}
19+
]
20+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"name": "Azure"
3+
}

0 commit comments

Comments
 (0)