diff --git a/build/briefe_holen.py b/build/briefe_holen.py new file mode 100644 index 0000000..3dd4ed4 --- /dev/null +++ b/build/briefe_holen.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +"""Holt briefe/brief-SLUG.json aus Gitea nach build/lokal/briefe/SLUG.json. Aufruf: python3 build/briefe_holen.py SLUG [...]""" +import base64, json, os, sys +exec(open(os.path.join(os.path.dirname(__file__), 'push_gitea.py'), encoding='utf-8').read().split('def sammle')[0]) +os.makedirs('build/lokal/briefe', exist_ok=True) +for s in sys.argv[1:]: + code, d = ruf('GET', f"{REPO}/contents/briefe/brief-{s}.json?ref=main") + if code != 200: + print('fehlt', s); continue + b = json.loads(base64.b64decode(d['content']).decode()) + json.dump(b, open(f'build/lokal/briefe/{s}.json', 'w', encoding='utf-8'), ensure_ascii=False, indent=2) + z = b.get('zusatz', {}) + print(f"== {s} | {b['query_id']} | Ziel {b['wortzahl_ziel']}") + print(' Pflicht:', ' | '.join(f"{x['begriff']}:{x['min']}-{x['max']}" for x in b['begriffe_pflicht'])) + print(' Titel:', ', '.join(z.get('begriffe_titel', []))) + print(' Desc:', ', '.join(z.get('begriffe_description', []))) + print(' H2:', ', '.join(z.get('begriffe_h2', [])[:25])) + erw = sorted(b['begriffe_erweitert'], key=lambda x: -(x['bei_wettbewerbern_pc'] or 0)) + print(' Erweitert:', ', '.join(x['begriff'] for x in erw[:45])) + print(' Fragen:', ' / '.join(f['frage'] for f in b['fragen'][:8])) diff --git a/build/gen_wf2.py b/build/gen_wf2.py index 179c116..6da8d6f 100644 --- a/build/gen_wf2.py +++ b/build/gen_wf2.py @@ -179,12 +179,13 @@ while ((m = re.exec(String(artikel.content_html || ''))) !== null) { } const shortcodes = (String(artikel.content_html || '').match(/\[skrift_preis[^\]]*\]/g) || []); -// NeuronWriter bewertet nur den uebergebenen Text. Kurzantwort und FAQ stehen +// NeuronWriter bewertet nur den uebergebenen Text. Titel (H1), Kurzantwort und FAQ stehen // aber auf der fertigen Seite, also gehoeren sie in die Bewertung. Der gespeicherte // Artikel bleibt unveraendert, das hier ist nur der Pruefkoerper. const faqText = (Array.isArray(artikel.faq) ? artikel.faq : []) .map(f => `
${f.antwort || ''}
`).join('\n'); const bewertungs_html = [ + artikel.titel ? `${artikel.kurzantwort}
` : '', artikel.content_html || '', faqText ? `{f.get('antwort','')}
" for f in a.get('faq') or []) - html = '\n'.join([f"{a['kurzantwort']}
" if a.get('kurzantwort') else '', a['content_html'], + html = '\n'.join([f"{a['kurzantwort']}
" if a.get('kurzantwort') else '', a['content_html'], f"([\\s\\S]*?)<\\/p>/g)].map(m => ohneTags(m[1])).filter(Boolean);\n const volltext = [ohneTags(artikel.kurzantwort), ohneTags(html),\n ...(Array.isArray(artikel.faq) ? artikel.faq.map(f => ohneTags(f.antwort)) : [])].join(' ');\n\n // 1) Floskeln und Formeln, die in generierten Texten gehaeuft auftreten\n const formeln = [\n ['genau das', 'Formel'], ['genau diese', 'Formel'], ['genau daran', 'Formel'], ['genau so', 'Formel'],\n ['der grund ist', 'Formel'], ['nicht nur', 'Formel \"nicht nur, sondern auch\"'],\n ['entscheidend ist', 'Formel'], ['entscheidend für', 'Formel'], ['größten hebel', 'Formel'],\n ['den unterschied', 'Formel'], ['am ende des tages', 'Floskel'], ['unterm strich', 'Floskel'],\n ['kurz gesagt', 'Floskel'], ['mit anderen worten', 'Floskel'], ['die gute nachricht', 'Floskel'],\n ['spielt eine rolle', 'Floskel'], ['es lohnt sich', 'Floskel'], ['egal ob', 'Formel'],\n ['in diesem artikel', 'Meta-Satz'], ['wir zeigen ihnen', 'Meta-Satz'], ['fazit', 'Zusammenfassung'],\n ['tatsächlich', 'Fuellwort'], ['letztlich', 'Fuellwort'], ['schlicht', 'Fuellwort'], ['simpel', 'Fuellwort'],\n ['erfahrungsgemäß', 'unbelegte Behauptung'], ['in aller regel', 'unbelegte Behauptung'],\n ['studien zeigen', 'unbelegte Behauptung'], ['nachweislich', 'unbelegte Behauptung'],\n ['bekanntlich', 'Floskel'],\n ];\n const klein = volltext.toLowerCase();\n formeln.forEach(([f, art]) => {\n let i = klein.indexOf(f);\n while (i >= 0) {\n add(art + ': \"' + f + '\"', '…' + volltext.slice(Math.max(0, i - 40), i + f.length + 50) + '…');\n i = klein.indexOf(f, i + f.length);\n }\n });\n\n // 2) Aufzaehlungen im Fliesstext\n if (/\\berstens\\b[\\s\\S]*\\bzweitens\\b/i.test(volltext)) add('Aufzaehlung \"Erstens, zweitens\"', 'Im Fliesstext lieber eine echte Liste oder zwei Saetze');\n const dreier = volltext.match(/\\b\\w+(?:ig|lich|ell|bar|iv|sam)\\b, \\w+(?:ig|lich|ell|bar|iv|sam)\\b und \\w+(?:ig|lich|ell|bar|iv|sam)\\b/gi) || [];\n dreier.forEach(d => add('Dreierreihe aus Adjektiven', d));\n\n // 3) Rhetorische Frage im Absatz, direkt beantwortet\n absaetze.forEach(a => {\n const m = a.match(/[^.!?]{8,}\\?\\s+[A-ZÄÖÜ][^.!?]{3,}[.!]/);\n if (m) add('Rhetorische Frage mit Sofortantwort', m[0]);\n });\n\n // 4) Satzlaengen: gleichfoermiger Rhythmus\n const saetze = ohneTags(html).split(/(?<=[.!?])\\s+/).map(s => s.trim())\n .filter(s => s.split(' ').length >= 3);\n const laengen = saetze.map(s => s.split(' ').length);\n if (laengen.length >= 8) {\n const mittel = laengen.reduce((x, y) => x + y, 0) / laengen.length;\n const sd = Math.sqrt(laengen.reduce((x, y) => x + (y - mittel) ** 2, 0) / laengen.length);\n if (sd < 4.5) add('Gleichfoermige Satzlaengen', `Durchschnitt ${mittel.toFixed(1)} Woerter, Streuung nur ${sd.toFixed(1)}. Kurze und lange Saetze mischen.`);\n for (let i = 0; i + 4 <= laengen.length; i++) {\n const fenster = laengen.slice(i, i + 4);\n if (Math.max(...fenster) - Math.min(...fenster) <= 3) {\n add('Vier Saetze gleicher Laenge hintereinander', saetze[i]);\n i += 3;\n }\n }\n }\n\n // 5) Gleiche Satzanfaenge\n for (let i = 0; i + 3 <= saetze.length; i++) {\n const w = saetze.slice(i, i + 3).map(s => s.split(' ')[0].toLowerCase());\n if (w[0] === w[1] && w[1] === w[2] && w[0].length > 2) { add('Drei Saetze mit gleichem Anfang', saetze[i]); i += 2; }\n }\n const anfaenge = {};\n absaetze.forEach(a => { const k = a.split(' ').slice(0, 2).join(' ').toLowerCase(); anfaenge[k] = (anfaenge[k] || 0) + 1; });\n Object.entries(anfaenge).filter(([, n]) => n >= 3).forEach(([k, n]) => add('Absatzanfaenge wiederholen sich', `${n} Absaetze beginnen mit \"${k}\"`));\n\n // 6) Gleich lange Absaetze\n const al = absaetze.map(a => a.split(' ').length).filter(n => n >= 12);\n if (al.length >= 5) {\n const m = al.reduce((x, y) => x + y, 0) / al.length;\n const sd = Math.sqrt(al.reduce((x, y) => x + (y - m) ** 2, 0) / al.length);\n if (sd / m < 0.25) add('Absaetze fast gleich lang', `Durchschnitt ${m.toFixed(0)} Woerter, kaum Abweichung. Einen Absatz bewusst kurz halten.`);\n }\n\n // 7) Praxiswissen: ohne eigene Stichpunkte bleibt der Text generisch\n if (!Array.isArray(artikel.praxis) || artikel.praxis.length === 0) {\n add('Kein Praxiswissen hinterlegt', 'Feld \"praxis\" in artikel-index.json fuellen, dann den Artikel darauf aufbauen');\n }\n\n // 7b) Preise: immer inkl. MwSt., Formulierung \"inkl. 19 % MwSt.\"\n const alleTexte = [String(artikel.kurzantwort || ''), html,\n ...(Array.isArray(artikel.faq) ? artikel.faq.map(f => String(f.antwort || '')) : [])].join(' ');\n (alleTexte.match(/\\[skrift_preis[^\\]]*\\]/g) || []).forEach(s => {\n if (!/brutto=\"1\"/.test(s)) add('Preis ohne MwSt.', `${s} braucht brutto=\"1\"`);\n });\n const nb = ohneTags(alleTexte.replace(/\\[skrift_preis[^\\]]*\\]/g, 'PREIS')).match(/[^.]{0,40}\\b(netto|brutto|zzgl\\.?|zuzüglich)\\b[^.]{0,30}/gi) || [];\n nb.forEach(s => add('Preisangabe: \"netto\"/\"brutto\" statt \"inkl. 19 % MwSt.\"', s.trim()));\n\n // 8) Interne Links: primaer auf Business-Leistungsseiten\n const B = 'https://skrift.de/';\n const BUSINESS = ['handgeschriebene-businessbriefe', 'handgeschriebene-postkarten',\n 'unterschriftenservice', 'automatisierte-follow-ups'];\n const NEUTRAL = ['papier-schriftmuster', 'kontakt'];\n const PRIVAT = ['handschrift-fuer-privatpersonen', 'handgeschriebene-private-briefe',\n 'handgeschriebene-private-postkarten'];\n const slugVon = (u) => String(u || '').replace(/^https?:\\/\\/(www\\.)?skrift\\.de\\/?/, '').replace(/\\/.*$/, '');\n const links = [...html.matchAll(/]*href=\"([^\"]+)\"/g)].map(m => m[1]);\n const intern = links.filter(u => /^https?:\\/\\/(www\\.)?skrift\\.de/.test(u) || u.startsWith('/'));\n const slugs = intern.map(u => u.startsWith('/') ? u.replace(/^\\/|\\/.*$/g, '') : slugVon(u));\n\n const cta = slugVon(artikel.cta_ziel);\n if (!BUSINESS.includes(cta)) add('Links: CTA-Ziel ist keine Business-Leistungsseite', `cta_ziel \"${artikel.cta_ziel || 'leer'}\", erlaubt: ${BUSINESS.join(', ')}`);\n const ctaAnzahl = slugs.filter(s => s === cta).length;\n if (ctaAnzahl < 1) add('Links: CTA-Ziel nicht verlinkt', 'cta_ziel mindestens einmal im Fliesstext verlinken');\n const bus = slugs.filter(s => BUSINESS.includes(s));\n const priv = slugs.filter(s => PRIVAT.includes(s));\n if (bus.length < 2) add('Links: zu wenige Business-Links', `${bus.length} Link(s) auf Business-Seiten, mindestens 2`);\n if (priv.length) add('Links: Privatkunden-Link im Text', 'Privatkunden-Seiten nicht aus dem Artikeltext verlinken, das uebernimmt das Seitenlayout');\n // Bausteine, die das Seitenlayout bereits liefert\n if (/Auch für Privatpersonen/i.test(html)) add('Baustein doppelt: \"Auch für Privatpersonen.\"', 'Block aus dem Artikeltext entfernen, er steht im Seitenlayout');\n if (/ ${f.antwort || ''} ${artikel.kurzantwort} ([\\s\\S]*?)<\\/p>/g)].map(m => ohneTags(m[1])).filter(Boolean);\n const volltext = [ohneTags(artikel.kurzantwort), ohneTags(html),\n ...(Array.isArray(artikel.faq) ? artikel.faq.map(f => ohneTags(f.antwort)) : [])].join(' ');\n\n // 1) Floskeln und Formeln, die in generierten Texten gehaeuft auftreten\n const formeln = [\n ['genau das', 'Formel'], ['genau diese', 'Formel'], ['genau daran', 'Formel'], ['genau so', 'Formel'],\n ['der grund ist', 'Formel'], ['nicht nur', 'Formel \"nicht nur, sondern auch\"'],\n ['entscheidend ist', 'Formel'], ['entscheidend für', 'Formel'], ['größten hebel', 'Formel'],\n ['den unterschied', 'Formel'], ['am ende des tages', 'Floskel'], ['unterm strich', 'Floskel'],\n ['kurz gesagt', 'Floskel'], ['mit anderen worten', 'Floskel'], ['die gute nachricht', 'Floskel'],\n ['spielt eine rolle', 'Floskel'], ['es lohnt sich', 'Floskel'], ['egal ob', 'Formel'],\n ['in diesem artikel', 'Meta-Satz'], ['wir zeigen ihnen', 'Meta-Satz'], ['fazit', 'Zusammenfassung'],\n ['tatsächlich', 'Fuellwort'], ['letztlich', 'Fuellwort'], ['schlicht', 'Fuellwort'], ['simpel', 'Fuellwort'],\n ['erfahrungsgemäß', 'unbelegte Behauptung'], ['in aller regel', 'unbelegte Behauptung'],\n ['studien zeigen', 'unbelegte Behauptung'], ['nachweislich', 'unbelegte Behauptung'],\n ['bekanntlich', 'Floskel'],\n ];\n const klein = volltext.toLowerCase();\n formeln.forEach(([f, art]) => {\n let i = klein.indexOf(f);\n while (i >= 0) {\n add(art + ': \"' + f + '\"', '…' + volltext.slice(Math.max(0, i - 40), i + f.length + 50) + '…');\n i = klein.indexOf(f, i + f.length);\n }\n });\n\n // 2) Aufzaehlungen im Fliesstext\n if (/\\berstens\\b[\\s\\S]*\\bzweitens\\b/i.test(volltext)) add('Aufzaehlung \"Erstens, zweitens\"', 'Im Fliesstext lieber eine echte Liste oder zwei Saetze');\n const dreier = volltext.match(/\\b\\w+(?:ig|lich|ell|bar|iv|sam)\\b, \\w+(?:ig|lich|ell|bar|iv|sam)\\b und \\w+(?:ig|lich|ell|bar|iv|sam)\\b/gi) || [];\n dreier.forEach(d => add('Dreierreihe aus Adjektiven', d));\n\n // 3) Rhetorische Frage im Absatz, direkt beantwortet\n absaetze.forEach(a => {\n const m = a.match(/[^.!?]{8,}\\?\\s+[A-ZÄÖÜ][^.!?]{3,}[.!]/);\n if (m) add('Rhetorische Frage mit Sofortantwort', m[0]);\n });\n\n // 4) Satzlaengen: gleichfoermiger Rhythmus\n const saetze = ohneTags(html).split(/(?<=[.!?])\\s+/).map(s => s.trim())\n .filter(s => s.split(' ').length >= 3);\n const laengen = saetze.map(s => s.split(' ').length);\n if (laengen.length >= 8) {\n const mittel = laengen.reduce((x, y) => x + y, 0) / laengen.length;\n const sd = Math.sqrt(laengen.reduce((x, y) => x + (y - mittel) ** 2, 0) / laengen.length);\n if (sd < 4.5) add('Gleichfoermige Satzlaengen', `Durchschnitt ${mittel.toFixed(1)} Woerter, Streuung nur ${sd.toFixed(1)}. Kurze und lange Saetze mischen.`);\n for (let i = 0; i + 4 <= laengen.length; i++) {\n const fenster = laengen.slice(i, i + 4);\n if (Math.max(...fenster) - Math.min(...fenster) <= 3) {\n add('Vier Saetze gleicher Laenge hintereinander', saetze[i]);\n i += 3;\n }\n }\n }\n\n // 5) Gleiche Satzanfaenge\n for (let i = 0; i + 3 <= saetze.length; i++) {\n const w = saetze.slice(i, i + 3).map(s => s.split(' ')[0].toLowerCase());\n if (w[0] === w[1] && w[1] === w[2] && w[0].length > 2) { add('Drei Saetze mit gleichem Anfang', saetze[i]); i += 2; }\n }\n const anfaenge = {};\n absaetze.forEach(a => { const k = a.split(' ').slice(0, 2).join(' ').toLowerCase(); anfaenge[k] = (anfaenge[k] || 0) + 1; });\n Object.entries(anfaenge).filter(([, n]) => n >= 3).forEach(([k, n]) => add('Absatzanfaenge wiederholen sich', `${n} Absaetze beginnen mit \"${k}\"`));\n\n // 6) Gleich lange Absaetze\n const al = absaetze.map(a => a.split(' ').length).filter(n => n >= 12);\n if (al.length >= 5) {\n const m = al.reduce((x, y) => x + y, 0) / al.length;\n const sd = Math.sqrt(al.reduce((x, y) => x + (y - m) ** 2, 0) / al.length);\n if (sd / m < 0.25) add('Absaetze fast gleich lang', `Durchschnitt ${m.toFixed(0)} Woerter, kaum Abweichung. Einen Absatz bewusst kurz halten.`);\n }\n\n // 7) Praxiswissen: ohne eigene Stichpunkte bleibt der Text generisch\n if (!Array.isArray(artikel.praxis) || artikel.praxis.length === 0) {\n add('Kein Praxiswissen hinterlegt', 'Feld \"praxis\" in artikel-index.json fuellen, dann den Artikel darauf aufbauen');\n }\n\n // 7b) Preise: immer inkl. MwSt., Formulierung \"inkl. 19 % MwSt.\"\n const alleTexte = [String(artikel.kurzantwort || ''), html,\n ...(Array.isArray(artikel.faq) ? artikel.faq.map(f => String(f.antwort || '')) : [])].join(' ');\n (alleTexte.match(/\\[skrift_preis[^\\]]*\\]/g) || []).forEach(s => {\n if (!/brutto=\"1\"/.test(s)) add('Preis ohne MwSt.', `${s} braucht brutto=\"1\"`);\n });\n const nb = ohneTags(alleTexte.replace(/\\[skrift_preis[^\\]]*\\]/g, 'PREIS')).match(/[^.]{0,40}\\b(netto|brutto|zzgl\\.?|zuzüglich)\\b[^.]{0,30}/gi) || [];\n nb.forEach(s => add('Preisangabe: \"netto\"/\"brutto\" statt \"inkl. 19 % MwSt.\"', s.trim()));\n\n // 8) Interne Links: primaer auf Business-Leistungsseiten\n const B = 'https://skrift.de/';\n const BUSINESS = ['handgeschriebene-businessbriefe', 'handgeschriebene-postkarten',\n 'unterschriftenservice', 'automatisierte-follow-ups'];\n const NEUTRAL = ['papier-schriftmuster', 'kontakt'];\n const PRIVAT = ['handschrift-fuer-privatpersonen', 'handgeschriebene-private-briefe',\n 'handgeschriebene-private-postkarten'];\n const slugVon = (u) => String(u || '').replace(/^https?:\\/\\/(www\\.)?skrift\\.de\\/?/, '').replace(/\\/.*$/, '');\n const links = [...html.matchAll(/]*href=\"([^\"]+)\"/g)].map(m => m[1]);\n const intern = links.filter(u => /^https?:\\/\\/(www\\.)?skrift\\.de/.test(u) || u.startsWith('/'));\n const slugs = intern.map(u => u.startsWith('/') ? u.replace(/^\\/|\\/.*$/g, '') : slugVon(u));\n\n const cta = slugVon(artikel.cta_ziel);\n if (!BUSINESS.includes(cta)) add('Links: CTA-Ziel ist keine Business-Leistungsseite', `cta_ziel \"${artikel.cta_ziel || 'leer'}\", erlaubt: ${BUSINESS.join(', ')}`);\n const ctaAnzahl = slugs.filter(s => s === cta).length;\n if (ctaAnzahl < 1) add('Links: CTA-Ziel nicht verlinkt', 'cta_ziel mindestens einmal im Fliesstext verlinken');\n const bus = slugs.filter(s => BUSINESS.includes(s));\n const priv = slugs.filter(s => PRIVAT.includes(s));\n if (bus.length < 2) add('Links: zu wenige Business-Links', `${bus.length} Link(s) auf Business-Seiten, mindestens 2`);\n if (priv.length) add('Links: Privatkunden-Link im Text', 'Privatkunden-Seiten nicht aus dem Artikeltext verlinken, das uebernimmt das Seitenlayout');\n // Bausteine, die das Seitenlayout bereits liefert\n if (/Auch für Privatpersonen/i.test(html)) add('Baustein doppelt: \"Auch für Privatpersonen.\"', 'Block aus dem Artikeltext entfernen, er steht im Seitenlayout');\n if (/ ${f.antwort || ''} ${artikel.kurzantwort}${f.frage || ''}
${artikel.faq_ueberschrift || 'Häufige Fragen'}
\\n${faqText}` : '',\n].filter(Boolean).join('\\n');\n\nconst praxis = Array.isArray(artikel.praxis) && artikel.praxis.length ? artikel.praxis\n : ((brief && brief.artikel && brief.artikel.praxis) || []);\n\nreturn [{ json: { slug: meta.slug, artikel, brief, brief_vorhanden: !!brief,\n bewertungs_html,\n stil_hinweise: stilpruefung({ ...artikel, praxis }),\n preis_warnung: preisTreffer.length\n ? `${preisTreffer.length} ausgeschriebene(r) Preis(e) im Text: ${[...new Set(preisTreffer)].slice(0,5).join(', ')}. `\n + 'Bitte durch [skrift_preis key=\"...\"] ersetzen.'\n : null,\n preis_shortcodes: shortcodes.length } }];\n"
+ "jsCode": "// Stilpruefung: findet typische Muster maschinell wirkender Texte im Deutschen.\n// Wird von gen_wf2.py in den Code-Node \"Artikel pruefen\" eingebettet und ist\n// lokal mit node testbar. Liefert Hinweise, blockiert nichts.\nfunction stilpruefung(artikel) {\n const hinweise = [];\n const add = (art, stelle) => hinweise.push({ art, stelle: String(stelle).slice(0, 140) });\n const ohneTags = (h) => String(h || '').replace(/<[^>]+>/g, ' ').replace(/ /g, ' ').replace(/\\s+/g, ' ').trim();\n\n const html = String(artikel.content_html || '');\n const absaetze = [...html.matchAll(/${f.frage || ''}
${artikel.titel}
` : '',\n artikel.kurzantwort ? `${artikel.faq_ueberschrift || 'Häufige Fragen'}
\\n${faqText}` : '',\n].filter(Boolean).join('\\n');\n\nconst praxis = Array.isArray(artikel.praxis) && artikel.praxis.length ? artikel.praxis\n : ((brief && brief.artikel && brief.artikel.praxis) || []);\n\nreturn [{ json: { slug: meta.slug, artikel, brief, brief_vorhanden: !!brief,\n bewertungs_html,\n stil_hinweise: stilpruefung({ ...artikel, praxis }),\n preis_warnung: preisTreffer.length\n ? `${preisTreffer.length} ausgeschriebene(r) Preis(e) im Text: ${[...new Set(preisTreffer)].slice(0,5).join(', ')}. `\n + 'Bitte durch [skrift_preis key=\"...\"] ersetzen.'\n : null,\n preis_shortcodes: shortcodes.length } }];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
@@ -362,7 +362,7 @@
1340,
420
],
- "id": "2a7b4374-a366-44f3-96b1-d33dc7378b2c",
+ "id": "f43fa611-de36-49c4-844b-7d127fbc5585",
"name": "Artikel pruefen"
},
{
@@ -392,7 +392,7 @@
1560,
420
],
- "id": "f163c0a3-181e-40c0-88a2-f2157042d415",
+ "id": "8baae2de-d269-4004-8a65-b56a3df52980",
"name": "Score ermitteln",
"credentials": {
"httpHeaderAuth": {
@@ -416,7 +416,7 @@
1560,
640
],
- "id": "4455414d-1ed4-48a3-921b-d10cafe23afd",
+ "id": "2345ad56-70bf-4e9e-95e5-078f32873908",
"name": "Fehler Score",
"onError": "continueRegularOutput"
},
@@ -431,7 +431,7 @@
1780,
420
],
- "id": "0fe1ca56-4b69-4504-aa55-87766e82d1e6",
+ "id": "bb5f3c85-3ce9-4ef6-9472-5c5d1041119a",
"name": "Score auswerten"
},
{
@@ -445,7 +445,7 @@
},
"conditions": [
{
- "id": "62fbfd27-c661-454c-b433-b5977f969e52",
+ "id": "d6bb630a-83c0-4ef6-b58f-b3f04c7e0420",
"leftValue": "={{ $json.bestanden }}",
"rightValue": "",
"operator": {
@@ -466,7 +466,7 @@
2000,
420
],
- "id": "ca4f34e1-f915-4fcf-91bd-6cbcc71abe77",
+ "id": "77d875da-9aa0-4e70-84e5-14f73ec2a275",
"name": "Score erreicht?"
},
{
@@ -480,7 +480,7 @@
2220,
640
],
- "id": "f598e1f9-a15a-4b34-a59d-5bdf15513402",
+ "id": "fead1ab1-34ed-476e-96b9-0fac9d7b6758",
"name": "Fehlende Begriffe ermitteln"
},
{
@@ -505,7 +505,7 @@
2440,
640
],
- "id": "2a20625a-a1b4-470a-a558-edf71e3985b8",
+ "id": "c8629336-a50d-4b58-9ae4-da4ebfcb22d0",
"name": "Nachbesserung vorhanden?",
"credentials": {
"httpHeaderAuth": {
@@ -525,7 +525,7 @@
2660,
640
],
- "id": "4413cca3-3996-40ff-88bc-90deceac60c9",
+ "id": "946d4b02-8c02-43eb-b6c9-1347691487a5",
"name": "Nachbesserung vorbereiten"
},
{
@@ -555,7 +555,7 @@
2880,
640
],
- "id": "7c6e53c5-fb96-4c18-811b-c6764804b3f9",
+ "id": "aeff7f66-195f-4434-92d9-ec9ddea02495",
"name": "Nachbesserung committen",
"credentials": {
"httpHeaderAuth": {
@@ -579,7 +579,7 @@
2880,
860
],
- "id": "24d265f2-7379-4dcc-af74-bd275c293ac1",
+ "id": "b868dae0-af73-442f-8962-f028ee5919ae",
"name": "Fehler Nachbesserung",
"onError": "continueRegularOutput"
},
@@ -594,7 +594,7 @@
3100,
640
],
- "id": "1bb8c4d3-91f7-4aa1-b0f3-ae176e5e4e3a",
+ "id": "cfb38044-2ef6-4a04-98d5-e3b100c1abe3",
"name": "Nachbesserung gemerkt"
},
{
@@ -624,7 +624,7 @@
2220,
240
],
- "id": "b1dd3437-1339-47a8-acf2-ac50a07e2fba",
+ "id": "87024225-d5c5-4f6e-8de0-2dc8c8779c18",
"name": "Revision zu NeuronWriter",
"credentials": {
"httpHeaderAuth": {
@@ -648,7 +648,7 @@
2220,
60
],
- "id": "41308b76-0798-4d3b-892f-bfa9a0c2331b",
+ "id": "477ca965-5538-4f95-ad0a-4f303a628ddf",
"name": "Fehler Revision",
"onError": "continueRegularOutput"
},
@@ -674,7 +674,7 @@
2440,
240
],
- "id": "92090059-6fd5-492b-b3d4-0f381ff24aa6",
+ "id": "d66ed8ec-6c8c-4341-b470-5481b84ea3b9",
"name": "Beitrag vorhanden?",
"credentials": {
"httpBasicAuth": {
@@ -708,7 +708,7 @@
2660,
240
],
- "id": "db39d451-3fae-476d-ac3f-e8a7a754c3af",
+ "id": "93bbd3d1-f4d2-4e3a-b725-b439c04a0743",
"name": "Kategorie suchen",
"credentials": {
"httpBasicAuth": {
@@ -731,7 +731,7 @@
2880,
240
],
- "id": "4574946a-3f6c-4616-9b39-ecc412802a93",
+ "id": "784c106d-1d45-4de5-9840-8e3d331c0a11",
"name": "Kategorie pruefen"
},
{
@@ -745,7 +745,7 @@
},
"conditions": [
{
- "id": "2cc73f4f-f7a9-4639-8e76-8a36e28e55ec",
+ "id": "ae40aca1-0466-4e7f-97b5-032b36d76c33",
"leftValue": "={{ $json.kategorie_fehlt }}",
"rightValue": "",
"operator": {
@@ -766,7 +766,7 @@
3100,
240
],
- "id": "54eda814-f0fa-4289-b85c-7d6bf1552894",
+ "id": "8fe4d39e-a88f-420c-a35a-27e3eb5fd3e1",
"name": "Kategorie anlegen?"
},
{
@@ -796,7 +796,7 @@
3320,
140
],
- "id": "97c45331-c51c-4500-9559-1531e5dd69fe",
+ "id": "be37bc13-b8a2-4a2c-ac3e-a253af1d5e05",
"name": "Kategorie anlegen",
"credentials": {
"httpBasicAuth": {
@@ -819,7 +819,7 @@
3540,
240
],
- "id": "8cca486f-9191-4afb-9022-69a95657cf25",
+ "id": "64489c08-1877-409d-b680-5884846fffc5",
"name": "Kategorie festlegen"
},
{
@@ -833,7 +833,7 @@
3760,
240
],
- "id": "64401c03-a0e6-493d-be07-7054964fa3d7",
+ "id": "5e619ffa-f0b4-4802-b01a-9c9cc0f30ef6",
"name": "WordPress-Body bauen"
},
{
@@ -863,7 +863,7 @@
3980,
240
],
- "id": "652a752f-aaf2-4169-bf1f-5e5c246b0575",
+ "id": "f2896d54-c081-4f82-b4c4-fa23a9a3c0fa",
"name": "Beitrag anlegen oder aktualisieren",
"credentials": {
"httpBasicAuth": {
@@ -886,7 +886,7 @@
4200,
240
],
- "id": "5c89708b-21a3-466b-a142-90ca5776cabb",
+ "id": "acab056e-56c5-4d45-adac-9ba7821cf345",
"name": "Ergebnis pruefen"
},
{
@@ -917,7 +917,7 @@
4420,
240
],
- "id": "617d82a6-7c93-42df-8aa3-5345ea5e5a11",
+ "id": "8fb3fedb-4f3e-46d8-a5e9-d7f0fa703a3a",
"name": "Cache leeren",
"credentials": {
"httpBasicAuth": {
@@ -937,7 +937,7 @@
4640,
240
],
- "id": "e930894f-0a23-4b6f-8672-539fddded17a",
+ "id": "432fbfc3-c81c-4974-94f6-1ebe160d37e1",
"name": "Importergebnis merken"
},
{
@@ -951,9 +951,9 @@
4860,
420
],
- "id": "b52ef44c-0a99-428f-ac87-6f23ad851dcc",
+ "id": "df9453e6-48aa-4a1c-8dc4-842593e4f330",
"name": "Pause Rate Limit",
- "webhookId": "601a717a-a791-4885-9ae4-6211c4042840"
+ "webhookId": "c29d13d4-053b-4e05-bc34-a62ab21808ba"
},
{
"parameters": {
@@ -966,7 +966,7 @@
},
"conditions": [
{
- "id": "3479c179-c254-4e07-bbe3-139c2232cb41",
+ "id": "095329b9-6759-4e7e-a325-e012f3ec8825",
"leftValue": "={{ $('Konfiguration').first().json.bild_aktiv === true && !Number($json.featured_media) }}",
"rightValue": "",
"operator": {
@@ -987,7 +987,7 @@
4860,
240
],
- "id": "ac9b1b62-9967-4bbf-b437-5b6d9d9c4f03",
+ "id": "65dbdf3c-cf02-4915-a03a-3f0fc0543356",
"name": "Beitragsbild fehlt?"
},
{
@@ -1012,7 +1012,7 @@
5080,
120
],
- "id": "fe7baabb-0017-4539-b367-78b55a7b59a4",
+ "id": "9d88551b-363e-4f2d-8ba2-ce5c7c702c8f",
"name": "Bilddaten laden",
"credentials": {
"httpHeaderAuth": {
@@ -1035,7 +1035,7 @@
5300,
120
],
- "id": "7b14c694-e412-4a82-ac54-3dc038492daa",
+ "id": "835c8714-a9bf-4036-8f08-2830f0b29d94",
"name": "Bildprompt bauen"
},
{
@@ -1049,7 +1049,7 @@
},
"conditions": [
{
- "id": "9cc14322-cbf9-4d63-8032-75f3a326e208",
+ "id": "c703bc15-3ff7-4b0f-9b6e-9141611aa975",
"leftValue": "={{ !!$json.bild_prompt }}",
"rightValue": "",
"operator": {
@@ -1070,7 +1070,7 @@
5520,
120
],
- "id": "ac5412be-fd49-4ae6-b727-54bb8a5e7b5b",
+ "id": "f1ab4c18-b561-4581-9b68-d8d3c9701651",
"name": "Bildprompt vorhanden?"
},
{
@@ -1100,7 +1100,7 @@
5740,
40
],
- "id": "f4a67217-eac5-4292-b48f-97dd852db890",
+ "id": "c406aa61-49c9-4561-857a-1c05ab21ed87",
"name": "Bild erzeugen",
"credentials": {
"httpHeaderAuth": {
@@ -1124,7 +1124,7 @@
5740,
260
],
- "id": "d0507f71-febb-4770-8879-289cd5db8bde",
+ "id": "87181190-d3f6-4fe6-b927-0817afdea28f",
"name": "Fehler Bild",
"onError": "continueRegularOutput"
},
@@ -1139,7 +1139,7 @@
5960,
40
],
- "id": "0a26c40e-f669-447c-9873-b4658a0caa75",
+ "id": "8bf6e26d-cd73-47df-b97a-128aba60626d",
"name": "Bild als Datei"
},
{
@@ -1174,7 +1174,7 @@
6180,
40
],
- "id": "1f93892d-ca03-480f-80d4-d3e9136ba6be",
+ "id": "7569c6db-d2e5-457e-b0aa-11c8d51356f3",
"name": "Bild in Mediathek",
"credentials": {
"httpBasicAuth": {
@@ -1208,7 +1208,7 @@
6400,
40
],
- "id": "df178293-f772-47db-bd70-5ebbbfecc99b",
+ "id": "7a9b4dd8-11b9-42fd-8852-17cf09d5e121",
"name": "Beitragsbild setzen",
"credentials": {
"httpBasicAuth": {
@@ -1231,7 +1231,7 @@
6620,
40
],
- "id": "7acb87e1-6d08-4068-86e1-148e66e30a15",
+ "id": "99577ca6-750d-4afa-accc-f85eb3fde9dc",
"name": "Bild gemerkt"
},
{
@@ -1245,7 +1245,7 @@
900,
80
],
- "id": "de688426-8e55-4f3e-8fa0-6b6c536a645e",
+ "id": "19abdb52-8b48-4363-b8d8-0b651f6a088b",
"name": "Ergebnisse sammeln"
},
{
@@ -1270,7 +1270,7 @@
1120,
80
],
- "id": "c4d40ae3-0c2a-4c85-afb2-8e35e3b7a910",
+ "id": "288fd94a-d9e4-49aa-a672-726d0dd6be20",
"name": "Statustabelle lesen",
"credentials": {
"httpHeaderAuth": {
@@ -1290,7 +1290,7 @@
1340,
80
],
- "id": "ef884157-2d8f-4108-8413-f8a44d30377c",
+ "id": "8c6ef018-eb58-4999-bfa0-b3375d23bb95",
"name": "Statustabelle fortschreiben"
},
{
@@ -1304,7 +1304,7 @@
},
"conditions": [
{
- "id": "88098264-cf81-4b80-8dd6-24e2b69ac9f6",
+ "id": "d80c40a3-8b68-4c25-96ba-ec948933abec",
"leftValue": "={{ $json.ueberspringen }}",
"rightValue": "",
"operator": {
@@ -1325,7 +1325,7 @@
1560,
80
],
- "id": "680f0cda-2253-4542-a268-b5789d36e3ba",
+ "id": "6be07c39-1d90-4d70-a44c-449e3e6fc7b9",
"name": "Gab es Importe?"
},
{
@@ -1355,7 +1355,7 @@
1780,
160
],
- "id": "e3c52d54-c52c-4afb-ba79-4de6fcbe6668",
+ "id": "e7dcf291-a4ea-4dca-b213-839c7d3abf17",
"name": "Statustabelle schreiben",
"credentials": {
"httpHeaderAuth": {
@@ -1379,7 +1379,7 @@
1780,
340
],
- "id": "fe8b8aca-18cb-4111-858f-61863c8b411f",
+ "id": "8677d1e3-66eb-4559-b330-f0eff8a23601",
"name": "Fehler Statustabelle",
"onError": "continueRegularOutput"
},
@@ -1394,7 +1394,7 @@
2000,
80
],
- "id": "557665ff-7190-485b-bbba-b001c50d04bf",
+ "id": "ea4f12d3-9039-4892-94a8-035d911aff47",
"name": "Meldung formulieren"
},
{
@@ -1412,7 +1412,7 @@
2220,
80
],
- "id": "0d7c548b-73ac-49a6-a2cd-0c4791507058",
+ "id": "a895dc43-e8cf-4f82-af63-da713ae5a603",
"name": "Benachrichtigung",
"disabled": true,
"notes": "SMTP-Credential zuweisen, Absender eintragen, dann aktivieren."