PHP code example of vergil-lai / wecom-aibot-php-sdk

1. Go to this page and download the library: Download vergil-lai/wecom-aibot-php-sdk library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

vergil-lai / wecom-aibot-php-sdk example snippets



VergilLai\WecomAiBot\WSClient;
use VergilLai\WecomAiBot\Types\WsClientOptions;
use VergilLai\WecomAiBot\Types\WsFrame;
use VergilLai\WecomAiBot\Utils;

// 1. 创建客户端实例
$wsClient = new WSClient(new WsClientOptions(
    botId: 'your-bot-id',       // 企业微信后台获取的机器人 ID
    secret: 'your-bot-secret',  // 企业微信后台获取的机器人 Secret
));

// 2. 建立连接(支持链式调用)
$wsClient->connect();

// 3. 监听认证成功
$wsClient->on('authenticated', function () {
    echo '🔐 认证成功', PHP_EOL;
});

// 4. 监听文本消息并进行流式回复
$wsClient->on('message.text', function (WsFrame $frame) use ($wsClient) {
    $content = $frame->body['text']['content'] ?? '';
    echo "收到文本: {$content}", PHP_EOL;

    $streamId = Utils::generateReqId('stream');

    // 发送流式中间内容
    $wsClient->replyStream($frame, $streamId, '正在思考中...', false);

    // 发送最终结果
    React\EventLoop\Loop::addTimer(1.0, function () use ($wsClient, $frame, $streamId, $content) {
        $wsClient->replyStream($frame, $streamId, "你好!你说的是: \"{$content}\"", true);
    });
});

// 5. 监听进入会话事件(发送欢迎语)
$wsClient->on('event.enter_chat', function (WsFrame $frame) use ($wsClient) {
    $wsClient->replyWelcome($frame, [
        'msgtype' => 'text',
        'text' => ['content' => '您好!我是智能助手,有什么可以帮您的吗?'],
    ]);
});

// 6. 优雅退出
$loop = React\EventLoop\Loop::get();
$loop->addSignal(SIGINT, function () use ($wsClient, $loop) {
    $wsClient->disconnect();
    $loop->stop();
});

$wsClient = new WSClient(options: WsClientOptions|array);

$wsClient->replyStream(
    frame: WsFrame,              // 收到的原始 WebSocket 帧(透传 req_id)
    streamId: string,            // 流式消息 ID(使用 Utils::generateReqId('stream') 生成)
    content: string,             // 回复内容(支持 Markdown),最长 20480 字节
    finish: bool = false,        // 是否结束流式消息
    msgItem: ?array = null,      // 图文混排项(仅 finish=true 时有效,最多 10 个)
    feedback: ?ReplyFeedback = null, // 反馈信息(仅首次回复时设置)
);

$streamId = Utils::generateReqId('stream');

// 发送流式中间内容
$wsClient->replyStream($frame, $streamId, '正在处理中...', false);

// 发送最终结果(finish=true 表示结束流)
$wsClient->replyStream($frame, $streamId, '处理完成!结果是...', true);

// 文本欢迎语
$wsClient->replyWelcome($frame, [
    'msgtype' => 'text',
    'text' => ['content' => '欢迎!'],
]);

// 模板卡片欢迎语
$wsClient->replyWelcome($frame, [
    'msgtype' => 'template_card',
    'template_card' => ['card_type' => 'text_notice', 'main_title' => ['title' => '欢迎']],
]);

$wsClient->replyStreamWithCard(
    frame: WsFrame,       // 收到的原始 WebSocket 帧
    streamId: string,     // 流式消息 ID
    content: string,      // 回复内容(支持 Markdown)
    finish: bool = false, // 是否结束流式消息
    options: ?array = null, // 选项(见下方)
);

// 发送 Markdown 消息
$wsClient->sendMessage('userid_or_chatid', [
    'msgtype' => 'markdown',
    'markdown' => ['content' => '这是一条**主动推送**的消息'],
]);

// 发送模板卡片消息
$wsClient->sendMessage('userid_or_chatid', [
    'msgtype' => 'template_card',
    'template_card' => ['card_type' => 'text_notice', 'main_title' => ['title' => '通知']],
]);

$filePath = '/path/to/image.png';
$result = $wsClient->uploadMedia($filePath, new UploadMediaOptions(
    type: WeComMediaType::Image,
    filename: 'image.png',
));

