v0.16.2: 优化附件提示词格式 — 去base64/真实文件名/用户文字前置
This commit is contained in:
@@ -14,7 +14,7 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="https://img.shields.io/badge/version-v0.16.1-E8734A?style=flat-square" alt="version">
|
<img src="https://img.shields.io/badge/version-v0.16.2-E8734A?style=flat-square" alt="version">
|
||||||
<img src="https://img.shields.io/badge/electron-33+-47848F?style=flat-square&logo=electron" alt="electron">
|
<img src="https://img.shields.io/badge/electron-33+-47848F?style=flat-square&logo=electron" alt="electron">
|
||||||
<img src="https://img.shields.io/badge/typescript-5.7+-3178C6?style=flat-square&logo=typescript" alt="typescript">
|
<img src="https://img.shields.io/badge/typescript-5.7+-3178C6?style=flat-square&logo=typescript" alt="typescript">
|
||||||
<img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" alt="license">
|
<img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" alt="license">
|
||||||
@@ -253,7 +253,7 @@ npm start
|
|||||||
ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ npm run dist
|
ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ npm run dist
|
||||||
```
|
```
|
||||||
|
|
||||||
产出:`release/Metona Ollama Setup v0.16.1.exe`
|
产出:`release/Metona Ollama Setup v0.16.2.exe`
|
||||||
|
|
||||||
## 🛠️ 常用命令
|
## 🛠️ 常用命令
|
||||||
|
|
||||||
@@ -501,7 +501,7 @@ npm start
|
|||||||
ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ npm run dist
|
ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ npm run dist
|
||||||
```
|
```
|
||||||
|
|
||||||
Output: `release/Metona Ollama Setup v0.16.1.exe`
|
Output: `release/Metona Ollama Setup v0.16.2.exe`
|
||||||
|
|
||||||
## 🛠️ Common Commands
|
## 🛠️ Common Commands
|
||||||
|
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "metona-ollama-desktop",
|
"name": "metona-ollama-desktop",
|
||||||
"version": "0.16.1",
|
"version": "0.16.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "metona-ollama-desktop",
|
"name": "metona-ollama-desktop",
|
||||||
"version": "0.16.1",
|
"version": "0.16.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ffmpeg-static": "^5.2.0",
|
"ffmpeg-static": "^5.2.0",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "metona-ollama-desktop",
|
"name": "metona-ollama-desktop",
|
||||||
"version": "0.16.1",
|
"version": "0.16.2",
|
||||||
"description": "Metona Ollama - TypeScript + Electron 桌面 AI 聊天客户端",
|
"description": "Metona Ollama - TypeScript + Electron 桌面 AI 聊天客户端",
|
||||||
"main": "dist/main/main.js",
|
"main": "dist/main/main.js",
|
||||||
"author": "thzxx",
|
"author": "thzxx",
|
||||||
|
|||||||
+1
-1
@@ -101,7 +101,7 @@ export function createMenu(): void {
|
|||||||
dialog.showMessageBox(mainWindow!, {
|
dialog.showMessageBox(mainWindow!, {
|
||||||
type: 'info',
|
type: 'info',
|
||||||
title: '关于 Metona Ollama',
|
title: '关于 Metona Ollama',
|
||||||
message: 'Metona Ollama Desktop v0.16.1',
|
message: 'Metona Ollama Desktop v0.16.2',
|
||||||
detail: 'TypeScript + Electron Ollama AI 聊天客户端\n\nhttps://gitee.com/thzxx/metona-ollama',
|
detail: 'TypeScript + Electron Ollama AI 聊天客户端\n\nhttps://gitee.com/thzxx/metona-ollama',
|
||||||
icon: getIconPath()
|
icon: getIconPath()
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -925,17 +925,7 @@ function buildPlanConfirmHtml(plan: string, steps: string[]): string {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Base64 编码(支持 UTF-8) */
|
function buildFileContentParts(fileContents: Array<{ name: string; language: string; content: string }>): string[] {
|
||||||
function base64Encode(str: string): string {
|
|
||||||
const bytes = new TextEncoder().encode(str);
|
|
||||||
let binary = '';
|
|
||||||
for (let i = 0; i < bytes.length; i++) {
|
|
||||||
binary += String.fromCharCode(bytes[i]);
|
|
||||||
}
|
|
||||||
return btoa(binary);
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildFileContentParts(fileContents: Array<{ language: string; content: string }>): string[] {
|
|
||||||
const numCtx = state.get<number>(KEYS.NUM_CTX, 24576);
|
const numCtx = state.get<number>(KEYS.NUM_CTX, 24576);
|
||||||
const fileBudget = Math.floor(numCtx * FILE_TOKEN_BUDGET_RATIO);
|
const fileBudget = Math.floor(numCtx * FILE_TOKEN_BUDGET_RATIO);
|
||||||
let usedTokens = 0;
|
let usedTokens = 0;
|
||||||
@@ -963,10 +953,9 @@ function buildFileContentParts(fileContents: Array<{ language: string; content:
|
|||||||
usedTokens += finalTokens;
|
usedTokens += finalTokens;
|
||||||
|
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
file_name: `文件 ${i + 1}/${fileContents.length}`,
|
file_name: f.name,
|
||||||
file_type: lang,
|
file_type: lang,
|
||||||
context_encode: 'base64',
|
context: text,
|
||||||
context: base64Encode(text),
|
|
||||||
});
|
});
|
||||||
}).filter(Boolean);
|
}).filter(Boolean);
|
||||||
}
|
}
|
||||||
@@ -1127,10 +1116,12 @@ async function sendMessageWithAgentLoop(text: string, currentSession: ChatSessio
|
|||||||
// ── 聊天卡片:只显示用户自己的文字 + 附件视觉预览(缩略图/文件卡片/视频帧),不含代码生成的文本标记 ──
|
// ── 聊天卡片:只显示用户自己的文字 + 附件视觉预览(缩略图/文件卡片/视频帧),不含代码生成的文本标记 ──
|
||||||
const displayContent = text || '';
|
const displayContent = text || '';
|
||||||
|
|
||||||
// ── Ollama API 用:附件 JSON 结构化数据在前,用户文字消息始终在最后 ──
|
// ── Ollama API 用:用户文字消息在最前,附件 JSON 结构化数据在后 ──
|
||||||
const apiParts: string[] = [];
|
const apiParts: string[] = [];
|
||||||
|
// 用户文字始终放最前
|
||||||
|
if (text) apiParts.push(text);
|
||||||
if (userFiles.length > 0) {
|
if (userFiles.length > 0) {
|
||||||
const fileContents = pendingFiles.map(f => ({ language: f.language, content: f.content }));
|
const fileContents = pendingFiles.map(f => ({ name: f.name, language: f.language, content: f.content }));
|
||||||
const fileParts = buildFileContentParts(fileContents);
|
const fileParts = buildFileContentParts(fileContents);
|
||||||
apiParts.push(...fileParts);
|
apiParts.push(...fileParts);
|
||||||
logInfo('📄 文件内容已注入', `${fileParts.length} 段, 共 ${fileContents.reduce((s, f) => s + f.content.length, 0)} 字符`);
|
logInfo('📄 文件内容已注入', `${fileParts.length} 段, 共 ${fileContents.reduce((s, f) => s + f.content.length, 0)} 字符`);
|
||||||
@@ -1150,8 +1141,7 @@ async function sendMessageWithAgentLoop(text: string, currentSession: ChatSessio
|
|||||||
apiParts.push(JSON.stringify({
|
apiParts.push(JSON.stringify({
|
||||||
file_name: v.name,
|
file_name: v.name,
|
||||||
file_type: v.name.split('.').pop() || 'video',
|
file_type: v.name.split('.').pop() || 'video',
|
||||||
context_encode: 'base64',
|
context: JSON.stringify({
|
||||||
context: base64Encode(JSON.stringify({
|
|
||||||
frame_count: v.count,
|
frame_count: v.count,
|
||||||
fps: 1,
|
fps: 1,
|
||||||
duration: Math.round(v.dur),
|
duration: Math.round(v.dur),
|
||||||
@@ -1161,13 +1151,11 @@ async function sendMessageWithAgentLoop(text: string, currentSession: ChatSessio
|
|||||||
timestamp: f.timestampSeconds,
|
timestamp: f.timestampSeconds,
|
||||||
image_index: imageStart + fi,
|
image_index: imageStart + fi,
|
||||||
})),
|
})),
|
||||||
})),
|
}),
|
||||||
}));
|
}));
|
||||||
imageStart += v.count;
|
imageStart += v.count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 用户文字始终放最后
|
|
||||||
if (text) apiParts.push(text);
|
|
||||||
apiContentForModel = apiParts.join('\n\n');
|
apiContentForModel = apiParts.join('\n\n');
|
||||||
|
|
||||||
const msg: ChatMessage = {
|
const msg: ChatMessage = {
|
||||||
@@ -1184,7 +1172,7 @@ async function sendMessageWithAgentLoop(text: string, currentSession: ChatSessio
|
|||||||
}
|
}
|
||||||
if (userFiles.length > 0) {
|
if (userFiles.length > 0) {
|
||||||
msg.files = userFiles;
|
msg.files = userFiles;
|
||||||
msg._fileContents = pendingFiles.map(f => ({ language: f.language, content: f.content }));
|
msg._fileContents = pendingFiles.map(f => ({ name: f.name, language: f.language, content: f.content }));
|
||||||
}
|
}
|
||||||
msgsToAdd.push(msg);
|
msgsToAdd.push(msg);
|
||||||
} else if (text || pendingFiles.length > 0) {
|
} else if (text || pendingFiles.length > 0) {
|
||||||
@@ -1196,7 +1184,7 @@ async function sendMessageWithAgentLoop(text: string, currentSession: ChatSessio
|
|||||||
};
|
};
|
||||||
if (userFiles.length > 0) {
|
if (userFiles.length > 0) {
|
||||||
msg.files = userFiles;
|
msg.files = userFiles;
|
||||||
msg._fileContents = pendingFiles.map(f => ({ language: f.language, content: f.content }));
|
msg._fileContents = pendingFiles.map(f => ({ name: f.name, language: f.language, content: f.content }));
|
||||||
}
|
}
|
||||||
msgsToAdd.push(msg);
|
msgsToAdd.push(msg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
<div class="header-left">
|
<div class="header-left">
|
||||||
<img class="logo" src="./assets/icons/llama.png" alt="logo" />
|
<img class="logo" src="./assets/icons/llama.png" alt="logo" />
|
||||||
<span class="app-title">Metona Ollama</span>
|
<span class="app-title">Metona Ollama</span>
|
||||||
<span class="app-version">v0.16.1</span>
|
<span class="app-version">v0.16.2</span>
|
||||||
<button class="icon-btn help-btn" id="btnHelp" title="使用帮助">
|
<button class="icon-btn help-btn" id="btnHelp" title="使用帮助">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
<circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/>
|
<circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/>
|
||||||
|
|||||||
Vendored
+1
@@ -97,6 +97,7 @@ export interface ChatFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface FileContent {
|
export interface FileContent {
|
||||||
|
name: string;
|
||||||
language: string;
|
language: string;
|
||||||
content: string;
|
content: string;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user