妖火帖子AI总结(太长不看)

调用OpenAI或其他支持completions功能API对妖火论坛帖子内容及评论进行摘要总结,并提供回帖建议

  1. // ==UserScript==
  2. // @name 妖火帖子AI总结(太长不看)
  3. // @namespace https://www.yaohuo.me/bbs/userinfo.aspx?touserid=20740
  4. // @version 1.9.99
  5. // @description 调用OpenAI或其他支持completions功能API对妖火论坛帖子内容及评论进行摘要总结,并提供回帖建议
  6. // @author SiXi
  7. // @match https://www.yaohuo.me/bbs*
  8. // @match https://yaohuo.me/bbs*
  9. // @grant GM_xmlhttpRequest
  10. // @grant GM_addStyle
  11. // @icon https://www.yaohuo.me/css/favicon.ico
  12. // @license Apache 2
  13. // @require https://code.jquery.com/jquery-3.6.0.min.js
  14. // ==/UserScript==
  15.  
  16. (function() {
  17. 'use strict';
  18.  
  19. // 用户配置参数
  20. const OPENAI_BASE_URL = 'https://api.gptgod.online/v1/chat/completions'; //模型的base_url,需要使用支持completions功能的url
  21. const OPENAI_API_KEY = 'sk-XXXXXXXXXXXX'; //密钥
  22. const OPENAI_MODEL = 'glm-4-flash'; //模型名称,火山方舟申请的模型是填'推理接入点'名称,ep开头那个
  23.  
  24. // 创建按钮并插入页面
  25. $(document).ready(function() {
  26. $('.Postinfo .Postime').each(function() {
  27. const postInfo = $(this).closest('.Postinfo');
  28. const button = $('<button class="ai-summary-btn">AI总结</button>')
  29. .css({
  30. 'padding': '5px 10px',
  31. 'background-color': '#4CAF50',
  32. 'color': 'white',
  33. 'border': 'none',
  34. 'border-radius': '5px',
  35. 'cursor': 'pointer'
  36. })
  37. .insertAfter(postInfo.find('.Postime'))
  38. .on('click', function() {
  39. handleButtonClick($(this), postInfo);
  40. });
  41. });
  42. });
  43.  
  44. // 获取评论内容
  45. function getComments() {
  46. const comments = [];
  47. $('.recontent .retext').each(function() {
  48. const commentText = $(this).text().trim();
  49. if (commentText && !$(this).closest('.quoted-content').length) {
  50. comments.push(commentText);
  51. }
  52. });
  53. return comments;
  54. }
  55.  
  56. // 处理按钮点击事件
  57. function handleButtonClick(button, postInfo) {
  58. button.prop('disabled', true).text('AI阅读中...');
  59.  
  60. const title = postInfo.find('.biaotiwenzi').text().trim();
  61. if (!title) {
  62. alert("未找到帖子标题!");
  63. button.prop('disabled', false).text('AI总结');
  64. return;
  65. }
  66.  
  67. const content = postInfo.closest('.content').find('.bbscontent').text().trim();
  68. if (!content) {
  69. alert("未找到帖子内容!");
  70. button.prop('disabled', false).text('AI总结');
  71. return;
  72. }
  73.  
  74. const comments = getComments();
  75.  
  76. const fullContent = `帖子标题:${title}\n\n原帖内容:\n${content}\n\n评论区内容:\n\n${comments.map((comment, index) => `${index + 1}. ${comment}`).join('\n')}`;
  77.  
  78. fetchSummaryAndReplies(fullContent, button);
  79. }
  80.  
  81. function fetchSummaryAndReplies(content, button) {
  82. GM_xmlhttpRequest({
  83. method: 'POST',
  84. url: `${OPENAI_BASE_URL}`,
  85. headers: {
  86. 'Authorization': `Bearer ${OPENAI_API_KEY}`,
  87. 'Content-Type': 'application/json'
  88. },
  89. data: JSON.stringify({
  90. model: OPENAI_MODEL,
  91. messages: [
  92. {
  93. role: "system",
  94. content: "你是妖火网论坛的用户。请分别总结原帖内容和评论区的主要观点。原帖内容用1-3句话总结,评论区的观点用1-2句话总结。总结内容用'原帖内容'和'妖友观点'前缀进行回复。同时,请根据原帖内容和评论区的讨论,生成5条适合的回帖内容,尽可能贴近评论区的观点,模仿他们的语气,使用口语化,用'回帖内容'前缀进行回复。"
  95. },
  96. {
  97. role: "user",
  98. content: `请总结:\n\n${content}`
  99. }
  100. ],
  101. stream: false
  102. }),
  103. onload: function(response) {
  104. try {
  105. const result = JSON.parse(response.responseText);
  106. let summary = result.choices[0].message.content.trim();
  107. summary = summary.replace("妖友观点:", "<hr>妖友观点:");
  108.  
  109. // 回帖内容解析
  110. let replies = [];
  111.  
  112. const pattern1 = /回帖内容:\s*((?:\d+\.\s*[^\n]+\n*)+)/;
  113. const match1 = summary.match(pattern1);
  114.  
  115. if (match1) {
  116. replies = match1[1].split(/\d+\./).filter(reply => reply.trim());
  117. } else {
  118. replies = summary.match(/回帖内容\d+:[^\n]+/g);
  119. if (replies) {
  120. replies = replies.map(reply => reply.replace(/回帖内容\d+:/, '').trim());
  121. }
  122. }
  123.  
  124. const summaryParts = summary.split(/回帖内容[:\d]/)[0].trim();
  125. const subtitleElement = $('<div class="subtitle content welcome"></div>');
  126. subtitleElement.html(summaryParts);
  127. $('.Postinfo').after(subtitleElement);
  128.  
  129. // 显示回帖建议
  130. if (replies && replies.length > 0) {
  131. showReplySuggestions(replies);
  132. }
  133.  
  134. button.prop('disabled', false).text('AI总结');
  135. } catch (error) {
  136. console.error("解析AI响应失败:", error);
  137. showErrorPopup("请求失败,请稍后再试。");
  138. button.prop('disabled', false).text('AI总结');
  139. }
  140. },
  141. onerror: function(error) {
  142. console.error("请求失败:", error);
  143. showErrorPopup("网络请求失败,请检查您的网络连接。");
  144. button.prop('disabled', false).text('AI总结');
  145. }
  146. });
  147. }
  148.  
  149. // 显示回帖建议
  150. function showReplySuggestions(replies) {
  151. // 首先移除旧的建议(如果存在)
  152. $('.reply-suggestions-container').remove();
  153.  
  154. const replyContainer = $('<div class="content"></div>')
  155. .insertAfter('.kuaisuhuifu');
  156.  
  157. replies.forEach(reply => {
  158. const replySpan = $('<div class="reply-suggestion"></div>')
  159. .css({
  160. 'padding': '1px 1px 1px 7px',
  161. 'margin': '5px 0',
  162. 'background-color': '#f5f5f5',
  163. 'border-radius': '4px',
  164. 'cursor': 'pointer',
  165. 'transition': 'background-color 0.2s'
  166. })
  167. .hover(
  168. function() { $(this).css('background-color', '#e0e0e0'); },
  169. function() { $(this).css('background-color', '#f5f5f5'); }
  170. )
  171. .text(reply.trim())
  172. .on('click', function() {
  173. $('.retextarea').val($(this).text());
  174. })
  175. .appendTo(replyContainer);
  176. });
  177. }
  178.  
  179. // 显示错误提示浮窗
  180. function showErrorPopup(message) {
  181. const popup = $('<div class="ai-error-popup"></div>')
  182. .css({
  183. 'position': 'fixed',
  184. 'top': '50%',
  185. 'left': '50%',
  186. 'transform': 'translate(-50%, -50%)',
  187. 'background-color': 'rgba(255,0,0,0.7)',
  188. 'color': 'white',
  189. 'padding': '20px',
  190. 'border-radius': '10px',
  191. 'z-index': '10000'
  192. })
  193. .html(`<p>${message}</p><button class="ai-error-close-btn">X</button>`)
  194. .appendTo('body');
  195.  
  196. popup.find('.ai-error-close-btn').on('click', function() {
  197. popup.remove();
  198. });
  199. }
  200. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址