This commit is contained in:
2026-06-16 09:19:32 +03:00
parent 7f1516c9c9
commit 8f3ac70b20
43 changed files with 1644 additions and 4668 deletions
+116
View File
@@ -0,0 +1,116 @@
from typing import Any
from app.homelab.digest import build_weather_briefing
from app.homelab.image_gen import generate_image as run_generate_image
from app.homelab.openmeteo import OpenMeteoClient
from app.tools._dispatch import NOT_HANDLED, ToolContext
TOOL_NAMES = frozenset({
"get_weather",
"get_morning_briefing",
"generate_image",
})
TOOL_DEFINITIONS: list[dict[str, Any]] = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": (
"ОБЯЗАТЕЛЬНО для вопросов о погоде, «что на улице», «будет ли дождь», «завтра», «на неделю». "
"Текущая погода, почасовой и дневной прогноз."
),
"parameters": {
"type": "object",
"properties": {
"hours_ahead": {
"type": "integer",
"description": "Сколько часов почасового прогноза (по умолчанию 12, до 168)",
},
"days_ahead": {
"type": "integer",
"description": "Сколько дней дневного прогноза (по умолчанию 7, до 16)",
},
},
"required": [],
},
},
},
{
"type": "function",
"function": {
"name": "get_morning_briefing",
"description": "Утренний брифинг: погода и заголовки новостей.",
"parameters": {
"type": "object",
"properties": {
"include_news": {
"type": "boolean",
"description": "Включить новости (по умолчанию true)",
},
},
"required": [],
},
},
},
{
"type": "function",
"function": {
"name": "generate_image",
"description": (
"Аниме-картинка (Anima). draw_self=true — персонаж из карточки; "
"scene_description — поза/кадр/одежда (booru-теги на англ. или короткий запрос: "
"full body, sitting, apron). Можно оба параметра: draw_self + scene_description. "
"Внешность только из appearance_tags карточки."
),
"parameters": {
"type": "object",
"properties": {
"draw_self": {
"type": "boolean",
"description": "Нарисовать персонажа из карточки",
},
"scene_description": {
"type": "string",
"description": (
"Поза, кадр, одежда, обстановка — booru-теги или запрос "
"(full_body, standing, apron, blush). С draw_self=true — уточняет сцену."
),
},
},
"required": [],
},
},
},
]
async def execute(name: str, arguments: dict[str, Any], ctx: ToolContext) -> Any:
if name not in TOOL_NAMES:
return NOT_HANDLED
if name == "get_weather":
hours = max(1, min(int(arguments.get("hours_ahead") or 12), 168))
days = max(1, min(int(arguments.get("days_ahead") or 7), 16))
client = OpenMeteoClient()
weather = client.fetch_forecast(hours_ahead=hours, days_ahead=days)
return {
"weather": weather,
"rain_summary": client.rain_summary(hours_ahead=hours, daily=weather.get("daily")) if weather.get("ok") else "",
"daily_summary": client.daily_summary(days_ahead=days) if weather.get("ok") else "",
}
if name == "get_morning_briefing":
include_news = arguments.get("include_news", True)
return build_weather_briefing(
hours_ahead=12,
include_news=bool(include_news),
)
if name == "generate_image":
return await run_generate_image(
ctx.db,
user_id=ctx.user_id,
session_id=ctx.session_id,
draw_self=bool(arguments.get("draw_self")),
scene_description=arguments.get("scene_description", ""),
)
return NOT_HANDLED