版本

依赖于google的 github Agent2Agent/samples/python
其他依赖:


absl-py==2.2.2
annotated-types==0.7.0
anyio==4.9.0
appdirs==1.4.4
asttokens==3.0.0
asyncclick==8.1.8.0
Authlib==1.5.2
blinker==1.9.0
cachetools==5.5.2
certifi==2025.4.26
cffi==1.17.1
charset-normalizer==3.4.2
click==8.1.8
colorama==0.4.6
cryptography==44.0.3
decorator==5.2.1
deepdiff==6.7.1
Deprecated==1.2.18
distro==1.9.0
docstring_parser==0.16
docx2pdf==0.1.8
dotenv==0.9.9
exceptiongroup==1.3.0
executing==2.2.0
fastapi==0.115.12
fastmcp==2.3.3
filetype==1.2.0
Flask==3.1.0
google-adk==0.5.0
google-ai-generativelanguage==0.6.18
google-api-core==2.24.2
google-api-python-client==2.169.0
google-auth==2.40.1
google-auth-httplib2==0.2.0
google-cloud-aiplatform==1.92.0
google-cloud-bigquery==3.31.0
google-cloud-core==2.4.3
google-cloud-resource-manager==1.14.2
google-cloud-secret-manager==2.23.3
google-cloud-speech==2.32.0
google-cloud-storage==2.19.0
google-cloud-trace==1.16.1
google-crc32c==1.7.1
google-genai==1.14.0
google-resumable-media==2.7.2
googleapis-common-protos==1.70.0
graphviz==0.20.3
greenlet==3.2.1
grpc-google-iam-v1==0.14.2
grpcio==1.72.0
grpcio-status==1.72.0
h11==0.16.0
httpcore==1.0.9
httplib2==0.22.0
httpx==0.28.1
httpx-sse==0.4.0
idna==3.10
importlib_metadata==8.6.1
ipython==9.2.0
ipython_pygments_lexers==1.1.1
itsdangerous==2.2.0
jedi==0.19.2
Jinja2==3.1.6
jiter==0.9.0
jsonpatch==1.33
jsonpointer==3.0.0
jwcrypto==1.5.6
langchain-core==0.3.58
langchain-google-genai==2.1.4
langchain-mcp-adapters==0.0.10
langchain-openai==0.3.16
langgraph==0.4.2
langgraph-checkpoint==2.0.25
langgraph-prebuilt==0.1.8
langgraph-sdk==0.1.66
langsmith==0.3.42
lxml==6.0.0
markdown-it-py==3.0.0
MarkupSafe==3.0.2
matplotlib-inline==0.1.7
mcp==1.8.1
mdurl==0.1.2
mesop==1.0.1
msgpack==1.1.0
msoffcrypto-tool==5.4.2
numpy==2.2.5
olefile==0.47
openai==1.77.0
openapi-pydantic==0.5.1
opentelemetry-api==1.32.1
opentelemetry-exporter-gcp-trace==1.9.0
opentelemetry-resourcedetector-gcp==1.9.0a0
opentelemetry-sdk==1.32.1
opentelemetry-semantic-conventions==0.53b1
ordered-set==4.1.0
orjson==3.10.18
ormsgpack==1.9.1
packaging==24.2
pandas==2.2.3
parso==0.8.4
prompt_toolkit==3.0.51
proto-plus==1.26.1
protobuf==6.31.0rc2
pure_eval==0.2.3
pyasn1==0.6.1
pyasn1_modules==0.4.2
pycparser==2.22
pydantic==2.11.4
pydantic-settings==2.9.1
pydantic_core==2.33.2
pyee==11.1.1
Pygments==2.19.1
PyJWT==2.10.1
pyparsing==3.2.3
pyppeteer==2.0.0
python-dateutil==2.9.0.post0
python-docx==1.2.0
python-dotenv==1.1.0
python-multipart==0.0.20
pytz==2025.2
pywin32==311
PyYAML==6.0.2
regex==2024.11.6
requests==2.32.3
requests-toolbelt==1.0.0
rich==14.0.0
rsa==4.9.1
shapely==2.1.0
shellingham==1.5.4
six==1.17.0
sniffio==1.3.1
SQLAlchemy==2.0.40
sse-starlette==2.3.4
stack-data==0.6.3
starlette==0.46.2
tenacity==9.1.2
tiktoken==0.9.0
tqdm==4.67.1
traitlets==5.14.3
typer==0.15.3
typing-inspection==0.4.0
typing_extensions==4.13.2
tzdata==2025.2
tzlocal==5.3.1
uritemplate==4.1.1
urllib3==1.26.20
uv==0.7.2
uvicorn==0.34.2
watchdog==6.0.0
wcwidth==0.2.13
websockets==14.0
Werkzeug==3.1.3
wrapt==1.17.2
xxhash==3.5.0
zipp==3.21.0
zstandard==0.23.0

