# Auto-generate titles, descriptions & tags for Supabase uploads [View original](https://ittybit.com/guides/supabase/auto-generate-titles-descriptions-and-tags-for-supabase-uploads) ## Step 1: Create a Supabase storage bucket You can use an existing storage bucket or create a new one. If you haven't already created a bucket, you can do so with the following SQL script with the [Supabase SQL editor](https://supabase.com/features/sql-editor): ```sql insert into storage.buckets (id, name) values ('ittybit-storage', 'ittybit-storage'); ``` *** ## Step 2: Upload a file to Supabase storage bucket We will start by uploading a media file to the bucket. Here's a sample (using [Supabase Edge Functions](https://supabase.com/docs/guides/functions)) which uploads a file to a bucket called `ittybit-storage`. ```ts // Setup type definitions for built-in Supabase Runtime APIs import "jsr:@supabase/functions-js/edge-runtime.d.ts"; import { createClient } from "jsr:@supabase/supabase-js@2"; const supabase = createClient( Deno.env.get("SUPABASE_URL"), Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") ); Deno.serve(async (req) => { const formData = await req.formData(); const file = formData.get("file") as File; const bucket = supabase.storage.from("ittybit-storage"); const path = `/${file.name}`; const { data: uploadData, error: uploadError } = await bucket.upload( path, file, { contentType: file.type, } ); if (uploadError) throw uploadError; console.log("Upload data:", uploadData); }); ``` *** ## Step 3: Get a signed URL A signed URL gives ittybit temporary access to a file in your supabase bucket. ```ts Deno.serve(async (req) => { // ... the rest of your code ... console.log("Upload data:", uploadData); const { data: signedUrlData, error: signedUrlError } = await bucket.createSignedUrl(path, 60); if (signedUrlError) throw signedUrlError; const signedUrl = signedUrlData.signedUrl; console.log("Signed URL:", signedUrl); }); ``` *** ## Step 4: Send a POST request to ittybit tasks API **Prerequisite**: This section uses the [ittybit TypeScript SDK](https://ittybit.com/sdks/typescript). Make sure it's installed in your project. ```bash npm install @ittybit/sdk ``` Next, use the ittybit SDK to create an [intelligence task](https://ittybit.com/docs/intelligence) with the signed URL from Supabase Storage. If you don’t have a webhook endpoint ready, you can use a webhook site placeholder (such as [webhook.site](https://webhook.site)) for the `webhook_url`. ```ts import { IttybitClient } from "@ittybit/sdk"; const ittybit = new IttybitClient({ apiKey: process.env.ITTYBIT_API_KEY! }); Deno.serve(async (req) => { // ... the rest of your code ... console.log("Signed URL:", signedUrl); const webhookUrl = "https://webhook.site/"; const task = await ittybit.tasks.create({ url: signedUrl, kind: "description", metadata: { object_id: objectId, }, webhook_url: webhookUrl, }); console.log("Task created:", task.id); return new Response(JSON.stringify({ data: task }), { headers: { "Content-Type": "application/json" }, }); ``` *** ## Step 5: Create a table to store the intelligence results Run the below SQL script in your [Supabase SQL editor](https://supabase.com/features/sql-editor). ```sql CREATE TABLE IF NOT EXISTS public.ittybit_intelligence ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), title varchar, description varchar, tags jsonb, object_id uuid NOT NULL, CONSTRAINT ittybit_intelligence_object_fk FOREIGN KEY (object_id) REFERENCES storage.objects (id) ON DELETE CASCADE ); ``` This will create a table called `ittybit_intelligence` in your Supabase project. *** ## Step 6: Set up a webhook receiver function To capture task results from ittybit and insert them into your Supabase database, you need a webhook endpoint. This endpoint listens for POST requests from ittybit once a task completes. Here's a sample [Supabase Edge Function](https://supabase.com/docs/guides/functions): This function validates the incoming request, then writes the results into `ittybit_intelligence` within your Supabase Project. ```ts // Setup type definitions for built-in Supabase Runtime APIs import "jsr:@supabase/functions-js/edge-runtime.d.ts"; import { createClient } from "jsr:@supabase/supabase-js@2"; const supabaseUrl = Deno.env.get("SUPABASE_URL"); const supabaseServiceRoleKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY"); if (!supabaseUrl || !supabaseServiceRoleKey) { throw new Error("SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY must be set"); } const supabase = createClient(supabaseUrl, supabaseServiceRoleKey); const table = "ittybit_intelligence" Deno.serve(async (req) => { const { title, description, tags, metadata } = await req.json(); const object_id = metadata?.object_id; if (!object_id) { console.error("metadata.object_id is required"); return new Response("Missing object_id", { status: 400 }); } const { error } = await supabase.from(table).insert([ { object_id, title, description, tags } ]); if (error) { console.error(error); return new Response(`Insert failed: ${error.message}`, { status: 500 }); } console.log(`Successfully inserted ${object_id} into ${table}`) return new Response("Inserted into DB", { status: 200 }); }); ``` *** ## Step 7: Update the task's webhook\_url You can now set the `webhook_url` property to your Supabase Edge function's public URL. **PLACEHOLDER IMAGE FOR SUPABASE EDGE FUNCTIONS PUBLIC URL** ```ts // ... the rest of your code ... const webhookUrl = "https://your-supabase-domain.supabase.co/functions/v1/ittybit-webhook"; // ... the rest of your code ... ``` You can now test end to end by uploading a file to Supabase Storage and checking the webhook endpoint for the results. *** ## Full example ```ts // Setup type definitions for built-in Supabase Runtime APIs import "jsr:@supabase/functions-js/edge-runtime.d.ts"; import { createClient } from "jsr:@supabase/supabase-js@2"; import { IttybitClient } from "npm:@ittybit/sdk"; const supabase = createClient( Deno.env.get("SUPABASE_URL"), Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") ); const ittybit = new IttybitClient({ apiKey: Deno.env.get("ITTYBIT_API_KEY"), }); Deno.serve(async (req) => { const formData = await req.formData(); const file = formData.get("file") as File; const bucket = supabase.storage.from("ittybit-storage"); const path = `/${file.name}`; const { data: uploadData, error: uploadError } = await bucket.upload( path, file, { contentType: file.type, } ); if (uploadError) throw uploadError; const { data: signedUrlData, error: signedUrlError } = await bucket.createSignedUrl(path, 60); if (signedUrlError) throw signedUrlError; const objectId = uploadData.id; const signedUrl = signedUrlData.signedUrl; const webhookUrl = "https://webhook.site/"; const task = await ittybit.tasks.create({ url: signedUrl, kind: "description", metadata: { object_id: objectId, }, webhook_url: webhookUrl, }); return new Response(JSON.stringify({ data: task }), { headers: { "Content-Type": "application/json" }, }); }); ``` ```ts // Setup type definitions for built-in Supabase Runtime APIs import "jsr:@supabase/functions-js/edge-runtime.d.ts"; import { createClient } from "jsr:@supabase/supabase-js@2"; const supabaseUrl = Deno.env.get("SUPABASE_URL"); const supabaseServiceRoleKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY"); if (!supabaseUrl || !supabaseServiceRoleKey) { throw new Error("SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY must be set"); } const supabase = createClient(supabaseUrl, supabaseServiceRoleKey); const table = "ittybit_intelligence" Deno.serve(async (req) => { const { title, description, tags, metadata } = await req.json(); const object_id = metadata?.object_id; if (!object_id) { console.error("metadata.object_id is required"); return new Response("Missing object_id", { status: 400 }); } const { error } = await supabase.from(table).insert([ { object_id, title, description, tags } ]); if (error) { console.error(error); return new Response(`Insert failed: ${error.message}`, { status: 500 }); } console.log(`Successfully inserted ${object_id} into ${table}`) return new Response("Inserted into DB", { status: 200 }); }); ``` ## Conclusion When ittybit finishes processing the file, it will send the title, description, and tags to your webhook endpoint, and they will be inserted automatically into your Supabase database. You now have a working pipeline where: * Files are uploaded to Supabase Storage. * Tasks are created in ittybit using signed URLs. * Once processing is complete, ittybit delivers the results to your webhook endpoint. * The webhook inserts the metadata directly into your Supabase database. This gives you a fully automated flow without the need for manual polling.