当前位置: 首页 > ds >正文

Dify智能体平台源码二次开发笔记(8)- OpenAvatarChat数字人项目+dify智能体完美融合

目录

简介

整合后的效果

智能体调用日志

智能体配置

OpenAvatarChat的整合代码

在配置文件里LLM_Bailian,添加dify配置

重构llm_handler_openai_compatible代码

最后


简介

完美集成了多模态+知识库+数字人一站式体验
Open Avatar Chat是阿里开源的模块化的实时数字人对话系统,支持在单台电脑上运行完整的功能。
Open Avatar Chat支持低延迟的实时对话(平均响应延迟约2.2秒),兼容多模态语言模型,包括文本、音频和视频等多种交互方式。系统基于模块化设计,用户根据需求灵活替换组件,实现不同的功能组合。为开发者和研究人员提供了高效、灵活的数字人对话解决方案。

整合后的效果

智能体调用日志

智能体配置

OpenAvatarChat的整合代码


在配置文件里LLM_Bailian,添加dify配置


dify_chat_messages: "https://xxxxxxx/v1/chat-messages" #dify消息推送接口
dify_code: "xxxxxx" 秘钥
dify_upload: "https://xxxxxxx/v1/files/upload" dify图片上传接口

重构llm代码


在LLMConfig配置类中,添加

dify_chat_messages: str = Field(default=None)
dify_code: str = Field(default=None)
dify_upload: str = Field(default=None)

在LLMContext上下文类的init方法中,添加

self.conversation_id = None # 这个是dify的会话id字段,保障dify的多轮对话
self.dify_chat_messages = None
self.dify_code = None
self.dify_upload = None

最后就要处理核心方法了 在handle中改成dify调用

output_definition = output_definitions.get(ChatDataType.AVATAR_TEXT).definitioncontext = cast(LLMContext, context)text = Noneif inputs.type == ChatDataType.CAMERA_VIDEO and context.enable_video_input:context.current_image = inputs.data.get_main_data()returnelif inputs.type == ChatDataType.HUMAN_TEXT:text = inputs.data.get_main_data()else:returnspeech_id = inputs.data.get_meta("speech_id")if (speech_id is None):speech_id = context.session_idif text is not None:context.input_texts += texttext_end = inputs.data.get_meta("human_text_end", False)if not text_end:returnchat_text = context.input_textschat_text = re.sub(r"<\|.*?\|>", "", chat_text)if len(chat_text) < 1:returnlogger.info(f'llm input {context.model_name} {chat_text} ')current_content = context.history.generate_next_messages(chat_text, [context.current_image] if context.current_image is not None else [])#logger.info(f'llm input {context.model_name} {current_content} ')# completion = context.client.chat.completions.create(#     model=context.model_name,#     messages=[#         context.system_prompt,#     ] + current_content,#     stream=True,#     stream_options={"include_usage": True}# )request_data = {"inputs": {},"query": chat_text,"response_mode": "streaming","conversation_id": context.conversation_id or "","user": "user","files": []}if context.current_image is not None:try:for image in [context.current_image]: import base64if isinstance(image, bytes):binary_image = imageelse:base64image = ImageUtils.format_image(image)if isinstance(base64image, str) and base64image.startswith('data:image'):image_data = base64image.split(',')[1]binary_image = base64.b64decode(image_data)files = {'file': ('image.jpg', binary_image, 'image/jpeg')}data = {'user': 'user'}upload_url = context.dify_uploadtry:upload_response = requests.post(upload_url,headers={'Authorization': f'Bearer {context.dify_code}'},files=files,data=data,timeout=(30, 120)  # Add timeout)if upload_response.status_code in [200, 201]:file_info = upload_response.json()request_data["files"].append({"type": "image","transfer_method": "local_file","upload_file_id": file_info['id']})logger.info(f"upload image. Status code: {upload_response.status_code}")else:logger.error(f"Failed to upload image. Status code: {upload_response.status_code}")logger.error(f"Response: {upload_response.text}")except requests.exceptions.RequestException as e:logger.error(f"Error uploading image: {str(e)}")except Exception as e:logger.error(f"Unexpected error handling image upload: {str(e)}")# Continue with text-only request if image upload failslogger.info(f"Sending chat message request with data: {json.dumps(request_data, ensure_ascii=False)}")try:response = requests.post(context.dify_chat_messages,headers={'Authorization': f'Bearer {context.dify_code}','Content-Type': 'application/json'},json=request_data,stream=True)logger.info(f"Chat message response received. Status code: {response.status_code}")if response.status_code != 200:logger.error(f"Chat message request failed. Response: {response.text}")except requests.exceptions.RequestException as e:logger.error(f"Failed to send chat message: {str(e)}")returncontext.current_image = Nonecontext.input_texts = ''context.output_texts = ''# for chunk in completion:#     if (chunk and chunk.choices and chunk.choices[0] and chunk.choices[0].delta.content):#         output_text = chunk.choices[0].delta.content#         context.output_texts += output_text#         logger.info(output_text)#         # 生成输出数据包#         output = DataBundle(output_definition)#         output.set_main_data(output_text)#         output.add_meta("avatar_text_end", False)#         output.add_meta("speech_id", speech_id)#         yield outputfor line in response.iter_lines():if line:try:line_str = line.decode('utf-8')if line_str.startswith('data: '):line_str = line_str[6:]json_response = json.loads(line_str)if json_response.get('event') == 'message':output_text = json_response.get('answer', '')if output_text:context.output_texts += output_textlogger.info(f"Received message: {output_text}")output = DataBundle(output_definition)output.set_main_data(output_text)output.add_meta("avatar_text_end", False)output.add_meta("speech_id", speech_id)yield outputelif json_response.get('event') == 'message_end':logger.info("Message stream ended")context.conversation_id = json_response.get('conversation_id')if 'metadata' in json_response:logger.info(f"Message metadata: {json_response['metadata']}")except json.JSONDecodeError as e:logger.error(f"Failed to parse JSON: {e}")continueexcept Exception as e:logger.error(f"Error processing message: {e}")continuecontext.history.add_message(HistoryMessage(role="avatar", content=context.output_texts))context.output_texts = ''logger.info('avatar text end')end_output = DataBundle(output_definition)end_output.set_main_data('')end_output.add_meta("avatar_text_end", True)end_output.add_meta("speech_id", speech_id)yield end_output

