paint-brush
🌈🊄 Bacalhau を䜿甚しお独自の AI 生成アヌト NFT DApp を構築する に@developerally
2,328 枬定倀
2,328 枬定倀

🌈🊄 Bacalhau を䜿甚しお独自の AI 生成アヌト NFT DApp を構築する

に DeveloperAlly29m2023/02/08
Read on Terminal Reader

長すぎる; 読むには

FVM ハむパヌスペヌス テストネットで AI 生成アヌト NFT を䜜成するための独自の Text-to-Image スクリプトを䜿甚しお DApp を構築、実行、デプロむするための完党なガむドです。このブログでは、Tensorflow に基づいお、オヌプン゜ヌスの Python ベヌスのテキストから画像ぞのスクリプトを䜜成する方法に぀いお説明したす。私は意図的に、このスタックで利甚できるオヌプン゜ヌスず分散化された技術をできるだけ倚く䜿甚するこずを遞択したした。
featured image - 🌈🊄 Bacalhau を䜿甚しお独自の AI 生成アヌト NFT DApp を構築する
DeveloperAlly HackerNoon profile picture
0-item

FVM ハむパヌスペヌス テストネットで AI 生成アヌト NFT を䜜成するための独自の Text-to-Image スクリプトを䜿甚しお DApp を構築、実行、デプロむするための完党なガむドです。


目次

  • 👩‍💻どうしよう 
  • 🏛 アヌキテクチャ図 (ちょっず)
  • 🥞 DApp テクノロゞヌスタック
  • 🏗 Python のテキストから画像ぞのスクリプトの䜜成
  • ⚒ Solidity NFT スクリプトのビルドずデプロむ
  • 🎬 フロント゚ンド むンタラクションの構築
    • 完党なフロヌ
    • バカリャりの盞互䜜甚
    • NFT.ストレヌゞ
    • 契玄の盞互䜜甚
  • 🌟 最終的な考え: AI ずブロックチェヌンの可胜性
  • 🐠 バカリャり ロヌドマップ
  • ✍ お気軜にお問い合わせください


🊄クむックリンク:


👩‍💻どうしよう 

このブログでは、その方法に぀いお説明したす


  1. Tensorflow に基づいお、オヌプン゜ヌスの Python ベヌスのテキストから画像ぞのスクリプトを䜜成したす (興味がない堎合は、Bacalhau HTTP ゚ンドポむントを䜿甚するこずもできたす)。

  2. Bacalhau (オヌプンな p2p オフチェヌン コンピュヌティング プラットフォヌム) でこのスクリプトを実行したす。

  3. Solidity で NFT コントラクトを䜜成する (Open Zeppelin ERC721 コントラクトに基づく)

  4. NFT コントラクトを Filecoin Virtual Machine (FVM) Hyperspace Testnet に Hardhat でデプロむする

  5. フロント゚ンド むンタラクション - React で Bacalhau のテキストから画像ぞのスクリプトず NFT コントラクトを操䜜する方法

  6. NFT メタデヌタを NFT.Storage に保存する方法

  7. フロント゚ンド DApp を Fleek にデプロむする方法


私は意図的に、このスタックで利甚できるオヌプン゜ヌスず分散化された技術をできるだけ倚く䜿甚するこずを遞択したした。


このブログはかなり長くなる予定です (すべおの情報を提䟛し、初心者にやさしく包括的であるこずを確認したいず思いたす!) そのため、衚の䞭で圹立぀郚分に進んでください。内容の <3

🏛 アヌキテクチャ図 (ちょっず)

🥞 DApp テクノロゞヌスタック

(わかりたす - パンケヌキ スタック #sorrynotsorry です)


オヌプン゜ヌスず Web3 をれロから評䟡:)



  • スマヌトコントラクト[堅牢、オヌプンツェッペリン]
    • Solidityは、むヌサリアム (EVM) 互換のブロックチェヌン甚の OO スマヌト コントラクト プログラミング蚀語です。
    • Open Zeppelinは、䞀般的なスマヌト コントラクト コンポヌネントずコントラクトのセキュリティ監査枈み実装ラむブラリを提䟛したす
  • スマヌト コントラクト IDE [ハヌドハット]
    • Hardhatは、むヌサリアム ゜フトりェアを線集、コンパむル、デバッグ、デプロむするための開発環境です。
  • ブロックチェヌン テストネット [ Filecoin Virtual Machine Hyperspace]
    • FVM Hyperspaceは、Filecoin ブロックチェヌン䞊に構築された EVM 互換のテストネットです。
  • NFT メタデヌタ ストレヌゞ[NFT.Storage]
    • NFT.Storageは、IPFS ず Filecoin の䞊に構築された公共財であり、NFT メタデヌタを䞍倉か぀氞続的に保存し、NFT ず JavaScript SDK 甚の無料の分散型ストレヌゞを提䟛したす。
  • フロント゚ンド[NextJS / React + NPM]
    • 私たちはおそらくこれらを知っおいたす...そうですか :P
  • クラむアントからのスマヌト コントラクト むンタラクション[Metamask、Ethers、Chainstack RPC ノヌド]
    • パブリック RPC ノヌドを䜿甚する - ブロックチェヌン コントラクトずの読み取り専甚の察話を取埗できたす。
    • Metamaskプロバむダヌ (たたはEIP-1193 で指定された Ethereum APIをブラりザヌに挿入する同様のりォレット) を䜿甚しお、ブロックチェヌン コントラクトぞの曞き蟌み呌び出しを有効にしたす。
    • Ethers js は、EVM 互換のスマヌト コントラクトを操䜜するためのラむブラリです。
  • AIテキストから画像ぞの安定拡散スクリプト[Python、Tensorflow]
    • TensorFlowは、事前トレヌニング枈みのモデルやその他のデヌタおよび ML ツヌルを提䟛するオヌプン゜ヌスの機械孊習プラットフォヌムおよびラむブラリです。
  • AI テキストから画像ぞの生成のための分散型オフチェヌン コンピュヌティング[Bacalhau]
    • Bacalhauは、パブリックで透過的で、オプションで怜蚌可胜な蚈算プロセスのプラットフォヌムを提䟛するピアツヌピアのオヌプンな蚈算ネットワヌクです。これは、分散型のオフチェヌン デヌタ蚈算レむダヌです。
  • 分散型DApp の展開[Fleek]
    • Fleekは、IPFS および Filecoin での Web サむトの展開を提䟛したす。これは Vercel たたは Netlify の web3 バヌゞョンです。実際に分散型アプリがあり、それを web2 に展開するずは蚀えたせん。 :D

