HEX
Server: LiteSpeed
System: Linux houston.panomity.com 6.8.0-100-generic #100-Ubuntu SMP PREEMPT_DYNAMIC Tue Jan 13 16:40:06 UTC 2026 x86_64
User: nudepix (1011)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //opt/af/src/components/data_analysis.py
import streamlit as st
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import matplotlib.pyplot as plt
import seaborn as sns
from io import StringIO
import os
import datetime
import json

from ai.agent import AIAgent
from database.mysql_connector import MySQLConnector
from sftp.sftp_client import SFTPClient

def render_data_analysis():
    """
    Rendert die Streamlit-Komponente für die Datenanalyse.
    """
    st.header("Datenanalyse")
    
    # Erstelle eine Instanz des AI-Agenten, MySQL-Connectors und SFTP-Clients
    agent = AIAgent()
    db_connector = MySQLConnector()
    sftp_client = SFTPClient()
    
    # Erstelle Tabs für verschiedene Datenquellen
    tabs = st.tabs(["Lokale Datei", "Datenbank", "SFTP", "Kombinierte Analyse"])
    
    # Session State für Dataframes
    if 'dataframes' not in st.session_state:
        st.session_state.dataframes = {
            'local': None,
            'mysql': None,
            'sftp': None,
            'combined': None
        }
    
    # Tab 1: Lokale Datei
    with tabs[0]:
        process_local_file(agent)
    
    # Tab 2: Datenbankdaten
    with tabs[1]:
        process_database_data(db_connector, agent)
    
    # Tab 3: SFTP-Daten
    with tabs[2]:
        process_sftp_data(sftp_client, agent)
    
    # Tab 4: Kombinierte Analyse
    with tabs[3]:
        process_combined_data(agent)

def process_local_file(agent):
    """
    Verarbeitet eine lokal hochgeladene Datei.
    """
    st.subheader("Lokale Dateianalyse")
    
    # Datei-Upload
    uploaded_file = st.file_uploader("CSV-Datei hochladen", type=["csv"])
    
    if uploaded_file is not None:
        # Lese die CSV-Datei
        df = load_csv_file(uploaded_file)
        
        # Speichere das DataFrame im Session State
        st.session_state.dataframes['local'] = df
        
        # Analyse der Daten
        analyze_dataframe(df, "Lokale Datei", agent)
    else:
        st.info("Bitte laden Sie eine CSV-Datei hoch")

def process_database_data(db_connector, agent):
    """
    Verarbeitet Daten aus der MySQL-Datenbank.
    """
    st.subheader("Datenbankanalyse")
    
    # SQL-Abfrage eingeben
    sql_query = st.text_area("SQL-Abfrage eingeben:", height=100)
    
    # Abfrage ausführen
    if st.button("Abfrage ausführen"):
        if sql_query:
            with st.spinner("Daten werden aus der Datenbank abgerufen..."):
                results = db_connector.execute_query(sql_query)
                if results:
                    df = pd.DataFrame(results)
                    st.success(f"{len(df)} Datensätze erfolgreich abgerufen")
                    
                    # Speichere das DataFrame im Session State
                    st.session_state.dataframes['mysql'] = df
                    
                    # Analyse der Daten
                    analyze_dataframe(df, "Datenbank", agent)
                else:
                    st.error("Fehler bei der Abfrage oder keine Ergebnisse")
        else:
            st.warning("Bitte geben Sie eine SQL-Abfrage ein")
            
    # Tabellenliste anzeigen
    if st.checkbox("Verfügbare Tabellen anzeigen"):
        with st.spinner("Tabellen werden abgerufen..."):
            tables = db_connector.execute_query("SHOW TABLES")
            if tables:
                table_names = [list(table.values())[0] for table in tables]
                st.write("Verfügbare Tabellen:")
                st.write(table_names)
                
                # Tabellenstruktur anzeigen
                selected_table = st.selectbox("Tabellenstruktur anzeigen:", table_names)
                if selected_table:
                    columns = db_connector.execute_query(f"DESCRIBE {selected_table}")
                    if columns:
                        st.write(f"Struktur von {selected_table}:")
                        columns_df = pd.DataFrame(columns)
                        st.dataframe(columns_df)

