diff --git a/electron-file-search/README.md b/electron-file-search/README.md index 6ff378a..1e85c55 100644 --- a/electron-file-search/README.md +++ b/electron-file-search/README.md @@ -1,4 +1,4 @@ -# Data Identification Manager : Personal Edition +# Data Identification Manager An Electron-based desktop application that uses AI to help you search and understand your files through natural language queries. diff --git a/electron-file-search/electron/ipc/handlers.ts b/electron-file-search/electron/ipc/handlers.ts index 5a559de..6888272 100644 --- a/electron-file-search/electron/ipc/handlers.ts +++ b/electron-file-search/electron/ipc/handlers.ts @@ -277,6 +277,28 @@ export function setupIpcHandlers() { return { success: false, error: err.message }; } }); + + ipcMain.handle('meilisearch-get-documents', async (_: unknown, indexName: string) => { + try { + const documents = await (global as any).meilisearchService.getDocuments(indexName); + return { success: true, data: documents }; + } catch (error) { + const err = error as Error; + console.error('Error getting documents from Meilisearch:', err); + return { success: false, error: err.message }; + } + }); + + ipcMain.handle('meilisearch-search', async (_: unknown, indexName: string, query: string) => { + try { + const results = await (global as any).meilisearchService.search(indexName, query); + return { success: true, data: results }; + } catch (error) { + const err = error as Error; + console.error('Error searching Meilisearch:', err); + return { success: false, error: err.message }; + } + }); } export default setupIpcHandlers; diff --git a/electron-file-search/electron/main.ts b/electron-file-search/electron/main.ts index 6e7469b..71f00b0 100644 --- a/electron-file-search/electron/main.ts +++ b/electron-file-search/electron/main.ts @@ -14,170 +14,14 @@ const slugify = (str: string) => { }; const { platform } = require('os'); - -class MeilisearchService { - private binaryPath: string; - private serverProcess: any | null = null; - private client: any | null = null; - - constructor() { - this.binaryPath = this.getBinaryPath(); - this.client = new MeiliSearch({ - host: 'http://127.0.0.1:7700', - apiKey: process.env.MEILISEARCH_MASTER_KEY || 'Damie', - }); - } - - private getBinaryPath(): string { - const arch = process.arch; - let binaryName: string; - - switch (platform()) { - case 'darwin': - binaryName = arch === 'arm64' ? 'meilisearch-macos-arm' : 'meilisearch-macos-x64'; - break; - case 'win32': - binaryName = 'meilisearch-windows.exe'; - break; - case 'linux': - binaryName = arch === 'arm' ? 'meilisearch-linux-arm' : 'meilisearch-linux-x64'; - break; - default: - throw new Error(`Unsupported platform: ${platform()}`); - } - - return path.join(__dirname, '..', 'meilisearch_binaries', binaryName); - } - - public async startServer(): Promise { - if (this.serverProcess) { - console.log('Meilisearch server is already running.'); - return; - } - - try { - const apiKey = 'Damie'; // Use the system's name as the API key - process.env.MEILISEARCH_MASTER_KEY = apiKey; - - this.serverProcess = spawn(this.binaryPath, ['--http-addr', '127.0.0.1:7700'], { - env: process.env, // Pass the environment variables to the child process - }); - - this.serverProcess.stdout?.on('data', (data) => { - console.log(`Meilisearch: ${data}`); - }); - - this.serverProcess.stderr?.on('data', (data) => { - console.error(`Meilisearch: ${data}`); - }); - - this.serverProcess.on('close', (code) => { - console.log(`Meilisearch server stopped with code ${code}`); - this.serverProcess = null; - }); - - this.serverProcess.on('error', (err) => { - console.error('Failed to start Meilisearch server:', err); - this.serverProcess = null; - }); - - console.log('Meilisearch server started.'); - } catch (error) { - console.error('Failed to start Meilisearch server:', error); - } - } - - public async stopServer(): Promise { - if (!this.serverProcess) { - console.log('Meilisearch server is not running.'); - return; - } - - this.serverProcess.kill(); - this.serverProcess = null; - console.log('Meilisearch server stopped.'); - } - - // Implement methods for adding, removing, and updating documents and collections - // using the Meilisearch API. - public async addDocuments(indexName: string, documents: any[]): Promise { - // TODO: Implement this method - console.log(`Adding documents to index ${indexName}`); - } - - public async removeDocuments(indexName: string, documentIds: string[]): Promise { - // TODO: Implement this method - console.log(`Removing documents from index ${indexName}`); - } - - public async updateDocuments(indexName: string, documents: any[]): Promise { - // TODO: Implement this method - console.log(`Updating documents in index ${indexName}`); - } - - public async createIndex(indexName: string): Promise { - const sluggedIndexName = slugify(indexName); - // TODO: Implement this method - console.log(`Creating index ${sluggedIndexName}`); - try { - await this.client.createIndex(sluggedIndexName); - console.log(`Index ${sluggedIndexName} created successfully`); - } catch (error) { - console.error(`Failed to create index ${sluggedIndexName}:`, error); - throw error; - } - } - - public async deleteIndex(indexName: string): Promise { - try { - await this.client.deleteIndex(indexName); - console.log(`Index ${indexName} deleted successfully`); - } catch (error) { - console.error(`Failed to delete index ${indexName}:`, error); - throw error; - } - } - - public async addDocuments(indexName: string, documents: any[]): Promise { - try { - const index = await this.client.index(indexName); - await index.addDocuments(documents); - console.log(`Documents added to index ${indexName} successfully`); - } catch (error) { - console.error(`Failed to add documents to index ${indexName}:`, error); - throw error; - } - } - - public async removeDocuments(indexName: string, documentIds: string[]): Promise { - try { - const index = await this.client.index(indexName); - await index.deleteDocuments(documentIds); - console.log(`Documents removed from index ${indexName} successfully`); - } catch (error) { - console.error(`Failed to remove documents from index ${indexName}:`, error); - throw error; - } - } - - public async updateDocuments(indexName: string, documents: any[]): Promise { - try { - const index = await this.client.index(indexName); - await index.updateDocuments(documents); - console.log(`Documents updated in index ${indexName} successfully`); - } catch (error) { - console.error(`Failed to update documents in index ${indexName}:`, error); - throw error; - } - } -} - -// Initialize IPC handlers immediately -setupIpcHandlers(); +import MeilisearchService from './services/meilisearchService'; const meilisearchService = new MeilisearchService(); (global as any).meilisearchService = meilisearchService; +// Initialize IPC handlers immediately +setupIpcHandlers(); + function createWindow() { const mainWindow = new BrowserWindow({ width: 1200, diff --git a/electron-file-search/electron/preload.ts b/electron-file-search/electron/preload.ts index 7b890e6..8a42742 100644 --- a/electron-file-search/electron/preload.ts +++ b/electron-file-search/electron/preload.ts @@ -84,6 +84,9 @@ contextBridge.exposeInMainWorld('electron', { ipcRenderer.removeListener(channel, onProgress); }); }, + + meilisearchSearch: async (indexName: string, query: string): Promise<{ success: boolean; data: any[] }> => + ipcRenderer.invoke('meilisearch-search', indexName, query), // Window Controls minimizeWindow: () => ipcRenderer.invoke('window-minimize'), diff --git a/electron-file-search/electron/services/meilisearchService.ts b/electron-file-search/electron/services/meilisearchService.ts index 55e60bb..82188d6 100644 --- a/electron-file-search/electron/services/meilisearchService.ts +++ b/electron-file-search/electron/services/meilisearchService.ts @@ -1,13 +1,89 @@ -import { MeiliSearch } from 'meilisearch' +import { MeiliSearch } from 'meilisearch'; +import slugify from 'slugify'; +const { platform } = require('os'); +const path = require('path'); +const spawn = require('child_process').spawn; class MeilisearchService { private client: MeiliSearch; + private binaryPath: string; + private serverProcess: any | null = null; constructor() { this.client = new MeiliSearch({ host: 'http://localhost:7700', }); - this.createIndex('files'); // Ensure the index exists + this.binaryPath = this.getBinaryPath(); + } + + private getBinaryPath(): string { + const arch = process.arch; + let binaryName: string; + + switch (platform()) { + case 'darwin': + binaryName = arch === 'arm64' ? 'meilisearch-macos-arm' : 'meilisearch-macos-x64'; + break; + case 'win32': + binaryName = 'meilisearch-windows.exe'; + break; + case 'linux': + binaryName = arch === 'arm' ? 'meilisearch-linux-arm' : 'meilisearch-linux-x64'; + break; + default: + throw new Error(`Unsupported platform: ${platform()}`); + } + + return path.join(__dirname, '..', 'meilisearch_binaries', binaryName); + } + + public async startServer(): Promise { + if (this.serverProcess) { + console.log('Meilisearch server is already running.'); + return; + } + + try { + const apiKey = 'Damie'; // Use the system's name as the API key + process.env.MEILISEARCH_MASTER_KEY = apiKey; + + this.serverProcess = spawn(this.binaryPath, ['--http-addr', '127.0.0.1:7700'], { + env: process.env, // Pass the environment variables to the child process + }); + + this.serverProcess.stdout?.on('data', (data) => { + console.log(`Meilisearch: ${data}`); + }); + + this.serverProcess.stderr?.on('data', (data) => { + console.error(`Meilisearch: ${data}`); + }); + + this.serverProcess.on('close', (code) => { + console.log(`Meilisearch server stopped with code ${code}`); + this.serverProcess = null; + }); + + this.serverProcess.on('error', (err) => { + console.error('Failed to start Meilisearch server:', err); + this.serverProcess = null; + }); + + console.log('Meilisearch server started.'); + } catch (error) { + console.error('Failed to start Meilisearch server:', error); + } + } + + public async stopServer(): Promise { + if (!this.serverProcess) { + console.log('Meilisearch server is not running.'); + return; + } + + this.serverProcess.kill(); + this.serverProcess = null; + console.log('Meilisearch server stopped.'); } // Implement methods for adding, removing, and updating documents and collections @@ -68,17 +144,26 @@ class MeilisearchService { public async getDocuments(indexName: string): Promise { try { const index = this.client.index(indexName); - const { hits } = await index.search(''); // Empty search to get all documents - return hits; + const documents = await index.getDocuments(); + return documents.results; } catch (error) { console.error(`Failed to get documents from index ${indexName}:`, error); throw error; } } + private slugifyPath(path):string { + return path + .toLowerCase() // Convert to lowercase + .replace(/[\\\/:*?"<>|]/g, '-') // Replace invalid characters with a dash + .replace(/\s+/g, '-') // Replace spaces with a dash + .replace(/-+/g, '-') // Replace multiple dashes with a single dash + .replace(/^-+|-+$/g, ''); + } public async search(indexName: string, query: string): Promise { try { - const index = this.client.index(indexName); + console.log(indexName) + const index = this.client.index(this.slugifyPath(indexName)); const { hits } = await index.search(query); return hits; } catch (error) { diff --git a/electron-file-search/index.html b/electron-file-search/index.html index 26e3978..a1276ab 100644 --- a/electron-file-search/index.html +++ b/electron-file-search/index.html @@ -4,7 +4,7 @@ - Data Identification Manager : Personal Edition + Data Identification Manager
diff --git a/electron-file-search/package-lock.json b/electron-file-search/package-lock.json index e06ca6a..bedd688 100644 --- a/electron-file-search/package-lock.json +++ b/electron-file-search/package-lock.json @@ -26,7 +26,8 @@ "react-dom": "^18.2.0", "react-markdown": "^9.0.3", "react-virtuoso": "^4.12.5", - "rehype-highlight": "^7.0.2" + "rehype-highlight": "^7.0.2", + "slugify": "^1.6.6" }, "devDependencies": { "@types/node": "^20.11.16", @@ -8910,6 +8911,15 @@ "node": ">=8" } }, + "node_modules/slugify": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz", + "integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", diff --git a/electron-file-search/package.json b/electron-file-search/package.json index a533ba8..53b2cea 100644 --- a/electron-file-search/package.json +++ b/electron-file-search/package.json @@ -31,7 +31,8 @@ "react-dom": "^18.2.0", "react-markdown": "^9.0.3", "react-virtuoso": "^4.12.5", - "rehype-highlight": "^7.0.2" + "rehype-highlight": "^7.0.2", + "slugify": "^1.6.6" }, "build": { "appId": "com.electron-file-search", diff --git a/electron-file-search/src/App.tsx b/electron-file-search/src/App.tsx index a6d781c..94423c2 100644 --- a/electron-file-search/src/App.tsx +++ b/electron-file-search/src/App.tsx @@ -154,7 +154,7 @@ function AppContent() { }} > - +
- + + + + ); diff --git a/electron-file-search/src/electron.d.ts b/electron-file-search/src/electron.d.ts index a787c81..a4c0342 100644 --- a/electron-file-search/src/electron.d.ts +++ b/electron-file-search/src/electron.d.ts @@ -19,7 +19,7 @@ declare global { sources: DocumentMetadata[]; }>; getLLMConfig: () => Promise; - + meilisearchSearch: (indexName: string, query: string) => Promise<{ success: boolean; data: any[] }>; // Vector Store Operations getDocuments: () => Promise<{ success: boolean; data?: DocumentMetadata[]; error?: string }>; addDocument: (content: string, metadata: DocumentMetadata) => Promise; diff --git a/package-lock.json b/package-lock.json index 4c6e3d6..1c5fcce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,8 @@ "": { "dependencies": { "@mui/x-data-grid": "^7.26.0", - "meilisearch": "^0.48.2" + "meilisearch": "^0.48.2", + "slugify": "^1.6.6" } }, "node_modules/@babel/runtime": { @@ -537,6 +538,15 @@ "license": "MIT", "peer": true }, + "node_modules/slugify": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz", + "integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/stylis": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", diff --git a/package.json b/package.json index 8b38ea1..5937828 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "dependencies": { "@mui/x-data-grid": "^7.26.0", - "meilisearch": "^0.48.2" + "meilisearch": "^0.48.2", + "slugify": "^1.6.6" } }