Neu trainieren-Button deaktiviert, wenn keine neuen Kennzahlen vorhanden sind; Trainingsdaten werden beim Start bereinigt

pull/94/head
Abdulrahman Dabbagh 2025-06-29 16:34:25 +02:00
parent 521ac1dcbd
commit 5af1d40c08
6 changed files with 90 additions and 186 deletions

View File

@ -1,11 +1,12 @@
from controller.spacy_controller import spacy_controller
from controller.kpi_setting_controller import kpi_setting_controller
from controller.kpi_setting_controller import kpi_setting_controller, kpi_routes
from controller.pitch_book_controller import pitch_book_controller
from controller.progress_controller import progress_controller
def register_routes(app):
app.register_blueprint(kpi_setting_controller)
app.register_blueprint(kpi_routes)
app.register_blueprint(pitch_book_controller)
app.register_blueprint(spacy_controller)
app.register_blueprint(progress_controller)

View File

@ -2,7 +2,10 @@ from flask import Blueprint, request, jsonify
from model.database import db
from model.kpi_setting_model import KPISettingModel, KPISettingType
# Routen für /api/kpi/settings (Auslesen im Frontend)
kpi_routes = Blueprint("kpi_routes", __name__, url_prefix="/api/kpi")
# Routen für /api/kpi_setting/ (Hinzufügen, Ändern, Löschen)
kpi_setting_controller = Blueprint(
"kpi_settings", __name__, url_prefix="/api/kpi_setting"
)
@ -14,12 +17,6 @@ def get_all_kpi_settings():
return jsonify([kpi_setting.to_dict() for kpi_setting in kpi_settings]), 200
@kpi_setting_controller.route("/<int:id>", methods=["GET"])
def get_kpi_setting(id):
kpi_setting = KPISettingModel.query.get_or_404(id)
return jsonify(kpi_setting.to_dict()), 200
@kpi_setting_controller.route("/", methods=["POST"])
def create_kpi_setting():
data = request.json
@ -149,3 +146,21 @@ def update_kpi_positions():
except Exception as e:
db.session.rollback()
return jsonify({"error": f"Failed to update positions: {str(e)}"}), 500
@kpi_routes.route("/settings", methods=["GET"])
def get_kpi_settings():
try:
kpis = KPISettingModel.query.all()
return jsonify([k.to_dict() for k in kpis]), 200
except Exception as e:
return (
jsonify({"error": "Fehler beim Abrufen der KPIs", "details": str(e)}),
500,
)
@kpi_setting_controller.route("/<int:id>", methods=["GET"])
def get_kpi_setting(id):
kpi_setting = KPISettingModel.query.get_or_404(id)
return jsonify(kpi_setting.to_dict()), 200

View File

