Compare commits

..

No commits in common. "b9d7f425e5e5f225ffde8e22b9355b4bb54c35d4" and "05d428990268cb9980527e1f7563a3d9a2e06a2a" have entirely different histories.

21 changed files with 7907 additions and 493 deletions

View File

@ -1,21 +0,0 @@
# 1. Python-Image verwenden
FROM python:3.11-alpine
# 2. Arbeitsverzeichnis im Container setzen
WORKDIR /app
# 3. production-style server mit gunicorn
RUN pip install gunicorn eventlet
# 4. requirements.txt kopieren und Pakete installieren
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 5. Quellcode kopieren (z.B. app.py)
COPY . .
ENV PYTHONUNBUFFERED=1
EXPOSE 5000
CMD ["gunicorn", "--worker-class", "eventlet", "-w", "1", "--bind", "0.0.0.0:5000", "app:app"]

View File

@ -1,14 +1,10 @@
from flask import Flask from flask import Flask
from flask_cors import CORS
import os import os
from dotenv import load_dotenv from dotenv import load_dotenv
from controller import register_routes from controller import register_routes
from model.database import init_db from model.database import init_db
from controller.socketIO import socketio
app = Flask(__name__) app = Flask(__name__)
CORS(app)
socketio.init_app(app)
load_dotenv() load_dotenv()
DATABASE_URL = os.getenv("DATABASE_URL") DATABASE_URL = os.getenv("DATABASE_URL")
@ -29,4 +25,4 @@ def health_check():
# für Docker wichtig: host='0.0.0.0' # für Docker wichtig: host='0.0.0.0'
if __name__ == "__main__": if __name__ == "__main__":
socketio.run(app,debug=True, host="0.0.0.0", port=5050) app.run(debug=True, host="0.0.0.0")

View File

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

View File

@ -4,7 +4,6 @@ from model.pitch_book_model import PitchBookModel
from io import BytesIO from io import BytesIO
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
import puremagic import puremagic
from controller.socketIO import socketio
pitch_book_controller = Blueprint("pitch_books", __name__, url_prefix="/api/pitch_book") pitch_book_controller = Blueprint("pitch_books", __name__, url_prefix="/api/pitch_book")
@ -55,7 +54,6 @@ def upload_file():
db.session.add(new_file) db.session.add(new_file)
db.session.commit() db.session.commit()
socketio.emit("progress", {"id": new_file.id, "progress": 0})
return jsonify(new_file.to_dict()), 201 return jsonify(new_file.to_dict()), 201
except Exception as e: except Exception as e:
print(e) print(e)
@ -83,7 +81,6 @@ def update_file(id):
print(e) print(e)
if "kpi" in request.form: if "kpi" in request.form:
socketio.emit("progress", {"id": id, "progress": 100})
file.kpi = request.form.get("kpi") file.kpi = request.form.get("kpi")
db.session.commit() db.session.commit()

View File

@ -1,19 +0,0 @@
from flask import Blueprint, request, jsonify
from controller.socketIO import socketio
progress_controller = Blueprint("progress", __name__, url_prefix="/api/progress")
@progress_controller.route("/", methods=["POST"])
def progress():
data = request.get_json()
if 'id' not in data or 'progress' not in data:
return jsonify({"error": "Missing required fields. [id, progress]"}), 400
if not isinstance(data['progress'], (int, float)) or data['progress'] < 0 or data['progress'] >= 100:
return jsonify({"error": "Invalid progress value"}), 400
socketio.emit("progress", {"id": data["id"], "progress": data["progress"]})
# Process the data and return a response
return jsonify({"message": "Progress updated"})

View File

@ -1,3 +0,0 @@
from flask_socketio import SocketIO
socketio = SocketIO(cors_allowed_origins="*")

View File