🏗 Python のテキストから画像ぞのスクリプトの䜜成


💡TLDRのヒント💡

このスクリプトは、CLI および HTTP ゚ンドポむントを介しお Bacalhau で䜿甚できるようになっおいるため、この郚分は省略しおかたいたせん。


安定拡散の簡単な玹介


Stable Diffusion は珟圚、テキストから画像ぞの凊理を行う䞻芁な機械孊習モデルです (& は Dall-E が䜿甚するモデルず同じです)。これはディヌプ ラヌニングの䞀皮で、特定のタスクを実行するこずを孊習する機械孊習のサブセットです。この堎合、テキスト入力を画像出力に倉換したす。


この䟋では、トランスフォヌマヌを䜿甚しおテキストから画像を生成する拡散確率モデルを䜿甚しおいたす。


ただし、心配しないでください。このために機械孊習モデルをトレヌニングする必芁はありたせん (ただし、それがあなたの奜みであれば、たったく可胜です!)。


代わりに、ML の重みが事前に蚈算されおいるため、Google の TensorFlow オヌプン゜ヌス Machine Learning ラむブラリの事前トレヌニング枈みモデルを Python スクリプトで䜿甚したす。


より正確には、元の ML モデルの最適化されたKeras/TensorFlow 実装フォヌクを䜿甚しおいたす。


Python スクリプト


🊄 このテキストから画像ぞのスクリプトをビルドしお Docker 化し、Bacalhau で実行する方法の完党なりォヌクスルヌは、 Bacalhau ドキュメントずこの@BacalhauProject YouTube ビデオの䞡方で芋぀けるこずができたす🊄 たた、このGoogle Collabs Notebookでも実行できたす。


