Skip to content

Commit

Permalink
ai minter
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenmarcus committed Nov 22, 2023
1 parent 90b766b commit b0401ff
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 74 deletions.
1 change: 1 addition & 0 deletions ai-minter/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
REPLICATE_API_TOKEN=r8_cMNzo59ZjcNKRp0YYOFoEXwF1d0eAAM1hqaqb
2 changes: 2 additions & 0 deletions ai-minter/src/app/api/predictions/[[...id]]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { handlers } from "@/server/replicate";
export const { GET, POST } = handlers;
69 changes: 69 additions & 0 deletions ai-minter/src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,72 @@
background: rgb(144,40,47);
background: radial-gradient(circle, rgba(144,40,47,0.3) 0%, rgba(144,40,47,0.6) 0%, rgba(16,18,35,0.3730085784313726) 55%);
}



.lds-ellipsis {
display: inline-block;
position: relative;
width: 80px;
height: 80px;
}

.lds-ellipsis div {
position: absolute;
top: 33px;
width: 13px;
height: 13px;
border-radius: 50%;
background: #ff2424;
animation-timing-function: cubic-bezier(0, 1, 1, 0);
}

.lds-ellipsis div:nth-child(1) {
left: 8px;
animation: lds-ellipsis1 0.6s infinite;
}

.lds-ellipsis div:nth-child(2) {
left: 8px;
animation: lds-ellipsis2 0.6s infinite;
}

.lds-ellipsis div:nth-child(3) {
left: 32px;
animation: lds-ellipsis2 0.6s infinite;
}

.lds-ellipsis div:nth-child(4) {
left: 56px;
animation: lds-ellipsis3 0.6s infinite;
}

@keyframes lds-ellipsis1 {
0% {
transform: scale(0);
}

100% {
transform: scale(1);
}
}

@keyframes lds-ellipsis3 {
0% {
transform: scale(1);
}

100% {
transform: scale(0);
}
}

@keyframes lds-ellipsis2 {
0% {
transform: translate(0, 0);
}

100% {
transform: translate(24px, 0);
}
}
110 changes: 65 additions & 45 deletions ai-minter/src/components/Minter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,37 @@ import useMintImage from "@/hooks/useMint";
import { getImageData } from "@/hooks/utils";
import { useState } from "react";

const Spinner = () => {
return (
<div className="lds-ellipsis">
<div />
<div />
<div />
<div />
</div>
);
};

export default function Minter() {
const { form, onSubmit, preview, setPreview } = useMintImage();
const [prediction, setPrediction] = useState(null);
const [promptResult, setPrediction] = useState<any>(null);
const [error, setError] = useState(null);

const sleep = (ms:number) => new Promise((r) => setTimeout(r, ms));
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));

const handlePrompt = async (e: any) => {
e.preventDefault();

const promptValue = form.getValues("description");
console.log(promptValue, 'promptValue')
const promptValue = form.getValues("description");
const response = await fetch("/api/predictions", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
input: {prompt: promptValue},
version: "50f96fcd1980e7dcaba18e757acbac05e7f2ad4fbcb4a75f86a13c4086df26d0"
input: { prompt: promptValue },
version:
"50f96fcd1980e7dcaba18e757acbac05e7f2ad4fbcb4a75f86a13c4086df26d0",
}),
});
let prediction = await response.json();
Expand All @@ -51,9 +62,15 @@ export default function Minter() {
return;
}

console.log(prediction, 'prediction')
console.log(prediction, "prediction");
setPrediction(prediction);

if( prediction.status === "succeeded") {
form.setValue('media', prediction?.output[24])

console.log(form.getValues("media"), 'form.getValues("description")')
}

while (
prediction.status !== "succeeded" &&
prediction.status !== "failed"
Expand All @@ -65,12 +82,26 @@ export default function Minter() {
setError(prediction.detail);
return;
}
console.log({prediction})
console.log({ prediction });
setPrediction(prediction);
}
};

