Git Product home page Git Product logo

nft-generator-py's Introduction

nft-generator-py

preview

Unit Tests (on PR)

nft-generator-py is a simple script which programatically generates images using weighted layer files.

Getting Started

Clone the repository and install the requirements.

git clone https://github.com/Jon-Becker/nft-generator-py
cd nft-generator-py
python3 -m pip install -r requirements.txt

Create a configuration file, or use the build_configuration command to create a configuration file from a directory of traits. For more information on configuration files, see Configuration.

CLI Options

The following commands are available:

Command Usage Description
generate python3 main.py generate --config <config> [options] Generates a set of images using the provided configuration file.
build_config python3 main.py build_config --trait-dir <trait_dir> [options] Builds a configuration file from a directory of traits.
validate python3 main.py validate --config <config> [options] Validates a configuration file.
update_metadata python3 main.py update_metadata --image-path <config> [options] Updates the metadata files for all generated images at the provided --output path.

Optional Arguments

Argument Description
-o <output>, --output <output> The path to the directory where the generated images will be saved.
-c <config>, --config <config> The path to the configuration file.
--trait-dir <trait_dir> The path to the directory containing the trait images.
-n <amount>, --amount <amount> The number of images to generate.
-v, --verbose Enables verbose logging.
--start-at <start_at> The number to start counting from when generating images.
--allow-duplicates Allows duplicate images to be generated.
--no-pad Disables zero-padding of tokenIds.
-s <seed>, --seed <seed> The seed to use when generating images. Allows for reproducible results.

Configuration

{
  "layers": [
    {
      "name": "Background",
      "values": ["Blue", "Orange", "Purple", "Red", "Yellow"],
      "trait_path": "./trait-layers/backgrounds",
      "filename": ["blue", "orange", "purple", "red", "yellow"],
      "weights": [30, 45, 15, 5, 10]
    },
    ...
  ],
  "incompatibilities": [
    {
      "layer": "Background",
      "value": "Blue",
      "incompatible_with": ["Python Logo 2"],
      "default": {
        "value": "Default Incompatibility",
        "filename": "./trait-layers/foreground/logo"
      }
    }
  ],
  "baseURI": ".",
  "name": "NFT #",
  "description": "This is a description for this NFT series."
}

The config object is a dict that contains configuration instructions that can be changed to produce different outputs when running the program. Within metadata files, tokens are named using the configuration's name parameter, and described using the description parameter.

  • In ascending order, tokenIds are appended to the name resulting in NFT metadata names such as NFT #0001.
  • tokenIds are padded to the largest amount generated. IE, generating 999 objects will result in names NFT #001, using the above configuration, and generating 1000 objects will result in NFT #0001.
  • As of v1.0.2, padding filenames has been removed.

The layers list contains layer objects that define the layers for the program to use when generating unique tokens. Each layer has a name, which will be displayed as an attribute, values, trait_path, filename, and weights.

  • trait_path refers to the path where the image files in filename can be found. Please note that filenames omit .png, and it will automatically be prepended.
  • weight corresponds with the percent chance that the specific value that weight corresponds to will be selected when the program is run. The weights must add up to 100, or the program will fail.

The incompatibilities list contains an object that tells the program what layers are incompatible with what. In the above configuration, A Blue Background layer will never be generated with Python Logo 2.

  • layer refers to the targeted layer.
  • value is the value of the layer that is incompatible with attributes within the incompatible_with list.
  • incompatible_with is the list of incompatible layers that will never be selected when layer has attribute value.
  • An optional default object can be provided to each incompatibility. This object will be selected 100% of the time if present and an incompatible layer is selected. The default object has a value and filename attribute.
    • value is the name of the default selection which will be displayed in the metadata.
    • filename is the path to the image file that will be used as the default selection.

Troubleshooting

  • All images should be in .png format.
  • All images should be the same size in pixels, IE: 1000x1000.
  • The weight values for each attribute should add up to equal 100.

Contributing

Before contributing, make a new branch with the following format:

user/{username}/{description}

Your names should be descriptive of the changes you are making. For example, if you are adding a new command, your branch name might be user/jon-becker/some-new-command.

Your code will be reviewed and require at least one approval before being merged into the main branch.

Please follow this guide when writing commit messages. Messages should be descriptive and clean.

nft-generator-py's People

Contributors

