From b8d3a6092a178d2c645c33b23e09bc4d39bf761a Mon Sep 17 00:00:00 2001 From: jbergner Date: Fri, 24 Jul 2026 07:31:19 +0200 Subject: [PATCH] OV --- .env.example | 8 +- CHANGELOG.md | 22 -- Makefile | 4 - README.md | 63 +--- bulkweb/static/bulk.css | 7 - bulkweb/static/bulk.js | 552 ---------------------------------- bulkweb/templates/index.html | 249 --------------- compose.yaml | 58 +--- deploy/kubernetes.yaml | 4 - deploy/swarm-stack.yaml | 4 - docs/BACKGROUND-PAGE.md | 4 - docs/EU-AI-ACT-COMPLIANCE.md | 231 -------------- docs/LEGAL-AND-SECURITY.md | 149 --------- docs/LICENSE-CLIENT.md | 4 - docs/LICENSE-INTEGRATION.md | 4 - internal/app/licensing.go | 8 - internal/app/server.go | 104 ------- internal/app/server_test.go | 67 ----- internal/badge/render.go | 144 --------- internal/badge/render_test.go | 108 ------- internal/bulk/server.go | 279 ----------------- internal/bulk/server_test.go | 159 ---------- internal/i18n/catalog.go | 285 ------------------ internal/marketing/content.go | 11 - openapi.yaml | 25 -- web/static/app.js | 126 +------- web/static/style.css | 21 -- web/templates/background.html | 4 - web/templates/index.html | 14 +- web/templates/marketing.html | 4 - 30 files changed, 7 insertions(+), 2715 deletions(-) delete mode 100644 bulkweb/static/bulk.css delete mode 100644 bulkweb/static/bulk.js delete mode 100644 bulkweb/templates/index.html delete mode 100644 docs/EU-AI-ACT-COMPLIANCE.md delete mode 100644 docs/LEGAL-AND-SECURITY.md delete mode 100644 internal/bulk/server.go delete mode 100644 internal/bulk/server_test.go diff --git a/.env.example b/.env.example index 600c206..c285afd 100644 --- a/.env.example +++ b/.env.example @@ -1,13 +1,9 @@ BASE_URL=http://localhost:8080 OUTPUT_BASE_URL=http://localhost:8080 PUBLIC_NAME=AI Usage Disclosure -CONTACT_URL=https://ai.trustednet.eu +CONTACT_URL=https://b1tsblog.org/page/ai DEFAULT_LANGUAGE=de -<<<<<<< HEAD TRUST_PROXY=false -======= -BULK_URL=http://localhost:8088 ->>>>>>> ec58fc30f840ce85ea06eb3d07457640a84f941c # Runtime mode: full (UI + API), api (API without public product/generator pages), bulk. SERVICE_MODE=full @@ -17,7 +13,7 @@ API_ALLOWED_ORIGIN=* # No private keys or configurable public keys belong in this application. LICENSE_TOKEN= LICENSE_MODE=offline -LICENSE_SERVER_URL=https://license.trustednet.eu +LICENSE_SERVER_URL= LICENSE_INSTANCE_ID= LICENSE_CACHE_FILE=/data/license-lease.json LICENSE_REFRESH_INTERVAL=15m diff --git a/CHANGELOG.md b/CHANGELOG.md index 21bcb58..8f89172 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,28 +1,6 @@ # Changelog -<<<<<<< HEAD ## 2.0.0 -======= -## 1.8.2 - 2026-07-23 - -- Fixed the Bulk results view so it previews the same accessible badge-plus-visible-text disclosure used by the recommended `embedHtml` export. -- Renamed the raw badge link to `SVG (nur Grafik)` to make clear that the standalone SVG is only the visual asset and not the recommended first-exposure integration. -- Kept Bulk HTML exports unchanged on `embedHtml`; this release fixes the misleading preview/link presentation rather than introducing a second rendering path. - -## 1.8.1 - 2026-07-23 - -- Added an accessible first-exposure embed with visible link text next to the SVG badge instead of relying on SVG/`alt` information alone. -- Added `accessibleText` and `embedHtml` to `GET /v1/render`; `embedHtml` combines the visible disclosure and inline JSON-LD in one copy/paste artifact. -- The normal generator now renders HTML/Markdown/JSON-LD through the core render endpoint and copies the complete HTML + JSON-LD embed by default. -- Bulk HTML exports now use `embedHtml`, so each subject receives visible disclosure markup and JSON-LD in one step. -- Flat SVG badges automatically choose black or white text per segment for at least 4.5:1 contrast; the old overlay gradient was removed so the computed contrast remains deterministic. -- Emoji/icon badges enforce at least 3:1 foreground/background contrast by falling back to black or white when a custom colour pair is insufficient; the generator shows a corresponding warning. -- Increased the recommended linked disclosure target to at least 36 CSS pixels high and added a visible text label in the generator preview. -- Adopted the supplied registry deployment: `compose.yaml` now uses `git.send.nrw/sendnrw/ai-disclosure-standard:latest` and `:bulk-latest`, and `.gitea/workflows/registry-bulk.yml` builds the separate bulk tags. -- Removed the superseded GHCR bulk workflow to avoid competing release pipelines. - -## 1.8.0 - 2026-07-22 ->>>>>>> ec58fc30f840ce85ea06eb3d07457640a84f941c ### Article 50 decision support diff --git a/Makefile b/Makefile index 7a7d9d9..157364a 100644 --- a/Makefile +++ b/Makefile @@ -23,11 +23,7 @@ build: CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o bin/ai-disclosure ./cmd/server docker-build: -<<<<<<< HEAD docker build --build-arg VERSION=$(VERSION) -t ai-disclosure-standard:$(VERSION)-local . -======= - docker build -t ai-disclosure-standard:1.8.2-local . ->>>>>>> ec58fc30f840ce85ea06eb3d07457640a84f941c docker-build-bulk: docker build -f Dockerfile.bulk --build-arg VERSION=$(VERSION) -t ai-disclosure-standard-bulk:$(VERSION)-local . diff --git a/README.md b/README.md index 198d145..cdcf6ef 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,14 @@ -<<<<<<< HEAD # AI Disclosure Standard 2.0.0 -======= -# AI Disclosure Standard 1.8.2 ->>>>>>> ec58fc30f840ce85ea06eb3d07457640a84f941c Ein mehrsprachiger, selbst hostbarer Go-Dienst für sichtbare und maschinenlesbare Erklärungen zur KI-Nutzung in Artikeln, Webseiten und einzelnen Inhaltsbestandteilen. Die Community-Basis bleibt offen und ohne Plattformzwang nutzbar. Für professionelle Betreiber stehen zusätzlich lizenzierbare Laufzeitfunktionen wie eigene Darstellung, Bulk-Verarbeitung, Export-Bundles und White-Label-Betrieb zur Verfügung. Lizenzen werden ausschließlich durch die separat betriebene **Universal License Platform** ausgestellt. -<<<<<<< HEAD ## Funktionsumfang ### Offener Kern - Einzeldeklarationen und zusammengefasste Artikel-/Webseiten-Deklarationen; -======= -- einzelne Deklarationen und zusammengefasste Artikel-/Webseiten-Deklarationen; -- SVG-Badges, sichtbarer barrierearmer HTML-Hinweis und JSON-LD unter einem gemeinsamen Link; -- empfohlener Ein-Schritt-Embed: sichtbarer Hinweis + dekoratives SVG + inline JSON-LD in einem HTML-Snippet; ->>>>>>> ec58fc30f840ce85ea06eb3d07457640a84f941c - Text, Titelbild, weitere Bilder, Recherche, Übersetzung, Audio, Video und Code getrennt erfassbar; - SVG-Badges, HTML-Erklärung und JSON-LD aus derselben Deklaration; - automatisch erzeugte Fließtext-Zusammenfassung und sauber gerasterte Tabellenansicht; @@ -86,51 +76,22 @@ go run .\cmd\server Danach: ```text -<<<<<<< HEAD Generator: http://localhost:8080/ Produktseite: http://localhost:8080/product Hintergrund: http://localhost:8080/background Capabilities: http://localhost:8080/v1/capabilities Health: http://localhost:8080/healthz Readiness: http://localhost:8080/readyz -======= -Generator: http://localhost:8080/ -Produktseite: http://localhost:8080/product -Hintergrund: http://localhost:8080/background -Impressum: http://localhost:8080/impressum -Datenschutz: http://localhost:8080/datenschutz -Barrierefrei: http://localhost:8080/barrierefreiheit -Healthcheck: http://localhost:8080/healthz -Funktionen: http://localhost:8080/v1/capabilities -Bulk (Compose-Port): http://localhost:8088/ ->>>>>>> ec58fc30f840ce85ea06eb3d07457640a84f941c ``` Go lädt `.env` beim direkten Start nicht automatisch. Docker Compose kann sie explizit verwenden: ```powershell Copy-Item .env.example .env -docker compose --env-file .env pull -docker compose --env-file .env up -d +docker compose --env-file .env up -d --build ``` -<<<<<<< HEAD ## Betriebsmodi -======= -Die bereitgestellte `compose.yaml` verwendet die Registry-Images `git.send.nrw/sendnrw/ai-disclosure-standard:latest` und `:bulk-latest`, bindet beide Dienste an das externe Netzwerk `proxy` und veröffentlicht den Bulk-Dienst zusätzlich auf Host-Port `8088`. Das Netzwerk `proxy` muss vor dem Start bereits existieren. - - -## Gitea Actions: Bulk-Image - -Der Workflow `.gitea/workflows/registry-bulk.yml` baut `Dockerfile.bulk` unabhängig vom Hauptimage und veröffentlicht in der konfigurierten Registry unter anderem: - -```text -git.send.nrw/sendnrw/:bulk-latest -git.send.nrw/sendnrw/:bulk- -``` - -Er verwendet dieselbe Registry- und Secret-Konfiguration wie der vorhandene Hauptimage-Workflow (`DOCKER_USERNAME` / `DOCKER_PASSWORD`). ->>>>>>> ec58fc30f840ce85ea06eb3d07457640a84f941c `SERVICE_MODE` trennt öffentliche Oberfläche und Server-to-Server-Betrieb: @@ -142,42 +103,20 @@ Er verwendet dieselbe Registry- und Secret-Konfiguration wie der vorhandene Haup Der dedizierte Bulk-Container setzt bereits: -<<<<<<< HEAD ```text SERVICE_MODE=bulk REQUIRE_LICENSE=true BULK_REQUIRE_API_KEY=true API_ALLOWED_ORIGIN= ``` -======= -1. Kennzeichnung im normalen Generator konfigurieren. -2. **Als Bulk-Vorlage öffnen** auswählen. -3. Optional ein Website-Profil mit wiederkehrenden Angaben wie Autor, Impressums-/Verantwortlichkeits-URL und Beschwerdestelle im Browser speichern. -4. Absolute URLs oder relative Pfade einfügen. Für relative Pfade kann einmalig eine Basis-URL gesetzt werden. -5. Das komplette HTML (sichtbarer Hinweis + JSON-LD), Markdown, separates JSON-LD, JSONL oder CSV erzeugen und kopieren bzw. herunterladen. - -Der HTML-Export verwendet standardmäßig `embedHtml` aus dem Core: Das SVG ist dekorativ (`alt=""`), der Link enthält unmittelbar sichtbaren Text und hat ein größeres Klickziel; direkt danach folgt das JSON-LD als ` - - -{{end}} diff --git a/compose.yaml b/compose.yaml index 835d1ca..10d99e5 100644 --- a/compose.yaml +++ b/compose.yaml @@ -1,6 +1,5 @@ services: app: -<<<<<<< HEAD build: context: . dockerfile: Dockerfile @@ -30,12 +29,6 @@ services: BULK_API_KEY: "${BULK_API_KEY:-}" ports: - "8080:8080" -======= - image: git.send.nrw/sendnrw/ai-disclosure-standard:latest - container_name: ai - env_file: - - .env ->>>>>>> ec58fc30f840ce85ea06eb3d07457640a84f941c volumes: - license-cache:/data read_only: true @@ -47,58 +40,11 @@ services: - ALL restart: unless-stopped healthcheck: - test: - - CMD - - /ai-disclosure - - --healthcheck + test: ["CMD", "/ai-disclosure", "--healthcheck"] interval: 15s timeout: 3s retries: 3 start_period: 5s -<<<<<<< HEAD -======= - networks: - - proxy - bulk: - image: git.send.nrw/sendnrw/ai-disclosure-standard:bulk-latest - container_name: ai-bulk - env_file: - - .env - environment: - CORE_INTERNAL_URL: http://app:8080 - DISCLOSURE_BASE_URL: ${BASE_URL:-http://localhost:8080} - GENERATOR_URL: ${BASE_URL:-http://localhost:8080} - BULK_PUBLIC_NAME: ${PUBLIC_NAME:-AI Disclosure Bulk} - BULK_MAX_URLS: ${BULK_MAX_URLS:-500} - BULK_WORKERS: ${BULK_WORKERS:-4} - ports: - - 8088:8081 - read_only: true - tmpfs: - - /tmp:size=8m,mode=1777 - security_opt: - - no-new-privileges:true - cap_drop: - - ALL - depends_on: - app: - condition: service_healthy - restart: unless-stopped - healthcheck: - test: - - CMD - - /ai-disclosure-bulk - - --healthcheck - interval: 15s - timeout: 3s - retries: 3 - start_period: 5s - networks: - - proxy ->>>>>>> ec58fc30f840ce85ea06eb3d07457640a84f941c volumes: - license-cache: null -networks: - proxy: - external: true + license-cache: diff --git a/deploy/kubernetes.yaml b/deploy/kubernetes.yaml index 3e5687a..fbed20e 100644 --- a/deploy/kubernetes.yaml +++ b/deploy/kubernetes.yaml @@ -32,11 +32,7 @@ spec: type: RuntimeDefault containers: - name: app -<<<<<<< HEAD image: ghcr.io/REPLACE_ME/ai-disclosure-standard:2.0.0 -======= - image: ghcr.io/REPLACE_ME/ai-disclosure-standard:1.8.2 ->>>>>>> ec58fc30f840ce85ea06eb3d07457640a84f941c imagePullPolicy: IfNotPresent ports: - name: http diff --git a/deploy/swarm-stack.yaml b/deploy/swarm-stack.yaml index cb5eb2d..221652f 100644 --- a/deploy/swarm-stack.yaml +++ b/deploy/swarm-stack.yaml @@ -1,11 +1,7 @@ version: "3.9" services: app: -<<<<<<< HEAD image: ghcr.io/REPLACE_ME/ai-disclosure-standard:2.0.0 -======= - image: ghcr.io/REPLACE_ME/ai-disclosure-standard:1.8.2 ->>>>>>> ec58fc30f840ce85ea06eb3d07457640a84f941c environment: BASE_URL: https://ai.example.org PUBLIC_NAME: AI Usage Disclosure diff --git a/docs/BACKGROUND-PAGE.md b/docs/BACKGROUND-PAGE.md index 5b9fcf5..f72abc3 100644 --- a/docs/BACKGROUND-PAGE.md +++ b/docs/BACKGROUND-PAGE.md @@ -1,10 +1,6 @@ # Mehrsprachige Hintergrundseite -<<<<<<< HEAD Version 2.0.0 stellt unter `/background` eine eigenständige Informationsseite zur KI-Kennzeichnung und zu Artikel 50 des EU AI Act bereit. -======= -Version 1.8.2 stellt unter `/background` eine eigenständige Informationsseite zur KI-Kennzeichnung und zu Artikel 50 des EU AI Act bereit. ->>>>>>> ec58fc30f840ce85ea06eb3d07457640a84f941c ## Routen diff --git a/docs/EU-AI-ACT-COMPLIANCE.md b/docs/EU-AI-ACT-COMPLIANCE.md deleted file mode 100644 index 5159bb5..0000000 --- a/docs/EU-AI-ACT-COMPLIANCE.md +++ /dev/null @@ -1,231 +0,0 @@ -# EU AI Act: Compliance-Grenzen und Betreiber-Checkliste - -**Rechtsstand: 22. Juli 2026** - -Diese Datei beschreibt, welche Teile des EU AI Act (Verordnung (EU) 2024/1689) dieses Projekt technisch unterstützen kann und welche Pflichten außerhalb seines Funktionsumfangs liegen. Sie ersetzt keine Prüfung des konkreten Einsatzes. - -## 1. Was dieses Projekt ist - -Die mitgelieferte Anwendung erzeugt deterministisch SVG-Hinweise, Erklärungsseiten und JSON-LD aus den vom Nutzer eingegebenen Angaben. Sie enthält selbst kein KI-Modell und führt keine Modellinferenz aus. - -Der AI Act erfasst nur Systeme, die unter die Definition eines „AI system“ in Artikel 3 Absatz 1 fallen. Ob eine konkrete, veränderte oder erweiterte Installation diese Definition erfüllt, ist anhand der tatsächlichen technischen Funktion zu prüfen. - -Offizielle Quelle: - -- https://ai-act-service-desk.ec.europa.eu/en/ai-act/article-3 - -## 2. Dieses Projekt ist keine vollständige AI-Act-Compliance-Lösung - -Der Generator unterstützt vor allem die **sichtbare und dokumentierte Offenlegung von KI-Nutzung**. Er kann insbesondere bei freiwilliger Transparenz und bei bestimmten Betreiberpflichten aus Artikel 50 Absatz 4 helfen. - -Er erfüllt oder prüft **nicht automatisch**: - -- die Anbieterpflicht zur technischen, maschinenlesbaren Markierung von generierten oder manipulierten Ausgaben nach Artikel 50 Absatz 2; -- die Transparenzpflicht bei direkter Mensch-KI-Interaktion nach Artikel 50 Absatz 1; -- Informationspflichten bei Emotionserkennung oder biometrischer Kategorisierung nach Artikel 50 Absatz 3; -- die Pflicht zur AI Literacy nach Artikel 4; -- Verbote nach Artikel 5; -- die Einstufung und Pflichten für Hochrisiko-KI nach Kapitel III; -- Pflichten für Anbieter von General-Purpose-AI-Modellen nach Kapitel V; -- sonstige Pflichten aus Datenschutz-, Urheber-, Verbraucher-, Medien- oder Produktsicherheitsrecht. - -## 3. Artikel 50: sichtbare Offenlegung durch Betreiber - -Artikel 50 gilt ab **2. August 2026**. Betreiber bestimmter generativer KI-Systeme müssen insbesondere Deepfakes und bestimmte KI-generierte oder manipulierte Texte zu Angelegenheiten von öffentlichem Interesse offenlegen. - -Für solche sichtbaren Offenlegungen gilt nach Artikel 50 Absatz 5 und den Leitlinien der Kommission insbesondere: - -1. Der Hinweis muss **klar und unterscheidbar** sein. -2. Er muss **spätestens bei der ersten Exposition** gegenüber der betroffenen natürlichen Person erscheinen. -3. Er muss die geltenden Anforderungen an **Barrierefreiheit** berücksichtigen. -4. Bei Deepfakes genügt eine nur maschinenlesbare Markierung des Anbieters nicht als sichtbare Betreiber-Offenlegung. - -Daher gilt für die Einbettung dieses Projekts: - -- den empfohlenen `embedHtml`-Baustein oder eine gleichwertige Umsetzung unmittelbar am betroffenen Inhalt platzieren; -- nicht ausschließlich im Footer, Impressum oder auf einer erst später erreichbaren Unterseite; -- sichtbaren, verständlichen Text als Bestandteil des Links bereitstellen, damit die Offenlegung nicht nur über eine Grafik wahrnehmbar ist; -- das Badge im empfohlenen Embed mit `alt=""`/`aria-hidden="true"` dekorativ behandeln, weil derselbe Bedeutungsgehalt bereits als sichtbarer Linktext vorhanden ist und sonst doppelt angesagt würde; -- bei einer alleinstehenden Badge-Grafik weiterhin einen aussagekräftigen Alternativtext bereitstellen; -- ausreichende Kontraste und ein ausreichend großes, tastaturerreichbares Linkziel sicherstellen. Der mitgelieferte Renderer wählt bei flachen Badges automatisch Schwarz/Weiß für mindestens 4,5:1 Textkontrast und korrigiert Emoji-/Icon-Farben unter 3:1. - -Offizielle Quellen: - -- https://ai-act-service-desk.ec.europa.eu/en/ai-act/article-50 -- https://digital-strategy.ec.europa.eu/en/faqs/transparency-obligations-under-article-50-ai-act -- https://digital-strategy.ec.europa.eu/en/policies/guidelines-transparency-ai-generated-content - -## 4. Menschliche Prüfung und redaktionelle Kontrolle - -Für bestimmte veröffentlichte KI-generierte oder manipulierte Texte zu Angelegenheiten von öffentlichem Interesse kann die Kennzeichnungspflicht nach Artikel 50 Absatz 4 entfallen, wenn die gesetzlichen Voraussetzungen tatsächlich erfüllt sind. - -Die Kommission stellt klar: - -- „human review“ erfordert eine bewusste inhaltliche Prüfung durch Personen mit einschlägigem Wissen und professionellem Urteil; -- „editorial control“ setzt tatsächliche inhaltliche Entscheidungsbefugnis voraus, also insbesondere die Möglichkeit, Inhalte aus sachlichen Gründen zu genehmigen, zu ändern oder abzulehnen; -- rein oberflächliche, formale oder prozedurale Prüfungen wie Rechtschreib- oder Grammatikprüfung genügen nicht; -- zusätzlich muss eine natürliche oder juristische Person die redaktionelle Verantwortung für die Veröffentlichung tragen. - -Aus diesem Grund setzt der Generator seit dieser Härtung **keine menschliche oder redaktionelle Prüfung mehr automatisch voraus**. Der Nutzer muss den tatsächlich durchgeführten Prozess ausdrücklich auswählen. - -Die Felder `editorialResponsibility.role`, `editorialResponsibility.name` und `editorialResponsibility.url` dienen nur der Dokumentation. Der Generator berücksichtigt eine mögliche Ausnahme nur, wenn mindestens Rolle und verantwortliche Person/Organisation ausdrücklich angegeben sind. Auch diese Dokumentation beweist nicht automatisch, dass die gesetzlichen Voraussetzungen tatsächlich vorliegen. - -**Autor/Byline und redaktionelle Verantwortung sind getrennt.** `author` beschreibt die Urheberschaft bzw. Veröffentlichungs-Byline. `editorialResponsibility` beschreibt dagegen diejenige natürliche oder juristische Person, die letztlich die rechtliche redaktionelle Verantwortung für die Veröffentlichung trägt. Beides kann zusammenfallen, muss es aber nicht. - -## 5. Besondere Ausnahme für gesetzlich autorisierte Strafverfolgungsnutzung - -Artikel 50 Absatz 4 enthält für Deepfakes und Public-Interest-Texte eine besondere Ausnahme, soweit die konkrete Nutzung **gesetzlich zur Aufdeckung, Verhütung, Ermittlung oder Verfolgung von Straftaten autorisiert** ist. - -Schema 1.3 kann diese Selbsteinordnung in `legalContext.lawEnforcementAuthorization` (`yes`, `no`, `unsure`) dokumentieren. Das Feld erscheint im Generator nur, wenn zuvor eine Deepfake- oder Public-Interest-Konstellation ausgewählt wurde. Ein bloßer Behördenstatus genügt nicht als Grundlage für „yes“; die konkrete gesetzliche Autorisierung des konkreten Einsatzes sollte intern nachvollziehbar dokumentiert sein. Bei `unsure` warnt der Generator davor, die Ausnahme ohne weitere Prüfung zugrunde zu legen. - -Offizielle Quelle: - -- https://ai-act-service-desk.ec.europa.eu/en/ai-act/article-50 - -## 6. Beschwerde-/Rückmeldestelle: Best Practice, nicht Art.-50-Pflicht - -Eine eigene interne Beschwerde- oder Rückmeldestelle für jeden gekennzeichneten Inhalt ist **keine allgemeine Pflicht aus Artikel 50**. Das Projekt bietet `complaintsContact` deshalb ausdrücklich als Best-Practice-Metadatum an und trennt es von rechtlich erforderlichen Feldern. - -Daneben enthält der AI Act in Artikel 85 ein eigenständiges Recht, bei einer Marktüberwachungsbehörde Beschwerde über einen Verstoß gegen den AI Act einzulegen. Eine freiwillige interne Anlaufstelle des Publishers ersetzt dieses gesetzliche Beschwerderecht nicht. Zusätzlich können Medien-, Verbraucher-, Plattform-, Datenschutz- oder andere Fachregeln eigene Kontakt- oder Beschwerdepflichten begründen. - -Offizielle Quellen: - -- https://ai-act-service-desk.ec.europa.eu/en/ai-act/article-85 -- https://ai-act-service-desk.ec.europa.eu/en/ai-act/article-50 - -## 7. Mögliche Konsequenzen bei Verstößen gegen Artikel 50 - -Artikel 99 Absatz 4 ordnet Verstöße gegen die Transparenzpflichten des Artikels 50 grundsätzlich einem Bußgeldrahmen von **bis zu 15 Mio. EUR** oder – bei Unternehmen – **bis zu 3 % des weltweiten Jahresgesamtumsatzes des vorangegangenen Geschäftsjahres** zu. Für KMU einschließlich Start-ups enthält Artikel 99 Absatz 6 eine besondere Deckelungsregel; außerdem müssen Art, Schwere, Dauer, Verantwortungsgrad und weitere Umstände des Einzelfalls berücksichtigt werden. - -Der Generator zeigt diesen Rahmen als Risikohinweis, aber **nicht als Prognose einer konkreten Geldbuße**. Ob ein Verstoß vorliegt, welche Maßnahmen angemessen sind und ob bzw. in welcher Höhe eine Geldbuße verhängt wird, ist Sache der zuständigen Behörden bzw. Gerichte. - -Offizielle Quelle: - -- https://ai-act-service-desk.ec.europa.eu/en/ai-act/article-99 - -## 8. Artikel 50 Absatz 2: JSON-LD ist kein Ersatz für Provider-Marking - -Anbieter generativer KI-Systeme müssen in den erfassten Fällen dafür sorgen, dass generierte oder manipulierte Inhalte maschinenlesbar markiert und als künstlich generiert oder manipuliert erkennbar sind. Nach Artikel 50 Absatz 2 müssen die technischen Lösungen wirksam, interoperabel, robust und zuverlässig sein, soweit dies technisch machbar ist. - -Artikel 50 Absatz 2 nimmt Systeme aus, die lediglich Standard-Bearbeitungsfunktionen ausführen oder die vom Betreiber bereitgestellten Eingabedaten bzw. deren Semantik nicht wesentlich verändern. Ob diese Ausnahme tatsächlich greift, hängt von der konkreten Funktion und Veränderungswirkung ab; der sichtbare Generator kann diese technische Anbieterfrage nicht automatisch entscheiden. - -Das von diesem Projekt erzeugte **JSON-LD ist ergänzende Dokumentation**. Es ist nicht als Ersatz für die technische Markierung gedacht, die der Anbieter des generativen KI-Systems in oder an der Ausgabe implementieren muss. Der Endpunkt `/v1/render` kann es über `embedHtml` direkt zusammen mit der sichtbaren Offenlegung als `" - - w.Header().Set("Content-Type", "application/json; charset=utf-8") - w.Header().Set("Cache-Control", "no-store") - _ = json.NewEncoder(w).Encode(renderedArtifacts{ - Subject: d.Subject, DeclarationURL: declarationURL, BadgeURL: badgeURL, ManifestURL: manifestURL, AccessibleText: accessibleText, - HTML: htmlMarkup, EmbedHTML: embedMarkup, Markdown: markdown, JSONLD: d, - }) -} - -func renderBadgeAlt(q url.Values, d declaration.Declaration, locale i18n.Locale, assessment legalAssessment) string { - if assessment.RequiresDisclosure && assessment.BadgeMessage != "" { - return assessment.BadgeMessage - } - if q.Get("mode") == "article" || len(d.Components) > 1 { - if value := locale.Text["badge_article"]; value != "" { - return value - } - } - if preset, ok := locale.Presets[q.Get("preset")]; ok && preset.Title != "" { - return preset.Title - } - for _, component := range d.Components { - if value := locale.Extents[component.AIExtent]; value != "" { - return value - } - } - return "AI usage disclosure" -} - -func markdownAlt(value string) string { - value = strings.ReplaceAll(value, `\`, `\\`) - value = strings.ReplaceAll(value, `]`, `\]`) - return strings.ReplaceAll(value, `[`, `\[`) -} - -func markdownText(value string) string { - for _, marker := range []string{"\\", "*", "_", "`", "[", "]"} { - value = strings.ReplaceAll(value, marker, "\\"+marker) - } - return value -} - ->>>>>>> ec58fc30f840ce85ea06eb3d07457640a84f941c func (s *Server) declarationFromQuery(q url.Values) (declaration.Declaration, error) { return declaration.NewFromQueryWithOptions(q, s.cfg.BaseURL+"/context/v1", declaration.ParseOptions{ AllowCustomText: s.licenses.Has(FeatureCustomText), AllowCustomBadge: s.licenses.Has(FeatureCustomBadge), DefaultLanguage: s.cfg.DefaultLanguage, diff --git a/internal/app/server_test.go b/internal/app/server_test.go index a4ee24d..b9f328f 100644 --- a/internal/app/server_test.go +++ b/internal/app/server_test.go @@ -395,74 +395,7 @@ func TestRequireLicenseFailsClosedForApplicationRequests(t *testing.T) { } } -<<<<<<< HEAD r := httptest.NewRequest(http.MethodGet, "/healthz", nil) -======= -func TestUnclearDeepfakeAssessmentUsesCautiousDisclosureGuidance(t *testing.T) { - r := httptest.NewRequest(http.MethodGet, "/declaration?mode=article&imageExtent=full&imageReview=none&deepfakeAssessment=unsure&legalRole=deployer&useContext=professional&lawEnforcementAuthorization=no&lang=de", nil) - w := httptest.NewRecorder() - testHandler(t).ServeHTTP(w, r) - if w.Code != http.StatusOK { - t.Fatalf("status %d: %s", w.Code, w.Body.String()) - } - body := w.Body.String() - for _, expected := range []string{"Deepfake-Einordnung", "Unklar / muss geprüft werden", "kann anhand der Angaben nicht ausgeschlossen werden"} { - if !strings.Contains(body, expected) { - t.Fatalf("unclear deepfake guidance missing %q: %s", expected, body) - } - } -} - -func TestRenderEndpointReturnsReusableArtifacts(t *testing.T) { - r := httptest.NewRequest(http.MethodGet, "/v1/render?component=text&extent=partial&review=editorial&lang=de&subject=https%3A%2F%2Fcontent.example%2Farticle&theme=mono", nil) - w := httptest.NewRecorder() - testHandler(t).ServeHTTP(w, r) - if w.Code != http.StatusOK { - t.Fatalf("status %d: %s", w.Code, w.Body.String()) - } - var payload struct { - Subject string `json:"subject"` - DeclarationURL string `json:"declarationUrl"` - BadgeURL string `json:"badgeUrl"` - ManifestURL string `json:"manifestUrl"` - AccessibleText string `json:"accessibleText"` - HTML string `json:"html"` - EmbedHTML string `json:"embedHtml"` - Markdown string `json:"markdown"` - JSONLD map[string]any `json:"jsonLd"` - } - if err := json.Unmarshal(w.Body.Bytes(), &payload); err != nil { - t.Fatal(err) - } - if payload.Subject != "https://content.example/article" { - t.Fatalf("subject %q", payload.Subject) - } - for name, value := range map[string]string{"declaration": payload.DeclarationURL, "badge": payload.BadgeURL, "manifest": payload.ManifestURL, "accessibleText": payload.AccessibleText, "html": payload.HTML, "embedHtml": payload.EmbedHTML, "markdown": payload.Markdown} { - if value == "" { - t.Fatalf("%s is empty", name) - } - } - if got, _ := payload.JSONLD["subject"].(string); got != payload.Subject { - t.Fatalf("jsonLd subject %q", got) - } - if strings.Contains(payload.DeclarationURL, "theme=") { - t.Fatalf("theme leaked into declaration URL: %s", payload.DeclarationURL) - } - if !strings.Contains(payload.BadgeURL, "theme=mono") { - t.Fatalf("badge URL missing theme: %s", payload.BadgeURL) - } - if !strings.Contains(payload.HTML, `alt="" aria-hidden="true"`) || !strings.Contains(payload.HTML, "Details zur KI-Nutzung") { - t.Fatalf("accessible visible disclosure missing: %s", payload.HTML) - } - if !strings.Contains(payload.EmbedHTML, ` diff --git a/web/templates/index.html b/web/templates/index.html index c74dace..b3365a5 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -130,25 +130,18 @@ - {{if .CustomBadge}}{{end}} {{end}}