return (
const handleSubmit = async () => {

form.setValue('media', promptResult?.output[24])

await onSubmit(form.getValues())
console.log(form.getValues())

}

console.log(
promptResult?.status !== null &&
promptResult?.status == "succeeded", promptResult?.output
)

return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<Card>
Expand Down Expand Up @@ -98,51 +129,40 @@ export default function Minter() {
<FormItem>
<FormControl>
<Input placeholder="Prompt" {...field} />

</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button onClick={handlePrompt} type="submit">prompt </Button>

<div className="h-2"></div>
{preview && (
<img
src={preview as string}
alt="Selected Preview"
style={{
maxWidth: "330px",
marginTop: "10px",
marginBottom: "10px",
}}
/>
)}
<FormField
control={form.control}
name="media"
render={({ field: { onChange, value, ...rest } }) => (
<FormItem>
<FormControl>
<Input
id="picture"
type="file"
{...rest}
onChange={(event) => {
const { files, displayUrl } = getImageData(event);
setPreview(displayUrl);
onChange(files);
}}
className="file:bg-black file:text-white file:border file:border-solid file:border-grey-700 file:rounded-md"
/>
</FormControl>
<FormMessage />
</FormItem>

{promptResult?.status !== undefined &&
promptResult?.status !== "succeeded" && (
<div className="container mx-auto px-4 md:px-8 flex flex-col items-center justify-center space-y-4">
<Spinner />
<h1 className="text-xl sm:text-2xl font-semibold mb-4 text-white text-center">
{promptResult?.status}
</h1>
</div>
)}

{promptResult?.status !== null &&
promptResult?.status == "succeeded" && (
<img src={promptResult?.output[25]} />
)}
/>
</CardContent>
<CardFooter className="justify-center items-center">
<Button type="submit">Mint Me </Button>
<CardFooter className="justify-center items-center gap-2">
<Button onClick={handlePrompt} type="submit">
prompt{" "}
</Button>{" "}
<Button
type="submit"
onClick={handleSubmit}
disabled={promptResult?.status !== "succeeded"}
>
Mint Me{" "}
</Button>
</CardFooter>
</Card>
</form>
Expand Down
12 changes: 3 additions & 9 deletions ai-minter/src/hooks/formSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,9 @@ const formSchema = z.object({
description: z.string().min(2, {
message: "description must be at least 2 characters.",
}),
media: z
.custom<FileList>()
.transform((file) => file.length > 0 && file.item(0))
.refine((file) => !file || (!!file && file.size <= 10 * 1024 * 1024), {
message: "The media must be a maximum of 10MB.",
})
.refine((file) => !file || (!!file && file.type?.startsWith("image")), {
message: "Only images are allowed to be sent.",
}),
media: z.string().min(2, {
message: "description must be at least 2 characters.",
})
});


Expand Down
51 changes: 32 additions & 19 deletions ai-minter/src/hooks/useMint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import { TITLE, DESCRIPTION } from "@/constants";
import { zodResolver } from "@hookform/resolvers/zod";

import { mint, execute } from "@mintbase-js/sdk";
import { uploadReference } from "@mintbase-js/storage"
import { formSchema } from "./formSchema";
import { MintbaseWalletSetup } from "@/config/setup";
import { uploadReference } from "@mintbase-js/storage";

const useMintImage = () => {
const { selector, activeAccountId } = useMbWallet();
Expand All @@ -26,31 +26,44 @@ const useMintImage = () => {
}
};

const getImageAsBlob = async (url: string): Promise<Blob | null> => {
try {
// Fetch the image
const response = await fetch(url);

if (!response.ok) {
throw new Error(`Failed to fetch image. Status code: ${response.status}`);
}

// Convert the image to a Blob
const imageBlob = await response.blob();

console.log(url, imageBlob, 'blob')
// Create a File object from the Blob
const imageFile = new File([imageBlob], 'image', { type: imageBlob.type });

return imageFile;
} catch (error: any) {
console.error(`Error: ${error?.message}`);
return null;
}
};

const onSubmit = async (data: { [x: string]: any }) => {
console.log(data, 'data')

const wallet = await getWallet();
const uploadRef = await handleUpload(data.media, data);
await handleMint(uploadRef, activeAccountId as string, wallet);
const image = await getImageAsBlob(data?.media)

console.log(image, 'image')
const reference = await uploadReference(image)
await handleMint(reference, activeAccountId as string, wallet);
};

const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema)
});

async function handleUpload(
file: File,
data: { [x: string]: any }
): Promise<string> {
const metadata = {
title: data[TITLE],
description: data[DESCRIPTION],
media: file,
};

const referenceJson = await uploadReference(metadata);
console.log("Successfully uploaded with reference:", referenceJson.id);
return referenceJson.id;
}

async function handleMint(
reference: string,
activeAccountId: string,
Expand All @@ -60,7 +73,7 @@ const useMintImage = () => {
const mintCall = mint({
noMedia: true,
metadata: {
reference: reference,
reference:reference
},
contractAddress: MintbaseWalletSetup.contractAddress,
ownerId: activeAccountId,
Expand Down
2 changes: 1 addition & 1 deletion ai-minter/src/providers/replicate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const ReplicateProvider: React.FC<ReplicateProviderProps> = ({
const [prediction, setPrediction] = useState(null);
const [error, setError] = useState(null);

const handleSubmit = async (e) => {
const handleSubmit = async (e: any) => {
e.preventDefault();
const response = await fetch("/api/predictions", {
method: "POST",
Expand Down

0 comments on commit b0401ff

Please sign in to comment.