@ -1,4 +1,3 @@
bidict==0.23.1
black==25.1.0 black==25.1.0
blinker==1.9.0 blinker==1.9.0
cfgv==3.4.0 cfgv==3.4.0
@ -7,11 +6,8 @@ distlib==0.3.9
filelock==3.18.0 filelock==3.18.0
flake8==7.2.0 flake8==7.2.0
Flask==3.1.1 Flask==3.1.1
flask-cors==6.0.0
Flask-SocketIO==5.5.1
Flask-SQLAlchemy==3.1.1 Flask-SQLAlchemy==3.1.1
greenlet==3.2.2 greenlet==3.2.2
h11==0.16.0
identify==2.6.12 identify==2.6.12
itsdangerous==2.2.0 itsdangerous==2.2.0
Jinja2==3.1.6 Jinja2==3.1.6
@ -28,12 +24,8 @@ puremagic==1.29
pycodestyle==2.13.0 pycodestyle==2.13.0
pyflakes==3.3.2 pyflakes==3.3.2
python-dotenv==1.1.0 python-dotenv==1.1.0
python-engineio==4.12.1
python-socketio==5.13.0
PyYAML==6.0.2 PyYAML==6.0.2
simple-websocket==1.1.0
SQLAlchemy==2.0.41 SQLAlchemy==2.0.41
typing_extensions==4.13.2 typing_extensions==4.13.2
virtualenv==20.31.2 virtualenv==20.31.2
Werkzeug==3.1.3 Werkzeug==3.1.3
wsproto==1.2.0

View File

@ -19,11 +19,11 @@ services:
coordinator: coordinator:
build: build:
context: backend/coordinator context: backend/coordinator
dockerfile: ../../Dockerfile
env_file: env_file:
- .env - .env
depends_on: depends_on:
db: - db
condition: service_healthy
healthcheck: healthcheck:
test: wget --spider --no-verbose http://127.0.0.1:5000/health || exit 1 test: wget --spider --no-verbose http://127.0.0.1:5000/health || exit 1
interval: 10s interval: 10s

View File

