AI生成文章摘要

去年部署自己的博客后,后面看到很多博主的博客具有自动生成文章摘要的功能。后面网上找了一下,主要有本地和在线两种方式。

  • 本地:自己在 front-matter 中填写摘要,可以自己写,也可以找 AI 生成
  • 在线:通过 TianliGPT 生成摘要。须购买额度, ¥8.99 / 50000 字

之前购买过TianliGPT,但是由于一些原因不太适合自己的博客网站,所以一直想找一个比较合适的服务,我更想适用开源项目自己部署这样的服务,实现资源可控。

通义千问大模型有比较高(200 万 tokens,限时 180 天)的免费额度,适合我这种喜欢白嫖的。

注意:上面提到的 token 的计算方式和其他的不太一样:对于中文文本来说,1 个 token 通常对应一个汉字;对于英文文本来说,1 个 token 通常对应 3 至 4 个字母。

图片

封面图由阿里云的通义万相生成,提示语为“AI,技术,Python,生成,摘要,大模型,自动化”。

阿里云灵积模型服务及其使用

服务简介

阿里云的这款服务名为灵积(DashScope),标榜为“模型服务”。简单来说,就是通过 Python / Java 的 SDK,或者是 HTTP 请求,提供在线的大模型 AI 服务。

最大的亮点是:除了阿里自己的通义千问外,它还支持 LLaMa2、百川、Stable Diffusion、ChatGLM 等多种其他模型。

操作步骤也非常简单:

  1. 开通灵积服务
  2. 生成一个 key
  3. 通过 SDK 或 HTTP 请求,调用可选择的大模型

说实话,只要看官网的文档就能够解决几乎所有问题。

通过Java自动生成摘要

阿里云官方提供 Python 和 Java 的 SDK,并给出了调用的代码。这是与本文相关的代码示例。

需要添加环境变量,所谓改一下里面的内容,就可以了:

// Copyright (c) Alibaba, Inc. and its affiliates.

import com.alibaba.dashscope.aigc.conversation.Conversation;
import com.alibaba.dashscope.aigc.conversation.ConversationParam;
import com.alibaba.dashscope.aigc.conversation.ConversationResult;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.utils.JsonUtils;

public class Main {
   public static void quickStart() throws ApiException, NoApiKeyException {
       Conversation conversation = new Conversation();
       String prompt = "用萝卜、土豆、茄子做饭,给我个菜谱。";
       ConversationParam param = ConversationParam
      .builder()
      .model(Conversation.Models.QWEN_TURBO)
      .prompt(prompt)
      .build();
       ConversationResult result = conversation.call(param);
       System.out.println(JsonUtils.toJson(result));
  }
   public static void main(String[] args) {
       try {
           quickStart();
      } catch (ApiException | NoApiKeyException e) {
           System.out.println(e.getMessage());
      }
       System.exit(0);
  }
}

返回的 JSON 内容形如:

{"requestId":"7a21407f-9f16-9ba0-a91b-df0bdd1cc5bb","usage":{"input_tokens":25,"output_tokens":321},"output":{"text":"好的,以下是一道简单易做的蔬菜炒饭的菜谱:\n\n材料:\n- 2 个白萝卜,削皮并切成小丁\n- 1 个土豆,削皮并切成小丁\n- 2 个茄子,削皮并切成小丁\n- 1 杯米饭\n- 2 个青椒,切成小丁\n- 1 个红椒,切成小丁\n- 2 汤匙酱油\n- 1 汤匙油\n- 盐和黑胡椒适量\n\n做法:\n1. 在锅中加入 2 汤匙油,加热至中高温。\n2. 加入白萝卜丁和土豆丁,翻炒至软化并略微焦黄。\n3. 加入茄子丁,继续翻炒至软化。\n4. 加入米饭,翻炒均匀,让米粒散开。\n5. 加入青椒丁和红椒丁,继续翻炒约2-3分钟,直到蔬菜变软和略微焦黄。\n6. 加入酱油,盐和黑胡椒,再翻炒均匀,使所有材料均匀地涂上酱油和调料。\n7. 把炒饭盛到碗里,配上一碗清汤或者鱼汤,即可开始享用。","finish_reason":"stop"}}

