jquery在文心智能体平台使用API方式部署智能体-AI客服

jquery在文心智能体平台使用API方式部署智能体-AI客服

创建智能体

创建地址:https://agents.baidu.com/agent/list/codeless

查看需要部署智能体的ID和秘钥

这两哥参数,ID和秘钥,接口中要用到。

实现功能

参考文档:https://agents.baidu.com/docs/develop/out-deployment/conversation/

有两种方式可以实现与智能体进行对话并且获取非流式返回、流式返回 ,仅支持零代码方式创建的智能体

非流式对话接口是查询所有答案之后再返回,流式对话接口是边查询边返回,更友好一些。

我用的是流式对话接口的形式。

点击旁边的AI客服按钮,出现聊天弹框。

css:

typescript 复制代码
.znt-dialog{
		position: fixed;
		top: 21%;
		right: 4.5%;
		display: none;
		width: 346px;
		height: 570px;
		border: 1px solid #33615f;
		background: #fff;
		border-radius: 10px;
		box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgb(179 164 164 / 24%);
		z-index: 999;
	}
	.znt-show{
		display: block;
	}
	.znt-title{
		height: 35px;
		line-height: 35px;
		/*text-align: right;*/
		padding: 0 15px 0 15px;
		border-bottom: 1px solid #eee;
		display: flex;
		justify-content: space-between;
		align-items: center;

	}
	.znt-title-icon{
		background: url("/images/before/kf/ZNKF.svg") no-repeat 0px 7px / 100% 100%;
		background-size: 18px 18px;
		padding-left: 22px;
		display: inline-block;
	}
	.znt-close{
		cursor: pointer;
	}
	.znt-cont{
		position: absolute;
		top: 35px;
		left: 0px;
		right: 0px;
		bottom: 0px;
		display: flex;
		flex-direction: column;
		overflow: hidden;
	}
	/* 聊天记录区(可滚动) */
	#chatMessages {
		flex: 1;
		padding: 16px;
		overflow-y: auto;
		/*background: #f5f7fa;*/
		background: url("/images/before/kf/znkf_bg.png") no-repeat 0px 0px / 100% 100%;
		/* 阻止滚动穿透到背后的页面 */
		overscroll-behavior: contain;
	}

	/* 消息气泡样式(区分用户/智能体) */
	.message {
		margin-bottom: 12px;
		max-width: 70%;
		padding: 8px 12px;
		border-radius: 8px;
		line-height: 1.5;
		white-space: pre-line;
		/* 宽度贴合内容,最大宽度 70% */
		width: fit-content;
	}
	.user-message {
		background: #2f54eb;
		color: #fff;
		margin-left: auto; /* 用户消息右对齐 */
	}
	.agent-message {
		background: #e5e6eb;
		color: #1d2129;
		margin-right: auto; /* 智能体消息左对齐 */
	}

	/* 输入区域 */
	#chatInputArea {
		display: flex;
		padding: 12px;
		border-top: 1px solid #eee;
	}
	#userInput {
		flex: 1;
		padding: 8px 12px;
		border: 1px solid #ddd;
		border-radius: 4px;
		outline: none;
	}
	#sendMsgBtn {
		margin-left: 8px;
		padding: 8px 16px;
		background: #2f54eb;
		color: #fff;
		border: none;
		border-radius: 4px;
		cursor: pointer;
	}
	#sendMsgBtn:disabled {
		background: #c9cdd4;
		cursor: not-allowed;
	}

html:

typescript 复制代码
<!--点击-->
<li  class="zxli cl1 znt">
	<img class="img" src="xxx" alt="点击" title="点击" >
	<p>AI客服</p>
</li>

<!--智能体弹窗-->
<div class="znt-dialog" >
	<div class="znt-title">
		<span class="znt-title-icon">
<!--			<img class="img" src="/images/before/kf/ZNKF.svg" style="width: 20px;height: 20px" >-->
			AI客服
		</span>
		<span class="znt-close">X</span>
	</div>
	<div class="znt-cont">
		<!-- 聊天记录区 -->
		<div id="chatMessages"></div>
		<!-- 输入区 -->
		<div id="chatInputArea">
			<input type="text" id="userInput" placeholder="请输入您的问题...">
			<button id="sendMsgBtn">发送</button>
		</div>
	</div>
</div>

js:

typescript 复制代码
$(function(){
	var startWord = "我是xxx助理,我能帮助您提供xxx建议和技术服务,以及给您提供相关的智慧解决方案。请问您需要了解xxxxx什么问题呢?";
	const chatState = {
	 threadId: "",
	 agentReplyBuffer: "",
	 isRequesting: false
	};
	
	$(document).on("click", ".znt", function () {
	 $("#userInput").val("");
	 const $dialog = $(".znt-dialog");
	 if ($dialog.hasClass('znt-show')) {
		 $dialog.removeClass('znt-show');
		 // $("#chatMessages").html('');
		 // chatState.threadId = "";
		 chatState.agentReplyBuffer = "";
	 } else {
		 $dialog.addClass('znt-show');
		 $("#userInput").focus();
		 // addMessageToUI("agent", startWord, "");
	
		 // 【新增】首次打开时,若聊天记录为空,才添加欢迎语
		 if ($("#chatMessages").html().trim() === "") {
			 addMessageToUI("agent", startWord, "");
		 }
	
	 }
	});
	
	$(document).on("click", ".znt-close", function () {
	 $("#userInput").val("");
	 $(".znt-dialog").removeClass('znt-show');
	 // $("#chatMessages").html('');
	 // chatState.threadId = "";
	 chatState.agentReplyBuffer = "";
	});
	
	$(document).on("click", "#sendMsgBtn", function () {
	 const userQuestion = $("#userInput").val().trim();
	 if (userQuestion && !chatState.isRequesting) {
		 addMessageToUI("user", userQuestion, "");
		 sendStreamingPostRequest(userQuestion);
		 $("#userInput").val("");
	 }
	});
	
	$(document).on("keydown", "#userInput", function (e) {
	 const userQuestion = $(this).val().trim();
	 if (e.key === 'Enter' && userQuestion &&!chatState.isRequesting) {
		 addMessageToUI("user", userQuestion, "");
		 sendStreamingPostRequest(userQuestion);
		 $(this).val('');
		 e.preventDefault();// 阻止输入框默认换行
	 }
	});
	
	async function sendStreamingPostRequest(userQuestion) {
	 const appId = localStorage.getItem("clientId");
	 const secretKey = localStorage.getItem("clientSecret");
	 if (!appId ||!secretKey) {
		 addMessageToUI("agent", "错误:未获取到智能体配置(appId/secretKey 缺失)", "");
		 return;
	 }
	
	 chatState.isRequesting = true;
	 const loadingMsgId = `loading-${Date.now()}`;
	 addMessageToUI("agent", "正在查询,请稍等...", "loadingDom", loadingMsgId);
	
	 const openId = generateSecureRandomString(10);
	 const requestParams = {
		 message: {
			 content: {
				 type: "text",
				 value: { showText: userQuestion }
			 }
		 },
		 source: appId,
		 from: "openapi",
		 openId: openId,
		 threadId: chatState.threadId || ""
	 };
	
	 try {
		 // 1. 发起 POST 请求,获取流式响应
		 const response = await fetch('https://agentapi.baidu.com/assistant/conversation?appId=' + appId + '&secretKey=' + secretKey, {
			 method: 'POST',
			 headers: {
				 'Content-Type': 'application/json'
			 },
			 body: JSON.stringify(requestParams)
		 });
	
		 if (!response.ok) {
			 throw new Error(`HTTP 错误!状态码:${response.status}`);
		 }
	
		 // 2. 处理流式响应(核心:逐块读取并解析)
		 const reader = response.body.getReader();
		 const decoder = new TextDecoder();
		 let accumulatedText = ""; // 累计的智能体回复文本
	
		 while (true) {
			 const { done, value } = await reader.read();
			 if (done) break;
	
			 // 3. 解码二进制数据为字符串,按行分割(SSE 每行是一个数据块)
			 const chunk = decoder.decode(value, { stream: true });
			 const lines = chunk.split('\n');
	
			 // 4. 逐行解析数据
			 for (const line of lines) {
				 if (line.trim() === '') continue; // 跳过空行
	
				 try {
					 // 提取 data: 后的 JSON 字符串
					 const dataStr = line.startsWith('data:')? line.slice('data:'.length) : null;
					 if (!dataStr) continue;
	
					 const data = JSON.parse(dataStr);
					 handleStreamData(data, loadingMsgId, accumulatedText);
	
					 // 5. 提取并累计有效文本
					 const textFragment = extractTextFromData(data);
					 if (textFragment) {
						 accumulatedText += textFragment;
						 // 实时渲染累计的文本(带 Markdown 格式转换)
						 const formattedText = convertMarkdownToHtml(accumulatedText);
						 renderStreamingMessage("agent", formattedText);
					 }
	
				 } catch (err) {
					 console.error('解析数据块失败:', line, err);
				 }
			 }
		 }
	
		 chatState.isRequesting = false;
	 } catch (error) {
		 chatState.isRequesting = false;
		 chatState.agentReplyBuffer = "";
		 $(`#${loadingMsgId}`).remove();
		 addMessageToUI("agent", `请求失败:${error.message}`, "");
	 }
	
	 // 流式结束后,释放请求锁(若用 EventSource,需在 close 事件中设置)
	 chatState.isRequesting = false;
	}
	
	// 辅助函数:从数据中提取文本片段
	function extractTextFromData(data) {
	 // 1. 过滤无效数据(data 为 null 或无 content)
	 if (!data || !data.data || !data.data.message || !data.data.message.content) {
		 return null;
	 }
	
	 // 2. 提取 content 数组中第一个元素的 text(假设是 markdown 类型)
	 const contentItem = data.data.message.content[0];
	 return contentItem?.data?.text || null;
	}
	// 辅助函数:处理单块流式数据(可扩展错误处理、endTurn 判断等)
	function handleStreamData(data, loadingMsgId, accumulatedText) {
	 // 示例:存储 threadId(用于上下文关联)
	 if (data.data?.message?.threadId) {
		 chatState.threadId = data.data.message.threadId;
	 }
	
	 // 示例:判断是否为最后一块数据(endTurn: true)
	 if (data.data?.message?.endTurn === true) {
		 // 移除"正在查询"提示
		 $(`#${loadingMsgId}`).remove();
		 // 追加最终的智能体消息(用 addMessageToUI,确保是新容器)
		 addMessageToUI("agent", accumulatedText, "");
		 // 重置缓冲区
		 chatState.agentReplyBuffer = "";
		 // 自动聚焦输入框
		 $("#userInput").focus();
	 }
	}
	
	// 实时渲染智能体消息
	function renderStreamingMessage(sender, formattedContent) {
	 const $chatContainer = $("#chatMessages");
	 let $agentMsg = $chatContainer.find(".agent-message:last");
	
	 if (!$agentMsg.length) {
		 $agentMsg = $(`<div class="message agent-message" ></div>`);
		 $chatContainer.append($agentMsg);
	 }
	
	 $agentMsg.html(formattedContent);
	 $chatContainer.scrollTop($chatContainer[0].scrollHeight);
	}
	
	// 将信息渲染到聊天框内
	function addMessageToUI(sender, content, loadingDom, loadingMsgId = "") {
	 $(".loadingDom").remove();
	
	 const $chatContainer = $("#chatMessages");
	 const messageDiv = document.createElement('div');
	
	 messageDiv.className = `message ${sender === 'user'? 'user-message' : 'agent-message'} ${loadingDom || ''}`;
	 if (loadingMsgId) messageDiv.id = loadingMsgId;
	
	 const formattedContent = convertMarkdownToHtml(content);
	 messageDiv.innerHTML = formattedContent;
	
	 $chatContainer.append(messageDiv);
	 $chatContainer.scrollTop($chatContainer[0].scrollHeight);
	}
	
	function convertMarkdownToHtml(markdownText) {
	 if (!markdownText) return "";
	 let html = markdownText;
	
	 html = html.replace(/\n/g, "<br>");
	 html = html.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>");
	 html = html.replace(/^- (.*?)(<br>|$)/gm, "<li style='margin: 4px 0;'>$1</li>");
	 html = html.replace(/(<li>.*?<\/li>)(\s*<li>.*?<\/li>)+/g, "<ul style='padding-left: 20px; margin: 8px 0;'>$&</ul>");
	 html = html.replace(/### (.*?)(<br>|$)/g, "<h4 style='margin: 8px 0; font-size: 15px; font-weight: 600;'>$1</h4>$2");
	
	 return html;
	}
	
	function generateSecureRandomString(length = 10) {
	 const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
	 let result = '';
	 for (let i = 0; i < length; i++) {
		 result += chars[Math.floor(Math.random() * chars.length)];
	 }
	 return result;
	}
	
});
相关推荐
郑陈皮2 小时前
qiankun vs MicroApp 微前端框架对比分析
前端·前端框架
信息快讯2 小时前
【智能融合:增材制造多物理场AI建模与工业应用实战】
人工智能·制造
Kylo_Cheok2 小时前
如何从 0 到 1 开发一个浏览器插件(AI 赋能)
前端
子兮曰2 小时前
🚀我用这个Bun.js技巧,让JSON API开发效率提升300%
前端·javascript·bun
心不正意不诚身不修不知其可也2 小时前
leaflet点阵地图
前端
月亮慢慢圆2 小时前
Page Visibility API
前端
高级测试工程师欧阳2 小时前
CSS 属性概述
前端·css
wolfking2612 小时前
elpis里程碑四:动态组件库建设
前端
昔人'2 小时前
纯`css`轻松防止滚动穿透
前端·css