{{index .Text "preview"}}

- + {{index .Text
-<<<<<<< HEAD -======= - - - ->>>>>>> ec58fc30f840ce85ea06eb3d07457640a84f941c
@@ -160,13 +153,8 @@

HA

{{index .Text "api_stateless_title"}}

{{index .Text "api_stateless_desc"}}

-<<<<<<< HEAD
{{if not .WhiteLabel}}AI Usage Disclosure · {{end}}App 2.0.0 · Schema 1.2 · {{.License.Edition}}{{index .Text "footer_no_legal"}}
-======= -
AI Usage Disclosure · App 1.8.2 · Schema 1.3 · {{.License.Edition}}{{template "legal-links" .}}
- ->>>>>>> ec58fc30f840ce85ea06eb3d07457640a84f941c diff --git a/web/templates/marketing.html b/web/templates/marketing.html index d1d5433..02c9f5c 100644 --- a/web/templates/marketing.html +++ b/web/templates/marketing.html @@ -119,11 +119,7 @@ -<<<<<<< HEAD
{{if not .WhiteLabel}}{{.Marketing.Footer}}{{end}}App 2.0.0 · Schema 1.2 · {{.License.Edition}}
-======= -
{{.Marketing.Footer}} · App 1.8.2 · Schema 1.3 · {{.License.Edition}}{{template "legal-links" .}}
->>>>>>> ec58fc30f840ce85ea06eb3d07457640a84f941c