alexlisong avatar elyak123 avatar faea726 avatar ftruzzi avatar jon-becker avatar redheadphone avatar tnkerer avatar webcoderz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

nft-generator-py's Issues

Feature Request: Calculate "amount" number

Right now it's a bit of trial and error trying to get the right amount files to generate based on the input layers.

It would be great to calculate this figure based on the config.

Problem with generating images

I'm having an issue with generating images, The problem seems to be in main.py

Here is the error

python3 main.py generate  --config config.json --amount 100

Traceback (most recent call last):
  File "/home/alan/Pictures/Phunks/nft-generator-py/main.py", line 66, in <module>
    generator: Generator = Generator(**args)
  File "/home/alan/Pictures/Phunks/nft-generator-py/src/core/main.py", line 35, in __init__
    self.config = read_json(args["config"])
  File "/home/alan/Pictures/Phunks/nft-generator-py/src/utils/io.py", line 14, in read_json
    config = json.load(f)
  File "/usr/lib/python3.10/json/__init__.py", line 293, in load
    return loads(fp.read(),
  File "/usr/lib/python3.10/json/__init__.py", line 346, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python3.10/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python3.10/json/decoder.py", line 353, in raw_decode
    obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Expecting ':' delimiter: line 15 column 46 (char 509)

When I take off the "--amount" flag I get this error

python3 main.py generate  --config config.json 

Traceback (most recent call last):
  File "/home/alan/Pictures/Phunks/nft-generator-py/main.py", line 66, in <module>
    generator: Generator = Generator(**args)
  File "/home/alan/Pictures/Phunks/nft-generator-py/src/core/main.py", line 26, in __init__
    raise ValueError("No amount was provided.")
ValueError: No amount was provided.

Here is my config file


{
  "layers": [
    {
      "name": "Type",
      "values": ["Male", "Ape", "Zombie", "Alien"],
      "trait_path": "./Phunk-Test/Type",
      "filename": ["Male", "Ape", "Zombie", "Alien"],
      "weights": [70, 10, 7, 3]
    },
    {
      "name": "Eyes",
      "values": ["3D Glasses", "Big Glasses", "Classic Glasses", "Clown Eyes", "Eye Mask",
      "Eye Patch", "Horned Rim Glasses", "Nerd Glasses", "Shades", "VR"],
      "trait_path": "./Phunk-Test/Eyes",
      "filename": "3D_Glasses", "Big_Glasses", "Classic_Glasses", "Clown_Eyes", "Eye_Mask",
      "Eye_Patch", "Horned_Rim_Glasses", "Nerd_Glasses", "Shades", "VR"],
      "weights": [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
    },
    {
      "name": "Hair",
      "values": ["Bandana", "Cap", "Clown Hair", "Crazy Violet Hair", "Fedora", "Headband", "Knitten Cap",
      "Mohawk_Dark", "Police Cap"],
      "trait_path": "./Phunk-Test/Hair",
      "filename": ["Bandana", "Cap", "Clown_Hair", "Crazy_Violet_Hair", "Fedora", "Headband", "Knitten_Cap",
      "Mohawk_Dark", "Police_Cap"],
      "weights": [20, 10, 10, 10, 10, 10, 10, 10, 10]
    },
    {
      "name": "Facial Hair",
      "values": ["Chin Strap", "Front Beard Dark", "Front Beard", "Moustache", "Muttonchops",
      "Normal Beard Black", "Normal Beard", "Handlebar"],
      "trait_path": "./Phunk-Test/Facial_Hair",
      "filename": ["Chin_Strap", "Front_Beard_Dark", "Front_Beard", "Moustache", "Muttonchops",
      "Normal_Beard_Black", "Normal_Beard", "Handlebar"],
      "weights": [12.5, 12.5, 12.5, 12.5, 12.5, 12.5, 12.5, 12.5]
    },
    {
      "name": "Face",
      "values": ["Clown Nose", "Frown", "Mole", "Smile"],
      "trait_path": "./Phunk-Test/Face",
      "filename": ["Clown_Nose", "Frown", "Mole", "Smile"],
      "weights": [25, 25, 25, 25]
    },
    {
      "name": "Jewlery",
      "values": ["Earring", "Gold Chain", "Silver Chain"],
      "trait_path": "./Phunk-Test/Jewlery",
      "filename": ["Earring", "Gold_Chain", "Silver_Chain"],
      "weights": [35, 35, 30]
    },
    {
      "name": "Vice",
      "values": ["None", "Cigarette", "Vape"],
      "trait_path": "./Phunk-Test/Vice",
      "filename": ["none", "Cigarette", "Vape"],
      "weights": [35, 35, 30]
    }

  ],
  "incompatibilities": [
    {
      "layer": "Type",
      "value": "Alien",
      "incompatible_with": ["Facial Hair"],
      },
      {
        "layer": "Type",
        "value": "Ape",
        "incompatible_with": ["Facial Hair"],
        }

    }
  ],
  "baseURI": "1",
  "name": "NFT #",
  "description": "This is a description for this NFT series."
}

