562 lines
29 KiB
Plaintext
562 lines
29 KiB
Plaintext
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>AI 写作工坊 - 结构化生成工具</title>
|
||
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
|
||
<script src="https://cdn.tailwindcss.com"></script>
|
||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||
|
||
<style>
|
||
/* 自定义滚动条样式,适配深色主题 */
|
||
::-webkit-scrollbar { width: 8px; height: 8px; }
|
||
::-webkit-scrollbar-track { background: #1e293b; }
|
||
::-webkit-scrollbar-thumb { background: #475569; border-radius: 4px; }
|
||
::-webkit-scrollbar-thumb:hover { background: #64748b; }
|
||
|
||
/* Markdown 内容样式覆盖 */
|
||
.prose h1, .prose h2, .prose h3 { color: #e2e8f0; margin-top: 1.5em; margin-bottom: 0.8em; }
|
||
.prose p { margin-bottom: 1.2em; line-height: 1.75; color: #cbd5e1; }
|
||
.prose ul { list-style-type: disc; padding-left: 1.5em; margin-bottom: 1.2em; color: #cbd5e1; }
|
||
.prose strong { color: #60a5fa; font-weight: 600; }
|
||
.prose blockquote { border-left-color: #3b82f6; background: #1e293b; padding: 0.5rem 1rem; font-style: italic; }
|
||
.prose code { background: #334155; padding: 0.2em 0.4em; border-radius: 4px; font-size: 0.9em; color: #f8fafc; }
|
||
|
||
[v-cloak] { display: none; }
|
||
</style>
|
||
</head>
|
||
<body class="bg-slate-900 text-slate-200 h-screen overflow-hidden font-sans">
|
||
|
||
<div id="app" v-cloak class="flex h-full">
|
||
|
||
<aside class="w-[400px] flex flex-col border-r border-slate-700 bg-slate-800 shrink-0">
|
||
|
||
<div class="p-4 border-b border-slate-700 flex items-center justify-between">
|
||
<div class="flex items-center gap-4">
|
||
<h1 class="font-bold text-lg text-white flex items-center gap-2">
|
||
<span class="text-2xl">✍️</span>
|
||
<span v-if="currentPage === 'writer'">AI 写作工坊</span>
|
||
<span v-else>写作范式分析</span>
|
||
</h1>
|
||
<button
|
||
@click="currentPage = currentPage === 'writer' ? 'analysis' : 'writer'"
|
||
class="text-xs px-2 py-1 rounded bg-slate-700 text-slate-300 hover:bg-slate-600 transition"
|
||
>
|
||
{{ currentPage === 'writer' ? '写作范式' : '返回写作' }}
|
||
</button>
|
||
</div>
|
||
<span class="text-xs px-2 py-1 rounded bg-blue-900 text-blue-300 border border-blue-700">Pro版</span>
|
||
</div>
|
||
|
||
<div class="flex-1 overflow-y-auto p-4 space-y-6" v-if="currentPage === 'writer'">
|
||
|
||
<section>
|
||
<label class="block text-sm font-medium text-slate-400 mb-2 flex justify-between">
|
||
1. 写作任务 (User Input)
|
||
<span class="text-xs text-slate-500">{{ inputTask.length }} 字</span>
|
||
</label>
|
||
<textarea
|
||
v-model="inputTask"
|
||
class="w-full h-32 bg-slate-900 border border-slate-700 rounded-lg p-3 text-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition placeholder-slate-600 resize-none"
|
||
placeholder="请输入具体的写作要求、主题、核心观点..."
|
||
></textarea>
|
||
</section>
|
||
|
||
<section>
|
||
<div class="flex justify-between items-center mb-2">
|
||
<label class="text-sm font-medium text-slate-400">2. 参考案例 (Style Ref)</label>
|
||
<button @click="showRefInput = !showRefInput" class="text-xs text-blue-400 hover:text-blue-300">
|
||
{{ showRefInput ? '取消' : '+ 添加案例' }}
|
||
</button>
|
||
</div>
|
||
|
||
<div v-if="showRefInput" class="mb-3 p-3 bg-slate-900 rounded-lg border border-blue-500/30">
|
||
<input v-model="newRefTitle" placeholder="案例标题 (如: 乔布斯演讲)" class="w-full mb-2 bg-slate-800 border border-slate-700 rounded px-2 py-1 text-xs outline-none">
|
||
<textarea v-model="newRefContent" placeholder="粘贴优秀的参考文本..." class="w-full h-24 bg-slate-800 border border-slate-700 rounded px-2 py-1 text-xs outline-none resize-none mb-2"></textarea>
|
||
<button @click="addReference" class="w-full bg-blue-600 hover:bg-blue-500 text-xs py-1.5 rounded text-white">确认添加</button>
|
||
</div>
|
||
|
||
<div class="space-y-2">
|
||
<div v-for="(ref, index) in references" :key="index" class="group flex items-center justify-between bg-slate-700/50 p-2 rounded border border-slate-700 hover:border-slate-600">
|
||
<div class="flex items-center gap-2 overflow-hidden">
|
||
<span class="text-lg">📄</span>
|
||
<div class="flex flex-col min-w-0">
|
||
<span class="text-xs font-medium text-slate-200 truncate">{{ ref.title }}</span>
|
||
<span class="text-[10px] text-slate-500 truncate">{{ ref.content.substring(0, 20) }}...</span>
|
||
</div>
|
||
</div>
|
||
<button @click="removeReference(index)" class="text-slate-500 hover:text-red-400 opacity-0 group-hover:opacity-100 transition px-2">×</button>
|
||
</div>
|
||
<div v-if="references.length === 0" class="text-xs text-slate-600 text-center py-4 border border-dashed border-slate-700 rounded">
|
||
暂无参考案例,AI 将自由发挥
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section>
|
||
<label class="block text-sm font-medium text-slate-400 mb-2">3. 输出规范 (Constraints)</label>
|
||
<div class="flex flex-wrap gap-2 mb-3">
|
||
<button
|
||
v-for="tag in presetTags"
|
||
:key="tag"
|
||
@click="toggleTag(tag)"
|
||
:class="['px-2 py-1 rounded text-xs border transition',
|
||
selectedTags.includes(tag)
|
||
? 'bg-blue-600/20 border-blue-500 text-blue-300'
|
||
: 'bg-slate-900 border-slate-700 text-slate-500 hover:border-slate-500']"
|
||
>
|
||
{{ tag }}
|
||
</button>
|
||
</div>
|
||
<input
|
||
v-model="customConstraint"
|
||
type="text"
|
||
class="w-full bg-slate-900 border border-slate-700 rounded px-3 py-2 text-xs focus:border-blue-500 outline-none"
|
||
placeholder="补充其他要求 (例如: 严禁使用'综上所述')"
|
||
>
|
||
</section>
|
||
</div>
|
||
|
||
<div class="p-4 bg-slate-800 border-t border-slate-700 space-y-3 z-10">
|
||
<div class="flex items-center justify-between">
|
||
<label class="flex items-center gap-2 cursor-pointer">
|
||
<input type="checkbox" v-model="showPromptDebug" class="hidden">
|
||
<div class="w-8 h-4 bg-slate-900 rounded-full border border-slate-600 relative transition-colors" :class="{'bg-blue-900 border-blue-500': showPromptDebug}">
|
||
<div class="w-2 h-2 bg-slate-400 rounded-full absolute top-1 left-1 transition-transform" :class="{'translate-x-4 bg-blue-400': showPromptDebug}"></div>
|
||
</div>
|
||
<span class="text-xs text-slate-500 select-none">预览构建的 Prompt</span>
|
||
</label>
|
||
<span class="text-xs text-slate-600">deepseek</span>
|
||
</div>
|
||
|
||
<!-- API 配置 -->
|
||
<div class="space-y-2">
|
||
<input
|
||
v-model="apiUrl"
|
||
type="text"
|
||
class="w-full bg-slate-900 border border-slate-700 rounded px-3 py-2 text-xs focus:border-blue-500 outline-none"
|
||
placeholder="API 地址: https://your-kong-gateway.com/v1/chat/completions"
|
||
>
|
||
<input
|
||
v-model="apiKey"
|
||
type="password"
|
||
class="w-full bg-slate-900 border border-slate-700 rounded px-3 py-2 text-xs focus:border-blue-500 outline-none"
|
||
placeholder="API Key: Bearer YOUR_KEY"
|
||
>
|
||
</div>
|
||
|
||
<button
|
||
@click="generateContent"
|
||
:disabled="isGenerating || !inputTask"
|
||
class="w-full py-3 rounded-lg font-bold text-white shadow-lg shadow-blue-900/20 flex items-center justify-center gap-2 transition-all transform active:scale-95 disabled:opacity-50 disabled:cursor-not-allowed"
|
||
:class="isGenerating ? 'bg-slate-700' : 'bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-500 hover:to-indigo-500'"
|
||
>
|
||
<span v-if="isGenerating" class="animate-spin text-lg">↻</span>
|
||
{{ isGenerating ? '正在思考与撰写...' : '开始生成文稿' }}
|
||
</button>
|
||
</div>
|
||
</aside>
|
||
|
||
<!-- 写作范式分析页面 -->
|
||
<aside v-if="currentPage === 'analysis'" class="w-[400px] flex flex-col border-r border-slate-700 bg-slate-800 shrink-0">
|
||
<div class="flex-1 overflow-y-auto p-4 space-y-6">
|
||
<section>
|
||
<h3 class="text-sm font-medium text-slate-400 mb-4">📚 写作范式库</h3>
|
||
|
||
<div class="space-y-3">
|
||
<div class="bg-slate-700/50 rounded-lg p-4 border border-slate-600 hover:border-blue-500 transition cursor-pointer">
|
||
<h4 class="font-medium text-white mb-2">📝 技术博客范式</h4>
|
||
<p class="text-xs text-slate-400 mb-2">适用于技术分享、教程类文章</p>
|
||
<div class="flex flex-wrap gap-1">
|
||
<span class="text-xs px-2 py-1 bg-blue-900/30 text-blue-300 rounded">问题引入</span>
|
||
<span class="text-xs px-2 py-1 bg-blue-900/30 text-blue-300 rounded">解决方案</span>
|
||
<span class="text-xs px-2 py-1 bg-blue-900/30 text-blue-300 rounded">代码示例</span>
|
||
<span class="text-xs px-2 py-1 bg-blue-900/30 text-blue-300 rounded">总结</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="bg-slate-700/50 rounded-lg p-4 border border-slate-600 hover:border-blue-500 transition cursor-pointer">
|
||
<h4 class="font-medium text-white mb-2">📊 商业分析范式</h4>
|
||
<p class="text-xs text-slate-400 mb-2">适用于行业分析、市场报告</p>
|
||
<div class="flex flex-wrap gap-1">
|
||
<span class="text-xs px-2 py-1 bg-green-900/30 text-green-300 rounded">背景介绍</span>
|
||
<span class="text-xs px-2 py-1 bg-green-900/30 text-green-300 rounded">数据支撑</span>
|
||
<span class="text-xs px-2 py-1 bg-green-900/30 text-green-300 rounded">趋势分析</span>
|
||
<span class="text-xs px-2 py-1 bg-green-900/30 text-green-300 rounded">建议</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="bg-slate-700/50 rounded-lg p-4 border border-slate-600 hover:border-blue-500 transition cursor-pointer">
|
||
<h4 class="font-medium text-white mb-2">🎯 产品文案范式</h4>
|
||
<p class="text-xs text-slate-400 mb-2">适用于产品介绍、营销文案</p>
|
||
<div class="flex flex-wrap gap-1">
|
||
<span class="text-xs px-2 py-1 bg-purple-900/30 text-purple-300 rounded">痛点切入</span>
|
||
<span class="text-xs px-2 py-1 bg-purple-900/30 text-purple-300 rounded">价值主张</span>
|
||
<span class="text-xs px-2 py-1 bg-purple-900/30 text-purple-300 rounded">功能亮点</span>
|
||
<span class="text-xs px-2 py-1 bg-purple-900/30 text-purple-300 rounded">行动号召</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="bg-slate-700/50 rounded-lg p-4 border border-slate-600 hover:border-blue-500 transition cursor-pointer">
|
||
<h4 class="font-medium text-white mb-2">📖 学术论文范式</h4>
|
||
<p class="text-xs text-slate-400 mb-2">适用于学术写作、研究报告</p>
|
||
<div class="flex flex-wrap gap-1">
|
||
<span class="text-xs px-2 py-1 bg-orange-900/30 text-orange-300 rounded">摘要</span>
|
||
<span class="text-xs px-2 py-1 bg-orange-900/30 text-orange-300 rounded">引言</span>
|
||
<span class="text-xs px-2 py-1 bg-orange-900/30 text-orange-300 rounded">文献综述</span>
|
||
<span class="text-xs px-2 py-1 bg-orange-900/30 text-orange-300 rounded">方法论</span>
|
||
<span class="text-xs px-2 py-1 bg-orange-900/30 text-orange-300 rounded">结果</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section>
|
||
<h3 class="text-sm font-medium text-slate-400 mb-4">🔍 范式分析工具</h3>
|
||
<textarea
|
||
v-model="analysisText"
|
||
class="w-full h-32 bg-slate-900 border border-slate-700 rounded-lg p-3 text-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition placeholder-slate-600 resize-none"
|
||
placeholder="粘贴文章内容,分析其写作范式..."
|
||
></textarea>
|
||
<button
|
||
@click="analyzeArticleParadigm"
|
||
:disabled="isAnalyzing || !analysisText"
|
||
class="mt-3 w-full bg-blue-600 hover:bg-blue-500 text-white py-2 rounded-lg text-sm font-medium transition disabled:opacity-50 disabled:cursor-not-allowed"
|
||
>
|
||
{{ isAnalyzing ? '正在分析...' : '分析文章范式' }}
|
||
</button>
|
||
</section>
|
||
</div>
|
||
</aside>
|
||
|
||
<main class="flex-1 flex flex-col bg-slate-950 relative">
|
||
|
||
<div v-if="showPromptDebug" class="absolute inset-0 bg-slate-950/95 z-20 p-8 overflow-auto backdrop-blur-sm">
|
||
<div class="max-w-3xl mx-auto">
|
||
<div class="flex justify-between items-center mb-4">
|
||
<h3 class="text-lg font-bold text-yellow-500">🔧 构建的 Prompt 结构预览</h3>
|
||
<button @click="showPromptDebug = false" class="text-sm text-slate-400 hover:text-white">关闭预览</button>
|
||
</div>
|
||
<div class="bg-black/50 p-6 rounded-lg border border-slate-700 font-mono text-sm text-green-400 whitespace-pre-wrap leading-relaxed shadow-inner">
|
||
{{ constructedPrompt }}
|
||
</div>
|
||
<p class="mt-4 text-xs text-slate-500 text-center">此内容将直接发送给 API 接口</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="h-14 border-b border-slate-800 flex items-center justify-between px-6 bg-slate-950">
|
||
<span class="text-sm font-medium text-slate-400">
|
||
{{ currentPage === 'writer' ? '输出预览' : '范式分析结果' }}
|
||
</span>
|
||
<div class="flex items-center gap-4" v-if="currentPage === 'writer'">
|
||
<span class="text-xs text-slate-600">
|
||
字数: {{ generatedContent.length }} {{ isGenerating ? '(生成中...)' : '' }}
|
||
</span>
|
||
<div class="flex gap-3">
|
||
<button @click="copyContent" class="text-xs text-slate-400 hover:text-white flex items-center gap-1 transition">
|
||
📋 复制 Markdown
|
||
</button>
|
||
<button @click="generatedContent = ''" class="text-xs text-slate-400 hover:text-red-400 flex items-center gap-1 transition">
|
||
🗑️ 清空
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="flex-1 overflow-y-auto p-8 md:p-12">
|
||
<div class="max-w-3xl mx-auto min-h-[500px]">
|
||
<!-- 写作页面内容 -->
|
||
<div v-if="currentPage === 'writer'">
|
||
<div v-if="!generatedContent && !isGenerating" class="h-full flex flex-col items-center justify-center text-slate-700 mt-20">
|
||
<span class="text-6xl mb-4 opacity-20">⌨️</span>
|
||
<p>在左侧配置参数,点击生成开始写作</p>
|
||
</div>
|
||
|
||
<div v-else class="prose prose-invert max-w-none">
|
||
<div v-html="renderedMarkdown"></div>
|
||
<span v-if="isGenerating" class="inline-block w-2 h-5 bg-blue-500 ml-1 animate-pulse align-middle"></span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 范式分析页面内容 -->
|
||
<div v-else class="space-y-8">
|
||
<div v-if="!analysisResult" class="h-full flex flex-col items-center justify-center text-slate-700 mt-20">
|
||
<span class="text-6xl mb-4 opacity-20">📊</span>
|
||
<p>选择左侧的写作范式或使用分析工具</p>
|
||
</div>
|
||
<div v-else class="space-y-6">
|
||
<div v-if="analysisResult.error" class="bg-red-900/20 rounded-lg p-6 border border-red-700">
|
||
<h3 class="text-lg font-bold text-red-400 mb-4">分析失败</h3>
|
||
<p class="text-red-300">{{ analysisResult.message }}</p>
|
||
</div>
|
||
<div v-else class="bg-slate-900 rounded-lg p-6 border border-slate-700">
|
||
<h3 class="text-lg font-bold text-white mb-4">分析结果</h3>
|
||
<div class="prose prose-invert max-w-none">
|
||
<div v-html="marked.parse(analysisResult.analysis)"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
|
||
</div>
|
||
|
||
<script>
|
||
const { createApp, computed, ref } = Vue;
|
||
|
||
createApp({
|
||
setup() {
|
||
// --- 状态数据 ---
|
||
const inputTask = ref('请帮我写一篇关于“AI 辅助编程如何改变软件开发流程”的博客文章,面向中级程序员。');
|
||
|
||
// 参考案例相关
|
||
const references = ref([
|
||
{ title: '示例:技术博客风格.txt', content: '本文深入探讨了...(此处省略2000字,这是为了让AI模仿这种干练的技术风格)...' }
|
||
]);
|
||
const showRefInput = ref(false);
|
||
const newRefTitle = ref('');
|
||
const newRefContent = ref('');
|
||
|
||
// 规范相关
|
||
const presetTags = ['Markdown格式', '总分总结构', '数据支撑', '语气幽默', '严禁被动语态', '引用权威来源'];
|
||
const selectedTags = ref(['Markdown格式', '总分总结构']);
|
||
const customConstraint = ref('');
|
||
|
||
// 生成相关
|
||
const isGenerating = ref(false);
|
||
const generatedContent = ref('');
|
||
const showPromptDebug = ref(false);
|
||
|
||
// 页面切换
|
||
const currentPage = ref('writer'); // 'writer' 或 'analysis'
|
||
|
||
// 范式分析相关
|
||
const analysisText = ref('');
|
||
const analysisResult = ref(null);
|
||
const isAnalyzing = ref(false);
|
||
|
||
// API 配置
|
||
const apiUrl = ref('https://api.deepseek.com/chat/completions');
|
||
const apiKey = ref('YOUR_KEY');
|
||
|
||
// --- 核心逻辑:Meta-Prompt 组装器 ---
|
||
const constructedPrompt = computed(() => {
|
||
let prompt = `# Role\n你是一个资深的专业写作助手,请严格按照以下要求进行创作。\n\n`;
|
||
|
||
// 1. 注入规范
|
||
prompt += `# System Constraints (必须遵守)\n`;
|
||
selectedTags.value.forEach(tag => prompt += `- ${tag}\n`);
|
||
if (customConstraint.value) prompt += `- ${customConstraint.value}\n`;
|
||
prompt += `\n`;
|
||
|
||
// 2. 注入参考案例 (Few-Shot)
|
||
if (references.value.length > 0) {
|
||
prompt += `# Reference Cases (请模仿以下风格)\n`;
|
||
references.value.forEach((ref, idx) => {
|
||
prompt += `<case_${idx + 1} title="${ref.title}">\n${ref.content}\n</case_${idx + 1}>\n\n`;
|
||
});
|
||
}
|
||
|
||
// 3. 注入用户任务
|
||
prompt += `# Current Task (User Input)\n${inputTask.value}`;
|
||
|
||
return prompt;
|
||
});
|
||
|
||
const renderedMarkdown = computed(() => {
|
||
return marked.parse(generatedContent.value);
|
||
});
|
||
|
||
// --- 方法 ---
|
||
const addReference = () => {
|
||
if (!newRefTitle.value || !newRefContent.value) return;
|
||
references.value.push({
|
||
title: newRefTitle.value,
|
||
content: newRefContent.value
|
||
});
|
||
newRefTitle.value = '';
|
||
newRefContent.value = '';
|
||
showRefInput.value = false;
|
||
};
|
||
|
||
const removeReference = (index) => {
|
||
references.value.splice(index, 1);
|
||
};
|
||
|
||
const toggleTag = (tag) => {
|
||
if (selectedTags.value.includes(tag)) {
|
||
selectedTags.value = selectedTags.value.filter(t => t !== tag);
|
||
} else {
|
||
selectedTags.value.push(tag);
|
||
}
|
||
};
|
||
|
||
const generateContent = async () => {
|
||
if (!apiUrl.value || !apiKey.value || apiKey.value === 'YOUR_KEY') {
|
||
alert('请先配置 API 地址和 API Key');
|
||
return;
|
||
}
|
||
|
||
isGenerating.value = true;
|
||
generatedContent.value = '';
|
||
|
||
try {
|
||
const response = await fetch(apiUrl.value, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': `Bearer ${apiKey.value}`
|
||
},
|
||
body: JSON.stringify({
|
||
model: 'deepseek-chat',
|
||
messages: [
|
||
{
|
||
role: 'system',
|
||
content: '你是一个资深的专业写作助手,请严格按照用户的要求进行创作。'
|
||
},
|
||
{
|
||
role: 'user',
|
||
content: constructedPrompt.value
|
||
}
|
||
],
|
||
stream: true,
|
||
temperature: 0.7
|
||
})
|
||
});
|
||
|
||
if (!response.ok) {
|
||
const errorText = await response.text();
|
||
console.error('API Error Response:', errorText);
|
||
throw new Error(`API 请求失败: ${response.status} ${response.statusText}\n\n详细信息: ${errorText}`);
|
||
}
|
||
|
||
const reader = response.body.getReader();
|
||
const decoder = new TextDecoder();
|
||
|
||
while (true) {
|
||
const { done, value } = await reader.read();
|
||
if (done) break;
|
||
|
||
const chunk = decoder.decode(value);
|
||
const lines = chunk.split('\n').filter(line => line.trim());
|
||
|
||
for (const line of lines) {
|
||
if (line.startsWith('data: ')) {
|
||
const data = line.slice(6);
|
||
if (data === '[DONE]') continue;
|
||
|
||
try {
|
||
const parsed = JSON.parse(data);
|
||
const content = parsed.choices?.[0]?.delta?.content || '';
|
||
generatedContent.value += content;
|
||
} catch (e) {
|
||
// 忽略解析错误
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} catch (error) {
|
||
generatedContent.value = `## 错误\n\n${error.message}\n\n请检查 API 配置是否正确。`;
|
||
} finally {
|
||
isGenerating.value = false;
|
||
}
|
||
};
|
||
|
||
const copyContent = () => {
|
||
navigator.clipboard.writeText(generatedContent.value);
|
||
alert('已复制到剪贴板');
|
||
};
|
||
|
||
const analyzeArticleParadigm = async () => {
|
||
if (!analysisText.value.trim()) {
|
||
alert('请输入要分析的文章内容');
|
||
return;
|
||
}
|
||
|
||
isAnalyzing.value = true;
|
||
analysisResult.value = null;
|
||
|
||
try {
|
||
const response = await fetch(apiUrl.value, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': `Bearer ${apiKey.value}`
|
||
},
|
||
body: JSON.stringify({
|
||
model: 'deepseek-chat',
|
||
messages: [
|
||
{
|
||
role: 'system',
|
||
content: '你是一个专业的写作分析师,擅长分析文章的写作范式、结构和特点。请从以下几个方面分析文章:1. 主要写作范式类型 2. 文章结构特点 3. 语言风格特征 4. 目标读者群体 5. 写作技巧总结。请用简洁明了的语言回答。'
|
||
},
|
||
{
|
||
role: 'user',
|
||
content: `请分析以下文章的写作范式:\n\n${analysisText.value}`
|
||
}
|
||
],
|
||
stream: false,
|
||
temperature: 0.3
|
||
})
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error(`分析请求失败: ${response.status} ${response.statusText}`);
|
||
}
|
||
|
||
const data = await response.json();
|
||
analysisResult.value = {
|
||
paradigm: '技术博客范式',
|
||
features: [
|
||
'采用问题-解决方案的叙述结构',
|
||
'包含大量代码示例',
|
||
'语言简洁,逻辑清晰'
|
||
],
|
||
analysis: data.choices[0].message.content
|
||
};
|
||
} catch (error) {
|
||
analysisResult.value = {
|
||
error: true,
|
||
message: error.message
|
||
};
|
||
} finally {
|
||
isAnalyzing.value = false;
|
||
}
|
||
};
|
||
|
||
return {
|
||
inputTask,
|
||
references,
|
||
showRefInput,
|
||
newRefTitle,
|
||
newRefContent,
|
||
presetTags,
|
||
selectedTags,
|
||
customConstraint,
|
||
isGenerating,
|
||
generatedContent,
|
||
showPromptDebug,
|
||
currentPage,
|
||
analysisText,
|
||
analysisResult,
|
||
isAnalyzing,
|
||
apiUrl,
|
||
apiKey,
|
||
constructedPrompt,
|
||
renderedMarkdown,
|
||
addReference,
|
||
removeReference,
|
||
toggleTag,
|
||
generateContent,
|
||
copyContent,
|
||
analyzeArticleParadigm
|
||
};
|
||
}
|
||
}).mount('#app');
|
||
</script>
|
||
|
||
</body>
|
||
</html> |