Skip to content

Commit

Permalink
feat: AI集成-支持生成标题和生成摘要
Browse files Browse the repository at this point in the history
  • Loading branch information
terwer committed Aug 23, 2023
1 parent c701ce6 commit 2e48ca5
Show file tree
Hide file tree
Showing 7 changed files with 257 additions and 25 deletions.
4 changes: 2 additions & 2 deletions src/components/publish/BatchPublishIndex.vue
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ const handleRefresh = () => {
BrowserUtil.reloadPage()
}
const chckedChatGPTEnabled = () => {
const checkChatGPTEnabled = () => {
let flag = false
try {
useChatGPT()
Expand All @@ -321,7 +321,7 @@ onMounted(async () => {
// ==================
// 这里可以控制一些功能开关
formData.useAi = chckedChatGPTEnabled()
formData.useAi = checkChatGPTEnabled()
formData.editType = PageEditMode.EditMode_simple
})
</script>
Expand Down
9 changes: 5 additions & 4 deletions src/components/publish/SinglePublishDoPublish.vue
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ const initPage = async () => {
}
}
const chckedChatGPTEnabled = () => {
const checkChatGPTEnabled = () => {
let flag = false
try {
useChatGPT()
Expand Down Expand Up @@ -402,7 +402,7 @@ onMounted(async () => {
// ==================
// 这里可以控制一些功能开关
formData.useAi = chckedChatGPTEnabled()
formData.useAi = checkChatGPTEnabled()
formData.editType = PageEditMode.EditMode_simple
})
</script>
Expand Down Expand Up @@ -445,9 +445,9 @@ onMounted(async () => {
<publish-title
v-model:use-ai="formData.useAi"
v-model="formData.mergedPost.title"
@emitSyncPublishTitle="syncPublishTitle"
v-model:md="formData.mergedPost.markdown"
v-model:html="formData.mergedPost.html"
@emitSyncPublishTitle="syncPublishTitle"
/>

<!-- 知识空间 -->
Expand Down Expand Up @@ -478,7 +478,8 @@ onMounted(async () => {
v-model:use-ai="formData.useAi"
v-model:page-id="id"
v-model:desc="formData.mergedPost.shortDesc"
v-model:content="formData.mergedPost.html"
v-model:md="formData.mergedPost.markdown"
v-model:html="formData.mergedPost.html"
@emitSyncDesc="syncDesc"
/>

Expand Down
50 changes: 37 additions & 13 deletions src/components/publish/form/PublishDescription.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ import { useVueI18n } from "~/src/composables/useVueI18n.ts"
import { reactive, watch } from "vue"
import { createAppLogger } from "~/src/utils/appLogger.ts"
import { ElMessage } from "element-plus"
import { HtmlUtil, SmartUtil, StrUtil } from "zhi-common"
import { HtmlUtil, JsonUtil, SmartUtil, StrUtil } from "zhi-common"
import { prompt, ShortDescAIResult } from "~/src/utils/ai/prompt.ts"
import { useChatGPT } from "~/src/composables/useChatGPT.ts"
const logger = createAppLogger("publish-description")
const { t } = useVueI18n()
Expand Down Expand Up @@ -74,33 +76,55 @@ watch(
}
)
watch(
() => props.md,
(newValue) => {
formData.md = newValue
}
)
const emit = defineEmits(["emitSyncDesc"])
const handleMakeDesc = async () => {
logger.debug("准备生成摘要...")
formData.isDescLoading = true
try {
if (formData.useAi) {
if (StrUtil.isEmptyString(formData.html)) {
throw new Error("正文为空,无法生成摘要")
}
logger.debug("使用人工智能提取摘要", { q: formData.html })
const result = await SmartUtil.autoSummary(formData.html)
logger.debug("auto summary reault =>", result)
if (!StrUtil.isEmptyString(result.errMsg)) {
throw new Error(result.errMsg)
} else {
formData.desc = result.result
const inputWord = `${formData.md}\n${prompt.shortDescPrompt.content}`
const { chat } = useChatGPT()
const chatText = await chat(inputWord)
if (StrUtil.isEmptyString(chatText)) {
ElMessage.error("请求错误,请在偏好设置配置请求地址和ChatGPT key!")
return
}
ElMessage.warning("使用人工智能提取摘要成功")
const resJson = JsonUtil.safeParse<ShortDescAIResult>(chatText, {} as ShortDescAIResult)
formData.desc = resJson.desc
logger.info("使用AI智能生成的摘要结果 =>", {
inputWord: inputWord,
chatText: chatText,
})
// 自部署无监督摘要
// if (StrUtil.isEmptyString(formData.html)) {
// throw new Error("正文为空,无法生成摘要")
// }
// logger.debug("使用人工智能提取摘要", { q: formData.html })
// const result = await SmartUtil.autoSummary(formData.html)
// logger.debug("auto summary reault =>", result)
// if (!StrUtil.isEmptyString(result.errMsg)) {
// throw new Error(result.errMsg)
// } else {
// formData.desc = result.result
// }
ElMessage.success("使用人工智能提取摘要成功")
} else {
formData.desc = HtmlUtil.parseHtml(formData.html, MAX_PREVIEW_LENGTH, true)
ElMessage.success(`操作成功,未开启人工智能,直接截取文章前${MAX_PREVIEW_LENGTH}个字符作为摘要`)
}
// ElMessage.success(t("main.opt.success"))
} catch (e) {
logger.error(t("main.opt.failure") + "=>", e)
ElMessage.error(t("main.opt.failure") + "=>"+ e)
ElMessage.error(t("main.opt.failure") + "=>" + e)
}
formData.isDescLoading = false
Expand Down
49 changes: 47 additions & 2 deletions src/components/publish/form/PublishTitle.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,13 @@
import { reactive } from "vue"
import { useVueI18n } from "~/src/composables/useVueI18n.ts"
import { watch } from "vue"
import { JsonUtil, StrUtil } from "zhi-common"
import { ElMessage } from "element-plus"
import { useChatGPT } from "~/src/composables/useChatGPT.ts"
import { createAppLogger } from "~/src/utils/appLogger.ts"
import { prompt, TitleAIResult } from "~/src/utils/ai/prompt.ts"
const logger = createAppLogger("publish-title")
const { t } = useVueI18n()
const props = defineProps({
Expand All @@ -49,11 +55,12 @@ const props = defineProps({
},
})
const TITLE_AI_PROPMTS = ""
const formData = reactive({
postTitle: props.modelValue,
isLoading: false,
useAi: props.useAi,
md: props.md,
html: props.html,
})
watch(
Expand All @@ -63,13 +70,51 @@ watch(
}
)
watch(
() => props.modelValue,
(newValue) => {
formData.postTitle = newValue
}
)
watch(
() => props.md,
(newValue) => {
formData.md = newValue
}
)
const emit = defineEmits(["emitSyncPublishTitle"])
const handleTitleChange = () => {
emit("emitSyncPublishTitle", formData.postTitle)
}
const handleMakeTitle = () => {}
const handleMakeTitle = async () => {
try {
formData.isLoading = true
const inputWord = `${formData.md}\n${prompt.titlePrompt.content}`
const { chat } = useChatGPT()
const chatText = await chat(inputWord)
if (StrUtil.isEmptyString(chatText)) {
ElMessage.error("请求错误,请在偏好设置配置请求地址和ChatGPT key!")
return
}
const resJson = JsonUtil.safeParse<TitleAIResult>(chatText, {} as TitleAIResult)
formData.postTitle = resJson.title
emit("emitSyncPublishTitle", formData.postTitle)
logger.info("使用AI智能生成的标题结果 =>", {
inputWord: inputWord,
chatText: chatText,
})
ElMessage.success("使用人工智能提取标题成功")
} catch (e) {
logger.error(t("main.opt.failure") + "=>", e)
ElMessage.error(t("main.opt.failure") + "=>" + e)
} finally {
formData.isLoading = false
}
}
</script>

<template>
Expand Down
63 changes: 63 additions & 0 deletions src/models/aiPrompt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2023, Terwer . All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Terwer designates this
* particular file as subject to the "Classpath" exception as provided
* by Terwer in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Terwer, Shenzhen, Guangdong, China, youweics@163.com
* or visit www.terwer.space if you need additional information or have any
* questions.
*/

/**
* 表示一个 AI 提示的类,用于存储标题、内容和描述等信息
*
* 使用:const prompt = new AiPrompt("Generate Blog Post",
* "Write a blog post about the benefits of AI.",
* "Generate a blog post discussing the various advantages of artificial intelligence in different industries.");
*/
class AiPrompt {
/**
* 提示的标题
*/
title: string

/**
* 提示的内容
*/
content: string

/**
* 提示的描述
*/
description: string

/**
* 创建一个 AiPrompt 的新实例
*
* @param title - 提示的标题
* @param content - 提示的内容
* @param description - 提示的描述
*/
constructor(title: string, content: string, description: string) {
this.title = title
this.content = content
this.description = description
}
}

export { AiPrompt }
11 changes: 7 additions & 4 deletions src/pages/AiChat.vue
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,11 @@ onMounted(async () => {
<el-alert
v-if="formData.usePage && formData.showPage && !StrUtil.isEmptyString(formData.siyuanPost.markdown)"
:closable="false"
:title="`当前上下文为${formData.siyuanPost.title}`"
:title="`当前为上下文模式,文档上下文为${formData.siyuanPost.title}`"
class="top-tip"
type="success"
/>
<el-alert v-else :closable="false" :title="`当前为自由聊天模式`" class="top-tip" type="info" />
<el-form class="chatgpt-form">
<el-form-item>
<el-input
Expand All @@ -118,12 +119,14 @@ onMounted(async () => {
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="sendMessage" :loading="formData.isLoading">发送消息</el-button>
<el-button type="danger" @click="clearChatOutput">清屏</el-button>
<div v-if="formData.showPage && !StrUtil.isEmptyString(formData.siyuanPost.markdown)">
<el-switch v-model="formData.usePage" class="use-context" /> &nbsp; 使用当前文档作为上下文
</div>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="sendMessage" :loading="formData.isLoading">发送消息</el-button>
<el-button type="danger" @click="clearChatOutput">清屏</el-button>
</el-form-item>
<el-form-item>
<div class="chat-output">
<pre>{{ chatOutput }}</pre>
Expand All @@ -141,4 +144,4 @@ onMounted(async () => {
margin-top 20px
.use-context
margin-left 10px
</style>
</style>
Loading

0 comments on commit 2e48ca5

Please sign in to comment.