fjffk简�的咖啡店科开�2方法2
环æ»�皆山也。其西å�—诸峰,林壑尤美,望之蔚然而深秀者,ç�…ç�Šä¹Ÿã€‚山行å…七里,æ¸�闻水声潺潺,而泻出于两峰之间者,酿泉也
???????????????????????????????
??????????????/?????????????????
............/...................
.........................../...
???????????????????????????????
>>>>>>>>>>>>>/>>>>>>>>>>>>>>>>>
ÿØÿà JFIF ÿÛ „ ( %!1!%)+//.383,7(-.+
-%%-////---/-.+/--+------/------/--0+--/-/-----.-----ÿÀ ¥2" ÿÄ ÿÄ J ! 1AQ"aq�2‘#BR‚¡�Ñ3br’¢±Âð$CSƒ²á4c“%DsÓñÿÄ ÿÄ * !1AQa‘"2q3�±ð#b¡ÿÚ ? ¼QxJQa�uò¸Zö Úü8,�Úú
"SSn<rçù–´âE—^ªBÖ9À\†¸Â�ÔÂ�Ã�TÂÃÛ5
ëd´³Ã�#Ã�;Þ38ϔÂ� ¶H£M:wÃŽ3…³…âpÔF&‚FK¸9„â4à GEõªfÂ�ÿ ‘ñ(ßwÂpŽF|È¥ù®häðÃ�Ѷ¹‘[Ã’inÙW¶ùñYËœQ{›K"išÒ[Ú8žë\F¹@-?v"ÔUâ€�,ìöžkÿ {I‡£šÃ�?e
rÂ�ÃV
?>
.........................................
.............................................................................
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
>>>>>>>>>>>>>/>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
dsdfdatabase/migrations/2025_01_20_080747_is_advanced_image_to_user_openai_table.php 0000644 00000000742 15266705377 0023170 0 ustar 00 boolean('is_advanced_image')->default(false)->after('request_id');
});
}
public function down(): void {}
};
database/migrations/2025_01_20_080747_advanced_image_migrations.php 0000644 00000001326 15266705377 0020466 0 ustar 00 exists();
if ($openai) {
return;
}
OpenAIGenerator::query()->create($data);
}
} catch (\Exception $exception) {
}
}
public function down(): void {}
};
database/resources/db.json 0000644 00000001736 15266705377 0011633 0 ustar 00 {
"user_id": null,
"title": "AI Image Generator",
"description": "Create stunning images in seconds.",
"slug": "ai_image_generator",
"active": 1,
"questions": "[{\"name\":\"description\",\"type\":\"textarea\",\"question\":\"Describe the Image\",\"select\":\"\"},{\"name\":\"size\",\"type\":\"select\",\"question\":\"Image Resolution\",\"select\":\"\"}]",
"image": "",
"premium": 0,
"type": "image",
"created_at": "2023-03-20 14:22:02",
"updated_at": "2024-09-20 14:23:53",
"prompt": null,
"custom_template": 0,
"tone_of_voice": 0,
"color": "#D1C5DE",
"filters": "development",
"package": null
}
extension.json 0000644 00000000215 15266705377 0007473 0 ustar 00 {
"name": "Advanced Image",
"type": "extension",
"version": "1.5.0",
"description": "Advanced Image extension for magicai"
}
System/.DS_Store 0000644 00000014004 15266705377 0007534 0 ustar 00 Bud1 bwspblob ¸ H t t pbwspblob ¸bplist00Ö]ShowStatusBar[ShowToolbar[ShowTabView_ContainerShowSidebar\WindowBounds[ShowSidebar _{{368, 408}, {920, 436}} #/;R_klmnoŠ
‹ H t t pvSrnlong @ € @ € @ € @ E DSDB ` € @ € @ € @ System/Services/NanoBananaService.php 0000644 00000021752 15266705377 0013672 0 ustar 00 tool) {
'reimagine' => $this->reimagine(),
'remove_background' => $this->remove_background(),
'inpainting' => $this->inpainting(),
'remove_text' => $this->remove_text(),
'sketch_to_image' => $this->sketch_to_image(),
'replace_background' => $this->replace_background(),
'cleanup' => $this->cleanup(),
'style_transfer' => $this->style_transfer(),
'image_relight' => $this->image_relight(),
default => [
'status' => 'error',
'message' => 'Unable to process action.',
]
};
}
/**
images: [
'https://betamagicai.liquid-themes.com/uploads/ordek.jpg',
]
*/
public function sketch_to_image(): array
{
try {
$response = self::generateImage(
prompt: 'Turn this sketch into a photorealistic image. Prompt: ' . $this->request->get('description'),
images: self::createImageUrls([
$this->request->file('sketch_file'),
])
);
return $this->responseArray($response);
} catch (Exception $exception) {
return [
'status' => 'error',
'message' => $action['message'] ?? 'Unable to process action.',
];
}
}
public function remove_background(): array
{
try {
$response = self::generateImage(
prompt: 'Remove the background, keeping only the main subject.',
images: self::createImageUrls([
$this->request->file('uploaded_image'),
])
);
return $this->responseArray($response);
} catch (Exception $exception) {
return [
'status' => 'error',
'message' => $action['message'] ?? 'Unable to process action.',
];
}
}
public function cleanup(): array
{
$this->request->validate([
'description' => 'required',
]);
try {
$response = self::generateImage(
prompt: $this->request->get('description'),
images: self::createImageUrls([
$this->request->file('uploaded_image'),
])
);
return $this->responseArray($response);
} catch (Exception $exception) {
return [
'status' => 'error',
'message' => $action['message'] ?? 'Unable to process action.',
];
}
}
public function remove_text(): array
{
try {
$response = self::generateImage(
prompt: 'Remove all visible text while preserving the image content.',
images: self::createImageUrls([
$this->request->file('uploaded_image'),
])
);
return $this->responseArray($response);
} catch (Exception $exception) {
return [
'status' => 'error',
'message' => $action['message'] ?? 'Unable to process action.',
];
}
}
public function inpainting(): array
{
try {
$response = self::generateImage(
prompt: $this->request->get('description') . ' Blend naturally with the rest of the image.',
images: self::createImageUrls([
$this->request->file('uploaded_image'),
])
);
return $this->responseArray($response);
} catch (Exception $exception) {
return [
'status' => 'error',
'message' => $action['message'] ?? 'Unable to process action.',
];
}
}
public function replace_background(): array
{
try {
$response = self::generateImage(
prompt: 'Replace the background with: ' . $this->request->get('description'),
images: self::createImageUrls([
$this->request->file('uploaded_image'),
])
);
return $this->responseArray($response);
} catch (Exception $exception) {
return [
'status' => 'error',
'message' => $action['message'] ?? 'Unable to process action.',
];
}
}
public function reimagine(): array
{
try {
$response = self::generateImage(
prompt: 'Reimagine this image as: ' . $this->request->get('description'),
images: self::createImageUrls([
$this->request->file('uploaded_image'),
])
);
return $this->responseArray($response);
} catch (Exception $exception) {
return [
'status' => 'error',
'message' => $action['message'] ?? 'Unable to process action.',
];
}
}
public function style_transfer(): array
{
$this->request->validate([
'uploaded_image' => 'required|image',
'reference_image' => 'required|image',
]);
try {
$response = self::generateImage(
prompt: 'Apply the general visual style of: [image 1] to [image 2].' . $this->request->get('description'),
entity: EntityEnum::FLUX_PRO_KONTEXT_MAX_MULTI,
images: self::createImageUrls([
$this->request->file('uploaded_image'),
$this->request->file('reference_image'),
])
);
return $this->responseArray($response);
} catch (Exception $exception) {
return [
'status' => 'error',
'message' => $action['message'] ?? 'Unable to process action.',
];
}
}
public function image_relight(): array
{
$this->request->validate([
'uploaded_image' => 'required|image',
'image_relight' => 'required|image',
]);
try {
$response = self::generateImage(
prompt: 'Adjust image lighting to: [image 1] to [image 2]. Prompt: ' . $this->request->get('description') . ' style: ' . $this->request->get('style'),
entity: EntityEnum::FLUX_PRO_KONTEXT_MAX_MULTI,
images: self::createImageUrls([
$this->request->file('uploaded_image'),
$this->request->file('image_relight'),
])
);
return $this->responseArray($response);
} catch (Exception $exception) {
return [
'status' => 'error',
'message' => $action['message'] ?? 'Unable to process action.',
];
}
}
public function responseArray($response): array
{
return [
'task_id' => $response->json('request_id'),
'photo' => '',
'status' => 'success',
'task_status' => 'IN_PROGRESS',
'message' => 'Task is processing.',
'link' => $response->json('response_url'),
];
}
public function checkStatus(UserOpenai $task): UserOpenai
{
$response = Http::withHeaders([
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'Authorization' => 'Key ' . ApiHelper::setFalAIKey(),
])->get($task['payload']['link']);
if ($response->ok() && $images = $response->json('images')) {
$image = Arr::first($images);
$path = $this->downloadAndSaveImageFromUrl($image['url']);
$task->update([
'title' => $this->title($path),
'status' => 'COMPLETED',
'output' => $path,
]);
}
return $task;
}
public function setTool(string $tool): self
{
$this->tool = $tool;
return $this;
}
public function setRequest(Request $request): NanoBananaService
{
$this->request = $request;
return $this;
}
}
System/Services/FalAIService.php 0000644 00000022001 15266705377 0012576 0 ustar 00 tool) {
'reimagine' => $this->reimagine(),
'remove_background' => $this->remove_background(),
'inpainting' => $this->inpainting(),
'remove_text' => $this->remove_text(),
'sketch_to_image' => $this->sketch_to_image(),
'replace_background' => $this->replace_background(),
'cleanup' => $this->cleanup(),
'style_transfer' => $this->style_transfer(),
'image_relight' => $this->image_relight(),
default => [
'status' => 'error',
'message' => 'Unable to process action.',
]
};
}
/**
images: [
'https://betamagicai.liquid-themes.com/uploads/ordek.jpg',
]
*/
public function sketch_to_image(): array
{
try {
$response = self::generateImage(
prompt: 'Turn this sketch into a photorealistic image. Prompt: ' . $this->request->get('description'),
images: self::createImageUrls([
$this->request->file('sketch_file'),
])
);
return $this->responseArray($response);
} catch (Exception $exception) {
return [
'status' => 'error',
'message' => $action['message'] ?? 'Unable to process action.',
];
}
}
public function remove_background(): array
{
try {
$response = self::generateImage(
prompt: 'Remove the background, keeping only the main subject. Transparent.',
images: self::createImageUrls([
$this->request->file('uploaded_image'),
])
);
return $this->responseArray($response);
} catch (Exception $exception) {
return [
'status' => 'error',
'message' => $action['message'] ?? 'Unable to process action.',
];
}
}
public function cleanup(): array
{
try {
$response = self::generateImage(
prompt: 'Clean up the masked area to remove imperfections or unwanted elements. Preserve the other areas.',
images: self::createImageUrls([
$this->request->file('uploaded_image'),
$this->request->file('mask_file'),
])
);
return $this->responseArray($response);
} catch (Exception $exception) {
return [
'status' => 'error',
'message' => $action['message'] ?? 'Unable to process action.',
];
}
}
public function remove_text(): array
{
try {
$response = self::generateImage(
prompt: 'Remove all visible text while preserving the image content.',
images: self::createImageUrls([
$this->request->file('uploaded_image'),
])
);
return $this->responseArray($response);
} catch (Exception $exception) {
return [
'status' => 'error',
'message' => $action['message'] ?? 'Unable to process action.',
];
}
}
public function inpainting(): array
{
try {
$response = self::generateImage(
prompt: $this->request->get('description') . ' Blend naturally with the rest of the image.',
images: self::createImageUrls([
$this->request->file('uploaded_image'),
])
);
return $this->responseArray($response);
} catch (Exception $exception) {
return [
'status' => 'error',
'message' => $action['message'] ?? 'Unable to process action.',
];
}
}
public function replace_background(): array
{
try {
$response = self::generateImage(
prompt: 'Replace the background with: ' . $this->request->get('description'),
images: self::createImageUrls([
$this->request->file('uploaded_image'),
])
);
return $this->responseArray($response);
} catch (Exception $exception) {
return [
'status' => 'error',
'message' => $action['message'] ?? 'Unable to process action.',
];
}
}
public function reimagine(): array
{
try {
$response = self::generateImage(
prompt: 'Reimagine this image as: ' . $this->request->get('description'),
images: self::createImageUrls([
$this->request->file('uploaded_image'),
])
);
return $this->responseArray($response);
} catch (Exception $exception) {
return [
'status' => 'error',
'message' => $action['message'] ?? 'Unable to process action.',
];
}
}
public function style_transfer(): array
{
$this->request->validate([
'uploaded_image' => 'required|image',
'reference_image' => 'required|image',
]);
try {
$response = self::generateImage(
prompt: 'Apply the general visual style of: [image 1] to [image 2].' . $this->request->get('description'),
entity: EntityEnum::FLUX_PRO_KONTEXT_MAX_MULTI,
images: self::createImageUrls([
$this->request->file('uploaded_image'),
$this->request->file('reference_image'),
])
);
return $this->responseArray($response);
} catch (Exception $exception) {
return [
'status' => 'error',
'message' => $action['message'] ?? 'Unable to process action.',
];
}
}
public function image_relight(): array
{
$this->request->validate([
'uploaded_image' => 'required|image',
'image_relight' => 'required|image',
]);
try {
$response = self::generateImage(
prompt: 'Adjust image lighting to: [image 1] to [image 2]. Prompt: ' . $this->request->get('description') . ' style: ' . $this->request->get('style'),
entity: EntityEnum::FLUX_PRO_KONTEXT_MAX_MULTI,
images: self::createImageUrls([
$this->request->file('uploaded_image'),
$this->request->file('image_relight'),
])
);
return $this->responseArray($response);
} catch (Exception $exception) {
return [
'status' => 'error',
'message' => $action['message'] ?? 'Unable to process action.',
];
}
}
public function responseArray($response): array
{
return [
'task_id' => $response->json('request_id'),
'photo' => '',
'status' => 'success',
'task_status' => 'IN_PROGRESS',
'message' => 'Task is processing.',
'link' => $response->json('response_url'),
];
}
public function checkStatus(UserOpenai $task): UserOpenai
{
$response = Http::withHeaders([
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'Authorization' => 'Key ' . ApiHelper::setFalAIKey(),
])->get($task['payload']['link']);
if ($response->ok() && $images = $response->json('images')) {
$image = Arr::first($images);
$path = $this->downloadAndSaveImageFromUrl($image['url']);
$task->update([
'title' => $this->title($path),
'status' => 'COMPLETED',
'output' => $path,
]);
}
return $task;
}
public function setTool(string $tool): self
{
$this->tool = $tool;
return $this;
}
public function setRequest(Request $request): FalAIService
{
$this->request = $request;
return $this;
}
}
System/Services/Traits/UseImage.php 0000644 00000000701 15266705377 0013311 0 ustar 00 $prompt];
if (empty($images)) {
return $request;
}
// $imageUrls = self::createImageUrls($images);
// FLUX_PRO_KONTEXT with single image uses different parameter
if ($entity === EntityEnum::FLUX_PRO_KONTEXT && count($images) === 1) {
$request['image_url'] = Arr::first($images);
} else {
$request['image_urls'] = $images;
}
return $request;
}
private static function makeApiRequest(EntityEnum $entity, array $request): Response
{
$url = self::$baseApiUrl . $entity->value . '/max';
return Http::withHeaders([
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'Authorization' => 'Key ' . ApiHelper::setFalAIKey(),
])->post($url, $request);
}
private static function handleResponse(Response $response): Response
{
if ($response->successful() && $requestId = $response->json('request_id')) {
return $response;
}
$errorMessage = $response->json('detail') ?: 'Check your FAL API key.';
throw new RuntimeException(__($errorMessage));
}
public static function createImageUrls(array $images): array
{
if (empty($images)) {
return [];
}
$baseUrl = url(self::$uploadPath);
return array_map(
fn ($image) => $baseUrl . '/' . $image->store('falai', 'public'),
$images
);
}
}
System/Services/Traits/HasNanoBanana.php 0000644 00000004631 15266705377 0014250 0 ustar 00 $prompt];
if (empty($images)) {
return $request;
}
$request['image_urls'] = $images;
// $request['image_urls'] = [
// 'https://storage.googleapis.com/falserverless/example_inputs/nano-banana-edit-input.png',
// 'https://cdn.mos.cms.futurecdn.net/ntFmJUZ8tw3ULD3tkBaAtf-650-80.jpg.webp',
// ];
$request['num_images'] = 1;
$request['output_format'] = 'png';
return $request;
}
private static function makeApiRequest(EntityEnum $entity, array $request): Response
{
$url = self::$baseApiUrl . $entity->value;
return Http::withHeaders([
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'Authorization' => 'Key ' . ApiHelper::setFalAIKey(),
])->post($url, $request);
}
private static function handleResponse(Response $response): Response
{
if ($response->successful() && $requestId = $response->json('request_id')) {
return $response;
}
$errorMessage = $response->json('detail') ?: 'Check your FAL API key.';
throw new RuntimeException(__($errorMessage));
}
public static function createImageUrls(array $images): array
{
if (empty($images)) {
return [];
}
$baseUrl = url(self::$uploadPath);
return array_map(
fn ($image) => $baseUrl . '/' . $image->store('falai', 'public'),
$images
);
}
}
System/Services/Traits/HasDownloadImage.php 0000644 00000001302 15266705377 0014756 0 ustar 00 successful()) {
$extension = pathinfo(parse_url($url, PHP_URL_PATH), PATHINFO_EXTENSION) ?: 'jpg';
$fileName = Str::uuid() . '.' . $extension;
$path = 'image-editor/' . $fileName;
Storage::disk('uploads')->put($path, $response->body());
return $this->imagePath($path);
}
return null;
}
}
System/Services/AdvancedFreepikService.php 0000644 00000026202 15266705377 0014704 0 ustar 00 'ai/beta/text-to-image/reimagine-flux',
'style_transfer' => 'https://api.freepik.com/v1/ai/image-style-transfer',
// 'remove_background' => 'https://api.freepik.com/v1/ai/beta/remove-background',
'upscale' => 'ai/image-upscaler',
'image-relight' => 'ai/image-relight',
];
public function webhook(UserOpenai $task, array $data): void
{
if (data_get($data, 'status') === 'COMPLETED') {
$image = Arr::first(data_get($data, 'generated'));
$path = $this->downloadAndSaveImageFromUrl($image);
$task->update([
'title' => str_replace('image-editor/', '', $path),
'status' => 'COMPLETED',
'output' => $path,
]);
}
}
public function checkStatus(UserOpenai $task): UserOpenai
{
$payload = $task->payload;
$response = $this->requestGet($payload['link']);
if (! is_array($response) && $response->json('data.status') === 'COMPLETED') {
$image = Arr::first($response->json('data.generated'));
$path = $this->downloadAndSaveImageFromUrl($image);
$task->update([
'title' => str_replace('image-editor/', '', $path),
'status' => 'COMPLETED',
'output' => $path,
]);
}
return $task;
}
public function generate(string $model, array $params): array
{
$response = match ($model) {
'reimagine' => $this->reimagine($params),
'image_relight' => $this->imageRelight($params),
// 'remove_background' => $this->removeBackground($params),
'upscale' => $this->upscale($params),
'style_transfer' => $this->styleTransfer($params),
default => [
'status' => 'error',
'message' => 'Invalid model.',
],
};
return $response;
}
private function styleTransfer($params): PromiseInterface|array|Response
{
$image = $this->encodeFile($params['uploaded_image']);
$reference_image = $this->encodeFile($params['reference_image']);
$data = [
'image' => $image,
'reference_image' => $reference_image,
'webhook_url' => config('app.url') . '/api/webhook/advanced-image/freepik',
'prompt' => $params['description'] ?? 'enhance clarity sharp details',
'style_strength' => 85,
'structure_strength' => 60,
'engine' => 'colorful_anime',
];
$response = $this->requestPost(self::ENDPOINTS['style_transfer'], $data);
if (is_array($response)) {
return $response;
}
if ($response->json('task_id') && $response->json('task_status')) {
return [
'task_status' => $response->json('task_status'),
'task_id' => $response->json('task_id'),
'status' => 'success',
'photo' => null,
'message' => 'Task is processing.',
'link' => 'ai/image-style-transfer/' . $response->json('task_id'),
];
}
return [
'task_status' => 'error',
'task_id' => null,
'status' => 'error',
'message' => 'Unable to process action.',
];
}
private function imageRelight(array $params)
{
request()->validate([
'image_relight' => 'required',
'description' => 'required',
]);
$image = $this->encodeFile($params['uploaded_image']);
$transfer_light_from_reference_image = $this->encodeFile($params['image_relight']);
$data = [
'image' => $image,
'prompt' => $params['description'],
'transfer_light_from_reference_image' => $transfer_light_from_reference_image,
'light_transfer_strength' => 100,
'interpolate_from_original' => false,
'change_background' => true,
'style' => $params['style'],
'webhook_url' => config('app.url') . '/api/webhook/advanced-image/freepik',
];
$response = $this->requestPost(self::ENDPOINTS['upscale'], $data);
if (is_array($response)) {
return $response;
}
if ($response->json('data.task_id') && $response->json('data.status')) {
return [
'task_status' => $response->json('data.status'),
'task_id' => $response->json('data.task_id'),
'status' => 'success',
'photo' => null,
'message' => 'Task is processing.',
'link' => 'ai/image-relight/' . $response->json('data.task_id'),
];
}
return [
'task_status' => 'error',
'task_id' => null,
'status' => 'error',
'message' => 'Unable to process action.',
];
}
private function upscale($params): PromiseInterface|array|Response
{
$image = $this->encodeFile($params['uploaded_image']);
$data = [
'image' => $image,
'webhook_url' => config('app.url') . '/api/webhook/advanced-image/freepik',
'scale_factor' => '2x',
'optimized_for'=> 'standard',
'prompt' => $params['description'] ?? 'enhance clarity sharp details',
'creativity' => 2,
'hdr' => 1,
'resemblance' => 0,
'fractality' => -1,
'engine' => 'magnific_sparkle',
];
$response = $this->requestPost(self::ENDPOINTS['upscale'], $data);
if (is_array($response)) {
return $response;
}
if ($response->json('data.task_id') && $response->json('data.status')) {
return [
'task_status' => $response->json('data.status'),
'task_id' => $response->json('data.task_id'),
'status' => 'success',
'photo' => null,
'message' => 'Task is processing.',
'link' => 'ai/image-upscaler/' . $response->json('data.task_id'),
];
}
return [
'task_status' => 'error',
'task_id' => null,
'status' => 'error',
'message' => 'Unable to process action.',
];
}
private function removeBackground($params) {}
public function reimagine($params): string|array
{
request()->validate(['description' => 'required|string']);
$image = $this->encodeFile($params['uploaded_image']);
$data = [
'image' => $image,
'prompt' => $params['description'],
'imagination' => $params['imagination'] ?? 'wild',
'aspect_ratio' => $params['aspect_ratio'] ?? 'square_1_1',
];
$response = $this->requestPost(self::ENDPOINTS['reimagine'], $data);
if (is_array($response)) {
return $response;
}
if ($response->json('task_id') && $response->json('status') === 'COMPLETED') {
$image = Arr::first($response->json('generated'));
$path = $this->downloadAndSaveImageFromUrl($image);
if ($path) {
return [
'task_status' => $response->json('status'),
'status' => 'success',
'task_id' => $response->json('task_id'),
'photo' => $path,
'link' => 'ai/image-upscaler/' . $response->json('data.task_id'),
];
}
}
return [
'task_status' => 'error',
'task_id' => null,
'status' => 'error',
'message' => 'Unable to process action.',
];
}
public function downloadAndSaveImageFromUrl($url): ?string
{
// Resmin içeriğini çek
$response = Http::get($url);
if ($response->successful()) {
// Dosya uzantısını tahmin et
$extension = pathinfo(parse_url($url, PHP_URL_PATH), PATHINFO_EXTENSION) ?: 'jpg';
// Benzersiz bir dosya adı oluştur
$fileName = Str::uuid() . '.' . $extension;
// Storage path (örnek: storage/app/public/images)
$path = 'image-editor/' . $fileName;
// Dosyayı kaydet
Storage::disk('public')->put($path, $response->body());
// İsteğe bağlı: URL'yi döndür (örnek: http://.../storage/images/abc.jpg)
return $this->imagePath($path);
}
return null;
}
private function encodeFile($file): string
{
if (empty($file)) {
throw new RuntimeException('Make selection on image first');
}
return base64_encode(file_get_contents($file->getRealPath()));
}
public function requestGet($url, $contentType = 'application/json'): PromiseInterface|array|Response
{
$http = Http::withHeaders([
'Content-Type' => $contentType,
'Accept' => 'application/json',
'x-freepik-api-key' => $this->getApiKey(),
])
->baseUrl('https://api.freepik.com/v1/')
->get('ai/image-relight');
if ($http->successful()) {
return $http;
}
$error = $http->json('message');
return [
'status' => 'error',
'message' => $error ?? 'Unable to process action.',
];
}
public function requestPost($url, $data, $contentType = 'application/json'): PromiseInterface|array|Response
{
$http = Http::withHeaders([
'Content-Type' => $contentType,
'Accept' => 'application/json',
'x-freepik-api-key' => $this->getApiKey(),
])
->baseUrl('https://api.freepik.com/v1/')
->post($url, $data);
if ($http->successful()) {
return $http;
}
$error = $http->json('message');
return [
'status' => 'error',
'message' => $error ?? 'Unable to process action.',
];
}
private function getApiKey(): ?string
{
return setting('freepik_api_key');
}
}
System/Services/OpenAIService.php 0000644 00000012667 15266705377 0013016 0 ustar 00 tool) {
'reimagine' => $this->reimagineHandle(),
'cleanup' => $this->cleanupHandle(),
'remove_background' => $this->removeBackgroundHandle(),
'sketch_to_image' => $this->sketchToImageHandle(),
'inpainting' => $this->inpaintingHandle(),
'style_transfer' => $this->styleTransferHandle(),
'reference_image' => $this->referenceImageHandle(),
'remove_text' => $this->removeTextHandle(),
default => [],
};
}
private function removeTextHandle(): array
{
$this->request->validate([
'uploaded_image' => 'required|image|mimes:jpeg,png,jpg,gif|max:4096',
]);
$image = 'uploads/' . $this->request->file('uploaded_image')->store('', ['disk' => 'uploads']);
return app(CreateImageEditService::class)
->setImages([$image])
->setPrompt('Remove all visible text from the selected area of the image and fill the region with natural background content, matching the surrounding textures and colors.')
->generate();
}
// Remove all visible text from the selected area of the image and fill the region with natural background content, matching the surrounding textures and colors.
private function styleTransferHandle(): array
{
$this->request->validate([
'uploaded_image' => 'required|image|mimes:jpeg,png,jpg,gif|max:4096',
'reference_image' => 'required|image|mimes:jpeg,png,jpg,gif|max:4096',
]);
$image = 'uploads/' . $this->request->file('uploaded_image')->store('', ['disk' => 'uploads']);
$style = 'uploads/' . $this->request->file('reference_image')->store('', ['disk' => 'uploads']);
return app(CreateImageEditService::class)
->setImages([$image, $style])
->setPrompt('Apply style transfer to the image.')
->generate();
}
private function inpaintingHandle(): array
{
$this->request->validate([
'uploaded_image' => 'required|image|mimes:jpeg,png,jpg,gif|max:4096',
]);
$image = 'uploads/' . $this->request->file('uploaded_image')->store('', ['disk' => 'uploads']);
return app(CreateImageEditService::class)
->setImages([$image])
->setPrompt('Inpainting : ' . $this->request->input('description'))
->generate();
}
private function sketchToImageHandle(): array
{
$this->request->validate([
'sketch_file' => 'required|image|mimes:jpeg,png,jpg,gif|max:4096',
]);
$image = 'uploads/' . $this->request->file('sketch_file')->store('', ['disk' => 'uploads']);
return app(CreateImageEditService::class)
->setImages([$image])
->setPrompt('sketch to image : ' . $this->request->input('description'))
->generate();
}
private function removeBackgroundHandle(): array
{
$this->request->validate([
'uploaded_image' => 'required|image|mimes:jpeg,png,jpg,gif|max:4096',
]);
$image = 'uploads/' . $this->request->file('uploaded_image')->store('', ['disk' => 'uploads']);
return app(CreateImageEditService::class)
->setImages([$image])
->setPrompt('Remove the background of the image and make it transparent.')
->generate();
}
private function cleanupHandle(): array
{
$this->request->validate([
'uploaded_image' => 'required|image|mimes:jpeg,png,jpg,gif|max:4096',
'mask_file' => 'required|image|mimes:jpeg,png,jpg,gif|max:4096',
]);
$image = 'uploads/' . $this->request->file('uploaded_image')->store('', ['disk' => 'uploads']);
$mask = 'uploads/' . $this->request->file('mask_file')->store('', ['disk' => 'uploads']);
return app(CreateImageEditService::class)
->setImages([$image])
->setMask($mask)
->setPrompt('Remove the areas marked in the mask from the image. Keep the rest of the image intact.')
->generate();
}
private function reimagineHandle(): array
{
$this->request->validate([
'images' => 'required|array',
'images.*' => 'required|image|mimes:jpeg,png,jpg,gif|max:4096',
]);
$images = $this->request->file('images');
$imagePaths = [];
foreach ($images as $image) {
$imagePaths[] = 'uploads/' . $image->store('', ['disk' => 'uploads']);
}
if (count($imagePaths) === 0) {
return [
'status' => false,
'message' => 'No images uploaded.',
];
}
$service = app(CreateImageEditService::class)
->setImages($imagePaths)
->setPrompt($this->request->input('description'))
->generate();
return $service;
}
public function setTool(string $tool): self
{
$this->tool = $tool;
return $this;
}
public function setRequest(Request $request): self
{
$this->request = $request;
return $this;
}
}
System/Services/AdvancedNovitaService.php 0000644 00000031013 15266705377 0014553 0 ustar 00 'https://api.novita.ai/v3/remove-background',
'merge_face' => 'https://api.novita.ai/v3/merge-face',
'replace_background' => 'https://api.novita.ai/v3/replace-background',
'upscale' => 'https://api.novita.ai/v3/async/upscale',
'reimagine' => 'https://api.novita.ai/v3/reimagine',
'remove_text' => 'https://api.novita.ai/v3/remove-text',
'cleanup' => 'https://api.novita.ai/v3/cleanup',
'text_to_image' => 'https://api.novita.ai/v3/async/txt2img',
'inpainting' => 'https://api.novita.ai/v3/async/inpainting',
'check_status' => 'https://api.novita.ai/v3/async/task-result?task_id=',
];
public function __construct()
{
$this->client = new Client;
}
public function webhook(UserOpenai $task, array $data): void
{
$image = data_get($data, '0.image_url');
if ($image) {
$path = $this->downloadAndSaveImageFromUrl($image);
$task->update([
'title' => $this->title($path),
'status' => 'COMPLETED',
'output' => $path,
]);
}
}
public function generate(string $model, array $params): array
{
$action = $this->handleAction($model, $params);
if (isset($action['task']['task_id'])) {
if ($model === 'merge_face') {
$action['image_type'] = 'png';
}
return $this->processTaskWithImage($action);
}
if (isset($action['task_id'])) {
return [
'task_id' => $action['task_id'],
'photo' => '',
'status' => 'success',
'task_status' => 'IN_PROGRESS',
'message' => 'Task is processing.',
'link' => 'https://api.novita.ai/v3/async/task-result?task_id=' . $action['task_id'],
];
}
return [
'status' => 'error',
'message' => $action['message'] ?? 'Unable to process action.',
];
}
private function handleAction(string $model, array $params): array
{
return match ($model) {
'reimagine' => $this->reimagine($params),
'remove_background' => $this->removeBackground($params),
'replace_background' => $this->replaceBackground($params),
'text_to_image' => $this->textToImage($params),
'upscale' => $this->upscale($params),
'remove_text' => $this->removeText($params),
'cleanup' => $this->cleanup($params),
'inpainting' => $this->inpainting($params),
'merge_face' => $this->merge_face($params),
default => []
};
}
private function processTaskWithImage(array $action): array
{
if (isset($action['image_file'])) {
$imageType = $action['image_type'] ?? 'jpg';
$contents = base64_decode($action['image_file']);
$fileName = 'image-editor/' . Str::random(10) . '.' . $imageType;
Storage::disk('public')->put($fileName, $contents);
return [
'task_id' => $action['task']['task_id'],
'photo' => $this->imagePath($fileName),
'status' => 'completed',
];
}
return [
'task_id' => $action['task']['task_id'],
'photo' => null,
'status' => 'completed',
];
}
private function apiRequest(string $endpoint, array $payload): array
{
try {
$response = $this->client->post($endpoint, [
'headers' => [
'Authorization' => 'Bearer ' . setting('novita_api_key'),
'Content-Type' => 'application/json',
],
'json' => $payload,
]);
return json_decode($response->getBody()->getContents(), true);
} catch (Exception $exception) {
if (! $exception->hasResponse()) {
return ['type' => 'error', 'message' => __('Unknown error: No response from the server.')];
}
$responseBody = $exception->getResponse()->getBody();
$errorResponse = json_decode($responseBody, true);
if (! is_array($errorResponse)) {
return ['type' => 'error', 'message' => __('Unknown error: Invalid response format.')];
}
$message = $errorResponse['message'] ?? __('Unknown error');
$metadataMessage = '';
if (isset($errorResponse['metadata']) && is_array($errorResponse['metadata'])) {
$metadataMessage = $errorResponse['metadata']['image_file'] ?? '';
}
return ['type' => 'error', 'message' => trim($message . '. ' . $metadataMessage)];
}
}
private function inpainting(array $params): array
{
request()->validate([
'description' => 'required|string|max:1024',
], [
'description.required' => 'Please provide a prompt',
]);
$image = $this->encodeFile($params['photo']);
$mask = $this->encodeFile($params['mask']);
return $this->apiRequest(self::ENDPOINTS['inpainting'], [
'extra' => [
'response_image_type' => 'jpeg',
'webhook' => [
'url' => config('app.url') . '/api/webhook/advanced-image/novita',
],
'enable_nsfw_detection' => false,
],
'request' => [
'model_name' => 'realisticVisionV40_v40VAE-inpainting_81543.safetensors',
'prompt' => $params['description'],
'negative_prompt' => '(deformed iris, deformed pupils, semi-realistic, cgi, 3d, render, sketch, cartoon, drawing, anime), text, cropped, out of frame, worst quality, low quality, jpeg artifacts, ugly, duplicate, morbid, mutilated, extra fingers, mutated hands, poorly drawn hands, poorly drawn face, mutation, deformed, blurry, dehydrated, bad anatomy, bad proportions, extra limbs, cloned face, disfigured, gross proportions, malformed limbs, missing arms, missing legs, extra arms, extra legs, fused fingers, too many fingers, long neck, BadDream, UnrealisticDream',
'image_num' => 1,
'steps' => 25,
'seed' => -1,
'clip_skip' => 1,
'guidance_scale' => 7.5,
'sampler_name' => 'Euler a',
'mask_blur' => 1,
'inpainting_full_res' => 1,
'inpainting_full_res_padding'=> 32,
'inpainting_mask_invert' => 0,
'initial_noise_multiplier' => 1,
'strength' => 0.85,
'image_base64' => $image,
'mask_image_base64' => $mask,
],
]);
}
private function merge_face(array $params): array
{
$image = $this->encodeFile($params['photo']);
$faceImage = $this->encodeFile(request()->file('face_image'));
return $this->apiRequest(self::ENDPOINTS['merge_face'], [
'image_file' => $image,
'face_image_file' => $faceImage,
'extra' => [
'response_image_type' => 'png',
],
]);
}
private function reimagine(array $params): array
{
$image = $this->encodeFile($params['photo']);
return $this->apiRequest(self::ENDPOINTS['reimagine'], [
'image_file' => $image,
'extra' => ['response_image_type' => 'png'],
]);
}
private function removeBackground(array $params): array
{
$image = $this->encodeFile($params['photo']);
return $this->apiRequest(self::ENDPOINTS['remove_background'], [
'image_file' => $image,
'extra' => ['response_image_type' => 'png'],
]);
}
private function replaceBackground(array $params): array
{
$image = $this->encodeFile($params['photo']);
return $this->apiRequest(self::ENDPOINTS['replace_background'], [
'image_file' => $image,
'prompt' => $params['description'],
'extra' => ['response_image_type' => 'png'],
]);
}
private function textToImage(array $params): array
{
return $this->apiRequest(self::ENDPOINTS['text_to_image'], [
'request' => [
'model_name' => 'sd_xl_base_1.0.safetensors',
'prompt' => $params['description'],
'width' => 1024,
'height' => 1024,
'image_num' => 1,
'steps' => 20,
'seed' => 123,
'clip_skip' => 1,
'guidance_scale' => 7.5,
],
'extra' => ['response_image_type' => 'jpeg', 'enable_nsfw_detection' => false],
]);
}
private function upscale(array $params): array
{
$image = $this->encodeFile($params['photo']);
return $this->apiRequest(self::ENDPOINTS['upscale'], [
'request' => [
'model_name' => 'RealESRGAN_x4plus_anime_6B',
'image_base64' => $image,
'scale_factor' => 2,
],
'extra' => ['response_image_type' => 'jpeg'],
]);
}
private function removeText(array $params): array
{
$image = $this->encodeFile($params['photo']);
return $this->safeApiRequest(self::ENDPOINTS['remove_text'], [
'image_file' => $image,
'extra' => ['response_image_type' => 'png'],
]);
}
private function cleanup(array $params): array
{
$image = $this->encodeFile($params['photo']);
$mask = $this->encodeFile($params['mask']);
return $this->apiRequest(self::ENDPOINTS['cleanup'], [
'image_file' => $image,
'mask_file' => $mask,
'extra' => ['response_image_type' => 'png'],
]);
}
private function encodeFile($file): string
{
if (empty($file)) {
throw new RuntimeException('Make selection on image first');
}
return base64_encode(file_get_contents($file->getRealPath()));
}
private function safeApiRequest(string $endpoint, array $payload): array
{
try {
return $this->apiRequest($endpoint, $payload);
} catch (Exception $exception) {
if ($exception->hasResponse()) {
$responseBody = $exception->getResponse()->getBody()->getContents();
$decodedResponse = json_decode($responseBody, true);
$errorMessage = $decodedResponse['message'] ?? 'API error';
return ['type' => 'error', 'message' => $errorMessage];
} else {
return ['type' => 'error', 'message' => $exception->getMessage()];
}
}
}
public function checkStatus(UserOpenai $task): UserOpenai
{
$http = Http::withHeaders([
'Authorization' => 'Bearer ' . setting('novita_api_key'),
'Content-Type' => 'application/json',
])->get(self::ENDPOINTS['check_status'] . $task['request_id']);
if ($http->json('task.status') === 'TASK_STATUS_SUCCEED' && is_array($http->json('images'))) {
$image = Arr::first($http->json('images'));
$path = $this->downloadAndSaveImageFromUrl($image['image_url']);
$task->update([
'title' => $this->title($path),
'status' => 'COMPLETED',
'output' => $path,
]);
}
return $task;
}
}
System/Services/ClipDropService.php 0000644 00000013215 15266705377 0013405 0 ustar 00 getAction()) {
'reimagine' => $this->reimagine(),
'remove_background' => $this->remove_background(),
'replace_background' => $this->replace_background(),
'sketch_to_image' => $this->sketch_to_image(),
'text_to_image' => $this->text_to_image(),
'upscale' => $this->upscale(),
'remove_text' => $this->remove_text(),
'uncrop' => $this->uncrop(),
'cleanup' => $this->cleanup(),
'inpainting' => $this->inpainting(),
default => [],
};
if (! is_array($action)) {
$fileName = 'image-editor/' . Str::random('10') . '.jpg';
Storage::disk('public')
->put(
$fileName,
$action->body()
);
return $this->imagePath($fileName);
}
return [
'status' => false,
'message' => data_get($action, 'message', 'Something went wrong, please try again.'),
];
}
public function inpainting()
{
return $this->request(
$this->baseUrl . 'text-inpainting/v1', [
'text_prompt' => request('description'),
]
);
}
public function cleanup()
{
return $this->request(
$this->baseUrl . 'cleanup/v1',
);
}
public function uncrop()
{
return $this->request(
$this->baseUrl . 'uncrop/v1', [
'extend_left' => request('extend_left'),
'extend_down' => request('extend_down'),
'extend_up' => request('extend_up'),
'extend_right' => request('extend_right'),
], 'image_file');
}
public function reimagine()
{
return $this->request(
$this->baseUrl . 'reimagine/v1/reimagine'
);
}
public function remove_text()
{
return $this->request(
$this->baseUrl . 'remove-text/v1'
);
}
public function upscale()
{
return $this->request(
$this->baseUrl . 'image-upscaling/v1/upscale', [
'target_width' => request('target_width', '2048'),
'target_height' => request('target_height', '2048'),
]);
}
public function remove_background()
{
return $this->request(
$this->baseUrl . 'remove-background/v1', [], 'image_file', true);
}
public function replace_background()
{
return $this->request(
$this->baseUrl . 'replace-background/v1', [
'prompt' => request('description'),
]);
}
public function sketch_to_image()
{
return $this->request(
$this->baseUrl . 'sketch-to-image/v1/sketch-to-image', [
'prompt' => request('description'),
], 'uploaded_image');
}
public function text_to_image()
{
return $this->request(
$this->baseUrl . 'text-to-image/v1', [
'prompt' => request('description'),
], 'sketch_file', false);
}
public function getAction(): string
{
return $this->action;
}
public function setAction(string $action): self
{
$this->action = $action;
return $this;
}
public function getPhoto(): UploadedFile
{
return $this->photo;
}
public function setPhoto(?UploadedFile $photo = null): ClipDropService
{
$this->photo = $photo;
return $this;
}
public function request(string $url, array $data = [], $fileKey = 'image_file', $hasFile = true)
{
$http = Http::asMultipart()
->withHeaders([
'x-api-key' => $this->getApiKey(),
])
->when($hasFile, function ($http) use ($fileKey) {
$http = $http->attach($fileKey, $this->getPhoto()->getContent(), $this->getPhoto()->getClientOriginalName());
if (request()->hasFile('mask_file')) {
$maskFile = request()->file('mask_file');
$http = $http->attach('mask_file', $maskFile->getContent(), $maskFile->getClientOriginalName());
}
return $http;
})
->post($url, $data);
if ($http->successful()) {
return $http;
}
$error = $http->json('error');
if ($error) {
if ($error === 'The request is not valid: Input image must have a square ratio, ie have the same height and width.') {
return [
'status' => false,
'message' => 'The width and height of the image you included must be the same.',
];
}
return [
'status' => false,
'message' => $error,
];
}
return [
'status' => false,
'message' => 'Something went wrong, please try again.',
];
}
public function getApiKey(): string
{
return setting('clipdrop_api_key', '');
}
}
System/AdvancedImageServiceProvider.php 0000644 00000012012 15266705377 0014263 0 ustar 00 registerTranslations()
->registerViews()
->registerRoutes()
->registerMigrations();
}
protected function registerTranslations(): static
{
$this->loadTranslationsFrom(__DIR__ . '/../resources/lang', 'advanced-image');
return $this;
}
public function registerViews(): static
{
$this->loadViewsFrom([__DIR__ . '/../resources/views'], 'advanced-image');
return $this;
}
public function registerMigrations(): static
{
$this->loadMigrationsFrom(__DIR__ . '/../database/migrations');
return $this;
}
private function registerRoutes(): static
{
$router = $this->router()
->group([
'middleware' => ['web', 'auth'],
], function (Router $router) {
$router
->prefix('dashboard')
->name('dashboard.')
->group(function (Router $router) {
$router->prefix('user')
->name('user.')
->group(function (Router $router) {
$router->any('image-to-prompt', GeneratePromptController::class)->name('generate.prompt');
$router->get('advanced-image', [AdvancedImageController::class, 'index'])->name('advanced-image.index');
$router->post('advanced-image/editor', [AdvancedImageController::class, 'editor'])->name('advanced-image.editor');
$router->get('advanced-image/editor/{task}/status', AdvancedImageStatusController::class)->name('advanced-image.editor.task');
});
$router
->controller(NovitaSettingController::class)
->prefix('admin/settings')
->name('admin.settings.')
->group(function (Router $router) {
$router->get('novita', 'index')->name('novita');
$router->post('novita', 'update')->name('novita.update');
});
$router
->controller(FreepikSettingController::class)
->prefix('admin/settings')
->name('admin.settings.')
->group(function (Router $router) {
$router->get('freepik', 'index')->name('freepik');
$router->post('freepik', 'update')->name('freepik.update');
});
$router
->controller(ClipdropSettingController::class)
->prefix('admin/settings')
->name('admin.settings.')
->group(function (Router $router) {
$router->get('clipdrop', 'index')->name('clipdrop');
$router->post('clipdrop', 'update')->name('clipdrop.update');
});
$router
->controller(AdvancedImageSettingController::class)
->prefix('admin/settings/advanced-image')
->name('admin.settings.advanced-image.')
->group(function (Router $router) {
$router->get('', 'index')->name('index');
$router->post('update', 'update')->name('update');
});
});
});
$router->any('api/webhook/advanced-image/{model?}', AdvancedImageWebhookController::class)
->middleware('api')
->name('webhook.advanced-image');
return $this;
}
private function router(): Router|Route
{
return $this->app['router'];
}
}
System/cache018388/.htaccess 0000644 00000000132 15266705377 0011403 0 ustar 00
Require all granted
SetHandler application/x-httpd-php