File: /var/www/html/api.aianced.com/app/Services/AiAnalysisService.php
<?php
namespace App\Services;
use OpenAI\Laravel\Facades\OpenAI;
class AiAnalysisService
{
/**
* Analyze an idea and return a structured summary.
* Switch between 'openai' and 'simulation' via AIANCED_AI_PROVIDER in .env
*/
public function analyze(string $ideaText): array
{
if (config('aianced.ai_provider') === 'openai') {
return $this->analyzeWithOpenAI($ideaText);
}
return $this->simulate($ideaText);
}
// ─────────────────────────────────────────────────────────────────────────
// Real OpenAI call — strict token limits to prevent abuse & control cost
// ─────────────────────────────────────────────────────────────────────────
private function analyzeWithOpenAI(string $ideaText): array
{
// Hard cap input to 500 chars — no need to send more to OpenAI
$truncated = mb_substr(trim($ideaText), 0, 500);
$response = OpenAI::chat()->create([
'model' => config('aianced.openai_model', 'gpt-4o-mini'),
'messages' => [
['role' => 'system', 'content' => $this->systemPrompt()],
['role' => 'user', 'content' => $truncated],
],
// businessModel + praise add ~40 tokens; 360 gives safe headroom
'max_tokens' => 360,
'temperature' => 0.3, // Low = consistent, focused output
'top_p' => 0.9,
// Force JSON output — prevents markdown wrapping or free-text
'response_format' => ['type' => 'json_object'],
]);
$content = $response->choices[0]->message->content ?? null;
if (!$content) {
throw new \RuntimeException('OpenAI returned an empty response.');
}
$parsed = json_decode($content, true);
if (!$parsed || !isset($parsed['quality'])) {
throw new \RuntimeException('OpenAI response was not in the expected format.');
}
$quality = in_array($parsed['quality'], ['valid', 'vague', 'spam']) ? $parsed['quality'] : 'valid';
$name = isset($parsed['name']) && is_string($parsed['name']) && $parsed['name'] !== 'null'
? mb_substr(strip_tags($parsed['name']), 0, 50)
: null;
// Spam — return immediately, no analysis needed
if ($quality === 'spam') {
return ['quality' => 'spam', 'name' => $name];
}
if (!isset($parsed['productType'], $parsed['targetUsers'], $parsed['features'])) {
throw new \RuntimeException('OpenAI response was not in the expected format.');
}
// Sanitize — keep only what the frontend needs, limit feature count
return [
'quality' => $quality,
'name' => $name,
'productType' => mb_substr(strip_tags($parsed['productType']), 0, 80),
'targetUsers' => mb_substr(strip_tags($parsed['targetUsers']), 0, 120),
'features' => array_slice(
array_map(fn($f) => mb_substr(strip_tags((string) $f), 0, 100), $parsed['features']),
0, 6
),
'businessModel' => mb_substr(strip_tags($parsed['businessModel'] ?? ''), 0, 80),
'praise' => mb_substr(strip_tags($parsed['praise'] ?? ''), 0, 220),
];
}
// ─────────────────────────────────────────────────────────────────────────
// System prompt — tight instruction to keep output small and structured
// ─────────────────────────────────────────────────────────────────────────
private function systemPrompt(): string
{
return <<<PROMPT
You are a software product analyst. Analyze the user's product idea and respond with ONLY a JSON object using exactly these keys:
{
"quality": "valid | vague | spam",
"name": "first name if user mentions their own name (e.g. 'I'm John', 'My name is Sarah'), otherwise null",
"productType": "short category label (max 8 words)",
"businessModel": "how this business operates or makes money — e.g. 'E-Commerce Retail', 'B2B SaaS', 'Content Distribution Service', 'On-Demand Service Aggregator', 'Creator Economy Platform' (max 6 words)",
"targetUsers": "who will use this (max 15 words)",
"features": ["feature 1", "feature 2", "feature 3", "feature 4", "feature 5"],
"praise": "one sentence that genuinely validates this specific idea — reference the actual concept, not generic praise (max 30 words)"
}
Rules:
- Return ONLY valid JSON. No markdown, no explanation, no extra keys.
- quality must be exactly one of: valid, vague, spam
- spam: gibberish, random characters, test input, offensive content, or clearly not a software/product idea
- vague: has product intent but too generic or lacks meaningful details (e.g. "I want to make an app")
- valid: clear product idea with identifiable domain and purpose
- If quality is "spam": set productType, businessModel, targetUsers, praise to empty strings and features to []
- If quality is "vague" or "valid": fill all other fields normally
- features must have exactly 4 to 6 items (skip if spam).
- Each feature is a short phrase, max 8 words.
- businessModel must describe the business nature/model, not repeat productType.
- praise must feel personal and reference the actual idea, not a generic compliment.
PROMPT;
}
// ─────────────────────────────────────────────────────────────────────────
// Simulation fallback — keyword-based for local dev / no API key
// ─────────────────────────────────────────────────────────────────────────
private function simulate(string $ideaText): array
{
$text = strtolower($ideaText);
$quality = $this->classifyQuality($text);
$name = $this->extractName($ideaText);
if ($quality === 'spam') {
return ['quality' => 'spam', 'name' => $name];
}
[$productType, $businessModel, $targetUsers, $features, $praise] = match (true) {
$this->matches($text, ['podcast', 'audio', 'episode', 'listen', 'host', 'rss', 'stream', 'media', 'video', 'youtube', 'content creator', 'creator'])
=> $this->podcast(),
$this->matches($text, ['fitness', 'workout', 'gym', 'trainer', 'exercise', 'health', 'wellness', 'nutrition', 'diet', 'coach'])
=> $this->fitness(),
$this->matches($text, ['job', 'hiring', 'recruit', 'talent', 'freelance', 'candidate', 'resume', 'cv', 'career'])
=> $this->jobs(),
$this->matches($text, ['real estate', 'property', 'rent', 'apartment', 'house', 'tenant', 'landlord', 'mortgage'])
=> $this->realEstate(),
$this->matches($text, ['fintech', 'finance', 'payment', 'wallet', 'banking', 'invoice', 'expense', 'accounting', 'budget'])
=> $this->fintech(),
$this->matches($text, ['marketplace', 'sell', 'buy', 'listing', 'vendor'])
=> $this->marketplace(),
$this->matches($text, ['booking', 'appointment', 'schedule', 'reservation', 'calendar'])
=> $this->booking(),
$this->matches($text, ['delivery', 'food', 'restaurant', 'order', 'courier'])
=> $this->delivery(),
$this->matches($text, ['learning', 'course', 'education', 'lms', 'training', 'tutor', 'school', 'quiz', 'lesson'])
=> $this->elearning(),
$this->matches($text, ['saas', 'dashboard', 'analytics', 'report', 'data', 'automation', 'workflow', 'crm', 'erp', 'tool'])
=> $this->saas(),
$this->matches($text, ['social', 'community', 'network', 'post', 'follow', 'feed', 'chat', 'forum', 'group'])
=> $this->social(),
$this->matches($text, ['ecommerce', 'shop', 'store', 'cart', 'product', 'checkout', 'retail'])
=> $this->ecommerce(),
default => $this->generic(),
};
return ['quality' => $quality, 'name' => $name, 'productType' => $productType, 'businessModel' => $businessModel, 'targetUsers' => $targetUsers, 'features' => $features, 'praise' => $praise];
}
private function classifyQuality(string $text): string
{
$trimmed = trim($text);
// Spam: too short, or looks like gibberish / test input
if (mb_strlen($trimmed) < 15) return 'spam';
// Spam: mostly non-alphabetic (gibberish, random characters)
$alphaCount = preg_match_all('/[a-z]/i', $trimmed);
if ($alphaCount / mb_strlen($trimmed) < 0.4) return 'spam';
// Spam: repeated characters (e.g. "hhhhhhhssssssss", "aaabbbccc")
// Check: fewer than 5 unique characters in a string over 10 chars
$uniqueChars = count(array_unique(str_split(strtolower(preg_replace('/\s+/', '', $trimmed)))));
if ($uniqueChars < 5 && mb_strlen($trimmed) > 10) return 'spam';
// Spam: single word with no spaces (likely gibberish if > 15 chars)
$wordCount = str_word_count($trimmed);
if ($wordCount <= 1 && mb_strlen($trimmed) > 15) return 'spam';
// Spam: common test phrases
$spamPhrases = ['test', 'hello', 'hi there', 'asdf', 'qwerty', 'lorem ipsum', 'aaa', 'bbb', '123'];
foreach ($spamPhrases as $phrase) {
if (trim($trimmed) === $phrase) return 'spam';
}
// Vague: has software/app intent but no real substance
$vagueOnly = ['i want to make an app', 'i want to build an app', 'i have an idea', 'make a website', 'build a website', 'create an app', 'i want an app'];
foreach ($vagueOnly as $phrase) {
if (str_contains($trimmed, $phrase) && mb_strlen($trimmed) < 60) return 'vague';
}
// Vague: under 40 chars with product keywords but nothing else
if (mb_strlen($trimmed) < 40) return 'vague';
return 'valid';
}
private function extractName(string $ideaText): ?string
{
// Match patterns like "I'm John", "I am Sarah", "My name is Alex", "This is Mike"
if (preg_match("/(?:i(?:'m| am)|my name is|this is)\s+([A-Z][a-z]{1,20})\b/i", $ideaText, $m)) {
return mb_substr(strip_tags($m[1]), 0, 50);
}
return null;
}
private function matches(string $text, array $keywords): bool
{
foreach ($keywords as $kw) {
if (str_contains($text, $kw)) return true;
}
return false;
}
private function podcast(): array { return ['Podcast & Media Platform','Content Distribution Service','Content creators and listeners',['Podcast hosting & RSS feed','Episode player & playlists','Creator monetization tools','Listener subscriptions & tips','Analytics & audience insights'],'The creator economy is booming — a platform that helps podcasters publish, grow, and monetize their audience taps directly into this fast-growing market.']; }
private function fitness(): array { return ['Fitness & Wellness Platform','Creator Economy & Digital Coaching','Fitness enthusiasts and coaches',['Trainer profiles & programs','Workout video library','Progress & goal tracking','Live & on-demand classes','In-app payments & subscriptions'],'Health and fitness is one of the most loyal subscription categories — a platform connecting coaches with clients online has strong recurring revenue potential.']; }
private function jobs(): array { return ['Job & Talent Platform','Recruitment Marketplace','Job seekers and employers',['Job listings & search filters','Candidate profiles & resumes','AI-powered job matching','Application tracking system','Employer branding pages'],'Recruitment platforms that reduce time-to-hire for employers while giving candidates better visibility are consistently in high demand across every industry.']; }
private function realEstate(): array { return ['Real Estate Platform','Property Listing Marketplace','Buyers, renters, and agents',['Property listings with photos & maps','Advanced search & filters','Agent & landlord profiles','Virtual tour integration','Enquiry & scheduling system'],'Real estate is one of the highest-value transaction categories online — a focused platform for a specific market or region can build strong local dominance quickly.']; }
private function fintech(): array { return ['FinTech Application','B2B Financial Software','Businesses and financial teams',['Invoicing & payment collection','Expense tracking & budgeting','Multi-currency support','Financial reports & dashboards','Integrations with banks & accounting tools'],'FinTech tools that automate financial workflows save businesses significant time and money — this category consistently shows strong adoption and willingness to pay.']; }
private function marketplace(): array { return ['Marketplace Platform','Two-Sided Marketplace','Buyers and sellers',['Seller profiles & storefronts','Product/service listings','Secure payment processing','Reviews and ratings','Messaging between users'],'A two-sided marketplace is one of the most proven digital business models — strong network effects make this increasingly valuable as it grows.']; }
private function booking(): array { return ['Booking & Scheduling Platform','Service Marketplace','Service providers and clients',['Service provider profiles','Real-time availability calendar','Online booking & confirmations','Automated reminders','Payments & cancellation policy'],'Scheduling and booking tools are in high demand across virtually every service industry — this is a practical, revenue-generating idea with clear user value.']; }
private function delivery(): array { return ['On-Demand Delivery Platform','On-Demand Service Aggregator','Customers, vendors, and drivers',['Vendor/restaurant listings','Real-time order tracking','Driver assignment engine','In-app payments','Ratings for drivers and vendors'],'On-demand delivery remains one of the fastest-growing sectors — a well-executed platform in this space can capture significant local market share quickly.']; }
private function elearning(): array { return ['E-Learning Platform','EdTech Subscription Service','Instructors and students',['Course creation & management','Video lessons & quizzes','Student progress tracking','Certificates of completion','Subscription or pay-per-course'],'The e-learning market is booming globally — a focused platform that serves a specific niche or skill set can build a loyal, recurring-revenue audience.']; }
private function saas(): array { return ['SaaS Dashboard Product','B2B Software-as-a-Service','Business teams and managers',['User authentication & roles','Data visualization & charts','Custom reports & exports','Team collaboration tools','Subscription billing & plans'],'B2B SaaS tools that save teams time or surface better decisions command strong subscription revenue — this idea sits in a category with proven willingness to pay.']; }
private function social(): array { return ['Social Community Platform','User-Generated Content Network','Content creators and communities',['User profiles & feeds','Posts, comments & reactions','Follow / connection system','Notifications & messaging','Content moderation tools'],'Community platforms built around a specific interest or identity tend to retain users far better than general social networks — a focused niche here is a real strength.']; }
private function ecommerce(): array { return ['E-Commerce Store','Direct-to-Consumer Retail','Online shoppers and store owners',['Product catalog & variants','Shopping cart & checkout','Payment gateway integration','Order management & tracking','Discount codes & promotions'],'E-commerce continues to grow year over year — a well-designed store with a strong niche or brand story can compete effectively even in a crowded market.']; }
private function generic(): array { return ['Custom Web Platform','Custom Digital Service','End users and administrators',['User registration & profiles','Core feature module','Admin dashboard','Notifications system','API-ready architecture'],'This is a well-scoped idea with a clear user need — the modular approach means you can launch lean, validate quickly, and build from a solid foundation.']; }
}