Getting Started with the Firefly Services SDK
As a developer, you have the flexibility to choose how you want to integrate with Firefly Services, tailoring the experience to your specific needs and preferences.
Overview
Whether you prefer the direct control and language-specific implementations provided by REST APIs or the simplified, streamlined approach offered by our Node SDK, Firefly Services has you covered.
Choosing the Right Approach for Your Project
When to Use REST APIs: If you need maximum flexibility, detailed control, and are working in a language other than JavaScript/TypeScript, direct REST API access might be the best choice for you.
When to Use the Node SDK: If you're working in a
Node.js
environment and want to simplify the integration process, reduce boilerplate code, and speed up development, the Node SDK is the way to go. By offering both direct REST API access and a Node SDK, Firefly Services ensures that you have the tools you need to build powerful integrations in the way that best suits your workflow.
Let's explore what you need to get started with your first integration.
The SDK supports Node.js and either JavaScript or TypeScript. While this article will focus on Firefly APIs, the SDK also includes Photoshop and Lightroom APIs.
Prerequisites
- You will need a set of credentials for Firefly Services. You can get those here.
The Workflow
Before digging into the code, let's break down the process.
- Add the SDK packages
- Setting up authentication
- Instantiate Firefly
- Generating an Image with a Prompt
- Download the Results
Step 1: Add the SDK packages
Let's begin by initializing a new package.json
in your prompt with npm init -y
.
Next, you need to add the SDK. As described in the SDK's readme, there are four individual packages you can install:
- The
common APIs
package is required for authentication, you'll always need this. - A package for Firefly API.
- A package for Photoshop API.
- A package for Lightroom API.
For your needs, you only require the common and Firefly APIs. Install them like so:
Copied to your clipboardnpm install @adobe/firefly-services-common-apisnpm install @adobe/firefly-apis
Lastly, in order to use top-level await and imports, add a type
setting of module
to your package.json. Here's a complete example for reference:
Copied to your clipboard{"name": "code","version": "1.0.0","type":"module","description": "","main": "firefly.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"keywords": [],"author": "","license": "ISC","dependencies": {"@adobe/firefly-apis": "^1.0.0","@adobe/firefly-services-common-apis": "^1.0.0"}}
Step 2: Setting up Authentication
Let's begin with a simple example, generating an image from a prompt. Our code needs to begin with authentication and creating the Firefly object:
Copied to your clipboardimport { FireflyClient } from '@adobe/firefly-apis';const authOptions = {autoRefresh: true,serviceEnvironment:'stage'};const firefly = await FireflyClient.createWithCredentials(process.env.CLIENT_ID, process.env.CLIENT_SECRET, authOptions);
In the code above, you need to use two environment variables (CLIENT_ID
and CLIENT_SECRET
) and pass them to the createWithCredentials
method. Note that for the bug bash, the authOptions
object specified above is required.
Step 3: Instantiate Firefly
The next part is much more simple, creating an instance of the Firefly SDK:
Copied to your clipboardimport { FireflyClient } from '@adobe/firefly-apis';const firefly = new FireflyClient(config);
Step 4: Generating an Image with a Prompt
With authentication done and the Firefly client created, how do you generate images for a prompt? It takes all of one line!
Copied to your clipboardconst resp = await firefly.generateImages({prompt:'a cat riding a unicorn headed into the sunset, dramatic pose'});
As a reminder, the Firefly API can accept many parameters, and they're all supported by the SDK, but in this case, you have passed just a prompt and the number of images required. The result of the SDK call is twofold - first a result
JSON object that matches what the REST API returns, and secondly a set of headers
you can inspect if needed.
Here's the JSON returned in the result
key:
Copied to your clipboard{"size": {"width": 2048,"height": 2048},"outputs": [{"seed": 85987617,"image": {"url": "https://pre-signed-firefly-stage.s3-accelerate.amazonaws.com/images/2df5e7ac-cd6a-42c1-b407-e9c316006a55?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIA55EBG7KCZFCHQDZT%2F20240606%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240606T144529Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=cbcdb705aa5f2ceeefb524c31b96715381f1f8e5980126f5051b7b289bfc31e3"}}],"contentClass": "photo"}
Step 5: Download the Results
Currently, the SDK doesn't support downloading the images for you, but this can be done with a few lines of code. Here's the required import and a basic utility function to download a URL to a path:
Copied to your clipboardimport fs from 'fs';import { Readable } from 'stream';import { finished } from 'stream/promises';async function downloadFile(url, filePath) {let res = await fetch(url);const body = Readable.fromWeb(res.body);const download_write_stream = fs.createWriteStream(filePath);return await finished(body.pipe(download_write_stream));}
To put it all together, here's a complete script that handles the authentication, generating images based on our prompt, and then saving each result to the file system using the results seed
value.
Copied to your clipboardimport fs from 'fs';import { Readable } from 'stream';import { finished } from 'stream/promises';import { FireflyClient } from '@adobe/firefly-apis';async function downloadFile(url, filePath) {let res = await fetch(url);const body = Readable.fromWeb(res.body);const download_write_stream = fs.createWriteStream(filePath);return await finished(body.pipe(download_write_stream));}const authOptions = {autoRefresh: true,serviceEnvironment:'stage'};const firefly = await FireflyClient.createWithCredentials(process.env.CLIENT_ID, process.env.CLIENT_SECRET, authOptions);const resp = await firefly.generateImages({prompt:'a cat riding a unicorn headed into the sunset, dramatic pose', n:4});for(let output of resp.result.outputs) {let fileName = `./${output.seed}.jpg`;await downloadFile(output.image.url, fileName);}
And here's one of the sample results of our prompt:
Additional workflow: Working with Reference Images
One of the benefits of having a Firefly SDK is how easy it is to build more complex workflows. To demonstrate a simple example of this, let's enhance our simple text-to-image prompt example by using a reference image. Reference images help guide the visual style of the generated result.
In order for this to work, you first need your reference image. You can use this:
Skipping over the authentication bits that is already covered, the first change is to upload our reference image:
Copied to your clipboardconst uploadResp = await firefly.upload(new Blob([await fs.readFile('./source_image.jpg')],{type:'image/jpeg'}));
The upload
SDK method requires a Blob which is wrapped around a file read on ./source_image.jpg
. As with the previous SDK example, the response includes a JSON result as well as the headers, with the JSON matching what you get when using the REST API. As an example:
Copied to your clipboard{"images": [{"id": "9f54159b-f0e9-4696-b4f5-f543a3fb90c0"}]}
Using that reference when generating images looks like so:
Copied to your clipboardconst resp = await firefly.generateImages({prompt:'a cat riding a unicorn headed into the sunset, dramatic pose', style: {imageReference: {source: {uploadId:uploadResp.result.images[0].id}}}});
Compared to the previous version of the SDK, the style
attribute has been added and passed in the imageReference
value. The changes to the generated images are immediately recognizable as being based on the style of the reference image.
Next Steps
Now that you've seen how the SDK can *greatly* simplify your Firefly Services workflows, take a look over the Github repository and check out the docs and other samples as well.