Skip to content

Commit

Permalink
feat(tool): getimg.ai integration (langgenius#6260)
Browse files Browse the repository at this point in the history
  • Loading branch information
MatriQ authored and cuiks committed Aug 6, 2024
1 parent 1de9df5 commit e38ab7d
Show file tree
Hide file tree
Showing 6 changed files with 317 additions and 0 deletions.
1 change: 1 addition & 0 deletions api/core/tools/provider/builtin/getimgai/_assets/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions api/core/tools/provider/builtin/getimgai/getimgai.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from core.tools.errors import ToolProviderCredentialValidationError
from core.tools.provider.builtin.getimgai.tools.text2image import Text2ImageTool
from core.tools.provider.builtin_tool_provider import BuiltinToolProviderController


class GetImgAIProvider(BuiltinToolProviderController):
def _validate_credentials(self, credentials: dict) -> None:
try:
# Example validation using the text2image tool
Text2ImageTool().fork_tool_runtime(
runtime={"credentials": credentials}
).invoke(
user_id='',
tool_parameters={
"prompt": "A fire egg",
"response_format": "url",
"style": "photorealism",
}
)
except Exception as e:
raise ToolProviderCredentialValidationError(str(e))

29 changes: 29 additions & 0 deletions api/core/tools/provider/builtin/getimgai/getimgai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
identity:
author: Matri Qi
name: getimgai
label:
en_US: getimg.ai
zh_CN: getimg.ai
description:
en_US: GetImg API integration for image generation and scraping.
icon: icon.svg
tags:
- image
credentials_for_provider:
getimg_api_key:
type: secret-input
required: true
label:
en_US: getimg.ai API Key
placeholder:
en_US: Please input your getimg.ai API key
help:
en_US: Get your getimg.ai API key from your getimg.ai account settings. If you are using a self-hosted version, you may enter any key at your convenience.
url: https://dashboard.getimg.ai/api-keys
base_url:
type: text-input
required: false
label:
en_US: getimg.ai server's Base URL
placeholder:
en_US: https://api.getimg.ai/v1
59 changes: 59 additions & 0 deletions api/core/tools/provider/builtin/getimgai/getimgai_appx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import logging
import time
from collections.abc import Mapping
from typing import Any

import requests
from requests.exceptions import HTTPError

logger = logging.getLogger(__name__)

class GetImgAIApp:
def __init__(self, api_key: str | None = None, base_url: str | None = None):
self.api_key = api_key
self.base_url = base_url or 'https://api.getimg.ai/v1'
if not self.api_key:
raise ValueError("API key is required")

def _prepare_headers(self):
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {self.api_key}'
}
return headers

def _request(
self,
method: str,
url: str,
data: Mapping[str, Any] | None = None,
headers: Mapping[str, str] | None = None,
retries: int = 3,
backoff_factor: float = 0.3,
) -> Mapping[str, Any] | None:
for i in range(retries):
try:
response = requests.request(method, url, json=data, headers=headers)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
if i < retries - 1 and isinstance(e, HTTPError) and e.response.status_code >= 500:
time.sleep(backoff_factor * (2 ** i))
else:
raise
return None

def text2image(
self, mode: str, **kwargs
):
data = kwargs['params']
if not data.get('prompt'):
raise ValueError("Prompt is required")

endpoint = f'{self.base_url}/{mode}/text-to-image'
headers = self._prepare_headers()
logger.debug(f"Send request to {endpoint=} body={data}")
response = self._request('POST', endpoint, data, headers)
if response is None:
raise HTTPError("Failed to initiate getimg.ai after multiple retries")
return response
39 changes: 39 additions & 0 deletions api/core/tools/provider/builtin/getimgai/tools/text2image.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import json
from typing import Any, Union

from core.tools.entities.tool_entities import ToolInvokeMessage
from core.tools.provider.builtin.getimgai.getimgai_appx import GetImgAIApp
from core.tools.tool.builtin_tool import BuiltinTool


class Text2ImageTool(BuiltinTool):
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
app = GetImgAIApp(api_key=self.runtime.credentials['getimg_api_key'], base_url=self.runtime.credentials['base_url'])

options = {
'style': tool_parameters.get('style'),
'prompt': tool_parameters.get('prompt'),
'aspect_ratio': tool_parameters.get('aspect_ratio'),
'output_format': tool_parameters.get('output_format', 'jpeg'),
'response_format': tool_parameters.get('response_format', 'url'),
'width': tool_parameters.get('width'),
'height': tool_parameters.get('height'),
'steps': tool_parameters.get('steps'),
'negative_prompt': tool_parameters.get('negative_prompt'),
'prompt_2': tool_parameters.get('prompt_2'),
}
options = {k: v for k, v in options.items() if v}

