File size: 4,685 Bytes
48f1655
 
 
 
1b225dc
 
 
 
 
 
 
 
 
 
 
48f1655
 
 
1b225dc
 
48f1655
 
 
 
 
 
1b225dc
48f1655
 
 
 
1b225dc
48f1655
 
 
 
 
 
 
1b225dc
48f1655
1b225dc
48f1655
 
 
 
 
1b225dc
48f1655
 
1b225dc
48f1655
1b225dc
20a3dbe
48f1655
1b225dc
20a3dbe
1b225dc
 
 
 
 
508a88b
1b225dc
48f1655
 
 
 
1b225dc
48f1655
cf23d48
 
 
1b225dc
cf23d48
1b225dc
cf23d48
 
 
 
 
 
 
 
48f1655
 
1b225dc
48f1655
 
 
 
 
 
 
 
 
 
1b225dc
 
 
48f1655
 
 
 
 
 
 
 
 
 
1b225dc
 
48f1655
1b225dc
48f1655
 
1b225dc
48f1655
1b225dc
cd6ded6
 
1b225dc
 
 
 
cd6ded6
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import pandas as pd
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

# Globale Analyseinstanz
_analyzer = None

def get_analyzer():
    """Singleton-Muster zur Vermeidung der Modellneuinitialisierung bei jedem Aufruf"""
    global _analyzer
    if _analyzer is None:
        _analyzer = CSVAnalysierer()
    return _analyzer

class CSVAnalysierer:
    def __init__(self):
        self.model_name = "mistralai/Mistral-7B-Instruct-v0.2"
        try:
            print("Modell wird initialisiert...")
            # Tokenizer-Initialisierung mit spezifischer Konfiguration
            self.tokenizer = AutoTokenizer.from_pretrained(
                self.model_name,
                trust_remote_code=True,
                use_fast=False
            )
            
            # Padding-Token-Konfiguration
            if self.tokenizer.pad_token is None:
                self.tokenizer.pad_token = self.tokenizer.eos_token
                self.tokenizer.padding_side = "right"

            # Modell-Initialisierung
            self.model = AutoModelForCausalLM.from_pretrained(
                self.model_name,
                torch_dtype=torch.float16,
                device_map="auto",
                trust_remote_code=True
            )
            
            # Sicherstellen, dass das Modell das Padding-Token kennt
            self.model.config.pad_token_id = self.tokenizer.pad_token_id
            print("Modell erfolgreich initialisiert!")
            
        except Exception as e:
            print(f"Initialisierungsfehler: {str(e)}")
            raise

    def kontext_vorbereiten(self, df: pd.DataFrame) -> str:
        """Bereitet den Kontext mit den DataFrame-Daten vor."""
        try:
            kontext = "E-Mail-Informationen:\n\n"
            
            # DataFrame in String umwandeln und fehlende Werte behandeln
            df_str = df.fillna("Keine Angabe").astype(str)
            
            # Jede Zeile verarbeiten
            for index in range(len(df_str)):
                zeile = df_str.iloc[index]
                kontext += f"E-Mail {index + 1}:\n"
                for spalte in df_str.columns:
                    kontext += f"{spalte}: {zeile[spalte]}\n"
                kontext += "---\n"
            
            return kontext.strip()
            
        except Exception as e:
            raise Exception(f"Fehler bei der Kontextvorbereitung: {str(e)}")

    def antwort_generieren(self, kontext: str, frage: str) -> str:
        """Generiert eine Antwort auf die Frage unter Verwendung des Kontexts."""
        prompt = f"""<s>[INST] Sie sind ein deutscher Assistent für Facility Management Datenanalyse. 
Analysieren Sie die folgenden E-Mail-Daten:

{kontext}

Frage: {frage}

Wichtige Anweisungen:
1. Antworten Sie AUSSCHLIEßLICH auf Deutsch
2. Beziehen Sie sich auf die konkreten E-Mail-Daten (Datum, Absender, Betreff)
3. Fassen Sie den relevanten Inhalt präzise zusammen
4. Bei Bedarf erstellen Sie eine strukturierte Übersicht der wichtigsten Punkte

Ihre deutsche Antwort: [/INST]"""

        try:
            eingabe = self.tokenizer(
                prompt,
                return_tensors="pt",
                padding=True,
                truncation=True,
                max_length=2048,
                pad_to_multiple_of=8,
                return_attention_mask=True
            ).to(self.model.device)
            
            with torch.no_grad():
                ausgabe = self.model.generate(
                    input_ids=eingabe["input_ids"],
                    attention_mask=eingabe["attention_mask"],
                    max_new_tokens=512,
                    temperature=0.7,
                    top_p=0.95,
                    repetition_penalty=1.15,
                    do_sample=True,
                    num_beams=1,
                    pad_token_id=self.tokenizer.pad_token_id,
                    eos_token_id=self.tokenizer.eos_token_id
                )
            
            antwort = self.tokenizer.decode(ausgabe[0], skip_special_tokens=True)
            antwort = antwort.split("[/INST]")[-1].strip()
            
            return antwort
            
        except Exception as e:
            return f"Generierungsfehler: {str(e)}"

def csv_analysieren(df: pd.DataFrame, frage: str) -> str:
    """Hauptfunktion zur CSV-Analyse und Fragenbeantwortung."""
    try:
        analysierer = get_analyzer()  # Verwendet die einzige Instanz
        kontext = analysierer.kontext_vorbereiten(df)
        antwort = analysierer.antwort_generieren(kontext, frage)
        return antwort
        
    except Exception as e:
        return f"Fehler bei der Analyse: {str(e)}"