Skip to content

Commit cadaeb4

Browse files
committed
SDK-1555: Add Doc Scan demo project
1 parent 378cd6d commit cadaeb4

17 files changed

Lines changed: 803 additions & 0 deletions

File tree

examples/doc-scan/.env.example

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Required Keys
2+
YOTI_CLIENT_SDK_ID=yourClientSdkId
3+
YOTI_KEY_FILE_PATH=yourKeyFilePath
4+
5+
# Optional Keys
6+
YOTI_DOC_SCAN_IFRAME_URL=

examples/doc-scan/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.pem

examples/doc-scan/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Doc Scan Example
2+
3+
## Running the example
4+
5+
1. Rename the [.env.example](.env.example) file to `.env` and fill in the required configuration values
6+
1. Install the dependencies with `pip install -r requirements.txt`
7+
1. Start the server `flask run`
8+
1. Visit `http://localhost:5000`

examples/doc-scan/app.py

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import base64
2+
from io import BytesIO
3+
4+
from filetype import filetype
5+
from flask import Flask, Response, render_template, request, send_file, session
6+
from yoti_python_sdk.doc_scan import (
7+
DocScanClient,
8+
RequestedDocumentAuthenticityCheckBuilder,
9+
RequestedFaceMatchCheckBuilder,
10+
RequestedLivenessCheckBuilder,
11+
RequestedTextExtractionTaskBuilder,
12+
SdkConfigBuilder,
13+
SessionSpecBuilder,
14+
)
15+
from yoti_python_sdk.doc_scan.exception import DocScanException
16+
17+
from .settings import (
18+
YOTI_APP_BASE_URL,
19+
YOTI_CLIENT_SDK_ID,
20+
YOTI_DOC_SCAN_IFRAME_URL,
21+
YOTI_KEY_FILE_PATH,
22+
)
23+
24+
app = Flask(__name__)
25+
app.secret_key = "someSecretKey"
26+
27+
28+
def create_session():
29+
"""
30+
Creates a Doc Scan session
31+
32+
:return: the create session result
33+
:rtype: CreateSessionResult
34+
"""
35+
doc_scan_client = DocScanClient(YOTI_CLIENT_SDK_ID, YOTI_KEY_FILE_PATH)
36+
37+
sdk_config = (
38+
SdkConfigBuilder()
39+
.with_allows_camera_and_upload()
40+
.with_primary_colour("#2d9fff")
41+
.with_secondary_colour("#FFFFFF")
42+
.with_font_colour("#FFFFFF")
43+
.with_locale("en-GB")
44+
.with_preset_issuing_country("GBR")
45+
.with_success_url("{url}/success".format(url=YOTI_APP_BASE_URL))
46+
.with_error_url("{url}/error".format(url=YOTI_APP_BASE_URL))
47+
.build()
48+
)
49+
50+
session_spec = (
51+
SessionSpecBuilder()
52+
.with_client_session_token_ttl(600)
53+
.with_resources_ttl(90000)
54+
.with_user_tracking_id("some-user-tracking-id")
55+
.with_requested_check(RequestedDocumentAuthenticityCheckBuilder().build())
56+
.with_requested_check(
57+
RequestedLivenessCheckBuilder()
58+
.for_zoom_liveness()
59+
.with_max_retries(1)
60+
.build()
61+
)
62+
.with_requested_check(
63+
RequestedFaceMatchCheckBuilder().with_manual_check_fallback().build()
64+
)
65+
.with_requested_task(
66+
RequestedTextExtractionTaskBuilder().with_manual_check_always().build()
67+
)
68+
.with_sdk_config(sdk_config)
69+
.build()
70+
)
71+
72+
return doc_scan_client.create_session(session_spec)
73+
74+
75+
@app.route("/")
76+
def index():
77+
try:
78+
result = create_session()
79+
except DocScanException as e:
80+
return render_template("error.html", error=e.text)
81+
82+
session["doc_scan_session_id"] = result.session_id
83+
84+
iframe_url = (
85+
YOTI_DOC_SCAN_IFRAME_URL
86+
+ "?sessionID={session_id}&sessionToken={session_token}"
87+
).format(session_id=result.session_id, session_token=result.client_session_token)
88+
89+
return render_template("index.html", iframe_url=iframe_url)
90+
91+
92+
@app.route("/success")
93+
def success():
94+
doc_scan_client = DocScanClient(YOTI_CLIENT_SDK_ID, YOTI_KEY_FILE_PATH)
95+
96+
session_id = session.get("doc_scan_session_id", None)
97+
98+
try:
99+
session_result = doc_scan_client.get_session(session_id)
100+
except DocScanException as e:
101+
return render_template("error.html", error=e.text)
102+
103+
return render_template("success.html", session_result=session_result)
104+
105+
106+
@app.route("/error")
107+
def error():
108+
error_message = "An unknown error occurred"
109+
110+
if request.args.get("yotiErrorCode", None) is not None:
111+
error_message = "Error Code: {}".format(request.args.get("yotiErrorCode"))
112+
113+
return render_template("error.html", error=error_message)
114+
115+
116+
@app.route("/media")
117+
def media():
118+
media_id = request.args.get("mediaId", None)
119+
if media_id is None:
120+
return Response(status=404)
121+
122+
doc_scan_client = DocScanClient(YOTI_CLIENT_SDK_ID, YOTI_KEY_FILE_PATH)
123+
124+
base64_req = request.args.get("base64", "0")
125+
126+
session_id = session.get("doc_scan_session_id", None)
127+
if session_id is None:
128+
return Response("No session ID available", status=404)
129+
130+
try:
131+
retrieved_media = doc_scan_client.get_media_content(session_id, media_id)
132+
except DocScanException as e:
133+
return render_template("error.html", error=e.text)
134+
135+
if base64_req == "1" and retrieved_media.mime_type == "application/octet-stream":
136+
decoded = base64.b64decode(retrieved_media.content)
137+
info = filetype.guess(decoded)
138+
139+
buffer = BytesIO()
140+
buffer.write(decoded)
141+
buffer.seek(0)
142+
143+
return send_file(
144+
buffer,
145+
attachment_filename="media." + info.extension,
146+
mimetype=info.mime,
147+
as_attachment=True,
148+
)
149+
150+
return Response(
151+
retrieved_media.content, content_type=retrieved_media.mime_type, status=200
152+
)
153+
154+
155+
if __name__ == "__main__":
156+
app.run()

