2026-03-11 21:45:46 +08:00
import uuid
2026-03-30 19:37:10 +08:00
from typing import Optional
2026-03-19 17:55:39 +08:00
import httpx
2026-03-20 16:13:19 +08:00
import logging
2026-03-26 17:16:58 +08:00
from langchain_core . runnables import RunnableConfig
2026-03-20 16:13:19 +08:00
from minio import Minio
2026-03-30 19:37:10 +08:00
# from pathlib import Path
# from datetime import datetime
2026-03-20 16:13:19 +08:00
from langchain_core . tools import tool
2026-03-19 17:55:39 +08:00
from langgraph . prebuilt import ToolRuntime
2026-03-20 16:13:19 +08:00
from src . core . config import settings , MONGO_URI
2026-03-30 19:37:10 +08:00
# from src.server.deep_agent.utils.mongodb_util import ThreadImageMinIOStore
2026-03-11 21:45:46 +08:00
2026-03-20 16:13:19 +08:00
logger = logging . getLogger ( __name__ )
2026-03-11 21:45:46 +08:00
minio_client = Minio ( settings . MINIO_URL , access_key = settings . MINIO_ACCESS , secret_key = settings . MINIO_SECRET , secure = settings . MINIO_SECURE )
2026-03-30 19:37:10 +08:00
# image_store = ThreadImageMinIOStore(MONGO_URI, "agent_tool_generate_db")
2026-03-11 21:45:46 +08:00
2026-03-26 17:16:58 +08:00
@tool
2026-03-30 19:37:10 +08:00
async def generate_furniture ( runtime : ToolRuntime , prompts : list [ str ] = None , num_images : Optional [ int ] = 1 ) :
2026-03-26 17:16:58 +08:00
"""
使用图像生成模型根据用户提供的详细英文提示词 , 从零生成一张全新的家具设计草图 。
功能说明 :
- 输入一段详细的英文描述 , 即可生成一张高品质的家具设计图片 ( 可用于草图 、 效果图 、 渲染图等 ) 。
- 生成后的图片会以 image_url 形式返回 , 自动加入对话上下文 , 后续 Agent 可以直接 “ 看到 ” 生成的家具图片并继续操作 ( 描述 、 编辑 、 迭代等 ) 。
参数说明 :
- prompt ( str ) : * * 必须是详细的英文提示词 * * , 越详细越好 , 包含家具类型 、 风格 、 颜色 、 材质 、 尺寸比例 、 背景 、 视角 、 光影等具体要求 。
示例 : " Generate a modern minimalist dining chair made of light oak wood and white leather, with slim metal legs, photographed in a bright Scandinavian living room with natural sunlight, high detail, 8k resolution. "
2026-03-30 19:37:10 +08:00
- num_images ( int , 可选 ) : 要生成的图片数量 , 默认 1 张 。 最大只能是 4 张 。 如果输入超过 4 , 会自动限制为 4 。
2026-03-26 17:16:58 +08:00
返回值 :
返回新生成家具图片的 image_url , 后续对话中 Agent 可直接引用该图片进行描述 、 进一步编辑或分析 。
使用场景 :
- 从零创建新的家具设计方案
- 快速生成多种风格的家具概念图
- 室内设计初期灵感生成
- 家具产品可视化展示
注意 :
- 生成的图片会自动携带到整个对话上下文中 , 支持后续使用 edit_furniture 等工具进行迭代修改 。
- 如果需要生成多个方案 , 可以多次调用本工具或在 prompt 中明确要求生成不同变体 。
"""
2026-03-30 19:37:10 +08:00
if num_images is None or num_images < 1 :
num_images = 1
elif num_images > 4 :
num_images = 4
# current_checkpoint_id = runtime.store.get(namespace=("image_history",), key="checkpoint_id", ).value.get("current_checkpoint_id")
2026-03-30 15:12:56 +08:00
logger . info ( f " \n [系统日志] 正在调用 generate_furniture ...当前checkpoint_id= { current_checkpoint_id } " )
2026-03-26 17:16:58 +08:00
try :
2026-03-30 19:37:10 +08:00
bucket_name = " fida-public-bucket "
object_name = f " furniture/sketches/ { uuid . uuid4 ( ) } "
image_urls = [ ]
for i in range ( num_images ) :
image_urls . append ( await generate_or_edit_image ( prompt = prompts [ i ] , bucket_name = bucket_name , object_name = f " { object_name } - { i } .png " ) )
2026-03-30 15:12:56 +08:00
2026-03-30 19:37:10 +08:00
# if image_urls:
# image_store.save_image_path(thread_id=current_checkpoint_id, object_path=image_urls, metadata={"prompt": prompt, "generated_at": str(datetime.now())})
return image_urls
# else:
# return "Image generation failed."
2026-03-26 17:16:58 +08:00
except Exception as e :
logger . warning ( f " 绘图流程异常: { e } " )
return " generate furniture error "
@tool
2026-03-30 19:37:10 +08:00
async def edit_furniture ( runtime : ToolRuntime , config : RunnableConfig , input_image_paths : list [ str ] = None , prompts : list [ str ] = None , ) :
2026-03-26 17:16:58 +08:00
"""
2026-03-30 19:37:10 +08:00
使用先进的图像编辑模型对家具设计草图进行精准修改 。
2026-03-26 17:16:58 +08:00
功能说明 :
2026-03-30 19:37:10 +08:00
- 支持批量处理多张家具图片 , 根据对应的提示词生成修改后的新图片 。
- input_image_paths 和 prompts 必须一一对应 , 数量完全一致 。
- 最多支持同时处理 4 对图片和提示词 ( 即最多 4 张图片 ) 。
2026-03-26 17:16:58 +08:00
参数说明 :
2026-03-30 19:37:10 +08:00
- input_image_paths ( list [ str ] ) :
输入图片在 MinIO 中的存储路径列表 。
示例 : [ " furniture/designs/sofa_concept_v1.png " , " projects/room_2026/chair_v2.jpg " ]
注意 : 路径必须是有效的 MinIO 对象路径 , 工具会自动下载对应图片 。
- prompts ( list [ str ] ) :
与图片一一对应的详细英文提示词列表 。
每个提示词描述对对应图片的具体修改要求 ( 风格 、 颜色 、 材质 、 形状 、 添加 / 删除元素等 ) 。
示例 : [ " Change the sofa to a modern minimalist style with dark gray fabric and metal legs, add a matching coffee table. " ,
" Convert the chair to Scandinavian Nordic style with light wood and soft beige upholstery. " ]
使用要求 ( 重要 ) :
- input_image_paths 和 prompts 的长度必须完全相同 。
- 列表长度必须在 1 到 4 之间 ( 最多 4 对 ) 。
- input_image_paths [ 0 ] 对应 prompts [ 0 ] , 以此类推 , 一一对应进行编辑 。
2026-03-26 17:16:58 +08:00
使用场景 :
2026-03-30 19:37:10 +08:00
- 家具设计方案迭代
- 室内设计多方案对比修改
- 批量风格转换 ( 现代 / 北欧 / 工业 / 奢华风等 )
- 材质 、 颜色 、 细节批量调整
2026-03-26 17:16:58 +08:00
2026-03-30 19:37:10 +08:00
示例调用 :
input_image_paths = [ " designs/sofa1.png " , " designs/chair1.png " ]
prompts = [
" Make the sofa more luxurious with velvet fabric and gold accents. " ,
" Change the chair to a sleek modern design with black leather and chrome legs. "
]
2026-03-26 17:16:58 +08:00
"""
2026-03-30 15:12:56 +08:00
2026-03-30 19:37:10 +08:00
# image_history = runtime.store.get(namespace=("image_history",), key="checkpoint_id", )
# last_checkpoint_id = image_history.value.get("last_checkpoint_id")
# current_checkpoint_id = image_history.value.get("current_checkpoint_id")
#
# logger.info(f"\n[系统日志] 正在调用 edit_furniture ...current_checkpoint_id={current_checkpoint_id} --- last_checkpoint_id={last_checkpoint_id}")
#
# if image_store.get_image_path(last_checkpoint_id):
# current_image_path = image_store.get_image_path(last_checkpoint_id).get("current_image_path", False)
# if current_image_path:
# if isinstance(current_image_path, list):
# # 只取最后一张
# current_image_path = current_image_path[-1]
# else:
# current_image_path = None
2026-03-26 17:16:58 +08:00
2026-03-30 19:37:10 +08:00
# input_path = []
2026-03-26 17:16:58 +08:00
try :
2026-03-30 19:37:10 +08:00
# user_input_image_paths = runtime.state.get("files").get("input_image", [])
# user_quote_image_path = runtime.state.get("files").get("quote_image", "")
result = [ ]
if len ( input_image_paths ) :
for i in range ( len ( input_image_paths ) ) :
2026-03-30 15:12:56 +08:00
bucket_name = " fida-public-bucket "
object_name = f " furniture/sketches/ { uuid . uuid4 ( ) } .png "
2026-03-30 19:37:10 +08:00
image_url = await generate_or_edit_image ( input_path = [ input_image_paths [ i ] ] , prompt = prompts [ i ] , bucket_name = bucket_name , object_name = f " { object_name } - { i } .png " )
result . append ( image_url )
# image_url = await generate_or_edit_image(input_path=input_path, prompt=prompt, bucket_name=bucket_name, object_name=object_name)
# if image_url:
# image_store.save_image_path(thread_id=current_checkpoint_id, object_path=[image_url], metadata={"prompt": prompt, "generated_at": str(datetime.now())})
return result
# else:
# return "Image generation failed."
# else:
# return "The picture to be edited does not exist."
# else:
# return "No recent image found, please upload or cite it"
2026-03-19 17:55:39 +08:00
2026-03-26 17:16:58 +08:00
except Exception as e :
logger . warning ( f " edit_furniture error : { e } " )
return " edit_furniture error "
2026-03-19 17:55:39 +08:00
2026-03-30 15:12:56 +08:00
2026-03-30 19:37:10 +08:00
@tool
async def edit_quote_upload_furniture ( image_paths : list [ str ] = None , mode : str = " auto " , prompts : list [ str ] = None , ) :
"""
使用先进的图像编辑模型对家具图片进行精准批量修改 。
支持四种模式 :
- one_to_one ( 最常用 ) : 多张图片 + 多个提示词 , 一一对应编辑
- one_to_many : 多张图片 + 1 个提示词 ( 所有图片统一修改 )
- many_to_one : 1 张图片 + 多个提示词 ( 同一张图生成多个不同变体 , 例如不同颜色 )
- many_to_many ( 新增 ) : 多张图片 + 多个提示词 , 一一对应 ( 多对多交叉编辑 )
参数说明 :
- image_paths ( list [ str ] ) : MinIO 图片路径列表 , 长度建议 1 ~ 4
- prompts ( list [ str ] ) : 详细英文提示词列表
- mode ( str ) : " one_to_one " , " one_to_many " , " many_to_one " , " many_to_many " , " auto " ( 默认自动判断 )
使用要求 :
- image_paths 长度必须在 1 ~ 4 之间
- mode = " auto " 时会根据长度智能判断
- many_to_many 模式下 : image_paths 和 prompts 的长度必须完全相同
示例 :
示例1 : many_to_many ( 多对多 , 一一对应 )
image_paths = [ " sofa1.png " , " chair1.png " , " table1.png " ]
prompts = [
" Change to bright yellow modern style. " ,
" Change to deep green luxury style. " ,
" Change to soft beige Scandinavian style. "
]
mode = " many_to_many "
示例2 : many_to_one ( 同一张图多个颜色版本 )
image_paths = [ " sofa_original.png " ]
prompts = [ " yellow version " , " green version " , " blue version " , " black version " ]
mode = " many_to_one "
"""
try :
# ====================== 参数校验(直接返回错误信息) ======================
if not image_paths or len ( image_paths ) < 1 or len ( image_paths ) > 4 :
return f " 参数错误: image_paths 必须提供,且长度需要在 1 到 4 张之间。目前收到 { len ( image_paths ) if image_paths else 0 } 张。 "
if not prompts :
return " 参数错误: prompts 不能为空,请至少提供一个修改提示词。 "
if mode not in [ " one_to_one " , " one_to_many " , " many_to_one " , " many_to_many " , " auto " ] :
return f " 参数错误: mode 参数无效。可用值: one_to_one, one_to_many, many_to_one, many_to_many, auto。当前收到: { mode } "
# Auto 模式智能判断
if mode == " auto " :
if len ( image_paths ) == 1 and len ( prompts ) > 1 :
mode = " many_to_one "
elif len ( prompts ) == 1 :
mode = " one_to_many "
elif len ( image_paths ) == len ( prompts ) :
mode = " many_to_many " # 新增:数量相等时优先 many_to_many
else :
mode = " one_to_one "
# 各模式严格校验
if mode == " many_to_one " :
if len ( image_paths ) != 1 :
return f " 参数错误: many_to_one 模式只能传入 1 张图片,当前传入了 { len ( image_paths ) } 张。 "
if len ( prompts ) < 1 :
return " 参数错误: many_to_one 模式下 prompts 至少需要 1 个。 "
elif mode == " one_to_many " :
if len ( prompts ) != 1 :
return f " 参数错误: one_to_many 模式下 prompts 必须只有 1 个,当前有 { len ( prompts ) } 个。 "
elif mode in [ " one_to_one " , " many_to_many " ] :
if len ( prompts ) != len ( image_paths ) :
return ( f " 参数错误: { mode } 模式下 image_paths 和 prompts 数量必须完全一致。 \n "
f " 当前 image_paths 有 { len ( image_paths ) } 张, prompts 有 { len ( prompts ) } 个。 " )
# ====================== 执行编辑 ======================
result = [ ]
bucket_name = " fida-public-bucket "
if mode == " many_to_one " :
# 同一张图片 + 多个 prompt
base_image = image_paths [ 0 ]
for i , prompt in enumerate ( prompts ) :
object_name = f " furniture/sketches/ { uuid . uuid4 ( ) } .png "
image_url = await generate_or_edit_image (
input_path = [ base_image ] ,
prompt = prompt ,
bucket_name = bucket_name ,
object_name = f " { object_name } -var { i } .png "
)
result . append ( image_url )
else :
# one_to_one、many_to_many、one_to_many 统一处理
for i in range ( len ( image_paths ) ) :
# 根据模式决定当前使用的 prompt
if mode == " one_to_many " :
current_prompt = prompts [ 0 ]
else :
current_prompt = prompts [ i ] # one_to_one 和 many_to_many 都用对应位置的 prompt
object_name = f " furniture/sketches/ { uuid . uuid4 ( ) } .png "
image_url = await generate_or_edit_image (
input_path = [ image_paths [ i ] ] ,
prompt = current_prompt ,
bucket_name = bucket_name ,
object_name = f " { object_name } - { i } .png "
)
result . append ( image_url )
return result
except Exception as e :
logger . error ( f " edit_quote_upload_furniture 执行异常: { e } " , exc_info = True )
return f " 工具执行失败: { str ( e ) } ,请检查参数后重试。 "
2026-03-30 15:12:56 +08:00
async def generate_or_edit_image ( input_path = None , bucket_name = " fida-public-bucket " ,
object_name = f " furniture/sketches/ { uuid . uuid4 ( ) } .png " ,
prompt = " Generate a modern minimalist dining chair made of light "
" oak wood and white leather, with slim metal legs, photographed "
" in a bright Scandinavian living room with natural sunlight, high detail, "
" 8k resolution. " ) :
if input_path is None :
input_path = [ ]
request_data = {
" input_image_paths " : input_path ,
" prompt " : prompt ,
" bucket_name " : bucket_name ,
" object_name " : object_name ,
" width " : 1024 ,
" height " : 1024
}
async with httpx . AsyncClient ( timeout = 120 ) as client :
resp = await client . post (
f " http:// { settings . FLUX2_GEN_IMG_MODEL_URL } /predict " ,
json = request_data ,
)
result = resp . json ( )
image_url = result . get ( " output_path " , None )
return image_url