mirror of
https://gitee.com/dify_ai/dify.git
synced 2024-12-04 20:28:12 +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