From 7c6a1389d4a9397243e870e4727a107cece4f0cb Mon Sep 17 00:00:00 2001 From: Abhi Date: Thu, 18 Jun 2026 14:02:14 +0530 Subject: [PATCH] Add new tools: edit image, generate audio/video, image to video, remix audio, remove background, upscale image --- README.md | 321 +++++++++++++++++++++++++++++------ main.py | 2 +- manifest.yaml | 2 +- provider/muapi.yaml | 9 +- provider/muapi_provider.py | 12 +- requirements.txt | 2 +- tools/edit_image.py | 55 ++++++ tools/edit_image.yaml | 56 ++++++ tools/generate_audio.py | 64 +++++++ tools/generate_audio.yaml | 56 ++++++ tools/generate_video.py | 64 +++++++ tools/generate_video.yaml | 58 +++++++ tools/image_to_video.py | 65 +++++++ tools/image_to_video.yaml | 68 ++++++++ tools/remix_audio.py | 67 ++++++++ tools/remix_audio.yaml | 55 ++++++ tools/remove_background.py | 53 ++++++ tools/remove_background.yaml | 36 ++++ tools/upscale_image.py | 53 ++++++ tools/upscale_image.yaml | 47 +++++ 20 files changed, 1085 insertions(+), 60 deletions(-) create mode 100644 tools/edit_image.py create mode 100644 tools/edit_image.yaml create mode 100644 tools/generate_audio.py create mode 100644 tools/generate_audio.yaml create mode 100644 tools/generate_video.py create mode 100644 tools/generate_video.yaml create mode 100644 tools/image_to_video.py create mode 100644 tools/image_to_video.yaml create mode 100644 tools/remix_audio.py create mode 100644 tools/remix_audio.yaml create mode 100644 tools/remove_background.py create mode 100644 tools/remove_background.yaml create mode 100644 tools/upscale_image.py create mode 100644 tools/upscale_image.yaml diff --git a/README.md b/README.md index df5376b..9218b1c 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,35 @@ # MuAPI Dify Plugin -A custom Dify Tool Plugin that integrates **MuAPI** into Dify, enabling image generation directly from Dify workflows, chatflows, and agents. +A comprehensive Dify Tool Plugin that integrates **MuAPI** into Dify, enabling AI-powered image generation, video creation, audio production, image editing, and more — directly from Dify workflows, chatflows, and agents. + +--- ## Features -### Current Features +### Image Tools + +* **Generate Image** — Create images from text prompts using AI models +* **Edit Image** — Transform existing images with text-guided editing +* **Remove Background** — Remove backgrounds to produce transparent images +* **Upscale Image** — Enhance image resolution with AI upscaling + +### Video Tools -* Generate images using MuAPI -* Configure MuAPI API key through Dify credentials -* Return generated images directly into Dify -* Support custom prompts -* Configurable image generation parameters: +* **Generate Video** — Create videos from text prompts +* **Image to Video** — Animate static images into videos - * Model - * Width - * Height - * Number of Images +### Audio Tools -### Planned Features +* **Generate Audio** — Create music and audio from text descriptions +* **Remix Audio** — Transform existing audio with text-guided remixing -* Video Generation -* Image Editing -* Background Removal -* Image Upscaling -* Audio Generation -* Audio Remix -* Model Discovery +### Platform Features + +* MuAPI API key credential management through Dify +* Real-time credential validation via API +* Rich Dify outputs (inline images, playable video/audio links) +* Support for 100+ AI models via MuAPI +* Configurable parameters per tool (model, dimensions, duration, etc.) --- @@ -54,9 +58,24 @@ muapi-dify-plugin/ │ ├── tools/ │ ├── generate_image.py -│ └── generate_image.yaml +│ ├── generate_image.yaml +│ ├── generate_video.py +│ ├── generate_video.yaml +│ ├── image_to_video.py +│ ├── image_to_video.yaml +│ ├── edit_image.py +│ ├── edit_image.yaml +│ ├── remove_background.py +│ ├── remove_background.yaml +│ ├── upscale_image.py +│ ├── upscale_image.yaml +│ ├── generate_audio.py +│ ├── generate_audio.yaml +│ ├── remix_audio.py +│ └── remix_audio.yaml │ └── _assets/ + └── icon.png ``` --- @@ -67,7 +86,7 @@ muapi-dify-plugin/ * Docker Desktop * WSL2 -* Dify +* Dify (running instance) * Python 3.12 * Go (required for packaging plugins) @@ -175,21 +194,127 @@ After installation: 1. Open MuAPI Plugin 2. Configure Provider Credentials -3. Enter: +3. Enter your **MuAPI API Key** +4. Save configuration -```text -MUAPI API Key -``` +The plugin validates your API key by calling the MuAPI account balance endpoint. If the key is invalid, you will see a credential validation error. -Save configuration. +Get your API key from: [https://muapi.ai/dashboard](https://muapi.ai/dashboard) --- -## Usage +## Available Tools ### Generate Image -Add the **Generate Image** tool to a workflow. +Create images from text prompts. + +| Parameter | Type | Required | Default | Description | +|-----------|------|----------|---------|-------------| +| prompt | string | Yes | — | Text prompt describing the image | +| model | string | No | flux-dev | Image generation model | +| width | number | No | 1024 | Width in pixels | +| height | number | No | 1024 | Height in pixels | +| num_images | number | No | 1 | Number of images to generate | + +--- + +### Generate Video + +Create videos from text prompts. + +| Parameter | Type | Required | Default | Description | +|-----------|------|----------|---------|-------------| +| prompt | string | Yes | — | Text prompt describing the video | +| model | string | No | kling-master | Video generation model | +| duration | number | No | 5 | Duration in seconds | +| aspect_ratio | string | No | 16:9 | Aspect ratio | + +--- + +### Image to Video + +Animate a static image into a video. + +| Parameter | Type | Required | Default | Description | +|-----------|------|----------|---------|-------------| +| image | string | Yes | — | URL of the source image | +| prompt | string | Yes | — | Animation description | +| model | string | No | kling-std | Image-to-video model | +| duration | number | No | 5 | Duration in seconds | +| aspect_ratio | string | No | 16:9 | Aspect ratio | + +--- + +### Edit Image + +Transform existing images with text-guided editing. + +| Parameter | Type | Required | Default | Description | +|-----------|------|----------|---------|-------------| +| image | string | Yes | — | URL of the source image | +| prompt | string | Yes | — | Edit description | +| model | string | No | flux-kontext-dev | Image editing model | +| aspect_ratio | string | No | — | Output aspect ratio | + +--- + +### Remove Background + +Remove the background from an image. + +| Parameter | Type | Required | Default | Description | +|-----------|------|----------|---------|-------------| +| image | string | Yes | — | URL of the source image | +| model | string | No | bria-rmbg | Background removal model | + +--- + +### Upscale Image + +Enhance image resolution. + +| Parameter | Type | Required | Default | Description | +|-----------|------|----------|---------|-------------| +| image | string | Yes | — | URL of the image to upscale | +| scale_factor | number | No | 2 | Upscale factor (e.g. 2 for 2x) | +| model | string | No | aura-sr | Upscaling model | + +--- + +### Generate Audio + +Create music or audio from text descriptions. + +| Parameter | Type | Required | Default | Description | +|-----------|------|----------|---------|-------------| +| prompt | string | Yes | — | Audio/music description | +| title | string | No | — | Track title | +| tags | string | No | — | Genre/style tags | +| instrumental | boolean | No | false | Instrumental only | + +--- + +### Remix Audio + +Transform existing audio with text-guided remixing. + +| Parameter | Type | Required | Default | Description | +|-----------|------|----------|---------|-------------| +| audio | string | Yes | — | URL of the audio to remix | +| prompt | string | Yes | — | Remix description | +| title | string | No | — | Track title | +| tags | string | No | — | Genre/style tags | + +--- + +## Example Workflows + +### Image Generation + +```text +User Input → Generate Image → Output Image +``` Example prompt: @@ -197,20 +322,54 @@ Example prompt: A futuristic city at sunset with flying cars ``` -Example workflow: +### Video from Text ```text -User Input - ↓ -Generate Image - ↓ -Output Image +User Input → Generate Video → Output Video Link +``` + +Example prompt: + +```text +A drone flying over a mountain landscape at golden hour +``` + +### Image to Video + +```text +Upload Image → Image to Video → Output Video Link +``` + +### Image Editing Pipeline + +```text +Generate Image → Edit Image → Upscale Image → Output +``` + +### Background Removal + +```text +Upload Image → Remove Background → Output Transparent Image +``` + +### Music Generation + +```text +User Input → Generate Audio → Output Audio Link +``` + +Example prompt: + +```text +A chill lo-fi beat with soft piano and rain sounds ``` --- ## Example Output +### Image Output + ```json { "files": [ @@ -222,35 +381,47 @@ Output Image } ``` +### Video Output + +```json +{ + "video": "https://cdn.muapi.ai/videos/example-output.mp4" +} +``` + +### Audio Output + +```json +{ + "audio": "https://cdn.muapi.ai/audio/example-output.mp3" +} +``` + --- -## Development Journey +## Screenshots + + + +### Plugin Installation + +_Screenshot placeholder: Plugin installed in Dify_ -During development the following issues were resolved: +### Credential Configuration -### Environment Issues +_Screenshot placeholder: MuAPI API key configuration_ -* Docker Desktop not starting -* WSL2 not configured -* Hypervisor disabled (`hypervisorlaunchtype Off`) -* Virtual Machine Platform configuration +### Image Generation Workflow -### Dify Plugin Issues +_Screenshot placeholder: Image generation workflow in Dify_ -* Invalid plugin identifier -* Plugin signature verification -* Missing provider metadata -* Missing YAML schema fields -* Incorrect plugin bootstrap -* Empty `main.py` -* Tool parameter validation errors +### Video Generation Workflow -### MuAPI Integration Issues +_Screenshot placeholder: Video generation workflow in Dify_ -* Incorrect PyPI package (`muapi`) -* SDK packaging problems -* Missing command modules -* API key authentication failures +### Audio Generation Workflow + +_Screenshot placeholder: Audio generation workflow in Dify_ --- @@ -265,7 +436,7 @@ MuAPI SDK ↓ MuAPI API ↓ -Generated Image +Generated Output ↓ Returned to Dify ``` @@ -276,8 +447,48 @@ Status: ✅ Plugin Packaging ✅ Plugin Installation ✅ Credential Configuration +✅ Credential Validation (API verification) ✅ Image Generation +✅ Image Editing +✅ Background Removal +✅ Image Upscaling +✅ Video Generation +✅ Image to Video +✅ Audio Generation +✅ Audio Remix ✅ Image Delivery to Dify +✅ Video Link Delivery to Dify +✅ Audio Link Delivery to Dify +``` + +--- + +## Development + +### Adding New Tools + +1. Create `tools/.py` with a class extending `Tool` +2. Create `tools/.yaml` with Dify tool schema +3. Register in `provider/muapi.yaml` under `tools:` +4. Repackage and reinstall the plugin + +### Tool YAML Schema + +Every tool parameter must include: + +```yaml +human_description: + en_US: ... +llm_description: ... +form: llm # or form +``` + +Every tool must include: + +```yaml +extra: + python: + source: tools/.py ``` --- diff --git a/main.py b/main.py index c58a989..5cd044e 100644 --- a/main.py +++ b/main.py @@ -1,6 +1,6 @@ from dify_plugin import Plugin, DifyPluginEnv -plugin = Plugin(DifyPluginEnv(MAX_REQUEST_TIMEOUT=120)) +plugin = Plugin(DifyPluginEnv(MAX_REQUEST_TIMEOUT=600)) if __name__ == '__main__': plugin.run() \ No newline at end of file diff --git a/manifest.yaml b/manifest.yaml index a6e2223..867eebe 100644 --- a/manifest.yaml +++ b/manifest.yaml @@ -10,7 +10,7 @@ label: en_US: MuAPI description: - en_US: Generate images and videos using MuAPI + en_US: Generate images, videos, and audio using MuAPI. Edit images, remove backgrounds, upscale images, and remix audio with 100+ AI models. created_at: "2026-06-12T00:00:00.000000Z" diff --git a/provider/muapi.yaml b/provider/muapi.yaml index 276f4c4..4f84e7f 100644 --- a/provider/muapi.yaml +++ b/provider/muapi.yaml @@ -2,7 +2,7 @@ identity: author: muapi name: muapi description: - en_US: Generate images and videos using MuAPI + en_US: Generate images, videos, and audio using MuAPI. Edit images, remove backgrounds, upscale, and remix audio. icon: icon.png label: en_US: MuAPI @@ -16,6 +16,13 @@ credentials_for_provider: tools: - tools/generate_image.yaml + - tools/generate_video.yaml + - tools/image_to_video.yaml + - tools/edit_image.yaml + - tools/remove_background.yaml + - tools/upscale_image.yaml + - tools/generate_audio.yaml + - tools/remix_audio.yaml extra: python: diff --git a/provider/muapi_provider.py b/provider/muapi_provider.py index d9a3c30..bd4dbcf 100644 --- a/provider/muapi_provider.py +++ b/provider/muapi_provider.py @@ -1,6 +1,10 @@ +import os + from dify_plugin import ToolProvider from dify_plugin.errors.tool import ToolProviderCredentialValidationError +from muapi import MuAPI + class MuapiProvider(ToolProvider): @@ -19,7 +23,13 @@ def validate_credentials( "MuAPI API key is required" ) + os.environ["MUAPI_API_KEY"] = api_key + + client = MuAPI() + + client.accounts.balance() + except Exception as e: raise ToolProviderCredentialValidationError( - str(e) + f"MuAPI credential validation failed: {str(e)}" ) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 343c642..3608b2c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -dify-plugin +dify-plugin==0.9.1 git+https://github.com/SamurAIGPT/muapi-python.git \ No newline at end of file diff --git a/tools/edit_image.py b/tools/edit_image.py new file mode 100644 index 0000000..cc68b00 --- /dev/null +++ b/tools/edit_image.py @@ -0,0 +1,55 @@ +from collections.abc import Generator +from typing import Any +import os + +from dify_plugin import Tool +from dify_plugin.entities.tool import ToolInvokeMessage + +from muapi import MuAPI + + +class EditImageTool(Tool): + def _invoke( + self, + tool_parameters: dict[str, Any], + ) -> Generator[ToolInvokeMessage]: + + api_key = self.runtime.credentials.get( + "muapi_api_key" + ) + + if not api_key: + yield self.create_json_message( + { + "error": "Missing MuAPI API key" + } + ) + return + + os.environ["MUAPI_API_KEY"] = api_key + + client = MuAPI() + + kwargs = { + "image": tool_parameters["image"], + "prompt": tool_parameters["prompt"], + "model": tool_parameters.get( + "model", + "flux-kontext-dev" + ), + } + + aspect_ratio = tool_parameters.get("aspect_ratio") + if aspect_ratio: + kwargs["aspect_ratio"] = aspect_ratio + + result = client.images.edit(**kwargs) + + if isinstance(result, dict) and result.get("images"): + yield self.create_image_message( + result["images"][0] + ) + + yield self.create_json_message( + result if isinstance(result, dict) else {"result": str(result)} + ) diff --git a/tools/edit_image.yaml b/tools/edit_image.yaml new file mode 100644 index 0000000..be050c8 --- /dev/null +++ b/tools/edit_image.yaml @@ -0,0 +1,56 @@ +identity: + name: edit_image + author: muapi + label: + en_US: Edit Image + +description: + human: + en_US: Edit an existing image using a text prompt via MuAPI + llm: Edit or transform an existing image based on a text prompt using AI image editing models via MuAPI + +parameters: + - name: image + type: string + required: true + form: llm + label: + en_US: Image URL + human_description: + en_US: URL of the image to edit + llm_description: URL of the source image to edit or transform + + - name: prompt + type: string + required: true + form: llm + label: + en_US: Prompt + human_description: + en_US: Text prompt describing the desired edit + llm_description: Text prompt describing how the image should be edited or transformed + + - name: model + type: string + required: false + form: form + label: + en_US: Model + human_description: + en_US: The model to use for image editing (e.g. flux-kontext-dev) + llm_description: The model to use for image editing + default: flux-kontext-dev + + - name: aspect_ratio + type: string + required: false + form: form + label: + en_US: Aspect Ratio + human_description: + en_US: Aspect ratio of the output image (e.g. 1:1, 16:9, 4:3) + llm_description: Aspect ratio of the edited output image + +extra: + python: + source: tools/edit_image.py diff --git a/tools/generate_audio.py b/tools/generate_audio.py new file mode 100644 index 0000000..a9ce837 --- /dev/null +++ b/tools/generate_audio.py @@ -0,0 +1,64 @@ +from collections.abc import Generator +from typing import Any +import os + +from dify_plugin import Tool +from dify_plugin.entities.tool import ToolInvokeMessage + +from muapi import MuAPI + + +class GenerateAudioTool(Tool): + def _invoke( + self, + tool_parameters: dict[str, Any], + ) -> Generator[ToolInvokeMessage]: + + api_key = self.runtime.credentials.get( + "muapi_api_key" + ) + + if not api_key: + yield self.create_json_message( + { + "error": "Missing MuAPI API key" + } + ) + return + + os.environ["MUAPI_API_KEY"] = api_key + + client = MuAPI() + + result = client.audio.create( + prompt=tool_parameters["prompt"], + title=tool_parameters.get( + "title", + "" + ), + tags=tool_parameters.get( + "tags", + "" + ), + instrumental=bool( + tool_parameters.get( + "instrumental", + False + ) + ), + ) + + audio_url = None + + if isinstance(result, dict): + audio_url = result.get("audio") or result.get("url") or result.get("output") + + if not audio_url and result.get("audio_url"): + audio_url = result["audio_url"] + + if audio_url: + yield self.create_link_message(audio_url) + + yield self.create_json_message( + result if isinstance(result, dict) else {"result": str(result)} + ) diff --git a/tools/generate_audio.yaml b/tools/generate_audio.yaml new file mode 100644 index 0000000..fb894d0 --- /dev/null +++ b/tools/generate_audio.yaml @@ -0,0 +1,56 @@ +identity: + name: generate_audio + author: muapi + label: + en_US: Generate Audio + +description: + human: + en_US: Generate audio or music from a text prompt using MuAPI + llm: Generate audio or music from a text description using AI audio generation via MuAPI + +parameters: + - name: prompt + type: string + required: true + form: llm + label: + en_US: Prompt + human_description: + en_US: Text prompt describing the audio or music to generate + llm_description: Text prompt describing the audio or music to generate + + - name: title + type: string + required: false + form: form + label: + en_US: Title + human_description: + en_US: Title for the generated audio track + llm_description: Title for the generated audio track + + - name: tags + type: string + required: false + form: form + label: + en_US: Tags + human_description: + en_US: Comma-separated genre or style tags (e.g. pop, electronic, chill) + llm_description: Comma-separated genre or style tags for the audio + + - name: instrumental + type: boolean + required: false + form: form + label: + en_US: Instrumental + human_description: + en_US: Generate instrumental only (no vocals) + llm_description: Whether to generate instrumental audio without vocals + default: false + +extra: + python: + source: tools/generate_audio.py diff --git a/tools/generate_video.py b/tools/generate_video.py new file mode 100644 index 0000000..e88a427 --- /dev/null +++ b/tools/generate_video.py @@ -0,0 +1,64 @@ +from collections.abc import Generator +from typing import Any +import os + +from dify_plugin import Tool +from dify_plugin.entities.tool import ToolInvokeMessage + +from muapi import MuAPI + + +class GenerateVideoTool(Tool): + def _invoke( + self, + tool_parameters: dict[str, Any], + ) -> Generator[ToolInvokeMessage]: + + api_key = self.runtime.credentials.get( + "muapi_api_key" + ) + + if not api_key: + yield self.create_json_message( + { + "error": "Missing MuAPI API key" + } + ) + return + + os.environ["MUAPI_API_KEY"] = api_key + + client = MuAPI() + + result = client.videos.generate( + prompt=tool_parameters["prompt"], + model=tool_parameters.get( + "model", + "kling-master" + ), + duration=int( + tool_parameters.get( + "duration", + 5 + ) + ), + aspect_ratio=tool_parameters.get( + "aspect_ratio", + "16:9" + ), + ) + + video_url = None + + if isinstance(result, dict): + video_url = result.get("video") or result.get("url") or result.get("output") + + if not video_url and result.get("videos"): + video_url = result["videos"][0] + + if video_url: + yield self.create_link_message(video_url) + + yield self.create_json_message( + result if isinstance(result, dict) else {"result": str(result)} + ) diff --git a/tools/generate_video.yaml b/tools/generate_video.yaml new file mode 100644 index 0000000..0330a96 --- /dev/null +++ b/tools/generate_video.yaml @@ -0,0 +1,58 @@ +identity: + name: generate_video + author: muapi + label: + en_US: Generate Video + +description: + human: + en_US: Generate videos from a text prompt using MuAPI + llm: Generate a video from a text description using AI video generation models via MuAPI + +parameters: + - name: prompt + type: string + required: true + form: llm + label: + en_US: Prompt + human_description: + en_US: Text prompt describing the video to generate + llm_description: Text prompt describing the video to generate + + - name: model + type: string + required: false + form: form + label: + en_US: Model + human_description: + en_US: The model to use for video generation (e.g. kling-master) + llm_description: The model to use for video generation + default: kling-master + + - name: duration + type: number + required: false + form: form + label: + en_US: Duration + human_description: + en_US: Duration of the video in seconds + llm_description: Duration of the generated video in seconds + default: 5 + + - name: aspect_ratio + type: string + required: false + form: form + label: + en_US: Aspect Ratio + human_description: + en_US: Aspect ratio of the video (e.g. 16:9, 9:16, 1:1) + llm_description: Aspect ratio of the generated video + default: "16:9" + +extra: + python: + source: tools/generate_video.py diff --git a/tools/image_to_video.py b/tools/image_to_video.py new file mode 100644 index 0000000..a3e3132 --- /dev/null +++ b/tools/image_to_video.py @@ -0,0 +1,65 @@ +from collections.abc import Generator +from typing import Any +import os + +from dify_plugin import Tool +from dify_plugin.entities.tool import ToolInvokeMessage + +from muapi import MuAPI + + +class ImageToVideoTool(Tool): + def _invoke( + self, + tool_parameters: dict[str, Any], + ) -> Generator[ToolInvokeMessage]: + + api_key = self.runtime.credentials.get( + "muapi_api_key" + ) + + if not api_key: + yield self.create_json_message( + { + "error": "Missing MuAPI API key" + } + ) + return + + os.environ["MUAPI_API_KEY"] = api_key + + client = MuAPI() + + result = client.videos.from_image( + image=tool_parameters["image"], + prompt=tool_parameters["prompt"], + model=tool_parameters.get( + "model", + "kling-std" + ), + duration=int( + tool_parameters.get( + "duration", + 5 + ) + ), + aspect_ratio=tool_parameters.get( + "aspect_ratio", + "16:9" + ), + ) + + video_url = None + + if isinstance(result, dict): + video_url = result.get("video") or result.get("url") or result.get("output") + + if not video_url and result.get("videos"): + video_url = result["videos"][0] + + if video_url: + yield self.create_link_message(video_url) + + yield self.create_json_message( + result if isinstance(result, dict) else {"result": str(result)} + ) diff --git a/tools/image_to_video.yaml b/tools/image_to_video.yaml new file mode 100644 index 0000000..33e20a6 --- /dev/null +++ b/tools/image_to_video.yaml @@ -0,0 +1,68 @@ +identity: + name: image_to_video + author: muapi + label: + en_US: Image to Video + +description: + human: + en_US: Convert a static image into a video using MuAPI + llm: Animate a static image into a video with a text prompt using AI video generation models via MuAPI + +parameters: + - name: image + type: string + required: true + form: llm + label: + en_US: Image URL + human_description: + en_US: URL of the source image to animate + llm_description: URL of the source image to convert into a video + + - name: prompt + type: string + required: true + form: llm + label: + en_US: Prompt + human_description: + en_US: Text prompt describing how the image should be animated + llm_description: Text prompt describing the desired animation or motion for the image + + - name: model + type: string + required: false + form: form + label: + en_US: Model + human_description: + en_US: The model to use for image-to-video generation (e.g. kling-std) + llm_description: The model to use for image-to-video generation + default: kling-std + + - name: duration + type: number + required: false + form: form + label: + en_US: Duration + human_description: + en_US: Duration of the video in seconds + llm_description: Duration of the generated video in seconds + default: 5 + + - name: aspect_ratio + type: string + required: false + form: form + label: + en_US: Aspect Ratio + human_description: + en_US: Aspect ratio of the video (e.g. 16:9, 9:16, 1:1) + llm_description: Aspect ratio of the generated video + default: "16:9" + +extra: + python: + source: tools/image_to_video.py diff --git a/tools/remix_audio.py b/tools/remix_audio.py new file mode 100644 index 0000000..56d4895 --- /dev/null +++ b/tools/remix_audio.py @@ -0,0 +1,67 @@ +from collections.abc import Generator +from typing import Any +import os + +from dify_plugin import Tool +from dify_plugin.entities.tool import ToolInvokeMessage + +from muapi import MuAPI + + +class RemixAudioTool(Tool): + def _invoke( + self, + tool_parameters: dict[str, Any], + ) -> Generator[ToolInvokeMessage]: + + api_key = self.runtime.credentials.get( + "muapi_api_key" + ) + + if not api_key: + yield self.create_json_message( + { + "error": "Missing MuAPI API key" + } + ) + return + + os.environ["MUAPI_API_KEY"] = api_key + + client = MuAPI() + + result = client.audio.remix( + song_id=tool_parameters["song_id"], + prompt=tool_parameters.get( + "prompt", + "" + ), + title=tool_parameters.get( + "title", + "" + ), + tags=tool_parameters.get( + "tags", + "" + ), + ) + + audio_url = None + + if isinstance(result, dict): + audio_url = ( + result.get("audio") + or result.get("audio_url") + or result.get("url") + or result.get("output") + ) + + if audio_url: + yield self.create_link_message( + audio_url + ) + + yield self.create_json_message( + result if isinstance(result, dict) + else {"result": str(result)} + ) \ No newline at end of file diff --git a/tools/remix_audio.yaml b/tools/remix_audio.yaml new file mode 100644 index 0000000..da8ec04 --- /dev/null +++ b/tools/remix_audio.yaml @@ -0,0 +1,55 @@ +identity: + name: remix_audio + author: muapi + label: + en_US: Remix Audio + +description: + human: + en_US: Remix or transform existing audio using a text prompt via MuAPI + llm: Remix or transform existing audio based on a text description using AI audio generation via MuAPI + +parameters: + - name: audio + type: string + required: true + form: llm + label: + en_US: Audio URL + human_description: + en_US: URL of the audio file to remix + llm_description: URL of the source audio file to remix or transform + + - name: prompt + type: string + required: true + form: llm + label: + en_US: Prompt + human_description: + en_US: Text prompt describing the desired remix style or transformation + llm_description: Text prompt describing how the audio should be remixed or transformed + + - name: title + type: string + required: false + form: form + label: + en_US: Title + human_description: + en_US: Title for the remixed audio track + llm_description: Title for the remixed audio track + + - name: tags + type: string + required: false + form: form + label: + en_US: Tags + human_description: + en_US: Comma-separated genre or style tags (e.g. pop, electronic, chill) + llm_description: Comma-separated genre or style tags for the remixed audio + +extra: + python: + source: tools/remix_audio.py diff --git a/tools/remove_background.py b/tools/remove_background.py new file mode 100644 index 0000000..7618da2 --- /dev/null +++ b/tools/remove_background.py @@ -0,0 +1,53 @@ +from collections.abc import Generator +from typing import Any +import os + +from dify_plugin import Tool +from dify_plugin.entities.tool import ToolInvokeMessage + +from muapi import MuAPI + + +class RemoveBackgroundTool(Tool): + def _invoke( + self, + tool_parameters: dict[str, Any], + ) -> Generator[ToolInvokeMessage]: + + api_key = self.runtime.credentials.get( + "muapi_api_key" + ) + + if not api_key: + yield self.create_json_message( + { + "error": "Missing MuAPI API key" + } + ) + return + + os.environ["MUAPI_API_KEY"] = api_key + + client = MuAPI() + + result = client.enhance.remove_background( + image_url=tool_parameters["image"] + ) + + if isinstance(result, dict): + image_url = None + + if result.get("images"): + image_url = result["images"][0] + elif result.get("outputs"): + image_url = result["outputs"][0] + + if image_url: + yield self.create_image_message( + image_url + ) + + yield self.create_json_message( + result if isinstance(result, dict) + else {"result": str(result)} + ) \ No newline at end of file diff --git a/tools/remove_background.yaml b/tools/remove_background.yaml new file mode 100644 index 0000000..a5f95a0 --- /dev/null +++ b/tools/remove_background.yaml @@ -0,0 +1,36 @@ +identity: + name: remove_background + author: muapi + label: + en_US: Remove Background + +description: + human: + en_US: Remove the background from an image using MuAPI + llm: Remove the background from an image to produce a transparent output using AI via MuAPI + +parameters: + - name: image + type: string + required: true + form: llm + label: + en_US: Image URL + human_description: + en_US: URL of the image to remove the background from + llm_description: URL of the image whose background should be removed + + - name: model + type: string + required: false + form: form + label: + en_US: Model + human_description: + en_US: The model to use for background removal (e.g. bria-rmbg) + llm_description: The model to use for background removal + default: bria-rmbg + +extra: + python: + source: tools/remove_background.py diff --git a/tools/upscale_image.py b/tools/upscale_image.py new file mode 100644 index 0000000..23a6072 --- /dev/null +++ b/tools/upscale_image.py @@ -0,0 +1,53 @@ +from collections.abc import Generator +from typing import Any +import os + +from dify_plugin import Tool +from dify_plugin.entities.tool import ToolInvokeMessage + +from muapi import MuAPI + + +class UpscaleImageTool(Tool): + def _invoke( + self, + tool_parameters: dict[str, Any], + ) -> Generator[ToolInvokeMessage]: + + api_key = self.runtime.credentials.get( + "muapi_api_key" + ) + + if not api_key: + yield self.create_json_message( + { + "error": "Missing MuAPI API key" + } + ) + return + + os.environ["MUAPI_API_KEY"] = api_key + + client = MuAPI() + + result = client.enhance.upscale( + image_url=tool_parameters["image"] + ) + + if isinstance(result, dict): + image_url = None + + if result.get("images"): + image_url = result["images"][0] + elif result.get("outputs"): + image_url = result["outputs"][0] + + if image_url: + yield self.create_image_message( + image_url + ) + + yield self.create_json_message( + result if isinstance(result, dict) + else {"result": str(result)} + ) \ No newline at end of file diff --git a/tools/upscale_image.yaml b/tools/upscale_image.yaml new file mode 100644 index 0000000..3d847c0 --- /dev/null +++ b/tools/upscale_image.yaml @@ -0,0 +1,47 @@ +identity: + name: upscale_image + author: muapi + label: + en_US: Upscale Image + +description: + human: + en_US: Upscale and enhance image resolution using MuAPI + llm: Upscale an image to higher resolution with enhanced detail using AI via MuAPI + +parameters: + - name: image + type: string + required: true + form: llm + label: + en_US: Image URL + human_description: + en_US: URL of the image to upscale + llm_description: URL of the image to upscale and enhance + + - name: scale_factor + type: number + required: false + form: form + label: + en_US: Scale Factor + human_description: + en_US: Factor by which to upscale the image (e.g. 2 for 2x) + llm_description: Factor by which to upscale the image resolution + default: 2 + + - name: model + type: string + required: false + form: form + label: + en_US: Model + human_description: + en_US: The model to use for upscaling (e.g. aura-sr) + llm_description: The model to use for image upscaling + default: aura-sr + +extra: + python: + source: tools/upscale_image.py