diff --git a/ai-minter/.env.example b/ai-minter/.env.example
new file mode 100644
index 00000000..24ad6f22
--- /dev/null
+++ b/ai-minter/.env.example
@@ -0,0 +1 @@
+REPLICATE_API_TOKEN=r8_cMNzo59ZjcNKRp0YYOFoEXwF1d0eAAM1hqaqb
\ No newline at end of file
diff --git a/ai-minter/src/app/api/predictions/[[...id]]/route.ts b/ai-minter/src/app/api/predictions/[[...id]]/route.ts
new file mode 100644
index 00000000..ee0751e7
--- /dev/null
+++ b/ai-minter/src/app/api/predictions/[[...id]]/route.ts
@@ -0,0 +1,2 @@
+import { handlers } from "@/server/replicate";
+export const { GET, POST } = handlers;
diff --git a/ai-minter/src/app/globals.css b/ai-minter/src/app/globals.css
index 11979362..c3167ed5 100644
--- a/ai-minter/src/app/globals.css
+++ b/ai-minter/src/app/globals.css
@@ -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);
+ }
+}
\ No newline at end of file
diff --git a/ai-minter/src/components/Minter.tsx b/ai-minter/src/components/Minter.tsx
index 0483e2f2..01b18ee1 100644
--- a/ai-minter/src/components/Minter.tsx
+++ b/ai-minter/src/components/Minter.tsx
@@ -23,26 +23,37 @@ import useMintImage from "@/hooks/useMint";
import { getImageData } from "@/hooks/utils";
import { useState } from "react";
+const Spinner = () => {
+ return (
+
+ );
+};
+
export default function Minter() {
const { form, onSubmit, preview, setPreview } = useMintImage();
- const [prediction, setPrediction] = useState(null);
+ const [promptResult, setPrediction] = useState(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();
@@ -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"
@@ -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 (
diff --git a/ai-minter/src/hooks/formSchema.ts b/ai-minter/src/hooks/formSchema.ts
index 8feadd66..7ec2d689 100644
--- a/ai-minter/src/hooks/formSchema.ts
+++ b/ai-minter/src/hooks/formSchema.ts
@@ -9,15 +9,9 @@ const formSchema = z.object({
description: z.string().min(2, {
message: "description must be at least 2 characters.",
}),
- media: z
- .custom()
- .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.",
+ })
});
diff --git a/ai-minter/src/hooks/useMint.ts b/ai-minter/src/hooks/useMint.ts
index 7b56d7ab..65ec8191 100644
--- a/ai-minter/src/hooks/useMint.ts
+++ b/ai-minter/src/hooks/useMint.ts
@@ -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();
@@ -26,31 +26,44 @@ const useMintImage = () => {
}
};
+ const getImageAsBlob = async (url: string): Promise => {
+ 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>({
resolver: zodResolver(formSchema)
});
- async function handleUpload(
- file: File,
- data: { [x: string]: any }
- ): Promise {
- 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,
@@ -60,7 +73,7 @@ const useMintImage = () => {
const mintCall = mint({
noMedia: true,
metadata: {
- reference: reference,
+ reference:reference
},
contractAddress: MintbaseWalletSetup.contractAddress,
ownerId: activeAccountId,
diff --git a/ai-minter/src/providers/replicate.tsx b/ai-minter/src/providers/replicate.tsx
index 512c10cb..22600d2f 100644
--- a/ai-minter/src/providers/replicate.tsx
+++ b/ai-minter/src/providers/replicate.tsx
@@ -41,7 +41,7 @@ export const ReplicateProvider: React.FC = ({
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",