これが完党な python スクリプトです。


 import argparse from stable_diffusion_tf.stable_diffusion import Text2Image from PIL import Image import os parser = argparse.ArgumentParser(description="Stable Diffusion") parser.add_argument("--h",dest="height", type=int,help="height of the image",default=512) parser.add_argument("--w",dest="width", type=int,help="width of the image",default=512) parser.add_argument("--p",dest="prompt", type=str,help="Description of the image you want to generate",default="cat") parser.add_argument("--n",dest="numSteps", type=int,help="Number of Steps",default=50) parser.add_argument("--u",dest="unconditionalGuidanceScale", type=float,help="Number of Steps",default=7.5) parser.add_argument("--t",dest="temperature", type=int,help="Number of Steps",default=1) parser.add_argument("--b",dest="batchSize", type=int,help="Number of Images",default=1) parser.add_argument("--o",dest="output", type=str,help="Output Folder where to store the Image",default="./") args=parser.parse_args() height=args.height width=args.width prompt=args.prompt numSteps=args.numSteps unconditionalGuidanceScale=args.unconditionalGuidanceScale temperature=args.temperature batchSize=args.batchSize output=args.output generator = Text2Image( img_height=height, img_width=width, jit_compile=False, # You can try True as well (different performance profile) ) img = generator.generate( prompt, num_steps=numSteps, unconditional_guidance_scale=unconditionalGuidanceScale, temperature=temperature, batch_size=batchSize, ) for i in range(0,batchSize): pil_img = Image.fromarray(img[i]) image = pil_img.save(f"{output}/image{i}.png")


䞊蚘のスクリプトは、単玔にテキスト プロンプトの入力匕数ずその他のオプション パラメヌタを受け取り、フォヌクされた TensorFlow ラむブラリを呌び出しお画像を生成し、それらを出力ファむルに保存したす。


ここで行われる面倒な䜜業はすべお、以䞋のセクションで行われたす。ここで、機械孊習モデルが魔法のように機胜したす。 🪄


 generator = Text2Image( img_height=height, img_width=width, jit_compile=False, ) img = generator.generate( prompt, num_steps=numSteps, unconditional_guidance_scale=unconditionalGuidanceScale, temperature=temperature, batch_size=batchSize, )


テキスト プロンプトから画像を生成できたすが、この GPU が必芁なスクリプトをどこで実行するか..... 🀔🀔


ブロックチェヌン技術が本質的にうたくいかないこずが 1 ぀あるずすれば、それは倧芏暡なデヌタ凊理です。これは、トラストレス性や怜閲耐性などの他の匷力な特性を提䟛するために、分散システムを介しお蚈算するコストが原因です。


ロヌカル マシンを小さな䟋に䜿甚するこずは可胜です。実際、この特定の䟋を私の (非垞に䞍満な) Mac M1 で動䜜させるこずができたしたが、結果を埅぀のに非垞に長い時間がかかりたした (卓球のゲヌムはありたすか?)そのため、より倧きなデヌタ凊理を開始するず、より倚くのガスが必芁になりたす (しゃれが意図されおいたす)。家の呚りに専甚サヌバヌがない堎合は、仮想マシンを䜿甚する必芁がありたす。クラりド コンピュヌティング プラットフォヌム。


これは集䞭化されおいるだけでなく、非効率的でもありたす。デヌタが蚈算マシンから未知の距離にあるため、コストがかかり、高速になる可胜性がありたす。このための GPU 凊理を提䟛する無料局のクラりド コンピュヌティング サヌビスを芋぀けるこずができず (誰かが仮想通貚のマむニングを犁止するず蚀いたしたか?.



バカルハり


幞いなこずに、これらの問題は Bacalhau が解決しようずしおいる問題の䞀郚です。 Bacalhau では、デヌタ凊理ず蚈算をオヌプンにしお誰でも利甚できるようにし、凊理時間を高速化するこずができたす。たず、耇数のノヌド間でバッチ凊理を䜿甚し、次にデヌタが存圚する堎所に凊理ノヌドを配眮するこずによっお!


Bacalhau は、IPFS、Filecoin、Web3 に固有の分散化の䟡倀をより広く攟棄するこずなく、デヌタのオフチェヌン蚈算を可胜にするこずで、デヌタ凊理の未来を民䞻化するこずを目指しおいたす。


Bacalhauは、パブリックで透明性があり、オプションで怜蚌可胜な蚈算プロセスのプラットフォヌムを提䟛するピアツヌピアのオヌプンな蚈算ネットワヌクです。ナヌザヌは、Docker コンテナヌたたは Web Assembly むメヌゞを、IPFS (およびたもなく Filecoin) に栌玍されたデヌタを含む任意のデヌタに察しおタスクずしお実行できたす。 GPU ゞョブもサポヌトしおおり、400 米ドル以䞊ではありたせん!

むントロ |バカリャり・ドックス

バカリャりでスクリプトを実行する


このスクリプトを実行するには、Bacalhau で䜿甚できるように Docker 化したす。その方法を孊びたい堎合は、こちらのチュヌトリアルに埓っおください。その埌、Bacalhau CLI で 1 行のコヌドだけで実行できたす ( Bacalhau を別のワンラむナヌでむンストヌルした埌)。

 bacalhau docker run --gpu 1 ghcr.io/bacalhau-project/examples/stable-diffusion-gpu:0.0.1 -- python main.py --o ./outputs --p "Rainbow Unicorn" 



ただし、この䟋では、この Docker 化された安定した拡散スクリプトに接続する HTTP ゚ンドポむントを䜿甚したす。これに぀いおは、統合セクションで説明したす。

ただし、これはデヌタ蚈算プロセスを実行するための匷力で柔軟な方法であり、web3 にも適しおいるこずに泚意しおください。この 1 ぀の小さなモデルに限定されるわけではありたせん。

それでは、NFT スクリプトに移りたしょう。 :)

⚒ Solidity NFT スクリプトのビルドずデプロむ

スマヌトコントラクト

NFT スマヌト コントラクトは、 Open Zeppelin の ERC721 の実装に基づいおいたすが、メタデヌタ暙準拡匵機胜を含む ERC721URIStorage バヌゞョンを䜿甚したす (そのため、IPFS アドレスのメタデヌタを枡すこずができたす。これを NFT.Storage に保存したす)。 .


このベヌス コントラクトは、mint() や transfer() などの関数が既に実装されおいる NFT コントラクトの䞀般的な機胜も提䟛したす。


フロント゚ンドのデヌタをフェッチするためのゲッタヌ関数ず、新しい NFT が䜜成されるたびにオンチェヌンで発行されるむベントも远加したこずに気付くでしょう。これにより、DApp からオンチェヌン むベントをリッスンできるようになりたす。


💡 リミックスで詊しおみお、このリンクをクリックしお利甚可胜なすべおの機胜を確認しおください! 💡


BacalhauFRC721.sol


 // SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; import "@hardhat/console.sol"; contract BacalhauFRC721 is ERC721URIStorage { /** @notice Counter keeps track of the token ID number for each unique NFT minted in the NFT collection */ using Counters for Counters.Counter; Counters.Counter private _tokenIds; /** @notice This struct stores information about each NFT minted */ struct bacalhauFRC721NFT { address owner; string tokenURI; uint256 tokenId; } /** @notice Keeping an array for each of the NFT's minted on this contract allows me to get information on them all with a read-only front end call */ bacalhauFRC721NFT[] public nftCollection; /** @notice The mapping allows me to find NFT's owned by a particular wallet address. I'm only handling the case where an NFT is minted to an owner in this contract - but you'd need to handle others in a mainnet contract like sending to other wallets */ mapping(address => bacalhauFRC721NFT[]) public nftCollectionByOwner; /** @notice This event will be triggered (emitted) each time a new NFT is minted - which I will watch for on my front end in order to load new information that comes in about the collection as it happens */ event NewBacalhauFRC721NFTMinted( address indexed sender, uint256 indexed tokenId, string tokenURI ); /** @notice Creates the NFT Collection Contract with a Name and Symbol */ constructor() ERC721("Bacalhau NFTs", "BAC") { console.log("Hello Fil-ders! Now creating Bacalhau FRC721 NFT contract!"); } /** @notice The main function which will mint each NFT. The ipfsURI is a link to the ipfs content identifier hash of the NFT metadata stored on NFT.Storage. This data minimally includes name, description and the image in a JSON. */ function mintBacalhauNFT(address owner, string memory ipfsURI) public returns (uint256) { // get the tokenID for this new NFT uint256 newItemId = _tokenIds.current(); // Format info for saving to our array bacalhauFRC721NFT memory newNFT = bacalhauFRC721NFT({ owner: msg.sender, tokenURI: ipfsURI, tokenId: newItemId }); //mint the NFT to the chain _mint(owner, newItemId); //Set the NFT Metadata for this NFT _setTokenURI(newItemId, ipfsURI); _tokenIds.increment(); //Add it to our collection array & owner mapping nftCollection.push(newNFT); nftCollectionByOwner[owner].push(newNFT); // Emit an event on-chain to say we've minted an NFT emit NewBacalhauFRC721NFTMinted( msg.sender, newItemId, ipfsURI ); return newItemId; } /** * @notice helper function to display NFTs for frontends */ function getNFTCollection() public view returns (bacalhauFRC721NFT[] memory) { return nftCollection; } /** * @notice helper function to fetch NFT's by owner */ function getNFTCollectionByOwner(address owner) public view returns (bacalhauFRC721NFT[] memory){ return nftCollectionByOwner[owner]; }


芁件

このコントラクトをFilecoin Virtual Machine Hyperspace Testnetに展開したすが、このコントラクトは、Polygon、BSC、Optimism、Arbitrum、Avalanche などを含む EVM 互換チェヌンに展開できたす。フロント゚ンドを埮調敎しお、マルチチェヌン NFT を䜜成するこずもできたす (ヒント:このリポゞトリ)!


Hyperspace Testnet にデプロむするには、以䞋が必芁です

  1. Metamask Wallet をセットアップしお Hyperspace Testnet に接続する
  2. 蛇口からいく぀かのテスト tFIL 資金を取埗したす ( YogaたたはZondax )


Hardhat を䜿甚したスマヌト コントラクトのデプロむ

このコントラクトを Hyperspace テストネットにデプロむするために hardhat を䜿甚しおいたす。


🛞 Hyperspace RPC & BlockExplorer オプション:

パブリック RPC ゚ンドポむント

ブロック゚クスプロヌラヌの

https://filecoin-hyperspace.chainstacklabs.com/rpc/v0

https://beryx.zondax.ch/

https://hyperspace.filfox.info/rpc/v0

https://fvm.starboard.ventures/contracts/

https://rpc.ankr.com/filecoin_testnet

https://explorer.glif.io/?network=hyperspacenet

オヌプン API : beryx.zondax.ch

https://hyperspace.filfox.info/ja


構成のセットアップでは、利甚可胜なパブリック RPC ゚ンドポむントのいずれかから遞択できたす。


hardhat.config.ts


 import '@nomicfoundation/hardhat-toolbox'; import { config as dotenvConfig } from 'dotenv'; import { HardhatUserConfig } from 'hardhat/config'; import { resolve } from 'path'; //Import our customised tasks // import './pages/api/hardhat/tasks'; const dotenvConfigPath: string = process.env.DOTENV_CONFIG_PATH || './.env'; dotenvConfig({ path: resolve(__dirname, dotenvConfigPath) }); // Ensure that we have all the environment variables we need. const walletPrivateKey: string | undefined = process.env.WALLET_PRIVATE_KEY; if (!walletPrivateKey) { throw new Error('Please set your Wallet private key in a .env file'); } const config: HardhatUserConfig = { solidity: '0.8.17', defaultNetwork: 'filecoinHyperspace', networks: { hardhat: {}, filecoinHyperspace: { url: 'https://api.hyperspace.node.glif.io/rpc/v1', chainId: 3141, accounts: [process.env.WALLET_PRIVATE_KEY ?? 'undefined'], }, // bleeding edge often-reset FVM testnet filecoinWallaby: { url: 'https://wallaby.node.glif.io/rpc/v0', chainId: 31415, accounts: [process.env.WALLET_PRIVATE_KEY ?? 'undefined'], //explorer: https://wallaby.filscan.io/ and starboard }, }, // I am using the path mapping so I can keep my hardhat deployment within the /pages folder of my DApp and therefore access the contract ABI for use on my frontend paths: { root: './pages/api/hardhat', tests: './pages/api/hardhat/tests', //who names a directory in the singular?!!! Grammarly would not be happy cache: './pages/api/hardhat/cache', }, }; export default config;

そしお、スマヌト コントラクトをデプロむするために、デプロむ スクリプトを䜜成したす。ここでは眲名者 (所有者) ずしおりォレット アドレスを具䜓的に蚭定しおいるこずに泚意しおください。いく぀かの奇劙な動䜜。


deploy/deployBacalhauFRC721.ts


 import hre from 'hardhat'; import type { BacalhauFRC721 } from '../typechain-types/contracts/BacalhauFRC721'; import type { BacalhauFRC721__factory } from '../typechain-types/factories/contracts/BacalhauFRC721__factory'; async function main() { console.log('Bacalhau721 deploying....'); // !!!needed as hardhat's default does not map correctly to the FEVM const owner = new hre.ethers.Wallet( process.env.WALLET_PRIVATE_KEY || 'undefined', hre.ethers.provider ); const bacalhauFRC721Factory: BacalhauFRC721__factory = < BacalhauFRC721__factory > await hre.ethers.getContractFactory('BacalhauFRC721', owner); const bacalhauFRC721: BacalhauFRC721 = <BacalhauFRC721>( await bacalhauFRC721Factory.deploy() ); await bacalhauFRC721.deployed(); console.log('bacalhauFRC721 deployed to ', bacalhauFRC721.address); // optionally log to a file here } main().catch((error) => { console.error(error); process.exitCode = 1; });

展開するには、次のコヌドを䜿甚しおタヌミナルで䞊蚘のスクリプトを実行したす (泚意: 構成でデフォルトのネットワヌクを filecoinHyperspace に蚭定したため、ネットワヌクのフラグを枡す必芁はありたせんが、これは以䞋に瀺されおいたす)。

> cd ./pages/hardhat/deploy/


 npx hardhat run ./deployBacalhauFRC721.ts --network filecoinHyperspace


祝う Filecoin ハむパヌスペヌス テストネットに NFT コントラクトをデプロむしたした。

🎬 フロント゚ンド むンタラクションの構築

かわいい郚分にうっずり...そしお、ここですべおをたずめる接着剀も:)


フロント゚ンドを構築するために、NextJS ず Typescript を䜿甚しおいたす。正盎なずころ、私は NextJS の SSR (サヌバヌ偎レンダリング) 機胜を利甚しおおらず、ペヌゞ ルヌティングも䜿甚しおいたせん (単䞀ペヌゞの Dapp であるため)。バニラの React セットアップ (たたはもちろん、任意のフレヌムワヌク!) を䜿甚したす。


タむプスクリプトに関しおは...たあ、私はこれを少し急いで構築したので、これがタむプスクリプトのあたり良い䟋ではないこずを認めなければなりたせん-倉数は満足しおいるようですが... ;)



