Skip to content

Latest commit

Β 

History

79 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•—  β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—
β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•β•β•β•šβ•β•β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ•”β•β•β•β•β•β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•”β•β•šβ•β•β–ˆβ–ˆβ•”β•β•β•
β–ˆβ–ˆβ•‘  β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—     β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•    β–ˆβ–ˆβ•‘
β–ˆβ–ˆβ•‘  β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β•     β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•”β•β•β•  β–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•—    β–ˆβ–ˆβ•‘
β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—   β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘  β–ˆβ–ˆβ•—   β–ˆβ–ˆβ•‘
β•šβ•β•β•β•β•β• β•šβ•β•β•β•β•β•β•   β•šβ•β•   β•šβ•β•β•β•β•β•β•β•šβ•β•  β•šβ•β•   β•šβ•β•

TikTok AI & deepfake detection bot. Mention it on a video or slideshow, get a verdict.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  TikTok mention ──► Worker polls ──► Download media ──► Sightengine      β”‚
β”‚                                                                          β”‚
β”‚  @orkavilabs in comments     polled via TikTok notification API          β”‚
β”‚  Videos                  downloaded via yt-dlp, uploaded to GCS          β”‚
β”‚  Slideshows              images extracted, uploaded to GCS               β”‚
β”‚  AI + deepfake scan      Sightengine genai + deepfake models             β”‚
β”‚  Reply                   Camoufox browser posts result as comment        β”‚
β”‚  Rate limiting           per-user via Upstash Redis                      β”‚
β”‚  Caching                 Firestore dedup + result cache                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

What it is

A TikTok bot that detects AI-generated content and deepfakes. Someone mentions the bot in a comment on any TikTok video or slideshow. The bot downloads the media, runs it through Sightengine's AI generation and deepfake detection models, and replies with a verdict β€” "AI (92%)", "real (97%)", "deepfake detected", or "not sure".

Supports videos and multi-image slideshows (carousels). Each image in a carousel is scanned individually and results are reported per-slide.

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  detekt_worker   │◄── Temporal workflows ──►│  detekt_replier  β”‚
β”‚  (GCE VM)        β”‚                          β”‚  (GCE VM)        β”‚
β”‚                  β”‚                          β”‚                  β”‚
β”‚  Poll mentions   β”‚                          β”‚  Receive reply   β”‚
β”‚  Download media  β”‚                          β”‚  task via        β”‚
β”‚  Upload to GCS   β”‚                          β”‚  Temporal        β”‚
β”‚  Scan via        β”‚                          β”‚                  β”‚
β”‚  Sightengine     β”‚                          β”‚  Open TikTok in  β”‚
β”‚  Dispatch reply  β”‚                          β”‚  Camoufox        β”‚
β”‚                  β”‚                          β”‚  Type & post     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                          β”‚  comment reply   β”‚
         β”‚                                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
    β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚  Firestore    GCS bucket    Upstash β”‚
    β”‚  (scan cache  (media        Redis   β”‚
    β”‚   + dedup)     staging)   (rate lim)β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Two services, both Docker containers on GCE VMs running Container-Optimized OS:

detekt_worker β€” Temporal worker that runs two workflows. PollerWorkflow polls TikTok's notification API on a loop, filters for trigger-word mentions, then spawns a ProcessMentionWorkflow per mention. That workflow downloads the media (yt-dlp for videos, httpx for slideshow images), uploads to GCS, scans via Sightengine (AI generation + deepfake detection), caches results in Firestore, and dispatches a reply task to the replier's Temporal queue.

detekt_replier β€” Temporal worker that receives reply tasks. Uses Camoufox (anti-fingerprint Firefox) with Playwright to open the TikTok video page, click "Reply" on the original comment, @mention the user, type the result message with human-like typing delays, and post. Handles session rotation (12h TTL), status-8 detection, and automatic reboots.

How scanning works

Content type Download Scan
Video yt-dlp β†’ bytes β†’ GCS vids/{id}/video.mp4 Sightengine genai + deepfake video sync (frame-by-frame, averaged)
Slideshow httpx per image β†’ GCS pics/{id}/{n}.{ext} Sightengine genai + deepfake per image, max score across carousel

Results are cached in Firestore by comment ID. Duplicate mentions are deduped by mention:{cid} documents.

The reply message is randomized from a pool of templates based on confidence level:

  • High confidence AI β†’ "yep, that's AI (92% sure)"
  • High confidence deepfake β†’ "real video but the face is swapped (87% sure)"
  • Low confidence β†’ "not sure on this one (54% AI generated/manipulated)"
  • Real β†’ "looks real to me (96% sure)"

Secrets management

All secrets are managed via Doppler. Both containers run with doppler run -- as the entrypoint, which injects secrets as environment variables. A background thread refreshes the secret cache every 30 seconds with a 120-second TTL.

Infrastructure

Terraform manages all GCP resources:

Resource What
google_compute_instance.dtkt_worker GCE VM (c2-standard-4), COS image, runs worker container
google_compute_instance.dtkt_replier GCE VM (c2-standard-4, 30GB disk), COS image, runs replier container
google_storage_bucket.dtkt_media GCS bucket for downloaded media, 7-day lifecycle delete
google_firestore_database.dtkt_default Firestore Native database for scan results + dedup
Service accounts Separate SAs for worker (storage admin, firestore, logging) and replier (storage read/write, logging)

Region defaults to europe-west2 (London).

Deploying