处理报错

在测试的时候,我突然发现,有一些文章无法通过通义千问生成 AI 摘要,报错信息如下:

Request id: xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, Status code: 400, error code: DataInspectionFailed, error message: Input data may contain inappropriate content.

文档对此的解释为:

数据检查错误,输入或者输出包含疑似敏感内容被绿网拦截

一个非常正常的内容都这样,难怪国内的大语言模型发展不起来。

不过现在要处理这个问题。原先的代码我基本上没怎么动,就是添加了返回值,以及日志、报错信息:

// Copyright (c) Alibaba, Inc. and its affiliates.

import com.alibaba.dashscope.aigc.conversation.Conversation;
import com.alibaba.dashscope.aigc.conversation.ConversationParam;
import com.alibaba.dashscope.aigc.conversation.ConversationResult;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import io.reactivex.Flowable;
import com.alibaba.dashscope.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Main {
   public static void testStreamCall() throws ApiException, NoApiKeyException {
       Conversation conversation = new Conversation();
       String prompt = "用萝卜、土豆、茄子做饭,给我个菜谱。";
       ConversationParam param = ConversationParam
      .builder()
      .model(Conversation.Models.QWEN_TURBO)
      .prompt(prompt)
      .build();
       try{
           Flowable<ConversationResult> result = conversation.streamCall(param);
           result.blockingForEach(msg->{
               System.out.print(msg.output)
               Syst;
          });
      }catch(ApiException ex){
           System.out.println(ex.getMessage());
      }
  }
   public static void main(String[] args){
       try {
           testStreamCall();
      } catch (ApiException | NoApiKeyException e) {
           System.out.println(e.getMessage());
      }
       System.exit(0);
  }
}

上面的代码中,对于无法获取 AI 摘要的情况,我会添加一个Type字段,以便后期检查。

读取文章内容后,首先检查是否已经写入 ai 字段 或 Type 字段,如果没有才会把文本发给阿里云那边处理,以节省成本。

中英文之间加空格

我发现,很多情况下,通义千问生成的摘要中,中英文之间未加空格。这不符合我的文章风格。

解决方法也很简单,使用正则表达式

Pattern pattern = Pattern.compile("([\\u4e00-\\u9fa5]+)([a-zA-Z])|([a-zA-Z])([\\u4e00-\\u9fa5]+)");  
       Matcher matcher = pattern.matcher(text);  
 
       StringBuffer sb = new StringBuffer();  
       while (matcher.find()) {  
           matcher.appendReplacement(sb, matcher.group(1) + " " + matcher.group(2) + " " + matcher.group(3) + " " + matcher.group(4));  
      }  
       matcher.appendTail(sb);  
 
       String result = sb.toString().trim().replaceAll(" +", " "); // 移除多余的空格,确保只有一个空格  
       System.out.println(result);  

整体代码

整体的代码如下:

public class AbstractArticle {
   
       public static String testStreamCall() throws ApiException, NoApiKeyException {
           Conversation conversation = new Conversation();
           String prompt = "用萝卜、土豆、茄子做饭,给我个菜谱。";
           ConversationParam param = ConversationParam
                  .builder()
                  .model(Conversation.Models.QWEN_TURBO)
                  .prompt(prompt).apiKey("申请的key")
                  .build();
           ConversationResult result = null;
           try {
               result = conversation.call(param);
          } catch (InputRequiredException e) {
               e.printStackTrace();
          }
           System.out.println(result.getOutput().getText());
           return result.getOutput().getText();

      }
       public static String replaceText(String conTent){
           Pattern pattern = Pattern.compile("([\\u4e00-\\u9fa5]+)([a-zA-Z])|([a-zA-Z])([\\u4e00-\\u9fa5]+)");
           Matcher matcher = pattern.matcher(conTent);

           StringBuffer sb = new StringBuffer();
           while (matcher.find()) {
               matcher.appendReplacement(sb, matcher.group(1) + " " + matcher.group(2) + " " + matcher.group(3) + " " + matcher.group(4));
          }
           matcher.appendTail(sb);

           String result = sb.toString().trim().replaceAll(" +", " "); // 移除多余的空格,确保只有一个空格  
           return result;
      }
       
