From 4045097eb0d19ece4c67812c0d710de32de60785 Mon Sep 17 00:00:00 2001 From: Rishi Ghan Date: Wed, 14 Aug 2024 12:19:55 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=8F=97=EF=B8=8F=20Added=20string-similari?= =?UTF-8?q?ty=20lib?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 72 ++++++++++++++++-------------- package.json | 7 +-- services/comicprocessor.service.ts | 38 +++++++++++++--- 3 files changed, 74 insertions(+), 43 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2a50e64..f95073a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,8 @@ "kafkajs": "^2.2.4", "moleculer": "^0.14.27", "moleculer-web": "^0.10.5", - "parse-torrent": "^9.1.5" + "parse-torrent": "^9.1.5", + "string-similarity-alg": "^1.3.2" }, "devDependencies": { "@jest/globals": "^29.3.1", @@ -2356,12 +2357,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -3025,39 +3026,18 @@ } }, "node_modules/engine.io-client": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz", - "integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==", + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz", + "integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==", "dev": true, "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", - "ws": "~8.11.0", + "ws": "~8.17.1", "xmlhttprequest-ssl": "~2.0.0" } }, - "node_modules/engine.io-client/node_modules/ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/engine.io-parser": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", @@ -3892,9 +3872,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -7300,6 +7280,11 @@ "node": ">=10" } }, + "node_modules/string-similarity-alg": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/string-similarity-alg/-/string-similarity-alg-1.3.2.tgz", + "integrity": "sha512-M+jTGEJmWLfIg2dawXOifzbkUs/tp8HbeSCXZpNII2oZvU5uexaBFx+NoUBWS3M6VQ2ezJJCMstU8L8gq6YqsQ==" + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -8055,6 +8040,27 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/xmlhttprequest-ssl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", diff --git a/package.json b/package.json index 1af15b1..bb2000e 100644 --- a/package.json +++ b/package.json @@ -51,9 +51,10 @@ "@robertklep/qbittorrent": "^1.0.1", "ioredis": "^5.0.0", "kafkajs": "^2.2.4", - "moleculer": "^0.14.27", - "moleculer-web": "^0.10.5", - "parse-torrent": "^9.1.5" + "moleculer": "^0.14.34", + "moleculer-web": "^0.10.7", + "parse-torrent": "^9.1.5", + "string-similarity-alg": "^1.3.2" }, "engines": { "node": ">= 16.x.x" diff --git a/services/comicprocessor.service.ts b/services/comicprocessor.service.ts index 8b82c25..a53fab2 100644 --- a/services/comicprocessor.service.ts +++ b/services/comicprocessor.service.ts @@ -3,6 +3,7 @@ import { Service, ServiceBroker, ServiceSchema } from "moleculer"; import { Kafka, EachMessagePayload, logLevel } from "kafkajs"; import io from "socket.io-client"; import { isUndefined } from "lodash"; +import stringSimilarity from "string-similarity-alg"; interface SearchResult { result: { @@ -44,7 +45,26 @@ export default class ComicProcessorService extends Service { day: date.getDate(), }; }, - rankSearchResults: (results, query: string) => {}, + rankSearchResults: async (results: Map, query: string) => { + // Find the highest-ranked response based on similarity to the search string + let highestRankedResult = null; + let highestSimilarity = -1; + + results.forEach((resultArray) => { + resultArray.forEach((result) => { + const similarity = stringSimilarity("jaro-winkler").compare( + result.name, + query, + ); + if (similarity > highestSimilarity) { + highestSimilarity = similarity; + highestRankedResult = { ...result, similarity }; + } + }); + }); + + return highestRankedResult; + }, processJob: async (job: any) => { try { this.logger.info("Processing job:", JSON.stringify(job, null, 2)); @@ -137,12 +157,17 @@ export default class ComicProcessorService extends Service { this.logger.error("Error processing job:", error); } }, - produceResultsToKafka: async (query: string) => { + produceResultsToKafka: async (query: string, result: any[]) => { try { /* Match and rank */ - + const result = await this.rankSearchResults( + this.airDCPPSearchResults, + query, + ); + console.log("majori"); + console.log(result); /* Kafka messages need to be in a format that can be serialized to JSON, and a Map is not directly serializable in a way that retains its structure, hence why we use Object.fromEntries */ @@ -150,9 +175,7 @@ export default class ComicProcessorService extends Service { topic: "comic-search-results", messages: [ { - value: JSON.stringify( - Object.fromEntries(this.airDCPPSearchResults), - ), + value: JSON.stringify(result), }, ], }); @@ -165,7 +188,7 @@ export default class ComicProcessorService extends Service { args: [ { query, - results: Object.fromEntries(this.airDCPPSearchResults), + result, }, ], }); @@ -265,6 +288,7 @@ export default class ComicProcessorService extends Service { this.logger.info( `Search complete for query: "${data.searchInfo.query.pattern}"`, ); + await this.produceResultsToKafka(data.searchInfo.query.pattern); }); },