Update
This commit is contained in:
183
app/Helpers/FirstParty/Meme/MemeGenerator.php
Normal file
183
app/Helpers/FirstParty/Meme/MemeGenerator.php
Normal file
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
namespace App\Helpers\FirstParty\Meme;
|
||||
|
||||
use App\Helpers\FirstParty\AI\CloudflareAI;
|
||||
use App\Helpers\FirstParty\AI\OpenAI;
|
||||
use App\Helpers\FirstParty\AI\RunwareAI;
|
||||
use App\Helpers\FirstParty\AspectRatio;
|
||||
use App\Helpers\FirstParty\MediaEngine\MediaEngine;
|
||||
use App\Models\BackgroundMedia;
|
||||
use App\Models\Category;
|
||||
use App\Models\Meme;
|
||||
use App\Models\MemeMedia;
|
||||
use Pgvector\Laravel\Distance;
|
||||
use Str;
|
||||
|
||||
class MemeGenerator
|
||||
{
|
||||
|
||||
const TYPE_SINGLE_CAPTION_MEME_BACKGROUND = 'single_caption_meme_background';
|
||||
|
||||
const STATUS_PENDING = 'pending';
|
||||
const STATUS_COMPLETED = 'completed';
|
||||
|
||||
public static function generateMemeByCategory(Category $category)
|
||||
{
|
||||
$meme_output = self::getMemeOutputByCategory($category);
|
||||
|
||||
$meme = null;
|
||||
|
||||
if ($meme_output->success) {
|
||||
$meme = Meme::create([
|
||||
'type' => self::TYPE_SINGLE_CAPTION_MEME_BACKGROUND,
|
||||
'prompt' => $meme_output->prompt,
|
||||
'category_id' => $category->id,
|
||||
'caption' => $meme_output->caption,
|
||||
'meme_keywords' => $meme_output->keywords,
|
||||
'background' => $meme_output->background,
|
||||
'keywords' => $meme_output->keywords,
|
||||
'is_system' => true,
|
||||
'status' => self::STATUS_PENDING
|
||||
]);
|
||||
|
||||
$meme->attachTags($meme_output->keywords, 'meme');
|
||||
}
|
||||
|
||||
if (!is_null($meme) && $meme->status == self::STATUS_PENDING) {
|
||||
// populate meme_id
|
||||
$meme->meme_id = self::getMemeMediaByKeywords($meme_output->keywords)->id;
|
||||
$meme->background_id = self::generateBackgroundMediaWithRunware($meme_output->background)->id;
|
||||
|
||||
if (!is_null($meme->meme_id) && !is_null($meme->background_id)) {
|
||||
$meme->status = self::STATUS_COMPLETED;
|
||||
}
|
||||
|
||||
$meme->save();
|
||||
}
|
||||
|
||||
return $meme;
|
||||
}
|
||||
|
||||
public static function getMemeOutputByCategory(Category $category)
|
||||
{
|
||||
$retries = 3;
|
||||
$attempt = 0;
|
||||
|
||||
$random_keyword = Str::lower($category->name);
|
||||
|
||||
if (!is_null($category->parent_id)) {
|
||||
$random_keyword = $category->parent->name . " - " . $random_keyword;
|
||||
}
|
||||
|
||||
if (!is_null($category->meme_angles)) {
|
||||
$random_keyword .= " - " . collect($category->meme_angles)->random();
|
||||
} else if (!is_null($category->keywords)) {
|
||||
$random_keyword .= " - " . collect($category->keywords)->random();
|
||||
}
|
||||
|
||||
$prompt = "Write me 1 meme about {$random_keyword}";
|
||||
|
||||
// RETRY MECHANISM START
|
||||
do {
|
||||
$attempt++;
|
||||
|
||||
$meme_response = OpenAI::getSingleMemeGenerator($prompt);
|
||||
$meme_output = json_decode(OpenAI::getOpenAIOutput($meme_response));
|
||||
|
||||
$output_is_valid = false;
|
||||
|
||||
if (!is_null($meme_output)) {
|
||||
if (
|
||||
isset($meme_output->caption) &&
|
||||
isset($meme_output->meme_keywords) &&
|
||||
isset($meme_output->background) &&
|
||||
isset($meme_output->keywords)
|
||||
) {
|
||||
$output_is_valid = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If output is valid or we've exhausted all retries, break the loop
|
||||
if ($output_is_valid || $attempt >= $retries) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Optional: Add a small delay between retries to avoid rate limiting
|
||||
// sleep(1);
|
||||
|
||||
} while ($attempt < $retries);
|
||||
// RETRY MECHANISM END
|
||||
|
||||
if ($output_is_valid) {
|
||||
$meme_output->success = true;
|
||||
$meme_output->prompt = $prompt;
|
||||
$meme_output->category = $category;
|
||||
$meme_output->attempts = $attempt; // Optional: track how many attempts it took
|
||||
} else {
|
||||
$meme_output = (object) [
|
||||
'success' => false,
|
||||
'attempts' => $attempt, // Optional: track how many attempts were made
|
||||
'error' => 'Failed to generate valid meme after ' . $retries . ' attempts'
|
||||
];
|
||||
}
|
||||
|
||||
return $meme_output;
|
||||
}
|
||||
|
||||
public static function generateBackgroundMediaWithRunware($prompt)
|
||||
{
|
||||
$media_width = 1024;
|
||||
$media_height = 1024;
|
||||
$aspect_ratio = AspectRatio::get($media_width, $media_height);
|
||||
|
||||
|
||||
$runware_output_url = RunwareAI::generateSchnellImage(Str::uuid(), $prompt, $media_width, $media_height);
|
||||
|
||||
$media = MediaEngine::addMedia(
|
||||
'system-i',
|
||||
'image',
|
||||
'system_uploaded',
|
||||
'replicate',
|
||||
null,
|
||||
$runware_output_url,
|
||||
'download'
|
||||
);
|
||||
|
||||
$background_media = BackgroundMedia::create([
|
||||
'media_uuid' => $media->uuid,
|
||||
'media_url' => MediaEngine::getMediaCloudUrl($media),
|
||||
'prompt' => $prompt,
|
||||
'status' => 'completed',
|
||||
'aspect_ratio' => $aspect_ratio,
|
||||
'media_width' => $media_width,
|
||||
'media_height' => $media_height,
|
||||
|
||||
]);
|
||||
|
||||
return $background_media;
|
||||
}
|
||||
|
||||
public static function getMemeMediaByKeywords(array $keywords)
|
||||
{
|
||||
$meme_media = null;
|
||||
|
||||
$meme_medias = MemeMedia::withAnyTags($keywords)->take(10)->get();
|
||||
|
||||
if ($meme_medias->count() > 0) {
|
||||
$meme_media = $meme_medias->random();
|
||||
}
|
||||
|
||||
if (is_null($meme_media)) {
|
||||
$meme_embedding = CloudflareAI::getVectorEmbeddingBgeSmall(implode(' ', $keywords));
|
||||
|
||||
$meme_medias = MemeMedia::query()->nearestNeighbors('embedding', $meme_embedding, Distance::L2)->take(10)->get();
|
||||
|
||||
if ($meme_medias->count() > 0) {
|
||||
$meme_media = $meme_medias->random();
|
||||
}
|
||||
}
|
||||
|
||||
return $meme_media;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user