Skip to content

Commit 900ac65

Browse files
committed
增加AI一键优化提示词
1 parent 54bbc7f commit 900ac65

3 files changed

Lines changed: 255 additions & 23 deletions

File tree

index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ <h2 id="modalTitle">创建智能体</h2>
268268
rows="8"
269269
></textarea>
270270
<div class="textarea-actions">
271-
<button type="button" class="action-btn" title="AI优化">
271+
<button type="button" class="action-btn" id="optimizePromptBtn" title="AI优化提示词">
272272
<i class="fas fa-magic"></i>
273273
</button>
274274
</div>

src/main.ts

Lines changed: 204 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ function bindEvents() {
4444
document.getElementById('themeToggle')?.addEventListener('click', toggleTheme);
4545
document.getElementById('settingsBtn')?.addEventListener('click', openSettings);
4646

47+
// 优化提示词按钮
48+
document.getElementById('optimizePromptBtn')?.addEventListener('click', optimizePrompt);
49+
4750
// 模态框
4851
document.getElementById('closeModal')?.addEventListener('click', closeModal);
4952
document.getElementById('cancelBtn')?.addEventListener('click', closeModal);
@@ -771,25 +774,47 @@ function showConfirmDialog(message: string): Promise<boolean> {
771774
});
772775
}
773776