def process_sftp_data(sftp_client, agent):
    """
    Verarbeitet Daten vom SFTP-Server.
    """
    st.subheader("SFTP-Datenanalyse")
    
    # Verbindung zum SFTP-Server herstellen
    if st.button("Mit SFTP-Server verbinden"):
        with st.spinner("Verbindung zum SFTP-Server wird hergestellt..."):
            if sftp_client.connect():
                st.success("Verbindung zum SFTP-Server hergestellt")
                
                # Liste der Dateien anzeigen
                files = sftp_client.list_files()
                if files:
                    # Filtere nur CSV-Dateien
                    csv_files = [f for f in files if f.lower().endswith('.csv')]
                    
                    if csv_files:
                        selected_file = st.selectbox("CSV-Datei auswählen:", csv_files)
                        
                        if st.button("Datei herunterladen und analysieren"):
                            with st.spinner(f"Datei {selected_file} wird heruntergeladen..."):
                                # Kombiniere Pfade
                                remote_path = os.path.join(sftp_client.remote_path, selected_file)
                                local_path = sftp_client.download_file(remote_path)
                                
                                if local_path:
                                    st.success(f"Datei erfolgreich heruntergeladen: {local_path}")
                                    
                                    # Lese die CSV-Datei
                                    df = pd.read_csv(local_path)
                                    
                                    # Speichere das DataFrame im Session State
                                    st.session_state.dataframes['sftp'] = df
                                    
                                    # Analyse der Daten
                                    analyze_dataframe(df, "SFTP", agent)
                                else:
                                    st.error("Fehler beim Herunterladen der Datei")
                    else:
                        st.warning("Keine CSV-Dateien gefunden")
                else:
                    st.error("Fehler beim Abrufen der Dateien")
            else:
                st.error("Fehler bei der Verbindung zum SFTP-Server")

def process_combined_data(agent):
    """
    Führt eine kombinierte Analyse von Daten aus verschiedenen Quellen durch.
    """
    st.subheader("Kombinierte Datenanalyse")
    
    # Prüfe, welche Datenquellen verfügbar sind
    available_sources = {}
    for source, df in st.session_state.dataframes.items():
        if df is not None:
            available_sources[source] = df
    
    if not available_sources:
        st.info("Keine Daten verfügbar. Bitte laden Sie zuerst Daten aus mindestens zwei Quellen.")
        return
    
    # Wenn mindestens zwei Datenquellen verfügbar sind
    if len(available_sources) >= 2:
        # Wähle Datenquellen für die Kombination
        selected_sources = st.multiselect(
            "Datenquellen auswählen:",
            list(available_sources.keys()),
            default=list(available_sources.keys())[:2]
        )
        
        if len(selected_sources) >= 2:
            # Optionen für das Kombinieren der Daten
            join_type = st.selectbox(
                "Verbindungstyp:",
                ["Inner Join", "Left Join", "Right Join", "Outer Join"]
            )
            
            # Wähle Schlüsselspalten für das Joining
            join_columns = {}
            for source in selected_sources:
                join_columns[source] = st.selectbox(
                    f"Schlüsselspalte für {source}:",
                    available_sources[source].columns
                )
            
            # Button zum Kombinieren der Daten
            if st.button("Daten kombinieren"):
                with st.spinner("Daten werden kombiniert..."):
                    # Starte mit dem ersten DataFrame
                    result_df = available_sources[selected_sources[0]].copy()
                    
                    # Kombiniere mit den anderen DataFrames
                    for i in range(1, len(selected_sources)):
                        source = selected_sources[i]
                        df = available_sources[source]
                        
                        # Bestimme den Join-Typ
                        how = join_type.lower().split()[0]
                        
                        # Führe den Join durch
                        result_df = result_df.merge(
                            df,
                            left_on=join_columns[selected_sources[0]],
                            right_on=join_columns[source],
                            how=how,
                            suffixes=(f"_{selected_sources[0]}", f"_{source}")
                        )
                    
                    # Speichere das kombinierte DataFrame
                    st.session_state.dataframes['combined'] = result_df
                    
                    # Analyse der kombinierten Daten
                    analyze_dataframe(result_df, "Kombinierte Daten", agent)
        else:
            st.warning("Bitte wählen Sie mindestens zwei Datenquellen aus")
    else:
        st.info("Mindestens zwei Datenquellen sind erforderlich für eine kombinierte Analyse")

def load_csv_file(file_obj):
    """
    Lädt und verarbeitet eine CSV-Datei.
    """
    try:
        # Versuche, die CSV-Datei zu lesen
        df = pd.read_csv(file_obj)
        return df
    except Exception as e:
        st.error(f"Fehler beim Lesen der CSV-Datei: {str(e)}")
        return None

