news 2026/7/7 6:29:55

将dify接入钉钉机器人中

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
将dify接入钉钉机器人中

想要将dify接入钉钉机器人中进行问答,首先需要创建应用,添加企业机器人,创建消息卡片,开发机器人回复消息的代码,最后接入dify,使用dify的工作流进行回答。

一、机器人准备

1、创建应用:创建应用 - 钉钉开放平台

2、添加应用能力:添加应用能力 - 钉钉开放平台

3、配置企业机器人:配置企业机器人 - 钉钉开放平台

4、新建卡片模板:打字机效果流式 AI 卡片 - 钉钉开放平台

二、开发代码

1、安装官方SDK

pip install dingtalk_stream loguru

2、修改模板代码

以下为官方模板代码,根据自己的需求修改消息接收和回复逻辑

import os import logging import asyncio import argparse from loguru import logger from dingtalk_stream import AckMessage import dingtalk_stream from http import HTTPStatus from dashscope import Generation from typing import Callable def define_options(): parser = argparse.ArgumentParser() parser.add_argument( "--client_id", dest="client_id", default=os.getenv("DINGTALK_APP_CLIENT_ID"), help="app_key or suite_key from https://open-dev.digntalk.com", ) parser.add_argument( "--client_secret", dest="client_secret", default=os.getenv("DINGTALK_APP_CLIENT_SECRET"), help="app_secret or suite_secret from https://open-dev.digntalk.com", ) options = parser.parse_args() return options async def call_with_stream(request_content: str, callback: Callable[[str], None]): messages = [{"role": "user", "content": request_content}] responses = Generation.call( Generation.Models.qwen_turbo, messages=messages, result_format="message", # set the result to be "message" format. stream=True, # set stream output. incremental_output=True, # get streaming output incrementally. ) full_content = "" # with incrementally we need to merge output. length = 0 for response in responses: if response.status_code == HTTPStatus.OK: full_content += response.output.choices[0]["message"]["content"] full_content_length = len(full_content) if full_content_length - length > 20: await callback(full_content) logger.info( f"调用流式更新接口更新内容:current_length: {length}, next_length: {full_content_length}" ) length = full_content_length else: raise Exception( f"Request id: {response.request_id}, Status code: {response.status_code}, error code: {response.code}, error message: {response.message}" ) await callback(full_content) logger.info( f"Request Content: {request_content}\nFull response: {full_content}\nFull response length: {len(full_content)}" ) return full_content async def handle_reply_and_update_card(self: dingtalk_stream.ChatbotHandler, incoming_message: dingtalk_stream.ChatbotMessage): # 卡片模板 ID card_template_id = "8aebdfb9-28f4-4a98-98f5-396c3dde41a0.schema" # 该模板只用于测试使用,如需投入线上使用,请导入卡片模板 json 到自己的应用下 content_key = "content" card_data = {content_key: ""} card_instance = dingtalk_stream.AICardReplier( self.dingtalk_client, incoming_message ) # 先投放卡片: https://open.dingtalk.com/document/orgapp/create-and-deliver-cards card_instance_id = await card_instance.async_create_and_deliver_card( card_template_id, card_data ) # 再流式更新卡片: https://open.dingtalk.com/document/isvapp/api-streamingupdate async def callback(content_value: str): return await card_instance.async_streaming( card_instance_id, content_key=content_key, content_value=content_value, append=False, finished=False, failed=False, ) try: full_content_value = await call_with_stream( incoming_message.text.content, callback ) await card_instance.async_streaming( card_instance_id, content_key=content_key, content_value=full_content_value, append=False, finished=True, failed=False, ) except Exception as e: self.logger.exception(e) await card_instance.async_streaming( card_instance_id, content_key=content_key, content_value="", append=False, finished=False, failed=True, ) class CardBotHandler(dingtalk_stream.ChatbotHandler): def __init__(self, logger: logging.Logger = logger): super(dingtalk_stream.ChatbotHandler, self).__init__() if logger: self.logger = logger async def process(self, callback: dingtalk_stream.CallbackMessage): incoming_message = dingtalk_stream.ChatbotMessage.from_dict(callback.data) self.logger.info(f"收到消息:{incoming_message}") if incoming_message.message_type != "text": self.reply_text("俺只看得懂文字喔~", incoming_message) return AckMessage.STATUS_OK, "OK" asyncio.create_task(handle_reply_and_update_card(self, incoming_message)) return AckMessage.STATUS_OK, "OK" def main(): options = define_options() credential = dingtalk_stream.Credential(options.client_id, options.client_secret) client = dingtalk_stream.DingTalkStreamClient(credential) client.register_callback_handler( dingtalk_stream.ChatbotMessage.TOPIC, CardBotHandler() ) client.start_forever() if __name__ == "__main__": main()

3、接入dify

根据dify创建的工作流的API文档进行调用,如果想进行多轮对话可以保存返回的conversation_id

full_content = "" length = 0 timeout = aiohttp.ClientTimeout(total=60) async with aiohttp.ClientSession(timeout=timeout) as session: try: async with session.post(DIFY_CHAT_URL, headers=headers, json=payload) as resp: if resp.status != 200: error_text = await resp.text() raise Exception(f"Dify API error: {resp.status}, {error_text}") async for line in resp.content: line = line.decode('utf-8').strip() if not line or not line.startswith("data:"): continue data_str = line[5:].strip() # 去掉 "data:" if data_str == "[DONE]": break try: data = json.loads(data_str) if 'conversation_id' in data and not conv_id: # 首次创建对话,保存 ID update_conversation_id(user_id, data['conversation_id']) except json.JSONDecodeError: continue if 'answer' in data: chunk = data['answer'] full_content += chunk # 策略1:每次收到 chunk 都回调 # await callback(full_content) # 策略2:累积一定长度再回调 if len(full_content) - length >= 20: await callback(full_content) logger.info( f"调用流式更新接口更新内容:current_length: {length}, next_length: {len(full_content)}" ) length = len(full_content) # 最终回调(确保完整内容被处理) if full_content and len(full_content) > length: await callback(full_content) logger.info( f"Request Content: {request_content}\nFull response: {full_content}\nFull response length: {len(full_content)}" ) return full_content except Exception as e: logger.error(f"调用 Dify 流式接口出错: {e}") raise

4、拓展

继续开发,不仅可以进行文字对话,还能够进行图片问答,先调用self.get_image_download_url方法获取钉钉上传的图像,再调用v1/files/upload接口即可上传图像到dify

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/7 8:13:59

C++中1 << 31 - 1相当于INT_MAX吗?

在 C 中&#xff0c;1 << 31 - 1 不相当于 INT_MAX&#xff0c;而且这是一个有问题的表达式&#xff0c;让我们分步分析&#xff1a;表达式解析 1 << 31 - 1 在 C 中会被解析为 1 << (31 - 1) &#xff0c;这是因为减法优先级高于左移&#xff0c;结果等于1 …

作者头像 李华
网站建设 2026/7/6 8:21:34

AdGuardHomeRules:百万级规则构建的智能广告拦截堡垒

AdGuardHomeRules&#xff1a;百万级规则构建的智能广告拦截堡垒 【免费下载链接】AdGuardHomeRules 高达百万级规则&#xff01;由我原创&整理的 AdGuardHomeRules ADH广告拦截过滤规则&#xff01;打造全网最强最全规则集 项目地址: https://gitcode.com/gh_mirrors/ad…

作者头像 李华
网站建设 2026/7/6 20:37:21

translate.js:两行代码解决网站多语言国际化难题

您是否曾面临这样的困境&#xff1a;精心打造的网站却因为语言障碍而无法触达全球用户&#xff1f;当您的网站内容仅局限于单一语言时&#xff0c;就意味着主动放弃了超过80%的潜在国际市场。传统的多语言解决方案往往需要重构页面结构、配置复杂的语言文件&#xff0c;甚至需要…

作者头像 李华
网站建设 2026/7/5 8:11:22

Wan2.2-T2V-5B在批量内容生产中的应用实践

Wan2.2-T2V-5B在批量内容生产中的应用实践 如今&#xff0c;一条短视频从创意到上线的时间窗口正在急剧压缩。社交媒体平台的算法偏爱高频更新、视觉新颖的内容&#xff0c;而传统视频制作流程却仍停留在“脚本—拍摄—剪辑—审核”的线性模式中&#xff0c;动辄数小时甚至数天…

作者头像 李华
网站建设 2026/7/7 15:21:29

Wan2.2-T2V-5B如何助力STM32边缘设备的交互式内容展示

Wan2.2-T2V-5B如何助力STM32边缘设备的交互式内容展示 在数字标牌、智能展台和教育机器人等场景中&#xff0c;用户不再满足于“播放预录视频”的被动体验。他们希望设备能“听懂”一句话&#xff0c;立刻生成一段专属动画——比如输入“一只戴着帽子的兔子在森林里跳舞”&…

作者头像 李华
网站建设 2026/7/7 10:20:33

FLUX.1-dev与Three.js结合:实现Web端动态AI图像生成

FLUX.1-dev与Three.js结合&#xff1a;实现Web端动态AI图像生成 在数字创作的边界不断被重新定义的今天&#xff0c;我们正见证一场从“静态输出”到“交互生成”的范式迁移。过去&#xff0c;AI图像生成往往止步于一张PNG或JPEG文件——用户输入提示词&#xff0c;等待几秒甚至…

作者头像 李华