Mcp

word操作mcp

GongRzhe/Office-Word-MCP-Server/

UML图绘制mcp

1 . plantuml官网下载jar包
2. 编写python mcp tool

import os
import subprocess
from fastmcp import FastMCP
from typing import Union
mcp = FastMCP("plant uml")

@mcp.tool()
def get_current_directory():
    """
    获取当前工作目录。

    返回:
        str: 当前工作目录的路径
    """
    current_dir = os.getcwd()
    print(f"当前工作目录是: {current_dir}")
    return current_dir


@mcp.tool()
def overwrite_file(content: Union[str, bytes], file_path: str) -> bool:
    """
    全量覆盖更新文件内容,仅在内容变化时执行写入操作

    参数:
        content (str|bytes): 要写入的内容,可以是字符串或字节
        file_path (str): 目标文件路径

    返回:
        bool: 是否执行了写入操作(True=已写入,False=未写入或失败)

    示例:
        >>> overwrite_file("new content", "/path/to/file.txt")
        True
    """
    try:
        # 标准化路径并创建目录
        file_path = os.path.normpath(file_path)
        os.makedirs(os.path.dirname(file_path), exist_ok=True)

        # 检查内容是否变化
        if os.path.exists(file_path):
            mode = 'rb' if isinstance(content, bytes) else 'r'
            with open(file_path, mode) as f:
                existing_content = f.read()
                if existing_content == content:
                    print(f"内容未变化,跳过写入: {file_path}")
                    return False

        # 执行写入操作
        mode = 'wb' if isinstance(content, bytes) else 'w'
        encoding = None if isinstance(content, bytes) else 'utf-8'
        with open(file_path, mode, encoding=encoding) as f:
            f.write(content)

        print(f"成功更新文件: {file_path}")
        return True
    except Exception as e:
        print(f"文件更新失败: {file_path} - {str(e)}")
        return False

@mcp.tool()
def save_text_to_file(content, file_path):
    """
    将指定文本保存到指定路径的文件中

    参数:
        content (str): 要保存的文本内容
        file_path (str): 文件的完整路径,例如 'D:/example.puml'

    返回:
        bool: 如果成功则返回 True,否则返回 False
    """
    try:
        # 创建目录(如果不存在)
        os.makedirs(os.path.dirname(file_path), exist_ok=True)

        with open(file_path, 'w', encoding='utf-8') as file:
            file.write(content)
        print(f"成功将文本保存到 {file_path}")
        return True
    except Exception as e:
        print(f"保存失败: {e}")
        return False

@mcp.tool()
def plant_uml(file_name):
    """
        渲染输入的*.plum文件为 png格式的UML 图

        参数:
            file_name (str): plantuml 文件的完整路径,例如 'D:/test.puml'

        返回:
            bool: 如果成功则返回 True,否则返回 False
        """
    # 确保文件存在
    if not os.path.exists(file_name):
        print(f"文件 {file_name} 不存在。")
        return False

    # 构造命令
    command = ["java", "-jar", "plantuml-epl-SNAPSHOT.jar", file_name]

    try:
        # 执行命令
        subprocess.run(command, check=True)
        print(f"成功生成 {file_name} 的图片。")
        return True
    except subprocess.CalledProcessError as e:
        print(f"渲染失败: {e}")
        return False

