paint-brush
🌈🊄 Bacalhau を的䜿甚しお只身䞀人の AI 蜬化成アヌト NFT DApp を構築する に@developerally
2,423 枬定倀
2,423 枬定倀

🌈🊄 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 をれロから評䟡:)



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


Python スクリプト


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


これが根本な 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 に确定性の细化化の䟡倀をより広く攟棄するこずなく、デヌタのオフチェヌン蚈算を或者にするこずで、デヌタ凊理の以后を民䞻化化するこずを目指しおいたす。


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

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

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


このスクリプトを実行するには、Bacalhau で应甚できるように Docker 化したす。その策略を孊びたい堎合は、に埓っおください。その埌、Bacalhau CLI で 1 行のコヌドだけで実行できたす ( した埌)。
 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 スマヌト コントラクトは、 に基づいおいたすが、メタデヌタ暙準拡匵機胜を含む 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]; }


芁件

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


Hyperspace Testnet にデプロむするには、䞋が有必芁です
  1. Metamask Wallet を
  2. 蛇口からいく぀かのテスト tFIL 資金を取埗したす ( たたは )


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

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


🛞 Hyperspace RPC & BlockExplorer オプション:

パブリック RPC ゚ンドポむントブロック゚クスプロヌラヌの

オヌプン API :


構成のセットアップでは、借助机䌚なパブリック 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: '//api.hyperspace.node.glif.io/rpc/v1', chainId: 3141, accounts: [process.env.WALLET_PRIVATE_KEY ?? 'undefined'], }, // bleeding edge often-reset FVM testnet filecoinWallaby: { url: '//wallaby.node.glif.io/rpc/v0', chainId: 31415, accounts: [process.env.WALLET_PRIVATE_KEY ?? 'undefined'], //explorer: //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 ゚ンドポむントの制䜜に぀いおは、゚ンゞニアのによるに蚘茉されおいたす。


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


>run/test in terminal


 curl -XPOST -d '{"prompt": "rainbow unicorn"}' '//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 = '//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 を開き、このを (.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 //[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 などの他のや、CID の IPFS ピンニングず Filecoin ストレヌゞ取匕を返すstatus() 関数も提䟛したす -> これは、 NFT のステヌタスをチェックするための FEVM DApp (たたは FEVM がメむンネット リリヌスになった埌の FEVM での NFT 実装)。

契玄の盞互䜜甚

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


  • 倉曎せずにチェヌンからデヌタを完成するための読み取り専甚呌び出し
  • 萜欟しおガスを支払うためにりォレットを需芁ずする呌び出しを曞き蟌みたす。 NFT の鋳造のように、チェヌンの状態を倉曎する関数!
  • むベント リスナヌ - コントラクトから発行されたむベントをリッスンする


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


パブリック 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 = '//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: [ '//hyperspace.filfox.info/rpc/v0', '//filecoin-hyperspace.chainstacklabs.com/rpc/v0', ], chainName: 'Filecoin Hyperspace', nativeCurrency: { name: 'tFIL', symbol: 'tFIL', decimals: 18, }, blockExplorerUrls: [ '//fvm.starboard.ventures/contracts/', '//hyperspace.filscan.io/', '//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 は 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


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


  • ツむッタヌ
  • YouTube
  • Filecoin Project Slack #bacalhau
  • フォヌラム


♥ ず

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

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



も掲茉されおいたす。


바칎띌사읎튞 바칎띌사읎튞 옚띌읞바칎띌