def analyze_dataframe(df, source_name, agent):
    """
    Führt Datenanalyse und Visualisierung für ein DataFrame durch.
    """
    if df is None or df.empty:
        st.warning("Keine Daten verfügbar für die Analyse")
        return
    
    # Zeige die Daten an
    with st.expander("Datenvorschau", expanded=True):
        st.dataframe(df.head(10))
    
    # Grundlegende Statistiken
    with st.expander("Datenstatistiken", expanded=True):
        col1, col2 = st.columns(2)
        
        with col1:
            st.write(f"Anzahl der Zeilen: {len(df)}")
            st.write(f"Anzahl der Spalten: {len(df.columns)}")
            
            # Fehlende Werte
            missing_values = df.isnull().sum()
            if missing_values.sum() > 0:
                st.write("Fehlende Werte:")
                st.write(missing_values[missing_values > 0])
            else:
                st.write("Keine fehlenden Werte gefunden")
        
        with col2:
            # Datentypen
            st.write("Datentypen:")
            st.write(df.dtypes)
    
    # Datenvorverarbeitung
    with st.expander("Datenvorverarbeitung", expanded=False):
        st.subheader("Datenvorverarbeitung")
        
        # Optionen für die Vorverarbeitung
        preprocessing_options = st.multiselect(
            "Vorverarbeitungsoptionen:",
            [
                "Fehlende Werte behandeln",
                "Ausreißer erkennen",
                "Normalisierung",
                "Kategorische Variablen kodieren"
            ]
        )
        
        processed_df = df.copy()
        
        if "Fehlende Werte behandeln" in preprocessing_options:
            st.write("Fehlende Werte behandeln:")
            
            # Wähle numerische Spalten
            numeric_cols = processed_df.select_dtypes(include=np.number).columns.tolist()
            selected_cols = st.multiselect("Spalten auswählen:", numeric_cols, default=numeric_cols)
            
            # Methode für die Behandlung von fehlenden Werten
            method = st.selectbox(
                "Methode:",
                ["Entfernen", "Mittelwert", "Median", "Modus", "Konstant"]
            )
            
            if st.button("Fehlende Werte behandeln"):
                if method == "Entfernen":
                    processed_df = processed_df.dropna(subset=selected_cols)
                elif method == "Mittelwert":
                    for col in selected_cols:
                        processed_df[col] = processed_df[col].fillna(processed_df[col].mean())
                elif method == "Median":
                    for col in selected_cols:
                        processed_df[col] = processed_df[col].fillna(processed_df[col].median())
                elif method == "Modus":
                    for col in selected_cols:
                        processed_df[col] = processed_df[col].fillna(processed_df[col].mode()[0])
                elif method == "Konstant":
                    const_value = st.number_input("Konstanter Wert:", value=0)
                    for col in selected_cols:
                        processed_df[col] = processed_df[col].fillna(const_value)
                
                st.write("Ergebnis nach der Behandlung:")
                st.dataframe(processed_df.head())
        
        if "Ausreißer erkennen" in preprocessing_options:
            st.write("Ausreißer erkennen:")
            
            # Wähle numerische Spalten
            numeric_cols = processed_df.select_dtypes(include=np.number).columns.tolist()
            selected_col = st.selectbox("Spalte auswählen:", numeric_cols)
            
            if st.button("Ausreißer erkennen"):
                # Z-Score-Methode für Ausreißererkennung
                z_scores = np.abs((processed_df[selected_col] - processed_df[selected_col].mean()) / processed_df[selected_col].std())
                outliers = processed_df[z_scores > 3]
                
                if len(outliers) > 0:
                    st.write(f"Gefundene Ausreißer ({len(outliers)} Zeilen):")
                    st.dataframe(outliers)
                    
                    # Boxplot für Ausreißer
                    fig = px.box(processed_df, y=selected_col, title=f"Boxplot für {selected_col}")
                    st.plotly_chart(fig)
                else:
                    st.write("Keine Ausreißer gefunden")
    
    # Erweiterte Visualisierung
    with st.expander("Datenvisualisierung", expanded=True):
        st.subheader("Datenvisualisierung")
        
        # Wähle den Visualisierungstyp
        chart_type = st.selectbox(
            "Visualisierungstyp:",
            [
                "Liniendiagramm", 
                "Balkendiagramm", 
                "Streudiagramm", 
                "Histogramm",
                "Heatmap",
                "Zeitreihe",
                "Box-Plot",
                "Pie-Chart",
                "3D-Streudiagramm"
            ]
        )
        
        # Visualisierungsoptionen basierend auf dem ausgewählten Typ
        if chart_type in ["Liniendiagramm", "Balkendiagramm", "Streudiagramm"]:
            x_column = st.selectbox("X-Achse:", df.columns)
            y_column = st.selectbox("Y-Achse:", df.columns)
            color_column = st.selectbox("Farbe (optional):", ["Keine"] + list(df.columns))
            
            color = None if color_column == "Keine" else color_column
            
            if chart_type == "Liniendiagramm":
                fig = px.line(df, x=x_column, y=y_column, color=color)
            elif chart_type == "Balkendiagramm":
                fig = px.bar(df, x=x_column, y=y_column, color=color)
            else:  # Streudiagramm
                fig = px.scatter(df, x=x_column, y=y_column, color=color)
                
            st.plotly_chart(fig)
            
        elif chart_type == "Histogramm":
            column = st.selectbox("Spalte:", df.columns)
            bins = st.slider("Anzahl der Bins:", min_value=5, max_value=100, value=20)
            fig = px.histogram(df, x=column, nbins=bins)
            st.plotly_chart(fig)
            
        elif chart_type == "Heatmap":
            # Nur numerische Spalten für die Heatmap
            numeric_cols = df.select_dtypes(include=np.number).columns.tolist()
            
            if len(numeric_cols) > 1:
                selected_cols = st.multiselect("Spalten auswählen:", numeric_cols, default=numeric_cols[:5])
                
                if selected_cols:
                    # Berechne die Korrelationsmatrix
                    corr = df[selected_cols].corr()
                    
                    # Erstelle die Heatmap
                    fig = px.imshow(
                        corr,
                        text_auto=True,
                        color_continuous_scale="RdBu_r",
                        title="Korrelationsmatrix"
                    )
                    st.plotly_chart(fig)
            else:
                st.warning("Nicht genügend numerische Spalten für eine Heatmap")
                
        elif chart_type == "Zeitreihe":
            # Prüfe, ob es Datumsspalten gibt
            date_cols = [col for col in df.columns if df[col].dtype == 'datetime64[ns]' or 'date' in col.lower() or 'time' in col.lower()]
            
            if date_cols:
                date_column = st.selectbox("Datumsspalte:", date_cols)
                value_column = st.selectbox("Wertspalte:", df.select_dtypes(include=np.number).columns)
                
                # Konvertiere die Datumsspalte, falls erforderlich
                try:
                    if df[date_column].dtype != 'datetime64[ns]':
                        df[date_column] = pd.to_datetime(df[date_column])
                    
                    # Sortiere nach Datum
                    temp_df = df.sort_values(by=date_column)
                    
                    # Erstelle das Zeitreihendiagramm
                    fig = px.line(
                        temp_df, 
                        x=date_column, 
                        y=value_column,
                        title=f"Zeitreihe: {value_column} über {date_column}"
                    )
                    st.plotly_chart(fig)
                    
                    # Einfache Zeitreihenanalyse
                    if st.checkbox("Einfache Zeitreihenanalyse anzeigen"):
                        # Berechne rollenden Durchschnitt
                        window = st.slider("Fensterbreite für rollenden Durchschnitt:", min_value=2, max_value=30, value=7)
                        
                        # Erstelle das DataFrame für die Analyse
                        analysis_df = temp_df[[date_column, value_column]].copy()
                        analysis_df['Rolling Average'] = analysis_df[value_column].rolling(window=window).mean()
                        
                        # Erstelle das Diagramm
                        fig = px.line(
                            analysis_df,
                            x=date_column,
                            y=[value_column, 'Rolling Average'],
                            title=f"Zeitreihenanalyse mit {window}-Perioden rollendem Durchschnitt"
                        )
                        st.plotly_chart(fig)
                except Exception as e:
                    st.error(f"Fehler bei der Zeitreihenanalyse: {str(e)}")
            else:
                st.warning("Keine geeigneten Datumsspalten gefunden für die Zeitreihenanalyse")
                
        elif chart_type == "Box-Plot":
            y_column = st.selectbox("Y-Achse (numerisch):", df.select_dtypes(include=np.number).columns)
            x_column = st.selectbox("X-Achse (kategoriell, optional):", ["Keine"] + list(df.columns))
            
            if x_column == "Keine":
                fig = px.box(df, y=y_column)
            else:
                fig = px.box(df, x=x_column, y=y_column)
                
            st.plotly_chart(fig)
            
        elif chart_type == "Pie-Chart":
            value_column = st.selectbox("Wertspalte:", df.select_dtypes(include=np.number).columns)
            name_column = st.selectbox("Namensspalte:", df.columns)
            
            # Limitiere die Anzahl der Einträge für bessere Lesbarkeit
            top_n = st.slider("Top N Einträge anzeigen:", min_value=3, max_value=20, value=10)
            
            # Aggregiere die Daten
            pie_data = df.groupby(name_column)[value_column].sum().reset_index()
            pie_data = pie_data.sort_values(by=value_column, ascending=False).head(top_n)
            
            fig = px.pie(
                pie_data,
                values=value_column,
                names=name_column,
                title=f"Verteilung von {value_column} nach {name_column}"
            )
            st.plotly_chart(fig)
            
        elif chart_type == "3D-Streudiagramm":
            # Nur wenn es mindestens 3 numerische Spalten gibt
            numeric_cols = df.select_dtypes(include=np.number).columns.tolist()
            
            if len(numeric_cols) >= 3:
                x_column = st.selectbox("X-Achse:", numeric_cols, index=0)
                y_column = st.selectbox("Y-Achse:", numeric_cols, index=min(1, len(numeric_cols)-1))
                z_column = st.selectbox("Z-Achse:", numeric_cols, index=min(2, len(numeric_cols)-1))
                color_column = st.selectbox("Farbe (optional):", ["Keine"] + list(df.columns))
                
                color = None if color_column == "Keine" else color_column
                
                fig = px.scatter_3d(
                    df, 
                    x=x_column, 
                    y=y_column, 
                    z=z_column,
                    color=color,
                    title="3D-Streudiagramm"
                )
                st.plotly_chart(fig)
            else:
                st.warning("Nicht genügend numerische Spalten für ein 3D-Streudiagramm")
    
    # KI-Analyse
    with st.expander("KI-Analyse", expanded=True):
        st.subheader("KI-gestützte Datenanalyse")
        
        # Analyseoptionen
        analysis_type = st.selectbox(
            "Analysetyp:",
            [
                "Allgemeine Datenanalyse",
                "Zeitreihenvorhersage",
                "Korrelationsanalyse",
                "Ausreißererkennung",
                "Segmentierung",
                "Benutzerdefinierte Analyse"
            ]
        )
        
        if analysis_type == "Benutzerdefinierte Analyse":
            # Analyseanfrage
            analysis_query = st.text_area("Analyseanfrage:", height=100)
            
            # Analysieren-Button
            if st.button("Analysieren"):
                if analysis_query:
                    with st.spinner("Daten werden analysiert..."):
                        # Führe die Analyse durch
                        context = {
                            "source": source_name,
                            "shape": df.shape,
                            "columns": list(df.columns),
                            "dtypes": str(df.dtypes),
                            "sample_data": df.head(5).to_dict()
                        }
                        analysis = agent.analyze_data(context, analysis_query)
                        
                        # Zeige die Analyseergebnisse an
                        st.markdown("### Analyseergebnisse")
                        st.write(analysis)
                else:
                    st.warning("Bitte geben Sie eine Analyseanfrage ein")
        else:
            # Vordefinierte Analysen
            if st.button("Analysieren"):
                with st.spinner(f"{analysis_type} wird durchgeführt..."):
                    # Erstelle die Analyseabfrage basierend auf dem ausgewählten Typ
                    if analysis_type == "Allgemeine Datenanalyse":
                        query = "Führe eine allgemeine Datenanalyse durch. Identifiziere wichtige Muster, Trends und Statistiken."
                    elif analysis_type == "Zeitreihenvorhersage":
                        query = "Analysiere zeitliche Muster in den Daten. Identifiziere Trends, Saisonalität und zyklische Komponenten."
                    elif analysis_type == "Korrelationsanalyse":
                        query = "Identifiziere und erkläre Korrelationen zwischen den Variablen. Welche Variablen haben starke Beziehungen zueinander?"
                    elif analysis_type == "Ausreißererkennung":
                        query = "Identifiziere potenzielle Ausreißer in den Daten und erkläre, warum sie als Ausreißer betrachtet werden könnten."
                    elif analysis_type == "Segmentierung":
                        query = "Identifiziere natürliche Segmente oder Cluster in den Daten. Wie können die Daten sinnvoll gruppiert werden?"
                    
                    # Führe die Analyse durch
                    context = {
                        "source": source_name,
                        "shape": df.shape,
                        "columns": list(df.columns),
                        "dtypes": str(df.dtypes),
                        "sample_data": df.head(5).to_dict(),
                        "analysis_type": analysis_type
                    }
                    analysis = agent.analyze_data(context, query)
                    
                    # Zeige die Analyseergebnisse an
                    st.markdown("### Analyseergebnisse")
                    st.write(analysis)