if __name__ == '__main__':
    mcp.run(
        transport='sse',
        host="127.0.0.1",
        port=9001,
        path="/sse"
    )

Agent2Agent

doc_agent.py

组装llm和mcp的类

import asyncio
import time

from google.adk.tools.mcp_tool.mcp_session_manager import SseServerParams
from langchain_core.messages import HumanMessage
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_mcp_adapters.tools import load_mcp_tools
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
from mcp import StdioServerParameters, ClientSession, stdio_client
from mcp.client.sse import sse_client
from langgraph.checkpoint.memory import MemorySaver  # 内存型检查点存储

class DocAgent:
    def __init__(self):
        self.model = ChatOpenAI(base_url="http://your_url/openai/v1", model="deepseek-chat",
                           streaming=True,
                           api_key="your_key")

        self.client =  MultiServerMCPClient(
                {
                    "PlantUmlServer": {
                        "url": "http://127.0.0.1:9001/sse",
                        "transport": "sse"
                    },
                    "OperateDocFileServer": {
                        "url": "http://127.0.0.1:8888/sse",
                        "transport": "sse"
                    }
                }
        )

    async def open(self):
        await self.client.__aenter__()
        self.tools = self.client.get_tools()
        print(self.tools)
        self.agent = create_react_agent(model=self.model, tools=self.tools, prompt="""你是一个doc项目文档编写助手""",
                                        checkpointer=MemorySaver())

    async def close(self):
        await self.client.__aexit__(None, None, None)
    async def agent_chat(self,query: str):
        state = await self.agent.aget_state({"configurable":{"thread_id": "1"}})

        # 从状态中获取 messages
        messages = state.values.get("messages", [])
        begin_index = len(messages)
        agent_response = await self.agent.ainvoke({
            "messages":query
        },
            {"configurable":{"thread_id": "1"}}
        )
        messages = agent_response.get("messages")
        if begin_index != 0:
            messages = messages[begin_index:]
        print("\n")
        for message in messages:
            print(message)

        content = messages[-1].content
        print(f"\n agent final response: {content}")
        return messages


async def begin():
    doc_agent = DocAgent()
    await doc_agent.open()
    result= await doc_agent.agent_chat("""据如下sql最终完成绘制uml的er实体关系图:""")
    await doc_agent.close()
if __name__ == "__main__":
   asyncio.run(begin())

dock_task_manager.py

a2a的task manager

from agents.wind_doc.doc_agent import DocAgent

import asyncio
from typing import AsyncIterable
from urllib import request

from common.server import InMemoryTaskManager
from common.types import SendTaskRequest, SendTaskResponse, SendTaskStreamingRequest, SendTaskStreamingResponse, \
    JSONRPCResponse, TaskState, TaskStatus, Message, Artifact, Task, TaskStatusUpdateEvent

from common.types import FileContent,FilePart
from pathlib import Path
import base64
from langchain_core.messages import BaseMessage
from file_util import convert_to_download_url
from pyasn1_modules.rfc7906 import id_enumeratedRestrictiveAttributes


