mirror of
https://gitee.com/dify_ai/dify.git
synced 2024-12-05 04:38:37 +08:00
feat(tool): getimg.ai integration (#6260)
This commit is contained in:
parent
c013086e64
commit
49ef9ef225
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><rect x="32" y="48" width="192" height="160" rx="8" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><circle cx="156" cy="100" r="12"/><path d="M147.31,164,173,138.34a8,8,0,0,1,11.31,0L224,178.06" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M32,168.69l54.34-54.35a8,8,0,0,1,11.32,0L191.31,208" fill="none" stroke="#1553ed" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></svg>
|
After Width: | Height: | Size: 617 B |
22
api/core/tools/provider/builtin/getimgai/getimgai.py
Normal file
22
api/core/tools/provider/builtin/getimgai/getimgai.py
Normal file
@ -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
api/core/tools/provider/builtin/getimgai/getimgai.yaml
Normal file
29
api/core/tools/provider/builtin/getimgai/getimgai.yaml
Normal file
@ -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
api/core/tools/provider/builtin/getimgai/getimgai_appx.py
Normal file
59
api/core/tools/provider/builtin/getimgai/getimgai_appx.py
Normal file
@ -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
api/core/tools/provider/builtin/getimgai/tools/text2image.py
Normal file
39
api/core/tools/provider/builtin/getimgai/tools/text2image.py
Normal file
@ -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
api/core/tools/provider/builtin/getimgai/tools/text2image.yaml
Normal file
167
api/core/tools/provider/builtin/getimgai/tools/text2image.yaml
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user