generate_unique_images(amount, config) error

hello,
when I run the "generate_unique_images(amount, config)" command I get a "syntax error near unexpected token `amount,'" error. what am I suppose to put instead of amount? I have tried replacing amount with the number of images i want to generate but still run into the same issue. what would an example input command be if i wanted to generate just 3 nft images?

thank you!

Invalid syntax in index.py file

Syntax errors detected :

Line 67:
layers[index] = Image.open(f'{config["layers"][index]["trait_path"]}/{trait_files[attr][item[attr]]}.png').convert('RGBA')
^
SyntaxError: invalid syntax

Any idea how to resolve? Thanks

Float Validation

No matter how i change the weights array i get something like this :

src.common.exceptions.ConfigValidationError: config["layers"][3]["weights"]: The sum of the weights must be 100. Current sum: 100.00000000000006

my weights
"weights": [
1.4, 1.4, 1.4, 1.4, 2.5, 1.4, 1.7, 9.2, 2.5, 1.4, 0.3, 1.7, 1.7, 1.2,
0.7, 1.4, 0.9, 1.4, 1.7, 0.5, 1.7, 1.4, 0.2, 1, 2.2, 1.7, 1.8, 1.4, 1.7,
1.4, 1.7, 1.4, 1.4, 1.4, 1.4, 1.4, 1.4, 1.4, 1.7, 1.7, 1.8, 1.7, 1.4,
1.4, 1.7, 2, 0.7, 1.8, 0.9, 1.8, 1.4, 1.4, 1.4, 1.7, 1.7, 1.8, 1.7, 1,
1.7, 1.4, 0.9, 1.7, 1.8
]

Updating IPFS CID

If I pressed enter after the nfts are generated where generator asks about ipfs CID. Is there any way to update the CID afterwards in all files?

Config Error

Getting this error when just trying to run the included default settings:

At line:1 char:30

  • generate_unique_images(amount, config)
  •                          ~
    

Missing argument in parameter list.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingArgument

Feature Request:

          Feature Request:

When deploying the NFT images and metadata to IPFS, it is necessary to first upload the images (and get a unique CID).
Then I need to update the JSON files to point at this CID. I can not create the CID in advance of running the generative script (index.py) as I do not have the CID until I upload the images.

Could a script be added to run after the index.py & once I get the CID to go through all files in the metadata folder and update the baseURI to represent the IPFS CID? (Or regenerate them based on all-object.json?) Obviously the data needs to maintain the connection to the image. is these feature possible if yes than can you share a video reference or doc for the same .

Originally posted by @sriharsh1104 in #7 (comment)

Index Error

Hi, after editing the config, I am receiving a Index Error: list index out of range,

I saw in previous issue this could be syntax or mismatch with layer files in folders. I quadruple checked my files and filenames but still receive the error. I have a lot of different traits as well as fractional weights.