class DocAgentTaskManager(InMemoryTaskManager):
    def __init__(self):
        super().__init__()
        self.doc_agent = None

    async def init(self):
        self.doc_agent = DocAgent()
        await self.doc_agent.open()

    async def destory(self):
        await self.doc_agent.close()

    async def on_send_task(self, request: SendTaskRequest) -> SendTaskResponse:
        await self.upsert_task(request.params)
        task_id = request.params.id

        received_text = request.params.message.parts[0].text
        if self.doc_agent is None:
            await self.init()
        messages = await self.doc_agent.agent_chat(received_text)
        chat_result = messages[-1].content

        await self._update_task_messages_text(
            task_id=task_id,
            task_state= TaskState.COMPLETED,
            messages=messages
        )
        task = await self._update_task_message_text(
            task_id=task_id,
            task_state=TaskState.COMPLETED,
            response_text=f"{chat_result}"
        )
        await self.process_tool_outcome(task_id, TaskState.COMPLETED, messages)
        task = self.tasks[task_id]
        return SendTaskResponse(id=request.id,result=task)

    async def on_send_task_subscribe(self, request: SendTaskStreamingRequest) -> AsyncIterable[
                                                                                     SendTaskStreamingResponse] | JSONRPCResponse:
        await self.upsert_task(request.params)
        task_id = request.params.id
        is_new_task = task_id in self.tasks
        await self.upsert_task(request.params)

        received_text = request.params.message.parts[0].text
        sse_event_queue = await self.setup_sse_consumer(task_id=task_id)


        return self.dequeue_events_for_sse(request_id=request.id, task_id=task_id, sse_event_queue=sse_event_queue)
    async def process_tool_outcome(self, task_id: str, task_state: TaskState, messages: list[BaseMessage]):
        args_map = {}
        for message in messages:
            if message.type == "ai":
                tool_calls = message.tool_calls
                for tool_call in tool_calls:
                    args_map[tool_call["id"]] = tool_call["args"]
            if message.type == "tool":
                tool_call_id = message.tool_call_id
                name = message.name
                if name == "create_document":
                    args = args_map[tool_call_id]
                    filename = args["filename"]
                    url = convert_to_download_url(filename)
                    await self._update_task_artifact_file_uri(task_id,task_state,url)
                if name == "plant_uml":
                    args = args_map[tool_call_id]
                    file_name = args["file_name"]
                    await self._update_task_artifact_img(task_id,task_state,file_name)
    async def _update_task_artifact_img(self,task_id: str, task_state: TaskState,image_path: str):
        path = Path(image_path.replace(".puml",".png"))

        # Read file as binary and encode as base64 string
        with open(path, 'rb') as f:
            file_bytes = f.read()
        base64_bytes = base64.b64encode(file_bytes).decode('utf-8')

        # 构建 FileContent 使用 URI 方式
        file_content = FileContent(
            name="er_diagram.png",
            mimeType="image/png",
            bytes=base64_bytes
        )
           # 构建 FilePart
        file_part = FilePart(
            file=file_content
        )

        task = self.tasks[task_id]
        if task.artifacts is None:
            task.artifacts=[]
        task.artifacts.append(Artifact(parts=[file_part]))
        self.tasks[task_id] = task
        return task


    async def _update_task_artifact_file_uri(self, task_id: str, task_state: TaskState, uri: str):
        # 构建 FileContent 使用 URI 方式
        file_content = FileContent(
            name=uri.split("-1")[-1],
            mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            uri=uri
        )

        # 构建 FilePart
        file_part = FilePart(
            file=file_content
        )

        task = self.tasks[task_id]
        if task.artifacts is None:
            task.artifacts=[]
        task.artifacts.append(Artifact(parts=[file_part]))
        self.tasks[task_id] = task
        return task

    async def _update_task_message_text(self, task_id: str, task_state: TaskState, response_text: str) -> Task:

        agent_response_parts = [
            {
                "type": "text",
                "text": response_text,
            }
        ]

        task = self.tasks[task_id]

        task.status = TaskStatus(state=task_state, message=Message(role="agent", parts=agent_response_parts))

        if task.artifacts is None:
            task.artifacts=[]
        task.artifacts.append( Artifact(parts=agent_response_parts))

        self.tasks[task_id] = task
        return task

    async def _update_task_messages_text(self, task_id: str, task_state: TaskState, messages: list[str]) -> Task:
        agent_response_parts = []
        for message in messages:
            if message.type == "tool":
                agent_response_parts.append({
                    "type": "text",
                    "text": "【工具调用】 ["+message.name+"] 执行结果: "+message.content,
                })

        task = self.tasks[task_id]

        task.status = TaskStatus(state=task_state, message=Message(role="agent", parts=agent_response_parts))

        if task.artifacts is None:
            task.artifacts = []
        task.artifacts.append(Artifact(parts=agent_response_parts))

        self.tasks[task_id] = task
        return task