examples/doc-scan/requirements.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
flask>=1.1.2
2+
python-dotenv>=0.13.0
3+
yoti>=2.11.2
4+
filetype>=1.0.7

examples/doc-scan/requirements.txt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#
2+
# This file is autogenerated by pip-compile
3+
# To update, run:
4+
#
5+
# pip-compile --output-file=requirements.txt requirements.in
6+
#
7+
asn1==2.2.0 # via yoti
8+
certifi==2020.4.5.1 # via requests
9+
cffi==1.14.0 # via cryptography
10+
chardet==3.0.4 # via requests
11+
click==7.1.2 # via flask
12+
cryptography==2.9.2 # via pyopenssl, yoti
13+
deprecated==1.2.6 # via yoti
14+
filetype==1.0.7 # via -r requirements.in
15+
flask==1.1.2 # via -r requirements.in
16+
future==0.18.2 # via yoti
17+
idna==2.9 # via requests
18+
iso8601==0.1.12 # via yoti
19+
itsdangerous==1.1.0 # via flask
20+
jinja2==2.11.2 # via flask
21+
markupsafe==1.1.1 # via jinja2
22+
protobuf==3.11.3 # via yoti
23+
pycparser==2.20 # via cffi
24+
pyopenssl==19.1.0 # via yoti
25+
python-dotenv==0.13.0 # via -r requirements.in
26+
requests==2.23.0 # via yoti
27+
six==1.14.0 # via cryptography, protobuf, pyopenssl
28+
urllib3==1.25.9 # via requests
29+
werkzeug==1.0.1 # via flask
30+
wrapt==1.12.1 # via deprecated
31+
yoti==2.11.2 # via -r requirements.in
32+
33+
# The following packages are considered to be unsafe in a requirements file:
34+
# setuptools

examples/doc-scan/settings.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from os import environ
2+
from os.path import dirname, join
3+
4+
from dotenv import load_dotenv
5+
6+
dotenv_path = join(dirname(__file__), ".env")
7+
load_dotenv(dotenv_path)
8+
9+
YOTI_CLIENT_SDK_ID = environ.get("YOTI_CLIENT_SDK_ID", None)
10+
YOTI_KEY_FILE_PATH = environ.get("YOTI_KEY_FILE_PATH", None)
11+
12+
if YOTI_CLIENT_SDK_ID is None or YOTI_KEY_FILE_PATH is None:
13+
raise ValueError("YOTI_CLIENT_SDK_ID or YOTI_KEY_FILE_PATH is None")
14+
15+
YOTI_DOC_SCAN_IFRAME_URL = environ.get(
16+
"YOTI_DOC_SCAN_IFRAME_URL", "https://api.yoti.com/idverify/v1/web/index.html"
17+
)
18+
YOTI_APP_BASE_URL = environ.get("YOTI_APP_BASE_URL", "http://localhost:5000")
790 Bytes
Loading
Lines changed: 1 addition & 0 deletions
Loading

examples/doc-scan/static/style.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
body {
3+
padding-top: 4.5rem;
4+
}
5+
6+
table td:first-child {
7+
width: 30%;
8+
}

0 commit comments

Comments
 (0)