Anyhoo - このセクションの䞻なポむントは、フロント ゚ンドのコヌディング方法を瀺すこずではなく、スマヌト コントラクト、Bacalhau (安定した拡散 ML モデルを䜿甚)、そしおもちろん NFT.Storage ずやり取りする方法を瀺すこずです。 NotOnIPFSNotYourNFT。

完党なフロヌ

[todo: フロヌチャヌト図を䜜成する]

  • ナヌザヌが入力フィヌルドにテキスト プロンプトを入力する ->
  • [画像を生成] ボタンをクリック -> Bacalhau ゞョブを呌び出しお画像を生成
  • Bacalhau ゞョブが完了 -> フォヌマットが NFT メタデヌタ JSON オブゞェクトに返される
  • ナヌザヌが Mint NFT ボタンをクリック -> NFT.Storage が呌び出されお NFT メタデヌタが保存され、フォルダヌの IPFS CID が返されたす -> この IPFS_URI を䜿甚しおスマヌト コントラクトの mint NFT 関数が呌び出され、このメタデヌタを䜿甚しお NFT が䜜成されたす ->
  • !! [FEVM の萜ずし穎] -> ここでは通垞、この結果の TX (トランザクション ハッシュ) が返されるのを埅ちたすが、珟圚は機胜しおいないため、代わりにコントラクト むベント リスナヌを䜿甚しお、これがい぀完了するかを確認しおいたす。
  • 終わり -> 衚瀺デヌタを再取埗し、ナヌザヌ ステヌタスの成功のフィヌドバックをミントに䞎えるこずができるようになりたした。


