?????? 大學開學了,博主的堂弟現(xiàn)在正值大四,論文是分毫未動,想要用國內網上的AI輔助寫作擬一篇文章進行完成,剛好聊天了解此事,我有點感興趣,去百度了一下,各個AI生成網站價格不菲,臨時起意想做一個AI代碼生成程序,當然這種生成的論文問題還是特別多,無法和成熟的軟件相比不過勝在成本低,可塑性強。
前置條件
????????首先我們需要對接現(xiàn)有大模型的接口,國內的各個大模型都有自己的商場,GPT-4在理解和生成自然語言方面比國內的模型在具有更強的能力,因此作者嫌麻煩花了10米去搞了個國內的中轉接口去調用GPT-4的api,否則你就需要魔法上網,去弄openAI的接口了。
代碼實現(xiàn)
????????首先簡單講解一下AI對話的原理,首先要了解tokens,引用一句AI的解釋:
????????在AI和機器學習的上下文中,"tokens" 通常是指文本數(shù)據(jù)被預處理后得到的基本單位。這些單位可以是單詞、子詞(subwords)、字符或更復雜的結構,取決于你選擇的分詞方法。Tokenization是自然語言處理中的一個重要步驟,它有助于將文本轉換為機器學習模型可以理解和處理的形式。
????????簡單來說就是你發(fā)送的消息和AI返回給你的內容都與tokens有關,字符越多,tokens越大,一般來說400個漢字,相當于1000tokens
??????? 而對話簡單來講就是你請求的時候會攜帶上文AI的回答或者你的塑造的上下文進行調用,如果不加限制就很容易消耗特別多的tokens,有些網站都是將次數(shù)限制到10條可能就是這個原因。
??????? 論文這個東西文本實在太多,使用我直接不考慮帶上文,這里是我的創(chuàng)建對話的代碼實現(xiàn):
private ChatResponseWrapper createChat(String message, String model) {
try {
if (!chatConfig.isEnable()) {
log.warn("createChat fail,ai is unable!");
throw new AIExecuteException("check ai is enable!");
}
List<ChatMessagesDto> messages = new ArrayList<>();
ChatMessagesDto systemMessage = new ChatMessagesDto(role, message);
messages.add(systemMessage);
//model 代表gpt當前的模型,我開發(fā)時使用的是3.5,role代表當前的角色
ChatRequest chatCompletionRequest = ChatRequest.builder().model(model).messages(messages).user(role).maxTokens(4096).temperature(BigDecimal.ONE).build();
ObjectMapper objectMapper = new ObjectMapper();
//對接大模型的url
HttpRequest request = HttpUtil.createPost(chatConfig.getUrl());
request.setConnectionTimeout(TIMEOUT);
request.body(objectMapper.writeValueAsBytes(chatCompletionRequest));
// 設置請求頭
request.header("Content-Type", "application/json");
//攜帶token
request.header("Authorization", "Bearer " + chatConfig.getAccessKey());
String body;
try (HttpResponse response = request.execute()) {
body = response.body();
}
if (log.isDebugEnabled()) {
log.debug("get Ai response body:{}", body);
}
ChatResponseWrapper wrapper = new ChatResponseWrapper();
wrapper.setResponse(objectMapper.readValue(body, ChatResponse.class));
wrapper.setQuestion(message);
return wrapper;
} catch (JsonProcessingException e) {
log.error("Json Parse error,message:{}", message, e);
throw new AIExecuteException(e.getMessage());
} catch (Exception e) {
log.error("createChat error,message:{}", message, e);
throw new AIExecuteException(e.getMessage());
}
}
??????? 接下來創(chuàng)建生成大綱的接口,入參是標題,也就是前端傳入的值
public List<ThesisOutline> genThesisOutline(String message) {
try {
String template = "以《{}》為題目,給我一篇計算類論文的大綱,使用中文回答,一級目錄使用編號1,二級目錄使用編號1.1,以此類推";
//對ai的問句
String askQuestion = StringUtil.format(template, message);
ChatResponseWrapper wrapper = aiClient.createChat35(askQuestion);
ChatResponse response = wrapper.getResponse();
if (response == null) {
throw new AIExecuteException();
}
List<ThesisOutline> thesisOutlines = new ArrayList<>();
for (ChatChoice choice : response.getChoices()) {
ChatMessagesDto choiceMessage = choice.getMessage();
String content = choiceMessage.getContent();
if (StringUtil.isEmpty(content)) {
continue;
}
//過濾為空的行和不為數(shù)字的行
List<String> outlines = StringUtil.split(content, "\n").stream().filter(StringUtil::isNotBlank).filter(StringUtil::isStartsWithDigit).map(String::trim).collect(Collectors.toList());
for (String outlineContent : outlines) {
ThesisOutline outline = new ThesisOutline();
outline.setContent(outlineContent);
thesisOutlines.add(outline);
}
}
return thesisOutlines;
} catch (Exception e) {
log.error("genThesisOutline error", e);
return Collections.emptyList();
}
}
/**
* 論文標題實體
* @author zwh
*/
@Data
public class ThesisOutline {
/**
* 層級
*/
private Integer level;
/**
* 標題內容
*/
private String content;
}
這個接口將生成的數(shù)據(jù)返回給前端
隨手寫的前端,樣式什么的也懶的調了,能用就行,代碼如下:
<template>
<div class="app-container home">
<el-card style="height: 95vh">
<el-button @click="genThesisOutline" :disabled="showText">生成論文大綱</el-button>
<el-button @click="toText" v-if="!showText">變更為文本</el-button>
<el-button @click="toList" v-if="showText">保存并展示為列表</el-button>
<el-button @click="downloadByOutline" icon="el-icon-download" v-if="!showText">生成并下載論文</el-button>
<div style="margin-top: 20px">
<div v-show="!showText">
<el-row style="margin-bottom: 10px">
<el-col :span="4">標題</el-col>
<el-col :span="20">{{ thesis.title }}</el-col>
</el-row>
<el-table ref="table" :data="outlineData" max-height="1100px">
<el-table-column type="index" width="100"/>
<el-table-column label="大綱內容" prop="content"/>
</el-table>
</div>
<el-form v-show="showText">
<el-form-item label="標題">
<el-input v-model="thesis.title"/>
</el-form-item>
<el-form-item label="大綱">
<el-input type="textarea" v-model="outlineText" rows="45"/>
</el-form-item>
</el-form>
</div>
</el-card>
<el-dialog title="生成論文大綱" :visible.sync="outline.visible">
<el-form>
<el-form-item label="論文題目">
<el-input v-model="outline.content"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="outline.visible = false">取 消</el-button>
<el-button type="primary" @click="genOutline">確認生成大綱</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {downloadWord, genOutline} from "@/api";
export default {
name: "Index",
data() {
return {
outline: {
visible: false,
content: null,
},
outlineData: [],
thesis: {
title: null,
messages: []
},
outlineText: null,
showText: false,
};
},
methods: {
genThesisOutline() {
this.outline.visible = true;
},
genOutline() {
genOutline(this.outline.content).then(resp => {
this.outlineData = resp.data
this.thesis.title = this.outline.content
this.outline.content = null
this.outline.visible = false
})
},
toText() {
const fieldValues = this.outlineData.map(obj => obj.content);
this.outlineText = fieldValues.join('\n');
this.showText = true;
},
toList() {
// 使用 split 方法按換行符分割字符串
const lines = this.outlineText.split('\n');
// 過濾掉空字符串,并將每個字符串轉化回對象
// 將每行轉化為一個對象,該對象具有指定的字段名和內容
this.outlineData = lines
.filter(line => line.trim() !== '')
.map(line => ({content: line}));
this.showText = false;
},
downloadByOutline() {
this.thesis.messages = this.outlineData.map(obj => obj.content);
downloadWord(this.thesis).then(resp => {
// 創(chuàng)建一個blob對象URL
const url = window.URL.createObjectURL(new Blob([resp]));
// 創(chuàng)建一個下載鏈接元素
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', this.thesis.title+'.docx'); // 設置下載文件名
// 觸發(fā)下載
document.body.appendChild(link);
link.click();
// 清理
window.URL.revokeObjectURL(url);
})
}
},
};
</script>
正文生成,因為是要對大綱的內容進行循環(huán)的請求,使用需要異步請求chatgpt,因為每一個論點請求花費的時間都十分之長,計算了一下一個論點大約30s左右,所以我們這里需要異步去請求論文返回的結果,我這里是使用CompletableFuture去異步請求,方法通過異步方式與AI交互,生成論文文本,并將結果導出為Word文檔供用戶下載。
@Override
public void genThesisText(List<String> messages, String title, HttpServletResponse resp) {
try {
String template = "請繼續(xù)以{}為題生成關于:{}的內容,內容需要在500字以上";
List<CompletableFuture<ThesisTextModel>> futures = new ArrayList<>(messages.size());
// 每個標題異步創(chuàng)建會話
for (String message : messages) {
String question = StringUtil.format(template, title, message);
CompletableFuture<ThesisTextModel> future = CompletableFuture.supplyAsync(() -> ThesisTextModel.builder().wrapper(aiClient.createChat35(question)).message(message).build(), executor).exceptionally(e -> {
log.error("createChat sync execute error", e);
return null;
});
futures.add(future);
}
// 獲取所有消息內容 (key: 問題, value: 回答)
Map<String, List<String>> allContent = new LinkedHashMap<>();
for (CompletableFuture<ThesisTextModel> future : futures) {
ThesisTextModel model = future.get();
ChatResponse response = model.getWrapper().getResponse();
List<ChatChoice> choices = response.getChoices();
String outline = model.getMessage();
ArrayList<String> perContent = new ArrayList<>();
for (ChatChoice choice : choices) {
ChatMessagesDto choiceMessage = choice.getMessage();
// 獲取某個標題的回答內容
String content = choiceMessage.getContent().replaceAll("\n+", "\n");
if (StringUtil.isEmpty(content)) {
continue;
}
perContent.add(content);
}
allContent.put(outline, perContent);
}
// 生成 word 文檔
ThesisBuildHelper.exportWordDocument(resp, allContent);
} catch (Exception e) {
log.error("genThesisText error", e);
}
}
調用ThesisBuildHelper設置好相應的格式,這里貼上我大學時使用的論文格式(ps.還是從吃灰的老電腦里翻到的)
總結
經過兩天的努力,到現(xiàn)在程序已經能夠生成結構清晰、內容豐富的論文。同時,通過導出為Word文檔的形式,使得我能夠方便地查看和編輯生成的論文。
這樣生成的論文成本也特別的低,我開發(fā)中使用的是gpt3.5,大概2w字的論文花費就2毛左右,可想而知百度到的論文生成網站里面利潤之高,其實我還想了將gpt3.5生成的文章交給gpt4潤色,加入參考文獻,不過嫌麻煩,也沒有好的思路,就懶得做了,說到底也是心血來潮。
最后,附以一張我畢業(yè)的論題生成的論文,27頁字數(shù)23184,雖然不是標準的論文,但是再也不需要去冥思苦想論文該咋寫了。文章來源:http://www.zghlxwxcb.cn/news/detail-844816.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-844816.html
到了這里,關于AI論文生成系統(tǒng)JAVA代碼簡單實現(xiàn)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!