$result->then(function (UploadMediaFinishResult $result) use ($wsClient, $frame) {
    echo "上传成功,media_id: {$result->mediaId}\n";
    // 使用 media_id 回复图片消息
    $wsClient->replyMedia($frame, WeComMediaType::Image, $result->mediaId);
});

// aesKey 取自消息体中的 image.aeskey 或 file.aeskey
$wsClient->on('message.image', function (WsFrame $frame) use ($wsClient) {
    $body = $frame->body;
    $result = $wsClient->downloadFile($body['image']['url'], $body['image']['aeskey'] ?? null);
    echo "文件名: {$result->filename}, 大小: " . strlen($result->buffer) . " bytes\n";
});

readonly class WsFrame
{
    public function __construct(
        public ?string $cmd,          // 命令类型
        public WsFrameHeaders $headers, // headers 含 req_id(回复时需透传)
        public ?array $body = null,   // 消息体
        public ?int $errcode = null,  // 响应错误码
        public ?string $errmsg = null, // 响应错误信息
    ) {}
}

$wsClient = new WSClient(new WsClientOptions(
    botId: 'your-bot-id',
    secret: 'your-bot-secret',
    logger: new class implements \Psr\Log\LoggerInterface {
        ...
    },
));

$wsClient->on('message.text', function (WsFrame $frame) use ($wsClient) {
    $streamId = Utils::generateReqId('stream');

    // 流式中间内容
    $wsClient->replyStream($frame, $streamId, '正在生成内容...', false);

    // 流式结束
    React\EventLoop\Loop::addTimer(1.0, function () use ($wsClient, $frame, $streamId) {
        $wsClient->replyStream($frame, $streamId, '这是最终结果', true);
    });
});

$wsClient->on('message.text', function (WsFrame $frame) use ($wsClient) {
    $filePath = '/path/to/document.pdf';

    $wsClient->uploadMedia($filePath, new UploadMediaOptions(
        type: WeComMediaType::File,
        filename: 'document.pdf',
    ))->then(function (UploadMediaFinishResult $result) use ($wsClient, $frame) {
        $wsClient->replyMedia($frame, WeComMediaType::File, $result->mediaId);
    });
});

$wsClient->on('authenticated', function () use ($wsClient) {
    // 向指定用户推送 Markdown 消息
    $wsClient->sendMessage('target_userid', [
        'msgtype' => 'markdown',
        'markdown' => ['content' => '# 通知\n\n这是一条**主动推送**的消息。'],
    ]);
});

// 回复带按钮的模板卡片
$wsClient->on('message.text', function (WsFrame $frame) use ($wsClient) {
    $wsClient->replyTemplateCard($frame, new TemplateCard(
        cardType: TemplateCardType::ButtonInteraction,
        mainTitle: ['title' => '请选择操作', 'desc' => '点击下方按钮进行操作'],
        buttonList: [
            ['text' => '确认', 'key' => 'btn_confirm', 'style' => 1],
            ['text' => '取消', 'key' => 'btn_cancel', 'style' => 2],
        ],
        taskId: 'task_' . time(),
    ));
});

// 监听卡片按钮点击事件并更新卡片
$wsClient->on('event.template_card_event', function (WsFrame $frame) use ($wsClient) {
    $eventKey = $frame->body['event']['event_key'] ?? '';
    $taskId = $frame->body['event']['task_id'] ?? '';

    $wsClient->updateTemplateCard($frame, new TemplateCard(
        cardType: TemplateCardType::TextNotice,
        mainTitle: ['title' => $eventKey === 'btn_confirm' ? '已确认' : '已取消'],
        taskId: $taskId,
    ));
});

$wsClient->on('message.image', function (WsFrame $frame) use ($wsClient) {
    $body = $frame->body;
    $imageUrl = $body['image']['url'] ?? '';
    if (empty($imageUrl)) return;

    $result = $wsClient->downloadFile($imageUrl, $body['image']['aeskey'] ?? null);
    $fileName = $result->filename ?? 'image_' . time() . '.jpg';
    file_put_contents(__DIR__ . '/' . $fileName, $result->buffer);
    echo "图片已保存: {$fileName} (" . strlen($result->buffer) . " bytes)\n";
});