Skip to content

Commit c57b1d5

Browse files
committed
feat: add support for leonardoai
1 parent 4c4f1dd commit c57b1d5

File tree

3 files changed

+177
-0
lines changed

3 files changed

+177
-0
lines changed

README.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ If you would like to make a donation to support development, please use [GitHub
4242
- [Stability AI](https://stability.ai)
4343
- [Dream](https://dream.ai)
4444
- [DeepAI](https://deepai.org)
45+
- [Leonardo.Ai](https://leonardo.ai)
4546

4647
\* _Midjourney currently uses an unofficial third party [package](https://github.com/erictik/midjourney-client). Use this integration at your own risk._
4748

@@ -367,6 +368,53 @@ dream:
367368
- buliojourney v2
368369
```
369370

371+
### `leonardoai`
372+
373+
To configure Leonardo.Ai, obtain an [API key](https://leonardo.ai) and add it to your config like the following. All other default settings found bellow will also be applied. You can overwrite the settings by updating your `config.yml` file.
374+
375+
```yaml
376+
# leonardoai settings (default: shown below)
377+
378+
leonardoai:
379+
# api key
380+
key:
381+
382+
image:
383+
# enable or disable image generation
384+
enable: true
385+
# number of seconds before the request times out and is aborted
386+
timeout: 30
387+
# indicate what you want to be removed from the image
388+
negative_prompt:
389+
# model id used for the image generation, if not provided uses sd_version to determine the version of stable diffusion to use
390+
model_id: 6bef9f1b-29cb-40c7-b9df-32b51c1f67d3
391+
# base version of stable diffusion to use if not using a custom model
392+
sd_version: v2
393+
# number of images to generate for each style
394+
num_images: 1
395+
# width of the image in pixels, must be between 32 and 1024 and be a multiple of 8
396+
width: 512
397+
# height of the image in pixels, must be between 32 and 1024 and be a multiple of 8
398+
height: 512
399+
# number of inference steps to use for the generation, must be between 30 and 60
400+
num_inference_steps:
401+
# how strongly the generation should reflect the prompt, must be between 1 and 20.
402+
guidance_scale: 7
403+
# scheduler to generate images with
404+
scheduler:
405+
# style to generate images with
406+
preset_style: LEONARDO
407+
# whether the generated images should tile on all axis
408+
tiling:
409+
# whether the generated images should show in the community feed
410+
public:
411+
# enable to use prompt magic
412+
prompt_magic:
413+
# used with summary to guide the image model towards a particular style
414+
style:
415+
- cinematic
416+
```
417+
370418
### `time`
371419

372420
```yaml

api/src/ai/leonardoai.ts

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import axios from 'axios';
2+
3+
import AI, { LogError } from './ai';
4+
import config from '../config';
5+
6+
const {
7+
LEONARDOAI: { KEY, IMAGE },
8+
} = config();
9+
10+
class DeepAI extends AI {
11+
generationId?: string;
12+
constructor(meta?: any) {
13+
super('leonardoai', meta);
14+
this.generationId = undefined;
15+
this.styles = IMAGE.STYLE;
16+
}
17+
18+
async generateImageId() {
19+
const { data } = await axios({
20+
method: 'post',
21+
url: 'https://cloud.leonardo.ai/api/rest/v1/generations',
22+
headers: {
23+
Authorization: `Bearer ${KEY}`,
24+
},
25+
data: {
26+
prompt: `${this.meta.summary.summary}, ${this.style}`,
27+
negative_prompt: IMAGE.NEGATIVE_PROMPT,
28+
modelId: IMAGE.MODEL_ID,
29+
sd_version: IMAGE.SD_VERSION,
30+
num_images: IMAGE.NUM_IMAGES,
31+
width: IMAGE.WIDTH,
32+
height: IMAGE.HEIGHT,
33+
num_inference_steps: IMAGE.NUM_INFERENCE_STEPS,
34+
guidance_scale: IMAGE.GUIDANCE_SCALE,
35+
scheduler: IMAGE.SCHEDULER,
36+
presetStyle: IMAGE.PRESET_STYLE,
37+
tiling: IMAGE.TILING,
38+
public: IMAGE.PUBLIC,
39+
promptMagic: IMAGE.PROMPT_MAGIC,
40+
},
41+
});
42+
43+
if (data?.sdGenerationJob?.generationId) this.generationId = data.sdGenerationJob.generationId;
44+
}
45+
46+
async generateImage() {
47+
await this.createAttemptHandler('create generation', this.generateImageId.bind(this))();
48+
if (!this.generationId) {
49+
this.log.error('generation id not found');
50+
return;
51+
}
52+
const images = await this.waitForImage();
53+
if (images?.length) await this.downloadImage(images);
54+
}
55+
56+
async waitForImage() {
57+
try {
58+
this.log.info('wait for image');
59+
for (let i = 0; i < IMAGE.TIMEOUT; i++) {
60+
const { data } = await axios({
61+
method: 'get',
62+
url: `https://cloud.leonardo.ai/api/rest/v1/generations/${this.generationId}`,
63+
headers: {
64+
Authorization: `Bearer ${KEY}`,
65+
},
66+
});
67+
68+
if (i === IMAGE.TIMEOUT / 2) {
69+
this.log.info('still waiting');
70+
}
71+
72+
const { status, generated_images } = data.generations_by_pk;
73+
if (status == 'FAILED') {
74+
this.log.error('failed to generate image');
75+
break;
76+
} else if (status == 'COMPLETE') {
77+
return generated_images.map(({ url }: { url: string }) => ({
78+
url,
79+
}));
80+
}
81+
await this.sleep(1);
82+
}
83+
this.log.warn(`image was not generated after ${IMAGE.TIMEOUT} seconds`);
84+
} catch (error: any) {
85+
this.logError({ type: 'wait for image', error });
86+
throw new Error(error);
87+
}
88+
}
89+
90+
async test() {
91+
try {
92+
const { data } = await axios({
93+
method: 'get',
94+
url: 'https://cloud.leonardo.ai/api/rest/v1/me',
95+
headers: { Authorization: `Bearer ${KEY}` },
96+
timeout: 10000,
97+
});
98+
return true;
99+
} catch (error: any) {
100+
return error?.response?.data || error;
101+
}
102+
}
103+
104+
logError({ type, error }: LogError) {
105+
this.log.error(`${type}: ${error?.response?.data.error || error}`);
106+
}
107+
}
108+
109+
export default DeepAI;

api/src/config/default.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,24 @@ export default {
7171
style: ['cinematic'],
7272
},
7373
},
74+
leonardoai: {
75+
image: {
76+
enable: true,
77+
negative_prompt: null,
78+
model_id: '6bef9f1b-29cb-40c7-b9df-32b51c1f67d3',
79+
sd_version: 'v2',
80+
num_images: 1,
81+
width: 512,
82+
height: 512,
83+
num_inference_steps: null,
84+
guidance_scale: 7,
85+
scheduler: null,
86+
preset_style: 'LEONARDO',
87+
tiling: null,
88+
public: null,
89+
prompt_magic: null,
90+
timeout: 30,
91+
style: ['cinematic'],
92+
},
93+
},
7494
};

0 commit comments

Comments
 (0)