@ -12,7 +12,7 @@
}, },
"formatter": { "formatter": {
"enabled": true, "enabled": true,
"indentStyle": "tab" "indentStyle": "space"
}, },
"organizeImports": { "organizeImports": {
"enabled": true "enabled": true

Binary file not shown.

View File

@ -20,4 +20,4 @@ server {
location = /50x.html { location = /50x.html {
root /usr/share/nginx/html; root /usr/share/nginx/html;
} }
} }

7590
project/frontend/package-lock.json generated 100644

File diff suppressed because it is too large Load Diff

View File

@ -26,8 +26,7 @@
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
"react-material-file-upload": "^0.0.4", "react-material-file-upload": "^0.0.4",
"react-pdf": "^8.0.2", "react-pdf": "^9.2.1"
"socket.io-client": "^4.8.1"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "1.9.4", "@biomejs/biome": "1.9.4",

View File

@ -1,33 +0,0 @@
import Box from "@mui/material/Box";
import CircularProgress, {
type CircularProgressProps,
} from "@mui/material/CircularProgress";
import Typography from "@mui/material/Typography";
export function CircularProgressWithLabel(
props: CircularProgressProps & { value: number },
) {
return (
<Box sx={{ position: "relative", display: "inline-flex" }}>
<CircularProgress {...props} />
<Box
sx={{
top: 0,
left: 0,
bottom: 0,
right: 0,
position: "absolute",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
<Typography
variant="subtitle1"
component="div"
sx={{ color: "inherit" }}
>{`${Math.round(props.value)}%`}</Typography>
</Box>
</Box>
);
}

View File

@ -1,178 +1,100 @@
import SettingsIcon from "@mui/icons-material/Settings"; import { useState } from 'react'
import { Backdrop, Box, Button, IconButton, Paper } from "@mui/material"; import FileUpload from 'react-material-file-upload'
import { useNavigate } from "@tanstack/react-router"; import {Box, Button, IconButton, Paper} from '@mui/material'
import { useCallback, useEffect, useState } from "react"; import { useNavigate } from '@tanstack/react-router'
import FileUpload from "react-material-file-upload"; import SettingsIcon from '@mui/icons-material/Settings';
import { socket } from "../socket";
import { CircularProgressWithLabel } from "./CircularProgressWithLabel";
const PROGRESS = false;
export default function UploadPage() { export default function UploadPage() {
const [files, setFiles] = useState<File[]>([]); const [files, setFiles] = useState<File[]>([])
const [pageId, setPageId] = useState<string | null>(null); const fileTypes = ["pdf"];
const [loadingState, setLoadingState] = useState<number | null>(null); const navigate = useNavigate()
const fileTypes = ["pdf"];
const navigate = useNavigate();
const uploadFile = useCallback(async () => { return (
const formData = new FormData(); <Box
formData.append("file", files[0]); display="flex"
const response = await fetch("http://localhost:5050/api/pitch_book", { flexDirection="column"
method: "POST", alignItems="center"
body: formData, justifyContent="center"
}); height="100vh"
bgcolor="white"
if (response.ok) { >
console.log("File uploaded successfully"); <Box
const data = await response.json(); width="100%"
console.log(data); maxWidth="1300px"
setPageId(data.id); display="flex"
setLoadingState(0); justifyContent="flex-end"
px={2}
!PROGRESS && >
navigate({ <IconButton onClick={() => navigate({ to: '/config' })}>
to: "/extractedResult/$pitchBook", <SettingsIcon fontSize="large"/>
params: { pitchBook: data.id }, </IconButton>
}); </Box>
} else { <Paper
console.error("Failed to upload file"); elevation={3}
} sx={{
}, [files, navigate]); width: 900,
height: 500,
const onConnection = useCallback(() => { backgroundColor: '#eeeeee',
console.log("connected"); borderRadius: 4,
}, []); display: 'flex',
justifyContent: 'center',
const onProgress = useCallback( alignItems: 'center',
(progress: { id: number; progress: number }) => { }}
console.log("Progress:", progress); >
console.log(pageId); <Box sx={{
if (Number(pageId) === progress.id) { height: '100%',
setLoadingState(progress.progress); width: '100%',
maxWidth: '100%',
if (progress.progress === 100) { margin: '0px',
navigate({ padding: '0px',
to: "/extractedResult/$pitchBook", '& .MuiBox-root': {
params: { pitchBook: progress.id.toString() }, display: 'flex',
}); flexDirection: 'column',
} alignItems: 'center',
} justifyContent: 'center',
}, border: 'none',
[pageId, navigate], textAlign: 'center',
); },
}}>
useEffect(() => { <FileUpload
socket.on("connect", onConnection); value={files}
socket.on("progress", onProgress); onChange={setFiles}
return () => { accept={`.${fileTypes.join(', .')}`}
socket.off("connect", onConnection); title="Hier Dokument hinziehen"
socket.off("progress", onProgress); buttonText="Datei auswählen"
}; sx={{
}, [onConnection, onProgress]); height: '100%',
width: '100%',
return ( padding: '0px',
<> '& svg': {
{PROGRESS && ( color: '#9e9e9e',
<Backdrop },
sx={(theme) => ({ color: "#fff", zIndex: theme.zIndex.drawer + 1 })} '& .MuiOutlinedInput-notchedOutline': {
open={pageId !== null && loadingState !== null} border: 'none',
> },
<CircularProgressWithLabel '& .MuiButton-root': {
color="inherit" backgroundColor: '#9e9e9e',
value={loadingState || 0} },
size={60} '& .MuiTypography-root': {
/> fontSize: '1.25rem',
</Backdrop> fontWeight: 500,
)} marginBottom: 1,
<Box },
display="flex" }}
flexDirection="column" />
alignItems="center" </Box>
justifyContent="center" </Paper>
height="100vh" <Button
bgcolor="white" variant="contained"
> sx={{
<Box mt: 4,
width="100%" backgroundColor: '#383838',
maxWidth="1300px" }}
display="flex" disabled={files.length === 0}
justifyContent="flex-end" onClick={() => navigate({ to: '/extractedResult' })}
px={2} >
> Kennzahlen extrahieren
<IconButton onClick={() => navigate({ to: "/config" })}> </Button>
<SettingsIcon fontSize="large" /> </Box>
</IconButton> )
</Box> }
<Paper
elevation={3}
sx={{
width: 900,
height: 500,
backgroundColor: "#eeeeee",
borderRadius: 4,
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<Box
sx={{
height: "100%",
width: "100%",
maxWidth: "100%",
margin: "0px",
padding: "0px",
"& .MuiBox-root": {
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
border: "none",
textAlign: "center",
},
}}
>
<FileUpload
value={files}
onChange={setFiles}
accept={`.${fileTypes.join(", .")}`}
title="Hier Dokument hinziehen"
buttonText="Datei auswählen"
sx={{
height: "100%",
width: "100%",
padding: "0px",
"& svg": {
color: "#9e9e9e",
},
"& .MuiOutlinedInput-notchedOutline": {
border: "none",
},
"& .MuiButton-root": {
backgroundColor: "#9e9e9e",
},
"& .MuiTypography-root": {
fontSize: "1.25rem",
fontWeight: 500,
marginBottom: 1,
},
}}
/>
</Box>
</Paper>
<Button
variant="contained"
sx={{
mt: 4,
backgroundColor: "#383838",
}}
disabled={files.length === 0}
onClick={uploadFile}
>
Kennzahlen extrahieren
</Button>
</Box>
</>
);
}

View File

@ -1,93 +1,91 @@
import { useEffect, useRef, useState } from "react"; import { Document, Page, pdfjs } from "react-pdf";
import { Document, Page } from "react-pdf"; import { useState, useRef, useEffect } from 'react';
import "react-pdf/dist/esm/Page/AnnotationLayer.css"; import 'react-pdf/dist/esm/Page/AnnotationLayer.css';
import "react-pdf/dist/esm/Page/TextLayer.css"; import 'react-pdf/dist/esm/Page/TextLayer.css';
import ArrowCircleLeftIcon from "@mui/icons-material/ArrowCircleLeft"; import { Box, IconButton } from '@mui/material';
import ArrowCircleRightIcon from "@mui/icons-material/ArrowCircleRight"; import ArrowCircleLeftIcon from '@mui/icons-material/ArrowCircleLeft';
import { Box, IconButton } from "@mui/material"; import ArrowCircleRightIcon from '@mui/icons-material/ArrowCircleRight';
import testPDF from '/example.pdf';
interface PDFViewerProps { pdfjs.GlobalWorkerOptions.workerSrc = new URL(
pitchBookId: string; "pdfjs-dist/build/pdf.worker.min.mjs",
} import.meta.url,
export default function PDFViewer({ pitchBookId }: PDFViewerProps) { ).toString();
const [numPages, setNumPages] = useState<number | null>(null);
const [pageNumber, setPageNumber] = useState(1);
const [containerWidth, setContainerWidth] = useState<number | null>(null);
const containerRef = useRef<HTMLDivElement>(null);
const onDocumentLoadSuccess = ({ numPages }: { numPages: number }) => { export default function PDFViewer() {
setNumPages(numPages); const [numPages, setNumPages] = useState<number | null>(null);
}; const [pageNumber, setPageNumber] = useState(1);
const [containerWidth, setContainerWidth] = useState<number | null>(null);
useEffect(() => { const containerRef = useRef<HTMLDivElement>(null);
const updateWidth = () => {
if (containerRef.current) {
setContainerWidth(containerRef.current.offsetWidth);
}
};
updateWidth(); const onDocumentLoadSuccess = ({ numPages }: { numPages: number }) => {
window.addEventListener("resize", updateWidth); setNumPages(numPages);
return () => window.removeEventListener("resize", updateWidth); };
}, []);
return ( useEffect(() => {
<Box const updateWidth = () => {
display="flex" if (containerRef.current) {
flexDirection="column" setContainerWidth(containerRef.current.offsetWidth);
justifyContent="center" }
alignItems="center" };
width="100%"
height="100%" updateWidth();
p={2} window.addEventListener('resize', updateWidth);
> return () => window.removeEventListener('resize', updateWidth);
<Box }, []);
ref={containerRef}
sx={{ return (
width: "100%", <Box
maxHeight: "90vh", display="flex"
overflow: "auto", flexDirection="column"
display: "flex", justifyContent="center"
justifyContent: "center", alignItems="center"
alignItems: "center", width="100%"
}} height="100%"
> p={2}
<Document >
file={`http://localhost:5050/api/pitch_book/${pitchBookId}/download`} <Box
onLoadSuccess={onDocumentLoadSuccess} ref={containerRef}
onLoadError={(error) => sx={{
console.error("Es gab ein Fehler beim Laden des PDFs:", error) width: '100%',
} maxHeight: '90vh',
onSourceError={(error) => console.error("Ungültige PDF:", error)} overflow: 'auto',
> display: 'flex',
{containerWidth && ( justifyContent: 'center',
<Page pageNumber={pageNumber} width={containerWidth * 0.8} /> alignItems: 'center',
)} }}
</Document> >
</Box> <Document file={testPDF}
<Box onLoadSuccess={onDocumentLoadSuccess}
mt={2} onLoadError={(error) => console.error('Es gab ein Fehler beim Laden des PDFs:', error)}
display="flex" onSourceError={(error) => console.error('Ungültige PDF:', error)}>
alignItems="center" {containerWidth && (
justifyContent="center" <Page
gap={1} pageNumber={pageNumber}
> width={containerWidth * 0.8}
<IconButton />
disabled={pageNumber <= 1} )}
onClick={() => setPageNumber((p) => p - 1)} </Document>
> </Box>
<ArrowCircleLeftIcon fontSize="large" /> <Box
</IconButton> mt={2}
<span> display="flex"
{pageNumber} / {numPages} alignItems="center"
</span> justifyContent="center"
<IconButton gap={1}
disabled={pageNumber >= (numPages || 1)} >
onClick={() => setPageNumber((p) => p + 1)} <IconButton disabled={pageNumber <= 1} onClick={() => setPageNumber(p => p - 1)}>
> <ArrowCircleLeftIcon fontSize="large" />
<ArrowCircleRightIcon fontSize="large" /> </IconButton>
</IconButton> <span>{pageNumber} / {numPages}</span>
</Box> <IconButton
</Box> disabled={pageNumber >= (numPages || 1)}
); onClick={() => setPageNumber(p => p + 1)}
} >
<ArrowCircleRightIcon fontSize="large" />
</IconButton>
</Box>
</Box>
);
}

View File

@ -34,8 +34,9 @@ declare module "@tanstack/react-router" {
} }
} }
// Initialize PDF.js worker
pdfjs.GlobalWorkerOptions.workerSrc = new URL( pdfjs.GlobalWorkerOptions.workerSrc = new URL(
"pdfjs-dist/build/pdf.worker.min.js", "pdfjs-dist/build/pdf.worker.min.mjs",
import.meta.url, import.meta.url,
).toString(); ).toString();

View File

@ -11,12 +11,18 @@
// Import Routes // Import Routes
import { Route as rootRoute } from './routes/__root' import { Route as rootRoute } from './routes/__root'
import { Route as ExtractedResultImport } from './routes/extractedResult'
import { Route as ConfigImport } from './routes/config' import { Route as ConfigImport } from './routes/config'
import { Route as IndexImport } from './routes/index' import { Route as IndexImport } from './routes/index'
import { Route as ExtractedResultPitchBookImport } from './routes/extractedResult.$pitchBook'
// Create/Update Routes // Create/Update Routes
const ExtractedResultRoute = ExtractedResultImport.update({
id: '/extractedResult',
path: '/extractedResult',
getParentRoute: () => rootRoute,
} as any)
const ConfigRoute = ConfigImport.update({ const ConfigRoute = ConfigImport.update({
id: '/config', id: '/config',
path: '/config', path: '/config',
@ -29,12 +35,6 @@ const IndexRoute = IndexImport.update({
getParentRoute: () => rootRoute, getParentRoute: () => rootRoute,
} as any) } as any)
const ExtractedResultPitchBookRoute = ExtractedResultPitchBookImport.update({
id: '/extractedResult/$pitchBook',
path: '/extractedResult/$pitchBook',
getParentRoute: () => rootRoute,
} as any)
// Populate the FileRoutesByPath interface // Populate the FileRoutesByPath interface
declare module '@tanstack/react-router' { declare module '@tanstack/react-router' {
@ -53,11 +53,11 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof ConfigImport preLoaderRoute: typeof ConfigImport
parentRoute: typeof rootRoute parentRoute: typeof rootRoute
} }
'/extractedResult/$pitchBook': { '/extractedResult': {
id: '/extractedResult/$pitchBook' id: '/extractedResult'
path: '/extractedResult/$pitchBook' path: '/extractedResult'
fullPath: '/extractedResult/$pitchBook' fullPath: '/extractedResult'
preLoaderRoute: typeof ExtractedResultPitchBookImport preLoaderRoute: typeof ExtractedResultImport
parentRoute: typeof rootRoute parentRoute: typeof rootRoute
} }
} }
@ -68,41 +68,41 @@ declare module '@tanstack/react-router' {
export interface FileRoutesByFullPath { export interface FileRoutesByFullPath {
'/': typeof IndexRoute '/': typeof IndexRoute
'/config': typeof ConfigRoute '/config': typeof ConfigRoute
'/extractedResult/$pitchBook': typeof ExtractedResultPitchBookRoute '/extractedResult': typeof ExtractedResultRoute
} }
export interface FileRoutesByTo { export interface FileRoutesByTo {
'/': typeof IndexRoute '/': typeof IndexRoute
'/config': typeof ConfigRoute '/config': typeof ConfigRoute
'/extractedResult/$pitchBook': typeof ExtractedResultPitchBookRoute '/extractedResult': typeof ExtractedResultRoute
} }
export interface FileRoutesById { export interface FileRoutesById {
__root__: typeof rootRoute __root__: typeof rootRoute
'/': typeof IndexRoute '/': typeof IndexRoute
'/config': typeof ConfigRoute '/config': typeof ConfigRoute
'/extractedResult/$pitchBook': typeof ExtractedResultPitchBookRoute '/extractedResult': typeof ExtractedResultRoute
} }
export interface FileRouteTypes { export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath fileRoutesByFullPath: FileRoutesByFullPath
fullPaths: '/' | '/config' | '/extractedResult/$pitchBook' fullPaths: '/' | '/config' | '/extractedResult'
fileRoutesByTo: FileRoutesByTo fileRoutesByTo: FileRoutesByTo
to: '/' | '/config' | '/extractedResult/$pitchBook' to: '/' | '/config' | '/extractedResult'
id: '__root__' | '/' | '/config' | '/extractedResult/$pitchBook' id: '__root__' | '/' | '/config' | '/extractedResult'
fileRoutesById: FileRoutesById fileRoutesById: FileRoutesById
} }
export interface RootRouteChildren { export interface RootRouteChildren {
IndexRoute: typeof IndexRoute IndexRoute: typeof IndexRoute
ConfigRoute: typeof ConfigRoute ConfigRoute: typeof ConfigRoute
ExtractedResultPitchBookRoute: typeof ExtractedResultPitchBookRoute ExtractedResultRoute: typeof ExtractedResultRoute
} }
const rootRouteChildren: RootRouteChildren = { const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute, IndexRoute: IndexRoute,
ConfigRoute: ConfigRoute, ConfigRoute: ConfigRoute,
ExtractedResultPitchBookRoute: ExtractedResultPitchBookRoute, ExtractedResultRoute: ExtractedResultRoute,
} }
export const routeTree = rootRoute export const routeTree = rootRoute
@ -117,7 +117,7 @@ export const routeTree = rootRoute
"children": [ "children": [
"/", "/",
"/config", "/config",
"/extractedResult/$pitchBook" "/extractedResult"
] ]
}, },
"/": { "/": {
@ -126,8 +126,8 @@ export const routeTree = rootRoute
"/config": { "/config": {
"filePath": "config.tsx" "filePath": "config.tsx"
}, },
"/extractedResult/$pitchBook": { "/extractedResult": {
"filePath": "extractedResult.$pitchBook.tsx" "filePath": "extractedResult.tsx"
} }
} }
} }

