重构七天训练营老师
This commit is contained in:
0
image_agent/__init__.py
Normal file
0
image_agent/__init__.py
Normal file
33
image_agent/agent.py
Normal file
33
image_agent/agent.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from agent_base.agent_base import HuiYuBaseAgent
|
||||
from common.models import minimax_model
|
||||
from .image_tools import search_images, get_image_detail, list_images
|
||||
|
||||
# ============================================================
|
||||
# 定义 Agent
|
||||
# ============================================================
|
||||
image_agent = HuiYuBaseAgent(
|
||||
name="image_agent",
|
||||
model=minimax_model,
|
||||
description="图片查询助手,能够搜索图片库、查看图片详情和图片列表。",
|
||||
instruction=(
|
||||
"你是一个图片查询助手,帮助用户在图片知识库中查找需要的图片。\n\n"
|
||||
"你的能力包括:\n"
|
||||
"1. 搜索图片:根据用户的自然语言描述,用 AI 语义搜索匹配的图片。"
|
||||
"当用户描述一个场景、主题或关键词时,调用 search_images 搜索。\n"
|
||||
"2. 查看图片详情:当用户想了解某张图片的完整 OCR 内容时,"
|
||||
"调用 get_image_detail 获取详情。\n"
|
||||
"3. 浏览图片列表:当用户想看图片库有哪些图片时,"
|
||||
"调用 list_images 获取列表。\n\n"
|
||||
"使用规则:\n"
|
||||
"- 用户问有没有关于某主题的图片时,用 search_images 搜索\n"
|
||||
"- 调用 search_images 时,如果用户说了要几张图片,就把用户说的数量传给 limit 参数;"
|
||||
"如果用户没说,默认传 5\n"
|
||||
"- 用户想看某张图片的完整内容时,用 get_image_detail 查详情\n"
|
||||
"- 用户想浏览图片库时,用 list_images 列表\n"
|
||||
"- 搜索结果返回的是预览,如果用户想看完整内容,引导用户用 get_image_detail\n"
|
||||
"- 回复时使用中文"
|
||||
),
|
||||
tools=[search_images, get_image_detail, list_images],
|
||||
)
|
||||
|
||||
root_agent = image_agent
|
||||
127
image_agent/image_tools.py
Normal file
127
image_agent/image_tools.py
Normal file
@@ -0,0 +1,127 @@
|
||||
"""
|
||||
图片查询工具 — 封装 EduBrain 图片 API
|
||||
"""
|
||||
|
||||
import os
|
||||
import json
|
||||
import httpx
|
||||
|
||||
BASE_URL = os.getenv("IMAGE_API_BASE", "http://localhost:8765")
|
||||
|
||||
|
||||
def _build_image_url(image_url: str) -> str:
|
||||
"""拼接完整的图片访问地址"""
|
||||
if image_url.startswith("http"):
|
||||
return image_url
|
||||
return f"{BASE_URL}{image_url}"
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Tool: AI 搜索图片(SSE 流式)
|
||||
# ============================================================
|
||||
def search_images(keyword: str, limit: int = 5) -> str:
|
||||
"""根据自然语言描述搜索图片库,返回语义匹配的图片列表。
|
||||
|
||||
使用 AI 语义搜索,支持模糊查询。例如搜"孩子不想上学"会匹配
|
||||
包含亲子关系、厌学等相关内容的图片。
|
||||
|
||||
Args:
|
||||
keyword: 搜索关键词,支持自然语言描述
|
||||
limit: 最多返回多少条匹配结果,默认 5
|
||||
"""
|
||||
results = []
|
||||
try:
|
||||
with httpx.Client(timeout=300.0) as client:
|
||||
with client.stream(
|
||||
"GET",
|
||||
f"{BASE_URL}/api/v1/images/search",
|
||||
params={"keyword": keyword, "limit": limit},
|
||||
) as resp:
|
||||
for line in resp.iter_lines():
|
||||
if not line.startswith("data: "):
|
||||
continue
|
||||
event = json.loads(line[6:])
|
||||
event_type = event.get("type")
|
||||
|
||||
if event_type == "result":
|
||||
# 透传接口返回的所有字段(含 base64、image_url 等)
|
||||
results.append(event)
|
||||
except httpx.ConnectError:
|
||||
return json.dumps({"error": f"无法连接到图片服务({BASE_URL}),请确认服务已启动。"}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({"error": f"搜索图片时出错: {e}"}, ensure_ascii=False)
|
||||
|
||||
if not results:
|
||||
return json.dumps({"keyword": keyword, "total": 0, "images": []}, ensure_ascii=False)
|
||||
|
||||
return json.dumps({"keyword": keyword, "total": len(results), "images": results}, ensure_ascii=False)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Tool: 获取图片详情
|
||||
# ============================================================
|
||||
def get_image_detail(image_id: int) -> str:
|
||||
"""根据图片 ID 获取图片的详细信息,包括完整 OCR 文本。
|
||||
|
||||
Args:
|
||||
image_id: 图片记录 ID
|
||||
"""
|
||||
try:
|
||||
resp = httpx.get(f"{BASE_URL}/api/v1/images/{image_id}", timeout=30.0)
|
||||
if resp.status_code == 404:
|
||||
return json.dumps({"error": f"未找到 ID 为 {image_id} 的图片。"}, ensure_ascii=False)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
except httpx.ConnectError:
|
||||
return json.dumps({"error": f"无法连接到图片服务({BASE_URL}),请确认服务已启动。"}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({"error": f"获取图片详情时出错: {e}"}, ensure_ascii=False)
|
||||
|
||||
result = {
|
||||
"id": data["id"],
|
||||
"image_url": _build_image_url(data.get("image_url", data.get("file_path", ""))),
|
||||
"ocr_text": data.get("ocr_text", ""),
|
||||
"tags": data.get("tags", []),
|
||||
"confidence": data.get("confidence"),
|
||||
"provider": data.get("provider"),
|
||||
"created_at": data.get("created_at", ""),
|
||||
}
|
||||
return json.dumps(result, ensure_ascii=False)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Tool: 获取图片列表
|
||||
# ============================================================
|
||||
def list_images(page: int = 1, page_size: int = 20, status: str = "completed") -> str:
|
||||
"""获取图片库列表,支持分页和状态筛选。
|
||||
|
||||
Args:
|
||||
page: 页码,默认第 1 页
|
||||
page_size: 每页数量,默认 20
|
||||
status: 筛选状态,可选 completed/pending/processing/failed,默认 completed
|
||||
"""
|
||||
try:
|
||||
resp = httpx.get(
|
||||
f"{BASE_URL}/api/v1/images",
|
||||
params={"page": page, "page_size": page_size, "status": status},
|
||||
timeout=30.0,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
except httpx.ConnectError:
|
||||
return json.dumps({"error": f"无法连接到图片服务({BASE_URL}),请确认服务已启动。"}, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({"error": f"获取图片列表时出错: {e}"}, ensure_ascii=False)
|
||||
|
||||
total = data.get("total", 0)
|
||||
items = []
|
||||
for item in data.get("items", []):
|
||||
items.append({
|
||||
"id": item["id"],
|
||||
"image_url": _build_image_url(item.get("image_url", item.get("file_path", ""))),
|
||||
"ocr_text_preview": (item.get("ocr_text") or "")[:150],
|
||||
"tags": item.get("tags", []),
|
||||
"created_at": item.get("created_at", ""),
|
||||
})
|
||||
|
||||
return json.dumps({"total": total, "page": page, "images": items}, ensure_ascii=False)
|
||||
Reference in New Issue
Block a user