Package: novelai
NovelAI-APIA lightweight asynchronous Python wrapper for NovelAI image generation API.FeaturesLightweight- Focuses on image generation only, providing a simple and easy-to-use interface.Concurrent- Supports both API and web backend, allowing to run two generating tasks simultaneously.Parameterized- Provides aMetadataclass to easily set up generation parameters with type validation.Asynchronous- Utilizesasyncioto run generating tasks and return outputs efficiently.InstallationInstall with pip:pipinstallnovelaiNote that this package requires Python3.12or higher. For Python 3.7-3.11, install the legacy version instead:pipinstallnovelai-legacyLegacy branch has the same features as master branch on user side, the only difference is code compatibility.UsageInitializationImport required packages and initialize a client with your NovelAI account credentials.importasynciofromnovelaiimportNAIClient# Replace argument values with your actual account credentialsusername="Your NovelAI username"password="Your NovelAI password"asyncdefmain():client=NAIClient(username,password,proxy=None)awaitclient.init(timeout=30)asyncio.run(main())Image GenerationAfter initializing successfully, you can generate images with thegenerate_imagemethod. The method takes aMetadataobject as the first argument, and an optionalhostargument to specify the backend to use.By passingverbose=True, the method will print the estimated Anlas cost each time a generating request is going to be made.The full parameter list ofMetadatacan be found in theclass definition.fromnovelaiimportMetadata,Host,Resolutionasyncdefmain():metadata=Metadata(prompt="1girl",negative_prompt="bad anatomy",res_preset=Resolution.NORMAL_PORTRAIT,n_samples=1,)print(f"Estimated Anlas cost:{metadata.calculate_cost(is_opus=False)}")# Choose host between "Host.API" and "Host.WEB"# Both of two hosts work the same for all actions mentioned belowoutput=awaitclient.generate_image(metadata,host=Host.WEB,verbose=False,is_opus=False)forimageinoutput:image.save(path="output images",verbose=True)asyncio.run(main())Image to ImageTo performimg2imgaction, setactionparameter in Metadata toAction.IMG2IMG, andimageparameter to your base image. The base image  needs to be converted into Base64-encoded format. This can be achieved usingbase64module.importbase64fromnovelaiimportMetadata,Actionasyncdefmain():withopen("tests/images/portrait.jpg","rb")asf:base_image=base64.b64encode(f.read()).decode("utf-8")metadata=Metadata(prompt="1girl",negative_prompt="bad anatomy",action=Action.IMG2IMG,width=832,height=1216,n_samples=1,image=base_image,strength=0.5,noise=0.1,)output=awaitclient.generate_image(metadata,verbose=True)forimageinoutput:image.save(path="output images",verbose=True)asyncio.run(main())InpaintingTo performinpaintaction, setactionparameter in Metadata toAction.INPAINTING, andimageparameter to your base image, andmaskparameter to the black and whitemask image, where white is the area to inpaint and black to keep as is. Both base image and mask need to be converted into Base64-encoded format. This can be achieved usingbase64module.importbase64fromnovelaiimportMetadata,Model,Action,Resolutionasyncdefmain():withopen("tests/images/portrait.jpg","rb")asf:base_image=base64.b64encode(f.read()).decode("utf-8")withopen("tests/images/inpaint_left.jpg","rb")asf:mask=base64.b64encode(f.read()).decode("utf-8")metadata=Metadata(prompt="1girl",negative_prompt="bad anatomy",model=Model.V3INP,action=Action.INPAINT,res_preset=Resolution.NORMAL_PORTRAIT,image=base_image,mask=mask,)output=awaitclient.generate_image(metadata,verbose=True)forimageinoutput:image.save(path="output images",verbose=True)asyncio.run(main())Vibe TransferVibe transfer doesn't have its own action type. Instead, it is achieved by adding areference_imageparameter in Metadata. The reference image needs to be converted into Base64-encoded format. This can be achieved usingbase64module.importbase64fromnovelaiimportMetadata,Resolutionasyncdefmain():withopen("tests/images/portrait.jpg","rb")asf:base_image=base64.b64encode(f.read()).decode("utf-8")metadata=Metadata(prompt="1girl",negative_prompt="bad anatomy",res_preset=Resolution.NORMAL_PORTRAIT,reference_image=base_image,reference_infomation_extracted=1,reference_strength=0.6,)output=awaitclient.generate_image(metadata,verbose=True)forimageinoutput:image.save(path="output images",verbose=True)asyncio.run(main())Concurrent GenerationBy default, NovelAI only allows one concurrent generating task at a time. However, this wrapper provides the ability tosimultaneously run two concurrent generating tasksby sending requests to API and web backend respectively.Note that API and web backend both have limit on concurrent generation. Therefore, running more than two concurrent tasks will result in a429 Too Many Requestserror.Full usage exampleis provided under/docs.asyncdeftask_api():awaitclient.generate_image(metadata,host=Host.API)print("API task completed")asyncdeftask_web():awaitclient.generate_image(metadata,host=Host.WEB)print("Web task completed")asyncdefmain():tasks=[asyncio.create_task(task_api()),asyncio.create_task(task_web()),]awaitasyncio.wait(tasks)asyncio.run(main())Use in CLIOptionally, a module function is also provided to directly generate access token in CLI.Once a access token is generated, it will be valid for 30 days. Token can be used as the authentication header to make requests to NovelAI.# Replace argument values with your actual account credentialspython3-mnovelailogin<username><password>ReferencesNovelAI BackendAedial/novelai-apiNovelAI Unofficial Knowledgebase