774-
function showNotification(message: string, type: 'success' | 'error' | 'info' = 'info') {
777+
function showNotification(message: string, type: 'success' | 'error' | 'info' = 'info', options: { center?: boolean, persistent?: boolean } = {}) {
775778
const notification = document.createElement('div');
776779
notification.className = `notification notification-${type}`;
777780
notification.textContent = message;
778781

779-
notification.style.cssText = `
780-
position: fixed;
781-
top: 20px;
782-
right: 20px;
783-
padding: 12px 20px;
784-
border-radius: 8px;
785-
color: white;
786-
font-weight: 500;
787-
z-index: 10000;
788-
max-width: 300px;
789-
word-wrap: break-word;
790-
transition: all 0.3s ease;
791-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
792-
`;
782+
// 根据是否居中显示来设置不同的样式
783+
if (options.center) {
784+
notification.style.cssText = `
785+
position: fixed;
786+
top: 50%;
787+
left: 50%;
788+
transform: translate(-50%, -50%);
789+
padding: 20px 30px;
790+
border-radius: 12px;
791+
color: white;
792+
font-weight: 500;
793+
z-index: 10000;
794+
max-width: 400px;
795+
word-wrap: break-word;
796+
transition: all 0.3s ease;
797+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
798+
backdrop-filter: blur(10px);
799+
font-size: 16px;
800+
text-align: center;
801+
`;
802+
} else {
803+
notification.style.cssText = `
804+
position: fixed;
805+
top: 20px;
806+
right: 20px;
807+
padding: 12px 20px;
808+
border-radius: 8px;
809+
color: white;
810+
font-weight: 500;
811+
z-index: 10000;
812+
max-width: 300px;
813+
word-wrap: break-word;
814+
transition: all 0.3s ease;
815+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
816+
`;
817+
}
793818

794819
switch (type) {
795820
case 'success':
@@ -806,15 +831,172 @@ function showNotification(message: string, type: 'success' | 'error' | 'info' =
806831

807832
document.body.appendChild(notification);
808833

809-
setTimeout(() => {
810-
if (document.body.contains(notification)) {
811-
notification.style.opacity = '0';
812-
notification.style.transform = 'translateX(100%)';
834+
// 如果不是持久化通知,3秒后自动消失
835+
if (!options.persistent) {
836+
setTimeout(() => {
837+
if (document.body.contains(notification)) {
838+
notification.style.opacity = '0';
839+
if (options.center) {
840+
notification.style.transform = 'translate(-50%, -50%) scale(0.9)';
841+
} else {
842+
notification.style.transform = 'translateX(100%)';
843+
}
844+
setTimeout(() => {
845+
if (document.body.contains(notification)) {
846+
document.body.removeChild(notification);
847+
}
848+
}, 300);
849+
}
850+
}, 3000);
851+
}
852+
853+
return notification; // 返回通知元素,以便后续手动移除
854+
}
855+
856+
// 优化提示词功能
857+
async function optimizePrompt() {
858+
const contentTextarea = document.getElementById('content') as HTMLTextAreaElement;
859+
const optimizeBtn = document.getElementById('optimizePromptBtn') as HTMLButtonElement;
860+
861+
if (!contentTextarea || !contentTextarea.value.trim()) {
862+
showNotification('请先输入提示词内容', 'error');
863+
return;
864+
}
865+
866+
const originalContent = contentTextarea.value;
867+
868+
// 显示加载状态
869+
const originalBtnContent = optimizeBtn.innerHTML;
870+
optimizeBtn.disabled = true;
871+
optimizeBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
872+
873+
// 显示居中的持久化通知
874+
const loadingNotification = showNotification('正在优化提示词...', 'info', { center: true, persistent: true });
875+
876+
try {
877+
const optimizedContent = await callZhipuAI(originalContent);
878+
879+
// 移除加载通知
880+
if (document.body.contains(loadingNotification)) {
881+
loadingNotification.style.opacity = '0';
882+
loadingNotification.style.transform = 'translate(-50%, -50%) scale(0.9)';
813883
setTimeout(() => {
814-
if (document.body.contains(notification)) {
815-
document.body.removeChild(notification);
884+
if (document.body.contains(loadingNotification)) {
885+
document.body.removeChild(loadingNotification);
816886
}
817887
}, 300);
818888
}
819-
}, 3000);
889+
890+
if (optimizedContent && optimizedContent.trim() !== originalContent.trim()) {
891+
contentTextarea.value = optimizedContent;
892+
showNotification('提示词优化完成!', 'success');
893+
894+
// 更新token计数
895+
const event = new Event('input');
896+
contentTextarea.dispatchEvent(event);
897+
} else {
898+
showNotification('优化失败,请稍后重试', 'error');
899+
}
900+
} catch (error) {
901+
console.error('优化提示词失败:', error);
902+
903+
// 移除加载通知
904+
if (document.body.contains(loadingNotification)) {
905+
loadingNotification.style.opacity = '0';
906+
loadingNotification.style.transform = 'translate(-50%, -50%) scale(0.9)';
907+
setTimeout(() => {
908+
if (document.body.contains(loadingNotification)) {
909+
document.body.removeChild(loadingNotification);
910+
}
911+
}, 300);
912+
}
913+
914+
showNotification('优化失败: ' + (error as any).message, 'error');
915+
} finally {
916+
// 恢复按钮状态
917+
optimizeBtn.disabled = false;
918+
optimizeBtn.innerHTML = originalBtnContent;
919+
}
920+
}
921+
922+
923+
924+
// 调用智谱AI API
925+
async function callZhipuAI(prompt: string): Promise<string> {
926+
try {
927+
// 直接使用API密钥
928+
const API_KEY = '7645eea5905a4c8b9d668e3e5330b33a.EFzS4nMaR1Ggj60T';
929+
const API_URL = 'https://open.bigmodel.cn/api/paas/v4/chat/completions';
930+
931+
const requestBody = {
932+
model: 'glm-4.5-flash',
933+
messages: [
934+
{
935+
role: 'system',
936+
content: `# 角色 (Role)
937+
你是一位专业的提示词生成专家,擅长运用RTF结构化框架优化提示词。
938+
939+
# 任务 (Task)
940+
根据用户提供的原始提示词,生成一套优化后的中文提示词。
941+
942+
## 要求 (Requirements)
943+
1. 严格按照RTF(Role-Task-Format)结构化框架重构提示词
944+
2. 遵循奥卡姆剃刀原理,确保提示词精简高效,去除所有冗余指令
945+
3. 应用金字塔原理组织指令,确保逻辑清晰、层次分明
946+
4. 在生成行为建议时,参考福格行为模型(B=MAT),确保建议具有可执行性
947+
948+
## 实现目标 (Objectives)
949+
优化后的提示词应能够:
950+
1. 角色定义更加明确和专业
951+
2. 任务描述更加清晰和具体
952+
3. 格式要求更加规范和易执行
953+
4. 整体结构更加合理和高效
954+
5. 能够获得更好的AI响应效果
955+
956+
# 格式 (Format)
957+
1. 使用Markdown格式输出完整的RTF框架提示词
958+
2. 包含明确的Role定义、Task说明和Format要求
959+
3. 提供必要的实现细节和约束条件
960+
4. 直接返回优化后的提示词,不要添加额外的解释`
961+
},
962+
{
963+
role: 'user',
964+
content: `请优化以下提示词:\n\n${prompt}`
965+
}
966+
],
967+
temperature: 0.6,
968+
stream: false
969+
};
970+
971+
const response = await fetch(API_URL, {
972+
method: 'POST',
973+
headers: {
974+
'Content-Type': 'application/json',
975+
'Authorization': `Bearer ${API_KEY}`
976+
},
977+
body: JSON.stringify(requestBody)
978+
});
979+
980+
if (!response.ok) {
981+
const errorText = await response.text();
982+
console.error('API响应错误:', response.status, response.statusText, errorText);
983+
throw new Error(`API请求失败: ${response.status} ${response.statusText} - ${errorText}`);
984+
}
985+
986+
const data = await response.json();
987+
console.log('API响应数据:', data);
988+
989+
if (data.choices && data.choices.length > 0 && data.choices[0].message) {
990+
return data.choices[0].message.content.trim();
991+
} else {
992+
console.error('API返回数据格式错误:', data);
993+
throw new Error('API返回数据格式错误');
994+
}
995+
} catch (error) {
996+
console.error('调用智谱AI API失败:', error);
997+
if (error instanceof Error) {
998+
throw error;
999+
}
1000+
throw new Error('调用智谱AI API时发生未知错误');
1001+
}
8201002
}

src/styles.css

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,3 +1255,53 @@ body {
12551255
min-width: auto;
12561256
}
12571257
}
1258+
1259+
/* 优化按钮样式增强 */
1260+
.textarea-actions .action-btn {
1261+
display: flex;
1262+
align-items: center;
1263+
justify-content: center;
1264+
width: 32px;
1265+
height: 32px;
1266+
border: 1px solid var(--border);
1267+
border-radius: var(--radius-md);
1268+
background: var(--card);
1269+
color: var(--primary);
1270+
cursor: pointer;
1271+
transition: all 0.2s ease;
1272+
font-size: 14px;
1273+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
1274+
}
1275+
1276+
.textarea-actions .action-btn:hover {
1277+
background: var(--primary);
1278+
color: var(--text-on-primary);
1279+
transform: scale(1.05);
1280+
box-shadow: 0 4px 8px rgba(0, 123, 255, 0.2);
1281+
}
1282+
1283+
.textarea-actions .action-btn:active {
1284+
transform: scale(0.95);
1285+
}
1286+
1287+
.textarea-actions .action-btn:disabled {
1288+
opacity: 0.6;
1289+
cursor: not-allowed;
1290+
transform: none;
1291+
background: var(--light);
1292+
color: var(--muted);
1293+
}
1294+
1295+
.textarea-actions .action-btn i.fa-spinner {
1296+
animation: spin 1s linear infinite;
1297+
}
1298+
1299+
@keyframes spin {
1300+
from { transform: rotate(0deg); }
1301+
to { transform: rotate(360deg); }
1302+
}
1303+
1304+
/* 确保textarea容器有足够的padding来容纳按钮 */
1305+
.textarea-container .field-textarea {
1306+
padding-right: 50px;
1307+
}

0 commit comments

Comments
 (0)