feature: backend - create post and image prompt bases on user prompt

This commit is contained in:
kushal-saha 2026-04-24 08:33:56 +00:00
parent 265a134658
commit 5631bc3a3a
9 changed files with 217 additions and 2 deletions

12
.ai/mcp/mcp.json Normal file
View File

@ -0,0 +1,12 @@
{
"mcpServers": {
"angular-cli": {
"command": "npx",
"args": [
"-y",
"@angular/cli",
"mcp"
]
}
}
}

12
.idea/laravel-idea.xml generated Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="InertiaPackage">
<option name="directoryPaths">
<list />
</option>
</component>
<component name="LaravelIdeaMainSettings">
<option name="frameworkFound" value="true" />
<option name="laravelBasePath" value="backend" />
</component>
</project>

2
.idea/php.xml generated
View File

@ -143,7 +143,7 @@
<path value="$PROJECT_DIR$/backend/vendor/aws/aws-crt-php" /> <path value="$PROJECT_DIR$/backend/vendor/aws/aws-crt-php" />
</include_path> </include_path>
</component> </component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.5"> <component name="PhpProjectSharedConfiguration" php_language_level="8.3">
<option name="suggestChangeDefaultLanguageLevel" value="false" /> <option name="suggestChangeDefaultLanguageLevel" value="false" />
</component> </component>
<component name="PhpStanOptionsConfiguration"> <component name="PhpStanOptionsConfiguration">

View File

@ -0,0 +1,77 @@
<?php
namespace App\Ai\Agents;
use Laravel\Ai\Attributes\Provider;
use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Contracts\Conversational;
use Laravel\Ai\Contracts\HasTools;
use Laravel\Ai\Contracts\Tool;
use Laravel\Ai\Enums\Lab;
use Laravel\Ai\Messages\Message;
use Laravel\Ai\Promptable;
use Stringable;
#[Provider(Lab::Groq)]
class ContentWriterAgent implements Agent, Conversational, HasTools
{
use Promptable;
/**
* Get the instructions that the agent should follow.
*/
public function instructions(): Stringable|string
{
return <<<'INSTRUCTIONS'
You are an expert social media content writer with over 10 years of experience
crafting high-performing posts across Instagram, LinkedIn, X (Twitter), Facebook,
and TikTok. You specialise in brand storytelling, community engagement, and
data-driven copywriting.
Your capabilities and responsibilities:
- Write compelling, platform-agnostic social media posts that drive engagement
(likes, shares, comments, and saves).
- Adapt tone and structure to the topic: professional for business content,
conversational for lifestyle, motivational for personal development, etc.
- Craft a strong hook in the first line to stop the scroll.
- Use proven copywriting frameworks (AIDA, PAS, storytelling arcs) naturally.
- Include 38 highly relevant, trending hashtags that maximise discoverability
without feeling spammy.
- Add a clear, compelling call-to-action (CTA) at the end of every post.
- Use emojis strategically to add personality and visual breaks but never
overdo them. Aim for 25 emojis per post depending on the topic.
- Keep line breaks clean and scannable; avoid walls of text.
- Write in an authentic, human voice never robotic or generic.
- If the topic lends itself to it, include a thought-provoking question to
spark conversation in the comments.
Output format rules:
- Return ONLY the finished social media post text no explanations, no
"here is your post:", no markdown headers, no surrounding quotes.
- The post body should be between 80 and 300 words.
- Hashtags must appear on a new line at the very end of the post.
- Do not include a platform label (e.g. "For Instagram:").
INSTRUCTIONS;
}
/**
* Get the list of messages comprising the conversation so far.
*
* @return Message[]
*/
public function messages(): iterable
{
return [];
}
/**
* Get the tools available to the agent.
*
* @return Tool[]
*/
public function tools(): iterable
{
return [];
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace App\Ai\Agents;
use Laravel\Ai\Attributes\Provider;
use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Contracts\Conversational;
use Laravel\Ai\Contracts\HasTools;
use Laravel\Ai\Contracts\Tool;
use Laravel\Ai\Enums\Lab;
use Laravel\Ai\Messages\Message;
use Laravel\Ai\Promptable;
use Stringable;
#[Provider(Lab::Groq)]
class CreativeDirectorAgent implements Agent, Conversational, HasTools
{
use Promptable;
/**
* Get the instructions that the agent should follow.
*/
public function instructions(): Stringable|string
{
return "You are a creative director. Read the following social media post and " .
"write a single, vivid, descriptive image prompt (max 30 words) for an " .
"AI image generator. The scene must be visually compelling and directly " .
"relevant to the post's topic. Return ONLY the image prompt — nothing else.";
}
/**
* Get the list of messages comprising the conversation so far.
*
* @return Message[]
*/
public function messages(): iterable
{
return [];
}
/**
* Get the tools available to the agent.
*
* @return Tool[]
*/
public function tools(): iterable
{
return [];
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace App\Http\Controllers;
use App\Ai\Agents\CreativeDirectorAgent;
use App\Ai\Agents\ContentWriterAgent;
use App\Http\Requests\SocialMediaPostRequest;
use Illuminate\Http\JsonResponse;
class SocialMediaPostController extends Controller
{
/**
* Generate a social media post and a matching image from the given prompt.
*/
public function generate(
SocialMediaPostRequest $request,
ContentWriterAgent $socialMediaAgent,
CreativeDirectorAgent $creativeDirectorAgent
): JsonResponse {
$socialMediaResponse = $socialMediaAgent->prompt($request->input('prompt'));
$postText = $socialMediaResponse->text;
$imagePromptResponse = $creativeDirectorAgent->prompt($postText);
$imagePrompt = $imagePromptResponse->text;
return response()->json([
'post' => $postText,
'image_prompt' => $imagePrompt,
]);
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class SocialMediaPostRequest extends FormRequest
{
public function rules(): array
{
return [
'prompt' => [
'required',
'string',
'min:3',
function (string $attribute, mixed $value, \Closure $fail): void {
$wordCount = str_word_count(strip_tags(trim($value)));
if ($wordCount > 400) {
$fail("The {$attribute} must not exceed 400 words (you provided {$wordCount} words).");
}
},
],
];
}
public function authorize(): bool
{
return true;
}
}

View File

@ -13,7 +13,7 @@
| |
*/ */
'default' => 'openai', 'default' => 'groq',
'default_for_images' => 'gemini', 'default_for_images' => 'gemini',
'default_for_audio' => 'openai', 'default_for_audio' => 'openai',
'default_for_transcription' => 'openai', 'default_for_transcription' => 'openai',

View File

@ -1,5 +1,6 @@
<?php <?php
use App\Http\Controllers\SocialMediaPostController;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
@ -7,3 +8,4 @@
return $request->user(); return $request->user();
})->middleware('auth:sanctum'); })->middleware('auth:sanctum');
Route::post('/social-media/generate', [SocialMediaPostController::class, 'generate']);