feat: 优化
This commit is contained in:
@@ -1,41 +1,44 @@
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
import { EditOutlined, CopyOutlined } from '@ant-design/icons-vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import ChatMessageRenderer from '@/components/ChatMessageRenderer.vue'
|
||||
import ChatMessageRendererV2 from '@/components/ChatMessageRendererV2.vue'
|
||||
import { ChatMessageApi } from '@/api/chat'
|
||||
import { streamChat } from '@/utils/streamChat'
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
mergedText: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
textCount: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
const props = withDefaults(defineProps<{
|
||||
visible: boolean
|
||||
mergedText: string
|
||||
textCount: number
|
||||
}>(), {
|
||||
visible: false,
|
||||
mergedText: '',
|
||||
textCount: 0,
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:visible', 'copy', 'save', 'use'])
|
||||
const emit = defineEmits<{
|
||||
'update:visible': [value: boolean]
|
||||
'copy': [text: string]
|
||||
'save': [text: string]
|
||||
'use': [text: string]
|
||||
}>()
|
||||
|
||||
const batchPrompt = ref('')
|
||||
const batchPromptEditMode = ref(false)
|
||||
const batchPromptGenerating = ref(false)
|
||||
const hasGenerated = ref(false)
|
||||
|
||||
function resetModal() {
|
||||
batchPrompt.value = ''
|
||||
batchPromptEditMode.value = false
|
||||
batchPromptGenerating.value = false
|
||||
hasGenerated.value = false
|
||||
}
|
||||
|
||||
watch(() => props.visible, (newVal) => {
|
||||
if (newVal && props.mergedText && !hasGenerated.value) {
|
||||
generateBatchPrompt()
|
||||
} else if (!newVal) {
|
||||
batchPrompt.value = ''
|
||||
batchPromptEditMode.value = false
|
||||
batchPromptGenerating.value = false
|
||||
hasGenerated.value = false
|
||||
resetModal()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -47,47 +50,61 @@ watch(() => props.mergedText, (newVal) => {
|
||||
|
||||
async function generateBatchPrompt() {
|
||||
if (!props.mergedText || hasGenerated.value) return
|
||||
|
||||
|
||||
hasGenerated.value = true
|
||||
|
||||
try {
|
||||
batchPromptGenerating.value = true
|
||||
const createPayload = { roleId: 20 }
|
||||
console.debug('createChatConversationMy payload(batch):', createPayload)
|
||||
const conversationResp = await ChatMessageApi.createChatConversationMy(createPayload)
|
||||
|
||||
let conversationId = null
|
||||
if (conversationResp?.data) {
|
||||
conversationId = typeof conversationResp.data === 'object' ? conversationResp.data.id : conversationResp.data
|
||||
}
|
||||
|
||||
if (!conversationId) {
|
||||
throw new Error('创建对话失败:未获取到 conversationId')
|
||||
}
|
||||
|
||||
const conversationId = await createConversation()
|
||||
|
||||
const aiContent = await streamChat({
|
||||
conversationId,
|
||||
content: props.mergedText,
|
||||
onUpdate: (fullText) => {
|
||||
onUpdate: (fullText: string) => {
|
||||
batchPrompt.value = fullText
|
||||
},
|
||||
enableTypewriter: true,
|
||||
typewriterSpeed: 10,
|
||||
typewriterBatchSize: 2
|
||||
typewriterBatchSize: 2,
|
||||
onComplete: () => {},
|
||||
onError: (error: Error) => {
|
||||
console.error('流式聊天错误:', error)
|
||||
},
|
||||
enableContext: false,
|
||||
enableWebSearch: false,
|
||||
timeout: 180000,
|
||||
attachmentUrls: []
|
||||
})
|
||||
|
||||
if (aiContent && aiContent !== batchPrompt.value) {
|
||||
batchPrompt.value = aiContent
|
||||
}
|
||||
|
||||
|
||||
message.success(`批量分析完成:已基于 ${props.textCount} 个视频的文案生成综合提示词`)
|
||||
} catch (aiError) {
|
||||
console.error('AI生成失败:', aiError)
|
||||
} catch (error) {
|
||||
console.error('AI生成失败:', error)
|
||||
message.error('AI生成失败,请稍后重试')
|
||||
} finally {
|
||||
batchPromptGenerating.value = false
|
||||
hasGenerated.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function createConversation() {
|
||||
const createPayload = { roleId: 20 }
|
||||
const conversationResp = await ChatMessageApi.createChatConversationMy(createPayload)
|
||||
|
||||
const conversationId = conversationResp?.data
|
||||
? (typeof conversationResp.data === 'object' ? conversationResp.data.id : conversationResp.data)
|
||||
: null
|
||||
|
||||
if (!conversationId) {
|
||||
throw new Error('创建对话失败:未获取到 conversationId')
|
||||
}
|
||||
|
||||
return conversationId
|
||||
}
|
||||
|
||||
function handleClose() {
|
||||
emit('update:visible', false)
|
||||
}
|
||||
@@ -112,131 +129,86 @@ function handleUse() {
|
||||
:width="800"
|
||||
:maskClosable="false"
|
||||
:keyboard="false"
|
||||
@cancel="handleClose">
|
||||
@cancel="handleClose"
|
||||
>
|
||||
<div class="batch-prompt-modal">
|
||||
<!-- 内容显示模式 -->
|
||||
<div v-if="!batchPromptEditMode" class="batch-prompt-display">
|
||||
<ChatMessageRenderer
|
||||
<ChatMessageRendererV2
|
||||
:content="batchPrompt"
|
||||
:is-streaming="batchPromptGenerating"
|
||||
/>
|
||||
</div>
|
||||
<a-textarea
|
||||
|
||||
<!-- 编辑模式 -->
|
||||
<a-textarea
|
||||
v-else
|
||||
v-model:value="batchPrompt"
|
||||
:rows="15"
|
||||
placeholder="内容将在这里显示..." />
|
||||
v-model:value="batchPrompt"
|
||||
:rows="15"
|
||||
placeholder="内容将在这里显示..."
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
<template #footer>
|
||||
<a-space>
|
||||
<a-button size="small" :title="batchPromptEditMode ? '取消编辑' : '编辑'" @click="batchPromptEditMode = !batchPromptEditMode">
|
||||
<template #icon>
|
||||
<EditOutlined />
|
||||
</template>
|
||||
</a-button>
|
||||
<a-button size="small" title="复制" @click="handleCopy">
|
||||
<template #icon>
|
||||
<CopyOutlined />
|
||||
</template>
|
||||
</a-button>
|
||||
<a-button size="small" title="保存提示词" @click="handleSave" :disabled="!batchPrompt.trim()">
|
||||
保存提示词
|
||||
</a-button>
|
||||
<a-button @click="handleClose">取消</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
:disabled="batchPromptGenerating || !batchPrompt.trim()"
|
||||
@click="handleUse">去创作</a-button>
|
||||
</a-space>
|
||||
<div class="footer-actions">
|
||||
<div class="left-actions">
|
||||
<a-button type="text" @click="batchPromptEditMode = !batchPromptEditMode">
|
||||
{{ batchPromptEditMode ? '取消编辑' : '编辑' }}
|
||||
</a-button>
|
||||
<a-button type="text" @click="handleCopy">复制</a-button>
|
||||
<a-button
|
||||
type="text"
|
||||
@click="handleSave"
|
||||
:disabled="!batchPrompt.trim()"
|
||||
>
|
||||
保存提示词
|
||||
</a-button>
|
||||
</div>
|
||||
<div class="right-actions">
|
||||
<a-button @click="handleClose">取消</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
:disabled="batchPromptGenerating || !batchPrompt.trim()"
|
||||
@click="handleUse"
|
||||
>
|
||||
去创作
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
<style scoped lang="less">
|
||||
.batch-prompt-modal {
|
||||
min-height: 200px;
|
||||
|
||||
.batch-prompt-display {
|
||||
min-height: 300px;
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
padding: 24px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 8px;
|
||||
background: var(--color-surface);
|
||||
}
|
||||
}
|
||||
|
||||
.batch-prompt-display {
|
||||
min-height: 300px;
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
padding: 12px;
|
||||
background: #0d0d0d;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 6px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.footer-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
|
||||
.batch-prompt-display :deep(h1) {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
margin: 12px 0;
|
||||
color: var(--color-text);
|
||||
}
|
||||
.left-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.batch-prompt-display :deep(h2) {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin: 16px 0 8px 0;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.batch-prompt-display :deep(h3) {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
margin: 12px 0 6px 0;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.batch-prompt-display :deep(p) {
|
||||
margin: 8px 0;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.batch-prompt-display :deep(ul),
|
||||
.batch-prompt-display :deep(ol) {
|
||||
margin: 8px 0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.batch-prompt-display :deep(li) {
|
||||
margin: 4px 0;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.batch-prompt-display :deep(strong) {
|
||||
font-weight: 600;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.batch-prompt-display :deep(code) {
|
||||
background: #1a1a1a;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 12px;
|
||||
color: #e11d48;
|
||||
}
|
||||
|
||||
.batch-prompt-display :deep(pre) {
|
||||
background: #1a1a1a;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
overflow-x: auto;
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.batch-prompt-display :deep(pre code) {
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.batch-prompt-display :deep(blockquote) {
|
||||
border-left: 3px solid var(--color-primary);
|
||||
padding-left: 12px;
|
||||
margin: 8px 0;
|
||||
color: var(--color-text-secondary);
|
||||
.right-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import { CopyOutlined, SaveOutlined } from '@ant-design/icons-vue'
|
||||
import ChatMessageRenderer from '@/components/ChatMessageRenderer.vue'
|
||||
import ChatMessageRendererV2 from '@/components/ChatMessageRendererV2.vue'
|
||||
|
||||
const props = defineProps({
|
||||
record: {
|
||||
@@ -26,7 +26,6 @@ function handleCreateContent() {
|
||||
|
||||
<template>
|
||||
<div class="expanded-content">
|
||||
<!-- 未分析的行显示提示 -->
|
||||
<div v-if="!record.transcriptions && !record.prompt" class="no-analysis-tip">
|
||||
<a-empty description="该视频尚未分析">
|
||||
<template #image>
|
||||
@@ -42,10 +41,8 @@ function handleCreateContent() {
|
||||
</a-button>
|
||||
</a-empty>
|
||||
</div>
|
||||
|
||||
<!-- 已分析的行显示内容 -->
|
||||
|
||||
<div v-else class="two-col">
|
||||
<!-- 左侧:原配音内容 -->
|
||||
<section class="col left-col">
|
||||
<div class="sub-title">原配音</div>
|
||||
<div class="transcript-box" v-if="record.transcriptions">
|
||||
@@ -54,44 +51,43 @@ function handleCreateContent() {
|
||||
<div v-else class="no-transcript">暂无转写文本,请先点击"分析"获取</div>
|
||||
</section>
|
||||
|
||||
<!-- 右侧:提示词 -->
|
||||
<section class="col right-col">
|
||||
<div class="sub-title">提示词</div>
|
||||
|
||||
|
||||
<div class="prompt-display-wrapper">
|
||||
<ChatMessageRenderer
|
||||
<ChatMessageRendererV2
|
||||
:content="record.prompt || ''"
|
||||
:is-streaming="record._analyzing || false"
|
||||
/>
|
||||
<div v-if="!record.prompt" class="no-prompt">暂无提示词</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="right-actions">
|
||||
<a-space>
|
||||
<a-button
|
||||
size="small"
|
||||
type="text"
|
||||
<a-button
|
||||
size="small"
|
||||
type="text"
|
||||
class="copy-btn"
|
||||
:title="'复制'"
|
||||
title="复制"
|
||||
@click="handleCopy">
|
||||
<template #icon>
|
||||
<CopyOutlined />
|
||||
</template>
|
||||
</a-button>
|
||||
<a-button
|
||||
<a-button
|
||||
v-if="record.prompt"
|
||||
size="small"
|
||||
type="text"
|
||||
size="small"
|
||||
type="text"
|
||||
class="save-server-btn"
|
||||
:title="'保存'"
|
||||
title="保存"
|
||||
@click="handleSaveToServer">
|
||||
<template #icon>
|
||||
<SaveOutlined />
|
||||
</template>
|
||||
保存
|
||||
</a-button>
|
||||
<a-button
|
||||
type="dashed"
|
||||
<a-button
|
||||
type="dashed"
|
||||
:disabled="!record.prompt || record._analyzing"
|
||||
@click="handleCreateContent">基于提示词去创作</a-button>
|
||||
</a-space>
|
||||
@@ -177,7 +173,6 @@ function handleCreateContent() {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
|
||||
.no-analysis-tip {
|
||||
padding: var(--space-8) var(--space-5);
|
||||
text-align: center;
|
||||
|
||||
Reference in New Issue
Block a user