Skip to content

Commit

Permalink
Bump duckduckgo-search and remve maps_search tool (not supported by d…
Browse files Browse the repository at this point in the history
…uckduckgo-search anymore)
  • Loading branch information
Shulyaka committed Jan 6, 2025
1 parent 902a215 commit 98ae4fb
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 102 deletions.
3 changes: 1 addition & 2 deletions custom_components/powerllm/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
DOMAIN,
)
from .llm_tools import PowerIntentTool, PowerLLMTool, PowerScriptTool
from .tools.duckduckgo import DDGMapsSearchTool, DDGNewsTool, DDGTextSearchTool
from .tools.duckduckgo import DDGNewsTool, DDGTextSearchTool
from .tools.memory import MemoryTool
from .tools.script import DynamicScriptTool

Expand Down Expand Up @@ -241,7 +241,6 @@ def _async_get_tools(
DDGTextSearchTool(self.config_entry.options[CONF_DUCKDUCKGO_REGION])
)
tools.append(DDGNewsTool(self.config_entry.options[CONF_DUCKDUCKGO_REGION]))
tools.append(DDGMapsSearchTool())
tools.append(MemoryTool(self.config_entry))

tools.extend(self.hass.data.get(DOMAIN, {}).values())
Expand Down
2 changes: 1 addition & 1 deletion custom_components/powerllm/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
"integration_type": "service",
"iot_class": "local_push",
"issue_tracker": "https://github.com/Shulyaka/powerllm/issues",
"requirements": ["duckduckgo-search==6.2.9", "RestrictedPython>=7.4", "trafilatura==2.0.0"],
"requirements": ["duckduckgo-search==7.2.0", "RestrictedPython>=7.4", "trafilatura==2.0.0"],
"version": "0.0.1"
}
89 changes: 16 additions & 73 deletions custom_components/powerllm/tools/duckduckgo.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import logging

import voluptuous as vol
from duckduckgo_search import AsyncDDGS
from duckduckgo_search import DDGS
from duckduckgo_search.exceptions import DuckDuckGoSearchException
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
Expand All @@ -21,7 +21,7 @@ class DDGBaseTool(PowerLLMTool):

def __init__(self, region: str = "wt-wt"):
"""Initialize the tool."""
self._ddg = AsyncDDGS()
self._ddg = DDGS()
self._region = region


