支持 OCR

This commit is contained in:
锦恢 2025-04-25 21:42:30 +08:00
parent ca64ce040f
commit 5fc7a9e468
9 changed files with 109 additions and 7 deletions

View File

@ -13,7 +13,7 @@
<script lang="ts"> <script lang="ts">
import { defineComponent, ref, watch, nextTick } from 'vue'; import { defineComponent, ref, watch, nextTick } from 'vue';
import { debounce } from 'lodash-es'; import { debounce } from 'lodash';
export default defineComponent({ export default defineComponent({
name: 'KInputObject', name: 'KInputObject',

View File

@ -80,7 +80,7 @@ export function doConnect() {
const { code, msg } = data; const { code, msg } = data;
connectionResult.success = (code === 200); connectionResult.success = (code === 200);
if (code === 200) { if (code === 200) {
const res = await getServerVersion() as { name: string, version: string }; const res = await getServerVersion() as { name: string, version: string };
connectionResult.serverInfo.name = res.name || ''; connectionResult.serverInfo.name = res.name || '';
connectionResult.serverInfo.version = res.version || ''; connectionResult.serverInfo.version = res.version || '';

View File

@ -23,6 +23,7 @@
"sqlite": "^5.1.1", "sqlite": "^5.1.1",
"sqlite3": "^5.1.7", "sqlite3": "^5.1.7",
"tesseract.js": "^6.0.1", "tesseract.js": "^6.0.1",
"uuid": "^11.1.0",
"ws": "^8.18.1" "ws": "^8.18.1"
}, },
"devDependencies": { "devDependencies": {
@ -4085,6 +4086,19 @@
"node": ">= 0.4.0" "node": ">= 0.4.0"
} }
}, },
"node_modules/uuid": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz",
"integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"license": "MIT",
"bin": {
"uuid": "dist/esm/bin/uuid"
}
},
"node_modules/v8-compile-cache-lib": { "node_modules/v8-compile-cache-lib": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",

View File

@ -44,6 +44,7 @@
"sqlite": "^5.1.1", "sqlite": "^5.1.1",
"sqlite3": "^5.1.7", "sqlite3": "^5.1.7",
"tesseract.js": "^6.0.1", "tesseract.js": "^6.0.1",
"uuid": "^11.1.0",
"ws": "^8.18.1" "ws": "^8.18.1"
} }
} }

View File

@ -18,7 +18,7 @@ export class LocalDB<T extends Entity> {
private async init() { private async init() {
// 默认存储在用户目录的 .openmcp 目录下 // 默认存储在用户目录的 .openmcp 目录下
const homedir = os.homedir(); const homedir = os.homedir();
const filename = path.join(homedir, '.openmcp', 'db.sqlite'); const filename = path.join(homedir, '.openmcp', 'index.db');
this.db = await open({ this.db = await open({
filename, filename,

View File

@ -0,0 +1,85 @@
import * as os from 'os';
import * as path from 'path';
import * as fs from 'fs';
import { v4 as uuidv4 } from 'uuid';
export function saveBase64ImageData(
base64String: string,
mimeType: string
): string {
const homedir = os.homedir();
const imageStorageFolder = path.join(homedir, '.openmcp', 'storage');
// 确保存储目录存在
if (!fs.existsSync(imageStorageFolder)) {
fs.mkdirSync(imageStorageFolder, { recursive: true });
}
// 从 base64 字符串中提取数据部分
const base64Data = base64String.replace(/^data:.+;base64,/, '');
// 生成唯一文件名
const fileName = `${uuidv4()}.${mimeType.split('/')[1]}`;
const filePath = path.join(imageStorageFolder, fileName);
// 将 base64 数据写入文件
fs.writeFileSync(filePath, base64Data, { encoding: 'base64' });
return fileName;
}
export function loadBase64ImageData(fileName: string): string {
const homedir = os.homedir();
const imageStorageFolder = path.join(homedir, '.openmcp','storage');
const filePath = path.join(imageStorageFolder, fileName);
// 读取文件内容
if (!fs.existsSync(filePath)) {
return '';
}
const fileContent = fs.readFileSync(filePath, { encoding: 'base64' });
// 构建 base64 字符串
const base64String = `data:image/png;base64,${fileContent}`;
return base64String;
}
interface ToolCallContent {
type: string;
text?: string;
data?: any;
mimeType?: string;
_meta?: any;
[key: string]: any;
}
interface ToolCallResponse {
_meta?: any;
content?: ToolCallContent[];
isError?: boolean;
toolResult?: any;
}
export function postProcessToolcallResponse(response: ToolCallResponse): ToolCallResponse {
if (response.isError) {
// 如果是错误响应,将其转换为错误信息
return response;
}
// 将 content 中的图像 base64 提取出来,并保存到本地
if (response.content) {
response.content.forEach((content) => {
if (content.type === 'image') {
// TODO: check here
if (content.data && content.mimeType) {
const fileName = saveBase64ImageData(content.data, content.mimeType);
content.data = fileName;
content._meta = {
ocr: true
};
}
}
})
}
return response;
}

View File

@ -1,6 +1,8 @@
import Tesseract from 'tesseract.js'; import Tesseract from 'tesseract.js';
async function tesseractOCR(
export async function tesseractOCR(
imagePath: string, imagePath: string,
logger: (message: Tesseract.LoggerMessage) => void, logger: (message: Tesseract.LoggerMessage) => void,
lang: string = 'eng+chi_sim' lang: string = 'eng+chi_sim'

View File

@ -30,7 +30,7 @@ function tryGetRunCommandError(command: string, args: string[] = [], cwd?: strin
} }
export async function connectService( export async function connectService(
client: MCPClient | undefined, _client: MCPClient | undefined,
option: MCPOptions, option: MCPOptions,
webview: PostMessageble webview: PostMessageble
) { ) {

View File

@ -243,7 +243,7 @@ export async function callToolService(
name: option.toolName, name: option.toolName,
arguments: option.toolArgs arguments: option.toolArgs
}); });
const result = { const result = {
code: 200, code: 200,
msg: toolResult msg: toolResult
@ -262,7 +262,7 @@ export async function getServerVersionService(
client: MCPClient | undefined, client: MCPClient | undefined,
data: any, data: any,
webview: PostMessageble webview: PostMessageble
) { ) {
if (!client) { if (!client) {
const connectResult = { const connectResult = {
code: 501, code: 501,