Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -70,6 +70,27 @@ Rules:
|
|
| 70 |
- verdict is one precise sentence in German, max 12 words. Acknowledge substance if present.
|
| 71 |
- ALL string values must be valid JSON strings."""
|
| 72 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
|
| 74 |
# ββ HF Dataset Persistenz ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 75 |
|
|
@@ -194,7 +215,7 @@ def _render_leaderboard() -> str:
|
|
| 194 |
def entry_html(e, rank, side="worst"):
|
| 195 |
pct = e["pct"]
|
| 196 |
if side == "best":
|
| 197 |
-
color = "#1A5C34" if pct <
|
| 198 |
else:
|
| 199 |
color = "#C0392B" if pct >= 70 else "#E67E22" if pct >= 50 else "#D4AC0D" if pct >= 30 else "#27AE60"
|
| 200 |
medal = ["π₯","π₯","π₯"] [rank] if rank < 3 else f"{rank+1}."
|
|
@@ -371,6 +392,26 @@ def get_bingo(text):
|
|
| 371 |
return (f"<p style='color:#c00;font-size:.85rem;padding:8px;'>Analyse fehlgeschlagen: {last_err}</p>",
|
| 372 |
_render_leaderboard())
|
| 373 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 374 |
|
| 375 |
def _render_bingo(data):
|
| 376 |
metrics = data.get("metrics", [])
|
|
@@ -424,6 +465,15 @@ def _render_bingo(data):
|
|
| 424 |
font-size:.88rem;color:#444;font-style:italic;line-height:1.6;">
|
| 425 |
π¬ <strong style="font-style:normal;">Urteil:</strong> {verdict}
|
| 426 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 427 |
</div>"""
|
| 428 |
|
| 429 |
|
|
@@ -572,6 +622,60 @@ with gr.Blocks(title="LinkedIn Translator") as demo:
|
|
| 572 |
markdown_out = gr.Markdown(value="*Noch kein Ergebnis - bitte zuerst ΓΌbersetzen.*", visible=True)
|
| 573 |
bingo_out = gr.HTML(value="", visible=False)
|
| 574 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 575 |
with gr.Row():
|
| 576 |
with gr.Column():
|
| 577 |
lb_out = gr.HTML(value=_render_leaderboard())
|
|
@@ -632,4 +736,20 @@ with gr.Blocks(title="LinkedIn Translator") as demo:
|
|
| 632 |
outputs=[lb_out]
|
| 633 |
)
|
| 634 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 635 |
demo.launch(css=CSS)
|
|
|
|
| 70 |
- verdict is one precise sentence in German, max 12 words. Acknowledge substance if present.
|
| 71 |
- ALL string values must be valid JSON strings."""
|
| 72 |
|
| 73 |
+
PROMPT_AI_TUNING = """Du bist ein LinkedIn-Post-Optimizer. Du bekommst einen LinkedIn-Post und Tuning-Parameter. Deine Aufgabe: Den Post gezielt verbessern basierend auf diesen Parametern.
|
| 74 |
+
|
| 75 |
+
TUNING PARAMETER:
|
| 76 |
+
- Ton (0=Business Pro/sachlich/professionell, 100=Dynamisch/bold/provokant)
|
| 77 |
+
- Substanz (0=Storytelling/persΓΆnlich/narrativ, 100=Fakten/Daten/konkrete Insights)
|
| 78 |
+
- LΓ€nge (0=sehr kurz max 3 AbsΓ€tze, 100=ausfΓΌhrlich mit Struktur)
|
| 79 |
+
- Zielgruppe: {zielgruppe}
|
| 80 |
+
- Call to Action Ziel: {cta}
|
| 81 |
+
|
| 82 |
+
REGELN:
|
| 83 |
+
- Behalte die Kernaussage des Original-Posts
|
| 84 |
+
- Optimiere GEZIELT fΓΌr die gewΓ€hlten Parameter
|
| 85 |
+
- Kein generisches LinkedIn-Bingo - echte Verbesserung
|
| 86 |
+
- Wenn Ton=Business Pro: klar, direkt, keine Emojis-Γberladung
|
| 87 |
+
- Wenn Ton=Dynamisch: mutig, Meinung, provokante ErΓΆffnung
|
| 88 |
+
- Wenn CTA=Kommentare: endet mit echter Diskussionsfrage
|
| 89 |
+
- Wenn CTA=Website: natΓΌrlicher Verweis auf konkreten Mehrwert
|
| 90 |
+
- Wenn CTA=Reichweite: Hook in Zeile 1, Struktur fΓΌr Γbersichtlichkeit
|
| 91 |
+
|
| 92 |
+
Antworte NUR mit dem verbesserten Post. Kein Vorwort, keine ErklΓ€rung."""
|
| 93 |
+
|
| 94 |
|
| 95 |
# ββ HF Dataset Persistenz ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 96 |
|
|
|
|
| 215 |
def entry_html(e, rank, side="worst"):
|
| 216 |
pct = e["pct"]
|
| 217 |
if side == "best":
|
| 218 |
+
color = "#1A5C34" if pct < 15 else "#27AE60" if pct < 70 else "#E67E22"
|
| 219 |
else:
|
| 220 |
color = "#C0392B" if pct >= 70 else "#E67E22" if pct >= 50 else "#D4AC0D" if pct >= 30 else "#27AE60"
|
| 221 |
medal = ["π₯","π₯","π₯"] [rank] if rank < 3 else f"{rank+1}."
|
|
|
|
| 392 |
return (f"<p style='color:#c00;font-size:.85rem;padding:8px;'>Analyse fehlgeschlagen: {last_err}</p>",
|
| 393 |
_render_leaderboard())
|
| 394 |
|
| 395 |
+
def generate_tuned_post(original_text, ton, substanz, laenge, zielgruppe, cta):
|
| 396 |
+
if not original_text.strip() or not HF_TOKEN:
|
| 397 |
+
return "Bitte zuerst einen Post analysieren."
|
| 398 |
+
|
| 399 |
+
prompt = PROMPT_AI_TUNING.format(zielgruppe=zielgruppe, cta=cta)
|
| 400 |
+
user_msg = f"""ORIGINAL POST:
|
| 401 |
+
{original_text}
|
| 402 |
+
|
| 403 |
+
TUNING:
|
| 404 |
+
- Ton: {ton}/100 (0=Business Pro, 100=Dynamisch & Bold)
|
| 405 |
+
- Substanz: {substanz}/100 (0=Storytelling, 100=Fakten & Insights)
|
| 406 |
+
- LΓ€nge: {laenge}/100 (0=Kurz, 100=AusfΓΌhrlich)
|
| 407 |
+
- Zielgruppe: {zielgruppe}
|
| 408 |
+
- Call to Action: {cta}"""
|
| 409 |
+
|
| 410 |
+
try:
|
| 411 |
+
return _call_llm(prompt, user_msg, max_tokens=800)
|
| 412 |
+
except Exception as e:
|
| 413 |
+
return f"Fehler: {e}"
|
| 414 |
+
|
| 415 |
|
| 416 |
def _render_bingo(data):
|
| 417 |
metrics = data.get("metrics", [])
|
|
|
|
| 465 |
font-size:.88rem;color:#444;font-style:italic;line-height:1.6;">
|
| 466 |
π¬ <strong style="font-style:normal;">Urteil:</strong> {verdict}
|
| 467 |
</div>
|
| 468 |
+
<div style="margin-top:14px;display:flex;justify-content:flex-end;">
|
| 469 |
+
<button onclick="
|
| 470 |
+
var panel = document.getElementById('tuning_toggle_btn');
|
| 471 |
+
if(panel) panel.click();
|
| 472 |
+
" style="background:#004182;color:#fff;border:none;border-radius:22px;
|
| 473 |
+
padding:8px 20px;font-size:.82rem;font-weight:700;cursor:pointer;">
|
| 474 |
+
β¨ AI Tuning
|
| 475 |
+
</button>
|
| 476 |
+
</div>
|
| 477 |
</div>"""
|
| 478 |
|
| 479 |
|
|
|
|
| 622 |
markdown_out = gr.Markdown(value="*Noch kein Ergebnis - bitte zuerst ΓΌbersetzen.*", visible=True)
|
| 623 |
bingo_out = gr.HTML(value="", visible=False)
|
| 624 |
|
| 625 |
+
# ββ AI Tuning Panel ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 626 |
+
with gr.Row():
|
| 627 |
+
with gr.Column():
|
| 628 |
+
tuning_panel = gr.Column(visible=False)
|
| 629 |
+
tuning_toggle_btn = gr.Button("toggle", elem_id="tuning_toggle_btn", visible=False)
|
| 630 |
+
with tuning_panel:
|
| 631 |
+
gr.HTML("""
|
| 632 |
+
<div style="background:#fff;border:1px solid #E0DFDC;border-radius:12px;
|
| 633 |
+
padding:22px 26px;margin-top:4px;box-shadow:0 2px 12px rgba(0,0,0,.07);">
|
| 634 |
+
<div style="display:flex;align-items:center;gap:10px;margin-bottom:20px;">
|
| 635 |
+
<span style="font-size:1.3rem;">β¨</span>
|
| 636 |
+
<span style="font-weight:700;font-size:.95rem;color:#004182;
|
| 637 |
+
text-transform:uppercase;letter-spacing:.5px;">AI Post Tuning</span>
|
| 638 |
+
</div>
|
| 639 |
+
</div>
|
| 640 |
+
""")
|
| 641 |
+
with gr.Row():
|
| 642 |
+
with gr.Column(scale=1):
|
| 643 |
+
slider_ton = gr.Slider(
|
| 644 |
+
minimum=0, maximum=100, value=50, step=1,
|
| 645 |
+
label="ποΈ Ton",
|
| 646 |
+
info="Business Pro ββββΆ Dynamisch & Bold"
|
| 647 |
+
)
|
| 648 |
+
slider_substanz = gr.Slider(
|
| 649 |
+
minimum=0, maximum=100, value=50, step=1,
|
| 650 |
+
label="π§ Substanz",
|
| 651 |
+
info="Storytelling ββββΆ Fakten & Insights"
|
| 652 |
+
)
|
| 653 |
+
slider_laenge = gr.Slider(
|
| 654 |
+
minimum=0, maximum=100, value=40, step=1,
|
| 655 |
+
label="π LΓ€nge",
|
| 656 |
+
info="Kurz & Knackig ββββΆ AusfΓΌhrlich"
|
| 657 |
+
)
|
| 658 |
+
with gr.Column(scale=1):
|
| 659 |
+
dd_zielgruppe = gr.Dropdown(
|
| 660 |
+
choices=["Fachpublikum", "FΓΌhrungskrΓ€fte", "Breites Netzwerk", "Potenzielle Kunden"],
|
| 661 |
+
value="Breites Netzwerk",
|
| 662 |
+
label="π― Zielgruppe"
|
| 663 |
+
)
|
| 664 |
+
dd_cta = gr.Dropdown(
|
| 665 |
+
choices=["Reichweite & Likes", "Kommentare & Dialog", "Reposts", "Website-Conversion", "DMs"],
|
| 666 |
+
value="Kommentare & Dialog",
|
| 667 |
+
label="β‘ Call to Action"
|
| 668 |
+
)
|
| 669 |
+
tuning_btn = gr.Button("β¨ Post optimieren", variant="primary")
|
| 670 |
+
|
| 671 |
+
tuning_out = gr.Textbox(
|
| 672 |
+
label="π‘ Optimierter Post",
|
| 673 |
+
lines=10,
|
| 674 |
+
interactive=True,
|
| 675 |
+
placeholder="Der optimierte Post erscheint hier..."
|
| 676 |
+
)
|
| 677 |
+
|
| 678 |
+
|
| 679 |
with gr.Row():
|
| 680 |
with gr.Column():
|
| 681 |
lb_out = gr.HTML(value=_render_leaderboard())
|
|
|
|
| 736 |
outputs=[lb_out]
|
| 737 |
)
|
| 738 |
|
| 739 |
+
# Tuning panel toggle
|
| 740 |
+
def toggle_tuning(current_text):
|
| 741 |
+
return gr.update(visible=True)
|
| 742 |
+
|
| 743 |
+
tuning_toggle_btn.click(
|
| 744 |
+
fn=toggle_tuning,
|
| 745 |
+
inputs=[input_box],
|
| 746 |
+
outputs=[tuning_panel]
|
| 747 |
+
)
|
| 748 |
+
|
| 749 |
+
# Post optimieren
|
| 750 |
+
tuning_btn.click(
|
| 751 |
+
fn=generate_tuned_post,
|
| 752 |
+
inputs=[input_box, slider_ton, slider_substanz, slider_laenge, dd_zielgruppe, dd_cta],
|
| 753 |
+
outputs=[tuning_out]
|
| 754 |
+
)
|
| 755 |
demo.launch(css=CSS)
|