最后
 

有dify个性化定制需求,可以联系联系

http://www.xdnf.cn/news/5060.html

相关文章:

  • 升级 Azure Kubernetes 服务群集的关键注意事项
  • Spring Cloud LoadBalancer (负载均衡)
  • Kubernetes生产实战:NodePort端口范围的隐藏规则与调优指南
  • C——数组和函数实践:扫雷
  • 【PostgreSQL数据分析实战:从数据清洗到可视化全流程】电商数据分析案例-9.4 可视化报告输出
  • 两台服务器之前共享文件夹
  • 第十五章,SSL VPN
  • 一文了解氨基酸的分类、代谢和应用
  • Spring Web MVC基础理论和使用
  • Missashe考研日记-day36(改版说明)
  • AWS之数据分析类产品
  • 算法与数据结构 - 二叉树结构入门
  • git高效杀器——cz-customizable 搭配 commitlint
  • SAF利用由Varjo和AFormX开发的VR/XR模拟器推动作战训练
  • 【2025最新】如何定制化、高效化使用LIghtRAG进行规范知识抽取
  • STM32TIM定时中断(6)
  • 聊聊Spring AI autoconfigure模块的拆分
  • 香港科技大学(广州)新开设智能制造理学硕士学位项目线上招生宣讲会
  • 切比雪夫不等式详解
  • Vibe Coding: 优点与缺点
  • 在 Kotlin 中什么是委托属性,简要说说其使用场景和原理
  • 嵌入式openharmony标准系统中HDF框架底层原理分析
  • 软件工程之面向对象分析深度解析
  • 从代码学习深度学习 - 区域卷积神经网络(R-CNN)系列 PyTorch版
  • Go语言Stdio传输MCP Server示例【Cline、Roo Code】
  • 《循序渐进linux》
  • 应急响应基础模拟靶机-security1
  • Vue Router 3 使用详解:从零构建嵌套路由页面
  • MySQL 与 Elasticsearch 数据一致性方案
  • Java反射 八股版