Flask App Datenbankabfrage

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
MaybeR6x
User
Beiträge: 2
Registriert: Dienstag 10. Mai 2022, 08:01

Guten Tag zusammen,

ich hoffe ich kann mein Problem gut beschreiben und jemand hat eine Antwort und am besten eine Lösung.

Ich habe eine Flask App (app.py) die beim Aufruf
@app.post("/predict")
def predict():
text = request.get_json().get('message')
response = get_response(text)
usw.

die Methode get_response() Aufruft und in der Methode wird eine Datenbankabfrage gemacht.
Jetzt habe ich gemerkt das wenn ich die Flask App gestartet habe und sich Datensätze in der Datenbank ändern, diese nicht Aktualisiert über get_response() ausgegeben werden.
Erst wenn ich den Server/die App neu starte.

Gibt es hierfür eine Lösung? oder ist das grunsätzlich nicht anders möglich?
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Da es ja nun viele Anwendungen gibt, bei denen das klappt, geht das grundsätzlich.

Du zeigst den relevanten Teil deiner Datenbankabfrage nicht, denn das hat damit zu tun. Nix mit flask, das hat auf die keinen Einfluss. Datenbanken haben üblicherweise Transaktionen, die sie voneinander isolieren. Damit musst du umgehen, wie genau, hängt vom Code und anwedungszweck ab.
MaybeR6x
User
Beiträge: 2
Registriert: Dienstag 10. Mai 2022, 08:01

__deets__ hat geschrieben: Dienstag 10. Mai 2022, 08:39 Da es ja nun viele Anwendungen gibt, bei denen das klappt, geht das grundsätzlich.

Du zeigst den relevanten Teil deiner Datenbankabfrage nicht, denn das hat damit zu tun. Nix mit flask, das hat auf die keinen Einfluss. Datenbanken haben üblicherweise Transaktionen, die sie voneinander isolieren. Damit musst du umgehen, wie genau, hängt vom Code und anwedungszweck ab.
Im grunde ist das die Datenbank Abfrage um die es geht:
mycursor.execute(f"SELECT Path FROM nltk_model where Active = 1 AND Kunden_NR = {kunde}")
path = mycursor.fetchall()
data = torch.load(str(path[0][0]))


die ganze methode sieht wie folgt aus:

def get_response(msg,kunde,chatID):
sql = "INSERT INTO messages (msg_id, msg,sent_by,Kunden_NR) VALUES (%s, %s, %s, %s)"
val = (chatID, msg,"User",kunde)
mycursor.execute(sql, val)
mydb.commit()

mycursor.execute(f"SELECT Path FROM nltk_model where Active = 1 AND Kunden_NR = {kunde}")
path = mycursor.fetchall()
data = torch.load(str(path[0][0]))
doc = getEntitys(msg,kunde)
doc = "Entities", [(ent.text, ent.label_) for ent in doc.ents]
input_size = data["input_size"]
hidden_size = data["hidden_size"]
output_size = data["output_size"]
all_words = data['all_words']
tags = data['tags']
model_state = data["model_state"]
model = NeuralNet(input_size, hidden_size, output_size).to(device)
model.load_state_dict(model_state)
model.eval()

mycursor.execute(f"SELECT tag FROM intents where active = 1 AND Kunden_NR = {kunde}")
tag = mycursor.fetchall()
jsonData = '{"intents": ['
for x in tag:
jsonData += '{' + f'"tag": "{x[0]}","patterns": ['
mycursor.execute(f"SELECT pattern FROM patterns where tag = '{x[0]}' AND Kunden_NR = {kunde}")
patterns = mycursor.fetchall()
for y in patterns:
jsonData += f'"{y[0]}",'
jsonData = jsonData[:-1]
jsonData += '],"responses": ['
mycursor.execute(f"SELECT responses FROM responses where tag = '{x[0]}' AND Kunden_NR = {kunde}")
patterns = mycursor.fetchall()
for y in patterns:
jsonData += f'"{y[0]}",'
jsonData = jsonData[:-1]
jsonData += ']},'
jsonData = jsonData[:-1] + "]}"
intents = json.loads(jsonData)

sentence = tokenize(msg)
X = bag_of_words(sentence, all_words)
X = X.reshape(1, X.shape[0])
X = torch.from_numpy(X).to(device)

output = model(X)
_, predicted = torch.max(output, dim=1)

tag = tags[predicted.item()]

probs = torch.softmax(output, dim=1)
prob = probs[0][predicted.item()]
if prob.item() > 0.75:
for intent in intents['intents']:
if tag == intent["tag"]:
answer = random.choice(intent['responses']) + str(doc)
sql = "INSERT INTO messages (msg_id, msg,sent_by,Kunden_NR) VALUES (%s, %s, %s, %s)"
val = (chatID, answer,"Bot",kunde)
mycursor.execute(sql, val)
mydb.commit()

