diff --git a/src/views/contextCompress.ts b/src/views/contextCompress.ts new file mode 100644 index 0000000..1e68b00 --- /dev/null +++ b/src/views/contextCompress.ts @@ -0,0 +1,249 @@ +/** + * 上下文压缩组件 + * 提供上下文使用情况显示和压缩功能 + */ + +/** + * 获取上下文压缩组件的 HTML 内容 + */ +export function getContextCompressContent(): string { + return ` + +
+
+
+ + + + + + + + + + + + + + + +
+ 0% +
+ + +
+
+
+ 0k / 200k 已用上下文 +
+ +
+
+
+ `; +} + +/** + * 获取上下文压缩组件的样式 + */ +export function getContextCompressStyles(): string { + return ` + /* 上下文显示样式 */ + .context-display { + display: flex; + flex-direction: column; + align-items: center; + position: relative; + } + .context-info { + display: flex; + align-items: center; + gap: 6px; + height: 40px; + background: transparent; + border: none; + border-radius: 4px; + font-size: 14px; + font-weight: 500; + color: var(--vscode-foreground); + transition: opacity 0.3s ease; + box-shadow: none; + position: relative; + overflow: hidden; + cursor: pointer; + } + .context-info:hover { + opacity: 0.8; + } + .database-icon { + display: flex; + align-items: center; + justify-content: center; + width: 12px; + height: 12px; + position: relative; + } + .db-svg { + width: 100%; + height: 100%; + } + .db-body { + fill: #ffffff; + } + .db-fill { + fill: #409eff; + transition: all 0.3s ease; + } + .context-percentage { + font-size: 14px; + font-weight: 500; + color: var(--vscode-foreground); + text-align: right; + } + /* 上下文信息弹窗样式 */ + .context-panel { + position: absolute; + bottom: 100%; + left: 50%; + transform: translateX(-50%); + margin-bottom: 8px; + z-index: 1000; + animation: fadeInUp 0.2s ease-out; + display: none; + } + .context-panel.active { + display: block; + } + .context-panel::after { + content: ""; + position: absolute; + bottom: -6px; + left: 50%; + transform: translateX(-50%); + width: 0; + height: 0; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-top: 6px solid #ffffff; + } + .context-panel-content { + background: #ffffff; + border: 1px solid rgba(0, 0, 0, 0.1); + border-radius: 8px; + padding: 12px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); + backdrop-filter: blur(10px); + min-width: 160px; + } + .context-info-text { + font-size: 12px; + color: #374151; + text-align: center; + margin-bottom: 8px; + white-space: nowrap; + } + .compress-button { + width: 100%; + background: linear-gradient(145deg, #3b82f6 0%, #1d4ed8 100%); + border: 1px solid rgba(59, 130, 246, 0.3); + border-radius: 6px; + color: white; + font-size: 12px; + font-weight: 500; + padding: 6px 12px; + cursor: pointer; + transition: all 0.2s ease; + } + .compress-button:hover { + background: linear-gradient(145deg, #2563eb 0%, #1e40af 100%); + transform: translateY(-1px); + box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3); + } + .compress-button:active { + transform: translateY(0); + } + @keyframes fadeInUp { + from { + opacity: 0; + transform: translateX(-50%) translateY(10px); + } + to { + opacity: 1; + transform: translateX(-50%) translateY(0); + } + } + `; +} + +/** + * 获取上下文压缩组件的脚本 + */ +export function getContextCompressScript(): string { + return ` + // 上下文面板相关函数 + function toggleContextPanel() { + const contextPanel = document.getElementById('contextPanel'); + if (contextPanel) { + if (contextPanel.classList.contains('active')) { + contextPanel.classList.remove('active'); + } else { + contextPanel.classList.add('active'); + } + } + } + + function compressConversation() { + // 发送压缩会话请求 + vscode.postMessage({ command: 'compressConversation' }); + addMessage('正在压缩会话...', 'bot'); + + // 关闭面板 + const contextPanel = document.getElementById('contextPanel'); + if (contextPanel) { + contextPanel.classList.remove('active'); + } + } + + function updateContextDisplay(currentTokens, maxTokens) { + const percentage = Math.min(Math.round((currentTokens / maxTokens) * 100), 100); + + // 更新百分比显示 + const contextPercentage = document.getElementById('contextPercentage'); + if (contextPercentage) { + contextPercentage.textContent = percentage + '%'; + } + + // 更新详细信息 + const contextInfoText = document.getElementById('contextInfoText'); + if (contextInfoText) { + const currentK = Math.round((currentTokens / 1000) * 10) / 10; + const maxK = Math.round(maxTokens / 1000); + contextInfoText.textContent = \`\${currentK}k / \${maxK}k 已用上下文\`; + } + + // 更新SVG填充效果(从下往上填充) + const fillRect = document.getElementById('fillRect'); + if (fillRect) { + const fillHeight = (1024 * percentage) / 100; + const fillY = 1024 - fillHeight; + fillRect.setAttribute('y', fillY.toString()); + fillRect.setAttribute('height', fillHeight.toString()); + } + } + + // 点击外部关闭上下文面板 + document.addEventListener('click', (event) => { + const contextDisplay = document.querySelector('.context-display'); + const contextPanel = document.getElementById('contextPanel'); + + if (contextPanel && contextPanel.classList.contains('active') && contextDisplay) { + if (!contextDisplay.contains(event.target)) { + contextPanel.classList.remove('active'); + } + } + }); + `; +} diff --git a/src/views/inputArea.ts b/src/views/inputArea.ts index 8c9ba5c..f7646e3 100644 --- a/src/views/inputArea.ts +++ b/src/views/inputArea.ts @@ -9,6 +9,11 @@ import { getContextButtonStyles, getContextButtonScript } from "./contextButton"; +import { + getContextCompressContent, + getContextCompressStyles, + getContextCompressScript +} from "./contextCompress"; /** * 获取输入区域的 HTML 内容 @@ -60,41 +65,7 @@ export function getInputAreaContent(): string { ${getModelSelectorContent()}
- -
-
-
- - - - - - - - - - - - - - - -
- 0% -
- - -
-
-
- 0k / 200k 已用上下文 -
- -
-
-
+ ${getContextCompressContent()}
@@ -120,6 +91,7 @@ export function getInputAreaStyles(): string { return ` ${getModelSelectorStyles()} ${getContextButtonStyles()} + ${getContextCompressStyles()} .input-area { border-top: 1px solid var(--vscode-panel-border); padding-top: 15px; @@ -397,130 +369,6 @@ export function getInputAreaStyles(): string { display: flex; align-items: flex-end; } - /* 上下文显示样式 */ - .context-display { - display: flex; - flex-direction: column; - align-items: center; - position: relative; - } - .context-info { - display: flex; - align-items: center; - gap: 6px; - height: 40px; - background: transparent; - border: none; - border-radius: 4px; - font-size: 14px; - font-weight: 500; - color: var(--vscode-foreground); - transition: opacity 0.3s ease; - box-shadow: none; - position: relative; - overflow: hidden; - cursor: pointer; - } - .context-info:hover { - opacity: 0.8; - } - .database-icon { - display: flex; - align-items: center; - justify-content: center; - width: 12px; - height: 12px; - position: relative; - } - .db-svg { - width: 100%; - height: 100%; - } - .db-body { - fill: #ffffff; - } - .db-fill { - fill: #409eff; - transition: all 0.3s ease; - } - .context-percentage { - font-size: 14px; - font-weight: 500; - color: var(--vscode-foreground); - text-align: right; - } - /* 上下文信息弹窗样式 */ - .context-panel { - position: absolute; - bottom: 100%; - left: 50%; - transform: translateX(-50%); - margin-bottom: 8px; - z-index: 1000; - animation: fadeInUp 0.2s ease-out; - display: none; - } - .context-panel.active { - display: block; - } - .context-panel::after { - content: ""; - position: absolute; - bottom: -6px; - left: 50%; - transform: translateX(-50%); - width: 0; - height: 0; - border-left: 6px solid transparent; - border-right: 6px solid transparent; - border-top: 6px solid #ffffff; - } - .context-panel-content { - background: #ffffff; - border: 1px solid rgba(0, 0, 0, 0.1); - border-radius: 8px; - padding: 12px; - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); - backdrop-filter: blur(10px); - min-width: 160px; - } - .context-info-text { - font-size: 12px; - color: #374151; - text-align: center; - margin-bottom: 8px; - white-space: nowrap; - } - .compress-button { - width: 100%; - background: linear-gradient(145deg, #3b82f6 0%, #1d4ed8 100%); - border: 1px solid rgba(59, 130, 246, 0.3); - border-radius: 6px; - color: white; - font-size: 12px; - font-weight: 500; - padding: 6px 12px; - cursor: pointer; - transition: all 0.2s ease; - } - .compress-button:hover { - background: linear-gradient(145deg, #2563eb 0%, #1e40af 100%); - transform: translateY(-1px); - box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3); - } - .compress-button:active { - transform: translateY(0); - } - @keyframes fadeInUp { - from { - opacity: 0; - transform: translateX(-50%) translateY(10px); - } - to { - opacity: 1; - transform: translateX(-50%) translateY(0); - } - } `; } @@ -531,6 +379,7 @@ export function getInputAreaScript(): string { return ` ${getModelSelectorScript()} ${getContextButtonScript()} + ${getContextCompressScript()} // 自动调整 textarea 高度 function autoResizeTextarea() { @@ -689,68 +538,5 @@ export function getInputAreaScript(): string { isOptimized = false; originalText = ''; } - - // 上下文面板相关函数 - function toggleContextPanel() { - const contextPanel = document.getElementById('contextPanel'); - if (contextPanel) { - if (contextPanel.classList.contains('active')) { - contextPanel.classList.remove('active'); - } else { - contextPanel.classList.add('active'); - } - } - } - - function compressConversation() { - // 发送压缩会话请求 - vscode.postMessage({ command: 'compressConversation' }); - addMessage('正在压缩会话...', 'bot'); - - // 关闭面板 - const contextPanel = document.getElementById('contextPanel'); - if (contextPanel) { - contextPanel.classList.remove('active'); - } - } - - function updateContextDisplay(currentTokens, maxTokens) { - const percentage = Math.min(Math.round((currentTokens / maxTokens) * 100), 100); - - // 更新百分比显示 - const contextPercentage = document.getElementById('contextPercentage'); - if (contextPercentage) { - contextPercentage.textContent = percentage + '%'; - } - - // 更新详细信息 - const contextInfoText = document.getElementById('contextInfoText'); - if (contextInfoText) { - const currentK = Math.round((currentTokens / 1000) * 10) / 10; - const maxK = Math.round(maxTokens / 1000); - contextInfoText.textContent = \`\${currentK}k / \${maxK}k 已用上下文\`; - } - - // 更新SVG填充效果(从下往上填充) - const fillRect = document.getElementById('fillRect'); - if (fillRect) { - const fillHeight = (1024 * percentage) / 100; - const fillY = 1024 - fillHeight; - fillRect.setAttribute('y', fillY.toString()); - fillRect.setAttribute('height', fillHeight.toString()); - } - } - - // 点击外部关闭上下文面板 - document.addEventListener('click', (event) => { - const contextDisplay = document.querySelector('.context-display'); - const contextPanel = document.getElementById('contextPanel'); - - if (contextPanel && contextPanel.classList.contains('active') && contextDisplay) { - if (!contextDisplay.contains(event.target)) { - contextPanel.classList.remove('active'); - } - } - }); `; }