aidn commited on
Commit
cc01a25
Β·
verified Β·
1 Parent(s): 2a1d14e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +50 -29
app.py CHANGED
@@ -9,12 +9,12 @@ MODEL_ID = "meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8"
9
 
10
  # ── System Prompts ─────────────────────────────────────────────────────────────
11
 
12
- PROMPT_TO_LINKEDIN = """Du bist ein LinkedIn-Influencer-Generator. Deine einzige Aufgabe ist es, banale, alltΓ€gliche Aussagen in absurd ausschweifende, klischeebeladene LinkedIn-Posts zu verwandeln.
13
 
14
  Regeln:
15
  - Alles ist eine "Journey", ein "Gamechanger" oder eine "powerful lesson"
16
  - Nutze mindestens 3 Emojis strategisch
17
- - ErwΓ€hne "Growth", "Mindset", "Passion" oder "Impact" wo immer moeglich
18
  - Fuege eine persoenliche Anekdote hinzu, die niemand braucht
19
  - Endet mit einer rhetorischen Frage an die Community
20
  - Benutze dramatische Zeilenumbrueche fuer Effekt
@@ -23,7 +23,7 @@ Regeln:
23
  - Klingt wie jemand, der gerade ein Buch ueber sich selbst schreiben wuerde
24
  - Formatiere mit Markdown: Eroeffnungssatz als ## Ueberschrift, Schluesselbegriffe wie **Gamechanger**, **Growth**, **Mindset**, **Journey** fett hervorheben, Abschnitte mit Leerzeilen trennen
25
 
26
- Antworte NUR mit dem LinkedIn-Post in Markdown. Kein Vorwort, keine ErklΓ€rung."""
27
 
28
  PROMPT_FROM_LINKEDIN = """Du bist ein gnadenloser semantischer Reduzierer. Du hasst Floskeln. Deine Aufgabe: LinkedIn-Texte auf das absolute, brutalste Minimum eindampfen.
29
 
@@ -31,29 +31,24 @@ Regeln:
31
  - EIN Satz. Nicht zwei. Einer.
32
  - Kuerze bis es wehtut. Dann nochmal kuerzen.
33
  - Null Emotion, null Wertung, null Kontext der niemanden interessiert
34
- - Streiche alles was keine neue Information trΓ€gt
35
  - Wenn der gesamte Post nur bedeutet "Ich hab heute Kaffee getrunken" schreib genau das
36
  - Maximal 15 Woerter
37
 
38
- Antworte NUR mit diesem einen Satz. Kein Vorwort, keine ErklΓ€rung."""
39
 
40
- PROMPT_BINGO = """Du bist ein sarkastischer LinkedIn-Prosa-Analytiker. Bewerte den folgenden LinkedIn-Post anhand von 5 Metriken.
41
 
42
- Antworte AUSSCHLIESSLICH mit einem validen JSON-Objekt. Kein Markdown, keine Backticks, keine ErklΓ€rung davor oder danach. Nur das rohe JSON.
43
 
44
- Format:
45
- {"metrics":[{"icon":"X","label":"Y","score":N,"comment":"Z"},...], "verdict":"..."}
46
 
47
- Verwende diese 5 Metriken in dieser Reihenfolge:
48
- 1. icon="Buzzword-Dichte" label="Buzzword-Dichte" - Wie viele inhaltsleere Modebegriffe?
49
- 2. icon="LΓ€nge vs. Inhalt" label="LΓ€nge vs. Inhalt" - Wie viel LΓ€nge fuer wie wenig Aussage?
50
- 3. icon="SelbstbeweihrΓ€uche" label="SelbstbeweihrΓ€uche" - Wie sehr dreht sich alles um den Autor?
51
- 4. icon="Hashtag-Overload" label="Hashtag-Overload" - Hashtag-Dichte und Sinnlosigkeit
52
- 5. icon="Sinnlosigkeits-Index" label="Sinnlosigkeits-Index" - Koennte man den Post loeschen ohne Informationsverlust?
53
-
54
- score ist ein Integer von 1-10. 10 = maximaler LinkedIn-Exzess.
55
- comment ist max. 6 Woerter, sarkastisch.
56
- verdict ist ein einziger vernichtender Satz, max. 12 Woerter."""
57
 
58
 
59
  # ── LLM-Calls ─────────────────────────────────────────────────────────────────
@@ -81,17 +76,43 @@ def translate(text, direction):
81
  return f"Fehler: {e}"
82
 
83
 
84
- def get_bingo(text):
85
- if not text.strip() or not HF_TOKEN:
86
- return ""
 
 
 
 
 
87
  try:
88
- raw = _call_llm(PROMPT_BINGO, text, max_tokens=512)
89
  start = raw.find("{")
90
  end = raw.rfind("}") + 1
91
- data = json.loads(raw[start:end])
92
- return _render_bingo(data)
93
- except Exception as e:
94
- return f"<p style='color:#c00'>Analyse fehlgeschlagen: {e}</p>"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
 
96
 
97
  def _render_bingo(data):
@@ -100,8 +121,8 @@ def _render_bingo(data):
100
 
101
  ICONS = {
102
  "Buzzword-Dichte": "πŸ—£οΈ",
103
- "LΓ€nge vs. Inhalt": "πŸ“",
104
- "SelbstbeweihrΓ€uche": "πŸͺž",
105
  "Hashtag-Overload": "#️⃣",
106
  "Sinnlosigkeits-Index": "πŸŒ€",
107
  }
 
9
 
10
  # ── System Prompts ─────────────────────────────────────────────────────────────
11
 
