Spaces:
Running
Running
New: SVG as python
Browse files
app.py
CHANGED
|
@@ -22,6 +22,9 @@ from safetensors.torch import load_file # Sicheres & schnelles Laden von We
|
|
| 22 |
# UI / Serving
|
| 23 |
import gradio as gr # Web-UI für Demo/Spaces
|
| 24 |
|
|
|
|
|
|
|
|
|
|
| 25 |
# Projektspezifische Module
|
| 26 |
from lib.bert_regressor import BertMultiHeadRegressor
|
| 27 |
from lib.bert_regressor_utils import (
|
|
@@ -111,6 +114,90 @@ def is_eng(review: str):
|
|
| 111 |
|
| 112 |
return lang_label[1] == "__label__en", lang_prob
|
| 113 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
### Do actual prediction #########################################################
|
| 115 |
@spaces.GPU(duration=10) # Sekunden GPU-Zeit pro Call
|
| 116 |
def predict(review: str):
|
|
@@ -133,90 +220,12 @@ def predict(review: str):
|
|
| 133 |
|
| 134 |
#html_out = f"<b>{html.escape(review)}</b>"
|
| 135 |
|
| 136 |
-
|
| 137 |
-
<svg id="wheel" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
| 138 |
-
|
| 139 |
-
<defs>
|
| 140 |
-
<path id="textPathU-68cfc5fd8ae1e" d="M 250, 250 m 0, 220 a -220,-220 0 1,1 0,-440 a -220,-220 0 1,1 0,440" style="stroke: red; fill: none;" />
|
| 141 |
-
<path id="textPathL-68cfc5fd8ae1e" d="M 250, 250 m 0, -220 a 220,220 0 1,0 0,440 a 220,220 0 1,0 0,-440" style="stroke: red; fill: none;" />
|
| 142 |
-
</defs>
|
| 143 |
-
|
| 144 |
-
<circle class="circle" r="40" cx="250" cy="250" style="stroke: black; fill: none;" />
|
| 145 |
-
<circle class="circle" r="80" cx="250" cy="250" style="stroke: black; fill: none;" />
|
| 146 |
-
<circle class="circle" r="120" cx="250" cy="250" style="stroke: black; fill: none;" />
|
| 147 |
-
<circle class="circle" r="160" cx="250" cy="250" style="stroke: black; fill: none;" />
|
| 148 |
-
<circle class="circle" r="200" cx="250" cy="250" style="stroke: black; fill: none;" />
|
| 149 |
-
|
| 150 |
-
<line class="line" x1="250" y1="210" x2="250" y2="50" style="stroke: black;" />
|
| 151 |
-
<line class="line" x1="278.28427124746" y1="221.71572875254" x2="391.42135623731" y2="108.57864376269" style="stroke: black;" />
|
| 152 |
-
<line class="line" x1="290" y1="250" x2="450" y2="250" style="stroke: black;" />
|
| 153 |
-
<line class="line" x1="278.28427124746" y1="278.28427124746" x2="391.42135623731" y2="391.42135623731" style="stroke: black;" />
|
| 154 |
-
<line class="line" x1="250" y1="290" x2="250" y2="450" style="stroke: black;" />
|
| 155 |
-
<line class="line" x1="221.71572875254" y1="278.28427124746" x2="108.57864376269" y2="391.42135623731" style="stroke: black;" />
|
| 156 |
-
<line class="line" x1="210" y1="250" x2="50" y2="250" style="stroke: black;" />
|
| 157 |
-
<line class="line" x1="221.71572875254" y1="221.71572875254" x2="108.57864376269" y2="108.57864376269" style="stroke: black;" />
|
| 158 |
-
|
| 159 |
-
<text text-anchor="middle" dy="0">
|
| 160 |
-
<textPath xlink:href="#textPathU-68cfc5fd8ae1e" startOffset="50%">
|
| 161 |
-
Grainy
|
| 162 |
-
</textPath>
|
| 163 |
-
</text>
|
| 164 |
-
|
| 165 |
-
<text text-anchor="middle" dy="0">
|
| 166 |
-
<textPath xlink:href="#textPathU-68cfc5fd8ae1e" startOffset="62.5%">
|
| 167 |
-
Grassy
|
| 168 |
-
</textPath>
|
| 169 |
-
</text>
|
| 170 |
-
|
| 171 |
-
<text text-anchor="middle" dy="0">
|
| 172 |
-
<textPath xlink:href="#textPathU-68cfc5fd8ae1e" startOffset="75%">
|
| 173 |
-
Fragrant
|
| 174 |
-
</textPath>
|
| 175 |
-
</text>
|
| 176 |
-
|
| 177 |
-
<text text-anchor="middle" dy="9px">
|
| 178 |
-
<textPath xlink:href="#textPathL-68cfc5fd8ae1e" startOffset="62.5%">
|
| 179 |
-
Fruity
|
| 180 |
-
</textPath>
|
| 181 |
-
</text>
|
| 182 |
-
|
| 183 |
-
<text text-anchor="middle" dy="9px">
|
| 184 |
-
<textPath xlink:href="#textPathL-68cfc5fd8ae1e" startOffset="50%">
|
| 185 |
-
Peaty
|
| 186 |
-
</textPath>
|
| 187 |
-
</text>
|
| 188 |
-
|
| 189 |
-
<text text-anchor="middle" dy="9px">
|
| 190 |
-
<textPath xlink:href="#textPathL-68cfc5fd8ae1e" startOffset="37.5%">
|
| 191 |
-
Woody
|
| 192 |
-
</textPath>
|
| 193 |
-
</text>
|
| 194 |
-
|
| 195 |
-
<text text-anchor="middle" dy="0">
|
| 196 |
-
<textPath xlink:href="#textPathU-68cfc5fd8ae1e" startOffset="25%">
|
| 197 |
-
Winey
|
| 198 |
-
</textPath>
|
| 199 |
-
</text>
|
| 200 |
-
|
| 201 |
-
<text text-anchor="middle" dy="0">
|
| 202 |
-
<textPath xlink:href="#textPathU-68cfc5fd8ae1e" startOffset="37.5%">
|
| 203 |
-
Off-Notes
|
| 204 |
-
</textPath>
|
| 205 |
-
</text>
|
| 206 |
-
|
| 207 |
-
<polyline class="graph" points></polyline>
|
| 208 |
-
|
| 209 |
-
<circle class="point" style="stroke: black; fill: white;" cx="250" cy="250" r="3.5" />
|
| 210 |
-
<circle class="point" style="stroke: black; fill: white;" cx="250" cy="250" r="3.5" />
|
| 211 |
-
<circle class="point" style="stroke: black; fill: white;" cx="250" cy="250" r="3.5" />
|
| 212 |
-
<circle class="point" style="stroke: black; fill: white;" cx="250" cy="250" r="3.5" />
|
| 213 |
-
<circle class="point" style="stroke: black; fill: white;" cx="250" cy="250" r="3.5" />
|
| 214 |
-
<circle class="point" style="stroke: black; fill: white;" cx="250" cy="250" r="3.5" />
|
| 215 |
-
<circle class="point" style="stroke: black; fill: white;" cx="250" cy="250" r="3.5" />
|
| 216 |
-
<circle class="point" style="stroke: black; fill: white;" cx="250" cy="250" r="3.5" />
|
| 217 |
-
|
| 218 |
-
</svg>
|
| 219 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 220 |
<style>
|
| 221 |
svg#wheel > .circle,
|
| 222 |
svg#wheel > .line {
|
|
@@ -231,56 +240,14 @@ def predict(review: str):
|
|
| 231 |
fill-opacity: 0.9;
|
| 232 |
}
|
| 233 |
svg#wheel > text {
|
| 234 |
-
font-family:
|
| 235 |
font-style: normal;
|
| 236 |
font-weight: 400;
|
| 237 |
font-size: 18px;
|
| 238 |
// text-transform: uppercase;
|
| 239 |
-
&.scale {
|
| 240 |
-
fill: rgb(180, 180, 180);
|
| 241 |
-
}
|
| 242 |
}
|
| 243 |
</style>
|
| 244 |
-
|
| 245 |
-
<script>
|
| 246 |
-
const setPoints = function (vals) {
|
| 247 |
-
|
| 248 |
-
const elemsPoint = document.querySelectorAll('.point');
|
| 249 |
-
const elemGraph = document.querySelector('.graph');
|
| 250 |
-
|
| 251 |
-
const points = [];
|
| 252 |
-
|
| 253 |
-
elemsPoint.forEach(function(elemPoint, i) {
|
| 254 |
-
// steps offset convert to bogenmass
|
| 255 |
-
const angle = (360 / config.segments * i + config.offsetAngle - 90) * (Math.PI * 2 / 360);
|
| 256 |
-
|
| 257 |
-
const val = vals[i];
|
| 258 |
-
|
| 259 |
-
const c = {
|
| 260 |
-
x: Math.cos(angle) * (val * config.inputRatio + config.innerRadius) + config.offsetCenter,
|
| 261 |
-
y: Math.sin(angle) * (val * config.inputRatio + config.innerRadius) + config.offsetCenter
|
| 262 |
-
}
|
| 263 |
-
|
| 264 |
-
points.push(`${c.x},${c.y}`);
|
| 265 |
-
|
| 266 |
-
elemGraph.setAttribute('points', points.join(' '));
|
| 267 |
-
|
| 268 |
-
elemPoint.setAttribute('cx', `${c.x}`);
|
| 269 |
-
elemPoint.setAttribute('cy', `${c.y}`);
|
| 270 |
-
});
|
| 271 |
-
}
|
| 272 |
-
|
| 273 |
-
const config = {
|
| 274 |
-
segments: 8,
|
| 275 |
-
offsetAngle: 0,
|
| 276 |
-
innerRadius: 40,
|
| 277 |
-
offsetCenter: 250,
|
| 278 |
-
inputRatio: 16
|
| 279 |
-
};
|
| 280 |
-
|
| 281 |
-
setPoints([0, 1, 1.5, 0, 2, 0, 3.4, 2])
|
| 282 |
-
</script>
|
| 283 |
-
'''
|
| 284 |
|
| 285 |
json_out = {
|
| 286 |
"review": review,
|
|
@@ -302,7 +269,7 @@ def predict(review: str):
|
|
| 302 |
}
|
| 303 |
|
| 304 |
return html_out, json_out
|
| 305 |
-
|
| 306 |
### Create Form interface with Gradio Framework ##################################
|
| 307 |
iface = gr.Interface(
|
| 308 |
fn=predict,
|
|
|
|
| 22 |
# UI / Serving
|
| 23 |
import gradio as gr # Web-UI für Demo/Spaces
|
| 24 |
|
| 25 |
+
import math
|
| 26 |
+
from typing import List, Tuple
|
| 27 |
+
|
| 28 |
# Projektspezifische Module
|
| 29 |
from lib.bert_regressor import BertMultiHeadRegressor
|
| 30 |
from lib.bert_regressor_utils import (
|
|
|
|
| 114 |
|
| 115 |
return lang_label[1] == "__label__en", lang_prob
|
| 116 |
|
| 117 |
+
### Wheel ##################################
|
| 118 |
+
|
| 119 |
+
# ---------- Geometrie: JS -> Python ----------
|
| 120 |
+
def compute_wheel_points(
|
| 121 |
+
vals: List[float],
|
| 122 |
+
segments: int = 8,
|
| 123 |
+
offset_angle_deg: float = 0.0,
|
| 124 |
+
inner_radius: float = 40.0,
|
| 125 |
+
center: float = 250.0,
|
| 126 |
+
input_ratio: float = 16.0,
|
| 127 |
+
) -> List[Tuple[float, float]]:
|
| 128 |
+
"""
|
| 129 |
+
Repliziert die JS-Logik:
|
| 130 |
+
angle = (360/segments*i + offsetAngle - 90) * (π*2/360)
|
| 131 |
+
r = vals[i] * inputRatio + innerRadius
|
| 132 |
+
x = cos(angle) * r + center
|
| 133 |
+
y = sin(angle) * r + center
|
| 134 |
+
"""
|
| 135 |
+
pts = []
|
| 136 |
+
for i, v in enumerate(vals):
|
| 137 |
+
angle_deg = (360.0 / segments) * i + offset_angle_deg - 90.0
|
| 138 |
+
angle = angle_deg * (math.pi * 2.0 / 360.0)
|
| 139 |
+
r = v * input_ratio + inner_radius
|
| 140 |
+
x = math.cos(angle) * r + center
|
| 141 |
+
y = math.sin(angle) * r + center
|
| 142 |
+
pts.append((x, y))
|
| 143 |
+
return pts
|
| 144 |
+
|
| 145 |
+
# ---------- SVG-Bau ----------
|
| 146 |
+
SVG_BASE = """<svg id="wheel" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg">
|
| 147 |
+
<!-- Ringe -->
|
| 148 |
+
<circle class="circle" r="40" cx="250" cy="250" style="stroke:black; fill:none" />
|
| 149 |
+
<circle class="circle" r="80" cx="250" cy="250" style="stroke:black; fill:none" />
|
| 150 |
+
<circle class="circle" r="120" cx="250" cy="250" style="stroke:black; fill:none" />
|
| 151 |
+
<circle class="circle" r="160" cx="250" cy="250" style="stroke:black; fill:none" />
|
| 152 |
+
<circle class="circle" r="200" cx="250" cy="250" style="stroke:black; fill:none" />
|
| 153 |
+
|
| 154 |
+
<!-- Achsen -->
|
| 155 |
+
<line class="line" x1="250" y1="210" x2="250" y2="50" style="stroke:black" />
|
| 156 |
+
<line class="line" x1="278.28427124746" y1="221.71572875254" x2="391.42135623731" y2="108.57864376269" style="stroke:black" />
|
| 157 |
+
<line class="line" x1="290" y1="250" x2="450" y2="250" style="stroke:black" />
|
| 158 |
+
<line class="line" x1="278.28427124746" y1="278.28427124746" x2="391.42135623731" y2="391.42135623731" style="stroke:black" />
|
| 159 |
+
<line class="line" x1="250" y1="290" x2="250" y2="450" style="stroke:black" />
|
| 160 |
+
<line class="line" x1="221.71572875254" y1="278.28427124746" x2="108.57864376269" y2="391.42135623731" style="stroke:black" />
|
| 161 |
+
<line class="line" x1="210" y1="250" x2="50" y2="250" style="stroke:black" />
|
| 162 |
+
<line class="line" x1="221.71572875254" y1="221.71572875254" x2="108.57864376269" y2="108.57864376269" style="stroke:black" />
|
| 163 |
+
|
| 164 |
+
<!-- Textpfade & Labels (dein Original kannst du hier einfügen) -->
|
| 165 |
+
{LABELS}
|
| 166 |
+
|
| 167 |
+
<!-- Fläche -->
|
| 168 |
+
<polyline class="graph" points="{POINTS}" style="fill:rgb(250,208,72); fill-opacity:0.9" />
|
| 169 |
+
|
| 170 |
+
<!-- Punkte -->
|
| 171 |
+
{POINT_CIRCLES}
|
| 172 |
+
</svg>"""
|
| 173 |
+
|
| 174 |
+
def build_point_circles(points: List[Tuple[float, float]]) -> str:
|
| 175 |
+
return "\n ".join(
|
| 176 |
+
f'<circle class="point" style="stroke:black; fill:white" cx="{x:.2f}" cy="{y:.2f}" r="3.5" />'
|
| 177 |
+
for x, y in points
|
| 178 |
+
)
|
| 179 |
+
|
| 180 |
+
def build_svg_with_values(
|
| 181 |
+
vals: List[float],
|
| 182 |
+
labels_svg: str = "",
|
| 183 |
+
segments: int = 8,
|
| 184 |
+
offset_angle_deg: float = 0.0,
|
| 185 |
+
inner_radius: float = 40.0,
|
| 186 |
+
center: float = 250.0,
|
| 187 |
+
input_ratio: float = 16.0,
|
| 188 |
+
) -> str:
|
| 189 |
+
pts = compute_wheel_points(
|
| 190 |
+
vals,
|
| 191 |
+
segments=segments,
|
| 192 |
+
offset_angle_deg=offset_angle_deg,
|
| 193 |
+
inner_radius=inner_radius,
|
| 194 |
+
center=center,
|
| 195 |
+
input_ratio=input_ratio,
|
| 196 |
+
)
|
| 197 |
+
points_attr = " ".join(f"{x:.2f},{y:.2f}" for x, y in pts)
|
| 198 |
+
circles = build_point_circles(pts)
|
| 199 |
+
return SVG_BASE.format(LABELS=labels_svg, POINTS=points_attr, POINT_CIRCLES=circles)
|
| 200 |
+
|
| 201 |
### Do actual prediction #########################################################
|
| 202 |
@spaces.GPU(duration=10) # Sekunden GPU-Zeit pro Call
|
| 203 |
def predict(review: str):
|
|
|
|
| 220 |
|
| 221 |
#html_out = f"<b>{html.escape(review)}</b>"
|
| 222 |
|
| 223 |
+
values = [0, 1, 1.5, 0, 2, 0, 3.4, 2] # deine 8 Werte
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 224 |
|
| 225 |
+
svg = build_svg_with_values(values, labels_svg="")
|
| 226 |
+
|
| 227 |
+
html_out = """
|
| 228 |
+
{svg}
|
| 229 |
<style>
|
| 230 |
svg#wheel > .circle,
|
| 231 |
svg#wheel > .line {
|
|
|
|
| 240 |
fill-opacity: 0.9;
|
| 241 |
}
|
| 242 |
svg#wheel > text {
|
| 243 |
+
font-family: "Source Sans Pro", ui-sans-serif, system-ui, sans-serif;
|
| 244 |
font-style: normal;
|
| 245 |
font-weight: 400;
|
| 246 |
font-size: 18px;
|
| 247 |
// text-transform: uppercase;
|
|
|
|
|
|
|
|
|
|
| 248 |
}
|
| 249 |
</style>
|
| 250 |
+
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 251 |
|
| 252 |
json_out = {
|
| 253 |
"review": review,
|
|
|
|
| 269 |
}
|
| 270 |
|
| 271 |
return html_out, json_out
|
| 272 |
+
|
| 273 |
### Create Form interface with Gradio Framework ##################################
|
| 274 |
iface = gr.Interface(
|
| 275 |
fn=predict,
|