Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Perspective Api Bundle Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

This package wraps Google's Perspective API (comment toxicity scoring) for PHP. Despite the -bundle name it targets Symfony's DI container, but the core service is plain PHP, so in Laravel you consume it as a small adapter rather than a full framework integration.

Minimal path:

  1. Credential first. Get a Perspective API key from Google Cloud (enable the Perspective Comment Analyzer API). Without it every call returns 403 and you'll waste time debugging your wiring.
  2. Install and inspect the service class. Read the constructor and the Resources/config (or equivalent) service definition before writing anything — this tells you exactly which config keys map to which constructor arguments, and that's where the 1.2 feature lives.
  3. Pick your first use case: score a single string on TOXICITY and log the result. Do not start by wiring it into moderation actions; start by observing score distributions on your real comment corpus.
  4. Bind it in a service provider. Register the underlying client/service as a singleton in AppServiceProvider using a small config file (config/perspective.php) fed by env vars.

As of 1.2, the service accepts custom HTTP client options. This is the headline change for Laravel users: you can now pass timeout, connect_timeout, proxy, and retry-related transport options through to the underlying HTTP client instead of being stuck with library defaults. Check the constructor signature after upgrading to confirm the exact argument name/shape — the release notes only say "custom HTTP client options," not the precise key.

Implementation Patterns

Wrap, don't scatter. Create one thin ToxicityScorer (or similar) application service that owns the package service. Every caller goes through it, so when Google adds attributes or you swap to a queue, you change one file.

Score asynchronously by default. Perspective calls are network round-trips of a few hundred ms. On user-generated content paths, dispatch a job (ScoreComment, queued) and store scores on the model. Only call synchronously for pre-publish blocking flows, and then only with a short timeout.

Threshold, don't boolean. Perspective returns per-attribute probabilities. Persist the raw scores (TOXICITY, SEVERE_TOXICITY, IDENTITY_ATTACK, INSULT, PROFANITY, THREAT) in a JSON column and apply thresholds in your own code. Thresholds tuned per-surface (public comments vs. DMs vs. usernames) beat one global number, and storing raw scores lets you re-tune retroactively without re-calling the API.

Batch where possible. Prefer sending multiple comments per request when the package/API surface allows it; it directly reduces quota consumption.

Fail open with a marker. In a job, catch transport errors and record scored_at = null, score_error = .... Never let a moderation API outage silently 500 a comment submission. In synchronous blocking flows, decide explicitly whether unknown = allow or unknown = hold.

Use the new HTTP client options deliberately. Configure them in config/perspective.php and pass them through:

  • timeout ~2–3s for synchronous paths (Google's P99 can exceed this under load),
  • connect_timeout ~1s,
  • proxy settings if you egress through a gateway,
  • retry/backoff options if your HTTP client supports them — but only for idempotent scoring calls, and keep retries out of the request/response path.

Cache aggressively. The same text (normalized: trimmed, lowercased where appropriate) yields the same score. A cache keyed on a hash of the text plus the requested attributes will absorb a large share of repeat content — spam, copypasta, and retried jobs especially.

Keep the key server-side. Put it in .env / a secret manager, exclude it from any client bundle, and never log request bodies containing it.

Gotchas and Tips

  • The -bundle naming is a trap. Docs and examples are Symfony-flavored (services.yaml, autowiring, bundle registration). Translate, don't copy. In Laravel you instantiate the service manually or via a bound factory.
  • Quota is the real constraint. Default quota is roughly 1 request/second per key and is not adjustable on the free tier. Queue workers with high concurrency will produce 429s; throttle the queue or the scorer explicitly. This is the single most common production surprise.
  • Language support is uneven. Non-English text scores poorly or not at all; Perspective's model coverage varies by attribute and language. Test on your actual locale mix before trusting thresholds. Don't assume a low TOXICITY score on a non-English comment means anything.
  • TOXICITY is the composite, the others are components. Don't sum them and don't double-count — use TOXICITY for gating and the components for explanation/UI reasons.
  • Scores are probabilities, not certainty. 0.55 on one short comment is noise; a distribution of scores on real data is the only way to choose a threshold. Also expect adversarial users to probe and evade.
  • Verify the 1.2 option shape after upgrade. Release 1.2 only says "custom HTTP client options" — confirm whether they're constructor arguments, a config array, or a client instance, and whether they replace or merge with defaults. Test timeout behavior with a deliberately slow endpoint rather than assuming.
  • Debugging 4xx: 400 usually means malformed payload (empty text, unknown attribute), 403 means key/quota/billing, 429 means rate limiting. Log the response status distinctly so you can tell them apart at 3am.
  • Empty and very short strings are unreliable inputs; short-circuit them before calling the API to save quota.
  • Extension point: since the HTTP options are now injectable, this is your hook for adding middleware-style behavior (request logging, correlation IDs, retry decorators) at the transport layer instead of wrapping every call site.
  • Pin the version in composer.json and re-read the constructor on every minor bump — this package's config surface is small and moving.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console