Update README, include cloud structure schematic

This commit is contained in:
Tobias Quadfasel
2024-09-04 08:15:12 +02:00
parent 0344da8191
commit fb53ddcc8e
2 changed files with 891 additions and 2 deletions

View File

@@ -1,5 +1,47 @@
# grid_application
Code for my application to Avacon AG for the role of Data Scientist. This is a web app containing different data science use-cases related to power grids and electricity generation.
# Avacon Data Science project: Chat with your data application
Code for a self-implemented web app for my application at Avacon Netz for the role of Data Scientist. This is a "chat with your data app" using generated data of customers and their gas and electricity meter readings.
## Einleitung
Ich hoffe, dass ich mit diesem kleinen Projekt meiner Begeisterung und Neugier für die Stelle noch einmal Nachdruck verleihen kann, aber auch einen Einblick in meinen "Coding Style" und meine technischen Fähigkeiten geben kann.
Ich habe das Thema "Chat with your data" ausgewählt, weil ich es passend für den Themenbereich Daten- und Plattformmanagement fand. Eine einfache Schnittstelle in natürlicher Sprache, mit der auch Kolleginnen und Kollegen ohne SQL-Programmierkenntnisse oder komplexe Benutzeroberflächen relevante Daten abrufen könen, ist sicherlich sehr hilfreich und kann die Effizienz und Nutzung von Daten-Tools im Unternehmen verbessern.
Ich habe diese App in Gänze selbst implementiert, von der generation des Datensatzes aus öffentlich verfügbaren Quellen bis hin zum finalen Deployment auf der Microsoft Azure Cloud. Alle Details sind in diesem Repository enthalten.
Die Applikation kann unter folgendem Link abgerufen werden: [Link](https://avc-app-ahbhc8hagheua3bx.germanywestcentral-01.azurewebsites.net/)
Benutzername und Passwort lasse ich über die Bewerbungsunterlagen zukommen. Gleiches gilt für die Umgebungs-Variablen, die benötigt werden, um den Code auch lokal laufen zu lassen.
## Running the Application
The app is deployed on an azure App Service instance (see Link above), but can also be run locally. To do this, several environment variables need to be set in order for APIs and authentication to work properly. These will be sent via my application documents.
To run this app, install poetry (see the [official documentation](https://python-poetry.org/docs/) for details). Then, simply run the following commands in a shell of your choice:
```
poetry install
poetry shell
```
Now, you should be in a shell with all the required packages installed. This code connects to Azure SQL using `pyodbc` and therefore, the Microsoft ODBC driver (version 18) must be installed. To do this, follow the [official documentation](https://learn.microsoft.com/en-us/sql/connect/odbc/download-odbc-driver-for-sql-server?view=sql-server-ver16) again. Once this is done, make sure the mentioned environment variables have been exported and then run:
```
cd app
gunicorn app:server -b 0.0.0.0:8000
```
The server should then start and can be accessed via browser at `0.0.0.0:8000`.
## General Structure of the app:
The main structure of the `Dash` app starts with a text input field, where the question prompt can be inserted. Once the submit button is klicked, the user message, together with a long and somewhat optimized system prompt, is sent via the OpenAI API to a generic GPT-4o model.
The model is prompted to give back its answer as a `JSON`-encoded string. It includes a summary in natural language and a SQL query. The query is run on the Azure SQL Database using `pyodbc`. The summary as well as the query itself are shown in an output text field to the user. The query result is read into a `pandas` dataframe, which is then displayed as an interactive table.
Below this main section, there is a "control field", which can be used to manually input SQL queries for comparison. It is also possible to copy/paste the SQL output of the model into this field to check its result.
The questions that can be asked of course depend on the data, which is described in detail in the following sections. Additionally, some example prompts are provided in the web application directly.
## Data sources
@@ -41,3 +83,17 @@ Meters have a signature, which also works like an ID. It is a string in the form
The `Addresses` table contains street name, house number, city, zip and geo information.
Finally, the `Readings` table stores the data of the meter values read by the customers. Each reading is done by a unique customer from a unique meter and contains the date and the value that was read off the meter.
## Cloud Infrastructure
The Infrastructure is best described by the image below:
<p align="center">
<img src="./assets/cloud_structure.svg" alt="A schematic of the cloud app structure" width="80%">
</p>
The App Service needs several secrets that it receives from an Azure Key Vault by authentication via role-based access control (RBAC) as a System Managed Identity. It also authenticates via the same method with the Azure SQL Server and Database. Using the secrets provided by the key vault, the App Service can authenticate users and query the AzureOpenAI resource using the API key, as well as connect to the SQL database to run queries.
Note that due to too strict rate limits, a regular OpenAI connection is used rather than an azure OpenAI instance, but the principle is the same.

833
assets/cloud_structure.svg Normal file
View File

@@ -0,0 +1,833 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="205.71643mm"
height="141.50673mm"
viewBox="0 0 205.71643 141.50673"
version="1.1"
id="svg5"
xml:space="preserve"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
sodipodi:docname="drawing.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="1.2938725"
inkscape:cx="454.06329"
inkscape:cy="314.94603"
inkscape:window-width="2560"
inkscape:window-height="1412"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g4098" /><defs
id="defs2"><marker
style="overflow:visible"
id="TriangleStart"
refX="0"
refY="0"
orient="auto-start-reverse"
inkscape:stockid="TriangleStart"
markerWidth="3"
markerHeight="3"
viewBox="0 0 5.3244081 6.1553851"
inkscape:isstock="true"
inkscape:collect="always"
preserveAspectRatio="none"
markerUnits="userSpaceOnUse"><path
transform="scale(0.5)"
style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path135" /></marker><linearGradient
id="b"
x1="4.4000001"
y1="11.48"
x2="4.3699999"
y2="7.5300002"
gradientUnits="userSpaceOnUse"><stop
offset="0"
stop-color="#ccc"
id="stop9" /><stop
offset="1"
stop-color="#fcfcfc"
id="stop11" /></linearGradient><linearGradient
id="c"
x1="10.13"
y1="15.45"
x2="10.13"
y2="11.9"
gradientUnits="userSpaceOnUse"><stop
offset="0"
stop-color="#ccc"
id="stop14" /><stop
offset="1"
stop-color="#fcfcfc"
id="stop16" /></linearGradient><linearGradient
id="d"
x1="14.18"
y1="11.15"
x2="14.18"
y2="7.3800001"
gradientUnits="userSpaceOnUse"><stop
offset="0"
stop-color="#ccc"
id="stop19" /><stop
offset="1"
stop-color="#fcfcfc"
id="stop21" /></linearGradient><radialGradient
id="a"
cx="13428.81"
cy="3518.8601"
r="56.669998"
gradientTransform="matrix(0.15,0,0,0.15,-2005.33,-518.83)"
gradientUnits="userSpaceOnUse"><stop
offset=".18"
stop-color="#5ea0ef"
id="stop24" /><stop
offset="1"
stop-color="#0078d4"
id="stop26" /></radialGradient><linearGradient
inkscape:collect="always"
xlink:href="#b"
id="linearGradient186"
gradientUnits="userSpaceOnUse"
x1="4.4000001"
y1="11.48"
x2="4.3699999"
y2="7.5300002" /><linearGradient
inkscape:collect="always"
xlink:href="#c"
id="linearGradient188"
gradientUnits="userSpaceOnUse"
x1="10.13"
y1="15.45"
x2="10.13"
y2="11.9" /><linearGradient
inkscape:collect="always"
xlink:href="#b"
id="linearGradient190"
gradientUnits="userSpaceOnUse"
x1="4.4000001"
y1="11.48"
x2="4.3699999"
y2="7.5300002" /><linearGradient
inkscape:collect="always"
xlink:href="#c"
id="linearGradient192"
gradientUnits="userSpaceOnUse"
x1="10.13"
y1="15.45"
x2="10.13"
y2="11.9" /><linearGradient
id="a-3"
x1="8.6370001"
y1="-1.9910001"
x2="8.6370001"
y2="16.739"
gradientUnits="userSpaceOnUse"><stop
offset="0"
stop-color="#5ea0ef"
id="stop248" /><stop
offset="1"
stop-color="#0078d4"
id="stop250" /></linearGradient><linearGradient
id="b-6"
x1="12.96"
y1="8.5609999"
x2="12.96"
y2="6.1409998"
gradientTransform="matrix(1,0,0,-1,0,20)"
gradientUnits="userSpaceOnUse"><stop
offset="0"
stop-color="#333132"
id="stop253" /><stop
offset="1"
stop-color="#5b5a5c"
id="stop255" /></linearGradient><radialGradient
id="a-7"
cx="9"
cy="9"
r="8.5"
gradientUnits="userSpaceOnUse"><stop
offset=".18"
stop-color="#5ea0ef"
id="stop302" /><stop
offset=".56"
stop-color="#5c9fee"
id="stop304" /><stop
offset=".69"
stop-color="#559ced"
id="stop306" /><stop
offset=".78"
stop-color="#4a97e9"
id="stop308" /><stop
offset=".86"
stop-color="#3990e4"
id="stop310" /><stop
offset=".93"
stop-color="#2387de"
id="stop312" /><stop
offset=".99"
stop-color="#087bd6"
id="stop314" /><stop
offset="1"
stop-color="#0078d4"
id="stop316" /></radialGradient><radialGradient
id="b-5"
cx="38.950001"
cy="182.07001"
r="9.8800001"
gradientTransform="matrix(0.94,0,0,0.94,-28.71,-163.24)"
gradientUnits="userSpaceOnUse"><stop
offset=".27"
stop-color="#ffd70f"
id="stop319" /><stop
offset=".49"
stop-color="#ffcb12"
id="stop321" /><stop
offset=".88"
stop-color="#feac19"
id="stop323" /><stop
offset="1"
stop-color="#fea11b"
id="stop325" /></radialGradient><linearGradient
id="a-35"
x1="13.25"
y1="13.02"
x2="8.6199999"
y2="4.25"
gradientUnits="userSpaceOnUse"><stop
offset="0"
stop-color="#1988d9"
id="stop368" /><stop
offset=".9"
stop-color="#54aef0"
id="stop370" /></linearGradient><linearGradient
id="b-62"
x1="11.26"
y1="10.47"
x2="14.46"
y2="15.99"
gradientUnits="userSpaceOnUse"><stop
offset=".1"
stop-color="#54aef0"
id="stop373" /><stop
offset=".29"
stop-color="#4fabee"
id="stop375" /><stop
offset=".51"
stop-color="#41a2e9"
id="stop377" /><stop
offset=".74"
stop-color="#2a93e0"
id="stop379" /><stop
offset=".88"
stop-color="#1988d9"
id="stop381" /></linearGradient><marker
style="overflow:visible"
id="TriangleStart-6"
refX="0"
refY="0"
orient="auto-start-reverse"
inkscape:stockid="TriangleStart"
markerWidth="3"
markerHeight="3"
viewBox="0 0 5.3244081 6.1553851"
inkscape:isstock="true"
inkscape:collect="always"
preserveAspectRatio="none"
markerUnits="userSpaceOnUse"><path
transform="scale(0.5)"
style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path135-0" /></marker><marker
style="overflow:visible"
id="TriangleStart-6-1"
refX="0"
refY="0"
orient="auto-start-reverse"
inkscape:stockid="TriangleStart"
markerWidth="3"
markerHeight="3"
viewBox="0 0 5.3244081 6.1553851"
inkscape:isstock="true"
inkscape:collect="always"
preserveAspectRatio="none"
markerUnits="userSpaceOnUse"><path
transform="scale(0.5)"
style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path135-0-8" /></marker><radialGradient
id="b-0"
cx="9.3599997"
cy="10.57"
r="7.0700002"
gradientUnits="userSpaceOnUse"><stop
offset="0"
stop-color="#f2f2f2"
id="stop2774" /><stop
offset=".58"
stop-color="#eee"
id="stop2776" /><stop
offset="1"
stop-color="#e6e6e6"
id="stop2778" /></radialGradient><linearGradient
id="a-2"
x1="2.5899999"
y1="10.16"
x2="15.41"
y2="10.16"
gradientUnits="userSpaceOnUse"><stop
offset="0"
stop-color="#005ba1"
id="stop2781" /><stop
offset=".07"
stop-color="#0060a9"
id="stop2783" /><stop
offset=".36"
stop-color="#0071c8"
id="stop2785" /><stop
offset=".52"
stop-color="#0078d4"
id="stop2787" /><stop
offset=".64"
stop-color="#0074cd"
id="stop2789" /><stop
offset=".82"
stop-color="#006abb"
id="stop2791" /><stop
offset="1"
stop-color="#005ba1"
id="stop2793" /></linearGradient><style
id="style2849">.cls-1{stroke-width:0px;}</style><marker
style="overflow:visible"
id="TriangleStart-6-1-3"
refX="0"
refY="0"
orient="auto-start-reverse"
inkscape:stockid="TriangleStart"
markerWidth="3"
markerHeight="3"
viewBox="0 0 5.3244081 6.1553851"
inkscape:isstock="true"
inkscape:collect="always"
preserveAspectRatio="none"
markerUnits="userSpaceOnUse"><path
transform="scale(0.5)"
style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path135-0-8-7" /></marker><marker
style="overflow:visible"
id="TriangleStart-6-1-3-2"
refX="0"
refY="0"
orient="auto-start-reverse"
inkscape:stockid="TriangleStart"
markerWidth="3"
markerHeight="3"
viewBox="0 0 5.3244081 6.1553851"
inkscape:isstock="true"
inkscape:collect="always"
preserveAspectRatio="none"
markerUnits="userSpaceOnUse"><path
transform="scale(0.5)"
style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path135-0-8-7-8" /></marker><marker
style="overflow:visible"
id="TriangleStart-61"
refX="0"
refY="0"
orient="auto-start-reverse"
inkscape:stockid="TriangleStart"
markerWidth="3"
markerHeight="3"
viewBox="0 0 5.3244081 6.1553851"
inkscape:isstock="true"
inkscape:collect="always"
preserveAspectRatio="none"
markerUnits="userSpaceOnUse"><path
transform="scale(0.5)"
style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path135-2" /></marker><marker
style="overflow:visible"
id="TriangleStart-61-3"
refX="0"
refY="0"
orient="auto-start-reverse"
inkscape:stockid="TriangleStart"
markerWidth="3"
markerHeight="3"
viewBox="0 0 5.3244081 6.1553851"
inkscape:isstock="true"
inkscape:collect="always"
preserveAspectRatio="none"
markerUnits="userSpaceOnUse"><path
transform="scale(0.5)"
style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
d="M 5.77,0 -2.88,5 V -5 Z"
id="path135-2-1" /></marker><linearGradient
id="a-35-1"
x1="13.25"
y1="13.02"
x2="8.6199999"
y2="4.25"
gradientUnits="userSpaceOnUse"><stop
offset="0"
stop-color="#1988d9"
id="stop368-0" /><stop
offset=".9"
stop-color="#54aef0"
id="stop370-6" /></linearGradient><linearGradient
id="b-62-3"
x1="11.26"
y1="10.47"
x2="14.46"
y2="15.99"
gradientUnits="userSpaceOnUse"><stop
offset=".1"
stop-color="#54aef0"
id="stop373-2" /><stop
offset=".29"
stop-color="#4fabee"
id="stop375-0" /><stop
offset=".51"
stop-color="#41a2e9"
id="stop377-6" /><stop
offset=".74"
stop-color="#2a93e0"
id="stop379-1" /><stop
offset=".88"
stop-color="#1988d9"
id="stop381-5" /></linearGradient></defs><g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(59.915421,-40.693409)"><rect
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.211931;stroke-dasharray:none;stroke-opacity:1"
id="rect3947"
width="205.71643"
height="141.50673"
x="-59.915421"
y="40.693409"
rx="2.0407324" /><g
id="g4098"
transform="translate(6.3180748,-0.67768603)"><g
id="g420"
transform="matrix(0.46907283,0,0,0.46907283,79.658632,99.030566)"><path
fill="#50e6ff"
d="M 1.01,10.19 8.93,15.33 16.99,10.17 18,11.35 8.93,17.19 0,11.35 Z"
id="path386" /><path
fill="#ffffff"
d="M 1.61,9.53 8.93,0.81 16.4,9.54 8.93,14.26 Z"
id="path388" /><path
fill="#50e6ff"
d="M 8.93,0.81 V 14.26 L 1.61,9.53 Z"
id="path390" /><path
fill="url(#a)"
d="M 8.93,0.81 V 14.26 L 16.4,9.54 Z"
id="path392"
style="fill:url(#a-35)" /><path
fill="#53b1e0"
d="M 8.93,7.76 16.4,9.54 8.93,14.26 Z"
id="path394" /><path
fill="#9cebff"
d="M 8.93,14.26 1.61,9.53 8.93,7.76 Z"
id="path396" /><path
fill="url(#b)"
d="M 8.93,17.19 18,11.35 16.99,10.17 8.93,15.33 Z"
id="path398"
style="fill:url(#b-62)" /></g><g
id="g420-5"
transform="matrix(0.46907283,0,0,0.46907283,21.339532,75.835983)"><path
fill="#50e6ff"
d="M 1.01,10.19 8.93,15.33 16.99,10.17 18,11.35 8.93,17.19 0,11.35 Z"
id="path386-4" /><path
fill="#ffffff"
d="M 1.61,9.53 8.93,0.81 16.4,9.54 8.93,14.26 Z"
id="path388-7" /><path
fill="#50e6ff"
d="M 8.93,0.81 V 14.26 L 1.61,9.53 Z"
id="path390-6" /><path
fill="url(#a)"
d="M 8.93,0.81 V 14.26 L 16.4,9.54 Z"
id="path392-5"
style="fill:url(#a-35-1)" /><path
fill="#53b1e0"
d="M 8.93,7.76 16.4,9.54 8.93,14.26 Z"
id="path394-6" /><path
fill="#9cebff"
d="M 8.93,14.26 1.61,9.53 8.93,7.76 Z"
id="path396-9" /><path
fill="url(#b)"
d="M 8.93,17.19 18,11.35 16.99,10.17 8.93,15.33 Z"
id="path398-3"
style="fill:url(#b-62-3)" /></g><g
id="g80"
transform="matrix(0.88512168,0,0,0.88512168,35.408986,105.84146)"><path
d="M 14.21,15.72 A 8.5030877,8.5030877 0 0 1 3.79,2.28 L 3.88,2.22 a 8.5,8.5 0 0 1 10.33,13.5"
fill="url(#a)"
id="path31"
style="fill:url(#a)" /><path
d="M 6.69,7.23 A 13,13 0 0 1 15.6,3.65 8.47,8.47 0 0 0 14.11,2.21 14.34,14.34 0 0 0 9.42,3.31 12.54,12.54 0 0 0 5.34,6.13 2.76,2.76 0 0 1 6.69,7.23 Z m -4.21,3.42 a 17.86,17.86 0 0 0 -0.83,2.62 7.82,7.82 0 0 0 0.62,0.92 c 0.18,0.23 0.35,0.44 0.55,0.65 A 17.94,17.94 0 0 1 3.9,11.37 2.76,2.76 0 0 1 2.48,10.65 Z"
fill="#ffffff"
opacity="0.6"
id="path33" /><path
d="M 3.46,6.11 A 12,12 0 0 1 2.77,3.17 8.15,8.15 0 0 0 1.67,4.62 12.69,12.69 0 0 0 2.24,7 2.69,2.69 0 0 1 3.46,6.11 Z"
fill="#f2f2f2"
opacity="0.55"
id="path35" /><circle
cx="4.3800001"
cy="8.6800003"
r="2.73"
fill="url(#b)"
id="circle37"
style="fill:url(#linearGradient186)" /><path
d="M 8.36,13.67 A 1.77,1.77 0 0 1 8.9,12.4 11.88,11.88 0 0 1 6.37,10.54 2.74,2.74 0 0 1 4.88,11.37 13.1,13.1 0 0 0 6.33,12.65 12.12,12.12 0 0 0 8.38,13.9 1.79,1.79 0 0 1 8.36,13.67 Z m 6.3,0.21 a 12,12 0 0 1 -2.76,-0.32 0.41,0.41 0 0 1 0,0.11 1.75,1.75 0 0 1 -0.51,1.24 13.69,13.69 0 0 0 3.42,0.24 8.21,8.21 0 0 0 1.19,-1.34 11.5,11.5 0 0 1 -1.34,0.07 z"
fill="#f2f2f2"
opacity="0.55"
id="path39" /><circle
cx="10.13"
cy="13.67"
r="1.78"
fill="url(#c)"
id="circle41"
style="fill:url(#linearGradient188)" /><path
d="m 12.32,8.93 a 1.83,1.83 0 0 1 0.61,-1 25.5,25.5 0 0 1 -4.46,-4.14 16.91,16.91 0 0 1 -2,-2.92 7.64,7.64 0 0 0 -1.09,0.42 18.14,18.14 0 0 0 2.15,3.18 26.44,26.44 0 0 0 4.79,4.46 z"
fill="#f2f2f2"
opacity="0.7"
id="path43" /><circle
cx="14.18"
cy="9.2700005"
r="1.89"
fill="url(#d)"
id="circle45"
style="fill:url(#d)" /><path
d="M 17.35,10.54 17,10.37 16.7,10.21 H 16.64 L 16.38,10 H 16.31 L 16,9.8 a 1.76,1.76 0 0 1 -0.64,0.92 c 0.12,0.08 0.25,0.15 0.38,0.22 l 0.08,0.05 0.35,0.19 0.86,0.45 a 8.63,8.63 0 0 0 0.29,-1.11 z"
fill="#f2f2f2"
opacity="0.55"
id="path47" /><circle
cx="4.3800001"
cy="8.6800003"
r="2.73"
fill="url(#b)"
id="circle49"
style="fill:url(#linearGradient190)" /><circle
cx="10.13"
cy="13.67"
r="1.78"
fill="url(#c)"
id="circle51"
style="fill:url(#linearGradient192)" /></g><text
xml:space="preserve"
style="font-size:3.175px;fill:#000000;stroke-width:0.264583"
x="30.089916"
y="127.11237"
id="text476"><tspan
sodipodi:role="line"
id="tspan474"
style="stroke-width:0.264583"
x="30.089916"
y="127.11237">Azure App Service</tspan></text><rect
style="fill:none;stroke:#000000;stroke-width:0.212;stroke-dasharray:none;stroke-opacity:1"
id="rect580"
width="29.855467"
height="5.8279505"
x="28.4305"
y="123.40941"
ry="0"
rx="1.7381607" /><g
id="g3945"
transform="translate(-2.6072396)"><text
xml:space="preserve"
style="font-size:3.175px;fill:#000000;stroke-width:0.264583"
x="-47.31797"
y="127.11237"
id="text476-4"><tspan
sodipodi:role="line"
id="tspan474-5"
style="stroke-width:0.264583"
x="-47.31797"
y="127.11237">Azure OpenAI Service</tspan></text><rect
style="fill:none;stroke:#000000;stroke-width:0.211931;stroke-dasharray:none;stroke-opacity:1"
id="rect580-25"
width="35.052578"
height="5.8105807"
x="-48.897827"
y="123.41809"
ry="0"
rx="2.0407324" /></g><g
id="g3534"
transform="translate(3.6390738,4.2942795)"><text
xml:space="preserve"
style="font-size:3.175px;fill:#000000;stroke-width:0.264583"
x="26.067286"
y="67.350319"
id="text476-7"><tspan
sodipodi:role="line"
id="tspan474-8"
style="stroke-width:0.264583"
x="26.067286"
y="67.350319">Azure SQL Server</tspan></text><rect
style="fill:none;stroke:#000000;stroke-width:0.212;stroke-dasharray:none;stroke-opacity:1"
id="rect580-4"
width="29.855467"
height="5.8279505"
x="23.925272"
y="63.647358"
ry="0"
rx="1.7381607" /></g><g
id="g366"
transform="matrix(0.88358824,0,0,0.88358824,108.64333,105.87067)"><path
d="M 9,0.5 A 8.5,8.5 0 1 0 17.5,9 8.51,8.51 0 0 0 9,0.5 Z M 9,16.34 A 7.34,7.34 0 1 1 16.34,9 7.34,7.34 0 0 1 9,16.34 Z"
fill="url(#a)"
id="path330"
style="fill:url(#a-7)" /><circle
cx="9"
cy="9"
r="7.3400002"
fill="#ffffff"
id="circle332" /><path
d="m 13.44,7.33 a 1.84,1.84 0 0 0 0,-2.59 L 10.29,1.58 a 1.83,1.83 0 0 0 -2.58,0 L 4.56,4.74 a 1.84,1.84 0 0 0 0,2.59 L 7.18,10 a 0.51,0.51 0 0 1 0.15,0.36 v 4.88 a 0.63,0.63 0 0 0 0.18,0.44 l 1.2,1.2 a 0.41,0.41 0 0 0 0.58,0 l 1.16,-1.16 0.68,-0.68 a 0.25,0.25 0 0 0 0,-0.34 l -0.49,-0.49 a 0.27,0.27 0 0 1 0,-0.37 l 0.49,-0.49 a 0.25,0.25 0 0 0 0,-0.34 l -0.49,-0.49 a 0.27,0.27 0 0 1 0,-0.37 l 0.49,-0.49 a 0.25,0.25 0 0 0 0,-0.34 L 10.45,10.63 V 10.38 Z M 9,2.35 A 1.035,1.035 0 0 1 9,4.42 1.035,1.035 0 1 1 9,2.35 Z"
fill="url(#b)"
id="path334"
style="fill:url(#b-5)" /><path
d="m 8.18,15.3 a 0.23,0.23 0 0 0 0.38,-0.17 v -4 a 0.24,0.24 0 0 0 -0.11,-0.2 0.22,0.22 0 0 0 -0.34,0.2 v 4 a 0.28,0.28 0 0 0 0.07,0.17 z"
fill="#ff9300"
opacity="0.75"
id="path336" /><rect
x="6.48"
y="5.79"
width="5.1700001"
height="0.61000001"
rx="0.28"
fill="#ff9300"
opacity="0.75"
id="rect338" /><rect
x="6.48"
y="6.7800002"
width="5.1700001"
height="0.61000001"
rx="0.28"
fill="#ff9300"
opacity="0.75"
id="rect340" /></g><text
xml:space="preserve"
style="font-size:3.175px;fill:#000000;stroke-width:0.264583"
x="109.63284"
y="127.12175"
id="text476-0"><tspan
sodipodi:role="line"
id="tspan474-9"
style="stroke-width:0.264583"
x="109.63284"
y="127.12175">Key Vault</tspan></text><text
xml:space="preserve"
style="font-size:3.175px;fill:#000000;stroke-width:0.264583"
x="60.967903"
y="111.0274"
id="text476-0-2"><tspan
sodipodi:role="line"
id="tspan474-9-6"
style="stroke-width:0.264583"
x="60.967903"
y="111.0274">Authorize as Managed Identity</tspan></text><text
xml:space="preserve"
style="font-size:3.175px;fill:#000000;stroke-width:0.264583"
x="61.783878"
y="124.03043"
id="text476-0-2-9"><tspan
sodipodi:role="line"
id="tspan474-9-6-2"
style="stroke-width:0.264583"
x="61.783878"
y="124.03043">Get login secrets and API keys</tspan></text><text
xml:space="preserve"
style="font-size:3.175px;fill:#000000;stroke-width:0.264583"
x="-12.76177"
y="124.03043"
id="text476-0-2-9-7"><tspan
sodipodi:role="line"
id="tspan474-9-6-2-3"
style="stroke-width:0.264583"
x="-12.76177"
y="124.03043">Receive LLM response</tspan></text><text
xml:space="preserve"
style="font-size:3.175px;fill:#000000;stroke-width:0.264583"
x="-20.84815"
y="111.0274"
id="text476-0-2-9-9"><tspan
sodipodi:role="line"
id="tspan474-9-6-2-2"
style="stroke-width:0.264583"
x="-20.84815"
y="111.0274">Use API key to send user prompt</tspan></text><rect
style="fill:none;stroke:#000000;stroke-width:0.211667;stroke-dasharray:none;stroke-opacity:1"
id="rect580-3"
width="16.318039"
height="5.8825364"
x="108.4366"
y="123.35499"
ry="0"
rx="0.9500227" /><g
id="g1401"
transform="translate(0.91374202,6.3500003)"><g
id="g300"
transform="matrix(0.86702599,0,0,0.86702599,34.645593,141.75549)"><path
d="m 7.43,8.178 2.589,-1.573 7.255,2.731 A 3.664,3.664 0 0 0 16.23,7.49 L 16.22,7.44 A 4.194,4.194 0 0 0 14,6.32 4.91,4.91 0 0 0 8.9,1.62 5.071,5.071 0 0 0 4.06,4.91 4.621,4.621 0 0 0 0,9.39 4.73,4.73 0 0 0 4.89,13.93 h 2.54 z"
fill="url(#a)"
id="path260"
style="fill:url(#a-3)" /><path
fill="#767676"
d="m 10.07,7.159 0.01,4.28 7.91,1.68 v -2.98 z"
id="path262" /><path
fill="#999999"
d="m 10.07,7.159 -2.14,1.3 v 3.98 l 2.15,-1"
id="path264" /><path
fill="#a3a3a3"
d="m 13.68,11.499 0.72,0.2 v -2.33 l -0.72,-0.25 z m -0.72,-2.61 -0.72,-0.26 v 2.49 l 0.72,0.2 z m 2.16,3 0.7,0.19 0.02,-2.22 -0.72,-0.24 z m -4.31,-1.14 0.72,0.18 v -2.53 l -0.72,-0.24 z m 6.46,-0.4 -0.72,-0.25 v 2.17 l 0.72,0.2 z"
id="path266" /><path
d="M 8.66,11.369 8.3,11.579 V 8.749 L 8.66,8.559 Z M 9.37,8.149 9,8.389 v 2.75 l 0.37,-0.2 z"
fill="#b3b3b3"
id="path268" /><path
fill="url(#b)"
d="m 17.99,13.119 -2.16,0.74 -7.9,-1.42 2.15,-1 z"
id="path270"
style="fill:url(#b-6)" /><path
fill="#767676"
d="m 17.99,16.169 -7.95,1.51 0.04,-5.59 7.91,1.47 z"
id="path272" /><path
fill="#a3a3a3"
d="m 10.81,16.759 v -3.55 l 0.72,0.09 v 3.34 z m 2.15,-0.36 -0.72,0.13 v -3.14 l 0.72,0.11 z m 0.72,-0.11 v -2.72 l 0.72,0.09 v 2.5 z m 2.15,-0.38 -0.71,0.13 v -2.29 l 0.71,0.11 z m 1.46,-0.23 -0.74,0.13 v -1.88 l 0.69,0.09 z"
id="path274" /><path
d="m 7.93,16.4 v -3.26 l 2.16,-1 v 5.6 z"
fill="#999999"
id="path276" /><path
d="m 8.61,16.389 -0.32,-0.16 v -2.76 l 0.32,-0.15 z M 9.38,12.939 9,13.129 v 3.48 l 0.37,0.19 v -3.86 z"
fill="#b3b3b3"
id="path278" /></g><g
id="g1355"><g
id="g1360"><text
xml:space="preserve"
style="font-size:3.175px;fill:#000000;stroke-width:0.264583"
x="28.517359"
y="164.13605"
id="text476-9"><tspan
sodipodi:role="line"
id="tspan474-1"
style="stroke-width:0.264583"
x="28.517359"
y="164.13605">Container Registry</tspan></text><rect
style="fill:none;stroke:#000000;stroke-width:0.212196;stroke-dasharray:none;stroke-opacity:1"
id="rect580-2"
width="29.855467"
height="5.8279505"
x="27.516758"
y="160.43309"
ry="0"
rx="1.7381607" /></g></g></g><path
style="fill:none;stroke:#000000;stroke-width:1.012;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#TriangleStart)"
d="m 43.358233,133.22491 v 11.24692"
id="path2004" /><g
id="g3538"
transform="translate(0.08460633)"><path
style="fill:none;stroke:#000000;stroke-width:1.012;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#TriangleStart-61)"
d="M 40.795655,103.34741 V 77.479487"
id="path2004-9"
sodipodi:nodetypes="cc" /><path
style="fill:none;stroke:#000000;stroke-width:1.012;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#TriangleStart-61-3)"
d="M 44.885445,75.478661 V 101.34658"
id="path2004-9-9"
sodipodi:nodetypes="cc" /></g><path
style="fill:none;stroke:#000000;stroke-width:1.012;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#TriangleStart-6)"
d="M 60.852248,113.5814 H 104.37833"
id="path2004-6"
sodipodi:nodetypes="cc" /><path
style="fill:none;stroke:#000000;stroke-width:1.012;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#TriangleStart-6-1)"
d="M 106.90833,118.27922 H 62.853073"
id="path2004-6-7"
sodipodi:nodetypes="cc" /><path
style="fill:none;stroke:#000000;stroke-width:1.012;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#TriangleStart-6-1-3)"
d="M 28.459543,113.5814 H -18.241548"
id="path2004-6-7-5"
sodipodi:nodetypes="cc" /><path
style="fill:none;stroke:#000000;stroke-width:1.012;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#TriangleStart-6-1-3-2)"
d="M -20.242376,118.27922 H 26.458715"
id="path2004-6-7-5-9"
sodipodi:nodetypes="cc" /><text
xml:space="preserve"
style="font-size:3.175px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.012;stroke-dasharray:none;stroke-opacity:1"
x="45.089935"
y="140.67429"
id="text2324"><tspan
sodipodi:role="line"
id="tspan2322"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.012"
x="45.089935"
y="140.67429">Deploy image</tspan></text><g
id="g2829"
transform="matrix(0.88358824,0,0,0.88358824,34.539785,51.089986)"><path
d="m 9,5.14 c -3.54,0 -6.41,-1 -6.41,-2.32 v 12.36 c 0,1.27 2.82,2.3 6.32,2.32 H 9 c 3.54,0 6.41,-1 6.41,-2.32 V 2.82 c 0,1.29 -2.87,2.32 -6.41,2.32 z"
fill="url(#a)"
id="path2798"
style="fill:url(#a-2)" /><path
d="M 15.41,2.82 C 15.41,4.11 12.54,5.14 9,5.14 5.46,5.14 2.59,4.14 2.59,2.82 2.59,1.5 5.46,0.5 9,0.5 c 3.54,0 6.41,1 6.41,2.32"
fill="#e8e8e8"
id="path2800" /><path
d="M 13.92,2.63 C 13.92,3.45 11.71,4.11 9,4.11 6.29,4.11 4.08,3.45 4.08,2.63 4.08,1.81 6.29,1.16 9,1.16 c 2.71,0 4.92,0.66 4.92,1.47"
fill="#50e6ff"
id="path2802" /><path
d="M 9,3 A 11.55,11.55 0 0 0 5.11,3.57 11.42,11.42 0 0 0 9,4.11 11.15,11.15 0 0 0 12.89,3.53 11.84,11.84 0 0 0 9,3 Z"
fill="#198ab3"
id="path2804" /><path
d="M 12.9,11.4 V 8 H 12 v 4.13 h 2.46 V 11.4 Z M 5.76,9.73 A 1.83,1.83 0 0 1 5.25,9.42 0.44,0.44 0 0 1 5.13,9.1 0.34,0.34 0 0 1 5.28,8.8 0.68,0.68 0 0 1 5.7,8.68 1.62,1.62 0 0 1 6.7,8.97 V 8.11 A 2.58,2.58 0 0 0 5.7,7.95 1.64,1.64 0 0 0 4.61,8.29 1.08,1.08 0 0 0 4.19,9.18 c 0,0.51 0.32,0.91 1,1.21 A 2.88,2.88 0 0 1 5.81,10.75 0.42,0.42 0 0 1 5.96,11.07 0.38,0.38 0 0 1 5.8,11.38 0.81,0.81 0 0 1 5.35,11.49 1.66,1.66 0 0 1 4.26,11.07 V 12 A 2.17,2.17 0 0 0 5.33,12.24 1.88,1.88 0 0 0 6.51,11.91 1.08,1.08 0 0 0 6.84,11 1.05,1.05 0 0 0 6.59,10.3 2.42,2.42 0 0 0 5.76,9.73 Z M 11,11.32 A 2.34,2.34 0 0 0 11.33,10.06 2.32,2.32 0 0 0 11,9 1.81,1.81 0 0 0 10.3,8.25 2,2 0 0 0 9.3,7.99 2.11,2.11 0 0 0 8.22,8.26 1.86,1.86 0 0 0 7.49,9 a 2.46,2.46 0 0 0 -0.26,1.14 2.26,2.26 0 0 0 0.24,1 1.76,1.76 0 0 0 0.69,0.74 2.06,2.06 0 0 0 1,0.3 l 0.86,1 h 1.21 L 10,12.08 a 1.79,1.79 0 0 0 1,-0.76 z m -1,-0.25 a 0.94,0.94 0 0 1 -0.76,0.35 0.92,0.92 0 0 1 -0.76,-0.36 1.52,1.52 0 0 1 -0.29,-1 1.53,1.53 0 0 1 0.29,-1 1,1 0 0 1 0.78,-0.37 0.87,0.87 0 0 1 0.75,0.37 1.62,1.62 0 0 1 0.27,1 1.46,1.46 0 0 1 -0.28,1.01 z"
fill="url(#b)"
id="path2806"
style="fill:url(#b-0)" /></g><path
class="cls-1"
d="m -27.542965,112.20032 c 0.340614,-1.02184 0.223608,-2.14248 -0.322414,-3.07332 -0.819032,-1.42747 -2.467499,-2.16069 -4.076963,-1.81487 -0.715029,-0.80604 -1.744671,-1.26626 -2.823714,-1.25846 -1.645866,-0.003 -3.104525,1.05564 -3.611545,2.6209 -1.055642,0.21582 -1.968279,0.87884 -2.501301,1.81488 -0.826833,1.42225 -0.637026,3.21633 0.465418,4.43838 -0.340613,1.02183 -0.223608,2.14248 0.322414,3.07331 0.819033,1.42746 2.467499,2.16069 4.076963,1.81488 0.71503,0.80603 1.744671,1.26625 2.823714,1.25845 1.645867,0.005 3.104526,-1.05564 3.611546,-2.6209 1.055642,-0.21582 1.968279,-0.87884 2.501301,-1.81487 0.824233,-1.42227 0.637025,-3.21634 -0.465419,-4.43578 v 0 z m -5.644828,7.89131 c -0.657826,0 -1.297452,-0.22881 -1.801872,-0.65262 0.0234,-0.013 0.0624,-0.0338 0.0884,-0.0494 l 2.990121,-1.72648 c 0.153406,-0.0858 0.24701,-0.24961 0.24701,-0.42641 v -4.21737 l 1.263651,0.73063 c 0.013,0.008 0.0234,0.0208 0.0234,0.0338 v 3.49193 c 0,1.55227 -1.25845,2.81072 -2.813313,2.81592 v 0 z m -6.047843,-2.58451 c -0.330213,-0.56941 -0.449818,-1.23764 -0.335414,-1.88507 0.0208,0.013 0.0598,0.0364 0.08841,0.052 l 2.99012,1.72648 c 0.150806,0.0884 0.340614,0.0884 0.49142,0 l 3.650547,-2.10869 v 1.45866 c 0,0.0156 -0.0052,0.0286 -0.0182,0.039 l -3.023922,1.74467 c -1.346854,0.77483 -3.065523,0.31462 -3.845554,-1.02964 v 0 z m -0.787832,-6.52885 c 0.327613,-0.57202 0.847635,-1.00624 1.46386,-1.23505 0,0.026 0,0.0702 0,0.104 v 3.45555 c 0,0.1768 0.0936,0.338 0.244409,0.42641 l 3.650547,2.10868 -1.263651,0.73063 c 0,0 -0.0286,0.0104 -0.0416,0.003 l -3.023922,-1.74723 c -1.344254,-0.77743 -1.804473,-2.4987 -1.029642,-3.84294 v 0 z m 10.387419,2.4181 -3.650547,-2.10869 1.263651,-0.73062 c 0,0 0.0286,-0.0104 0.0416,-0.003 l 3.023922,1.74466 c 1.346854,0.77744 1.807072,2.5013 1.029641,3.84556 -0.330213,0.56942 -0.847633,1.00623 -1.463859,1.23245 v -3.55954 c 0,-0.17681 -0.091,-0.33802 -0.244409,-0.42642 v 0 z m 1.25585,-1.89288 c -0.0208,-0.013 -0.0598,-0.0364 -0.08841,-0.052 l -2.990118,-1.72647 c -0.150807,-0.0885 -0.340615,-0.0885 -0.491421,0 l -3.650546,2.10868 v -1.45866 c 0,-0.0156 0.0052,-0.0286 0.0182,-0.039 l 3.023922,-1.74466 c 1.346854,-0.77743 3.068123,-0.31462 3.845555,1.03224 0.327613,0.56942 0.447218,1.23505 0.335413,1.88247 v 0 z m -7.909518,2.6001 -1.263651,-0.73063 c -0.013,-0.008 -0.0234,-0.0208 -0.0234,-0.0338 v -3.49194 c 0,-1.55486 1.261051,-2.81331 2.815914,-2.81331 0.657826,0 1.294852,0.23141 1.799272,0.65262 -0.0234,0.013 -0.0624,0.0338 -0.08841,0.0494 l -2.99012,1.72647 c -0.153406,0.0858 -0.24701,0.24961 -0.24701,0.42642 v 4.21477 c 0,0 0,0 0,0 z m 0.686427,-1.47946 1.627666,-0.93863 1.627665,0.93863 v 1.87728 l -1.627665,0.93864 -1.627666,-0.93864 z"
id="path2853" /><text
xml:space="preserve"
style="font-size:3.175px;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.211667;stroke-dasharray:none;stroke-opacity:1"
x="25.423044"
y="88.543953"
id="text3319"><tspan
sodipodi:role="line"
id="tspan3317"
style="text-align:center;text-anchor:middle;stroke-width:0.211667"
x="25.423044"
y="88.543953">Authorize as</tspan><tspan
sodipodi:role="line"
style="text-align:center;text-anchor:middle;stroke-width:0.211667"
x="25.423044"
y="92.512703"
id="tspan3323">Managed Identity,</tspan><tspan
sodipodi:role="line"
style="text-align:center;text-anchor:middle;stroke-width:0.211667"
x="25.423044"
y="96.481453"
id="tspan3321">send SQL query</tspan></text><text
xml:space="preserve"
style="font-size:3.175px;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.211667;stroke-dasharray:none;stroke-opacity:1"
x="56.64072"
y="92.841316"
id="text3319-5"><tspan
sodipodi:role="line"
style="text-align:center;text-anchor:middle;stroke-width:0.211667"
x="56.64072"
y="92.841316"
id="tspan3321-6">Receive data</tspan></text></g></g></svg>

After

Width:  |  Height:  |  Size: 35 KiB