Generating 2500 unique NFTs...
Traceback (most recent call last):
File "C:\Users\colin\Documents\NFTs\Froggos\Froggos Generator\Generator\nft-generator-py\index.py", line 110, in
generate_unique_images(2500, {
File "C:\Users\colin\Documents\NFTs\Froggos\Froggos Generator\Generator\nft-generator-py\index.py", line 35, in generate_unique_images
trait_files[trait["name"]][key] = trait["filename"][x]
IndexError: list index out of range
PS C:\Users\colin\Documents\NFTs\Froggos\Froggos Generator\Generator\nft-generator-py>

Make it possible to import configuration files in JSON format

Proposal

Changing the way generate_unique_images works allows it to use an external config.json file instead of hardcoding configs into index.py.

Motivation

I have been thinking about practical applications for this script to simplify its use for the general audience, like people unfamiliar with software development. I planned to create a container image using Docker and serve this script as a microservice. This service would receive a few arguments, like an URL for external storage containing trait layers, the number of NFTs generated, and a config.json to replace the second argument in generate_unique_images(num, config).

The first step would be making it so generate_unique_images(num, config) reads configuration from an external file.

Example

Given the config.json:

{
  "layers": [
    {
      "name": "Background",
      "values": ["Blue", "Orange", "Purple", "Red", "Yellow"],
      "trait_path": "./trait-layers/backgrounds",
      "filename": ["blue", "orange", "purple", "red", "yellow"],
      "weights": [20,20,20,20,20]
    },
    {
      "name": "Foreground",
      "values": ["Python Logo", "Python Logo 32"],
      "trait_path": "./trait-layers/foreground",
      "filename": ["logo", "logo"],
      "weights": [50, 50]
    },
    {
      "name": "Branding",
      "values": ["A Name", "Another Name"],
      "trait_path": "./trait-layers/text",
      "filename": ["text", "text"],
      "weights": [50, 50]
    }
  ],
  "incompatibilities": [
    {
      "layer": "Background",
      "value": "Blue",
      "incompatible_with": ["Python Logo 2"]
    }, 
  ],
  "baseURI": ".",
  "name": "NFT #",
  "description": "This is a description for this NFT series."
}

It is possible to load config.json with something similar to:

user_config = open('config.json')

data = json.load(user_config)
 
user_config.close()

PS: I am working on something similar on my side.

Multi Layering

I have a layer that goes on top of another one, lets call the top layer x and the base of the object y.
The problem is x is two parts, a part above y and a part below y. However, once the x has been decided it's already too late because the y is also there so putting the bottom part of x on top of y would result in an unwanted picture. Please help!

Weights for layer groups

Would be great to add support for weights for layer groups.
Lets say we have following layer groups:

Background - always render
Body - always render
Head - always render
Hats - render only on 20% of images
Glasses - render only on 10% of images

btw. love your script, really nicely done.

missing about 200 images from an 8K mint

Once the collection was deployed we realized that about 200 images were missing... Unfortunately, I didn't use a seed when generating an original collection. The metadata files are all there. Is it possible to generate images based on existing meta?

If not, should we just generate new images + meta and hope there are not dups?

Conditional trait selection

Hi, is it possible to select the next trait/trait path based on the previous trait?
like what i found on azuki the spirit body can only have spirit hair

Cant Generate

Hello, First of all thank you for amazing work.

I'm very noobie, first time trying to do something in .py.

I just wanted to check if your generator engine is work. I didn't change anything, but all the time have same error

Exception has occurred: ModuleNotFoundError
No module named 'PIL'
File "/Users/petre/Desktop/NFT-PY/index.py", line 2, in
from PIL import Image

Could you help me?

it is not possible to generate more than 5 nft with my config.

the process simply dies if I set a value greater than 5, and with a standard code greater than 20 is not generated "The kernel 'Python 3.10.2 64-bit' died. "
`generate_unique_images(5, {
"layers": [
{
"name": "Background",
"values": ["Common", "Uncommon", "Rare", "Epic", "Legendary"],
"trait_path": "./trait-layers/backgrounds",
"filename": ["blue", "orange", "purple", "red", "yellow"],
"weights": [40,35,15,9,1]
},
{
"name": "Foreground",
"values": ["Qw, "Qs","Qe","Qr","Qt" ],
"trait_path": "./trait-layers/foreground",
"filename": ["qw", "qs", "qe", "qr", "qt"],
"weights": [20,20,20,20,20]
},

],
"incompatibilities": [
{
"layer": "Foreground",
"value": "Qw",
"incompatible_with": ["Uncommon", "Rare", "Epic", "Legendary"]
},
{
"layer": "Foreground",
"value": "Qs",
"incompatible_with": ["Common", "Rare", "Epic", "Legendary"]
},
{
"layer": "Foreground",
"value": "Qe",
"incompatible_with": ["Common", "Uncommon", "Epic", "Legendary"]
},
{
"layer": "Foreground",
"value": "Qr",
"incompatible_with": ["Common", "Uncommon", "Rare", "Legendary"]
},
{
"layer": "Foreground",
"value": "Qt",
"incompatible_with": ["Common", "Uncommon", "Rare", "Epic"]
},
],
"baseURI": ".",
"name": "NFT #",
"description": "Generation 0"
})`

Trait counter

I added code to count and write used traits to JSON file.

from collections import Counter

all_token_rarity = []
for layer in config["layers"]:
  all_token_rarity.append({ layer["name"]: Counter(image[layer["name"]] for image in all_images) })

with open('./metadata/all-rarity.json', 'w') as outfile:
   json.dump(all_token_rarity, outfile, indent=4)

Maybe someone find it useful.

Script to update JSON file with proper IPFS Data for images

Feature Request:

When deploying the NFT images and metadata to IPFS, it is necessary to first upload the images (and get a unique CID).
Then I need to update the JSON files to point at this CID. I can not create the CID in advance of running the generative script (index.py) as I do not have the CID until I upload the images.

Could a script be added to run after the index.py & once I get the CID to go through all files in the metadata folder and update the baseURI to represent the IPFS CID? (Or regenerate them based on all-object.json?) Obviously the data needs to maintain the connection to the image.

IndexError: list index out of range

After adding all the traits to the "trait-layers" when I execute the code it gives me this error. I have total 8 layers and have 100+ attributes. Can you take a look at what's wrong? Thanks!

Invalid layer weight: '10.0'. Expected type: <class 'int'>

Hi,

I've just started playing around with nft-generator-py, great work! I'm currently running into an error when trying to validate my config file, which is as the title of the issue suggests: "Invalid layer weight: '10.0'. Expected type: <class 'int'>"

All of the weights are being generated as floating point, even if there are only 5 traits in a particular folder (e.g. weights are then:
[20.0, 20.0, 20.0, 20.0, 20.0], instead of [20, 20, 20, 20, 20], and the validation stage seems to consider this an error:

raise ConfigValidationError(
src.common.exceptions.ConfigValidationError: config["layers"][0]["weights"][0]: Invalid layer weight: '10.0'. Expected type: <class 'int'>

Is there any known way to avoid this issue?

Issue when generating config file while using build_config

While running build_config command with path to --trait-dir and if once of the layer folder contains 3 images. The auto generated file contains weights as 33, 33 and 33. The generator will give error as weight adds to 99 not 100. So is in many other cases like when its 6 with 16.

Use a command line interface instead of python script args

The current call is python script.py *args

It would be more useful to have it be script *args because it would be usable by users without the python tool working and it improves abstraction.

You can use a few libraries for this including Click.

Metadata issue

Hey, Everything works fine, except metadata name and token id inside. For exmp. When 5 image generation have completed I've got:

In image Folder: 1,2,3,4,5

In metadata Folder: 0,1,2,3,4 and all objects.

I have qustion if it's possible to match token id number to metadata number.

Thanks,

Petrre

incompatibilities not working for me

dear friend,

could not figure out why the incompatibilities is not working for me. is this feature still in development or should it work as described ? help would be much appreciated

thank you


    {
      "name": "BOTS",
      "values": ["Bombed", "Doodle", "Gold", "Green", "Grey", "Ironman", "Rot", "Wood", "Yellow", "Zombie"],
      "trait_path": "./trait-layers/2_BOTS",
      "filename": ["Bombed", "Doodle", "Gold", "Green", "Grey", "Ironman", "Rot", "Wood", "Yellow", "Zombie"],
      "weights": [8, 12, 2, 15, 15, 6, 15, 7, 15, 5]
    },
	{
      "name": "EYES",
      "values": ["Bullaugen", "Eyes_human", "Hawt_Augen", "Schlitzauge", "Tearsdrops"],
      "trait_path": "./trait-layers/4_EYES",
      "filename": ["Bullaugen", "Eyes_human", "Hawt_Augen", "Schlitzauge", "Tearsdrops"],
      "weights": [20, 20, 20, 20, 20]
    },
	
	
	...
	
	
	 "incompatibilities": [
    {"layer": "BOTS", "value": "Ironman", "incompatible_with": ["Bullaugen"]},
    {"layer": "BOTS", "value": "Ironman", "incompatible_with": ["Eyes_human"]},
    {"layer": "BOTS", "value": "Ironman", "incompatible_with": ["Hawt_Augen"]},
    {"layer": "BOTS", "value": "Ironman", "incompatible_with": ["Schlitzauge"]},
    {"layer": "BOTS", "value": "Ironman", "incompatible_with": ["Tearsdrops"]}

  ],

upload tool

i have my nft collection created, what tool can i use to bulk upload with this metadata format ?

Add ability to block two or more traits from combining

As a user, I want to be able to configure the script to block certain elements from combining.

For example:
If my project has 2 traits: eyes and glasses.
One of my eyes are have an attribute of "popping out".
If the eyes are "popping out" I do not want glasses to be added.
All other eye attributes would be OK to apply glasses to according to.

Issue with recently introduced incompatibilities layer

Hi Jon,

The incompatibilities layer causes some unwanted behavior that I've been trying to sort out but couldn't find the underlying reason. My collection consists of 6 trait layers (accessory, backgrounds, body, clothing, eyes, head).

Here's an example of an incompatibilities layer configuration:

      "layer": "Clothing",
      "value": "Grey Hoodie",
      "incompatible_with": ["Alien Bucket","Alien Hat","Autism","Bear Bucket","Black Beanie","Bunny","Chairman Der","Che","Coby","Cock Bucket","Commander","Comrad","Crowley","Curli","Dope","Dubai","Durag","Fiddler Cap","Fidela","Fish Cap","Fur Hat","Geeza","General Soggafi","Green Beanie","High Hat","Hippie","Itamae","Khaki Bucket","Killa","Kufi","Le Chique","Mara","Neet","Orange Beanie","Pastafarian","Peak Cap","Propeller Hat","Racer","Slayer","Soggelz","Thizz Cap","Thot Police","Tinfoil Hat","Trapper","Wizard","Yellow Beanie"],
      "default": {
        "value": "None",
        "filename": "./trait-layers/head/None"
      }
    },

However, upon generating, in random occasions whenever the "Grey Hoodie" is drafted it also updates the "Eyes" trait layer and sets it to none, this also happens on other layers such as "Body" of which both should always be compatible (and are not configured in the incompatibilities section).

Below is a metadata example:

    "image": "./images/3.png",
    "tokenId": 3,
    "name": "NFT #03",
    "description": "This is a description for this NFT series.",
    "attributes": [
        {
            "trait_type": "Background",
            "value": "Carentan"
        },
        {
            "trait_type": "Body",
            "value": "None"
        },
        {
            "trait_type": "Eyes",
            "value": "Samsquanch"
        },
        {
            "trait_type": "Clothing",
            "value": "Grey Hoodie"
        },
        {
            "trait_type": "Head",
            "value": "None"
        },
        {
            "trait_type": "Accessory",
            "value": "Phone"
        }
    ]

Notice how the trait type "Body" is set to a value of "None" upon picking the "Grey Hoodie" attribute. Any idea why this might be happening?

Unused import in generate.py

There is unused import in line 2 in generate.py. I am not sure what that module does but it I was having issue importing IPython then I noticed that imported display was not getting used anywhere in generate.py.

Where to enter amount of nft i want to generate?

Hey in the previous version there was a line "generate_unique_images (50, {"

In the updated 2.0 version I can't find where should I enter the amount :( I have this error now: "heimdall: error: Missing a mandatory option (-n or -c). Use -h to show the help menu"

Layer exclusions based on attribute selection

Context:
I have 6 trait layers (Background, Body, Eyes, Clothing, Head, Accessory). In the "Clothing" layer I have an attribute named "Grey Hoodie". This attribute contains art that overlaps with the "Head" layer.

For this reason, ideally, the "Head" layer should be excluded when the "Grey Hoodie" is picked.

The current incompatibilities object does not account for this logic atm.

Idea:

Create a layer_incompatibilities object to add "layer exclusions" for certain attributes. This could look something like this:

"layer_incompatibilities": [
    {
      "layer": "Clothing",
      "value": "Grey Hoodie",
      "incompatible_with": ["Head"]
    }
  ],

Getting List index out of range error.

When I try to run the program with my attributes, I keep getting this error: Not sure why? I did add more traits and values than the original. Any ideas?

% python3 index.py

Traceback (most recent call last):
File "/Users/NAME/Desktop/nft-generator/index.py", line 83, in
generate_unique_images(8888, {
File "/Users/NAME/Desktop/nft-generator/index.py", line 28, in generate_unique_images
trait_files[trait["name"]][key] = trait["filename"][x];
IndexError: list index out of range

Make the script multithreading

To male the script work faster (especially in case of animation generation) I suggest to make the script multithreading with option to edit nubmer of threads.

Increasing amount causes failure after adding more incompatibilities

Hi there, thanks for providing this resource. It helps for learning.
Testing, I have been growing the number of incompatibilities between traits and layers.
Removing a few target blocks of incompatibilities, you can generate 1000 or more.
Adding those sections back will see premature finish with exit code -1073741571 (0xC00000FD)
However you can then generate about 200 but exceeding that will again result in EC: -1073741571 (0xC00000FD)

Does it need more assets in this situation due to growing the number of incompatibilities limiting the total number of possible outcomes below 200?

Increasing "Amount" causes error

As soon as I try to increase the amount i get an error

return [population[bisect(cum_weights, random() * total, 0, hi)] File "/usr/local/Cellar/[email protected]/3.9.7/Frameworks/Python.framework/Versions/3.9/lib/python3.9/random.py", line 505, in <listcomp> return [population[bisect(cum_weights, random() * total, 0, hi)] RecursionError: maximum recursion depth exceeded in comparison

Multiple incompatibilities?

If I have 30 of each layers and I want one whole category to be incompatible with the other, my incompatibilities array would be full! Any way to achieve this fast? I need it tomorrow :(

Can't open JSON?

Traceback (most recent call last):
File "PATH\nft-generator-py-main\generate.py", line 147, in
generate_unique_images(int(args.amount), loadJSON(args.config))
File "PATH\nft-generator-py-main\lib\util\io.py", line 9, in loadJSON
contents = json.loads("".join(pathFile.readlines()))
File "C:\Users\PATH\miniconda3\lib\json_init_.py", line 346, in loads
return _default_decoder.decode(s)
File "C:\Users\PATH\miniconda3\lib\json\decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "C:\Users\PATH\miniconda3\lib\json\decoder.py", line 355, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 38 column 3 (char 9226)

I'm having this error when i try to python generate.py --amount 222 --config config.json

Errno2: No such file or directory for Metadata

Traceback (most recent call last):
File "/nft-generator-py-main/index.py", line 225, in
"description": "Space Cowboys NFT Collection"
File "/nft-generator-py-main/index.py", line 57, in generate_unique_images
with open('./metadata/all-objects.json', 'w') as outfile:
FileNotFoundError: [Errno 2] No such file or directory: './metadata/all-objects.json'

DNA

Hi Jon,

Not a dev, but had someone in exchange for some crypto to add the DNA for me.

Would you include it please in your next code update after you find a solution for below? I'll send you the zip if affirmative.

thanks for the tip, but then i get a few combinations where the EYES are missing where they should not. sorry for bothering you :)

I will look for a solution for now. You can add an imcompatibility with EYES none with everything but ironman. It'll only pick a none layer if ironman is selected then, and never pick a none layer otherwise.

Originally posted by @Jon-Becker in #19 (comment)

Include requirements file

First of all, thanks for this great project and the effort involved in it!!

I know the script is small but I still think would be great to add a requirements.txt file so can be easier for anyone installing the project to execute it.

The random.choices weighting seems quite innacurate

have been playing around with this all day and Im trying to deal with some really accurate trait weighting and unfortunately it seems like the randomness from the weighting is super inaccurate.

Any ideas what could be going on here? I have an example with 3 layers making 200 images and some of the lower end % traits should only be showing the image once but there are occasions where that trait will maybe show 4 - 5 times.

ValueError: images do not match

Generating 11 unique NFTs...
Traceback (most recent call last):
File "index.py", line 110, in
generate_unique_images(11, {
File "index.py", line 83, in generate_unique_images
main_composite = Image.alpha_composite(layers[0], layers[1])
File "/usr/lib/python3/dist-packages/PIL/Image.py", line 2882, in alpha_composite
return im1._new(core.alpha_composite(im1.im, im2.im))
ValueError: images do not match

continuously having this issue even though i checked and all files/directories match.
index.txt

How to start from where it's left?

How to start the generating image process from where it's left.
I've been trying to generate images and they almost certainly interrupted at %80-90 completed.
Is it possible to start from where it's interrupted? As all the metadata is already generated.

PS: Thank you for your awesome tool and releasing it for free.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.