Deaktiviere Pre-Commit temporär

pull/94/head
Abdulrahman Dabbagh 2025-06-29 11:09:11 +02:00
parent 360da3acb0
commit 6c55150e9c
11 changed files with 119 additions and 42 deletions

View File

@ -34,6 +34,7 @@ def create_kpi_setting():
"position", "position",
"active", "active",
"examples", "examples",
"is_trained",
] ]
for field in required_fields: for field in required_fields:
if field not in data: if field not in data:
@ -58,6 +59,7 @@ def create_kpi_setting():
position=data["position"], position=data["position"],
active=data["active"], active=data["active"],
examples=data.get("examples", []), examples=data.get("examples", []),
is_trained=False
) )
db.session.add(new_kpi_setting) db.session.add(new_kpi_setting)

View File

@ -6,6 +6,8 @@ from werkzeug.utils import secure_filename
from model.database import db from model.database import db
import os import os
import requests import requests
from model.kpi_setting_model import KPISettingModel
spacy_controller = Blueprint("spacy", __name__, url_prefix="/api/spacy") spacy_controller = Blueprint("spacy", __name__, url_prefix="/api/spacy")
@ -122,8 +124,14 @@ current_training_status = {"running": False}
def update_training_status(): def update_training_status():
data = request.get_json() data = request.get_json()
current_training_status["running"] = data.get("running", False) current_training_status["running"] = data.get("running", False)
running = current_training_status["running"]
print(f"[INFO] Trainingsstatus aktualisiert: running = {running}") if current_training_status["running"] is False:
try:
KPISettingModel.query.update({KPISettingModel.is_trained: True})
db.session.commit()
except Exception as e:
db.session.rollback()
return jsonify({"error": "is_trained konnte nicht aktualisiert werden", "details": str(e)}), 500
return jsonify({"status": "success", "running": current_training_status["running"]}) return jsonify({"status": "success", "running": current_training_status["running"]})

View File

@ -27,6 +27,8 @@ class KPISettingModel(db.Model):
position: Mapped[int] position: Mapped[int]
active: Mapped[bool] active: Mapped[bool]
examples: Mapped[list] = mapped_column(JSONB, default=[]) examples: Mapped[list] = mapped_column(JSONB, default=[])
is_trained: Mapped[bool] = mapped_column(default=False)
def to_dict(self): def to_dict(self):
return OrderedDict( return OrderedDict(
@ -38,13 +40,15 @@ class KPISettingModel(db.Model):
("position", self.position), ("position", self.position),
("examples", self.examples), ("examples", self.examples),
("active", self.active), ("active", self.active),
("is_trained", self.is_trained),
] ]
) )
def __init__(self, name, mandatory, type, position, active, examples=None): def __init__(self, name, mandatory, type, position, active, examples=None, is_trained=False):
self.name = name self.name = name
self.mandatory = mandatory self.mandatory = mandatory
self.type = type self.type = type
self.position = position self.position = position
self.active = active self.active = active
self.examples = examples or [] self.examples = examples or []
self.is_trained = is_trained

View File