main.py

主函数

import asyncio

import click

from agents.wind_doc.doc_task_manager import DocAgentTaskManager
from common.server import A2AServer
from common.types import AgentSkill, AgentCapabilities, AgentCard
from exceptiongroup import catch


def main():
    try:
        host = "127.0.0.1"
        port= 10001
        skill = AgentSkill(
            id="doc-operate-skill",
            name="operator doc file",
            description="operator doc file",
            tags=["doc"],
            examples=["create test.doc  on D:/Document"],
            inputModes=["text"],
            outputModes=["text"],
        )
        print(skill)

        capabilities = AgentCapabilities()
        agent_card = AgentCard(name="doc-operate-agent", description="program doc operate agent", url=f"http://{host}:{port}",
                         version="0.1.0", defaultInputModes=["text"], defaultOutputModes=["text"], capabilities=capabilities,
                         skills=[skill])
        print(agent_card)

        task_manager = DocAgentTaskManager()
        task_manager.init()
        server = A2AServer(agent_card= agent_card,task_manager=task_manager,host=host,port=port)
        server.start()
        print("Server started")
    except KeyboardInterrupt:
        print("shut down")
    finally:
        task_manager.destory()

if __name__ == '__main__':
    main()

file_system.py

启一个文件服务器,方便a2a client下载文件.

import os
from http.server import HTTPServer, SimpleHTTPRequestHandler

def run_http_server(directory="D:\\Document", port=8000):
    """
    启动 HTTP 服务器(前台运行,按 Ctrl+C 停止)
    """
    os.chdir(directory)
    server = HTTPServer(('0.0.0.0', port), SimpleHTTPRequestHandler)
    print(f"服务器已启动,访问: http://localhost:{port}")
    print("按 Ctrl+C 停止服务器...")
    try:
        server.serve_forever()  # 阻塞,直到手动停止
    except KeyboardInterrupt:
        print("\n服务器已停止")

# 启动服务器(会阻塞,直到手动停止)
run_http_server()

file_util.py

把本地路径转为远端可访问的uri

import os
from urllib.parse import quote

def convert_to_download_url(file_path, server_base_url="http://localhost:8000"):
    """
    将本地文件路径转换为可下载的URL,仅当文件位于 D:\Document 目录下时才允许转换

    参数:
        file_path (str): 本地文件的绝对路径
        server_base_url (str): 文件服务器的基础URL(默认 http://localhost:8000)

    返回:
        str: 可下载的URL,如果文件不在 D:\Document 下则返回 None

    示例:
        >>> convert_to_download_url("D:\\Document\\test.txt")
        "http://localhost:8000/test.txt"

        >>> convert_to_download_url("C:\\Other\\file.txt")
        None  # 文件不在 D:\Document 下,不允许访问
    """
    # 标准化路径,避免不同格式(如 D:/Document vs D:\Document)
    normalized_path = os.path.normpath(file_path)
    document_dir = os.path.normpath("D:\\Document")

    # 检查文件是否在 D:\Document 或其子目录下
    if not normalized_path.startswith(document_dir + os.sep):
        print(f"错误:文件 '{file_path}' 不在 D:\\Document 目录下,无法生成URL")
        return None

    # 检查文件是否存在
    if not os.path.exists(file_path):
        print(f"错误:文件 '{file_path}' 不存在")
        return None

    # 获取相对路径(相对于 D:\Document)
    relative_path = os.path.relpath(normalized_path, document_dir)

    # URL编码文件名(处理空格、中文等特殊字符)
    encoded_filename = quote(relative_path.replace(os.sep, '/'))

    # 构建完整的下载URL
    download_url = f"{server_base_url.rstrip('/')}/{encoded_filename}"

    return download_url