text2image_result = app.text2image(
mode=tool_parameters.get('mode', 'essential-v2'),
params=options,
wait=True
)

if not isinstance(text2image_result, str):
text2image_result = json.dumps(text2image_result, ensure_ascii=False, indent=4)

if not text2image_result:
return self.create_text_message("getimg.ai request failed.")

return self.create_text_message(text2image_result)
167 changes: 167 additions & 0 deletions api/core/tools/provider/builtin/getimgai/tools/text2image.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
identity:
name: text2image
author: Matri Qi
label:
en_US: text2image
icon: icon.svg
description:
human:
en_US: Generate image via getimg.ai.
llm: This tool is used to generate image from prompt or image via https://getimg.ai.
parameters:
- name: prompt
type: string
required: true
label:
en_US: prompt
human_description:
en_US: The text prompt used to generate the image. The getimg.aier will generate an image based on this prompt.
llm_description: this prompt text will be used to generate image.
form: llm
- name: mode
type: select
required: false
label:
en_US: mode
human_description:
en_US: The getimg.ai mode to use. The mode determines the endpoint used to generate the image.
form: form
options:
- value: "essential-v2"
label:
en_US: essential-v2
- value: stable-diffusion-xl
label:
en_US: stable-diffusion-xl
- value: stable-diffusion
label:
en_US: stable-diffusion
- value: latent-consistency
label:
en_US: latent-consistency
- name: style
type: select
required: false
label:
en_US: style
human_description:
en_US: The style preset to use. The style preset guides the generation towards a particular style. It's just efficient for `Essential V2` mode.
form: form
options:
- value: photorealism
label:
en_US: photorealism
- value: anime
label:
en_US: anime
- value: art
label:
en_US: art
- name: aspect_ratio
type: select
required: false
label:
en_US: "aspect ratio"
human_description:
en_US: The aspect ratio of the generated image. It's just efficient for `Essential V2` mode.
form: form
options:
- value: "1:1"
label:
en_US: "1:1"
- value: "4:5"
label:
en_US: "4:5"
- value: "5:4"
label:
en_US: "5:4"
- value: "2:3"
label:
en_US: "2:3"
- value: "3:2"
label:
en_US: "3:2"
- value: "4:7"
label:
en_US: "4:7"
- value: "7:4"
label:
en_US: "7:4"
- name: output_format
type: select
required: false
label:
en_US: "output format"
human_description:
en_US: The file format of the generated image.
form: form
options:
- value: jpeg
label:
en_US: jpeg
- value: png
label:
en_US: png
- name: response_format
type: select
required: false
label:
en_US: "response format"
human_description:
en_US: The format in which the generated images are returned. Must be one of url or b64. URLs are only valid for 1 hour after the image has been generated.
form: form
options:
- value: url
label:
en_US: url
- value: b64
label:
en_US: b64
- name: model
type: string
required: false
label:
en_US: model
human_description:
en_US: Model ID supported by this pipeline and family. It's just efficient for `Stable Diffusion XL`, `Stable Diffusion`, `Latent Consistency` mode.
form: form
- name: negative_prompt
type: string
required: false
label:
en_US: negative prompt
human_description:
en_US: Text input that will not guide the image generation. It's just efficient for `Stable Diffusion XL`, `Stable Diffusion`, `Latent Consistency` mode.
form: form
- name: prompt_2
type: string
required: false
label:
en_US: prompt2
human_description:
en_US: Prompt sent to second tokenizer and text encoder. If not defined, prompt is used in both text-encoders. It's just efficient for `Stable Diffusion XL` mode.
form: form
- name: width
type: number
required: false
label:
en_US: width
human_description:
en_US: he width of the generated image in pixels. Width needs to be multiple of 64.
form: form
- name: height
type: number
required: false
label:
en_US: height
human_description:
en_US: he height of the generated image in pixels. Height needs to be multiple of 64.
form: form
- name: steps
type: number
required: false
label:
en_US: steps
human_description:
en_US: The number of denoising steps. More steps usually can produce higher quality images, but take more time to generate. It's just efficient for `Stable Diffusion XL`, `Stable Diffusion`, `Latent Consistency` mode.
form: form

0 comments on commit e38ab7d

Please sign in to comment.