import os
from typing import Dict, List, Tuple

from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

from langgraph import graph
from langgraph.prebuilt import ToolNode

os.environ["OPENAI_API_KEY"] = "sk-quardo-lkiWl35MXbrFL2EKa1gCXPyeBF65a07nFGelnnOGCh87S1nG"
os.environ["OPENAI_API_BASE"] = "https://api.cow.rip/api/v1"

human_message = """Analyze this image and tell me what you see:

https://storage.googleapis.com/causal-diffusion.appspot.com/imagePrompts%2F0rw369i5h9t%2Foriginal.png"""

llm = ChatOpenAI(model="gpt-4o-mini", max_tokens=1024)
llm_response = llm.invoke(
    [
        HumanMessage(
            content=[
                {"type": "text", "text": human_message},
                {
                    "type": "image_url",
                    "image_url": {
                        "url": "https://storage.googleapis.com/causal-diffusion.appspot.com/imagePrompts%2F0rw369i5h9t%2Foriginal.png"
                    }
                },
            ]
        )
    ]
)
print(llm_response.content)

tools = [
    {
        "type": "function",
        "function": {
            "name": "identify_objects",
            "description": "Identify objects in an image",
            "parameters": {
                "type": "object",
                "properties": {
                    "objects": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "List of objects identified in the image",
                    }
                },
                "required": ["objects"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "analyze_weather",
            "description": "Analyze the weather conditions in an image",
            "parameters": {
                "type": "object",
                "properties": {
                    "weather_condition": {
                        "type": "string",
                        "description": "Description of the weather condition",
                    },
                    "temperature_estimate": {
                        "type": "string",
                        "description": "Estimated temperature range",
                    },
                },
                "required": ["weather_condition", "temperature_estimate"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "describe_landscape",
            "description": "Describe the landscape features in an image",
            "parameters": {
                "type": "object",
                "properties": {
                    "terrain_type": {
                        "type": "string",
                        "description": "Type of terrain (e.g., mountainous, coastal, urban)",
                    },
                    "notable_features": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "List of notable landscape features",
                    },
                },
                "required": ["terrain_type", "notable_features"],
            },
        },
    },
]

def fake_function_call(name, arguments):
    return f"Simulated response for {name} with arguments: {arguments}"

def tool_executor(tool_invocation):
    function_name = tool_invocation.name
    function_arguments = tool_invocation.arguments

    return fake_function_call(function_name, function_arguments)

tools_executor = ToolNode(tool_executor, tools)

system_message = """You are STORM (Situation, Task, Object, Relationships, and Mood), an expert image analyst AI. Your task is to analyze images using the STORM framework:

1. Situation: Describe the overall context or setting of the image.
2. Task: Identify any actions or activities taking place.
3. Objects: List and describe key objects, people, or elements in the image.
4. Relationships: Explain how different elements in the image relate to or interact with each other.
5. Mood: Describe the overall atmosphere, emotion, or tone conveyed by the image.

Use the available tools to gather specific information about the image. Always use tools when they are relevant to any part of the STORM analysis.
After using tools, incorporate the information into your analysis, ensuring you cover all aspects of the STORM framework comprehensively."""

human_message = """Analyze this image using the STORM framework:

https://storage.googleapis.com/causal-diffusion.appspot.com/imagePrompts%2F0rw369i5h9t%2Foriginal.png"""

agent_prompt = ChatPromptTemplate.from_messages(
    [
        ("system", system_message),
        MessagesPlaceholder(variable_name="messages"),
        ("human", "{input}"),
        MessagesPlaceholder(variable_name="agent_scratchpad"),
    ]
)

def agent(messages, input, agent_scratchpad):
    result = llm.invoke(
        agent_prompt.format_messages(
            messages=messages,
            input=input,
            agent_scratchpad=agent_scratchpad,
        )
    )
    return result.content

def should_continue(messages, input, agent_scratchpad):
    result = llm.invoke(
        agent_prompt.format_messages(
            messages=messages,
            input=input,
            agent_scratchpad=agent_scratchpad,
        )
    )
    if "tool_calls" in result.additional_kwargs:
        return "continue"
    else:
        return "end"

def call_tool(messages, input, agent_scratchpad):
    result = llm.invoke(
        agent_prompt.format_messages(
            messages=messages,
            input=input,
            agent_scratchpad=agent_scratchpad,
        )
    )
    if "tool_calls" in result.additional_kwargs:
        action = ToolInvocation(
            name=result.additional_kwargs["tool_calls"][0]["function"]["name"],
            arguments=result.additional_kwargs["tool_calls"][0]["function"]["arguments"],
        )
        return tools_executor.invoke(action)
    else:
        return result

workflow = graph.Graph()

workflow.add_node("agent", agent)
workflow.add_node("should_continue", should_continue)
workflow.add_node("call_tool", call_tool)

workflow.set_entry_point("agent")
workflow.add_edge("agent", "should_continue")
workflow.add_conditional_edges(
    "should_continue",
    {
        "continue": "call_tool",
        "end": "agent",
    },
)
workflow.add_edge("call_tool", "agent")

chain = workflow.compile()

for s in chain.stream(
    {
        "messages": [],
        "input": human_message,
        "agent_scratchpad": [],
    }
):
    print(s)
    print("----")
    
上面是我的代码，运行后报错：
The image depicts a scene featuring a young girl and a large, friendly-looking creature, often recognized as Totoro from the animated film "My Neighbor Totoro." The girl is holding a small pink umbrella, while Totoro holds a larger umbrella. They appear to be waiting at a bus stop in a forested area, with rain falling around them. The atmosphere is whimsical and serene, reflecting the themes of nature and companionship prevalent in the film.
Traceback (most recent call last):
  File "E:\ipynb\main.py", line 109, in <module>
    tools_executor = ToolNode(tool_executor, tools)
TypeError: ToolNode.__init__() takes 2 positional arguments but 3 were given
Press any key to continue . . .

请帮我修复，并给我完整代码，中文回答