V2EX-Comments-Summarizer

V2EX 评论区总结

当前为 2023-07-11 提交的版本,查看 最新版本

// ==UserScript==
// @name         V2EX-Comments-Summarizer
// @namespace    https://github.com/banbri
// @version      1.0
// @description  V2EX 评论区总结
// @author       Banbri
// @match        https://www.v2ex.com/t/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=v2ex.com
// @license      GPL-2.0-only
// ==/UserScript==

const rightbar = document.getElementById('Rightbar')

const box = document.createElement('div')
box.className = 'box'
box.style.minHeight = '200px'
box.style.padding = '10px'
box.style.overflowX = 'hidden'
rightbar.appendChild(box)

// 向 box 中添加一个 title 为 '评论区总结',并且添加样式
const title = document.createElement('div')
title.innerText = '评论区总结:'
title.style.textAlign = 'left'
title.style.fontWeight = 'bold'
box.appendChild(title)

// 再新建一个 div,用于存放评论区总结的内容
const contentDiv = document.createElement('div')
contentDiv.className = 'reply_content'
contentDiv.style.textAlign = 'left'
box.appendChild(contentDiv)

// 获取到所有的评论
const comments = document.querySelectorAll('.reply_content')
let contentText = 'Generating...'
for (let i = 0; i < comments.length; i++) {
  contentText += comments[i].innerText
}

// 如果评论内容低于 200 个字符,就不进行总结
if (contentText.length < 200) {
  contentDiv.innerText = '评论内容太少,不进行总结。'
} else {
  if (contentText.length > 2000) {
    contentText = contentText.substring(0, 2000)
  }
  getSummary()
}

async function getSummary() {
  const param = {
    model: 'gpt-3.5-turbo',
    temperature: 1,
    top_p: 0.9,
    frequency_penalty: 0,
    presence_penalty: 0,
    stop: '',
    messages: [
      { role: 'assistant', content: contentText },
      {
        role: 'user',
        content: '这是一个帖子的评论区,请总结一下,仅回复总结内容。',
      },
    ],
    stream: true,
  }
  const response = await fetch('https://thread-sum.com/v1/chat/completions', {
    method: 'POST',
    body: JSON.stringify(param),
  })
  const reader = response.body.getReader()
  const decoder = new TextDecoder('utf-8')
  contentText.innerText = ''
  let text = ''
  while (true) {
    const { done, value } = await reader.read()
    if (done) {
      break
    }
    // Massage and parse the chunk of data
    const chunk = decoder.decode(value, { stream: true })
    const dataStrList = chunk.split('\n\n')
    // eslint-disable-next-line
    dataStrList.forEach((dataStr) => {
      const dataJson = dataStr.replace(/^data:/, '').trim()
      try {
        const data = JSON.parse(dataJson)
        const content = data?.choices[0]?.delta?.content
        if (!content) return
        text += content
        contentDiv.innerText = text
      } catch (e) {}
    })
  }
}

QingJ © 2025

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