Plugin.php13.2 KB
<?php
/**
* Typecho AI写作助手插件(DeepSeek增强版)
*
* @package AIDeepSeek
* @author 小野博客
* @version 1.1.1
* @link https://lb5.net
*/
class AIDeepSeek_Plugin implements Typecho_Plugin_Interface
{
/**
* 激活插件方法
*/
public static function activate()
{
// 注册方式
Typecho_Plugin::factory('admin/write-post.php')->bottom = array(__CLASS__, 'render');
return "插件启用成功,请配置DeepSeek API参数";
}
/**
* 禁用插件方法
*/
public static function deactivate()
{
return "插件已禁用";
}
/**
* 获取插件配置面板
*/
public static function config(Typecho_Widget_Helper_Form $form)
{
$div = new Typecho_Widget_Helper_Layout();
$div->html('
<div style="background:#f8f9fa; padding:15px; border-radius:5px; margin-bottom:20px;">
<h5>DeepSeek API 配置</h5>
<p>1. 获取API密钥: 访问 <a href="https://platform.deepseek.com/api-keys" target="_blank">DeepSeek API Keys</a></p>
<p>2. 模型选择: deepseek-chat (通用) 或 deepseek-coder (编程)</p>
<p>3. 原创性参数: 控制创造性 (0.1-1.0)</p>
</div>
');
$div->render();
// DeepSeek API Key
$apiKey = new Typecho_Widget_Helper_Form_Element_Text('apiKey', null, null,
_t('API密钥'), _t('在此处输入DeepSeek API密钥'));
$form->addInput($apiKey->addRule('required', _t('API密钥不能为空')));
// 模型选择
$model = new Typecho_Widget_Helper_Form_Element_Select('model',
array(
'deepseek-chat' => 'deepseek-chat (通用写作)',
'deepseek-coder' => 'deepseek-coder (技术文章)'
),
'deepseek-chat',
_t('模型选择'), _t('根据写作内容选择合适模型'));
$form->addInput($model);
// 参数 - 修复浮点数验证问题
$temperature = new Typecho_Widget_Helper_Form_Element_Text('temperature', null, '0.7',
_t('原创性 (0.1-1.0)'), _t('值越高生成内容越有原创性'));
$form->addInput($temperature);
}
/**
* 个人用户的配置面板
*/
public static function personalConfig(Typecho_Widget_Helper_Form $form)
{
// 无需个人配置
}
/**
* 插件输出方法
*/
public static function render()
{
// 获取插件配置
$options = Helper::options()->plugin('AIDeepSeek');
$apiKey = $options->apiKey;
$model = $options->model;
$temperature = $options->temperature;
// 参数格式
$tempValue = is_numeric($temperature) ? floatval($temperature) : 0.7;
if ($tempValue < 0.1 || $tempValue > 1.0) {
$tempValue = 0.7;
}
// 安全输出JavaScript
$apiKeyJS = htmlspecialchars($apiKey ?? '', ENT_QUOTES);
$modelJS = htmlspecialchars($model ?? '', ENT_QUOTES);
$temperatureJS = number_format($tempValue, 1); // 确保格式化为浮点数
// 输出HTML和JavaScript
echo <<<HTML
<style>
.deepseek-panel {
background: #f8f9fa;
padding: 15px;
border-radius: 5px;
margin: 20px 0;
border: 1px solid #e1e4e8;
}
.deepseek-input {
width: 100%;
padding: 8px 12px;
border: 1px solid #ced4da;
border-radius: 4px;
margin-bottom: 10px;
}
.deepseek-btn {
padding: 8px 15px;
border: none;
border-radius: 4px;
cursor: pointer;
font-weight: 500;
transition: all 0.2s;
margin-right: 10px;
}
.deepseek-primary {
background-color: #2563eb;
color: white;
}
.deepseek-primary:hover {
background-color: #1d4ed8;
}
.deepseek-secondary {
background-color: #6c757d;
color: white;
}
.deepseek-secondary:hover {
background-color: #5a6268;
}
.deepseek-spinner {
display: inline-block;
width: 12px;
height: 12px;
border: 2px solid rgba(255,255,255,0.3);
border-radius: 50%;
border-top-color: #fff;
animation: spin 1s linear infinite;
margin-right: 5px;
vertical-align: middle;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
</style>
<script>
// 显示/隐藏AI面板
function toggleAIPanel() {
const panel = document.getElementById("deepseek-controls");
const button = document.getElementById("deepseek-toggle-btn");
if(panel.style.display === "none" || !panel.style.display){
panel.style.display = "block";
button.textContent = "收起AI写作";
} else {
panel.style.display = "none";
button.textContent = "使用AI写作";
}
}
// 显示遮罩层
function showOverlay() {
const overlay = document.getElementById("deepseek-overlay");
overlay.style.display = "block";
}
// 隐藏遮罩层
function hideOverlay() {
const overlay = document.getElementById("deepseek-overlay");
overlay.style.display = "none";
}
// 生成内容
function generateContent() {
const keywords = document.getElementById('deepseek-keywords').value;
const prompt = document.getElementById('deepseek-prompt').value;
const btn = document.getElementById('deepseek-generate-btn');
const originalText = btn.innerHTML;
if(!keywords.trim()) {
alert('请至少输入一个关键词');
return;
}
// 显示加载状态
btn.innerHTML = '<span class="deepseek-spinner"></span> 生成中...';
btn.disabled = true;
showOverlay();
// 组装提示词
const fullPrompt = "你是一位专业作家,请根据以下关键词和要求创作一篇文章:\\n\\n" +
"关键词:" + keywords + "\\n" +
"具体要求:" + (prompt || "生成一篇结构完整、语言流畅的文章");
// 创建请求数据
const requestData = {
model: "{$modelJS}",
messages: [
{role: "system", content: "你是专业的写作助手"},
{role: "user", content: fullPrompt}
],
temperature: {$temperatureJS},
max_tokens: 2000,
stream: false
};
// 发送请求到DeepSeek API
fetch('https://api.deepseek.com/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer {$apiKeyJS}'
},
body: JSON.stringify(requestData)
})
.then(response => {
if(!response.ok) {
throw new Error('API响应错误: ' + response.status);
}
return response.json();
})
.then(data => {
if(data.choices && data.choices.length > 0) {
let content = data.choices[0].message.content;
// 清理Markdown格式
content = content.replace(/【.*?】/g, '');
document.getElementById("deepseek-output").value = content;
} else {
throw new Error('未获取到有效内容: ' + JSON.stringify(data));
}
})
.catch(error => {
alert('请求失败: ' + error.message);
document.getElementById("deepseek-output").value = '生成失败: ' + error.message;
})
.finally(() => {
btn.innerHTML = originalText;
btn.disabled = false;
hideOverlay();
});
}
// 复制内容到剪贴板
function copyContent() {
const textarea = document.getElementById('deepseek-output');
textarea.select();
document.execCommand('copy');
alert('内容已复制到剪贴板');
}
</script>
<!-- 遮罩层 -->
<div id="deepseek-overlay" style="
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
z-index: 9999;
justify-content: center;
align-items: center;
">
<div style="
background: white;
padding: 30px;
border-radius: 8px;
text-align: center;
box-shadow: 0 4px 20px rgba(0,0,0,0.15);
">
<div class="deepseek-spinner" style="
width: 30px;
height: 30px;
border-width: 3px;
display: block;
margin: 0 auto 15px;
"></div>
<p style="font-size: 16px; margin: 0;">DeepSeek AI正在写作...</p>
</div>
</div>
<div style="margin:20px 0;">
<button id="deepseek-toggle-btn" class="deepseek-btn deepseek-primary"
onclick="toggleAIPanel()" style="font-size:14px;">
使用AI写作
</button>
</div>
<div id="deepseek-controls" class="deepseek-panel" style="display:none;">
<div>
<input type="text" placeholder="文章主题/关键词(必填)"
class="deepseek-input" id="deepseek-keywords">
<textarea placeholder="具体要求(可选,如:文章风格、结构、字数等)"
class="deepseek-input" id="deepseek-prompt"
rows="3"></textarea>
<div>
<button id="deepseek-generate-btn" class="deepseek-btn deepseek-primary"
onclick="generateContent()">
生成文章内容
</button>
<button class="deepseek-btn deepseek-secondary"
onclick="copyContent()">
复制到剪贴板
</button>
</div>
</div>
</div>
<div class="deepseek-panel">
<textarea autocomplete="off" id="deepseek-output" class="deepseek-input"
rows="8" placeholder="AI生成的内容将显示在这里"></textarea>
</div>
HTML;
}
/**
* 插件头部输出方法(空实现)
*/
public static function header() {}
/**
* 插件底部输出方法(空实现)
*/
public static function footer() {}
}