a2aClient.html

一个静态页面,用于访问A2A协议的server

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Agent Connector</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
        }
        .container {
            display: flex;
            flex-direction: column;
            gap: 20px;
        }
        .input-group {
            display: flex;
            gap: 10px;
        }
        input, textarea {
            flex: 1;
            padding: 8px;
            font-size: 16px;
        }
        button {
            padding: 8px 16px;
            background-color: #4CAF50;
            color: white;
            border: none;
            cursor: pointer;
            font-size: 16px;
        }
        button:hover {
            background-color: #45a049;
        }
        #agentInfo, #conversation {
            border: 1px solid #ddd;
            padding: 15px;
            border-radius: 5px;
            background-color: #f9f9f9;
            white-space: pre-wrap;
            font-family: monospace;
        }
        .status {
            padding: 10px;
            border-radius: 5px;
            margin-bottom: 10px;
        }
        .success {
            background-color: #dff0d8;
            color: #3c763d;
        }
        .error {
            background-color: #f2dede;
            color: #a94442;
        }
        .chat-message {
            margin: 10px 0;
            padding: 8px;
            border-radius: 4px;
        }
        .user-message {
            background-color: #e3f2fd;
            text-align: right;
        }
        .agent-message {
            background-color: #f1f1f1;
        }
        #dialogContainer {
            display: none;
            margin-top: 20px;
        }
        /* 图片消息样式 */
        .chat-message img {
            max-width: 100%;
            border-radius: 4px;
            margin-top: 8px;
            border: 1px solid #ddd;
        }

        /* 二进制数据提示 */
        .binary-meta {
            font-size: 12px;
            color: #666;
            margin-top: 4px;
        }
    </style>
</head>
<body>
<div class="container">
    <h1>Agent Connector</h1>

    <div class="input-group">
        <input type="text" id="agentUrl" placeholder="Enter Agent URL" value="http://localhost:10001">
        <button id="connectBtn">Connect</button>
    </div>
    
    <div id="statusContainer"></div>

    <h2>Agent Information</h2>
    <div id="agentInfo">Not connected</div>

    <!-- 新增的对话界面 -->
    <div id="dialogContainer">
        <h2>Conversation</h2>
        <div id="conversation"></div>

        <div class="input-group">
            <textarea id="messageInput" placeholder="Type your message here..." rows="3"></textarea>
        </div>
        <button id="sendBtn">Send Message</button>
    </div>
</div>

