freema/perspective-api-bundle
Symfony bundle for Google's Perspective API that scores text for toxicity and abusive language. Gives moderators a simple service to check comments and user-generated content, with configurable thresholds for filtering or flagging harmful posts in your app.
Architecture fit: The package wraps Google Jigsaw's Perspective API (toxicity/abuse scoring) in a thin PHP service. Note the naming: perspective-api-bundle follows Symfony bundle conventions, not Laravel package conventions — there is no service provider, no publishable config, no facade. In a Laravel codebase it is consumed as a plain library, bound into the container via our own provider, and called from a moderation service or queued job. Architecturally it is a synchronous, per-request dependency on a third-party endpoint, so it belongs behind an async boundary rather than in the request path.
Integration feasibility: Moderate but tractable. Requirements are an API key, egress to perspective.googleapis.com, and the DI glue we write ourselves. Release 1.2 is the first meaningful integration seam: it adds support for custom HTTP client options, which lets us set timeouts, proxy, retry, and base URI without forking. That single change is what moves this from "unusable behind our proxy" to "deployable." There is still no Laravel-native config/env surface — we own that.
Technical risk: Single-maintainer package (freema), low release cadence, and this is only PR #4 — bus factor of one. The new HTTP client options are passed through as an opaque array with no validation, so misconfiguration surfaces as runtime transport errors rather than startup failures. Upstream, Perspective API is quota-bound per key, probabilistic, and locale-sensitive; scores must drive threshold-plus-human-review, never automatic blocking. Third-party processing of user content raises DPA/data-residency questions independent of the code.
Key questions:
Stack fit: Perspective is a REST/JSON service; the package is a thin wrapper returning attribute scores. In Laravel it becomes a singleton bound in a PerspectiveServiceProvider, injected into a ModerationService and invoked from a queued job. The 1.2 client options map cleanly onto a config/services.php entry populated from env, giving us timeout, proxy, and handler-stack control from configuration — the practical path to production safety.
Migration path: Greenfield — no prior assessment and no existing integration. Start non-blocking: score asynchronously, persist scores and raw responses, and gate UI actions on a threshold. Only after calibration should inline pre-publish blocking be considered.
Compatibility: Pin to 1.2. The change is additive (optional options parameter), so 1.1 → 1.2 is non-breaking. Verify the PHP version constraint and the underlying HTTP client major version against our PHP 8.x / Laravel 10–11 baseline. Symfony components are likely already present transitively via Laravel, which softens the bundle-vs-library mismatch, but confirm rather than assume.
Sequencing:
Maintenance: We permanently own the Laravel glue. The package itself is small and slow-moving. Budget for a vendored fork or an in-house client if upstream goes stale — the API surface is narrow enough that replacement is days, not weeks.
Support: Community-grade. Single maintainer, GitHub issues as the only escalation path, no commercial backing. Treat upstream as best-effort and keep the adapter boundary thin so an internal rewrite stays cheap.
Scaling: Throughput is bounded by Perspective API quota, not by our application. Requires queueing, a concurrency cap, caching on content hash to avoid re-scoring duplicates, and graceful degradation when quota is exhausted. Cost scales with request volume and text-length caps.
Failure modes: Connect/read timeouts and 5xx from Google (now mitigated via configurable client options with explicit timeouts and backoff retry); quota exhaustion and 429s; invalid or rotated API key; malformed responses on unsupported languages; and silent score drift changing moderation outcomes without any code change. Recommended posture: fail-open on scoring — log, alert, pass the content through — never fail-closed on a transport error.
Ramp-up: Low for a PHP developer; the integration is a single service class. The real ramp is policy, not code: threshold calibration, multilingual false-positive handling, and standing up a human-review queue. Plan a short technical spike plus a trust & safety calibration session before anything user-facing is enforced.
How can I help you explore Laravel packages today?