View File

@ -1,100 +0,0 @@
import ContentPasteIcon from "@mui/icons-material/ContentPaste";
import { Box, Button, Paper, Typography } from "@mui/material";
import { createFileRoute, useNavigate } from "@tanstack/react-router";
import KennzahlenTable from "../components/KennzahlenTable";
import PDFViewer from "../components/pdfViewer";
export const Route = createFileRoute("/extractedResult/$pitchBook")({
component: ExtractedResultsPage,
});
function ExtractedResultsPage() {
const { pitchBook } = Route.useParams();
const navigate = useNavigate();
const status: "green" | "yellow" | "red" = "red";
const statusColor = {
red: "#f43131",
yellow: "#f6ed48",
green: "#3fd942",
}[status];
return (
<Box p={4}>
<Box display="flex" alignItems="center" gap={3}>
<Box
sx={{
width: 45,
height: 45,
borderRadius: "50%",
backgroundColor: statusColor,
top: 32,
left: 32,
}}
/>
<Typography variant="h5" gutterBottom>
Kennzahlen extrahiert aus: <br />
<strong>FONDSNAME: TODO</strong>
</Typography>
</Box>
<Box
display="flex"
gap={4}
sx={{
width: "100vw",
maxWidth: "100%",
height: "80vh",
mt: 4,
}}
>
<Paper
elevation={2}
sx={{
width: "45%",
height: "100%",
borderRadius: 2,
backgroundColor: "#eeeeee",
padding: 2,
overflow: "auto",
}}
>
<KennzahlenTable />
</Paper>
<Box
display="flex"
flexDirection="column"
justifyContent="space-between"
gap={5}
sx={{ width: "55%", height: "95%" }}
>
<Paper
elevation={2}
sx={{
height: "100%",
borderRadius: 2,
backgroundColor: "#eeeeee",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
<PDFViewer pitchBookId={pitchBook} />
</Paper>
<Box mt={2} display="flex" justifyContent="flex-end" gap={2}>
<Button variant="contained" sx={{ backgroundColor: "#383838" }}>
<ContentPasteIcon sx={{ fontSize: 18, mr: 1 }} />
Kennzahlenzeile kopieren
</Button>
<Button
variant="contained"
sx={{ backgroundColor: "#383838" }}
onClick={() => navigate({ to: "/" })}
>
Neu hochladen
</Button>
</Box>
</Box>
</Box>
</Box>
);
}

View File

@ -0,0 +1,103 @@
import { Box, Paper, Typography, Button } from '@mui/material';
import {createFileRoute, useNavigate} from '@tanstack/react-router';
import PDFViewer from '../components/pdfViewer';
import ContentPasteIcon from '@mui/icons-material/ContentPaste';
import KennzahlenTable from "../components/KennzahlenTable";
export const Route = createFileRoute('/extractedResult')({
component: ExtractedResultsPage,
});
function ExtractedResultsPage() {
const navigate = useNavigate();
const status: 'green' | 'yellow' | 'red' = 'red';
const statusColor = {
red: '#f43131',
yellow: '#f6ed48',
green: '#3fd942',
}[status];
return (
<Box p={4}>
<Box display="flex" alignItems="center" gap={3}>
<Box
sx={{
width: 45,
height: 45,
borderRadius: '50%',
backgroundColor: statusColor,
top: 32,
left: 32,
}}
/>
<Typography variant="h5" gutterBottom>
Kennzahlen extrahiert aus: <br/><strong>FONDSNAME: TODO</strong>
</Typography>
</Box>
<Box
display="flex"
gap={4}
sx={{
width: '100vw',
maxWidth: '100%',
height: '80vh',
mt: 4,
}}
>
<Paper
elevation={2}
sx={{
width: '45%',
height: '100%',
borderRadius: 2,
backgroundColor: '#eeeeee',
padding: 2, // Etwas Abstand innen
overflow: 'auto', // Scrollen falls Tabelle zu lang
}}
>
<KennzahlenTable />
</Paper>
<Box
display="flex"
flexDirection="column"
justifyContent="space-between"
gap={5}
sx={{ width: '55%', height: '95%' }}
>
<Paper
elevation={2}
sx={{
height: '100%',
borderRadius: 2,
backgroundColor: '#eeeeee',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<PDFViewer/>
</Paper>
<Box mt={2} display="flex" justifyContent="flex-end" gap={2}>
<Button
variant="contained"
sx={{ backgroundColor: '#383838' }}
>
<ContentPasteIcon sx={{ fontSize: 18, mr: 1 }} />
Kennzahlenzeile kopieren
</Button>
<Button
variant="contained"
sx={{ backgroundColor: '#383838' }}
onClick={() => navigate({ to: '/' })}
>
Neu hochladen
</Button>
</Box>
</Box>
</Box>
</Box>
);
}

View File

@ -1,6 +0,0 @@
import { io } from "socket.io-client";
// "undefined" means the URL will be computed from the `window.location` object
// const URL = process.env.NODE_ENV === 'production' ? undefined : 'http://localhost:4000';
export const socket = io("http://localhost:5050");