Skip to content

Instantly share code, notes, and snippets.

@monteiro
Created October 17, 2024 07:30
Show Gist options
  • Save monteiro/304a392a725bd12f222452d0277c5842 to your computer and use it in GitHub Desktop.
Save monteiro/304a392a725bd12f222452d0277c5842 to your computer and use it in GitHub Desktop.
Check contents of the image using free gemini 1.5 turbo
@php use Illuminate\Support\Str; @endphp
<div class="p-6 bg-gray-100 rounded-md w-full max-w-md mx-auto">
<div class="mb-4">
<label for="prompt" class="block text-sm font-medium text-gray-700 mb-1">Prompt:</label>
<input type="text" id="prompt" wire:model="prompt"
class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:border-indigo-500 focus:ring focus:ring-indigo-200">
</div>
<div class="mb-4">
<label for="image" class="block text-sm font-medium text-gray-700 mb-1">Image:</label>
<input type="file" id="image" wire:model="image"
class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:border-indigo-500 focus:ring focus:ring-indigo-200">
</div>
@if($loading)
<div class="flex items-center justify-center mb-4">
<svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-gray-500" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v8z"></path>
</svg>
<span>Loading...</span>
</div>
@endif
<div>
<button wire:click="submit"
class="px-4 py-2 bg-indigo-500 text-white rounded-md shadow hover:bg-indigo-700 focus:outline-none focus:ring focus:ring-indigo-200">
Submit
</button>
</div>
@if($response)
<div class="mt-4 p-4 bg-white rounded-md shadow">
<h3 class="text-lg font-medium mb-2">Response:</h3>
<div class="prose">
{!! Str::markdown($response) !!}
</div>
</div>
@endif
</div>
<?php
namespace App\Livewire;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use Livewire\Component;
use Livewire\WithFileUploads;
class ImageChecker extends Component
{
use WithFileUploads;
public $prompt;
public $image;
public $response;
public $loading = false;
public function submit()
{
$this->validate([
'image' => 'required|image|max:10240',
]);
$this->loading = true;
try {
$apiKey = env('GOOGLE_API_KEY');
$imagePath = $this->image->store('uploads');
$imageFullPath = Storage::path($imagePath);
// Get mime type and content length
$mimeType = mime_content_type($imageFullPath);
$contentLength = filesize($imageFullPath);
// Step 1: Initial resumable request defining metadata
$metadataResponse = Http::withHeaders([
'X-Goog-Upload-Protocol' => 'resumable',
'X-Goog-Upload-Command' => 'start',
'X-Goog-Upload-Header-Content-Length' => $contentLength,
'X-Goog-Upload-Header-Content-Type' => $mimeType,
'Content-Type' => 'application/json',
])->post("https://generativelanguage.googleapis.com/upload/v1beta/files?key={$apiKey}", [
'file' => [
'display_name' => basename($imageFullPath),
],
]);
if (!$metadataResponse->successful()) {
throw new \Exception('Failed to initiate resumable upload. Response: ' . $metadataResponse->body());
}
// Extract upload URL from the response headers
$uploadUrl = $metadataResponse->header('X-Goog-Upload-URL');
if (!$uploadUrl) {
throw new \Exception('Upload URL not found in response.');
}
// Step 2: Upload the actual bytes
$uploadResponse = Http::withHeaders([
'Content-Length' => $contentLength,
'X-Goog-Upload-Offset' => 0,
'X-Goog-Upload-Command' => 'upload, finalize',
])->withBody(file_get_contents($imageFullPath), $mimeType)
->post($uploadUrl);
if (!$uploadResponse->successful()) {
throw new \Exception('Failed to upload image data. Response: ' . $uploadResponse->body());
}
$fileUri = $uploadResponse->json('file.uri');
if (!$fileUri) {
throw new \Exception('No file URI returned in the response.');
}
// Step 3: Generate content using the uploaded file
$url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key={$apiKey}";
$data = [
'contents' => [
[
'parts' => [
[
'file_data' => [
'file_uri' => $fileUri,
'mime_type' => $mimeType,
]
],
[
'text' => 'Describe this image'
],
],
],
],
'generationConfig' => [
'temperature' => 1,
'topK' => 64,
'topP' => 0.95,
'maxOutputTokens' => 8192,
'responseMimeType' => 'text/plain'
],
];
$response = Http::withHeaders([
'Content-Type' => 'application/json',
])->post($url, $data);
if ($response->successful()) {
$this->response = $response->json('candidates')[0]['content']['parts'][0]['text'] ?? 'No response content found.';
} else {
throw new \Exception('Failed to generate content. Response: ' . $response->body());
}
} catch (\Exception $e) {
$this->response = 'Error: ' . $e->getMessage();
}
$this->loading = false;
}
public function render()
{
return view('livewire.image-checker');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment