# AI-Powered Lead Generation
Krayin's Magic AI feature turns uploaded documents โ invoices, business cards, contracts โ into ready-to-edit leads in one click. The integration sends the parsed file to an OpenRouter (opens new window) model, which returns a structured JSON of person, contact details, and lead value that Krayin then persists.
This page documents both how to enable the feature for end users and how the developer-facing MagicAIService works under the hood.
# ๐ช What you get
- PDF parsing โ text and embedded images, powered by smalot/pdfparser (opens new window).
- Image OCR (planned for future versions).
- Auto-mapping โ AI output is mapped straight into Krayin's lead + person + email + phone schema.
- Localised errors โ failure modes (bad upload, empty file, API failure) return translated user messages.
# โ๏ธ Enable Magic AI
# 1. Get an OpenRouter API key
Sign up at OpenRouter.ai (opens new window) and create an API key from your dashboard.
# 2. Configure in the admin
- Open the admin panel.
- Go to Settings โ Configuration โ General โ Magic AI.
- Toggle Magic AI on.
- Paste your API Key.
- Pick an AI model from the dropdown. Browse the full list at OpenRouter Models (opens new window) โ you can paste additional model IDs into the field if the one you want isn't pre-listed.
- Enable DOC Generation.
- Save.
Once saved, the Upload File control becomes available on the Leads index.
# ๐ Create a lead from a document
- Open Leads in the admin sidebar.
- Click Upload File.
- Pick a PDF or image (invoice, business card, โฆ).
- Magic AI parses the file, extracts the structured fields, and creates a draft lead pre-filled with what it found.
The flow is especially useful for capturing offline leads โ trade-show business cards, scanned contracts, emailed invoices.
# ๐ Expected AI output
The AI is instructed to return a strict JSON shape. If a field can't be extracted, it falls back to a default value:
{
"status": 1,
"title": "Untitled Lead",
"lead_value": 0,
"person": {
"name": "Unknown",
"emails": {
"value": null,
"label": null
},
"contact_numbers": {
"value": null,
"label": null
}
}
}
| Field | What's extracted |
|---|---|
title | Title of the lead โ usually the invoice subject or project name |
lead_value | Monetary value of the lead (numeric) |
person.name | Name of the individual or contact person |
person.emails.value | Email address |
person.emails.label | Optional email label (work, personal, โฆ) |
person.contact_numbers.value | Phone number |
person.contact_numbers.label | Optional phone label |
# ๐ ๏ธ Developer details โ MagicAIService
All of the above is orchestrated by:
Webkul\Lead\Services\MagicAIService
Responsibilities:
- Validating + decoding Base64-encoded uploads.
- Extracting content โ text and embedded images โ from supported file types via
smalot/pdfparser. - Calling OpenRouter using Laravel's HTTP client with the configured API key + model.
- Mapping the response into a valid Krayin lead payload (person, emails, phone numbers, value).
# Implementation notes
- Concurrency protection โ the service holds a re-entrancy flag so the same upload can't be processed twice in parallel.
- Temporary files โ uploads are written to a temp path, parsed, then deleted whether the call succeeds or fails.
- Token-limit handling โ oversized documents are truncated intelligently before the prompt is built, so the request stays inside the model's context window.
- Error path โ bad Base64, empty files, and AI response issues are caught and surfaced via
trans()so the UI gets a localised message rather than a stack trace.
# ๐งช Verify
After saving the config:
- Tail the Laravel log:
tail -f storage/logs/laravel.log. - Upload a small test PDF from the Leads page.
- You should see the OpenRouter request in the log, followed by a new lead in the list.
If the upload silently does nothing, check the Magic AI section in Settings โ Configuration โ General โ Magic AI โ an invalid or expired API key is the most common cause.