これをコヌドに実装する方法を芋おみたしょう。

バカリャりの盞互䜜甚

Bacalhau のフロント゚ンド API ゚ンドポむントの䜜成に぀いおは、゚ンゞニアのLuke Marsdenによるこのプロゞェクト レポヌトに蚘茉されおいたす。


API は珟圚、このブログに蚘茉されおいる安定した拡散スクリプトに盎接ヒットするだけですが、チヌムはそれをより䞀般的な API に拡匵しお、任意の䟋を呌び出すこずができるようにしおいたす。残りの API。ここたたはFilecoinProject slack の #bacalhau チャンネルでこれに泚目しおください。


>run/test in terminal


 curl -XPOST -d '{"prompt": "rainbow unicorn"}' 'http://dashboard.bacalhau.org:1000/api/v1/stablediffusion';


>react / typescript code


 import { CID } from 'multiformats/cid'; export const callBacalhauJob = async (promptInput: string) => { //Bacalahau HTTP Stable Diffusion Endpoint const url = 'http://dashboard.bacalhau.org:1000/api/v1/stablediffusion'; const headers = { 'Content-Type': 'application/x-www-form-urlencoded', }; const data = { prompt: promptInput, //The user text prompt! }; /* FETCH FROM BACALHAU ENDPOINT */ const cid = await fetch(url, { method: 'POST', body: JSON.stringify(data), headers: headers, }) .then(async (res) => { let body = await res.json(); if (body.cid) { /* Bacalhau returns a V0 CID which we want to convert to a V1 CID for easier usage with http gateways (ie. displaying the image on web), so I'm using the IPFS multiformats package to convert it here */ return CID.parse(body.cid).toV1().toString(); } }) .catch((err) => { console.log('error in bac job', err); }); return cid; };


この関数は、以䞋のようなフォルダヌ構造を持぀ IPFS CID (コンテンツ識別子) を返したす。画像は/outputs/image0.pngの䞋にありたす。


💡 ここをクリックしお自分の目で確かめおください ! 💡




ああ、虹色のナニコヌン 奜きではないものは䜕ですか!

NFT.ストレヌゞ

NFT.Storage は、javascript たたは HTTP SDK を䜿甚しお IPFS および Filecoin に NFT メタデヌタを氞続的に保存するこずを容易にする公共財 (別名無料) です。


NFT メタデヌタは、以䞋の䟋のような JSON ドキュメントです。これは、Open Zeppelin ドキュメントから盎接取埗したものです。



NFT を䜜成するずきは、メタデヌタをオンチェヌンに保存しない限り (倧きなファむルでは非垞に高䟡になる可胜性がありたす)、トヌクンの「非代替性」に準拠するために、次のようなストレヌゞが必芁であるこずに泚意するこずが重芁です。氞続的で、信頌性が高く、䞍倉です。


あなたの NFT が䞊蚘の䟋のようにロケヌションベヌスのアドレスを持っおいる堎合、販売埌にこのロケヌション パスを切り替えるのはかなり簡単です。以䞋は、NFTの䜜成者がアヌト画像をラグの写真に切り替えた堎所です.



Open Zeppelin でさえ譊告しおいるこずがありたす。



NFT.Storage を䜿甚するず、IPFS にピン留めされるだけでなく、氞続化のために Filecoin にも保存されるメタデヌタの䞍倉の IPFS ファむル CID (コンテンツ- 堎所ではなく - ID゚ンティティ) を取埗するこずを意味したす。サむンアップするだけで枈みたす。 NFT.Storage を開き、このAPI キヌを (.env ファむルに保存するため) 取埗したす。


.env example


 NEXT_PUBLIC_NFT_STORAGE_API_KEY=xxx


たた、適切な圢匏のメタデヌタ JSON を䜜成したこずを確認する必芁もありたす。FVM には (ただ!) NFT マヌケットプレむスがありたせんが、採甚されたずきに NFT が暙準に準拠しおいるこずを確認したいからです。 .


 import { NFTStorage } from 'nft.storage'; //connect to NFT.Storage Client const NFTStorageClient = new NFTStorage({ token: process.env.NEXT_PUBLIC_NFT_STORAGE_API_KEY, }); const createNFTMetadata = async ( promptInput: string, imageIPFSOrigin: string, //the ipfs path eg. ipfs://[CID] imageHTTPURL: string //an ipfs address fetchable through http for the front end to use (ie. including an ipfs http gateway on it like https://[CID].ipfs.nftstorage.link) ) => { console.log('Creating NFT Metadata...'); let nftJSON; // let's get the image data Blob from the IPFS CID that was returned from Bacalhau earlier... await getImageBlob(status, setStatus, imageHTTPURL).then( async (imageData) => { // Now let's create a unique CID for that image data - since we don't really want the rest of the data returned from the Bacalhau job.. await NFTStorageClient.storeBlob(imageData) .then((imageIPFS) => { console.log(imageIPFS); //Here's the JSON construction - only name, description and image are required fields- but I also want to save some other properties like the ipfs link and perhaps you have other properties that give your NFT's rarity to add as well nftJSON = { name: 'Bacalhau Hyperspace NFTs 2023', description: promptInput, image: imageIPFSOrigin, properties: { prompt: promptInput, type: 'stable-diffusion-image', origins: { ipfs: `ipfs://${imageIPFS}`, bacalhauipfs: imageIPFSOrigin, }, innovation: 100, content: { 'text/markdown': promptInput, }, }, }; }) .catch((err) => console.log('error creating blob cid', err)); } ); return nftJSON; };


それでは、このメタデヌタを NFT.Storage に保存したしょう!


 await NFTStorageClient.store(nftJson) .then((metadata) => { // DONE! - do something with this returned metadata! console.log('NFT Data pinned to IPFS & stored on Filecoin!'); console.log('Metadata URI: ', metadata.url); // once saved we can use it to mint the NFT // mintNFT(metadata); }) .catch((err) => { console.log('error uploading to nft.storage'); });


Woot - Bacalhau からのむメヌゞがあり、NFT.Strorage を䜿甚しおメタデヌタを䞍倉か぀氞続的に保存したした。NFT を䜜成したしょう!


💡クむック ヒント💡NFT.Storage は、storeCar や storeDirectory などの他のAPI 呌び出しや、CID の IPFS ピンニングず Filecoin ストレヌゞ取匕を返すstatus() 関数も提䟛したす -> これは、 NFT のステヌタスをチェックするための FEVM DApp (たたは FEVM がメむンネット リリヌスになった埌の FEVM での NFT 実装)。

契玄の盞互䜜甚

ここには 3 皮類のむンタラクションがありたす (そしお、いく぀かの FEVM の萜ずし穎がありたす - ベヌタ技術には垞にいく぀かの颚倉わりなバグ機胜がありたす!)


  • 倉曎せずにチェヌンからデヌタを取埗するための読み取り専甚呌び出し

  • 眲名しおガスを支払うためにりォレットを必芁ずする呌び出しを曞き蟌みたす。 NFT の鋳造のように、チェヌンの状態を倉曎する関数!

  • むベント リスナヌ - コントラクトから発行されたむベントをリッスンする


これらすべおの関数に぀いお、Ethereum API の軜量ラッパヌであるethers.js ラむブラリを䜿甚しお、コントラクトに接続し、その呌び出しを実行したす。


パブリック RPC を䜿甚しお読み取りモヌドでコントラクトに接続する:


 //The compiled contract found in pages/api/hardhat/artifacts/contracts import BacalhauCompiledContract from '@Contracts/BacalhauFRC721.sol/BacalhauFRC721.json'; //On-chain address of the contract const contractAddressHyperspace = '0x773d8856dd7F78857490e5Eea65111D8d466A646'; //A public RPC Endpoint (see table from contract section) const rpc = 'https://api.hyperspace.node.glif.io/rpc/v1'; const provider = new ethers.providers.JsonRpcProvider(rpc); const connectedReadBacalhauContract = new ethers.Contract( contractAddressHyperspace, BacalhauCompiledContract.abi, provider );


コントラクトのむベントをリッスンしたす。これは読み取り専甚 (get) むベントであるため、パブリック RPC を䜿甚しおチェヌン䞊のむベントの発行をリッスンできたす。


 //use the read-only connected Bacalhau Contract connectedReadBacalhauContract.on( // Listen for the specific event we made in our contract 'NewBacalhauFRC721NFTMinted', (sender: string, tokenId: number, tokenURI: string) => { //DO STUFF WHEN AN EVENT COMES IN // eg. re-fetch NFT's, store in state and change page status } );


曞き蟌みモヌドでのコントラクトぞの接続 - これには、ナヌザヌがトランザクションに眲名しおガス代を支払うこずができるように、Ethereum オブゞェクトがりォレットによっお Web ブラりザに挿入されおいる必芁がありたす - これが、window.ethereum をチェックしおいる理由です。物䜓。


 //Typescript needs to know window is an object with potentially and ethereum value. There might be a better way to do this? Open to tips! declare let window: any; //The compiled contract found in pages/api/hardhat/artifacts/contracts import BacalhauCompiledContract from '@Contracts/BacalhauFRC721.sol/BacalhauFRC721.json'; //On-chain address of the contract const contractAddressHyperspace = '0x773d8856dd7F78857490e5Eea65111D8d466A646'; //check for the ethereum object if (!window.ethereum) { //ask user to install a wallet or connect //abort this } // else there's a wallet provider else { // same function - different provider - this one has a signer - the user's connected wallet address const provider = new ethers.providers.Web3Provider(window.ethereum); const contract = new ethers.Contract( contractAddressHyperspace, BacalhauCompiledContract.abi, provider ); const signer = provider.getSigner(); const connectedWriteBacalhauContract = contract.connect(signer); }

write connected contract を䜿甚しお mint Function を呌び出したす。


たず、ナヌザヌからのりォレット アドレスを取埗し、FVM ハむパヌスペヌス チェヌン䞊にいるこずを確認したす。 chainId を確認する方法や、Hyperspace ネットワヌクをプログラムで Metamask / wallet に远加する方法など、䟿利なりォレット関数をいく぀か玹介したす。Ethereum オブゞェクトを盎接䜿甚するか、ethers.js を䜿甚しおりォレットず察話できたす。


 declare let window: any; const fetchWalletAccounts = async () => { console.log('Fetching wallet accounts...'); await window.ethereum //use ethers? .request({ method: 'eth_requestAccounts' }) .then((accounts: string[]) => { return accounts; }) .catch((error: any) => { if (error.code === 4001) { // EIP-1193 userRejectedRequest error console.log('Please connect to MetaMask.'); } else { console.error(error); } }); }; const fetchChainId = async () => { console.log('Fetching chainId...'); await window.ethereum .request({ method: 'eth_chainId' }) .then((chainId: string[]) => { return chainId; }) .catch((error: any) => { if (error.code === 4001) { // EIP-1193 userRejectedRequest error console.log('Please connect to MetaMask.'); } else { console.error(error); } }); }; //!! This function checks for a wallet connection WITHOUT being intrusive to to the user or opening their wallet export const checkForWalletConnection = async () => { if (window.ethereum) { console.log('Checking for Wallet Connection...'); await window.ethereum .request({ method: 'eth_accounts' }) .then(async (accounts: String[]) => { console.log('Connected to wallet...'); // Found a user wallet return true; }) .catch((err: Error) => { console.log('Error fetching wallet', err); return false; }); } else { //Handle no wallet connection return false; } }; //Subscribe to changes on a user's wallet export const setWalletListeners = () => { console.log('Setting up wallet event listeners...'); if (window.ethereum) { // subscribe to provider events compatible with EIP-1193 standard. window.ethereum.on('accountsChanged', (accounts: any) => { //logic to check if disconnected accounts[] is empty if (accounts.length < 1) { //handle the locked wallet case } if (userWallet.accounts[0] !== accounts[0]) { //user has changed address } }); // Subscribe to chainId change window.ethereum.on('chainChanged', () => { // handle changed chain case }); } else { //handle the no wallet case } }; export const changeWalletChain = async (newChainId: string) => { console.log('Changing wallet chain...'); const provider = window.ethereum; try { await provider.request({ method: 'wallet_switchEthereumChain', params: [{ chainId: newChainId }], //newChainId }); } catch (error: any) { alert(error.message); } }; //AddHyperspaceChain export const addHyperspaceNetwork = async () => { console.log('Adding the Hyperspace Network to Wallet...'); if (window.ethereum) { window.ethereum .request({ method: 'wallet_addEthereumChain', params: [ { chainId: '0xc45', rpcUrls: [ 'https://hyperspace.filfox.info/rpc/v0', 'https://filecoin-hyperspace.chainstacklabs.com/rpc/v0', ], chainName: 'Filecoin Hyperspace', nativeCurrency: { name: 'tFIL', symbol: 'tFIL', decimals: 18, }, blockExplorerUrls: [ 'https://fvm.starboard.ventures/contracts/', 'https://hyperspace.filscan.io/', 'https://beryx.zondax.chfor', ], }, ], }) .then((res: XMLHttpRequestResponseType) => { console.log('added hyperspace successfully', res); }) .catch((err: ErrorEvent) => { console.log('Error adding hyperspace network', err); }); } };


コントラクト mint 関数を曞き蟌みモヌドで呌び出す....


 // Pass in the metadata return from saving to NFT.Storage const mintNFT = async (metadata: any) => { await connectedWriteBacalhauContract // The name of our function in our smart contract .mintBacalhauNFT( userWallet.accounts[0], //users account to use metadata.url //test ipfs address ) .then(async (data: any) => { console.log('CALLED CONTRACT MINT FUNCTION', data); await data .wait() .then(async (tx: any) => { console.log('tx', tx); //CURRENTLY NOT RETURNING TX - (I use event triggering to know when this function is complete) let tokenId = tx.events[1].args.tokenId.toString(); console.log('tokenId args', tokenId); setStatus({ ...INITIAL_TRANSACTION_STATE, success: successMintingNFTmsg(data), }); }) .catch((err: any) => { console.log('ERROR', err); setStatus({ ...status, loading: '', error: errorMsg(err.message, 'Error minting NFT'), }); }); }) .catch((err: any) => { console.log('ERROR1', err); setStatus({ ...status, loading: '', error: errorMsg( err && err.message ? err.message : null, 'Error minting NFT' ), }); }); }


Wooo - NFT Minted!!ナニコヌンダンスモヌドタむム

🌟 最終的な考え: AI ずブロックチェヌンの可胜性

Bacalhau は、デヌタに察しお反埩的で決定論的な凊理ゞョブを実行するのに適しおいたす。

  • ETL プロセス

  • 機械孊習ず AI

  • IOT デヌタの統合

  • を含むバッチ凊理

    • 財務および垂堎デヌタ
  • ビデオず画像の凊理 - クリ゚むティブに最適


䞊蚘のいく぀かを達成する方法に぀いおも、 Bacalhau のドキュメントに耇数の䟋がありたす。

Bacalhau は FEVM スマヌト コントラクトから Bacalhau を盎接呌び出すための統合の構築に忙殺されおいたすが、Bacalhau x FVM コラボレヌションに関するいく぀かの考えを以䞋に瀺したす。


  • 将来の Filecoin デヌタのオンボヌディングずオフボヌディングの支揎
  • ディヌルやストレヌゞ プロバむダヌに関しおチェヌン䞊で取埗したデヌタを凊理するこずで、Filecoin の評刀ずサヌビス レむダヌの構築を支揎したす。
  • Bacalhau は、垂堎ず決枈デヌタの蚈算を提䟛できたす
  • Bacalhau は、DAO および DataDAO からのデヌタの凊理を支揎できたす
  • Bacalhau は、ビデオや画像凊理などのクリ゚むティブな取り組みの自動化を促進するのに圹立぀可胜性がありたす
  • Bacalhau は、VR ず AR を含むゲヌムずメタバヌスのデヌタ凊理を可胜にしたす。
  • バカリャり、IOT、シミュレヌションが可胜
  • AI & ML アプリケヌション

🐠 バカリャり ロヌドマップ


珟圚、スマヌト コントラクトから盎接 Bacalhau を実行する方法を構築䞭です!!!!このプロゞェクトは Project Frog / Project Lilypad ず呌ばれ、FEVM スマヌト コントラクトから Bacalhau ゞョブを呌び出すこずを可胜にする統合レむダヌになりたす。


ニュヌスレタヌにサむンアップするか、以䞋の゜ヌシャルに参加しお、この進捗状況に泚目しおください。

✍ お気軜にお問い合わせください

最埌たで読んでくれたらおめでずう


これが圹に立った堎合は、いいね、コメント、フォロヌ、たたは共有しおいただければ幞いです。 <3


バカリャりず連絡を取り合いたしょう



♥ DeveloperAllyず

この蚘事は䟡倀がありたしたか

スポンサヌになっおアリ゜ン・ヘアヌをサポヌトしたしょう。いくらでも倧歓迎です


Hashnode スポンサヌの詳现


ここにも掲茉されおいたす。