12
+ PROMPT_TO_LINKEDIN = """Du bist ein LinkedIn-Influencer-Generator. Deine einzige Aufgabe ist es, banale, alltaegliche Aussagen in absurd ausschweifende, klischeebeladene LinkedIn-Posts zu verwandeln.
13
 
14
  Regeln:
15
  - Alles ist eine "Journey", ein "Gamechanger" oder eine "powerful lesson"
16
  - Nutze mindestens 3 Emojis strategisch
17
+ - Erwaehne "Growth", "Mindset", "Passion" oder "Impact" wo immer moeglich
18
  - Fuege eine persoenliche Anekdote hinzu, die niemand braucht
19
  - Endet mit einer rhetorischen Frage an die Community
20
  - Benutze dramatische Zeilenumbrueche fuer Effekt
 
23
  - Klingt wie jemand, der gerade ein Buch ueber sich selbst schreiben wuerde
24
  - Formatiere mit Markdown: Eroeffnungssatz als ## Ueberschrift, Schluesselbegriffe wie **Gamechanger**, **Growth**, **Mindset**, **Journey** fett hervorheben, Abschnitte mit Leerzeilen trennen
25
 
26
+ Antworte NUR mit dem LinkedIn-Post in Markdown. Kein Vorwort, keine Erklaerung."""
27
 
28
  PROMPT_FROM_LINKEDIN = """Du bist ein gnadenloser semantischer Reduzierer. Du hasst Floskeln. Deine Aufgabe: LinkedIn-Texte auf das absolute, brutalste Minimum eindampfen.
29
 
 
31
  - EIN Satz. Nicht zwei. Einer.
32
  - Kuerze bis es wehtut. Dann nochmal kuerzen.
33
  - Null Emotion, null Wertung, null Kontext der niemanden interessiert
34
+ - Streiche alles was keine neue Information traegt
35
  - Wenn der gesamte Post nur bedeutet "Ich hab heute Kaffee getrunken" schreib genau das
36
  - Maximal 15 Woerter
37
 
38
+ Antworte NUR mit diesem einen Satz. Kein Vorwort, keine Erklaerung."""
39
 
40
+ PROMPT_BINGO = """You are a sarcastic LinkedIn prose analyst. Rate the following LinkedIn post on 5 metrics.
41
 
42
+ Reply ONLY with a single valid JSON object. No markdown fences, no backticks, no explanation before or after. Raw JSON only.
43
 
44
+ Use exactly this structure:
45
+ {"metrics":[{"label":"Buzzword-Dichte","score":7,"comment":"kurz sarkastisch"},{"label":"Laenge vs. Inhalt","score":5,"comment":"kurz sarkastisch"},{"label":"Selbstbeweihraeuche","score":8,"comment":"kurz sarkastisch"},{"label":"Hashtag-Overload","score":3,"comment":"kurz sarkastisch"},{"label":"Sinnlosigkeits-Index","score":6,"comment":"kurz sarkastisch"}],"verdict":"Ein vernichtender Satz auf Deutsch."}
46
 
47
+ Rules:
48
+ - score is an integer 1-10. 10 = worst LinkedIn excess possible.
49
+ - comment is max 5 words in German, sarcastic. Use only basic ASCII characters, no special chars.
50
+ - verdict is one devastating sentence in German, max 12 words. Use only basic ASCII characters.
51
+ - ALL string values must be valid JSON strings. Escape nothing special, just use plain ASCII."""
 
 
 
 
 
52
 
53
 
54
  # ── LLM-Calls ─────────────────────────────────────────────────────────────────
 
76
  return f"Fehler: {e}"
77
 
78
 
79
+ def _extract_json(raw: str) -> dict:
80
+ """Mehrere Strategien um JSON aus LLM-Antwort zu extrahieren."""
81
+ # 1. Direkt parsen
82
+ try:
83
+ return json.loads(raw)
84
+ except Exception:
85
+ pass
86
+ # 2. JSON-Block per Index extrahieren
87
  try:
 
88
  start = raw.find("{")
89
  end = raw.rfind("}") + 1
90
+ if start >= 0 and end > start:
91
+ return json.loads(raw[start:end])
92
+ except Exception:
93
+ pass
94
+ # 3. Whitespace bereinigen und nochmal versuchen
95
+ try:
96
+ cleaned = raw[raw.find("{"):raw.rfind("}")+1]
97
+ cleaned = " ".join(cleaned.split())
98
+ return json.loads(cleaned)
99
+ except Exception:
100
+ pass
101
+ raise ValueError("Kein valides JSON gefunden")
102
+
103
+
104
+ def get_bingo(text: str) -> str:
105
+ if not text.strip() or not HF_TOKEN:
106
+ return ""
107
+ last_err = None
108
+ for attempt in range(3):
109
+ try:
110
+ raw = _call_llm(PROMPT_BINGO, text, max_tokens=600)
111
+ data = _extract_json(raw)
112
+ return _render_bingo(data)
113
+ except Exception as e:
114
+ last_err = e
115
+ return f"<p style='color:#c00;font-size:.85rem;padding:8px;'>Analyse fehlgeschlagen nach 3 Versuchen: {last_err}</p>"
116
 
117
 
118
  def _render_bingo(data):
 
121
 
122
  ICONS = {
123
  "Buzzword-Dichte": "πŸ—£οΈ",
124
+ "Laenge vs. Inhalt": "πŸ“",
125
+ "Selbstbeweihraeuche": "πŸͺž",
126
  "Hashtag-Overload": "#️⃣",
127
  "Sinnlosigkeits-Index": "πŸŒ€",
128
  }