# set up .env from example
cp .env.example .env
# edit with your GCP project and Doppler tokens

# deploy everything (builds both images, pushes to GCR, runs terraform)
deploy.bat

# or deploy a single service
deploy.bat worker
deploy.bat replier

PowerShell alternative:

.\deploy.ps1 -Target all
.\deploy.ps1 -Target worker
.\deploy.ps1 -Target replier

This builds Docker images, pushes to GCR, and runs terraform apply with auto-approve.

Environment variables

Root (.env):

Var What
DTKT_GCP_PROJECT GCP project ID
DTKT_WORKER_DOPPLER_TOKEN Doppler service token for the worker
DTKT_REPLIER_DOPPLER_TOKEN Doppler service token for the replier

Worker secrets (via Doppler):

Var What
DTKT_TEMPORAL_HOST Temporal Cloud host
DTKT_TEMPORAL_NAMESPACE Temporal namespace
DTKT_TEMPORAL_API_KEY Temporal API key
DTKT_TEMPORAL_TASK_QUEUE Replier's Temporal task queue name
DTKT_WORKER_TASK_QUEUE Worker's own Temporal task queue name
DTKT_POLL_INTERVAL_SECONDS Polling interval
DTKT_TRIGGER_WORD Word that triggers the bot in comments
DTKT_USER_BLACKLIST Comma-separated usernames to ignore
DTKT_TT_SESSIONID TikTok session cookie
DTKT_SENTRY_DSN Sentry DSN
DTKT_SENTRY_FLUSH_TIMEOUT Sentry flush timeout in seconds
DTKT_BUCKET_NAME GCS bucket name
DTKT_FIRESTORE_DATABASE Firestore database name
DTKT_FIRESTORE_SCANS_COLLECTION Firestore collection name
DTKT_SIGHTENGINE_API_USER Sightengine API user
DTKT_SIGHTENGINE_API_SECRET Sightengine API secret
DTKT_SIGHTENGINE_REFRESH_INTERVAL Sightengine client refresh interval in seconds
DTKT_SIGHTENGINE_MIN_INTERVAL Min seconds between Sightengine API calls (rate limit)
DTKT_AI_THRESHOLD Score threshold for AI/deepfake classification
DTKT_LOW_CONFIDENCE_MIN Lower bound for "unsure" range
DTKT_LOW_CONFIDENCE_MAX Upper bound for "unsure" range
DTKT_VIDEO_ENA Enable video scanning
DTKT_PHOTO_ENA Enable photo/slideshow scanning
DTKT_MAX_CAROUSEL_PHOTOS Max photos per carousel to scan
DTKT_SUPPORTED_TYPES Comma-separated TikTok aweme types to process
DTKT_UPSTASH_REDIS_URL Upstash Redis URL
DTKT_UPSTASH_REDIS_TOKEN Upstash Redis token
DTKT_RATE_LIMIT_WINDOW Rate limit window in seconds
DTKT_RATE_LIMIT_MAX Max scans per user per window
DTKT_REDIS_REFRESH_INTERVAL Redis client refresh interval in seconds
DTKT_MAX_POLLS_BEFORE_CAN Polls before Temporal continue-as-new
DTKT_MAX_SESSION_RETRIES TikTok session creation retry count
DTKT_SESSION_MAX_AGE_SECONDS TikTok API session max age before rotation
DTKT_SECRETS_CACHE_TTL Secret cache TTL in seconds
DTKT_SECRETS_REFRESH_INTERVAL Secret background refresh interval in seconds
DTKT_WEBSHARE_API_KEY Webshare proxy API key
DTKT_WEBSHARE_COUNTRY Proxy country code
DTKT_WEBSHARE_PROXY_COUNT Number of proxy slots
DTKT_PROXY_ENABLED Enable/disable proxy

Replier secrets (via Doppler):

Var What
DTKT_TEMPORAL_HOST Temporal Cloud host
DTKT_TEMPORAL_NAMESPACE Temporal namespace
DTKT_TEMPORAL_API_KEY Temporal API key
DTKT_TEMPORAL_TASK_QUEUE Task queue to listen on
DTKT_SENTRY_DSN Sentry DSN
DTKT_BUCKET_NAME GCS bucket (for cookies + debug screenshots)
DTKT_GCS_COOKIES_PATH GCS path to Netscape cookie file
DTKT_GCP_SERVICE_ACCOUNT_JSON GCP SA JSON for GCS access
DTKT_DBG_ENA Enable debug screenshots
DTKT_GCS_DBGSC_PATH GCS path prefix for debug screenshots
DTKT_REPLIER_SESSION_TTL Camoufox browser session TTL in seconds
DTKT_REPLIER_BOOT_MAX_RETRIES Browser boot retry count
DTKT_GEO_LATITUDE Browser geolocation latitude
DTKT_GEO_LONGITUDE Browser geolocation longitude
DTKT_GEO_LANGUAGE Browser locale language
DTKT_GEO_REGION Browser locale region
DTKT_GEO_TIMEZONE Browser timezone
DTKT_SECRETS_CACHE_TTL Secret cache TTL in seconds
DTKT_SECRETS_REFRESH_INTERVAL Secret background refresh interval in seconds
Proxy vars Same as worker

Security

See SECURITY.md.

Maintaining

See MAINTAINING.md.

Contributing

See CONTRIBUTING.md.

License

MIT β€” see LICENSE.

About

AI generated content detection... but in a TikTok bot?

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages