From 9904b9bd7813a22ffe07d9e3f6995fb119ff19b7 Mon Sep 17 00:00:00 2001 From: ydy0615 Date: Sun, 5 Apr 2026 11:40:56 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=89=B9=E9=87=8F=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=8F=8Aprompt=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 支持多文件批量上传,一次最多10个 - 新增json/toml/yaml格式支持 - 优化inline补全prompt结构,增加边界决策指南 - size计算包含doc_block内容长度 - 超限时显示警告tooltip --- backend/prompt.py | 320 +++++++++++++++----------- src/components/MilkdownEditor.vue | 367 +++++++++++++++++++++++++----- src/plugins/copilotPlugin.ts | 7 +- src/utils/docBlock.js | 14 ++ src/utils/i18n.js | 31 ++- 5 files changed, 542 insertions(+), 197 deletions(-) diff --git a/backend/prompt.py b/backend/prompt.py index ac56694..b49c3de 100644 --- a/backend/prompt.py +++ b/backend/prompt.py @@ -331,124 +331,111 @@ def build_inline_system_prompt(language_id: str = "markdown") -> str: Return only the insertion text that should be placed between PREFIX and SUFFIX. -Hard constraints you must follow: -1) Output-only contract: -- Output insertion text only. -- No explanations, no meta labels, no wrapper quotes around the whole answer. +CORE PRINCIPLE: Output insertion text only. No explanations, no meta labels, no wrapper quotes. -2) Strict math formatting (KaTeX): -- If you output any math expression, it must be strict KaTeX-compatible math. -- Every formula must be wrapped with either $...$ (inline) or $$...$$ (block). -- Never output bare formulas without $ or $$ wrappers. -- Exception: If CURSOR_IN_FENCED_CODE_BLOCK=true and CURSOR_FENCE_LANGUAGE is latex/tex/katex, - output raw LaTeX without $ or $$ wrappers. +PRIORITY 1: CONTEXT AWARENESS (Read these flags from user prompt) +- CURSOR_IN_FENCED_CODE_BLOCK: Are you inside a code fence? +- CURSOR_FENCE_LANGUAGE: What language is the current fence? +- PREFIX_ENDS_WITH_NEWLINE: Does prefix end with newline? +- SUFFIX_STARTS_WITH_NEWLINE: Does suffix start with newline? +- MERMAID_CONTEXT: Is this a Mermaid diagram context? -3) Strict code formatting: -- Read CURSOR_IN_FENCED_CODE_BLOCK from the user prompt. -- If CURSOR_IN_FENCED_CODE_BLOCK=true: - - You are already inside a fenced code block. - - Never output triple backticks. - - Output code lines only. -- If CURSOR_IN_FENCED_CODE_BLOCK=false: - - Any code output must be in a fenced code block with a language tag: +PRIORITY 2: SPECIALIZED CONTENT RULES + +2.1 Code Block Handling: +If CURSOR_IN_FENCED_CODE_BLOCK=true: + - You are inside a code fence + - Output code lines ONLY (no triple backticks) + - Use single \\n for code line separation + +If CURSOR_IN_FENCED_CODE_BLOCK=false and code needed: + - Wrap code in fenced block with language tag: ```{{language}} - ... + code here ``` - - Do not output code snippets as inline backticks. - - Choose the language tag from context (no default fallback tag instruction). + - Never use inline backticks for code snippets -4) Mermaid-specific completion rules: -- Read CURSOR_FENCE_LANGUAGE and MERMAID_CONTEXT from the user prompt. -- If CURSOR_FENCE_LANGUAGE=mermaid: - - Output Mermaid statements only. - - Never output triple backticks. - - Never output prose explanations. -- If CURSOR_IN_FENCED_CODE_BLOCK=false and MERMAID_CONTEXT=true: - - Output a complete Mermaid fenced block: +2.2 Math Formatting (KaTeX): +- Inline math: wrap with $...$ +- Block math: wrap with $$...$$ +- Never output bare formulas +- Exception: inside latex/tex/katex fence, output raw LaTeX + +2.3 Mermaid Diagrams: +If CURSOR_FENCE_LANGUAGE=mermaid: + - Output Mermaid syntax ONLY + - No backticks, no explanations + +If MERMAID_CONTEXT=true and outside fence: + - Output complete fenced block: ```mermaid - ... + diagram syntax ``` - - Keep Mermaid syntax valid and concise. -- Never mix Mermaid code and explanatory narration in one output. -5) Boundary newline repair: -- Read PREFIX_ENDS_WITH_NEWLINE and SUFFIX_STARTS_WITH_NEWLINE from the user prompt. -- Carefully reason about whether OUTPUT should start or end with a newline. -- If PREFIX lacks a required boundary newline, add it at OUTPUT start. -- If SUFFIX lacks a required boundary newline, add it at OUTPUT end. -- Ensure PREFIX + OUTPUT + SUFFIX is structurally natural. +PRIORITY 3: MARKDOWN STRUCTURE -6) Context stitching: -- Do not repeat text that already appears at the start of SUFFIX. -- Preserve nearby language, tone, punctuation, indentation, and markdown structure. -- Continue existing structures naturally (lists, tables, block quotes, headings). +3.1 Newline Semantics: +- Single \\n: soft break (same paragraph, renders as space or
) +- Double \\n\\n: hard break (new paragraph/block) +- Use \\n\\n for: new paragraphs, before headings, starting lists/tables +- Use \\n for: continuation within blocks (list items, table cells) +- Exception: inside code blocks, use \\n freely for code lines -7) OCR safety: -- PREFIX may include hidden OCR metadata tags like . -- Never output any OCR tag. -- Never output OCR tag fragments such as .""" +3.2 Boundary Management: +Check PREFIX_ENDS_WITH_NEWLINE and SUFFIX_STARTS_WITH_NEWLINE: +- If PREFIX lacks needed newline: start OUTPUT with \\n +- If SUFFIX lacks needed newline: end OUTPUT with \\n +- Common cases requiring leading \\n: + * Starting a list after "Steps:" + * Creating new paragraph after text + * Adding heading after paragraph +- Common cases requiring trailing \\n: + * Before new heading + * End of section + +3.3 Context Stitching: +- Never repeat text from SUFFIX beginning +- Match PREFIX tone, style, indentation +- Continue structures: lists, tables, quotes, headings + +PRIORITY 4: HIDDEN CONTEXT +- OCR metadata like is hidden context +- Never copy OCR tags to output +- Use OCR content as semantic hint only +""" if language_guidance: - system_prompt = f"{system_prompt.rstrip()}\n{language_guidance.strip()}" + system_prompt = f"{system_prompt.rstrip()}\\n{language_guidance.strip()}" return system_prompt.strip() -INLINE_EXAMPLES = """[EX01] Prose continuation +INLINE_EXAMPLES = """=== CATEGORY A: PROSE CONTINUATION === + +[EX01] Simple prose continuation The quick brown fox jumps over the lazy dog. Expected OUTPUT: -moved quietly and then +moved quietly and then -[EX02] Avoid repeating suffix beginning +[EX02] Avoid repeating suffix Our launch plan starts with phase one, followed by phase two. Expected OUTPUT: -careful internal testing before +careful internal testing before +WRONG: phase one starts with (repeats suffix) -[EX03] Continue markdown checklist +=== CATEGORY B: MARKDOWN STRUCTURES === + +[EX03] Continue checklist ## TODO - [ ] Buy milk - [ ] Expected OUTPUT: -Write release notes and share draft with team +Write release notes and share draft with team -[EX04] Cursor outside code block, code must use fenced block -CURSOR_IN_FENCED_CODE_BLOCK=false -Parse this JSON payload in Python: - -Expected OUTPUT: -```python -import json -data = json.loads(payload) -``` - -[EX05] Cursor inside fenced code block, do not output fences -CURSOR_IN_FENCED_CODE_BLOCK=true -```python -def add(a, b): - return - -``` -Expected OUTPUT: -a + b - -[EX06] Inline math must use $...$ -The derivative of x^2 is -. -Expected OUTPUT: -$2x$ - -[EX07] Block math must use $$...$$ -We can write the Gaussian integral as: - -Expected OUTPUT: -$$ -\\int_{-\\infty}^{\\infty} e^{-x^2}\\,dx = \\sqrt{\\pi} -$$ - -[EX08] Prefix misses boundary newline; add newline at output start +[EX04] Start list after header (PREFIX lacks newline) PREFIX_ENDS_WITH_NEWLINE=false Deployment steps: @@ -457,21 +444,7 @@ Expected OUTPUT: - Build artifact - Deploy service -[EX09] Suffix misses boundary newline; add newline at output end -SUFFIX_STARTS_WITH_NEWLINE=false -Summary paragraph complete. -## Next Section -Expected OUTPUT: - - -[EX10] OCR metadata exists but must never be emitted -![whiteboard](img.png) -The relationship is -. -Expected OUTPUT: -$y = mx + b$ - -[EX11] Continue markdown table with correct row shape +[EX05] Continue table row | Name | Score | | --- | --- | | Alice | 92 | @@ -480,30 +453,91 @@ $y = mx + b$ Expected OUTPUT: 88 | -[EX12] Mixed text + math + code in one insertion -CURSOR_IN_FENCED_CODE_BLOCK=false -Use the area formula and provide a tiny JS helper. +[EX06] Start new paragraph +First paragraph ends. Expected OUTPUT: -The area is $A = \\pi r^2$. -```javascript -const area = (r) => Math.PI * r * r; +Second paragraph starts. +WRONG: Second paragraph starts. (missing leading \\n\\n) + +[EX07] Add newline before heading +PREFIX_ENDS_WITH_NEWLINE=false +End of previous section. +## Next Heading +Expected OUTPUT: + +WRONG: (would join with heading without separation) + +=== CATEGORY C: CODE BLOCKS === + +[EX08] Outside fence: wrap code in fence +CURSOR_IN_FENCED_CODE_BLOCK=false +Parse this JSON payload in Python: + +Expected OUTPUT: +```python +import json +data = json.loads(payload) ``` +WRONG: import json\\ndata = json.loads(payload) (no fence) -[EX13] Cursor inside mermaid fence: no backticks, mermaid lines only +[EX09] Inside fence: output code only CURSOR_IN_FENCED_CODE_BLOCK=true +```python +def add(a, b): + return + +``` +Expected OUTPUT: +a + b +WRONG: ```python\\nreturn a + b\\n``` (duplicate fences) + +[EX10] Code inside fence uses single newline +CURSOR_IN_FENCED_CODE_BLOCK=true +```python +def hello(): + +``` +Expected OUTPUT: + print("Hello") + return True +(Note: single \\n between code lines, no markdown rules) + +=== CATEGORY D: MATH === + +[EX11] Inline math +The derivative of x^2 is +. +Expected OUTPUT: +$2x$ +WRONG: 2x (bare formula) + +[EX12] Block math +We can write the Gaussian integral as: + +Expected OUTPUT: +$$ +\\int_{-\\infty}^{\\infty} e^{-x^2}\\,dx = \\sqrt{\\pi} +$$ +WRONG: \\int... (bare formula without $$) + +=== CATEGORY E: MERMAID === + +[EX13] Inside mermaid fence CURSOR_FENCE_LANGUAGE=mermaid +CURSOR_IN_FENCED_CODE_BLOCK=true ```mermaid flowchart TD -A[Start] --> + A[Start] --> ``` Expected OUTPUT: B{Valid?} B -->|Yes| C[Done] +WRONG: ```mermaid\\nB{Valid?}... (duplicate fence) -[EX14] Mermaid context outside fence: return full mermaid block +[EX14] Outside fence with mermaid context CURSOR_IN_FENCED_CODE_BLOCK=false MERMAID_CONTEXT=true Please provide a simple release pipeline diagram. @@ -511,8 +545,18 @@ MERMAID_CONTEXT=true Expected OUTPUT: ```mermaid flowchart LR -Build --> Test --> Deploy -```""" + Build --> Test --> Deploy +``` + +=== CATEGORY F: OCR METADATA === + +[EX15] Use OCR as context, never output +![whiteboard](img.png) +The relationship is +. +Expected OUTPUT: +$y = mx + b$ +WRONG: (OCR tag in output)""" def build_completion_prompts( @@ -552,35 +596,49 @@ def build_completion_prompts( preferences_instruction = f"\nUser Preferences:\n{preferences_instruction}" user_prompt = f"""Current time: {current_time}{location_info}{preferences_instruction} -Reasoning hint: {thinking_level} -Editor language id: {safe_language_id} +Reasoning level: {thinking_level} +Editor language: {safe_language_id} -Completion state flags: +=== STATE FLAGS === - CURSOR_IN_FENCED_CODE_BLOCK: {"true" if cursor_in_fenced_code_block else "false"} - CURSOR_FENCE_LANGUAGE: {cursor_fence_language} - MERMAID_CONTEXT: {"true" if mermaid_context else "false"} - PREFIX_ENDS_WITH_NEWLINE: {"true" if prefix_ends_with_newline else "false"} - SUFFIX_STARTS_WITH_NEWLINE: {"true" if suffix_starts_with_newline else "false"} -Task: -- Produce the best insertion text at the cursor between PREFIX and SUFFIX. -- Keep insertion meaningful and non-empty. -- Keep insertion concise unless structure requires more content. +=== TASK === +Produce the best insertion text between PREFIX and SUFFIX. +Requirements: +- Non-empty and meaningful +- Concise unless structure needs more +- Follows markdown rules in system prompt -Context notes: -- PREFIX may include OCR metadata after image markdown, e.g. ![alt](url) . -- OCR metadata is hidden context and must never be copied into output. -- Preserve local style and formatting. +=== BOUNDARY DECISION GUIDE === -Decision policy: -- Prioritize seamless join: PREFIX + OUTPUT + SUFFIX must read naturally. -- Do not repeat SUFFIX-leading text. -- If uncertain, prefer a complete short phrase/sentence with clear meaning. +Step 1: Check PREFIX_ENDS_WITH_NEWLINE +If false, ask: "Does output need to start on a new line?" + - YES if PREFIX ends with: ":", "steps:", "items:", heading text, or complete sentence before heading + - If YES: start output with \\n -Comprehensive examples: +Step 2: Check SUFFIX_STARTS_WITH_NEWLINE +If false, ask: "Does output need to end with a newline?" + - YES if SUFFIX starts with: heading (##), new paragraph, or list marker + - If YES: end output with \\n + +Step 3: Choose newline type + - Use \\n\\n for: new paragraphs, before headings, starting lists + - Use \\n for: continuing within blocks, list items, table cells + - Exception: inside code fences, use \\n freely + +=== CONTEXT NOTES === +- OCR metadata (e.g., ) is hidden context, never copy to output +- Match PREFIX tone, style, and indentation +- Do not repeat text from SUFFIX beginning + +=== EXAMPLES BY CATEGORY === {INLINE_EXAMPLES} -Now produce the insertion. +=== NOW COMPLETE THE TASK === {recent_prefix} diff --git a/src/components/MilkdownEditor.vue b/src/components/MilkdownEditor.vue index 2e01c27..a38ad2e 100644 --- a/src/components/MilkdownEditor.vue +++ b/src/components/MilkdownEditor.vue @@ -46,7 +46,7 @@ {{ t('uploadFile') }} - + -
- {{ sizeInKB }} KB -
+
+ + + + + + {{ sizeInKB }} KB + +
+ 文档超过32KB限制 + AI补全功能已暂停,建议精简内容或分段处理 +
+
+
@@ -153,6 +178,17 @@
+ +
+
+
+

{{ t('uploading') || '正在上传文件' }}

+

+ {{ uploadProgress.current }} / {{ uploadProgress.total }} +

+

{{ uploadProgress.filename }}

+
+