| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- """
- NanoBanana 工具测试脚本
- 测试场景:
- 1. 纯文本生成图像
- 2. 基于第一个测试生成的图像,转换为不同风格
- """
- import asyncio
- import sys
- from pathlib import Path
- from dotenv import load_dotenv
- # 添加项目根目录到 Python 路径
- project_root = Path(__file__).parent.parent.parent
- sys.path.insert(0, str(project_root))
- # 从 Agent 根目录加载 .env 文件
- env_path = project_root / ".env"
- if env_path.exists():
- load_dotenv(env_path)
- print(f"✅ 已加载环境变量: {env_path}")
- else:
- print(f"⚠️ 未找到 .env 文件: {env_path}")
- from agent.core.runner import AgentRunner, RunConfig
- from agent.trace.store import FileSystemTraceStore
- from agent.trace.models import Trace, Message
- from agent.llm.openrouter import create_openrouter_llm_call
- async def test_text_to_image(output_dir: Path) -> Path:
- """测试1: 纯文本生成图像
- Returns:
- 生成的图片路径
- """
- print("\n" + "="*60)
- print("测试1: 纯文本生成图像")
- print("="*60)
- # 导入自定义工具
- import examples.test_nanobanana.tool
- store = FileSystemTraceStore(base_path=".trace")
- llm_call = create_openrouter_llm_call(model="anthropic/claude-sonnet-4.5")
- runner = AgentRunner(
- trace_store=store,
- llm_call=llm_call,
- )
- config = RunConfig(
- model="anthropic/claude-sonnet-4.5",
- temperature=0.3,
- max_iterations=10,
- )
- # 使用绝对路径
- output_path = output_dir / "cat.png"
- task = f"""
- 请使用 nanobanana 工具生成一张图片:
- - 内容:一只可爱的橙色小猫,坐在窗台上看着外面的雨
- - 风格:水彩画风格
- - 保存到:{output_path}
- 注意:路径必须使用绝对路径。
- """
- print(f"\n任务: 生成小猫图片")
- print(f"输出路径: {output_path}\n")
- # 将任务转换为消息格式
- messages = [{"role": "user", "content": task}]
- generated_image = None
- try:
- async for item in runner.run(messages=messages, config=config):
- # 处理 Trace 对象(整体状态变化)
- if isinstance(item, Trace):
- if item.status == "running":
- print(f"[Trace] 开始: {item.trace_id[:8]}...")
- elif item.status == "completed":
- print(f"\n[Trace] ✅ 完成")
- print(f" - Total messages: {item.total_messages}")
- print(f" - Total tokens: {item.total_tokens}")
- print(f" - Total cost: ${item.total_cost:.4f}")
- if output_path.exists():
- generated_image = output_path
- print(f" - 生成的图片: {generated_image}")
- elif item.status == "failed":
- print(f"\n[Trace] ❌ 失败: {item.error_message}")
- elif item.status == "stopped":
- print(f"\n[Trace] ⏸️ 已停止")
- # 处理 Message 对象(执行过程)
- elif isinstance(item, Message):
- if item.role == "assistant":
- content = item.content
- if isinstance(content, dict):
- text = content.get("text", "")
- tool_calls = content.get("tool_calls")
- if text and not tool_calls:
- # 纯文本回复(最终响应)
- print(f"\n[Response] {text}")
- elif tool_calls:
- # 工具调用
- tool_names = [tc.get("function", {}).get("name") for tc in tool_calls]
- print(f"[Tool Call] {', '.join(tool_names)}")
- elif item.role == "tool":
- # 工具结果
- if isinstance(item.content, dict):
- tool_name = item.content.get("tool_name", "unknown")
- print(f"[Tool Result] {tool_name}")
- except Exception as e:
- print(f"\n❌ 测试失败: {e}")
- import traceback
- traceback.print_exc()
- return generated_image
- async def test_image_to_image(input_image: Path, output_dir: Path):
- """测试2: 基于参考图像生成新图像
- Args:
- input_image: 参考图像路径(来自测试1)
- output_dir: 输出目录
- """
- print("\n" + "="*60)
- print("测试2: 基于参考图像生成新图像")
- print("="*60)
- if not input_image or not input_image.exists():
- print("⚠️ 跳过测试2: 测试1没有成功生成图片")
- return
- print(f"参考图像: {input_image}")
- # 导入自定义工具
- import examples.test_nanobanana.tool
- store = FileSystemTraceStore(base_path=".trace")
- llm_call = create_openrouter_llm_call(model="anthropic/claude-sonnet-4.5")
- runner = AgentRunner(
- trace_store=store,
- llm_call=llm_call,
- )
- config = RunConfig(
- model="anthropic/claude-sonnet-4.5",
- temperature=0.3,
- max_iterations=10,
- )
- # 使用绝对路径
- output_path = output_dir / "cat_oil_painting.png"
- task = f"""
- 请使用 nanobanana 工具,基于参考图像生成一张新图片:
- - 参考图像:{input_image}
- - 要求:保持小猫和窗台的元素,但改变风格为油画风格
- - 保存到:{output_path}
- 注意:路径必须使用绝对路径。
- """
- print(f"\n任务: 将小猫图片转换为油画风格")
- print(f"输出路径: {output_path}\n")
- # 将任务转换为消息格式
- messages = [{"role": "user", "content": task}]
- try:
- async for item in runner.run(messages=messages, config=config):
- # 处理 Trace 对象(整体状态变化)
- if isinstance(item, Trace):
- if item.status == "running":
- print(f"[Trace] 开始: {item.trace_id[:8]}...")
- elif item.status == "completed":
- print(f"\n[Trace] ✅ 完成")
- print(f" - Total messages: {item.total_messages}")
- print(f" - Total tokens: {item.total_tokens}")
- print(f" - Total cost: ${item.total_cost:.4f}")
- if output_path.exists():
- print(f" - 生成的图片: {output_path}")
- elif item.status == "failed":
- print(f"\n[Trace] ❌ 失败: {item.error_message}")
- elif item.status == "stopped":
- print(f"\n[Trace] ⏸️ 已停止")
- # 处理 Message 对象(执行过程)
- elif isinstance(item, Message):
- if item.role == "assistant":
- content = item.content
- if isinstance(content, dict):
- text = content.get("text", "")
- tool_calls = content.get("tool_calls")
- if text and not tool_calls:
- # 纯文本回复(最终响应)
- print(f"\n[Response] {text}")
- elif tool_calls:
- # 工具调用
- tool_names = [tc.get("function", {}).get("name") for tc in tool_calls]
- print(f"[Tool Call] {', '.join(tool_names)}")
- elif item.role == "tool":
- # 工具结果
- if isinstance(item.content, dict):
- tool_name = item.content.get("tool_name", "unknown")
- print(f"[Tool Result] {tool_name}")
- except Exception as e:
- print(f"\n❌ 测试失败: {e}")
- import traceback
- traceback.print_exc()
- async def main():
- """运行所有测试"""
- print("\n" + "="*60)
- print("NanoBanana 工具测试")
- print("="*60)
- # 创建输出目录(使用绝对路径)
- output_dir = Path(__file__).parent / "output"
- output_dir.mkdir(exist_ok=True)
- print(f"输出目录: {output_dir.absolute()}\n")
- try:
- # 测试1: 纯文本生成
- generated_image = await test_text_to_image(output_dir)
- # 测试2: 图像转换(基于测试1的结果)
- if generated_image:
- await test_image_to_image(generated_image, output_dir)
- else:
- print("\n⚠️ 跳过测试2: 测试1未成功生成图片")
- print("\n" + "="*60)
- print("测试完成!")
- print("="*60)
- print(f"\n查看生成的图片:")
- if generated_image and generated_image.exists():
- print(f" 1. {generated_image}")
- oil_painting = output_dir / "cat_oil_painting.png"
- if oil_painting.exists():
- print(f" 2. {oil_painting}")
- except KeyboardInterrupt:
- print("\n\n⚠️ 测试被用户中断")
- except Exception as e:
- print(f"\n\n❌ 测试失败: {e}")
- import traceback
- traceback.print_exc()
- if __name__ == "__main__":
- asyncio.run(main())
|