return answer
answer = "I do not understand..." + str(doc)
sql = "INSERT INTO messages (msg_id, msg,sent_by,Kunden_NR) VALUES (%s, %s, %s, %s)"
val = (chatID, answer,"Bot",kunde)
mycursor.execute(sql, val)
mydb.commit()
return answer
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Bitte in Zukunft die Code-Tags benutzen, wenn du hier Code postest, damit die Einrueckungen erhalten bleiben.

Da sind eine Menge Probleme drin. Der groesste Klopper: die Eingabe "kunde" wird einfach mittels eines Formatstrings in eine SQL-Abfrage geballert. Und kann da beliebigen Schaden anrichten. Du musst *ueberall* die parametrisierte Form von execute verwenden, was du komischerweise an anderer Stelle auch machst.

JSON baut man nicht per String-Operationen zusammen, sondern nutzt json.dumps, um aus einer Datenstruktur eine JSON-Repraesentation zu bekommen. Und eigentlich noch nicht mal das, die Datenstruktur sollte Flask selbst in JSON umwandeln koennen. Und die Mischung aus + und format-strings ist auch "ungewoehnlich".

Viel zu lang und unuebersichtlich ist das Ding dann auch noch geworden.

mydb/mycursor fallen vom Himmel. Das ist mein Kandidat 1 fuer das von dir beobachtete Verhalten. Ich wuerde da ein funktionierendes Beispiel aus der Dokumentation von was auch immer du als DB-Adapter benutzt zugrunde legen, und dich dann langsam dahinarbeiten.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@__deets__: es ist ja noch schlimmer, der JSON-String wird nicht für die Rückgabe generiert, sondern um dann per json.loads die Daten in Python zu lesen!

@MaybeR6x: Warum liest Du die `intents` zu allen `tags`, obwohl Du nur ein einziges davon brauchst?
`doc` ist kein Objekt, das man sinnvoll in einen String umwandeln kann. Sowas will der Nutzer doch nicht sehen.

Die lange Funktion muß in viele kleine Funktionen aufgespalten werden. Es darf keine globalen Variablen geben.
Variablennamen schreibt man klein. Benutze keine Abkürzungen.
`cursor` sind was kurzlebiges und werden nicht herumgereicht.

Insgesamt komm ich bei sowas raus (ungetestet):

Code: Alles auswählen

def read_intent(database, kunde, tag):
    with closing(database.cursor()) as cursor:
        cursor.execute(f"SELECT count(*) FROM intents where active = 1 AND tag = %s AND Kunden_NR = %s", [tag, kunde])
        count = cursor.fetchone()[0]
        if count == 0:
            return None
        cursor.execute(f"SELECT pattern FROM patterns where tag = %s AND Kunden_NR = %s", [tag, kunde])
        patterns = [p for p, in cursor]
        cursor.execute(f"SELECT responses FROM responses where tag = %s AND Kunden_NR = %s", [tag, kunde])
        responses = [r for r, in cursor]
        return patterns, response

def write_message(database, chat_id, message, sent_by, kunde):
    with closing(database.cursor()) as cursor:
        sql = "INSERT INTO messages (msg_id, msg,sent_by,Kunden_NR) VALUES (%s, %s, %s, %s)"
        cursor.execute(sql, [chat_id, message, sent_by, kunde])
    database.commit()

def predict(database, kunde, message):
    with closing(database.cursor()) as cursor:
        cursor.execute(f"SELECT Path FROM nltk_model where Active = 1 AND Kunden_NR = %s", [kunde])
        path = cursor.fetchone()[0]
    
    data = torch.load(path)
    input_size = data["input_size"]
    hidden_size = data["hidden_size"]
    output_size = data["output_size"]
    all_words = data['all_words']
    tags = data['tags']
    model_state = data["model_state"]
    model = NeuralNet(input_size, hidden_size, output_size).to(device)
    model.load_state_dict(model_state)
    model.eval()

    sentence = tokenize(message)
    X = bag_of_words(sentence, all_words)
    X = X.reshape(1, X.shape[0])
    X = torch.from_numpy(X).to(device)

    output = model(X)
    _, predicted = torch.max(output, dim=1)

    tag = tags[predicted.item()]

    probs = torch.softmax(output, dim=1)
    prob = probs[0][predicted.item()]
    return tag, prob

def get_response(database, message, kunde, chat_id):
    write_message(database, char_id, message, "User", kunde)

    doc = get_entitys(database, message, kunde)
    doc = "Entities", [(ent.text, ent.label_) for ent in doc.ents]

    tag, prob = predict(database, kunde)

    intent = read_intent(database, kunde, tag) if prob.item() > 0.75 else None
    if intent is not None:
        answer = random.choice(intent['responses']) + str(doc)
    else:
        answer = f"I do not understand... {doc}"
    write_message(database, char_id, answer, "Bot", kunde)
    return answer
Antworten