<script>
    // 全局变量存储连接信息
    let currentSessionId = Date.now().toString(); // 生成唯一会话ID
    let agentBaseUrl = '';

    document.getElementById('connectBtn').addEventListener('click', async function() {
        const agentUrl = document.getElementById('agentUrl').value.trim();
        const statusContainer = document.getElementById('statusContainer');
        const agentInfo = document.getElementById('agentInfo');

        if (!agentUrl) {
            showStatus('Please enter a valid Agent URL', 'error');
            return;
        }

        try {
            showStatus('Connecting to agent...', 'success');

            // 测试连接
            const response = await fetch(`${agentUrl}/.well-known/agent.json`);

            if (!response.ok) {
                throw new Error(`Agent connection failed: ${response.status}`);
            }

            const data = await response.json();
            agentInfo.textContent = JSON.stringify(data, null, 2);
            showStatus('Successfully connected to agent!', 'success');

            // 连接成功后显示对话界面
            agentBaseUrl = agentUrl;
            document.getElementById('dialogContainer').style.display = 'block';
        } catch (error) {
            showStatus(`Error: ${error.message}`, 'error');
            agentInfo.textContent = 'Failed to load agent information';
            console.error('Connection error:', error);
        }
    });

    // 发送消息到A2A服务器
    document.getElementById('sendBtn').addEventListener('click', async function() {
        const messageInput = document.getElementById('messageInput').value.trim();
        const conversation = document.getElementById('conversation');

        if (!messageInput) {
            showStatus('Please enter a message', 'error');
            return;
        }

        try {
            // 添加用户消息到对话界面
            addMessageToConversation('user', messageInput);

            // 清空输入框
            document.getElementById('messageInput').value = '';

            // 准备请求数据
            const requestData = {
                "jsonrpc": "2.0",
                "method": "tasks/send",
                "params": {
                    "id": Date.now().toString(),
                    "sessionId": currentSessionId,
                    "message": {
                        "role": "user",
                        "parts": [{
                            "type": "text",
                            "text": messageInput
                        }]
                    }
                }
            };

            showStatus('Sending message to agent...', 'success');

            // 发送请求到A2A服务器
            const response = await fetch(`${agentBaseUrl}`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify(requestData)
            });
            
            if (!response.ok) {
                throw new Error(`Request failed: ${response.status}`);
            }

            const responseData = await response.json();

            // 添加AI响应到对话界面
            if (responseData.result) {
                addMessageToConversation('agent', JSON.stringify(responseData.result, null, 2));
            } else {
                addMessageToConversation('agent', JSON.stringify(responseData, null, 2));
            }

            console.log('Full agent response:', responseData);

            // 处理二进制附件(如图片)
            if (responseData.result.artifacts) {
                responseData.result.artifacts.forEach(artifact => {
                    console.log("one artifact")
                    artifact.parts.forEach(part => {
                        console.log("one part")
                        if (part.type === 'file' && part.file?.mimeType?.startsWith('image/')) {
                            console.log("one part is img")
                            displayBinaryImage(part);
                        }
                    });
                });
            }

            showStatus('Message sent successfully!', 'success');
        } catch (error) {
            showStatus(`Error: ${error.message}`, 'error');
            console.error('Message sending error:', error);
        }
    });

    // 辅助函数:显示状态消息
    function showStatus(message, type) {
        const statusContainer = document.getElementById('statusContainer');
        const statusDiv = document.createElement('div');
        statusDiv.className = `status ${type}`;
        statusDiv.textContent = message;
        statusContainer.innerHTML = '';
        statusContainer.appendChild(statusDiv);
    }

    // 辅助函数:添加消息到对话界面
    function addMessageToConversation(role, content) {
        const conversation = document.getElementById('conversation');
        const messageDiv = document.createElement('div');
        messageDiv.className = `chat-message ${role}-message`;

        const roleSpan = document.createElement('span');
        roleSpan.textContent = `${role}: `;
        roleSpan.style.fontWeight = 'bold';

        const contentSpan = document.createElement('span');
        contentSpan.textContent = content;

        messageDiv.appendChild(roleSpan);
        messageDiv.appendChild(document.createElement('br'));
        messageDiv.appendChild(contentSpan);

        conversation.appendChild(messageDiv);
        conversation.scrollTop = conversation.scrollHeight;
    }

        // 显示二进制图片
    function displayBinaryImage(part) {
        const conversation = document.getElementById('conversation');
        const messageDiv = document.createElement('div');
        messageDiv.className = 'chat-message agent-message';

        // 从Base64数据创建图片
        const img = document.createElement('img');
        img.src = `data:${part.file.mimeType};base64,${part.file.bytes}`;
        console.log(img)
        // 添加文件名提示
        const metaDiv = document.createElement('div');
        metaDiv.className = 'binary-meta';
        metaDiv.textContent = `图片附件: ${part.file.name}`;

        messageDiv.appendChild(img);
        messageDiv.appendChild(metaDiv);
        conversation.appendChild(messageDiv);
        conversation.scrollTop = conversation.scrollHeight;
    }

    // 将ArrayBuffer转换为Base64
    function arrayBufferToBase64(buffer) {
        let binary = '';
        const bytes = new Uint8Array(buffer);
        for (let i = 0; i < bytes.byteLength; i++) {
            binary += String.fromCharCode(bytes[i]);
        }
        return window.bzip2 ? window.bzip2(binary) : binary;
    }

</script>
</body>
</html>
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