forked from b2894lxlx/tuanwei-admin
feat(ai): 写作模式拆成自由创作与模板两条路(issue 18)
自由创作不再解析自然语言:原话整段作为 userContent 下发,docType 留空,由后端转 「AI 创意助手」。选了文体才提交 docType 等结构化条件,走「内容创作与宣传助手」。 - writing-params.ts 删掉 parseWritingRequest、字段别名表与字数兜底表,只留选项常量。 - chatgpt/index.vue:字数选择器只在选中文体后出现;撤掉图片比例选择器(上游开始 节点无比例变量,只能拼进 user_content,等于替上游写 prompt);结果不再用入参补标题。 - gxmu/manuscriptGen:新增「自由创作」入口与 freeContent 文本域,模板模式才展开活动 信息等可选项。 - 顺带删除 chatgpt/index.bak.vue 旧备份。
This commit is contained in:
@@ -22,18 +22,12 @@
|
||||
<a-button block @click="fillDemo('news')">活动新闻稿</a-button>
|
||||
<a-button block @click="fillDemo('wechat')">公众号推文</a-button>
|
||||
<a-button block @click="fillDemo('speech')">发言稿提纲</a-button>
|
||||
<a-button block @click="fillDemo('free')">自由创作示例</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<a-card :bordered="false" class="panel-card">
|
||||
<template #title>创作配置</template>
|
||||
<a-form layout="vertical">
|
||||
<a-form-item label="稿件标题">
|
||||
<a-input
|
||||
v-model:value="form.theme"
|
||||
allow-clear
|
||||
placeholder="例如:广西医科大学开展2026年春季志愿服务活动"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="稿件类型">
|
||||
<a-select
|
||||
v-model:value="form.docType"
|
||||
@@ -41,60 +35,78 @@
|
||||
placeholder="请选择稿件类型"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="活动类型">
|
||||
<a-select
|
||||
v-model:value="form.eventType"
|
||||
:options="eventTypeOptions"
|
||||
placeholder="请选择活动类型"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="活动时间">
|
||||
<a-input
|
||||
v-model:value="form.time"
|
||||
allow-clear
|
||||
placeholder="例如:2026年4月8日下午"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="活动地点">
|
||||
<a-input
|
||||
v-model:value="form.location"
|
||||
allow-clear
|
||||
placeholder="例如:广西医科大学校史馆广场"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="参与人员">
|
||||
<a-input
|
||||
v-model:value="form.participants"
|
||||
allow-clear
|
||||
placeholder="例如:校团委老师、青年志愿者代表共120人"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="亮点内容">
|
||||
<a-form-item v-if="!templateMode" label="想创作的内容">
|
||||
<a-textarea
|
||||
v-model:value="form.highlights"
|
||||
:auto-size="{ minRows: 5, maxRows: 8 }"
|
||||
placeholder="填写活动亮点、流程、成果、典型细节等关键信息"
|
||||
v-model:value="form.freeContent"
|
||||
:auto-size="{ minRows: 6, maxRows: 12 }"
|
||||
placeholder="例如:帮我写一段迎新晚会的主持人开场词,口语化一点,时长两分钟左右"
|
||||
/>
|
||||
<div class="upload-tip">
|
||||
不套模板时,这段内容会作为 `user_content` 交给「AI 创意助手」;选上面的文稿模板后可填写活动信息等可选参数。
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="建议篇幅">
|
||||
<a-input-number
|
||||
v-model:value="form.number"
|
||||
class="full-width"
|
||||
:min="100"
|
||||
:max="5000"
|
||||
:step="100"
|
||||
placeholder="请输入建议字数"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="附件材料">
|
||||
<a-upload
|
||||
:multiple="true"
|
||||
:show-upload-list="false"
|
||||
:customRequest="handleUpload"
|
||||
>
|
||||
<a-button>
|
||||
<template #icon>
|
||||
<UploadOutlined />
|
||||
<template v-if="templateMode">
|
||||
<a-form-item label="稿件标题">
|
||||
<a-input
|
||||
v-model:value="form.theme"
|
||||
allow-clear
|
||||
placeholder="例如:广西医科大学开展2026年春季志愿服务活动"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="活动类型">
|
||||
<a-select
|
||||
v-model:value="form.eventType"
|
||||
:options="eventTypeOptions"
|
||||
placeholder="请选择活动类型"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="活动时间">
|
||||
<a-input
|
||||
v-model:value="form.time"
|
||||
allow-clear
|
||||
placeholder="例如:2026年4月8日下午"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="活动地点">
|
||||
<a-input
|
||||
v-model:value="form.location"
|
||||
allow-clear
|
||||
placeholder="例如:广西医科大学校史馆广场"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="参与人员">
|
||||
<a-input
|
||||
v-model:value="form.participants"
|
||||
allow-clear
|
||||
placeholder="例如:校团委老师、青年志愿者代表共120人"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="亮点内容">
|
||||
<a-textarea
|
||||
v-model:value="form.highlights"
|
||||
:auto-size="{ minRows: 5, maxRows: 8 }"
|
||||
placeholder="填写活动亮点、流程、成果、典型细节等关键信息"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="建议篇幅">
|
||||
<a-input-number
|
||||
v-model:value="form.number"
|
||||
class="full-width"
|
||||
:min="100"
|
||||
:max="5000"
|
||||
:step="100"
|
||||
placeholder="请输入建议字数"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="附件材料">
|
||||
<a-upload
|
||||
:multiple="true"
|
||||
:show-upload-list="false"
|
||||
:customRequest="handleUpload"
|
||||
>
|
||||
<a-button>
|
||||
<template #icon>
|
||||
<UploadOutlined />
|
||||
</template>
|
||||
上传附件
|
||||
</a-button>
|
||||
@@ -119,6 +131,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</a-form>
|
||||
|
||||
<div class="submit-bar">
|
||||
@@ -136,8 +149,9 @@
|
||||
<div class="hint-block">
|
||||
<div class="hint-title">提交说明</div>
|
||||
<div class="hint-text">
|
||||
页面会先提交 `POST /ai/manuscriptGen`,再按 `/ai` 页面的方式通过 WebSocket
|
||||
流式接收生成结果;如果后端仍然直接返回正文,页面也会自动兼容解析。
|
||||
未选模板(自由创作)时只提交一段内容,后端转「AI 创意助手」;选了模板才提交
|
||||
`docType` 等结构化条件。两种都会先 `POST /ai/manuscriptGen`,再按 `/ai` 页面的方式
|
||||
通过 WebSocket 流式接收生成结果;如果后端仍然直接返回正文,页面也会自动兼容解析。
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
@@ -227,7 +241,9 @@
|
||||
import { resolveDisplayText, isFailedPayload, pickDisplayable, FAILED_TEXT } from '@/utils/ai-result';
|
||||
|
||||
interface FormState {
|
||||
/** 空串 = 自由创作(不套模板);非空 = 文稿模板,走「内容创作与宣传助手」 */
|
||||
docType: string;
|
||||
freeContent: string;
|
||||
eventType: string;
|
||||
theme: string;
|
||||
time: string;
|
||||
@@ -243,7 +259,7 @@
|
||||
summary: string;
|
||||
}
|
||||
|
||||
type DemoType = 'news' | 'wechat' | 'speech';
|
||||
type DemoType = 'news' | 'wechat' | 'speech' | 'free';
|
||||
type StreamResolver = {
|
||||
resolve: () => void;
|
||||
reject: (error: Error) => void;
|
||||
@@ -275,8 +291,13 @@
|
||||
const THINK_OPEN_TAG = '<think>';
|
||||
const THINK_CLOSE_TAG = '</think>';
|
||||
|
||||
/** 「自由创作」的取值:选中它时不下发 docType,后端转「AI 创意助手」 */
|
||||
const DOC_TYPE_FREE = '自由创作';
|
||||
|
||||
const form = reactive<FormState>({
|
||||
docType: '新闻稿',
|
||||
// 默认自由创作:未选模板就说清想写什么,交给「AI 创意助手」
|
||||
docType: DOC_TYPE_FREE,
|
||||
freeContent: '',
|
||||
eventType: '校园活动',
|
||||
theme: '',
|
||||
time: '',
|
||||
@@ -287,6 +308,8 @@
|
||||
});
|
||||
|
||||
const docTypeOptions = [
|
||||
// 自由创作:表单只留一个内容输入框,提交时不带 docType
|
||||
{ label: '自由创作(不套模板)', value: DOC_TYPE_FREE },
|
||||
{ label: '新闻稿', value: '新闻稿' },
|
||||
{ label: '公众号推文', value: '公众号推文' },
|
||||
{ label: '宣传稿', value: '宣传稿' },
|
||||
@@ -304,7 +327,13 @@
|
||||
{ label: '品牌项目', value: '品牌项目' }
|
||||
];
|
||||
|
||||
/** 选了文稿模板才展开其余可选参数 */
|
||||
const templateMode = computed(() => !!form.docType && form.docType !== DOC_TYPE_FREE);
|
||||
|
||||
const canSubmit = computed(() => {
|
||||
if (!templateMode.value) {
|
||||
return !!form.freeContent.trim();
|
||||
}
|
||||
return !!(form.theme.trim() || form.highlights.trim() || uploadedFiles.value.length);
|
||||
});
|
||||
|
||||
@@ -375,6 +404,13 @@
|
||||
});
|
||||
|
||||
const buildPayload = (): ManuscriptGenParams => {
|
||||
if (!templateMode.value) {
|
||||
// 自由创作:只发一段内容,后端见 docType 为空就转「AI 创意助手」
|
||||
return {
|
||||
docType: '',
|
||||
userContent: form.freeContent.trim()
|
||||
};
|
||||
}
|
||||
return {
|
||||
docType: form.docType,
|
||||
eventType: form.eventType,
|
||||
@@ -718,7 +754,9 @@
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
form.docType = '新闻稿';
|
||||
// 重置回自由创作,而不是上一次的模板
|
||||
form.docType = DOC_TYPE_FREE;
|
||||
form.freeContent = '';
|
||||
form.eventType = '校园活动';
|
||||
form.theme = '';
|
||||
form.time = '';
|
||||
@@ -730,6 +768,12 @@
|
||||
};
|
||||
|
||||
const fillDemo = (type: DemoType) => {
|
||||
if (type === 'free') {
|
||||
form.docType = DOC_TYPE_FREE;
|
||||
form.freeContent =
|
||||
'帮我写一段迎新晚会的主持人开场词,口语化一点,时长两分钟左右,面向大一新生。';
|
||||
return;
|
||||
}
|
||||
if (type === 'news') {
|
||||
form.theme = '广西医科大学青年志愿者开展“清洁校园”志愿服务活动';
|
||||
form.docType = '新闻稿';
|
||||
@@ -805,7 +849,11 @@
|
||||
|
||||
const handleGenerate = async () => {
|
||||
if (!canSubmit.value) {
|
||||
message.warning('请至少填写稿件标题、亮点内容或上传附件中的一项');
|
||||
message.warning(
|
||||
templateMode.value
|
||||
? '请至少填写稿件标题、亮点内容或上传附件中的一项'
|
||||
: '请先描述你想创作的内容'
|
||||
);
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
@@ -814,7 +862,9 @@
|
||||
responseSummary.value = '正在建立 WebSocket 连接...';
|
||||
try {
|
||||
await connectWebSocket();
|
||||
responseSummary.value = '连接成功,已提交生成任务,等待流式返回...';
|
||||
responseSummary.value = templateMode.value
|
||||
? '连接成功,已提交生成任务,等待流式返回...'
|
||||
: '自由创作已提交给 AI 创意助手,生成完成后一次性返回...';
|
||||
const waitStream = createStreamWaiter();
|
||||
const result = await manuscriptGen(buildPayload());
|
||||
if (!streamStarted.value && shouldTreatAsDirectResult(result)) {
|
||||
|
||||
Reference in New Issue
Block a user