       public static void main(String[] args){
           try {
               String s = replaceText(testStreamCall());
          } catch (ApiException | NoApiKeyException e) {
               System.out.println(e.getMessage());
          }
           System.exit(0);
      }
}

执行情况

好的,以下是一道用萝卜、土豆、茄子做的家常菜谱,希望您喜欢。
【土豆茄子炖萝卜】
材料:
萝卜(切片)、土豆(切块)、茄子(切块)、大葱(切断)、生姜(切片)、蒜(切片)、干辣椒(剪成小段)、生抽(适量)、老抽(适量)、料酒(适量)、盐(适量)、鸡精(适量)

做法:
1. 热锅凉油,油热后下入干辣椒、葱、姜、蒜炒香。
2. 下入萝卜和土豆翻炒一下。
3. 加入适量的生抽和老抽,继续翻炒。
4. 加入适量的料酒,可以去腥提味。
5. 加入适量的水,没过菜的量即可。
6. 最后加入茄子,炖煮10分钟左右。
7. 出锅前加入适量的盐和鸡精即可。
8. 盛出后撒上少许葱花点缀。

这道菜的特点是色彩丰富、味道浓郁。萝卜、土豆、茄子的搭配不仅营养丰富,而且口感也很好。喜欢的话可以自己在家试试看,希望您能喜欢。

执行效果

对于成功的文章——尤其是技术类的文章——来说,生成的效果还是不错的。

但还是要检查摘要是否正确。比如这篇文章,生成的摘要如下:

这篇文章主要介绍了 Unicode 中的数学字母数字符号,这些字符可以用于数学公式中。虽然 Unicode 支持这些字符,但并不是所有字体都支持它们,且不同的软件和设备可能显示不同。作者还分享了如何在电脑和手机上查看这些字符的全部字形。

但是“作者还分享了如何在电脑和手机上查看这些字符的全部字形。”并非我的意思。我只是在文末列出了全部的 Unicode 中的数学字母数字符号。

而对于诗歌,准确性就差了。比如这篇文章,生成的摘要如下:

这篇文章讲述了作者在高三时,听到了 July 的 In The Wind 这首歌,被深深打动,于是花了半天的时间为这首歌填词。歌词表达了作者想要丢弃过去的回忆和痛苦,继续前行的决心。

最后一句属实是过分解读了,我只是填词而已。

小说呢?这篇文章,生成的摘要如下:

文章讲述了作者在家乡的一片原野上玩耍的经历,包括春天的花朵、夏天的草地、秋天的星空和冬天的烟花。作者曾经试图骑自行车穿越那片原野,但发现了一堵高高的墙,他试图越过这堵墙,但没有成功。后来,他在地道中发现了一个美丽的世外桃源,但因为学习压力大,无法再去。最后,作者发现了一片湖,但湖边又出现了一堵更远的墙,他无法到达那片世外桃源。作者希望那堵墙能够消失,这样他就能再次去那片美丽的地方。

“但湖边又出现了一堵更远的墙”完全无法表达文章内容。原文的意思是,在原先的墙之前,又新建了一堵墙,把湖挡住了。

总结

总之,如果不考虑经常被拦截的情况,还是可以用的。

但是问题就在于,输入内容经常被误拦截。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值