Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ data.json

# Test Environment
.env.test
.env
24 changes: 9 additions & 15 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/components/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,8 @@ ${chatContent}`;
onAddImage={(files: File[]) => setSelectedImages((prev) => [...prev, ...files])}
setSelectedImages={setSelectedImages}
disableModelSwitch={selectedChain === ChainType.PROJECT_CHAIN}
chatHistory={chatHistory}
chainManager={chainManager}
/>
</div>
</>
Expand Down
96 changes: 96 additions & 0 deletions src/components/chat-components/ChatInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,24 @@ import { CustomPromptProcessor } from "@/customPromptProcessor";
import { COPILOT_TOOL_NAMES } from "@/LLMProviders/intentAnalyzer";
import { Mention } from "@/mentions/Mention";
import { getModelKeyFromModel, useSettingsValue } from "@/settings/model";
import { ChatMessage } from "@/sharedState";
import { getToolDescription } from "@/tools/toolManager";
import { checkModelApiKey, err2String, extractNoteFiles, isNoteTitleUnique } from "@/utils";
import { enhancePrompt } from "@/promptEnhancer";
import { getSettings } from "@/settings/model";
import ChainManager from "@/LLMProviders/chainManager";
import {
ArrowBigUp,
ChevronDown,
Command,
CornerDownLeft,
Image,
Loader2,
Sparkles,
StopCircle,
X,
} from "lucide-react";

import { App, Notice, Platform, TFile } from "obsidian";
import React, {
forwardRef,
Expand Down Expand Up @@ -68,6 +74,8 @@ interface ChatInputProps {
onAddImage: (files: File[]) => void;
setSelectedImages: React.Dispatch<React.SetStateAction<File[]>>;
disableModelSwitch?: boolean;
chatHistory?: ChatMessage[];
chainManager?: ChainManager;
}

const ChatInput = forwardRef<{ focus: () => void }, ChatInputProps>(
Expand All @@ -88,6 +96,8 @@ const ChatInput = forwardRef<{ focus: () => void }, ChatInputProps>(
onAddImage,
setSelectedImages,
disableModelSwitch,
chatHistory = [],
chainManager,
},
ref
) => {
Expand All @@ -107,6 +117,7 @@ const ChatInput = forwardRef<{ focus: () => void }, ChatInputProps>(
const isCopilotPlus =
currentChain === ChainType.COPILOT_PLUS_CHAIN || currentChain === ChainType.PROJECT_CHAIN;
const [loadingMessageIndex, setLoadingMessageIndex] = useState(0);
const [isEnhancing, setIsEnhancing] = useState(false);
const loadingMessages = [
"Loading the project context...",
"Processing context files...",
Expand Down Expand Up @@ -169,6 +180,76 @@ const ChatInput = forwardRef<{ focus: () => void }, ChatInputProps>(
});
};

const handleEnhancePrompt = async () => {
if (!inputMessage.trim()) {
new Notice("请先输入提示词");
return;
}

if (isEnhancing) {
return;
}

setIsEnhancing(true);

try {
// 获取设置
const settings = getSettings();

// 收集添加的上下文
let addedContext = "";

// 添加上下文笔记内容
if (contextNotes.length > 0) {
const contextContents = await Promise.all(
contextNotes.map(async (note) => {
const content = await app.vault.read(note);
return `【${note.basename}】\n${content}`;
})
);
addedContext += contextContents.join("\n\n");
}

// 添加当前活动笔记内容(如果启用)
if (includeActiveNote && currentActiveNote) {
const activeNoteContent = await app.vault.read(currentActiveNote);
if (addedContext) addedContext += "\n\n";
addedContext += `【当前笔记:${currentActiveNote.basename}】\n${activeNoteContent}`;
}

// 添加 URL 上下文
if (contextUrls.length > 0) {
if (addedContext) addedContext += "\n\n";
addedContext += `【相关链接】\n${contextUrls.join("\n")}`;
}

// 调用增强功能
if (!chainManager) {
throw new Error("ChainManager 未初始化");
}

const result = await enhancePrompt({
originalPrompt: inputMessage,
chatHistory: chatHistory,
addedContext: addedContext || "(无额外上下文)",
chainManager: chainManager,
customInstructionTemplate: settings.promptEnhancementTemplate,
});

if (result.success) {
setInputMessage(result.enhancedPrompt);
new Notice("提示词已成功优化!");
} else {
throw new Error(result.error || "增强失败");
}
} catch (error) {
console.error("Prompt enhancement failed:", error);
new Notice(`优化失败: ${error instanceof Error ? error.message : "未知错误"}`);
} finally {
setIsEnhancing(false);
}
};

const handleInputChange = async (event: React.ChangeEvent<HTMLTextAreaElement>) => {
const inputValue = event.target.value;
const cursorPos = event.target.selectionStart;
Expand Down Expand Up @@ -590,6 +671,21 @@ const ChatInput = forwardRef<{ focus: () => void }, ChatInputProps>(
</Button>
) : (
<>
{/* 增强按钮 */}
<Button
variant="ghost2"
size="fit"
onClick={handleEnhancePrompt}
disabled={isEnhancing || !inputMessage.trim()}
title="增强提示词"
>
{isEnhancing ? (
<Loader2 className="tw-size-4 tw-animate-spin" />
) : (
<Sparkles className="tw-size-4" />
)}
</Button>

{isCopilotPlus && (
<Button
variant="ghost2"
Expand Down
43 changes: 43 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,49 @@ export const DEFAULT_SETTINGS: CopilotSettings = {
lastDismissedVersion: null,
passMarkdownImages: true,
enableCustomPromptTemplating: true,
promptEnhancementTemplate: `You are an expert AI prompt engineer specializing in transforming basic user instructions into high-performance, structured prompts optimized for AI systems.

## Context Analysis
**Conversation History:** {{history}}
**Additional Context:** {{context}}
**Original Prompt:** {{prompt}}

## Enhancement Protocol

Execute ALL enhancement directives below:

### 1. ROLE SPECIFICATION
- Assign a specific professional role identity (e.g., "As a senior software architect", "As a technical documentation specialist")
- Define expertise domain and capability boundaries
- Establish authoritative context for the task

### 2. TASK DECOMPOSITION
- Break down the request into 2-4 sequential, executable steps
- Define clear success criteria for each step
- Specify dependencies and logical flow between steps

### 3. OUTPUT STANDARDIZATION
- Specify exact output format (structured lists, code blocks, paragraphs, etc.)
- Define length requirements and detail level
- Set language, tone, and technical complexity standards
- Include formatting and presentation requirements

### 4. QUALITY ASSURANCE
- Establish measurable quality benchmarks
- Define error prevention protocols
- Specify validation criteria and success metrics
- Include edge case handling requirements

### 5. CONTEXT INTEGRATION
- Leverage conversation history for continuity and personalization
- Incorporate additional context to enhance task specificity
- Ensure coherent integration with existing workflow

## Critical Requirements
- Enhanced prompt MUST be 3-5x more detailed than original
- Focus on actionable, executable instructions
- Eliminate ambiguity through precise specification
- Output the final optimized prompt directly without explanations or prefixes`,
};

export const EVENT_NAMES = {
Expand Down
Loading