Created
April 24, 2024 00:16
-
-
Save aldoyh/ae0300c523e31d28a1fb0dac8f4a8d72 to your computer and use it in GitHub Desktop.
Leonardo.ai Codes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Console\Commands; | |
use App\Models\Artwork; | |
use App\Models\Image; | |
use App\Services\LeonardoService; | |
use Illuminate\Console\Command; | |
use Illuminate\Database\Eloquent\Casts\Json; | |
use Illuminate\Support\Arr; | |
use Illuminate\Support\Carbon; | |
use Illuminate\Support\Facades\Cache; | |
use Illuminate\Support\Facades\File; | |
use Illuminate\Support\Facades\Http; | |
use Illuminate\Support\Facades\Log; | |
use Illuminate\Support\Facades\Storage; | |
use Symfony\Component\Console\Helper\TableCell; | |
use Symfony\Component\Console\Helper\TableStyle; | |
use Illuminate\Support\Str; | |
use function Laravel\Prompts\confirm; | |
use function Laravel\Prompts\info; | |
use function Laravel\Prompts\intro; | |
use function Laravel\Prompts\outro; | |
use function Laravel\Prompts\progress; | |
use function Laravel\Prompts\select; | |
use function Laravel\Prompts\spin; | |
use function Laravel\Prompts\table; | |
use function Laravel\Prompts\text; | |
use function Psy\debug; | |
class LeonardoGenerationsCommand extends Command | |
{ | |
private $path; | |
private $upscaled_image; | |
private $generation; | |
protected $count = 0; | |
protected $generations = []; | |
protected $leonardo; | |
protected $apiKey; | |
protected $url; | |
/** | |
* The name and signature of the console command. | |
* | |
* @var string | |
*/ | |
protected $signature = 'leo {cmd?} {id?} {--count=} {--all}'; | |
/** | |
* The console command description. | |
* | |
* @var string | |
*/ | |
protected $description = 'Run a new prediction using Leonardo.ai API, list all latest predictions, or get a single prediction by id.'; | |
/** | |
* Create a new command instance. | |
* | |
* @return void | |
*/ | |
public function __construct() | |
{ | |
parent::__construct(); | |
$this->leonardo = new LeonardoService(); | |
$this->apiKey = config('services.leo.key'); | |
$this->url = config('services.leo.url'); | |
$this->count = 10; | |
} | |
/** | |
* Execute the console command. | |
*/ | |
public function handle() | |
{ | |
if (empty($this->apiKey)) { | |
$this->error('LEONARDO_API_KEY environment variable is not set'); | |
} | |
$cmd = $this->argument('cmd'); | |
$leonardo = new LeonardoService(); | |
$this->generation = $this->argument('id') ?? null; | |
$this->count = $this->option('count') ?? $this->count; | |
$user_info = Cache::remember('user_info', 15 * 60, function () use ($leonardo) { | |
$user = $leonardo->getUserInfo(); | |
$user['renewalDays'] = Carbon::parse($user['tokenRenewalDate'])->diffInDays(); | |
$user['credits'] = $user['subscriptionTokens']; | |
return $user; | |
}); | |
intro("Welcome to Leonardo.ai CLI 🧙🏻♂️ 🪄 ♌️"); | |
intro("User info: " . $user_info['user']['username'] . " having a total of " . $user_info['subscriptionTokens'] . " credits and " . $user_info['renewalDays'] . " days left."); | |
/** | |
* LIST & UPSCALE COMMAND | |
* | |
* | |
* | |
* | |
* | |
* | |
* | |
* | |
* | |
* | |
*/ | |
if ($cmd == 'list') { | |
// $this->info('User info:'); | |
// $this->table( | |
// ['ID', 'Credits', 'Days Left'], | |
// [ | |
// ['ID' => $user_info['user']['id']], | |
// ['Credits' => $user_info['subscriptionTokens']], | |
// ['Days Left' => $user_info['renewalDays']], | |
// ] | |
// ); | |
$latest_gens = $leonardo->getGenerations(); | |
$latest_gens = array_shift($latest_gens); | |
$ctr = 0; | |
$this->alert('Total generations: ' . count($latest_gens)); | |
$rows = []; | |
foreach ($latest_gens as $gen) { | |
$gen_job = $gen['generated_images']; | |
foreach ($gen_job as $job) { | |
$url = count($job['generated_image_variation_generic']) ? $job['generated_image_variation_generic'][0]['url'] : $job['url']; | |
$rows[] = [ | |
$ctr++, | |
$gen['id'], | |
$job['id'], | |
Carbon::parse($gen['createdAt'])->diffForHumans(), | |
($gen['photoReal'] ? '📷' : ''), | |
count($job['generated_image_variation_generic']) ? '🔭' : '', | |
// shortened url | |
// str($url)->limit(50), | |
$url, | |
]; | |
} | |
} | |
$this->info('Total images: ' . count($rows)); | |
// $this->table( | |
// ['#', 'ID', 'PID', 'Created At', 'photoReal'], | |
// $rows | |
// ); | |
foreach ($rows as $row) { | |
// $this->info($row[0] . ' ' . $row[1] . ' ' . $row[2] . ' ' . $row[3] . ' ' . $row[4] . ' ' . $row[5] . ' ' . $row[6]); | |
// $row['full_url'] = new TableCell($row[6], ['colspan' => 2]); | |
unset($row[6]); | |
table( | |
[ | |
'#', | |
'ID', | |
'PID', | |
'Created At', | |
'photoReal', | |
'Variations', | |
'URL' | |
], | |
[$row] | |
); | |
} | |
// upscale each image | |
if ( | |
confirm( | |
label: 'Do you want to upscale the images?', | |
default: true, | |
) | |
) { | |
foreach ($rows as $row) { | |
$this->info('Upscaling image: ' . $row[2] . '...'); | |
$response = $leonardo->upscaleImage($row[2]); | |
sleep(2); | |
$generationId = $response['sdUpscaleJob']['id']; | |
$this->info('Upscaled image: ' . $generationId . '...'); | |
$this->alert('Getting upscaled image: ' . $generationId . '...'); | |
$response = $leonardo->getVariations($generationId); | |
while (!isset($response['generated_image_variation_generic'][0]['url'])) { | |
$this->info('Waiting for variations to be generated333...' . print_r($response, true)); | |
sleep(5); | |
$response = $leonardo->getVariations($generationId); | |
if (isset($response['generated_image_variation_generic'][0]['url'])) { | |
$this->info('URL: ' . $response['generated_image_variation_generic'][0]['url']); | |
break; | |
} | |
} | |
$gen_url = $response['generated_image_variation_generic'][0]['url']; | |
$filename = Str::afterLast($gen_url, '/'); | |
if (empty($filename) || empty($gen_url) || $gen_url == $filename) { | |
$this->error('Invalid URL: ' . $gen_url . ' ID: ' . $generationId . '...'); | |
continue; | |
} | |
$upscale_image_path = $leonardo->downloadImage( | |
$gen_url, | |
$filename | |
); | |
Artwork::create([ | |
'prompt' => $row[1], | |
'model_id' => $row[1], | |
'predict_id' => $row[2], | |
'user_id' => 1, | |
'is_public' => false, | |
'status' => 'upscaled', | |
'gen_id' => $generationId, | |
'path' => $upscale_image_path, | |
'data' => $response, | |
'published' => false, | |
'published_at' => Carbon::now(config('app.timezone')), | |
// 'tags' => $generation['tags'], | |
])->save(); | |
$this->info('Saved image: ' . $generationId . ' to storage...'); | |
} | |
outro( | |
'<fg=green>Done upscaling images...</>' | |
); | |
} | |
/** | |
* UPSCALE COMMAND | |
* | |
* | |
* | |
* | |
* | |
* | |
* | |
*/ | |
} elseif ($cmd == 'upscale' or $cmd == 'up') { | |
intro("Upscaling image...🧙🏻♂️ 🪄 ♌️"); | |
// TODO: get the selected images from the database | |
// $selected = (new LeonardoService())->getSelectedImages(); | |
$id = $this->argument('id'); | |
if (!$id) { | |
/** | |
* | |
* Display a table of selected images | |
* | |
* | |
*/ | |
// $this->table( | |
// ['Image ID'], | |
// [$selected] | |
// ); | |
// $id = $this->choice( | |
// 'Which image do you want to upscale?', | |
// $selected, | |
// 0, | |
// 3, | |
// true | |
// ); | |
// $this->info('You selected: ' . is_array($id) ? implode(', ', $id) : $id); | |
$this->info('Upscaling latest image generated...'); | |
// $last_image = Image::where('gen_id', '!=', null)->orderBy('id', 'desc')->first(); | |
// $last_image = Artwork::where('predict_id', '!=', null) | |
// $last_image = Image::where('predict_id', '!=', null) | |
$last_image = Image::where('status', '!=', 'upscaled') | |
->orderByDesc('id') | |
->first(); | |
if (!$last_image) { | |
$this->error('No images found in the database...(checking jsons/gens#.json)'); | |
$this->generations = $leonardo->getGenerations(); | |
} else { | |
$this->info('Last image: ' . $last_image->gen_id); | |
$this->generations = [ | |
$leonardo->getSingleGeneration($last_image->predict_id) | |
]; | |
} | |
$gens = (count($this->generations) == 1) ? array_shift($this->generations) : $leonardo->getGenerations(); | |
$gensOptions = []; | |
$this->info( | |
PHP_EOL . PHP_EOL | |
. '<fg=cyan>Total generations: ' . count($this->generations) . '</>' | |
); | |
$gensOptions[0] = 'All ⏳ 🔴'; | |
foreach ($gens as $gen) { | |
$gensOptions[$gen['id']] = Str::limit($gen['prompt'], 10) . ' 🗓️ ' . Carbon::parse($gen['createdAt'])->diffForHumans(); | |
} | |
// check for -a pr --all option to upscale all images | |
if ($this->option('all')) { | |
$this->info('Upscaling all images...'); | |
$selectedGens = 0; | |
} else { | |
$selectedGens = select( | |
'Select the generations to upscale', | |
$gensOptions, | |
0, | |
15, | |
null, | |
'Select a generation to upscale' | |
); | |
} | |
// $this->info('You selected: ' . $selectedGens); | |
if ($selectedGens == 0) { | |
$this->info('Upscaling all generations...'); | |
$gens = $leonardo->getGenerations(); | |
$gens = array_shift($gens); | |
} else { | |
$gens = $leonardo->getSingleGeneration($selectedGens); | |
} | |
foreach ($gens as $singleGen) { | |
if (!is_array($singleGen)) { | |
$this->warn('Image: ' . $singleGen . '...'); | |
} | |
$gens = $leonardo->getSingleGeneration($singleGen['id']); | |
$prompt = $gens['prompt']; | |
$modelId = $gens['modelId']; | |
$predictId = $gens['id']; | |
$file_ext = pathinfo($gens['generated_images'][0]['url'], PATHINFO_EXTENSION); | |
$userId = 1; | |
foreach ($gens['generated_images'] as $gen) { | |
$upscaleGenId = $this->canUpscaleGen($gen); | |
if (!$upscaleGenId) { | |
$this->info('😲 Image already upscaled: ' . $gen['id']); | |
continue; | |
} | |
$upscaledReq = $leonardo->checkImageVariations($upscaleGenId); | |
sleep(1); | |
$counter = 0; | |
$upscaledReq = Arr::first($upscaledReq); | |
do { | |
$upscaledReq = $leonardo->checkImageVariations($upscaleGenId)[0]; | |
sleep(2); | |
$this->info($counter++ . PHP_EOL . ' Waiting for variations to be generated...' . print_r($upscaledReq, true)); | |
} while (isset($upscaledReq['status']) && $upscaledReq['status'] == 'PENDING'); | |
$var_generated = $leonardo->checkImageVariations($upscaleGenId)[0]; | |
$filename = Arr::last(explode('/', $var_generated['url'])); | |
$this->path = $leonardo->downloadImage( | |
$var_generated['url'], | |
$filename, | |
null, | |
$gens['createdAt'] | |
); | |
$this->info('Saving 🎑 ' . $filename . PHP_EOL | |
. '🔗 ' . $var_generated['url'] . PHP_EOL); | |
// $image = Image::where('gen_id', $variationId)->first(); | |
$image_record = Artwork::where('gen_id', $var_generated['id'])->first(); | |
if (!$image_record) { | |
$this->info('📇 Adding to DB ...'); | |
$artwork = [ | |
'prompt' => $prompt, | |
'model_id' => $modelId, | |
'predict_id' => $predictId, | |
'user_id' => 1, | |
'is_public' => false, | |
'status' => 'UPSCALED', | |
'gen_id' => $var_generated['id'], | |
'path' => 'downloaded_images/' . $filename, | |
'data' => $var_generated, | |
'published' => false, | |
'published_at' => Carbon::now(config('app.timezone')), | |
// 'tags' => $generation['tags'], | |
]; | |
Artwork::create($artwork) | |
->saveOrFail(); | |
$this->info('Saved ' . $var_generated['id'] . ' to database...'); | |
} else { | |
// update the path if the image already exists | |
$file_path = 'downloaded_images/' . $filename; | |
if (File::exists(storage_path('app/public/' . $file_path))) { | |
$this->info("📯 Dumper skipped " . $filename . " because it already exists!!"); | |
continue; | |
} else { | |
// download the image from the URL and save it to the public disk | |
$this->path = $leonardo->downloadImage($var_generated['url'], $filename); | |
$this->info("📯 Dumper saved " . $filename . " to " . $this->path); | |
$image_record->save(); | |
} | |
} | |
$this->info('Saved ' . $var_generated['id'] . ' to storage...'); | |
} | |
} | |
} else { // ******** UPSCALING AN IMAGE w/ ID ******** | |
intro("Upscaling image ID $id...🧙🏻♂️ 🪄 ♌️"); | |
$response = $leonardo->getSingleGeneration($id); | |
$this->info('Upscaling image under PredictionID: ' . $response['id'] . ' having a total of ' . count($response['generated_images']) . ' images'); | |
foreach ($response['generated_images'] as $image) { | |
if (count($image['generated_image_variation_generics'])) { | |
$this->info('😲 Image already upscaled: ' . $image['id']); | |
continue; | |
} | |
$this->info('Upscaling image: ' . $image['id'] . '...'); | |
$upscale_req = $leonardo->upscaleImage($image['id']); | |
$this->info('Upscaled image: ' . $image['id'] . '...'); | |
while (!count($leonardo->getVariations($image['id']))) { | |
$this->info('Waiting for variations to be generated11...' . print_r($upscale_req, true)); | |
sleep(2); | |
} | |
$upscaleGenId = $leonardo->checkImageVariations($image['id']); | |
// foreach ($upscale_resp['generated_image_variation_generics'] as $variation) { | |
// $this->info('Downloading image: ' . $variation['id'] . '...'); | |
// $this->path = $leonardo->downloadImage($variation['url'], $variation['id'] . '.jpg'); | |
// $this->info('Saved image: ' . $variation['id'] . ' to storage...'); | |
// $this->info('Saving to database...'); | |
// // $image = Image::where('gen_id', $variation['id'])->first(); | |
// // Save to Artworks | |
// $image = Artwork::where('gen_id', $variation['id'])->first(); | |
// if (!$image) { | |
// $this->info('Image does not exist in database...'); | |
// $image = Artwork::create([ | |
// 'prompt' => $image->prompt, | |
// 'model_id' => $image->modelId, | |
// 'predict_id' => $image->id, | |
// 'user_id' => 2, | |
// 'is_public' => false, | |
// 'status' => 'upscaled', | |
// 'gen_id' => $variation['id'], | |
// 'path' => 'downloaded_images/' . $variation['id'] . '.jpg', | |
// 'data' => $variation, | |
// // 'tags' => $generation['tags'], | |
// ]); | |
// $this->info('Saved ' . $variation['id'] . ' to database...'); | |
// } else { | |
// $this->info('Image already exists in database...'); | |
// } | |
// } | |
$filename = Arr::last(explode('/', $upscaleGenId['url'])); | |
$this->info('Downloading image: ' . $upscaleGenId . '...'); | |
$upscaleJob = $leonardo->checkImageVariations($upscaleGenId); | |
$this->path = $leonardo->downloadImage( | |
$upscaleJob['url'], | |
$filename | |
); | |
$this->info('Saved image: ' . $upscaleGenId . ' to storage...'); | |
} | |
} | |
/** | |
* THE UPLOAD COMMAND | |
* | |
* | |
* | |
* | |
* | |
*/ | |
} elseif ($cmd == 'upload' or $cmd == 'u') { | |
intro("Uploading image...🧙🏻♂️ 🪄 ♌️"); | |
$this->showCredits(); | |
$this->info('Uploading image...'); | |
$images_path = $this->ask( | |
'Enter the path to the image:', | |
public_path('assets/stands/') | |
); | |
$this->info('You entered: ' . $images_path); | |
$images = glob($images_path . '*.{jpg,png,gif}', GLOB_BRACE); | |
$this->info('🎞️ Total images: ' . count($images)); | |
$selected_images = []; | |
foreach ($images as $image) { | |
if ( | |
Artwork::where('url', 'NOT LIKE', '%i.ibb.co%') | |
->where('path', $image) | |
->first() | |
) { | |
$this->info('<fg=bright-magenta>Image already exists in database: ' . $image . '</>'); | |
continue; | |
} | |
$selected_images[] = $image; | |
} | |
$this->info('Total images: ' . count($selected_images) | |
. ' Maximum: ' . $this->count); | |
if ( | |
confirm( | |
label: 'Do you want to upload the images?', | |
default: true, | |
) | |
) { | |
foreach ($selected_images as $image) { | |
if ($this->count-- <= 0) { | |
break; | |
} | |
if (Artwork::where('url', 'LIKE', '%' . $image . '%')->first()) { | |
$this->info('<fg=purple>Image already exists in database: ' . $image . '</>'); | |
// check if the image exists in the storage | |
if (!Storage::disk('public')->exists($image)) { | |
$this->info('<fg=red>Image does not exist in storage: ' . $image . '</>'); | |
} else { | |
$this->info('<fg=green>Image exists in storage: ' . $image . '</>'); | |
} | |
continue; | |
} | |
$this->info('Uploading image: ' . $image . '... ' . $this->count . ' left'); | |
$response = $leonardo->uploadImage($image); | |
$this->info('<fg=blue>' | |
. 'Uploaded image: ' . $response['data']['url'] | |
. '</>'); | |
// update the image url in the database | |
$artwork = Artwork::where('path', $image)->first(); | |
if ($artwork) { | |
$artwork->url = $response['data']['url']; | |
$artwork->save(); | |
} else { | |
$this->info('<fg=bright-cyan>' | |
. 'Image not found in database: ' . $image); | |
$uploadedId = $response['data']['id']; | |
$uploadedUrl = $response['data']['url']; | |
$uploadedViewUrl = $response['data']['url_viewer']; | |
Artwork::create([ | |
'name' => basename($image), | |
'path' => $image, | |
'url' => $uploadedUrl, | |
'user_id' => 1, | |
'prompt' => $uploadedId, | |
'predict_id' => $response['data']['id'], | |
'gen_id' => $response['data']['id'], | |
'is_public' => false, | |
'model_id' => 1, | |
'data' => $response['data'], | |
]) | |
->save(); | |
$this->info('<fg=bright-magenta>Saved image: ' . $uploadedId . ' to storage...' . PHP_EOL | |
. 'URL: ' . $uploadedUrl . PHP_EOL | |
. 'View URL: ' . $uploadedViewUrl . PHP_EOL | |
. '</>'); | |
} | |
} | |
} | |
} else { | |
$gens = $leonardo->getGenerations(); | |
$this->info('<fg=bright-red>🧙🏻♂️ 🪄 ♌️</> <fg=yellow>Leonardo.ai CLI</> <fg=bright-green>🧙🏻♂️ 🪄 ♌️</>'); | |
// if (confirm( | |
// label: 'Do you want to save the generations to a JSON file?', | |
// default: true, | |
// )) { | |
// $grand_spinner = new Spinner("Saving a total of " . count($gens) . " generations to a JSON file"); | |
Storage::disk('public')->put("jsons/generations.json", json_encode($gens)); | |
// } | |
// Storage::disk('public')->put("jsons/generations.json", json_encode($generations)); | |
$table_data = []; | |
$db_table = []; | |
$downloaded_images = []; | |
$ctr = 0; | |
$total_gens = count($gens); | |
$count = $this->count; | |
// foreach ($generations as $page => $gen) { | |
// info("Processing page: $page"); | |
$gens = array_slice($gens, 0, $this->count); | |
foreach ($gens as $pages) { | |
intro("Processing page: " . $ctr++ . " with total images: " . count($pages) . " and total gens: $total_gens "); | |
foreach ($pages as $generation) { | |
$generated_images = $generation['generated_images']; | |
$prompt = $generation['prompt']; | |
$createdAt = $generation['createdAt']; | |
// $photoReal = $generation['photoReal']; | |
// $images = array_map(function ($image) use ($generation, $total_gens, $count) { | |
foreach ($generated_images as $image) { | |
// download the image from the URL and save it to the public disk | |
$filename = Arr::last(explode('/', $image['url'])); | |
if (Artwork::where('gen_id', $image['id'])->first()) { | |
$this->info("Image already exists in DB: " . $image['id']); | |
$file_path = 'downloaded_images/' . $filename; | |
if (!Storage::disk('public')->exists($file_path)) { | |
$this->info("Image does not exist in storage: " . $file_path); | |
$this->path = $this->leonardo->downloadImage( | |
$image['url'], | |
$filename, | |
null, | |
$createdAt | |
); | |
} else { | |
info("Image exists in storage: " . $file_path); | |
$this->info("<bg=green>Image exists in storage: " . $file_path . "</>"); | |
$this->info("📯 Dumper skipped " . $filename . " because it already exists!!"); | |
} | |
} else { | |
$this->path = $this->leonardo->downloadImage( | |
$image['url'], | |
$filename, | |
null, | |
$createdAt | |
); | |
$this->info("📯 Dumper saved " . $filename . " to " . $this->path); | |
$this->info("📇 Adding to DB ..."); | |
Artwork::create([ | |
'prompt' => $prompt, | |
'model_id' => $generation['modelId'], | |
'predict_id' => $generation['id'], | |
'user_id' => 1, | |
'is_public' => false, | |
'status' => $generation['status'], | |
'gen_id' => $image['id'], | |
'path' => 'downloaded_images/' . $filename, | |
'data' => $generation, | |
// 'tags' => $generation['tags'], | |
])->saveOrFail(); | |
$this->info("Saved " . $image['id'] . " to database..."); | |
// $db_table[] = [ | |
// 'prompt' => $prompt, | |
// 'model_id' => $generation['modelId'], | |
// 'predict_id' => $generation['id'], | |
// 'user_id' => 1, | |
// 'is_public' => false, | |
// 'status' => $generation['status'], | |
// 'gen_id' => $image['id'], | |
// 'path' => 'downloaded_images/' . $filename, | |
// 'data' => $generation, | |
// // 'tags' => $generation['tags'], | |
// ]; | |
} | |
} | |
} | |
} | |
outro("Done saving to database...Total: " . count($db_table)); | |
} | |
} | |
/** | |
* | |
* | |
*/ | |
public function canUpscaleGen(array $gen) | |
{ | |
if ($gen['nsfw'] === true) { | |
Log::info('NSFW image'); | |
return false; | |
} | |
if (isset($gen['generated_image_variation_generic']) && $gen['generated_image_variation_generic'] !== null) { | |
return array_shift($gen['generated_image_variation_generic']); | |
} | |
$genId = $gen['id']; | |
$upscalingReqId = $this->leonardo->upscaleImage($genId); | |
sleep(2); | |
$upscaleGenId = $upscalingReqId['id']; | |
$upscale = $this->leonardo->checkImageVariations($upscaleGenId); | |
$counterr = 0; | |
while (isset($upscale['status']) && $upscale['status'] !== 'COMPLETED') { | |
Log::info('Waiting for variations to be generated...' . print_r($upscale, true) . ' Counter: ' . $counterr++); | |
sleep(5); | |
$upscale = $this->leonardo->checkImageVariations($upscaleGenId); | |
} | |
return $upscale; | |
} | |
/** | |
* to be decided later!! | |
* | |
* @param string $url | |
*/ | |
public function getsAllGensbyTheUser() | |
{ | |
// list all generations for the user | |
$leonardo_user_info = new LeonardoService(); | |
$leo_user = $leonardo_user_info->getUserInfo(); | |
$this->info('User info:'); | |
$this->table( | |
['Tokens', 'GptTokens', 'RenewalDate', 'DaysLeft'], | |
[ | |
// $leo_user['user']['id'], | |
// $leo_user['user']['username'], | |
// $leo_user['subscriptionTokens'], | |
// $leo_user['subscriptionGptTokens'], | |
// $leo_user['tokenRenewalDate'], | |
// ['ID' => $leo_user['user']['id']], | |
// ['Name' => $leo_user['user']['username']], | |
['Tokens' => $leo_user['subscriptionTokens']], | |
['GptTokens' => $leo_user['subscriptionGptTokens']], | |
['RenewalDate' => $leo_user['tokenRenewalDate']], | |
['DaysLeft' => Carbon::parse($leo_user['tokenRenewalDate'])->diffInDays()], | |
] | |
); | |
$leo_id = $leo_user['user']['id']; | |
$this->info('Getting all generations for user: ' . $leo_id); | |
$leonardo = new LeonardoService(); | |
$pages = 10; | |
$offset = 1; | |
$generations = []; | |
for ($i = 0; $i < $pages; $i++) { | |
$this->info('Getting generations page: ' . $i . ' offset: ' . $offset); | |
$response = $leonardo->getGenerations($offset ?? null); | |
File::put(database_path('jsons/gens' . $i . '.json'), json_encode($response['generations'])); | |
$generations[] = $response['generations']; | |
Log::info('Getting generations page: ' . $i . ' offset: ' . $offset); | |
$offset = 50 * $i; | |
} | |
// merge the first level of arrays into one | |
$generations = array_merge(...$generations); | |
$this->info('Total generations: ' . count($generations)); | |
return $generations; | |
} | |
/** | |
* Performs the upscale operation | |
* | |
* @param string $image_id | |
*/ | |
public function upscaleSingleImage($predict_id) | |
{ | |
// spin( | |
// function () use ($image_id) { | |
// $leonardo = new LeonardoService(); | |
// $response = $leonardo->upscaleImage($image_id); | |
// $this->upscaled_image = $response['generated_image_variation_generic']; | |
// return $response; | |
// }, | |
// 'Upscaling image: ' . $image_id, | |
// ); | |
$leonardo = new LeonardoService(); | |
$response = $leonardo->upscaleImage($predict_id); | |
// show a progress bar for the download | |
progress( | |
label: 'Upscaling image: ' . $predict_id, | |
steps: 10, | |
callback: function ($step) use ($predict_id, &$leonardo, &$response) { | |
$upscaleGenId = $leonardo->checkImageVariations($predict_id); | |
$this->info('Waiting for variations to be generated...' . print_r($response, true) . ' Step: ' . $step); | |
sleep(2); | |
$response = $leonardo->getVariations($predict_id); | |
if (isset ($response['generated_image_variation_generic'][0]['url'])) { | |
$this->info('URL: ' . $response['generated_image_variation_generic'][0]['url']); | |
} | |
return $upscaleGenId; | |
}, | |
); | |
$upscaled_image = $this->upscaled_image ?? []; | |
if (!count($upscaled_image)) { | |
$this->error('🔴 Error upscaling '); | |
return; | |
} | |
foreach ($upscaled_image as $ups) { | |
$this->info('🔭 Upscaled ' . $ups . '...'); | |
// debug here | |
Storage::disk('public')->put("downloaded_images/" . $ups . '.jpg', Http::get($ups['url'])); | |
$this->info('✅ Saved ' . $ups['id'] . ' to storage...'); | |
$this->info('🔭 Saving to database...'); | |
// $image = Image::where('gen_id', $ups['id'])->first(); | |
$image = Artwork::where('gen_id', $ups['id'])->first(); | |
if (!$image) { | |
$this->info('🔭 Image does not exist in database...'); | |
$image = Artwork::create([ | |
'prompt' => $image->prompt, | |
'model_id' => $image->modelId, | |
'predict_id' => $image->id, | |
'user_id' => 1, | |
'is_public' => false, | |
'status' => 'upscaled', | |
'gen_id' => $ups['id'], | |
'path' => 'downloaded_images/' . Arr::last(explode('/', $ups['url'])), | |
'data' => $ups, | |
// 'tags' => $generation['tags'], | |
]); | |
$this->info('✅ Saved ' . $ups['id'] . ' to database...'); | |
} else { | |
$this->info('🔴 Image already exists in database...'); | |
$image->save(); | |
} | |
} | |
} | |
/** | |
* Show the user's credits | |
*/ | |
public function showCredits() | |
{ | |
$user_info = $this->leonardo->getUserInfo(); | |
$this->info('User info:'); | |
$this->table( | |
['ID', 'Credits', 'Days Left'], | |
[ | |
['ID' => $user_info['user']['id']], | |
['Credits' => $user_info['subscriptionTokens']], | |
['Days Left' => Carbon::parse($user_info['tokenRenewalDate'])->diffInDays()], | |
] | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// namespace App\Providers; | |
namespace App\Services; | |
use App\Mail\NotifyAdminMail; | |
use App\Models\Artwork; | |
use App\Models\Image; | |
use App\Models\Prompt; | |
use Illuminate\Support\Facades\Cache; | |
use Illuminate\Support\Facades\Http; | |
use Illuminate\Support\Facades\Log; | |
use Illuminate\Support\Facades\Mail; | |
use Illuminate\Support\Facades\Request; | |
use Illuminate\Support\Facades\Storage; | |
use Intervention\Image\Imagick\Color; | |
use Symfony\Component\Console\Helper\ProgressBar; | |
use function Laravel\Prompts\confirm; | |
use function Laravel\Prompts\outro; | |
use function Laravel\Prompts\progress; | |
use function Laravel\Prompts\warning; | |
use function Termwind\ask; | |
class LeonardoService | |
{ | |
private $apiKey; | |
private $apiUrl; | |
protected $client; | |
private $authToken; | |
public $userId; | |
public function __construct() | |
{ | |
$this->client = new \GuzzleHttp\Client(); | |
$this->apiKey = config('services.leo.key'); | |
$this->apiUrl = config('services.leo.url'); | |
$this->userId = config('services.leo.user_id'); | |
// $this->authToken = env('LEONARDO_API_TOKEN'); | |
} | |
public static function getUserId() | |
{ | |
return config('services.leo.user_id'); | |
} | |
/** | |
* Make an API request to Leonardo | |
* | |
* @param string $prompt | |
* @return array | |
*/ | |
public function makeGenerationRequest($prompt, $presetStyle = 'CINEMATIC', $numImages = 4) | |
{ | |
if (!$prompt) { | |
Log::error('No prompt provided'); | |
// getting a random one | |
$prompt = Prompt::inRandomOrder()->first()->prompt; | |
} | |
$response = $this->makeApiRequest('/generations', [ | |
'height' => 1360, | |
'width' => 768, | |
'prompt' => $prompt, | |
'alchemy' => true, | |
'photoReal' => true, | |
'photoRealStrength' => 0.5, | |
'presetStyle' => $presetStyle, | |
'num_images' => $numImages, | |
], true); | |
// Process the API response and return the generated image | |
// Replace this with your actual response processing code | |
// $image = $this->processApiResponse($response); | |
return $response; | |
} | |
public function getUserInfo() | |
{ | |
$user_details = $this->makeApiRequest('/me', [], false); | |
return $user_details['user_details'][0]; | |
} | |
public function postGenerations($params) | |
{ | |
return $this->makeApiRequest('/generations', $params, true); | |
} | |
public function getSingleGeneration($generationId): array | |
{ | |
return $this->makeApiRequest('/generations/' . $generationId, [], false); | |
} | |
public function generateImage($prompt) | |
{ | |
// Get the prompt from the request | |
if (!$prompt) { | |
Log::error('No prompt provided'); | |
$prompt = Prompt::inRandomOrder()->first()->prompt; | |
Log::info('Using random prompt: ' . $prompt); | |
if (!$prompt) { | |
Log::error('No prompt found'); | |
return; | |
} | |
} | |
// Make API request to generate image using the prompt | |
// Replace this with your actual API request code | |
$response = $this->makeApiRequest('/generations', [ | |
'height' => 1360, | |
'width' => 768, | |
'prompt' => $prompt, | |
'alchemy' => true, | |
'photoReal' => true, | |
'photoRealStrength' => 0.3, | |
'presetStyle' => 'CINEMATIC', | |
], true); | |
// Process the API response and return the generated image | |
// Replace this with your actual response processing code | |
$image = $this->processApiResponse($response); | |
// TODO: save the image to the database and return the image URL | |
// dd($image); | |
// send a notification mail to the Admin | |
// Mail::to('doydevlabs@gmail.com') | |
// ->send(new NotifyAdminMail()); | |
return $image; | |
} | |
public static function getGenerations($offset = 0) | |
{ | |
// /generations/user/userId?offset=0&limit=10 | |
$url = '/generations/user/' . self::getUserId() . '?offset=' . $offset . '&limit=50'; | |
Log::info('URL: ' . $url); | |
$gens = self::makeApiRequest($url, [ | |
'offset' => $offset, | |
'limit' => 50, | |
], false); | |
return $gens; | |
} | |
/** | |
* Makes an API request to the Leonardo API. if methos is true then it is a POST request. | |
* | |
* @param mixed $endpoint | |
* @param mixed $data | |
* @param mixed $method | |
* @return mixed | |
*/ | |
public static function makeApiRequest($endpoint, $data, $method = false) | |
{ | |
// Make the API request using the provided endpoint and data | |
// Replace this with your actual API request code | |
$apiKey = config('services.leo.key'); | |
$apiUrl = config('services.leo.url'); | |
$userId = config('services.leo.user_id'); | |
if (!$apiUrl) { | |
Log::error('No API URL found'); | |
return; | |
} | |
$response = Http::withHeaders([ | |
'Authorization' => 'Bearer ' . $apiKey, | |
'Content-Type' => 'application/json', | |
'Accept' => 'application/json', | |
'User-Agent' => 'RedScarf AI v1.0 by HD@doy.tech (https://doy.tech)', | |
'X-User-Id' => $userId, | |
]); | |
if ($method) { | |
$response = $response->post($apiUrl . $endpoint, $data); | |
} else { | |
$response = $response->get($apiUrl . $endpoint, $data); | |
} | |
sleep(2); | |
// Log::info('Method: ' . $method ? 'P' : 'G' . ' Endpoint: ' . $endpoint . ' Data: ' . print_r($data, true)); | |
// $response_chunk = $response->collect(); | |
if ($response->status() !== 200) { | |
dump('🚧 Error: ' . $response); | |
Log::error('Error: ' . $response->status()); | |
return; | |
} | |
$response_chunk = $response->json(); | |
if (isset($response_chunk['sdGenerationJob']['generationId'])) { | |
$generationId = $response_chunk['sdGenerationJob']['generationId']; | |
Log::info('GenerationId: ' . $generationId); | |
return [ | |
'generationId' => $generationId, | |
'prompt' => $data['prompt'], | |
'status' => 'STARTED', | |
]; | |
} elseif (isset($response_chunk['generations_by_pk'])) { | |
$response = $response_chunk['generations_by_pk']; | |
$generationId = $response['id']; | |
Log::info('GenerationId: ' . $generationId); | |
return [ | |
'generationId' => $generationId, | |
'prompt' => $response['prompt'], | |
'status' => $response['status'], | |
'generated_images' => $response['generated_images'], | |
...$response | |
]; | |
} else { | |
return $response_chunk; | |
} | |
} | |
/** | |
* Downloads the image from the URL and saves it to the public disk | |
* | |
* @param string $url | |
* @param string $filename | |
* @return string | |
*/ | |
public function downloadImage($url, $filename, $folder = 'downloaded_images') | |
{ | |
// Download the image from the URL and save it to the public disk | |
// Replace this with your actual image download code | |
try { | |
$image = Http::get($url, [ | |
'User-Agent' => 'RedScarf AI v1.0 by HD', | |
]); | |
} catch (\Exception $e) { | |
Log::error('Error downloading image: ' . $filename); | |
return null; | |
} | |
$path = Storage::disk('public')->put("$folder/$filename", $image); | |
if (!$path) { | |
Log::error('Error saving image: ' . $filename); | |
return null; | |
} | |
Log::info('Image saved: ' . $filename); | |
return $folder . '/' . $filename; | |
} | |
/** | |
* Process the API response and return the generated image | |
* @param mixed $response | |
* @return mixed | |
*/ | |
private function processApiResponse($response) | |
{ | |
return json_decode($response, true); | |
} | |
/** | |
* Downloads the generated images and saves them to the public disk | |
* | |
* @param array $images | |
*/ | |
public static function downloadImages($generation_resp, $user_id = 2) | |
{ | |
if (!$generation_resp || !isset($generation_resp['generated_images']) || !isset($generation_resp['prompt'])) { | |
info('No generation_resp provided'); | |
return; | |
} | |
$gen_images = $generation_resp['generated_images']; | |
$prompt = $generation_resp['prompt']; | |
// $photoReal = $generation_resp['photoReal']; | |
foreach ($gen_images as $image) { | |
$filename = basename($image['url']); | |
$path = storage_path('app/public/gen_images/' . $filename); | |
if (!file_exists($path)) { | |
Storage::disk('public')->put("gen_images/$filename", Http::get($image['url'])); | |
$image = [ | |
'id' => $image['id'], | |
'gen_id' => $image['id'], | |
'modelId' => $generation_resp['modelId'], | |
'prompt' => $prompt, | |
'predict_id' => $generation_resp['id'], | |
'is_public' => false, | |
'user_id' => $user_id, | |
'name' => $filename, | |
'url' => $image['url'], | |
'created_at' => $generation_resp['createdAt'], | |
]; | |
// Image::create($image); | |
$artwork = Artwork::create($image); | |
Log::info('👍 Image downloaded: ' . $artwork->id); | |
} else { | |
Log::info("👎 Image already exists: " . $filename); | |
} | |
} | |
} | |
/** | |
* Request an upscale of the image | |
* | |
* @param string $imageId | |
*/ | |
public static function upscaleImage($imageId) | |
{ | |
if (!$imageId) { | |
info('No imageId provided'); | |
return; | |
} | |
$leo = new LeonardoService(); | |
$response = $leo->makeApiRequest('/variations/upscale', [ | |
'id' => $imageId, | |
], true); | |
if (isset($response['sdUpscaleJob'])) { | |
return $response['sdUpscaleJob']; | |
} else { | |
return $response; | |
} | |
} | |
/** | |
* Check the image variations | |
* | |
* | |
* @param string $requestId | |
*/ | |
public static function checkImageVariations($requestId) | |
{ | |
if (!$requestId) { | |
info('No requestId provided'); | |
return; | |
} | |
if (is_array($requestId)) { | |
if ( | |
isset($requestId['generated_image_variation_generic']) | |
&& count($requestId['generated_image_variation_generic']) | |
) { | |
return $requestId['generated_image_variation_generic']; | |
} else { | |
return $requestId; | |
} | |
} else { | |
$leo = new LeonardoService(); | |
$response = $leo->makeApiRequest('/variations/' . $requestId, []); | |
sleep(2); | |
} | |
if (isset($response['generated_image_variation_generic']) && count($response['generated_image_variation_generic'])) { | |
return $response['generated_image_variation_generic']; | |
} else { | |
return $response; | |
} | |
} | |
/** | |
* gets all images from all generations and saves them to the public disk | |
* | |
* @param array $images | |
*/ | |
public static function downloadAllImages($generations) | |
{ | |
$images = []; | |
foreach ($generations as $generation) { | |
$images = array_merge($images, $generation['generated_images']); | |
} | |
$images = array_map(function ($image) { | |
return $image['url']; | |
}, $images); | |
$images = array_unique($images); | |
info('Total images: ' . count($images)); | |
$progress_bar = progress( | |
label: 'Downloading images...', | |
steps: count($images), | |
callback: function ($user) use ($images) { | |
$bar = progress( | |
label: 'Downloading images...', | |
steps: count($images), | |
callback: function ($user) use ($images) { | |
foreach ($images as $image) { | |
$filename = basename($image); | |
$path = storage_path('app/public/gen_images/' . $filename); | |
if (!file_exists($path)) { | |
file_put_contents($path, Http::get($image)); | |
} | |
} | |
}, | |
); | |
}, | |
hint: 'This shouldnt take long ...', | |
); | |
} | |
/** | |
* Gets a list of selected images to mark as public | |
* | |
*/ | |
public static function getSelectedImages() | |
{ | |
$glob_pattern = storage_path('app/public/gen_images/*stand*'); | |
// Log::info('glob_pattern: ' . $glob_pattern); | |
$selectedImages = glob($glob_pattern); | |
$selectedImages = array_map(function ($image) { | |
return basename($image); | |
}, $selectedImages); | |
$selectedImages = array_map(function ($image) { | |
return str_replace('.jpg', '', $image); | |
}, $selectedImages); | |
return $selectedImages; | |
} | |
/** | |
* Marks the selected images as public | |
* | |
*/ | |
public static function markSelectedImagesAsPublic($makePublic = true) | |
{ | |
$selectedImages = self::getSelectedImages(); | |
$images = Image::whereIn('name', $selectedImages)->get(); | |
$images->each(function ($image) use ($makePublic) { | |
// $image->is_public = $makePublic; | |
$image->is_public = !$image->is_public; | |
$image->save(); | |
}); | |
Log::info('Images marked as public: ' . count($images)); | |
} | |
/** | |
* Gets the variations by ID | |
* | |
* @param string $variationId | |
*/ | |
public static function getVariations($variationId) | |
{ | |
if (!$variationId) { | |
info('No variationId provided'); | |
return; | |
} | |
$leo = new LeonardoService(); | |
$response = $leo->makeApiRequest('/variations/' . $variationId, []); | |
return $response['sdUpscaleJob']; | |
} | |
/** | |
* | |
* checks the status of the generation | |
* | |
* @param string $generationId | |
*/ | |
public static function checkGenerationStatus($generationId) | |
{ | |
if (!$generationId) { | |
info('No generationId provided'); | |
return; | |
} | |
$leo = new LeonardoService(); | |
$response = $leo->makeApiRequest('/generations/' . $generationId, []); | |
return $response['status']; | |
} | |
/** | |
* Uploads the image to imgBB | |
* | |
* Sample rsonse; | |
* | |
* | |
// array:3 [ | |
// "data" => array:14 [ | |
// "id" => "MCr8gCg" | |
// "title" => "3ad6a1c1a396" | |
// "url_viewer" => "https://ibb.co/MCr8gCg" | |
// "url" => "https://i.ibb.co/nL93wLw/3ad6a1c1a396.jpg" | |
// "display_url" => "https://i.ibb.co/kSj3GSG/3ad6a1c1a396.jpg" | |
// "width" => 768 | |
// "height" => 1152 | |
// "size" => 488066 | |
// "time" => 1706728072 | |
// "expiration" => 0 | |
// "image" => array:5 [ | |
// "filename" => "3ad6a1c1a396.jpg" | |
// "name" => "3ad6a1c1a396" | |
// "mime" => "image/jpeg" | |
// "extension" => "jpg" | |
// "url" => "https://i.ibb.co/nL93wLw/3ad6a1c1a396.jpg" | |
// ] | |
// "thumb" => array:5 [ | |
// "filename" => "3ad6a1c1a396.jpg" | |
// "name" => "3ad6a1c1a396" | |
// "mime" => "image/jpeg" | |
// "extension" => "jpg" | |
// "url" => "https://i.ibb.co/MCr8gCg/3ad6a1c1a396.jpg" | |
// ] | |
// "medium" => array:5 [ | |
// "filename" => "3ad6a1c1a396.jpg" | |
// "name" => "3ad6a1c1a396" | |
// "mime" => "image/jpeg" | |
// "extension" => "jpg" | |
// "url" => "https://i.ibb.co/kSj3GSG/3ad6a1c1a396.jpg" | |
// ] | |
// "delete_url" => "https://ibb.co/MCr8gCg/1ff48b62fb46aa383c47273cf0ca180f" | |
// ] | |
// "success" => true | |
// "status" => 200 | |
// ] | |
* | |
* @param string $imagePath | |
* | |
* @return string | null | |
*/ | |
public static function uploadImage($imagePath) | |
{ | |
if (!$imagePath) { | |
info('No imagePath provided'); | |
return; | |
} | |
// if ( | |
// // ask('Is imgBB details correct? ' . config('services.leo.imgbb_key') . ' ' . config('services.leo.imgbb_url')) | |
// confirm('Is imgBB details correct? ' . config('services.leo.imgbb_key') . ' ' . config('services.leo.imgbb_url') . PHP_EOL . 'Path: ' . $imagePath) | |
// ) { | |
// info('imgBB details are correct'); | |
// } else { | |
// info('imgBB details are incorrect'); | |
// return; | |
// } | |
if (!file_exists($imagePath)) { | |
info('Image not found: ' . $imagePath); | |
return; | |
} | |
// $response = Http::post(config('services.leo.imgbb_url') . '?key=' . config('services.leo.imgbb_key'), [ | |
// // 'key' => config('services.leo.imgbb_key'), | |
// 'image' => base64_encode(file_get_contents($imagePath)), | |
// ]) | |
// ->throw()->json(); | |
try { | |
$the_image = base64_encode(file_get_contents($imagePath)); | |
$response = Http::attach( | |
'image', | |
$the_image, | |
// 'image.jpg' // optional FILENAME | |
null, | |
[ | |
'content-type' => 'image/jpeg', | |
] | |
) | |
->post(config('services.leo.imgbb_url') | |
. '?key=' . config('services.leo.imgbb_key')); | |
} catch (\Exception $e) { | |
info('Error uploading image: ' . $e->getMessage()); | |
return; | |
} | |
unset($the_image); | |
$response = $response->json(); | |
Log::info('imgBB response: ' . print_r($response, true)); | |
return $response; | |
} | |
/** | |
* | |
* Updates the image with the imgBB URL | |
* | |
* @param string $imageId | |
* @param string $imgbbUrl | |
* @return boolean | null | |
*/ | |
public static function updateImage($imageId, $imgbbUrl) | |
{ | |
if (!$imageId) { | |
info('No imageId provided'); | |
return; | |
} | |
if (!$imgbbUrl) { | |
info('No imgbbUrl provided'); | |
return; | |
} | |
// update the image url in the database | |
$artwork = Artwork::find($imageId)->first(); | |
if ($artwork) { | |
$artwork->url = $imgbbUrl; | |
$artwork->save(); | |
info('Artwork updated: ' . $imageId); | |
return true; | |
} else { | |
info('Artwork not found: ' . $imageId); | |
// create a new record | |
$artwork = Artwork::create([ | |
'id' => $imageId, | |
'url' => $imgbbUrl, | |
'is_public' => true, | |
'user_id' => auth()->user()->id ?? 2, | |
'name' => $imageId, | |
'created_at' => now(), | |
]); | |
info('Artwork created: ' . $imageId); | |
return true; | |
} | |
} | |
/** | |
* Get the images where not uploaded to imgBB yet | |
* | |
* | |
* @return array | |
*/ | |
public static function getImagesNotUploaded() | |
{ | |
$images = Artwork::where('url', 'not like', '%ibb.co%')->get(); | |
return $images; | |
} | |
/** | |
* Converts hex colors to words using thesaurus | |
* | |
* @param string $hex | |
* | |
* @return string | |
*/ | |
public static function hexToNames($hexColor) | |
{ | |
$colors = json_decode(file_get_contents(database_path('jsons/colorBrewer.json')), true); | |
$hexColorWithoutHash = str_replace('#', '', $hexColor); | |
$colorNames = []; | |
// foreach ($colors as $colorName => $colorPalette) { | |
// foreach ($colorPalette as $color) { | |
// $colorWithoutHash = str_replace('#', '', $color); | |
// if ($hexColorWithoutHash === $colorWithoutHash) { | |
// $colorNames[] = $colorName; | |
// } | |
// } | |
// } | |
// search for the color in the colorBrewer.json file | |
$namedArr = array_keys($colors, $hexColorWithoutHash); | |
dd($namedArr); | |
if (count($colorNames) > 0) { | |
return response()->json([ | |
'hexColor' => $hexColor, | |
'englishNames' => $colorNames | |
]); | |
} else { | |
return response()->json([ | |
'hexColor' => $hexColor, | |
'englishNames' => ['Unknown'] | |
]); | |
} | |
} | |
public static function convertHexToWords($colors) | |
{ | |
// Initialize Guzzle HTTP client | |
// $client = new Client(); | |
$topColors = []; | |
foreach ($colors as $color) { | |
$hexColor = $color['hex']; | |
// convert hex to int | |
$hexColor = hexdec($hexColor); | |
// Check if the color name is already cached | |
$cacheKey = 'color_name_' . $hexColor; | |
$colorName = Cache::get($cacheKey); | |
if (!$colorName) { | |
// If not cached, call the API and cache the result | |
try { | |
// $response = $client->request('GET', "http://thecolorapi.com/id?hex=" . ltrim($hexColor, '#')); | |
$hex_api = "https://thecolorapi.com/id?hex=" . ltrim($hexColor, '#'); | |
$body = Http::get($hex_api)->body(); | |
Log::info('Body: ' . $body . ' ' . $hex_api); | |
$data = json_decode($body); | |
$colorName = $data->name->value ?? 'XX'; | |
// Cache the color name. You can specify the duration for caching as per your requirements | |
Cache::put($cacheKey, $colorName, now()->addYears(1)); // Caching for 1 year | |
} catch (\Exception $e) { | |
$colorName = 'Error determining color'; | |
} | |
} | |
$topColors[] = [ | |
'hex' => $hexColor, | |
'name' => $colorName | |
]; | |
} | |
// # Set the hexadecimal color code | |
// color_code="#FF0000" | |
// # Make a cURL request to the ColorTag API | |
// curl -s "http://api.colortag.io/tag-url?palette=simple&hex={{color_code}}" | |
// # Parse the JSON response and extract the color name | |
$response = Http::get("http://api.colortag.io/tag-url?palette=simple&hex=" . ltrim($hexColor, '#')); | |
$body = $response->getBody(); | |
$data = json_decode($body); | |
$topColors['color-tag'] = $data; | |
return $topColors; | |
} | |
/** | |
* Converts hex color to word using thesaurus | |
* | |
* @param string $hex | |
* | |
* @return string | |
*/ | |
#REGION: Masonry | |
/** | |
* Create a collage from the generated images in masonry style | |
*/ | |
public static function createMasonryCollage($outputPath = null, $total = 30) | |
{ | |
$images = glob(storage_path() . '/app/public/gen_images/*.jp*'); | |
info('Images: ' . print_r($images, true)); | |
if (!$outputPath) { | |
$outputPath = storage_path('app/public/gen_images/collage-' . | |
date('Y-m-d-H-i-s') . '.jpg'); | |
} | |
Log::info('Creating collage at ' . $outputPath); | |
// Define the dimensions of the collage | |
$collageWidth = 2900; | |
$collageHeight = 5360; | |
$collage = imagecreatetruecolor($collageWidth, $collageHeight); | |
// Set background color | |
$white = imagecolorallocate($collage, 255, 255, 255); | |
imagefill($collage, 0, 0, $white); | |
$x = 0; // Horizontal position | |
$y = 0; // Vertical position | |
shuffle($images); | |
foreach ($images as $imagePath) { | |
if (!file_exists($imagePath) || !is_file($imagePath)) { | |
warning('Image not found: ' . $imagePath); | |
continue; | |
} else { | |
info('Image found: ' . $imagePath); | |
} | |
$image = imagecreatefromjpeg($imagePath); | |
// Get image dimensions | |
$imgWidth = imagesx($image); | |
$imgHeight = imagesy($image); | |
// Resize image if needed | |
$scale = min(($collageWidth / 5) / $imgWidth, ($collageHeight / 4) / $imgHeight); | |
$newWidth = $imgWidth * $scale; | |
$newHeight = $imgHeight * $scale; | |
// Create resized image | |
$resizedImage = imagecreatetruecolor($newWidth, $newHeight); | |
imagecopyresampled($resizedImage, $image, 0, 0, 0, 0, $newWidth, $newHeight, $imgWidth, $imgHeight); | |
// Check for space and reset positions if necessary | |
if ($x + $newWidth > $collageWidth) { | |
$x = 0; | |
$y += $newHeight; // Move to next row | |
} | |
if ($y + $newHeight > $collageHeight) { | |
break; // No more space in collage | |
} | |
// Place resized image onto the collage | |
imagecopy($collage, $resizedImage, $x, $y, 0, 0, $newWidth, $newHeight); | |
// Update position for next image | |
$x += $newWidth; | |
imagedestroy($image); // Free memory | |
imagedestroy($resizedImage); // Free memory of resized image | |
$total--; | |
if ($total == 0) { | |
break; | |
} | |
} | |
// Save the collage | |
imagejpeg($collage, $outputPath); | |
imagedestroy($collage); | |
outro('Collage created at ' . $outputPath); | |
return $outputPath; | |
} | |
public static function createGalleryMasonry($images) | |
{ | |
// Create an array to store image data | |
$gallery = []; | |
foreach ($images as $image) { | |
// Calculate the width and height of each image | |
list($width, $height) = getimagesize($image); | |
// Determine the orientation (portrait or landscape) of each image | |
if ($width > $height) { | |
$orientation = 'landscape'; | |
} else { | |
$orientation = 'portrait'; | |
} | |
// Calculate the west and height of each image based on the orientation | |
if ($orientation === 'landscape') { | |
$gallery[] = [ | |
'width' => $width, | |
'height' => $height, | |
'west' => 0, | |
'top' => $height, | |
]; | |
} else { | |
// Adjust the west value to minimize the gaps between images | |
if ($gallery) { | |
$lastImage = end($gallery); | |
if ($width > $lastImage['west']) { | |
$gallery[] = [ | |
'width' => $width, | |
'height' => $height, | |
'west' => $lastImage['west'], | |
'top' => 0, | |
]; | |
} else { | |
$gallery[] = [ | |
'width' => $width, | |
'height' => $height, | |
'west' => $lastImage['west'] + ($gallery[$lastImage['top'] - 1]['width'] > $width ? $gallery[$lastImage['top'] - 1]['width'] : $width), | |
'top' => 0, | |
]; | |
} | |
} else { | |
$gallery[] = [ | |
'width' => $width, | |
'height' => $height, | |
'west' => 0, | |
'top' => 0, | |
]; | |
} | |
} | |
} | |
// Sort the images based on their west value to achieve masonry effect | |
usort($gallery, function ($a, $b) { | |
if ($a['west'] === $b['west']) { | |
return $a['top'] <=> $b['top']; | |
} else { | |
return $a['west'] <=> $b['west']; | |
} | |
}); | |
// Return the sorted gallery masonry data | |
return $gallery; | |
} | |
public static function createCollage($outputPath = null, $total = 30) | |
{ | |
// $images = glob(storage_path() . '/app/public/gen_images/*.jp*'); | |
$images = glob(base_path('json_db/raw_images/*.jp*')); | |
Log::info('Images: ' . count($images)); | |
shuffle($images); | |
// extract 10 images from the array | |
$images = array_slice($images, 0, 20); | |
if (!$outputPath) { | |
$outputPath = storage_path('app/public/gen_images/collage-' . | |
date('Y-m-d-H-i-s') . '.jpg'); | |
} | |
$gallery = self::createGalleryMasonry($images); | |
// Calculate the total height of all images | |
$totalHeight = 0; | |
foreach ($gallery as $image) { | |
$totalHeight += $image['height']; | |
} | |
// Create a new image with the maximum width and total height | |
$width = max(...array_column($gallery, 'width')); // Get the maximum width | |
$image = imagecreatetruecolor($width, $totalHeight); | |
// Draw each image onto the canvas | |
foreach ($gallery as $index => $imageData) { | |
// Calculate the x and y position of the image on the canvas based on its masonry data | |
$x = ($imageData['west'] === 0) ? 0 : ($gallery[$index - 1]['width'] + $imageData['west']); | |
$y = $totalHeight - $imageData['height']; // Adjust the y-coordinate here | |
// Draw the image onto the canvas | |
$sourceImage = imagecreatefromjpeg($images[$index]); | |
imagecopyresampled($image, $sourceImage, $x, $y, 0, 0, $imageData['width'], $imageData['height'], imagesx($sourceImage), imagesy($sourceImage)); | |
imagedestroy($sourceImage); | |
} | |
// save to disk | |
imagejpeg($image, $outputPath); | |
imagedestroy($image); // Free memory used by the image | |
} | |
#ENDREGION | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment