Wie du einen einfachen Satzgenerator für Horoskope in Python baust

Wie du einen einfachen Satzgenerator für Horoskope in Python baust

Für mein Twitch Horoskop Projekt brauchte ich ein Stück Software, das mir einen grammatikalisch korrekten Satz auf Englisch erzeugen kann. Dieses sollte in Python laufen, da das weitere Projekt darauf aufbaut.

Folgende Punkte waren mir wichtig: Es sollte die Möglichkeit geben einen Seed in Form eines Parameters, als String mitzugeben. Dieser Seed soll sicherstellen, dass mir die Funktion denselben Satz bei mehrmaliger Ausführung zurückliefert, solange sich der Seed nicht ändert. Darüber hinaus möchte ich die Horoskope etwas Persönlicher erscheinen lassen, indem ich die Namen von Streamern die dieser Streamer folgt gelegentlich in das Horoskop einbaue. Dies geschieht mit einem zweiten Parameter. Da ich zukünftig vielleicht unterschiedlich lange Horoskope erstellen möchte, sollte ein letzter Parameter die Anzahl der zurückgegebenen Horoskope einstellbar machen.

Zunächst schaute ich mir ein paar Horoskope aus dem Internet an. Dabei fiel auf, dass sie oft sehr ähnliche Wörter und Satzstrukturen verwenden. Ich schrieb mir ein paar davon raus:

  • Bla you will bla bla, and it will bla.
  • If bla, then bla.
  • If bla, bla.
  • Bla bla is bla, which means that you should bla bla bla blabla. Bla bla and bla.

Weil ich nicht so statisch wirkende Horoskope generieren will und ich es in diesem Fall nicht schlimm finde, wenn ein Horoskop aus mehreren Sätzen besteht, erweitere ich diese Strukturen etwas und schreibe sie in eine Liste von Objekten:

[
    {
        "structure": "%s you will %s %s, and it will %s. %s.",
        "parts": [
            [
                "Today",
                "This week",
                "Soon",
            ],
            [
                "stumble across",
                "find",
                "discover",
                "uncover",
            ],
            [
                "a long forgotten meme",
                "a game from your childhood",
                "a fact about {{streamername}}",
            ],
            [
                "become important to you",
                "take on a new meaning to you",
                "take on new meaning in your life",
            ],
            [
                "Sieze this day as your own",
                "Don't let this opportunity pass you by",
            ],
        ],
    },
    {
        "structure": "If %s, then %s. %s.",
        "parts": [
            [
                "you plan to look for cat videos on Youtube",
                "you plan to spam random emotes in the chat",
                "you consider becoming a fulltime chess player",
                "you plan to go to the next Twitchcon",
                "you consider founding an eSports team",
            ],
            [
                "this may be a big year for you",
                "don't put it off",
                "you might just be right",
                "you need to think about it more",
                "you might be right",
                "you arleady might know what to do",
                "{{streamername}} would agree",
            ],
            [
                
                "If that doesn't make sense for you, then the time is obviously wrong",
                "But it's never too late to reconsider your options",
                "When in doubt, consult someone wiser than you",
                "There's no reason to rush into anything rash",
            ],
        ],
    },
    {
        "structure": "If %s, %s. %s that %s. %s",
        "parts": [
            ...
        ]
    },
    {
        "structure": "%s %s is %s, which means that you should %s %s %s %s%s.%s%s",
        "parts": [
            ...
        ]
    },
    {
        "structure": "%s. %s %s and %s.%s%s",
        "parts": [
            ...
        ]
    },
}

Um Platz in deinem Browser zu speichern habe ich diese Liste oben im Beispiel verkürzt. Bei mir ist sie natürlich komplett ausgefüllt… Ist diese Satzliste mit Memes gefüllt können wir endlich eine Funktion schreiben die uns die Sätze generiert:

from random import choice, seed, shuffle
from jinja2 import Template

def get_sentences(seedstring, yourstreamers, amount):
    """Generates your horoscope !

    Args:
        seedstring (str): just any random str. Same string = same result
        yourstreamers (list): A list of str. Will be used within sentences
        amount (int): Amount of horoscopes, any positive number

    Returns
        list: A list of (str). each one representing an individual horoscope
    """
    seed(a=seedstring, version=2)
    shuffle(SENTENCEOBJECTS)
    sentences = []
    for sentenceobj in SENTENCEOBJECTS:
        parts = map(choice, sentenceobj[parts])
        sentence = sentenceobj["structure"] % (tuple(parts))
        sentence = Template(sentence).render(
            streamername=choice(yourstreamers)
        )
        sentences.append(sentence)
        amount -= 1
        if amount <= 0:
            break
    return sentences

Diese Funktion funktioniert so:

Erst wird der Seed gesetzt. Der Seed beeinflusst die Wahl der choice Funktion. In der nächsten Zeile wird die Satzliste durchmischt damit nicht immer dieselbe Satzstruktur zuerst verwendet wird. Innerhalb der Schleife werden mit map + choice die Satzbausteine zufällig ausgewählt und anschließend mithilfe des Prozent-Operators in den Satz eingesetzt. Der Prozent-Operator nimmt unsere Liste nur in Tupleform. Der Template().render Befehl ersetzt die {{streamername}} Substrings meiner Sätze mit einem zufälligen Namen aus der Streamerliste. Das fertige Horoskop wird in die sentences Variable gespeichert und das ganze wird "amount" mal wiederholt. Am Ende geben wir die sentences Variable zurück.

Um das ganze jetzt zu testen, müssen wir einfach die ganze Pythondatei importieren und als Funktion aufrufen:

from horoscopesentences import get_sentences
get_sentences(test,[test\],2)
[\'Next Twitchcon you will uncover a very old meme, and it will take on a new meaning to you. Why not get started with the rest of your life today.\', If you are having a bad feeling abour your eSports careeryou don\'t think you know exactly what you might want, then come to a decision and see it through. Understand that sometimes you can\'t appreciate standing up unless you have first fallen down. \]

Fertige Funktion
Fertige Funktion

Ergebnis
Ungefähr so sieht das Ergebnis auf der fertigen Webseite aus

Leave a Reply