@ -519,16 +519,6 @@
]
]
},
{
"text": "Laufzeit / Investtionszeltraum,10 bis 12 Jahre / bis zu 24 Monate angestrebt Ausschüttungsintervalle,Mindestens jährlich",
"entities": [
[
31,
46,
"LAUFZEIT"
]
]
},
{
"text": "10-12 Jahre Laufzeit bei einem LTV von bis zu 20%",
"entities": [
@ -594,21 +584,6 @@
]
]
},
{
"text": "Vehicle / domicile Alternative Investment Fund / Luxembourg (e.g. SCSp SICAV-RAIF) Investment strategy eturn pro Real Estate (PropCo + OpCo) Investing in upscale hotels with long-term management contracts in major European destinations Core/Core+ with OpCo premium Management Agreements solely with financially strong and experienced partners/ global brands Cash flow-oriented Cash-flow pattern Target equity /AuM € 400m equity / € 800m AuM (50% Loan-to-Value) Vehicle lifetime / investment period Open-ended fund",
"entities": [
[
498,
513,
"LAUFZEIT"
],
[
236,
245,
"RISIKOPROFIL"
]
]
},
{
"text": "Vehicle type (Lux-RAIF) (net of fees) IRR6.5% ACCOR Vehicle structure Open-ended Targetvehiclesize € 400m (equity) Manager-defined Core/Core+ with | style OpCo Premium darge CLV. 50% Pt H | LTO N WORLDWIDE Year of first closing 2020 Target no. ofinvestors 1-5 Fund life (yrs} Open-ended Min-commitmentper —¢ 400m",
"entities": [
@ -729,31 +704,6 @@
]
]
},
{
"text": "Prognose: 7,5%+ IRR auf Fondsebene",
"entities": [
[
10,
14,
"RENDITE"
]
]
},
{
"text": "= Prognostizierte jährliche Ausschüttung* von 84,0% = Prognostizierte Gesamtrendite (IRR}* von 7,5%",
"entities": [
[
96,
100,
"RENDITE"
],
[
49,
53,
"AUSSCHÜTTUNGSRENDITE"
]
]
},
{
"text": "= Lagefokussierung: Metropolregionen Deutschlands = Finanzierung: max. 20% LTV = Risikoprofil: Core, Core +",
"entities": [
@ -1054,36 +1004,6 @@
]
]
},
{
"text": "Unternehmensimmobilien Club 1 2016 Light Industrial Core+/D € 186 Mio. 9 (voll investiert) 13,0 % p.a.",
"entities": [
[
52,
57,
"RISIKOPROFIL"
],
[
91,
97,
"RENDITE"
]
]
},
{
"text": "Unternehmensimmobilien Club 2 2021 Light Industrial Core+/D € 262 Mio. 12 (voll investiert) 9,00 % p.a.",
"entities": [
[
52,
57,
"RISIKOPROFIL"
],
[
92,
98,
"RENDITE"
]
]
},
{
"text": "Individualmandat 2022 Light Industrial Value-Add / Nordics € 100 Mio. 5 (voll investiert) 18,0 % p.a.",
"entities": [

View File

@ -127,13 +127,10 @@
"/080%/212%/491",
"/2,12",
"/3",
"/AuM",
"/Core+",
"/FK",
"/XX",
"/XxX",
"/Xxxx+",
"/aum",
"/core+",
"/d",
"/d,dd",
@ -276,7 +273,6 @@
"45",
"491",
"5",
"5%+",
"5,0",
"5,00",
"5,1",
@ -306,7 +302,6 @@
"7",
"7,1",
"7,5",
"7,5%+",
"7,50",
"7,50%+",
"7.5",
@ -323,8 +318,6 @@
"8-D",
"8-d",
"80",
"800",
"84,0",
"85",
"8D",
"8d",
@ -464,7 +457,6 @@
"Abteilung",
"Access",
"Add",
"Agreements",
"Aktive",
"Aktueller",
"AlF",
@ -472,7 +464,6 @@
"Allocation",
"Allokation",
"Allokationsprofil",
"Alternative",
"Amsterdam",
"Andere",
"Anfrage",
@ -508,7 +499,6 @@
"Artikel",
"Asset",
"Assets",
"AuM",
"Aufbau",
"Auflage",
"Aufl\u00f6sung",
@ -578,10 +568,7 @@
"COR",
"CORE",
"CSU",
"CSp",
"Cash",
"Cash-Flow-Stabilit\u00e4t",
"Cash-flow",
"Chr",
"Chr.",
"Cie",
@ -815,7 +802,6 @@
"Interner",
"Invastitionsfokus",
"Investftionsvolumen",
"Investing",
"Investitionen",
"Investitions-annahmen",
"Investitionsphase",
@ -825,7 +811,6 @@
"Investmentzeitraum",
"Investoren",
"Investtionszeltraum",
"Investtionszeltraum,10",
"Investtonszeltraum",
"Ireland",
"Irland",
@ -897,7 +882,6 @@
"Light",
"Limited",
"Lisbon",
"Loan-to-Value",
"Local",
"Logistics",
"Logistik",
@ -1048,12 +1032,10 @@
"Prof",
"Prof.",
"Professor",
"Prognose",
"Prognostiderte",
"Prognostizierte",
"Projektentwicklungen",
"Projektentwicklungsrisiken",
"PropCo",
"Pt",
"Punkt",
"Q",
@ -1095,7 +1077,6 @@
"S",
"S'",
"SCS",
"SCSp",
"SEKTORENALLOKATION",
"SFDR",
"SG-",
@ -1254,7 +1235,6 @@
"XXXX",
"XXXX-XXXX",
"XXXd.d",
"XXXx",
"XXXxx",
"XXx",
"XXxxxx",
@ -1279,18 +1259,15 @@
"Xxxx-XXX",
"Xxxx-Xxxx-Xxxxx",
"Xxxx-Xxxxx-XXX",
"Xxxx-xx-Xxxxx",
"Xxxx-xxx",
"Xxxx-xxxx",
"Xxxx.",
"Xxxx.-Xxx",
"Xxxx.-Xxx.",
"XxxxXx",
"Xxxxx",
"Xxxxx)-",
"Xxxxx)/Xxxx",
"Xxxxx+",
"Xxxxx,dd",
"Xxxxx-",
"Xxxxx-XXX",
"Xxxxx-XxX",
@ -1371,6 +1348,7 @@
"a.g.",
"a.m.",
"a.z.",
"a34",
"ab",
"abb",
"abb.",
@ -1401,7 +1379,6 @@
"ae",
"aft",
"age",
"agreements",
"aha",
"ahe",
"ahl",
@ -1427,7 +1404,6 @@
"allokationsprofil",
"als",
"also",
"alternative",
"aly",
"am.",
"ambulant",
@ -1483,7 +1459,6 @@
"ary",
"as",
"ase",
"ash",
"ass",
"asset",
"assetor",
@ -1529,7 +1504,6 @@
"b.sc",
"b.sc.",
"bahnhof",
"bal",
"balanced",
"basis",
"bau",
@ -1571,7 +1545,6 @@
"both",
"bps",
"br.",
"brands",
"broad",
"brussels",
"bruttofondsverm\u00f6gens",
@ -1604,8 +1577,6 @@
"capital",
"capped",
"carbon",
"cash",
"cash-flow",
"cash-flow-stabilit\u00e4t",
"cbd",
"cdu",
@ -1666,7 +1637,6 @@
"d+au",
"d+aut",
"d,d",
"d,d%+",
"d,dd",
"d,dd%+",
"d,ddd",
@ -1683,7 +1653,6 @@
"d.h",
"d.h.",
"d.x",
"d34",
"dX",
"dXxx.\u20ac",
"d_d",
@ -1693,6 +1662,7 @@
"darge",
"darlehen",
"das",
"dasda34",
"dat",
"dd",
"dd,d",
@ -1718,7 +1688,6 @@
"der",
"dergleichen",
"des",
"destinations",
"deutsche",
"deutsches",
"deutschland",
@ -1749,7 +1718,6 @@
"dle",
"do",
"do.",
"domicile",
"domiciled",
"don",
"down",
@ -1757,7 +1725,6 @@
"dr.",
"drawbacks",
"driven",
"dsadad34",
"dte",
"du",
"dual",
@ -1828,7 +1795,6 @@
"eln",
"els",
"elt",
"ely",
"em",
"em.",
"emerging",
@ -1882,7 +1848,6 @@
"ete",
"etr",
"ets",
"eturn",
"eu-offenlegungsverordnung",
"eur",
"euro",
@ -1914,7 +1879,6 @@
"e\u2019s",
"f",
"f.",
"f45",
"fa",
"fa.",
"faktor",
@ -1930,10 +1894,8 @@
"festgelegt",
"festgelegter",
"ff",
"fh5",
"fierce",
"fil",
"financially",
"finanzierung",
"finanzierungskonditionen",
"finland",
@ -1941,7 +1903,6 @@
"first",
"flagship",
"flow",
"flow-oriented",
"fl\u00e4che",
"focus",
"focused",
@ -2028,13 +1989,10 @@
"ggfs.",
"gg\u00fc",
"gg\u00fc.",
"ghgh56",
"ghghgwef45",
"ght",
"gic",
"gie",
"gl.",
"global",
"globale",
"gmbh",
"goal",
@ -2054,7 +2012,6 @@
"h.",
"h.c",
"h.c.",
"h56",
"haltedauer",
"halten",
"halten-strategie",
@ -2078,7 +2035,6 @@
"her",
"here",
"hes",
"hewhfh5",
"hf.",
"hg",
"hg.",
@ -2216,7 +2172,6 @@
"investoren",
"investors",
"investtionszeltraum",
"investtionszeltraum,10",
"investtonszeltraum",
"inw",
"io.",
@ -2266,7 +2221,6 @@
"jeweiliges",
"jh",
"jh.",
"jhchewqc7",
"jhd",
"jhd.",
"jor",
@ -2300,11 +2254,9 @@
"key",
"kindertagesst\u00e4tte",
"kingdom",
"kkn7",
"kl.",
"klassifikation",
"klassifizierung",
"kn7",
"kontinentaleuropaische",
"kosten",
"kt-",
@ -2362,8 +2314,6 @@
"lls",
"llt",
"llv",
"lly",
"loan-to-value",
"local",
"locations",
"lock-in",
@ -2371,7 +2321,6 @@
"logistik",
"logistikimmobilien",
"london",
"long-term",
"low",
"lps",
"lso",
@ -2644,9 +2593,7 @@
"parformanceabh\u00e4ngige",
"paris",
"parks",
"partners",
"partnership",
"pattern",
"ped",
"pen",
"per",
@ -2677,18 +2624,15 @@
"pricey",
"pricing",
"prime",
"pro",
"prof",
"prof.",
"profile",
"prognose",
"prognostiderte",
"prognostizierte",
"program",
"projects",
"projektentwicklungen",
"projektentwicklungsrisiken",
"propco",
"properties",
"proprietary",
"provide",
@ -2702,7 +2646,6 @@
"q.",
"q.e.d",
"q.e.d.",
"qc7",
"quality",
"quarterly",
"quota",
@ -2801,14 +2744,11 @@
"sa.",
"sale",
"sb.",
"sc3",
"schule",
"schweden",
"scope",
"scs",
"scsp",
"sd.",
"sdcdsc3",
"sector",
"sectors",
"sed",
@ -2849,7 +2789,6 @@
"sofern",
"sog",
"sog.",
"solely",
"solvency",
"some",
"son",
@ -3140,14 +3079,12 @@
"xxx-Xxxxx",
"xxx-xxxx",
"xxx.",
"xxxd",
"xxxx",
"xxxx+",
"xxxx-xx",
"xxxx-xxx",
"xxxx-xxxx",
"xxxx.",
"xxxxd",
"xxxxdd",
"xxxx\u2019x",
"xxx\u2019x",

View File

@ -11,6 +11,7 @@ import CircularProgress from "@mui/material/CircularProgress";
export const Route = createFileRoute("/config")({
component: ConfigPage,
validateSearch: (search: Record<string, unknown>): { from?: string; success?: string } => {
@ -28,6 +29,28 @@ function ConfigPage() {
const [snackbarOpen, setSnackbarOpen] = useState(success === "true");
const [snackbarMessage, setSnackbarMessage] = useState<string>("Beispielsätze gespeichert. Jetzt auf -Neu trainieren- klicken oder zuerst weitere Kennzahlen hinzufügen.");
const [trainingRunning, setTrainingRunning] = useState(false);
const [hasUntrainedKPIs, setHasUntrainedKPIs] = useState(false);
const fetchKPISettings = async () => {
try {
const res = await fetch(`${API_HOST}/api/kpi/settings`);
const data = await res.json();
console.log("🔍 GELADENE KPIs:", data);
const untrainedExists = data.some((kpi: any) => {
console.log("➡️", kpi.name, "is_trained:", kpi.is_trained);
return kpi.is_trained === false;
});
setHasUntrainedKPIs(untrainedExists);
} catch (err) {
console.error("Fehler beim Laden der KPIs:", err);
}
};
useEffect(() => {
fetchKPISettings();
}, []);
@ -61,8 +84,7 @@ function ConfigPage() {
checkInitialTrainingStatus();
}, []);
const handleAddNewKPI = () => {
navigate({
to: "/config-add",
@ -113,8 +135,11 @@ function ConfigPage() {
console.log("Training abgeschlossen Snackbar wird ausgelöst");
setSnackbarMessage("Training abgeschlossen!");
setSnackbarOpen(true);
setTrainingRunning(false);
fetchKPISettings(); // 👉 hier hinzufügen!
}
} catch (err) {
console.error("Polling-Fehler:", err);
@ -152,40 +177,46 @@ function ConfigPage() {
Konfiguration der Kennzahlen
</Typography>
</Box>
<Box display="flex" flexDirection="column" alignItems="flex-end" gap={1}>
<Box display="flex" gap={2}>
<Button
variant="contained"
onClick={handleTriggerTraining}
disabled={trainingRunning || !hasUntrainedKPIs}
sx={{
backgroundColor: "#383838",
"&:hover": { backgroundColor: "#2e2e2e" },
}}
>
{trainingRunning ? (
<>
<CircularProgress size={20} sx={{ color: "white", mr: 1 }} />
Wird trainiert...
</>
) : (
"Neu trainieren"
)}
</Button>
{/* Rechte Seite: Buttons */}
<Box display="flex" gap={2}>
<Button
variant="contained"
onClick={handleTriggerTraining}
disabled={trainingRunning}
sx={{
backgroundColor: "#383838",
"&:hover": { backgroundColor: "#2e2e2e" },
}}
>
{trainingRunning ? (
<>
<CircularProgress size={20} sx={{ color: "white", mr: 1 }} />
Wird trainiert...
</>
) : (
"Neu trainieren"
)}
</Button>
<Button
variant="contained"
onClick={handleAddNewKPI}
sx={{
backgroundColor: "#383838",
"&:hover": { backgroundColor: "#2e2e2e" },
}}
>
Neue Kennzahl hinzufügen
</Button>
</Box>
<Button
variant="contained"
onClick={handleAddNewKPI}
sx={{
backgroundColor: "#383838",
"&:hover": { backgroundColor: "#2e2e2e" },
}}
>
Neue Kennzahl hinzufügen
</Button>
{!hasUntrainedKPIs && (
<Typography variant="body2" color="text.secondary" mt={1}>
Alle Kennzahlen sind bereits trainiert.
</Typography>
)}
</Box>
</Box>
{/* Tabelle */}