一款基于百度文心一言的商品品评智能回复Chrome插件

打印 上一主题 下一主题

主题 1869|帖子 1869|积分 5607

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
一、引言

在前次小弟发布了一款基于openai大模子的Chrome网页插件后,有很多朋友向我提意见,表示这个插件需要翻墙,对于真正的小白还是有些不友好。因此这次我花了两个通宵,完成了一款基于百度文心一言大模子的网页插件的创作。本文将以作为一款商品品评的智能回复工具为例,具体介绍插件的功能及利用方法,大家可以根据本身的需求魔改插件,实现不同的目标,例如文稿助手、谈天助手等。本插件完全开源,也欢迎大家一起学习,或作为课设毕设利用。
二、功能展示

本文以作为商品品评智能回复工具的目标为例,具体展示插件各功能。

在普通模式下,用户可以将消耗者的品评输入进插件,插件将会调用百度api进行智能回复。

而在高级模式下,用户可以选择四种情绪模式、三种回复策略来让插件作答,如图所示,每种模式将会有不同的表达,如许能让商家对于不同范例的买家品评做出最得当且快速的回复。
三、插件部署

对于插件本身来说,包罗这几个文件:

1.manifest.json
  1. {
  2.     "manifest_version": 3,
  3.     "name": "Wenxin Chat reply",
  4.     "version": "1.0",
  5.     "description": "A Chrome extension to chat with Baidu Wenxin",
  6.     "permissions": [
  7.         "activeTab",
  8.         "storage"
  9.     ],
  10.     "background": {
  11.         "service_worker": "background.js"
  12.     },
  13.     "action": {
  14.         "default_popup": "popup.html",
  15.         "default_icon": {
  16.             "16": "icons/icon16.png",
  17.             "48": "icons/icon48.png",
  18.             "128": "icons/icon128.png"
  19.         }
  20.     },
  21.     "icons": {
  22.         "16": "icons/icon16.png",
  23.         "48": "icons/icon48.png",
  24.         "128": "icons/icon128.png"
  25.     }
  26. }
复制代码

2.popup.html(插件前端页面)
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7.     <title>文心一言商家智能回复</title>
  8.     <style>
  9.         html, body {
  10.             width: 500px;  /* 调整宽度 */
  11.             height: 100%;
  12.             margin: 0;
  13.             padding: 0;
  14.             box-sizing: border-box;
  15.         }
  16.     </style>
  17.     <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
  18.     <link rel="stylesheet" href="./style.css">
  19.     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.7.2/font/bootstrap-icons.min.css">
  20.     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
  21. </head>
  22. <body>
  23.     <div class="container mt-4">
  24.         <h1 class="text-center mb-4">文心一言商品评价回复</h1>
  25.         <div class="form-check form-switch mb-3">
  26.             <span id="mode-text">智能回复(高级模式)</span>
  27.             <input class="form-check-input" type="checkbox" role="switch" id="model-selector">
  28.             <label class="form-check-label" for="model-selector"></label>
  29.         </div>
  30.         <p style="font-size: 17px;">消费者的评论</p>
  31.         <div class="form mb-3">
  32.             <textarea class="form-control" id="user-input" placeholder="请输入......" rows="4"></textarea>
  33.         </div>
  34.         <div id="review-section" class="d-none">
  35.             <div class="mb-3">
  36.                 <p>选择情绪模式:</p>
  37.                 <div class="btn-group-vertical w-100" role="group">
  38.                     <input type="radio" class="btn-check" name="emotionStrategy" id="acknowledgement" autocomplete="off" checked>
  39.                     <label class="btn btn-outline-primary" for="acknowledgement">认可</label>
  40.                     <input type="radio" class="btn-check" name="emotionStrategy" id="informal" autocomplete="off">
  41.                     <label class="btn btn-outline-primary" for="informal">随和</label>
  42.                     <input type="radio" class="btn-check" name="emotionStrategy" id="attentiveness" autocomplete="off">
  43.                     <label class="btn btn-outline-primary" for="attentiveness">关注</label>
  44.                     <input type="radio" class="btn-check" name="emotionStrategy" id="encouragement" autocomplete="off">
  45.                     <label class="btn btn-outline-primary" for="encouragement">鼓励</label>
  46.                 </div>
  47.             </div>
  48.             <div class="mb-3">
  49.                 <p>选择回复策略:</p>
  50.                 <div class="btn-group-vertical w-100" role="group">
  51.                     <input type="radio" class="btn-check" name="rationalStrategy" id="explanation" autocomplete="off" checked>
  52.                     <label class="btn btn-outline-success" for="explanation">解释</label>
  53.                     <input type="radio" class="btn-check" name="rationalStrategy" id="redress" autocomplete="off">
  54.                     <label class="btn btn-outline-success" for="redress">补偿</label>
  55.                     <input type="radio" class="btn-check" name="rationalStrategy" id="facilitation" autocomplete="off">
  56.                     <label class="btn btn-outline-success" for="facilitation">改进</label>
  57.                 </div>
  58.             </div>
  59.         </div>
  60.         <div class="d-grid gap-2 mb-4">
  61.             <button id="send-button" class="btn btn-primary">提交</button>
  62.         </div>
  63.         <div id="response" class="p-3 bg-light border rounded" style="min-height: 100px;"></div>
  64.     </div>
  65.     <script src="./popup.js"></script>
  66. </body>
  67. </html>
复制代码

3.popup.js
  1. document.getElementById('model-selector').addEventListener('change', function() {
  2.     const reviewSection = document.getElementById('review-section');
  3.     if (this.checked) {
  4.         reviewSection.classList.remove('d-none');
  5.     } else {
  6.         reviewSection.classList.add('d-none');
  7.     }
  8. });
  9. document.getElementById('send-button').addEventListener('click', function () {
  10.     const userInput = document.getElementById('user-input').value;
  11.     const responseElement = document.getElementById('response');
  12.     const isBasicMode = document.getElementById('model-selector').checked;
  13.     const emotionStrategy = isBasicMode ? document.querySelector('input[name="emotionStrategy"]:checked').id : null;
  14.     const rationalStrategy = isBasicMode ? document.querySelector('input[name="rationalStrategy"]:checked').id : null;
  15.     responseElement.innerText = 'Loading...';
  16.     chrome.runtime.sendMessage({ action: 'getWenxinResponse', content: userInput, emotionStrategy, rationalStrategy, isBasicMode }, function (response) {
  17.         if (chrome.runtime.lastError) {
  18.             responseElement.innerText = 'Error: ' + chrome.runtime.lastError.message;
  19.         } else {
  20.             responseElement.innerText = response;
  21.         }
  22.     });
  23. });
复制代码

4. background.js
  1. const serverUrl = 'http://127.0.0.1:3000';  // 代理服务器的URL
  2. function getAccessToken() {
  3.     return new Promise((resolve, reject) => {
  4.         fetch(`${serverUrl}/getAccessToken`, {
  5.             method: 'POST',
  6.             headers: {
  7.                 'Content-Type': 'application/json'
  8.             },
  9.             body: JSON.stringify({})
  10.         })
  11.         .then(response => {
  12.             if (!response.ok) {
  13.                 throw new Error(`HTTP error! Status: ${response.status}`);
  14.             }
  15.             return response.json();
  16.         })
  17.         .then(data => {
  18.             if (data.access_token) {
  19.                 resolve(data.access_token);
  20.             } else {
  21.                 throw new Error('Failed to retrieve access token');
  22.             }
  23.         })
  24.         .catch(error => {
  25.             console.error('Error fetching access token:', error);
  26.             reject(error);
  27.         });
  28.     });
  29. }
  30. function getPrompt(userMessage, emotionStrategy, rationalStrategy, isBasicMode) {
  31.     if (!isBasicMode) {
  32.         return `我是一名商家,需要回复消费者对自己商品的评价:${userMessage}`;
  33.     }
  34.     let emotionPrompt = '';
  35.     let rationalPrompt = '';
  36.     switch (emotionStrategy) {
  37.         case 'acknowledgement':
  38.             emotionPrompt = '请用一种理解客户情绪的方式进行回答';
  39.             break;
  40.         case 'informal':
  41.             emotionPrompt = '请用一种轻松、友好的语气与客户沟通';
  42.             break;
  43.         case 'attentiveness':
  44.             emotionPrompt = '请表示你会关注客户的问题,并尽力解决';
  45.             break;
  46.         case 'encouragement':
  47.             emotionPrompt = '请表达出你会改善的强烈意愿';
  48.             break;
  49.     }
  50.     switch (rationalStrategy) {
  51.         case 'explanation':
  52.             rationalPrompt = '请解释客户投诉的原因';
  53.             break;
  54.         case 'redress':
  55.             rationalPrompt = '请提供合适的补救措施来弥补';
  56.             break;
  57.         case 'facilitation':
  58.             rationalPrompt = '请提出改进措施';
  59.             break;
  60.     }
  61.     return `我是一名商家,需要回复消费者对自己商品的评价。${emotionPrompt}。${rationalPrompt}:${userMessage}`;
  62. }
  63. function getWenxinResponse(accessToken, userMessage, emotionStrategy, rationalStrategy, isBasicMode) {
  64.     const prompt = getPrompt(userMessage, emotionStrategy, rationalStrategy, isBasicMode);
  65.     return new Promise((resolve, reject) => {
  66.         fetch(`${serverUrl}/getWenxinResponse`, {
  67.             method: 'POST',
  68.             headers: {
  69.                 'Content-Type': 'application/json'
  70.             },
  71.             body: JSON.stringify({ accessToken, prompt })
  72.         })
  73.         .then(response => {
  74.             if (!response.ok) {
  75.                 throw new Error(`HTTP error! Status: ${response.status}`);
  76.             }
  77.             return response.json();
  78.         })
  79.         .then(data => {
  80.             if (data.result) {
  81.                 resolve(data.result);
  82.             } else {
  83.                 throw new Error('Failed to retrieve Wenxin response');
  84.             }
  85.         })
  86.         .catch(error => {
  87.             console.error('Error fetching Wenxin response:', error);
  88.             reject(error);
  89.         });
  90.     });
  91. }
  92. chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  93.     if (message.action === 'getWenxinResponse') {
  94.         getAccessToken()
  95.             .then(accessToken => getWenxinResponse(accessToken, message.content, message.emotionStrategy, message.rationalStrategy, message.isBasicMode))
  96.             .then(response => sendResponse(response))
  97.             .catch(error => sendResponse('Error: ' + error.message));
  98.         return true;  // Will respond asynchronously.
  99.     }
  100. });
复制代码

5.style.css
  1. body {
  2.     font-family: Arial, sans-serif;
  3.     background-color: #f7f7f7;
  4.     margin: 0;
  5.     padding: 0;
  6.     box-sizing: border-box;
  7. }
  8. .container {
  9.     padding: 20px;
  10.     max-width: 480px; /* 调整宽度 */
  11.     margin: auto;
  12.     background-color: #fff;
  13.     border-radius: 8px;
  14.     box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
  15. }
  16. .text-center {
  17.     font-size: 24px;
  18.     margin-bottom: 20px;
  19.     color: #333;
  20. }
  21. .form-control {
  22.     font-size: 16px;
  23.     padding: 10px;
  24.     border-radius: 4px;
  25.     border: 1px solid #ddd;
  26.     resize: none;
  27. }
  28. .btn-primary {
  29.     background-color: #4CAF50;
  30.     border-color: #4CAF50;
  31.     border-radius: 4px;
  32.     font-size: 16px;
  33.     transition: background-color 0.3s ease;
  34. }
  35. .btn-primary:hover {
  36.     background-color: #45a049;
  37. }
  38. .bg-light {
  39.     background-color: #f1f1f1;
  40.     border: 1px solid #ddd;
  41.     border-radius: 4px;
  42.     font-size: 14px;
  43.     white-space: pre-wrap;
  44. }
  45. .btn-outline-primary {
  46.     color: #007bff;
  47.     border-color: #007bff;
  48. }
  49. .btn-outline-primary:hover {
  50.     background-color: #007bff;
  51.     color: #ffffff;
  52. }
  53. .btn-check:checked + .btn-outline-primary {
  54.     background-color: #007bff;
  55.     border-color: #007bff;
  56.     color: #ffffff;
  57. }
  58. .btn-outline-success {
  59.     color: #28a745;
  60.     border-color: #28a745;
  61. }
  62. .btn-outline-success:hover {
  63.     background-color: #28a745;
  64.     color: #ffffff;
  65. }
  66. .btn-check:checked + .btn-outline-success {
  67.     background-color: #28a745;
  68.     border-color: #28a745;
  69.     color: #ffffff;
  70. }
复制代码
末了,大家需要在文件内里创建一个icons文件夹,如果不会调代码,请往内里存放命名为icon16、icon48、icon128的图片。
四、服务器部署

CORS(跨域资源共享)策略限制题目足足硬控了笔者一天,欣赏器会制止从插件的背景脚本直接发送跨域请求到第三方API。为相识决这个题目,笔者先通过修改background.js权限、利用CORS署理服务等方法进行实验,但都以失败告终。无奈之下,只好通过部署了一个本地服务器,在服务器上创建一个署理,将请求转发到百度API,从而解决CORS题目。
创建一个新python项目,命名为wenxin_proxy_pythonreply(举例)
创建一个名为server.py的文件
  1. from flask import Flask, request, jsonify
  2. from flask_cors import CORS
  3. import requests
  4. app = Flask(__name__)
  5. CORS(app)  # 启用CORS
  6. CLIENT_ID = '*****'  # 替换为你的API Key
  7. CLIENT_SECRET = '****'  # 替换为你的Secret Key
  8. @app.route('/getAccessToken', methods=['POST'])
  9. def get_access_token():
  10.     url = f"https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}"
  11.     headers = {
  12.         'Content-Type': 'application/json'
  13.     }
  14.     response = requests.post(url, headers=headers, json={})
  15.     if response.status_code == 200:
  16.         return jsonify(response.json())
  17.     else:
  18.         return jsonify({'error': 'Failed to retrieve access token'}), response.status_code
  19. @app.route('/getWenxinResponse', methods=['POST'])
  20. def get_wenxin_response():
  21.     data = request.get_json()
  22.     access_token = data['accessToken']
  23.     prompt = data['prompt']
  24.     url = f"https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/ernie-4.0-8k-0329?access_token={access_token}"
  25.     payload = {
  26.         "messages": [
  27.             {
  28.                 "role": "user",
  29.                 "content": prompt
  30.             }
  31.         ]
  32.     }
  33.     headers = {
  34.         'Content-Type': 'application/json'
  35.     }
  36.     response = requests.post(url, headers=headers, json=payload)
  37.     if response.status_code == 200:
  38.         return jsonify(response.json())
  39.     else:
  40.         return jsonify({'error': 'Failed to retrieve Wenxin response'}), response.status_code
  41. if __name__ == '__main__':
  42.     app.run(host='0.0.0.0', port=3000)
复制代码
复制后,在对应位置填入API Key和Secret Key,并在终端分别运行这两段代码
  1. pip install flask requests
复制代码
  1. pip install flask-cors
复制代码
然后运行server.py
如果没有报错,就将之前插件的文件夹在chrome://extensions/里打开,选择开辟者模式并点击“加载已解压的拓展步伐”。
末了,点击插件,输入内容,如果能够乐成运行,那么恭喜你大功告成。
五、总结

一款即插即用的多功能网页插件,能根据个人需求魔改成各种工具,欢迎大家交流学习!如有不解之处,请仔细阅读API调用文档https://cloud.baidu.com/doc/WENXINWORKSHOP/s/xlvlzz84k,或与我接洽,我将尽我所能。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

怀念夏天

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表