@ -14,6 +14,7 @@ def seed_default_kpi_settings():
"type": KPISettingType.STRING, "type": KPISettingType.STRING,
"position": 1, "position": 1,
"active": True, "active": True,
"is_trained": True,
"examples": [ "examples": [
{ {
"sentence": "Der Fonds trägt den Namen Alpha Real Estate Fund I.", "sentence": "Der Fonds trägt den Namen Alpha Real Estate Fund I.",
@ -31,6 +32,7 @@ def seed_default_kpi_settings():
"type": KPISettingType.STRING, "type": KPISettingType.STRING,
"position": 2, "position": 2,
"active": True, "active": True,
"is_trained": True,
"examples": [ "examples": [
{ {
"sentence": "Fondsmanager des Projekts ist Max Mustermann.", "sentence": "Fondsmanager des Projekts ist Max Mustermann.",
@ -48,6 +50,7 @@ def seed_default_kpi_settings():
"type": KPISettingType.STRING, "type": KPISettingType.STRING,
"position": 3, "position": 3,
"active": True, "active": True,
"is_trained": True,
"examples": [ "examples": [
{ {
"sentence": "AIFM ist die Alpha Investment Management GmbH.", "sentence": "AIFM ist die Alpha Investment Management GmbH.",
@ -65,6 +68,7 @@ def seed_default_kpi_settings():
"type": KPISettingType.DATE, "type": KPISettingType.DATE,
"position": 4, "position": 4,
"active": True, "active": True,
"is_trained": True,
"examples": [ "examples": [
{ {
"sentence": "Die Daten basieren auf dem Stand vom 05.05.2025.", "sentence": "Die Daten basieren auf dem Stand vom 05.05.2025.",
@ -82,6 +86,7 @@ def seed_default_kpi_settings():
"type": KPISettingType.STRING, "type": KPISettingType.STRING,
"position": 5, "position": 5,
"active": True, "active": True,
"is_trained": True,
"examples": [ "examples": [
{ {
"sentence": "Der Fonds hat das Risikoprofil Core/Core++.", "sentence": "Der Fonds hat das Risikoprofil Core/Core++.",
@ -99,6 +104,7 @@ def seed_default_kpi_settings():
"type": KPISettingType.BOOLEAN, "type": KPISettingType.BOOLEAN,
"position": 6, "position": 6,
"active": True, "active": True,
"is_trained": True,
"examples": [ "examples": [
{ {
"sentence": "Der Fonds erfüllt die Anforderungen von Artikel 8.", "sentence": "Der Fonds erfüllt die Anforderungen von Artikel 8.",
@ -116,6 +122,7 @@ def seed_default_kpi_settings():
"type": KPISettingType.NUMBER, "type": KPISettingType.NUMBER,
"position": 7, "position": 7,
"active": True, "active": True,
"is_trained": True,
"examples": [ "examples": [
{ {
"sentence": "Die angestrebte Zielrendite liegt bei 6.5%.", "sentence": "Die angestrebte Zielrendite liegt bei 6.5%.",
@ -130,6 +137,7 @@ def seed_default_kpi_settings():
"type": KPISettingType.NUMBER, "type": KPISettingType.NUMBER,
"position": 8, "position": 8,
"active": True, "active": True,
"is_trained": True,
"examples": [ "examples": [
{ {
"sentence": "Die Rendite für das Jahr beträgt 5.8%.", "sentence": "Die Rendite für das Jahr beträgt 5.8%.",
@ -147,6 +155,7 @@ def seed_default_kpi_settings():
"type": KPISettingType.NUMBER, "type": KPISettingType.NUMBER,
"position": 9, "position": 9,
"active": True, "active": True,
"is_trained": True,
"examples": [ "examples": [
{"sentence": "Die Zielausschüttung beträgt 4.0%.", "value": "4.0%"}, {"sentence": "Die Zielausschüttung beträgt 4.0%.", "value": "4.0%"},
{ {
@ -161,6 +170,7 @@ def seed_default_kpi_settings():
"type": KPISettingType.NUMBER, "type": KPISettingType.NUMBER,
"position": 10, "position": 10,
"active": True, "active": True,
"is_trained": True,
"examples": [ "examples": [
{ {
"sentence": "Die Ausschüttung im Jahr 2024 lag bei 3.8%.", "sentence": "Die Ausschüttung im Jahr 2024 lag bei 3.8%.",
@ -178,6 +188,7 @@ def seed_default_kpi_settings():
"type": KPISettingType.STRING, "type": KPISettingType.STRING,
"position": 11, "position": 11,
"active": True, "active": True,
"is_trained": True,
"examples": [ "examples": [
{ {
"sentence": "Die Laufzeit des Fonds beträgt 7 Jahre.", "sentence": "Die Laufzeit des Fonds beträgt 7 Jahre.",
@ -192,6 +203,7 @@ def seed_default_kpi_settings():
"type": KPISettingType.NUMBER, "type": KPISettingType.NUMBER,
"position": 12, "position": 12,
"active": True, "active": True,
"is_trained": True,
"examples": [ "examples": [
{"sentence": "Der LTV beträgt 65.0%.", "value": "65.0%"}, {"sentence": "Der LTV beträgt 65.0%.", "value": "65.0%"},
{"sentence": "Loan-to-Value-Ratio: 65.0%.", "value": "65.0%"}, {"sentence": "Loan-to-Value-Ratio: 65.0%.", "value": "65.0%"},
@ -203,6 +215,7 @@ def seed_default_kpi_settings():
"type": KPISettingType.NUMBER, "type": KPISettingType.NUMBER,
"position": 13, "position": 13,
"active": True, "active": True,
"is_trained": True,
"examples": [ "examples": [
{ {
"sentence": "Die Managementgebühren betragen jährlich 1.5%.", "sentence": "Die Managementgebühren betragen jährlich 1.5%.",
@ -220,6 +233,7 @@ def seed_default_kpi_settings():
"type": KPISettingType.ARRAY, "type": KPISettingType.ARRAY,
"position": 14, "position": 14,
"active": True, "active": True,
"is_trained": True,
"examples": [ "examples": [
{ {
"sentence": "Die Sektorenallokation umfasst Büro, Wohnen und Logistik.", "sentence": "Die Sektorenallokation umfasst Büro, Wohnen und Logistik.",
@ -237,6 +251,7 @@ def seed_default_kpi_settings():
"type": KPISettingType.ARRAY, "type": KPISettingType.ARRAY,
"position": 15, "position": 15,
"active": True, "active": True,
"is_trained": True,
"examples": [ "examples": [
{ {
"sentence": "Investitionen erfolgen in Deutschland, Frankreich und Österreich.", "sentence": "Investitionen erfolgen in Deutschland, Frankreich und Österreich.",
@ -260,6 +275,7 @@ def seed_default_kpi_settings():
position=kpi_data["position"], position=kpi_data["position"],
active=kpi_data["active"], active=kpi_data["active"],
examples=kpi_data.get("examples", []), examples=kpi_data.get("examples", []),
is_trained=kpi_data["is_trained"],
) )
db.session.add(kpi_setting) db.session.add(kpi_setting)
@ -273,3 +289,4 @@ def seed_default_kpi_settings():
db.session.rollback() db.session.rollback()
print(f"Fehler beim Hinzufügen der Standard KPI Settings: {e}") print(f"Fehler beim Hinzufügen der Standard KPI Settings: {e}")
raise raise

View File

@ -1394,7 +1394,6 @@
"across", "across",
"act", "act",
"active", "active",
"adasd23",
"add", "add",
"adv", "adv",
"adv.", "adv.",
@ -1684,7 +1683,7 @@
"d.h", "d.h",
"d.h.", "d.h.",
"d.x", "d.x",
"d23", "d34",
"dX", "dX",
"dXxx.\u20ac", "dXxx.\u20ac",
"d_d", "d_d",
@ -1758,6 +1757,7 @@
"dr.", "dr.",
"drawbacks", "drawbacks",
"driven", "driven",
"dsadad34",
"dte", "dte",
"du", "du",
"dual", "dual",
@ -1914,6 +1914,7 @@
"e\u2019s", "e\u2019s",
"f", "f",
"f.", "f.",
"f45",
"fa", "fa",
"fa.", "fa.",
"faktor", "faktor",
@ -1929,6 +1930,7 @@
"festgelegt", "festgelegt",
"festgelegter", "festgelegter",
"ff", "ff",
"fh5",
"fierce", "fierce",
"fil", "fil",
"financially", "financially",
@ -2026,6 +2028,8 @@
"ggfs.", "ggfs.",
"gg\u00fc", "gg\u00fc",
"gg\u00fc.", "gg\u00fc.",
"ghgh56",
"ghghgwef45",
"ght", "ght",
"gic", "gic",
"gie", "gie",
@ -2050,6 +2054,7 @@
"h.", "h.",
"h.c", "h.c",
"h.c.", "h.c.",
"h56",
"haltedauer", "haltedauer",
"halten", "halten",
"halten-strategie", "halten-strategie",
@ -2073,6 +2078,7 @@
"her", "her",
"here", "here",
"hes", "hes",
"hewhfh5",
"hf.", "hf.",
"hg", "hg",
"hg.", "hg.",
@ -2260,6 +2266,7 @@
"jeweiliges", "jeweiliges",
"jh", "jh",
"jh.", "jh.",
"jhchewqc7",
"jhd", "jhd",
"jhd.", "jhd.",
"jor", "jor",
@ -2293,9 +2300,11 @@
"key", "key",
"kindertagesst\u00e4tte", "kindertagesst\u00e4tte",
"kingdom", "kingdom",
"kkn7",
"kl.", "kl.",
"klassifikation", "klassifikation",
"klassifizierung", "klassifizierung",
"kn7",
"kontinentaleuropaische", "kontinentaleuropaische",
"kosten", "kosten",
"kt-", "kt-",
@ -2693,6 +2702,7 @@
"q.", "q.",
"q.e.d", "q.e.d",
"q.e.d.", "q.e.d.",
"qc7",
"quality", "quality",
"quarterly", "quarterly",
"quota", "quota",
@ -2791,12 +2801,14 @@
"sa.", "sa.",
"sale", "sale",
"sb.", "sb.",
"sc3",
"schule", "schule",
"schweden", "schweden",
"scope", "scope",
"scs", "scs",
"scsp", "scsp",
"sd.", "sd.",
"sdcdsc3",
"sector", "sector",
"sectors", "sectors",
"sed", "sed",
@ -3128,12 +3140,14 @@
"xxx-Xxxxx", "xxx-Xxxxx",
"xxx-xxxx", "xxx-xxxx",
"xxx.", "xxx.",
"xxxd",
"xxxx", "xxxx",
"xxxx+", "xxxx+",
"xxxx-xx", "xxxx-xx",
"xxxx-xxx", "xxxx-xxx",
"xxxx-xxxx", "xxxx-xxxx",
"xxxx.", "xxxx.",
"xxxxd",
"xxxxdd", "xxxxdd",
"xxxx\u2019x", "xxxx\u2019x",
"xxx\u2019x", "xxx\u2019x",

View File

@ -6,41 +6,56 @@ import type { Kennzahl } from "../types/kpi";
import { getDisplayType } from "../types/kpi"; import { getDisplayType } from "../types/kpi";
import { fetchKennzahlen as fetchK } from "../util/api"; import { fetchKennzahlen as fetchK } from "../util/api";
import { API_HOST } from "../util/api"; import { API_HOST } from "../util/api";
import WarningAmberIcon from "@mui/icons-material/WarningAmber";
type ConfigTableProps = {
export type ConfigTableProps = {
from?: string; from?: string;
trainingRunning?: boolean;
}; };
export function ConfigTable({ from }: ConfigTableProps) {
export function ConfigTable({ from, trainingRunning }: ConfigTableProps) {
const navigate = useNavigate(); const navigate = useNavigate();
const [kennzahlen, setKennzahlen] = useState<Kennzahl[]>([]); const [kennzahlen, setKennzahlen] = useState<Kennzahl[]>([]);
const [draggedItem, setDraggedItem] = useState<Kennzahl | null>(null); const [draggedItem, setDraggedItem] = useState<Kennzahl | null>(null);
const [isUpdatingPositions, setIsUpdatingPositions] = useState(false); const [isUpdatingPositions, setIsUpdatingPositions] = useState(false);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
useEffect(() => { const fetchKennzahlen = async () => {
const fetchKennzahlen = async () => { while (true) {
while (true) { try {
try { console.log("Fetching kennzahlen from API...");
console.log("Fetching kennzahlen from API..."); const data = await fetchK();
const data = await fetchK(); console.log("Fetched kennzahlen:", data);
console.log("Fetched kennzahlen:", data); const sortedData = data.sort((a, b) => a.position - b.position);
const sortedData = data.sort( setKennzahlen(sortedData);
(a: Kennzahl, b: Kennzahl) => a.position - b.position, setLoading(false);
); break;
setKennzahlen(sortedData); } catch (err) {
setLoading(false); console.error("Error fetching kennzahlen:", err);
break; await new Promise((resolve) => setTimeout(resolve, 2000));
} catch (err) {
console.error("Error fetching kennzahlen:", err);
await new Promise((resolve) => setTimeout(resolve, 2000));
}
} }
}; }
};
useEffect(() => {
fetchKennzahlen(); fetchKennzahlen();
}, []); }, []);
useEffect(() => {
if (trainingRunning === false) {
console.log("[ConfigTable] Training beendet → Kennzahlen neu laden...");
fetchKennzahlen();
}
}, [trainingRunning]);
const handleToggleActive = async (id: number) => { const handleToggleActive = async (id: number) => {
const kennzahl = kennzahlen.find((k) => k.id === id); const kennzahl = kennzahlen.find((k) => k.id === id);
if (!kennzahl) return; if (!kennzahl) return;
@ -326,15 +341,32 @@ export function ConfigTable({ from }: ConfigTableProps) {
padding: "12px", padding: "12px",
fontSize: "14px", fontSize: "14px",
color: "#333", color: "#333",
display: "flex",
alignItems: "center",
gap: "8px",
}} }}
> >
<span title={`Click to view details (ID: ${kennzahl.id})`}> <span title={`Click to view details (ID: ${kennzahl.id})`}>
{kennzahl.name} {kennzahl.name}
{kennzahl.mandatory && ( {kennzahl.mandatory && <span> *</span>}
<span> *</span>
)}
</span> </span>
{kennzahl.is_trained === false && (
<Tooltip
title={
<>
<b>Diese Kennzahl ist nicht trainiert.</b><br />
Klicken Sie oben auf <i>"Neu trainieren"</i>, um das Training zu starten.
</>
}
arrow
placement="right"
>
<WarningAmberIcon sx={{ color: "#f57c00", fontSize: 20 }} />
</Tooltip>
)}
</td> </td>
<td style={{ padding: "12px" }}> <td style={{ padding: "12px" }}>
<span <span
style={{ style={{

View File

@ -20,11 +20,8 @@ interface KPIFormProps {
const emptyKPI: Partial<Kennzahl> = { const emptyKPI: Partial<Kennzahl> = {
name: '', name: '',
description: '',
mandatory: false, mandatory: false,
type: 'string', type: 'string',
translation: '',
example: '',
active: true, active: true,
examples: [{ sentence: '', value: '' }], examples: [{ sentence: '', value: '' }],
}; };
@ -115,26 +112,24 @@ export function KPIForm({ mode, initialData, onSave, onCancel, loading = false,
// Dann in die DB speichern // Dann in die DB speichern
await onSave({ await onSave({
name: formData.name!, name: formData.name!,
description: formData.description || '',
mandatory: formData.mandatory ?? false, mandatory: formData.mandatory ?? false,
type: formData.type || 'string', type: formData.type || 'string',
translation: formData.translation || '',
example: formData.example || '',
position: formData.position ?? 0, position: formData.position ?? 0,
active: formData.active ?? true, active: formData.active ?? true,
examples: formData.examples ?? [] examples: formData.examples ?? [],
is_trained: false,
}); });
// Formular zurücksetzen: // Formular zurücksetzen:
setFormData(emptyKPI); setFormData(emptyKPI);
setSnackbarMessage("Beispielsätze gespeichert. Jetzt auf Neu trainieren klicken oder weitere Kennzahlen hinzufügen."); setSnackbarMessage("Beispielsätze gespeichert. Jetzt auf -Neu trainieren- klicken oder weitere Kennzahlen hinzufügen.");
setSnackbarSeverity("success"); setSnackbarSeverity("success");
setSnackbarOpen(true); setSnackbarOpen(true);
} catch (e: any) { } catch (e: any) {
// Prüfe auf 409-Fehler // Prüfe auf 409-Fehler
if (e?.message?.includes("409") || e?.response?.status === 409) { if (e?.message?.includes("409") || e?.response?.status === 409) {
setSnackbarMessage("Diese Kennzahl existiert bereits. Sie können sie unter Konfiguration bearbeiten."); setSnackbarMessage("Diese Kennzahl existiert bereits. Sie können sie unter -Konfiguration- bearbeiten.");
setSnackbarSeverity("info"); setSnackbarSeverity("info");
setSnackbarOpen(true); setSnackbarOpen(true);
} else { } else {

View File

@ -165,12 +165,16 @@ function ConfigPage() {
}} }}
> >
{trainingRunning ? ( {trainingRunning ? (
<CircularProgress size={24} sx={{ color: "white" }} /> <>
<CircularProgress size={20} sx={{ color: "white", mr: 1 }} />
Wird trainiert...
</>
) : ( ) : (
"Neu trainieren" "Neu trainieren"
)} )}
</Button> </Button>
<Button <Button
variant="contained" variant="contained"
onClick={handleAddNewKPI} onClick={handleAddNewKPI}
@ -186,7 +190,7 @@ function ConfigPage() {
{/* Tabelle */} {/* Tabelle */}
<Box sx={{ width: "100%", mt: 4, display: "flex", justifyContent: "center" }}> <Box sx={{ width: "100%", mt: 4, display: "flex", justifyContent: "center" }}>
<ConfigTable from={from} /> <ConfigTable from={from} trainingRunning={trainingRunning} />
</Box> </Box>
</Box> </Box>

View File

@ -1,11 +1,8 @@
export interface Kennzahl { export interface Kennzahl {
id: number; id: number;
name: string; name: string;
description: string;
mandatory: boolean; mandatory: boolean;
type: string; type: string;
translation: string;
example: string;
position: number; position: number;
active: boolean; active: boolean;
exampleText?: string; exampleText?: string;
@ -14,6 +11,7 @@ export interface Kennzahl {
sentence: string; sentence: string;
value: string; value: string;
}[]; }[];
is_trained?: boolean;
} }
export const typeDisplayMapping: Record<string, string> = { export const typeDisplayMapping: Record<string, string> = {

View File

@ -5,6 +5,9 @@ import { defineConfig } from "vite";
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [TanStackRouterVite({ autoCodeSplitting: true }), viteReact()], plugins: [TanStackRouterVite({ autoCodeSplitting: true }), viteReact()],
build: {
chunkSizeWarningLimit: 1000, // default ist 500
},
test: { test: {
globals: true, globals: true,
environment: "jsdom", environment: "jsdom",