santanche commited on
Commit
47f370d
·
1 Parent(s): 894bf9a

feat (app): initial setup

Browse files
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ __pycache__/
Dockerfile ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.9
2
+
3
+ RUN useradd -m -u 1000 user
4
+ USER user
5
+ ENV PATH="/home/user/.local/bin:$PATH"
6
+
7
+ WORKDIR /app
8
+
9
+ COPY --chown=user ./requirements.txt requirements.txt
10
+ RUN pip install --no-cache-dir --upgrade -r requirements.txt
11
+
12
+ COPY --chown=user ./app /app
13
+ CMD ["uvicorn", "server_sentiment_analysis:app", "--host", "0.0.0.0", "--port", "7860"]
app/sentiment_analysis.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from transformers import pipeline
2
+
3
+ class SentimentAnalysis:
4
+ def __init__(self):
5
+ # Initialize the sentiment analysis pipeline
6
+ self.pipe = pipeline("text-classification", model="tabularisai/multilingual-sentiment-analysis")
7
+
8
+ def classify(self, text: str):
9
+ # Use the pipeline to classify the input text
10
+ result_set = self.pipe(text)
11
+ result = result_set[0]
12
+ analysis = result["label"].lower()
13
+ result["value"] = "positive" if "positive" in analysis \
14
+ else "negative" if "negative" in analysis \
15
+ else "neutral"
16
+ return result
app/server_sentiment_analysis.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from fastapi.responses import RedirectResponse
3
+ from fastapi.middleware.cors import CORSMiddleware
4
+
5
+ # Import the SentimentAnalysis class
6
+ from sentiment_analysis import SentimentAnalysis
7
+
8
+ app = FastAPI()
9
+
10
+ app.add_middleware(
11
+ CORSMiddleware,
12
+ allow_origins=["http://127.0.0.1:5173","http://localhost:5173"],
13
+ allow_credentials=True,
14
+ allow_methods=["*"],
15
+ allow_headers=["*"],
16
+ )
17
+
18
+ # Create a global instance of SentimentAnalysis
19
+ classifier = SentimentAnalysis()
20
+
21
+ # Redirect root to /docs
22
+ @app.get("/")
23
+ async def redirect_to_docs():
24
+ return RedirectResponse(url="/docs")
25
+
26
+ @app.get("/classify")
27
+ async def classify(text: str):
28
+ try:
29
+ result = classifier.classify(text)
30
+ return result
31
+ except Exception as e:
32
+ raise HTTPException(status_code=500, detail=str(e)) from e
app/static/editor/index.html ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Playground Editor</title>
6
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mundorum/collections@0.3.1/full.min.css">
7
+ <script type="module" src="/app/static/editor/js/editor-rest.js"></script>
8
+ <script type="module">
9
+ import { EditorPg } from '/app/static/editor/js/editor-pg.js'
10
+ window.editorPg = EditorPg.i
11
+ </script>
12
+ </head>
13
+ <body onload="editorPg.start()">
14
+ <oid-sphere assets="https://mundorum.github.io/oid/oid/playground/assets/" stydefault="https://cdn.jsdelivr.net/npm/@mundorum/collections@0.3.1/full.min.css" global></oid-sphere>
15
+ <div style="width:100%;height:100vh;display:flex;flex-direction:column">
16
+ <div style="width:100%">
17
+ <h2>
18
+ <oid-sphere id="control" stylesheets="https://cdn.jsdelivr.net/npm/@mundorum/collections@0.3.1/"
19
+ style="display: flex; align-items: center; gap: 20px;">
20
+ Playground Editor
21
+ <file-oid label="Composition" publish="dispatch~file/loaded" style="width:200px"></file-oid>
22
+ <select id="oid-list" class="btn btn-secondary">
23
+ <option value="" selected>Select an id</option>
24
+ </select>
25
+ <button-oid label="Render" publish="click~control/render"></button-oid>
26
+ <button-oid label="Code" publish="click~control/code"></button-oid>
27
+ <button-oid label="Clear" publish="click~control/clear"></button-oid>
28
+ <button-oid label="Download Code" publish="click~control/download/code"></button-oid>
29
+ <button-oid label="Download Page" publish="click~control/download/page"></button-oid>
30
+ </oid-sphere>
31
+ </h2>
32
+ </div>
33
+
34
+ <div style="height:100%">
35
+ <split-pane-oid>
36
+ <div style="width:100%;height:100%" slot="side-a">
37
+ <split-pane-oid split="vertical">
38
+ <div id="pg-tree" slot="side-a"
39
+ style="width:100%;height:100%;padding:5px;border-style:solid;border-width:1px">
40
+ <oid-sphere id="control">
41
+ <graph-oid layout="vh"
42
+ subscribe="tree/node~node/add;tree/edge~edge/add;tree/clear~graph/clear"></graph-oid>
43
+ </oid-sphere>
44
+ </div>
45
+ <textarea id="pg-editor" slot="side-b" class="code"
46
+ style="width:100%;height:100%"></textarea>
47
+ </split-pane-oid>
48
+ </div>
49
+ <div style="width:100%;height:100%" slot="side-b">
50
+ <split-pane-oid split="vertical" proportion="75%">
51
+ <div id="pg-render" slot="side-a"
52
+ style="width:100%;height:100%;padding:5px;border-style:solid;border-width:1px">
53
+ </div>
54
+ <div id="pg-bus" style="width:100%;height:100%" slot="side-b">
55
+ <oid-sphere id="control">
56
+ <console-oid class="code" prompt="" subscribe="control/monitor~display">
57
+ </console-oid>
58
+ </oid-sphere>
59
+ </div>
60
+ </split-pane-oid>
61
+ </div>
62
+ </split-pane-oid>
63
+ </div>
64
+ </div>
65
+ </body>
66
+ </html>
app/static/editor/js/editor-pg.js ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import './editor-rest.js'
2
+ import { Sphere, Bus } from 'https://cdn.jsdelivr.net/npm/@mundorum/collections@0.3.1/full.js'
3
+
4
+ export class EditorPg {
5
+ start () {
6
+ this._controlSphere = Sphere.get('control').bus
7
+ this._controlSphere.subscribe(
8
+ 'file/loaded', this._renderFile.bind(this))
9
+ this._controlSphere.subscribe(
10
+ 'control/download/code', this._downloadCode.bind(this))
11
+ this._controlSphere.subscribe(
12
+ 'control/download/page', this._downloadPage.bind(this))
13
+ this._controlSphere.subscribe(
14
+ 'control/render', this._renderOids.bind(this))
15
+ this._controlSphere.subscribe(
16
+ 'control/code', this._codeOids.bind(this))
17
+ this._controlSphere.subscribe(
18
+ 'control/clear', this._clearOids.bind(this))
19
+ Bus.i.subscribe('#', this._busMonitor.bind(this))
20
+ }
21
+
22
+ _renderFile (topic, message) {
23
+ this._template = message.value
24
+ document.querySelector("#pg-render").innerHTML = this._template
25
+ this._showTree()
26
+ }
27
+
28
+ _showTree () {
29
+ const root = document.querySelector("#pg-render")
30
+ this._controlSphere.publish('tree/clear')
31
+ document.querySelector("#oid-list").innerHTML =
32
+ '<option value="">Select an OID</option>'
33
+ for (let childId = 1; childId <= root.children.length; childId++)
34
+ this._buildTree(root.children[childId-1], null, childId)
35
+ }
36
+
37
+ _buildTree (element, parentId, childId) {
38
+ const id = (parentId != null) ? `${parentId}.${childId}` : `${childId}`
39
+ const name = element.nodeName.toLowerCase()
40
+
41
+ // node
42
+ const node = { id: id,
43
+ label: name + (element.id ? `: ${element.id}` : '') }
44
+ if (!name.endsWith('-oid'))
45
+ node.format = 'light'
46
+ this._controlSphere.publish('tree/node', node)
47
+ if (element.id) {
48
+ const option = document.createElement('option')
49
+ option.value = element.id
50
+ option.text = element.id
51
+ document.querySelector("#oid-list").appendChild(option)
52
+ }
53
+
54
+ // edge
55
+ if (parentId != null) {
56
+ const edge = { source: parentId,
57
+ target: id }
58
+ this._controlSphere.publish('tree/edge', edge)
59
+ }
60
+
61
+ for (let childId = 1; childId <= element.children.length; childId++)
62
+ this._buildTree(element.children[childId-1], id, childId)
63
+ }
64
+
65
+ _renderOids () {
66
+ const div = document.createElement('div')
67
+ div.innerHTML = document.querySelector("#pg-editor").value
68
+
69
+ const selectedOption = document.querySelector("#oid-list").value
70
+ let base = document.querySelector(
71
+ (selectedOption === '') ? '#pg-render' : `#${selectedOption}`)
72
+
73
+ if (base instanceof SVGElement) {
74
+ const foreignObject = document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject')
75
+ foreignObject.setAttribute('width', '100%')
76
+ foreignObject.setAttribute('height', '100%')
77
+ base.appendChild(foreignObject)
78
+ base = foreignObject
79
+ }
80
+
81
+ while (div.firstChild)
82
+ base.appendChild(div.firstChild)
83
+
84
+ this._showTree()
85
+ }
86
+
87
+ _codeOids () {
88
+ const selectedOption = document.querySelector("#oid-list").value
89
+ const base = document.querySelector(
90
+ (selectedOption === '') ? '#pg-render' : `#${selectedOption}`)
91
+ document.querySelector("#pg-editor").value = base.innerHTML
92
+ }
93
+
94
+ _clearOids () {
95
+ document.querySelector("#pg-render").innerHTML =
96
+ (this._template != null) ? this._template : ''
97
+ this._showTree()
98
+ }
99
+
100
+ _busMonitor (topic, message) {
101
+ Sphere.get('control').bus.
102
+ publish('control/monitor', {value: `[${topic}] ${JSON.stringify(message)}`})
103
+ }
104
+
105
+ _downloadCode () {
106
+ this._download('code.html', document.querySelector('#pg-render').innerHTML)
107
+ }
108
+
109
+ _downloadPage () {
110
+ this._download('page.html',
111
+ EditorPg.pageBegin +
112
+ document.querySelector('#pg-render').innerHTML +
113
+ EditorPg.pageEnd)
114
+ }
115
+
116
+ _download (fileName, content) {
117
+ const a = document.createElement('a')
118
+ a.style.display = 'none'
119
+ document.body.appendChild(a)
120
+ a.href = window.URL.createObjectURL(
121
+ new Blob([content], {type: 'text/plain'}))
122
+ a.setAttribute('download', fileName)
123
+ a.click()
124
+ window.URL.revokeObjectURL(a.href)
125
+ document.body.removeChild(a)
126
+ }
127
+ }
128
+
129
+ EditorPg.i = new EditorPg()
130
+
131
+ EditorPg.pageBegin =
132
+ `<!DOCTYPE html>
133
+ <html>
134
+ <head>
135
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mundorum/oid/oid.min.css">
136
+ <script src="https://cdn.jsdelivr.net/npm/@mundorum/collections/full.min.js"></script>
137
+ </head>
138
+ <body>
139
+ <oid-sphere assets="https://mundorum.github.io/oid/oid/playground/assets/" stydefault="https://cdn.jsdelivr.net/npm/@mundorum/oid/oid.min.css" global></oid-sphere>`
140
+
141
+ EditorPg.pageEnd =
142
+ `</body>
143
+ </html>`
app/static/editor/js/editor-rest.js ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Oid } from 'https://cdn.jsdelivr.net/npm/@mundorum/collections@0.3.1/full.js'
2
+
3
+ Oid.customize('oid:rest', {
4
+ cid: 'cancer-predictor',
5
+ api: {
6
+ oas: {
7
+ paths: {
8
+ 'https://santanche-factory-ml.hf.space/train?train_path={train_path}&test_path={test_path}': {
9
+ 'post': {
10
+ operationId: 'train',
11
+ parameters: [
12
+ {name: 'train_path',
13
+ in: 'path'
14
+ },
15
+ {name: 'test_path',
16
+ in: 'path'
17
+ }
18
+ ]
19
+ }
20
+ },
21
+ 'https://santanche-factory-ml.hf.space/predict?radius_mean={radius_mean}&texture_mean={texture_mean}&symmetry_mean={symmetry_mean}&fractal_dimension_mean={fractal_dimension_mean}': {
22
+ 'get': {
23
+ operationId: 'predict',
24
+ parameters: [
25
+ {name: 'radius_mean',
26
+ in: 'path'
27
+ },
28
+ {name: 'texture_mean',
29
+ in: 'path'
30
+ },
31
+ {name: 'symmetry_mean',
32
+ in: 'path'
33
+ },
34
+ {name: 'fractal_dimension_mean',
35
+ in: 'path'
36
+ }
37
+ ]
38
+ }
39
+ }
40
+ }
41
+ }
42
+ }
43
+ })
44
+
45
+ Oid.customize('oid:rest', {
46
+ cid: 'factory-predictor',
47
+ api: {
48
+ oas: {
49
+ paths: {
50
+ 'https://santanche-factory-ml.hf.space/train': {
51
+ 'post': {
52
+ operationId: 'train'
53
+ }
54
+ },
55
+ 'https://santanche-factory-ml.hf.space/inform_temperature?value={value}': {
56
+ 'post': {
57
+ operationId: 'temperature',
58
+ parameters: [
59
+ {name: 'value',
60
+ in: 'path'
61
+ }
62
+ ]
63
+ }
64
+ },
65
+ 'https://santanche-factory-ml.hf.space/inform_pressure?value={value}': {
66
+ 'post': {
67
+ operationId: 'pressure',
68
+ parameters: [
69
+ {name: 'value',
70
+ in: 'path'
71
+ }
72
+ ]
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+ })
79
+
80
+ Oid.customize('oid:rest', {
81
+ cid: 'sentiment-analysis',
82
+ api: {
83
+ oas: {
84
+ paths: {
85
+ 'https://santanche-sentiment-analysis-oid.hf.space/classify?text={title}': {
86
+ 'get': {
87
+ operationId: 'classify',
88
+ parameters: [
89
+ {name: 'title',
90
+ in: 'path'
91
+ }
92
+ ]
93
+ }
94
+ }
95
+ }
96
+ }
97
+ }
98
+ })
app/static/gallery/cancer-prediction.html ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div>
2
+ <div style="font-size:larger;font-weight: bold">Cancer Prediction</div>
3
+ <form>
4
+ <div class="form-group">
5
+ <label for="train_path">Train path</label>
6
+ <input type="text" id="train_path" name="train_path" required value="breast-cancer-wisconsin_train.csv">
7
+ </div>
8
+ <div class="form-group">
9
+ <label for="test_path">Test path</label>
10
+ <input type="text" id="test_path" name="test_path" required value="breast-cancer-wisconsin_test.csv">
11
+ </div>
12
+
13
+ <submit-oid subscribe="form/train/submit~submit" publish="dispatch~form/train/submitted"></submit-oid>
14
+ </form>
15
+
16
+ <button-oid label="Train" publish="click~form/train/submit"></button-oid>
17
+
18
+ <form>
19
+ <div class="form-group">
20
+ <label for="radius_mean">Radius mean</label>
21
+ <input type="text" id="radius_mean" name="radius_mean" required>
22
+ </div>
23
+ <div class="form-group">
24
+ <label for="texture_mean">Texture mean</label>
25
+ <input type="text" id="texture_mean" name="texture_mean" required>
26
+ </div>
27
+ <div class="form-group">
28
+ <label for="symmetry_mean">Symmetry mean</label>
29
+ <input type="text" id="symmetry_mean" name="symmetry_mean" required>
30
+ </div>
31
+ <div class="form-group">
32
+ <label for="fractal_dimension_mean">Fractal dimension mean</label>
33
+ <input type="text" id="fractal_dimension_mean" name="fractal_dimension_mean" required>
34
+ </div>
35
+
36
+ <submit-oid subscribe="form/predict/submit~submit" publish="dispatch~form/predict/submitted"></submit-oid>
37
+ </form>
38
+
39
+ <button-oid label="Submit" publish="click~form/predict/submit"></button-oid>
40
+
41
+ <rest-oid custom="cancer-train"
42
+ subscribe=""
43
+ publish="dispatch~result/train/display">
44
+ </rest-oid>
45
+
46
+ <rest-oid custom="cancer-predictor"
47
+ subscribe="form/train/submitted~post/train;form/predict/submitted~get/predict"
48
+ publish="dispatch~result/predict/display">
49
+ </rest-oid>
50
+ </div>
app/static/gallery/factory-ai.html ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div style="width: 100%; height: 60%; background-color: lightgrey; text-align: center">
2
+ <div style="font-size:larger;font-weight: bold">Factory</div>
3
+ <span id="engine" style="width: 45%; display: inline-block; vertical-align: middle">
4
+ <image-oid source="assets:images/di-pietro-engine.gif" publish="mouseleave~thermo/low;mouseenter~thermo/medium;click~thermo/high/alert">
5
+ </image-oid>
6
+ </span>
7
+ <span id="cooler" style="width: 45%; display: inline-block; vertical-align: middle">
8
+ <state-pane-oid initial="off" subscribe="cooler/on~last;cooler/off~first">
9
+ <image-oid id="off" source="assets:images/evaporative-cooling.png"></image-oid>
10
+ <image-oid id="on" source="assets:images/evaporative-cooling.gif"></image-oid>
11
+ </state-pane-oid>
12
+ </span>
13
+ </div>
14
+ <div style="width: 100%; height: 35%; background-color: grey; text-align: center">
15
+ <div style="font-size: larger; font-weight: bold;">Control Panel</div>
16
+ <span id="alert" style="width: 20%; display: inline-block; vertical-align: middle">
17
+ <state-pane-oid initial="N" subscribe="update/alert~state">
18
+ <image-oid id="N" source="assets:images/light-green.svg"></image-oid>
19
+ <image-oid id="P" source="assets:images/light-red.svg"></image-oid>
20
+ </state-pane-oid>
21
+ </span>
22
+ <span id="train" style="width: 20%; display: inline-block; vertical-align: middle">
23
+ <switch-oid publish="on~predictor/train">
24
+ </switch-oid>
25
+ </span>
26
+ <span id="temperature" style="width: 20%; display: inline-block; vertical-align: middle">
27
+ <div style="font-size: larger; font-weight: bold;">Temperature</div>
28
+ <slider-oid min="40" max="120" value="40" index publish="change~predictor/temperature">
29
+ </slider-oid>
30
+ </span>
31
+ <span id="pressure" style="width: 20%; display: inline-block; vertical-align: middle">
32
+ <div style="font-size: larger; font-weight: bold;">Pressure</div>
33
+ <slider-oid min="40" max="200" value="40" index publish="change~predictor/pressure">
34
+ </slider-oid>
35
+ </span>
36
+ <rest-oid custom="factory-predictor"
37
+ subscribe="predictor/train~post/train;predictor/temperature~post/temperature;predictor/pressure~post/pressure"
38
+ publish="dispatch~update/alert">
39
+ </rest-oid>
40
+ </div>
app/static/gallery/factory-components.html ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <image-oid source="assets:images/di-pietro-engine.gif" publish="mouseleave~thermo/low;mouseenter~thermo/medium;click~thermo/high/alert">
2
+ </image-oid>
3
+
4
+ <state-pane-oid initial="off" subscribe="cooler/on~last;cooler/off~first">
5
+ <image-oid id="off" source="assets:images/evaporative-cooling.png"></image-oid>
6
+ <image-oid id="on" source="assets:images/evaporative-cooling.gif"></image-oid>
7
+ </state-pane-oid>
8
+
9
+ <state-pane-oid initial="low" subscribe="thermo/low~first;thermo/medium~next;thermo/high/#~last">
10
+ <image-oid id="low" source="assets:images/thermometer-a.svg"></image-oid>
11
+ <image-oid id="medium" source="assets:images/thermometer-b.svg"></image-oid>
12
+ <image-oid id="high" source="assets:images/thermometer-c.svg"></image-oid>
13
+ </state-pane-oid>
14
+
15
+ <state-pane-oid initial="green" subscribe="thermo/+~first;+/+/alert~last">
16
+ <image-oid id="green" source="assets:images/light-green.svg"></image-oid>
17
+ <image-oid id="red" source="assets:images/light-red.svg"></image-oid>
18
+ </state-pane-oid>
19
+
20
+ <switch-oid publish="on~cooler/on;off~cooler/off" subscribe="thermo/+~off;thermo/+/alert~on">
21
+ </switch-oid>
app/static/gallery/factory-composition.html ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div style="width: 100%; height: 60%; background-color: lightgrey; text-align: center">
2
+ <div style="font-size:larger;font-weight: bold">Factory</div>
3
+ <span id="engine" style="width: 45%; display: inline-block; vertical-align: middle">
4
+ <image-oid source="assets:images/di-pietro-engine.gif" publish="mouseleave~thermo/low;mouseenter~thermo/medium;click~thermo/high/alert">
5
+ </image-oid>
6
+ </span>
7
+ <span id="cooler" style="width: 45%; display: inline-block; vertical-align: middle">
8
+ <state-pane-oid initial="off" subscribe="cooler/on~last;cooler/off~first">
9
+ <image-oid id="off" source="assets:images/evaporative-cooling.png"></image-oid>
10
+ <image-oid id="on" source="assets:images/evaporative-cooling.gif"></image-oid>
11
+ </state-pane-oid>
12
+ </span>
13
+ </div>
14
+ <div style="width: 100%; height: 35%; background-color: grey; text-align: center">
15
+ <div style="font-size: larger; font-weight: bold;">Control Panel</div>
16
+ <span id="thermometer" style="width: 30%; display: inline-block; vertical-align: middle">
17
+ <state-pane-oid initial="low" subscribe="thermo/low~first;thermo/medium~next;thermo/high/#~last">
18
+ <image-oid id="low" source="assets:images/thermometer-a.svg"></image-oid>
19
+ <image-oid id="medium" source="assets:images/thermometer-b.svg"></image-oid>
20
+ <image-oid id="high" source="assets:images/thermometer-c.svg"></image-oid>
21
+ </state-pane-oid>
22
+ </span>
23
+ <span id="alert" style="width: 30%; display: inline-block; vertical-align: middle">
24
+ <state-pane-oid initial="green" subscribe="thermo/+~first;+/+/alert~last">
25
+ <image-oid id="green" source="assets:images/light-green.svg"></image-oid>
26
+ <image-oid id="red" source="assets:images/light-red.svg"></image-oid>
27
+ </state-pane-oid>
28
+ </span>
29
+ <span id="activate_cooler" style="width: 30%; display: inline-block; vertical-align: middle">
30
+ <switch-oid publish="on~cooler/on;off~cooler/off" subscribe="thermo/+~off;thermo/+/alert~on">
31
+ </switch-oid>
32
+ </span>
33
+ </div>
app/static/templates/dinosaur01.html ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ <h1>Dinosaur</h1>
2
+ <div style="margin: 20px; border: 2px solid black; padding: 10px;">
3
+ <p>I am a dinosaur</p>
4
+ <button-oid label="Roar" publish="click~dinosaur/roar"></button-oid>
5
+ </div>
app/static/templates/dinosaur02.html ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ <h1>Dinosaur</h1>
2
+ <div id="dino" style="margin: 20px; border: 2px solid black; padding: 10px;">
3
+ <p>I am a dinosaur</p>
4
+ </div>
app/static/templates/dinosaur03.html ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ <h1>Dinosaur</h1>
2
+ <div id="dino-area" style="margin: 20px; border: 2px solid black; padding: 10px;">
3
+ <p>Dino Area</p>
4
+ </div>
5
+ <div id="talk-area" style="margin: 20px; border: 2px solid black; padding: 10px;">
6
+ <p>Talk Area</p>
7
+ </div>
app/static/templates/ehr.svg ADDED
app/static/templates/factory.html ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div style="width: 100%; height: 60%; background-color: lightgrey; text-align: center">
2
+ <div style="font-size:larger;font-weight: bold">Factory</div>
3
+ <span id="engine" style="width: 45%; display: inline-block; vertical-align: middle">
4
+ </span>
5
+ <span id="cooler" style="width: 45%; display: inline-block; vertical-align: middle">
6
+ </span>
7
+ </div>
8
+ <div style="width: 100%; height: 35%; background-color: grey; text-align: center">
9
+ <div style="font-size: larger; font-weight: bold;">Control Panel</div>
10
+ <span id="thermometer" style="width: 30%; display: inline-block; vertical-align: middle">
11
+ </span>
12
+ <span id="alert" style="width: 30%; display: inline-block; vertical-align: middle"></span>
13
+ </span>
14
+ <span id="activate_cooler" style="width: 30%; display: inline-block; vertical-align: middle"></span>
15
+ </span>
16
+ </div>
app/static/templates/news.html ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div style="width: 100%; height: 60%; background-color: lightgrey; text-align: center">
2
+ <div style="font-size:larger;font-weight: bold">News</div>
3
+ <span id="tv" style="width: 30%; display: inline-block; vertical-align: middle">
4
+ <image-oid source="assets:images/tv-old.svg" label="Old TV"></image-oid>
5
+ </span>
6
+ <span id="news" style="width: 65%; display: inline-block; vertical-align: middle">
7
+ </span>
8
+ </div>
9
+ <div style="width: 100%; height: 35%; background-color: grey; text-align: center">
10
+ <div style="font-size: larger; font-weight: bold;">Control Panel</div>
11
+ <span id="control-1" style="width: 30%; display: inline-block; vertical-align: middle">
12
+ </span>
13
+ <span id="control-2" style="width: 30%; display: inline-block; vertical-align: middle">
14
+ </span>
15
+ <span id="alert" style="width: 30%; display: inline-block; vertical-align: middle">
16
+ </span>
17
+ </div>
18
+ <rest-oid custom="sentiment-analysis"
19
+ subscribe="rss/news~get/classify"
20
+ publish="dispatch~update/alert">
21
+ </rest-oid>
requirements.txt ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ annotated-types==0.7.0
2
+ anyio==4.10.0
3
+ certifi==2025.8.3
4
+ charset-normalizer==3.4.3
5
+ click==8.2.1
6
+ dnspython==2.7.0
7
+ email-validator==2.3.0
8
+ exceptiongroup==1.3.0
9
+ fastapi==0.116.1
10
+ fastapi-cli==0.0.10
11
+ fastapi-cloud-cli==0.1.5
12
+ filelock==3.19.1
13
+ fsspec==2025.9.0
14
+ h11==0.16.0
15
+ hf-xet==1.1.9
16
+ httpcore==1.0.9
17
+ httptools==0.6.4
18
+ httpx==0.28.1
19
+ huggingface-hub==0.34.4
20
+ idna==3.10
21
+ Jinja2==3.1.6
22
+ markdown-it-py==4.0.0
23
+ MarkupSafe==3.0.2
24
+ mdurl==0.1.2
25
+ mpmath==1.3.0
26
+ networkx==3.4.2
27
+ numpy==2.2.6
28
+ nvidia-cublas-cu12==12.8.4.1
29
+ nvidia-cuda-cupti-cu12==12.8.90
30
+ nvidia-cuda-nvrtc-cu12==12.8.93
31
+ nvidia-cuda-runtime-cu12==12.8.90
32
+ nvidia-cudnn-cu12==9.10.2.21
33
+ nvidia-cufft-cu12==11.3.3.83
34
+ nvidia-cufile-cu12==1.13.1.3
35
+ nvidia-curand-cu12==10.3.9.90
36
+ nvidia-cusolver-cu12==11.7.3.90
37
+ nvidia-cusparse-cu12==12.5.8.93
38
+ nvidia-cusparselt-cu12==0.7.1
39
+ nvidia-nccl-cu12==2.27.3
40
+ nvidia-nvjitlink-cu12==12.8.93
41
+ nvidia-nvtx-cu12==12.8.90
42
+ packaging==25.0
43
+ pydantic==2.11.7
44
+ pydantic_core==2.33.2
45
+ Pygments==2.19.2
46
+ python-dotenv==1.1.1
47
+ python-multipart==0.0.20
48
+ PyYAML==6.0.2
49
+ regex==2025.9.1
50
+ requests==2.32.5
51
+ rich==14.1.0
52
+ rich-toolkit==0.15.1
53
+ rignore==0.6.4
54
+ safetensors==0.6.2
55
+ sentry-sdk==2.37.0
56
+ shellingham==1.5.4
57
+ sniffio==1.3.1
58
+ starlette==0.47.3
59
+ sympy==1.14.0
60
+ tokenizers==0.22.0
61
+ torch==2.8.0
62
+ tqdm==4.67.1
63
+ transformers==4.56.1
64
+ triton==3.4.0
65
+ typer==0.17.4
66
+ typing-inspection==0.4.1
67
+ typing_extensions==4.15.0
68
+ urllib3==2.5.0
69
+ uvicorn==0.35.0
70
+ uvloop==0.21.0
71
+ watchfiles==1.1.0
72
+ websockets==15.0.1