Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "intentkit"
version = "0.5.0"
description = "Intent-based AI Agent Platform"
authors = [{ name = "Ruihua", email = "[email protected]" }]
requires-python = "==3.12.*"
requires-python = ">=3.12,<3.14"
readme = "README.md"
dependencies = [
"langgraph (>=0.4.3,<0.5.0)",
Expand Down Expand Up @@ -90,3 +90,6 @@ build-backend = "hatchling.build"

[tool.ruff.lint]
extend-select = ["I"]

[tool.hatch.build.targets.wheel]
packages = ["intentkit"]
40 changes: 40 additions & 0 deletions skills/face_swapper/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# intentkit/skills/face_swapper/__init__.py

from typing import TypedDict
from abstracts.skill import SkillStoreABC
from skills.base import SkillConfig, SkillState
from skills.face_swapper.base import FaceSwapperBaseTool
from skills.face_swapper.face_swap import FaceSwapTool

_cache: dict[str, FaceSwapperBaseTool] = {}

class SkillStates(TypedDict):
face_swap: SkillState

class Config(SkillConfig):
"""Configuration for face swap skills."""
states: SkillStates

async def get_skills(
config: "Config",
is_private: bool,
store: SkillStoreABC,
**_,
) -> list[FaceSwapperBaseTool]:
available_skills = []

for skill_name, state in config["states"].items():
if state == "disabled":
continue
elif state == "public" or (state == "private" and is_private):
available_skills.append(skill_name)

return [get_face_swapper_skill(name, store) for name in available_skills]

def get_face_swapper_skill(name: str, store: SkillStoreABC) -> FaceSwapperBaseTool:
if name == "face_swap":
if name not in _cache:
_cache[name] = FaceSwapTool(skill_store=store)
return _cache[name]
else:
raise ValueError(f"Unknown face swap skill: {name}")
18 changes: 18 additions & 0 deletions skills/face_swapper/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# intentkit/skills/face_swapper/base.py

from typing import Type
from pydantic import BaseModel, Field
from abstracts.skill import SkillStoreABC
from skills.base import IntentKitSkill

class FaceSwapperBaseTool(IntentKitSkill):
"""Base class for face swap tools."""

name: str = Field(description="The name of the tool")
description: str = Field(description="A description of what the tool does")
args_schema: Type[BaseModel]
skill_store: SkillStoreABC = Field(description="The skill store for persisting data")

@property
def category(self) -> str:
return "face_swapper"
50 changes: 50 additions & 0 deletions skills/face_swapper/face_swap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# intentkit/skills/face_swapper/face_swap.py

from typing import Type
from pydantic import BaseModel, Field
import httpx

from skills.face_swapper.base import FaceSwapperBaseTool


class FaceSwapInput(BaseModel):
"""Input untuk alat face swap."""

source_image_url: str = Field(description="URL gambar wajah sumber")
target_image_url: str = Field(description="URL gambar target")
api_url: str = Field(description="Endpoint API face swap pihak ketiga")
api_key: str = Field(description="API key untuk autentikasi dengan penyedia API")


class FaceSwapTool(FaceSwapperBaseTool):
"""Alat untuk melakukan face swap dengan API pihak ketiga."""

name: str = "face_swap"
description: str = (
"Swap wajah dari satu gambar ke gambar lain menggunakan layanan API eksternal."
)
args_schema: Type[BaseModel] = FaceSwapInput

async def _arun(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The api_url and api_key should not be included as _arun parameters.

You must integrate the actual third-party service directly, unless you're implementing the face-swap logic within your own skill code.

Please follow the skill development guidelines when contributing to the project.

You may also refer to existing skills to see how third-party services are properly integrated.

self,
source_image_url: str,
target_image_url: str,
api_url: str,
api_key: str,
**kwargs,
) -> str:
payload = {
"source_image": source_image_url,
"target_image": target_image_url,
}
headers = {
"Authorization": f"Bearer {api_key}"
}

async with httpx.AsyncClient() as client:
response = await client.post(api_url, json=payload, headers=headers)

if response.status_code == 200:
return response.json().get("result_url", "Success, but no result_url found.")
else:
return f"Error: {response.status_code} - {response.text}"
22 changes: 22 additions & 0 deletions skills/face_swapper/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"title": "Face Swapper Skills",
"description": "Configuration schema for face swapper tools",
"properties": {
"states": {
"type": "object",
"properties": {
"face_swap": {
"type": "string",
"title": "Face Swap Tool",
"enum": ["disabled", "public", "private"],
"description": "State of the face_swap tool"
}
},
"description": "States for each face swapper tool"
}
},
"required": ["states"],
"additionalProperties": true
}
Loading