forked from mito-systems/sol-mem-gen
Upload generated meme to Pinata #9
@ -1,3 +1,4 @@
|
|||||||
|
# Get key from https://fal.ai
|
||||||
FAL_AI_KEY=
|
FAL_AI_KEY=
|
||||||
|
|
||||||
NEXT_PUBLIC_MTM_TOKEN_MINT=97RggLo3zV5kFGYW4yoQTxr4Xkz4Vg2WPHzNYXXWpump
|
NEXT_PUBLIC_MTM_TOKEN_MINT=97RggLo3zV5kFGYW4yoQTxr4Xkz4Vg2WPHzNYXXWpump
|
||||||
@ -5,3 +6,7 @@ NEXT_PUBLIC_PAYMENT_RECEIVER_ADDRESS=FFDx3SdAEeXrp6BTmStB4BDHpctGsaasZq4FFcowRob
|
|||||||
NEXT_PUBLIC_SOLANA_RPC_URL=https://young-radial-orb.solana-mainnet.quiknode.pro/67612b364664616c29514e551bf5de38447ca3d4
|
NEXT_PUBLIC_SOLANA_RPC_URL=https://young-radial-orb.solana-mainnet.quiknode.pro/67612b364664616c29514e551bf5de38447ca3d4
|
||||||
NEXT_PUBLIC_SOLANA_WEBSOCKET_URL=wss://young-radial-orb.solana-mainnet.quiknode.pro/67612b364664616c29514e551bf5de38447ca3d4
|
NEXT_PUBLIC_SOLANA_WEBSOCKET_URL=wss://young-radial-orb.solana-mainnet.quiknode.pro/67612b364664616c29514e551bf5de38447ca3d4
|
||||||
NEXT_PUBLIC_USDC_MINT=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
|
NEXT_PUBLIC_USDC_MINT=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
|
||||||
|
|
||||||
|
# Get keys from https://app.pinata.cloud/developers/api-keys
|
||||||
|
PINATA_JWT=
|
||||||
|
PINATA_GATEWAY=
|
||||||
|
23
README.md
23
README.md
@ -16,31 +16,38 @@ This project is a Solana-based meme generator that allows users to connect their
|
|||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
1. Install dependencies:
|
- Install dependencies:
|
||||||
```sh
|
```sh
|
||||||
npm install
|
npm install
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Copy the `.env.example` file to `.env.local` and add your FAL AI key:
|
- Copy the `.env.example` file to `.env.local` and add your API keys:
|
||||||
```sh
|
```sh
|
||||||
cp .env.example .env.local
|
cp .env.example .env.local
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Add your FAL AI key to the `.env.local` file:
|
- Add your FAL AI key to the `.env.local` file:
|
||||||
```env
|
```env
|
||||||
# Get key from https://fal.ai/
|
# Get key from https://fal.ai/
|
||||||
FAL_AI_KEY=your_fal_ai_key
|
FAL_AI_KEY=your_fal_ai_key
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Run the development server:
|
- Setup a project on <https://app.pinata.cloud> then add the following to `.env.example`:
|
||||||
|
```env
|
||||||
|
# Get keys from https://app.pinata.cloud/developers/api-keys
|
||||||
|
PINATA_JWT=
|
||||||
|
PINATA_GATEWAY=
|
||||||
|
```
|
||||||
|
|
||||||
|
- Run the development server:
|
||||||
```sh
|
```sh
|
||||||
npm run dev
|
npm run dev
|
||||||
```
|
```
|
||||||
|
|
||||||
5. Open your browser and navigate to `http://localhost:3000`.
|
- Open your browser and navigate to `http://localhost:3000`.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
1. Connect your Solflare or Phantom wallet using the "Connect Wallet" button.
|
- Connect your Solflare or Phantom wallet using the "Connect Wallet" button.
|
||||||
2. Select an AI model and enter a prompt to generate a meme.
|
- Select an AI model and enter a prompt to generate a meme.
|
||||||
3. Pay the required MTM tokens and wait for the meme to be generated.
|
- Pay the required MTM tokens and wait for the meme to be generated.
|
||||||
|
2081
package-lock.json
generated
2081
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -18,6 +18,7 @@
|
|||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.4.7",
|
||||||
"next": "13.5.4",
|
"next": "13.5.4",
|
||||||
"openai": "^4.77.0",
|
"openai": "^4.77.0",
|
||||||
|
"pinata-web3": "^0.5.4",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
"sqlite3": "^5.1.7",
|
"sqlite3": "^5.1.7",
|
||||||
|
@ -5,6 +5,7 @@ import { fal } from "@fal-ai/client"
|
|||||||
import { FLUX_MODELS } from '../../../services/fluxService'
|
import { FLUX_MODELS } from '../../../services/fluxService'
|
||||||
import { initializeDataSource } from '../../../data-source'
|
import { initializeDataSource } from '../../../data-source'
|
||||||
import { verifyPayment, markSignatureAsUsed } from '../../../utils/verifyPayment';
|
import { verifyPayment, markSignatureAsUsed } from '../../../utils/verifyPayment';
|
||||||
|
import { uploadToPinata } from '../../../utils/uploadToPinata';
|
||||||
|
|
||||||
if (!process.env.FAL_AI_KEY) {
|
if (!process.env.FAL_AI_KEY) {
|
||||||
throw new Error('FAL_AI_KEY is not configured in environment variables')
|
throw new Error('FAL_AI_KEY is not configured in environment variables')
|
||||||
@ -97,7 +98,18 @@ export async function POST(req: NextRequest): Promise<NextResponse> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return NextResponse.json({ imageUrl })
|
const pinataResult = await uploadToPinata(imageUrl);
|
||||||
|
|
||||||
|
if (pinataResult.error) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Failed to upload image to Pinata' },
|
||||||
|
{ status: 500 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const publicUrl = pinataResult.imageUrl;
|
||||||
|
|
||||||
|
return NextResponse.json({ imageUrl: publicUrl })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Flux generation error:', error)
|
console.error('Flux generation error:', error)
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
|
@ -87,10 +87,10 @@ const Page: React.FC = (): React.ReactElement => {
|
|||||||
|
|
||||||
if (!transactionSignature) {
|
if (!transactionSignature) {
|
||||||
return { error: 'Transaction signature not found' }
|
return { error: 'Transaction signature not found' }
|
||||||
}
|
};
|
||||||
|
|
||||||
// Generate image with specified model and transaction reference
|
// Generate image with specified model and transaction reference
|
||||||
return generateWithFlux(prompt, modelId, transactionSignature)
|
return generateWithFlux(prompt, modelId, transactionSignature);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error in handleFluxGeneration:', error)
|
console.error('Error in handleFluxGeneration:', error)
|
||||||
return { error: error instanceof Error ? error.message : 'Unknown error' }
|
return { error: error instanceof Error ? error.message : 'Unknown error' }
|
||||||
|
28
src/utils/uploadToPinata.ts
Normal file
28
src/utils/uploadToPinata.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { PinataSDK } from 'pinata-web3';
|
||||||
|
import 'dotenv/config';
|
||||||
|
import assert from 'assert';
|
||||||
|
|
||||||
|
import { FluxGenerationResult } from '../services/fluxService';
|
||||||
|
|
||||||
|
assert(process.env.PINATA_JWT, "PINATA_JWT is required");
|
||||||
|
assert(process.env.PINATA_GATEWAY, "PINATA_GATEWAY is required");
|
||||||
|
|
||||||
|
const pinata = new PinataSDK({
|
||||||
|
pinataJwt: process.env.PINATA_JWT,
|
||||||
|
pinataGateway: process.env.PINATA_GATEWAY,
|
||||||
|
});
|
||||||
|
|
||||||
|
export async function uploadToPinata(imageUrl: string): Promise<FluxGenerationResult> {
|
||||||
|
try {
|
||||||
|
const upload = await pinata.upload.url(imageUrl);
|
||||||
|
|
||||||
|
const publicURL = await pinata.gateways.convert(upload.IpfsHash);
|
||||||
|
|
||||||
|
return { imageUrl: publicURL };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error uploading to Pinata:', error)
|
||||||
|
return {
|
||||||
|
error: error instanceof Error ? error.message : 'Upload failed'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user