Expand All @@ -44,10 +44,13 @@ async def async_call(
) -> JsonObjectType:
"""Execute text search."""
try:
return await self._ddg.atext(
tool_input.tool_args["query"],
region=self._region,
max_results=tool_input.tool_args.get("max_results"),
return await hass.loop.run_in_executor(
None,
lambda: self._ddg.text(
tool_input.tool_args["query"],
region=self._region,
max_results=tool_input.tool_args.get("max_results"),
),
) or {"error": "No results returned"}
except DuckDuckGoSearchException as e:
raise HomeAssistantError(str(e)) from e
Expand All @@ -72,73 +75,13 @@ async def async_call(
) -> JsonObjectType:
"""Execute news search."""
try:
return await self._ddg.anews(
tool_input.tool_args["keywords"],
region=self._region,
max_results=tool_input.tool_args.get("max_results"),
return await hass.loop.run_in_executor(
None,
lambda: self._ddg.news(
tool_input.tool_args["keywords"],
region=self._region,
max_results=tool_input.tool_args.get("max_results"),
),
) or {"error": "No results returned"}
except DuckDuckGoSearchException as e:
raise HomeAssistantError(str(e)) from e


class DDGMapsSearchTool(DDGBaseTool):
"""DuckDuckGo maps search tool."""

name = "maps_search"
description = "Search for places on the map"
parameters = vol.Schema(
{
vol.Required("keywords", description="keywords for the search"): cv.string,
vol.Optional(
"place", description="if set, the other parameters are not used"
): cv.string,
vol.Optional("street", description="house number/street"): cv.string,
vol.Optional("city", description="city of search"): cv.string,
vol.Optional("county", description="county of search"): cv.string,
vol.Optional("state", description="state of search"): cv.string,
vol.Optional("country", description="country of search"): cv.string,
vol.Optional("postalcode", description="postalcode of search"): cv.string,
vol.Optional(
"latitude", description="geographic coordinate (north-south position)"
): cv.string,
vol.Optional(
"longitude",
description="geographic coordinate (east-west position); if latitude "
"and longitude are set, the other parameters are not used",
): cv.string,
vol.Optional(
"radius",
description="expand the search square by the distance in kilometers",
): vol.Coerce(int),
vol.Optional(
"max_results", default=5, description="Number of results requested"
): vol.Coerce(int),
}
)

async def async_call(
self, hass: HomeAssistant, tool_input: ToolInput, llm_context: LLMContext
) -> JsonObjectType:
"""Execute news search."""
kwargs = tool_input.tool_args.copy()
if all(
kwargs.get(x) is None
for x in [
"place",
"street",
"city",
"county",
"state",
"country",
"postalcode",
"latitude",
"longitude",
]
):
kwargs["latitude"] = str(hass.config.latitude)
kwargs["longitude"] = str(hass.config.longitude)

try:
return await self._ddg.amaps(**kwargs) or {"error": "No results returned"}
except DuckDuckGoSearchException as e:
raise HomeAssistantError(str(e)) from e
2 changes: 1 addition & 1 deletion requirements_test_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ hassil
mutagen
ha-ffmpeg
pymicro-vad
duckduckgo-search
duckduckgo-search==7.2.0
RestrictedPython
trafilatura
1 change: 0 additions & 1 deletion tests/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
"HassTurnOff": True,
"HassTurnOn": True,
"homeassistant_script": True,
"maps_search": True,
"memory": True,
"news": True,
"websearch": True,
Expand Down
59 changes: 35 additions & 24 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,33 @@

from custom_components.powerllm.const import CONF_PROMPT_ENTITIES

INTENT_TOOLS = [
"HassTurnOn",
"HassTurnOff",
"HassGetState",
"HassSetPosition",
]

TIMER_TOOLS = [
"HassStartTimer",
"HassCancelTimer",
"HassCancelAllTimers",
"HassIncreaseTimer",
"HassDecreaseTimer",
"HassPauseTimer",
"HassUnpauseTimer",
"HassTimerStatus",
]

POWERLLM_TOOLS = [
"homeassistant_script",
"websearch",
"news",
"memory",
"python_code_execute",
"web_scrape",
]


def test_test(hass):
"""Workaround for https://github.com/MatthewFlamm/pytest-homeassistant-custom-component/discussions/160."""
Expand Down Expand Up @@ -70,19 +97,19 @@ class MyIntentHandler(intent.IntentHandler):

assert len(llm.async_get_apis(hass)) == 2
api = await llm.async_get_api(hass, "powerllm", llm_context)
assert len(api.tools) == 11
assert len(api.tools) == len(INTENT_TOOLS) + len(POWERLLM_TOOLS)

# Match all
intent_handler.platforms = None

api = await llm.async_get_api(hass, "powerllm", llm_context)
assert len(api.tools) == 12
assert len(api.tools) == len(INTENT_TOOLS) + len(POWERLLM_TOOLS) + 1

# Match specific domain
intent_handler.platforms = {"light"}

api = await llm.async_get_api(hass, "powerllm", llm_context)
assert len(api.tools) == 12
assert len(api.tools) == len(INTENT_TOOLS) + len(POWERLLM_TOOLS) + 1
tool = api.tools[4]
assert tool.name == "test_intent"
assert tool.description == "Execute Home Assistant test_intent intent"
Expand Down Expand Up @@ -278,26 +305,10 @@ class MyIntentHandler(intent.IntentHandler):

api = await llm.async_get_api(hass, "powerllm", llm_context)
assert [tool.name for tool in api.tools] == [
"HassTurnOn",
"HassTurnOff",
"HassGetState",
"HassSetPosition",
"HassStartTimer",
"HassCancelTimer",
"HassCancelAllTimers",
"HassIncreaseTimer",
"HassDecreaseTimer",
"HassPauseTimer",
"HassUnpauseTimer",
"HassTimerStatus",
*INTENT_TOOLS,
*TIMER_TOOLS,
"Super_crazy_intent_with_unique_name",
"homeassistant_script",
"websearch",
"news",
"maps_search",
"memory",
"python_code_execute",
"web_scrape",
*POWERLLM_TOOLS,
]


Expand All @@ -314,8 +325,8 @@ class MyIntentHandler(intent.IntentHandler):

assert len(llm.async_get_apis(hass)) == 2
api = await llm.async_get_api(hass, "powerllm", llm_context)
assert len(api.tools) == 13
tool = api.tools[5]
assert len(api.tools) == len(INTENT_TOOLS) + len(POWERLLM_TOOLS) + 2
tool = api.tools[len(INTENT_TOOLS) + 1]
assert tool.name == "test_intent"
assert tool.description == "my intent handler"

Expand Down

0 comments on commit 98ae4fb

Please sign in to comment.