Once T416659: Host sentence-transformers/LaBSE model in LiftWing is resolved, the model infrastructure dependency for this task will also be ready
- Feed Queries
- All Stories
- Search
- Feed Search
- Transactions
- Transaction Logs
Today
Here is nodejs client code that can give cosine similarity based on the above service.
Pull the above patch, then
docker compose build labse-embeddings docker compose up labse-embeddings
Get this code,
| 1 | #!/usr/bin/env node |
|---|---|
| 2 | |
| 3 | const http = require("http"); |
| 4 | |
| 5 | /** |
| 6 | * Get embedding vector from the API |
| 7 | * @param {string[]} text - Text to get embedding for |
| 8 | * @returns {Promise<number[]>} - Embedding vector |
| 9 | */ |
| 10 | async function getEmbedding(texts) { |
| 11 | const postData = JSON.stringify({ |
| 12 | input: texts, |
| 13 | }); |
| 14 | |
| 15 | const options = { |
| 16 | hostname: "localhost", |
| 17 | port: 8080, |
| 18 | path: "/v1/models/labse-embedding:predict", |
| 19 | method: "POST", |
| 20 | headers: { |
| 21 | "Content-Type": "application/json", |
| 22 | "Content-Length": Buffer.byteLength(postData), |
| 23 | }, |
| 24 | }; |
| 25 | |
| 26 | return new Promise((resolve, reject) => { |
| 27 | const req = http.request(options, (res) => { |
| 28 | let data = ""; |
| 29 | |
| 30 | res.on("data", (chunk) => { |
| 31 | data += chunk; |
| 32 | }); |
| 33 | |
| 34 | res.on("end", () => { |
| 35 | try { |
| 36 | const response = JSON.parse(data); |
| 37 | // Adjust this based on the actual API response structure |
| 38 | const embeddings = response.data; |
| 39 | resolve(embeddings); |
| 40 | } catch (error) { |
| 41 | reject(new Error(`Failed to parse response: ${error.message}`)); |
| 42 | } |
| 43 | }); |
| 44 | }); |
| 45 | |
| 46 | req.on("error", (error) => { |
| 47 | reject(new Error(`API request failed: ${error.message}`)); |
| 48 | }); |
| 49 | |
| 50 | req.write(postData); |
| 51 | req.end(); |
| 52 | }); |
| 53 | } |
| 54 | /** |
| 55 | * Calculate cosine similarity between two normalized vectors |
| 56 | * @param {number[]} vec1 - First normalized vector |
| 57 | * @param {number[]} vec2 - Second normalized vector |
| 58 | * @returns {number} - Similarity score between -1 and 1 |
| 59 | */ |
| 60 | function cosineSimilarity(vec1, vec2) { |
| 61 | if (vec1.length !== vec2.length) { |
| 62 | throw new Error("Vectors must have the same length"); |
| 63 | } |
| 64 | |
| 65 | let dotProduct = 0; |
| 66 | for (let i = 0; i < vec1.length; i++) { |
| 67 | dotProduct += vec1[i] * vec2[i]; |
| 68 | } |
| 69 | |
| 70 | return dotProduct; |
| 71 | } |
| 72 | |
| 73 | /** |
| 74 | * Compare two strings for similarity using embeddings |
| 75 | * @param {string} str1 - First string to compare |
| 76 | * @param {string} str2 - Second string to compare |
| 77 | * @returns {Promise<number>} - Similarity score between 0 and 1 |
| 78 | */ |
| 79 | async function compareStrings(str1, str2) { |
| 80 | console.log("Getting embeddings ..."); |
| 81 | const embeddings = await getEmbedding([str1, str2]); |
| 82 | console.log("Calculating similarity..."); |
| 83 | const similarity = cosineSimilarity( |
| 84 | embeddings[0].embedding, |
| 85 | embeddings[1].embedding, |
| 86 | ); |
| 87 | |
| 88 | return similarity; |
| 89 | } |
| 90 | |
| 91 | // Main execution |
| 92 | async function main() { |
| 93 | const args = process.argv.slice(2); |
| 94 | |
| 95 | if (args.length < 2) { |
| 96 | console.error("Usage: node compare-strings.js <string1> <string2>"); |
| 97 | console.error('Example: node compare-strings.js "Hello world" "Hi there"'); |
| 98 | process.exit(1); |
| 99 | } |
| 100 | |
| 101 | const string1 = args[0]; |
| 102 | const string2 = args[1]; |
| 103 | |
| 104 | console.log(`\nComparing strings:`); |
| 105 | console.log(`String 1: "${string1}"`); |
| 106 | console.log(`String 2: "${string2}"\n`); |
| 107 | |
| 108 | try { |
| 109 | const similarity = await compareStrings(string1, string2); |
| 110 | console.log( |
| 111 | `\nSimilarity score: ${similarity.toFixed(4)} (${(similarity * 100).toFixed(2)}%)`, |
| 112 | ); |
| 113 | } catch (error) { |
| 114 | console.error(`Error: ${error.message}`); |
| 115 | process.exit(1); |
| 116 | } |
| 117 | } |
| 118 | |
| 119 | main(); |
Fri, Feb 6
Thu, Feb 5
Tue, Jan 27
The current link suggestion system has an algorithmic issue that I had pointed in 2025. In this document and in a slack conversation(private), I explain this in detail. Basically, I argue that the problem is not a machine learning problem but a distributional fitting problem.
Nov 18 2025
Nov 17 2025
It looks like issue is specific to that file?
I tried https://commons.wikimedia.org/wiki/File:Moon_elevation.stl#/media/File:Moon_elevation.stl and working as expected
Nov 13 2025
slightly unrelated to this ticket - the sections suggested for translation from this example is incorrect for many titles due to issues in current section alignment algorithm. For example: Etymology is asked to translate, but it is already there in the target article.
Nov 10 2025
Oct 27 2025
The graphs are still empty. Is there anything else to fix or will it take time to refresh the data?
Oct 23 2025
Yandex was removed from cxserver
Oct 22 2025
The custom font embedding feature(also known as webfonts - https://www.mediawiki.org/wiki/Universal_Language_Selector/WebFonts ) was part of Universal Language Selector project. This was introduced more than a decade ago to support scripts when operating systems did not ship any fonts for them. The situation improved a lot in past several years. Embedding fonts in wikipedia pages has performance and network cost. So we gradually removed fonts as they got widely available. At present, in 2025, this feature is no longer recommended. It is also not actively maintained. There are a few fonts still in Universal Language Selector, but they are not embedded in wiki pages by default. Users can choose them from settings. But even then it is only available for Desktop and not for mobile. The Universal Language Selector is also undergoing a full rewrite this year as part of modernization.
Oct 7 2025
The LLM evaluation could be a little bit systematic. Currently GPS-OSS is 20B param mode, which we are comparing with Aya Expanse 32B. And Aya Expanse is an older model too. The prompt need to be versioned to see which is better. I would focus on figuring out a prompt and LLM param range that gives reasonable score and keep the LLM choice flexible since LLMs are are moving target and there are many practical considering to pick one.
Oct 6 2025
Marking as stalled for now.
I am abandoning the patches as they are outdated and I do not plan to keep them updated with the changes mentioned above.
This proposal is intended to support corrections for exact sentences.
...
if a user fixes a typo in one specific sentence, it gets fixed only for that instance (even if similar sentences exist).
Sep 25 2025
Thanks. It works now. Tool is up https://api-explorer.toolforge.org/
Sep 24 2025
Notes:
- Does not work with words in sentences since it require “fitting” that selection of word in to the original sentence and keep grammar accurate.(in localization we call this “avoiding lego messages”.) -This limitation also applies to translation memory for phrases(incomplete sentences). Chances of encountering the (exactly) same sentence again less in general prose.
- Examples
- This is Basil(person) - ഇവൻ(male)/ഇവൾ(female) ബേസിലാണ് (the translation of basil get fused with affirmative ആണ് - aka agglutination. Same below)
- This is basil(herb) - ഇത് തുളസിയാണ് (grammatical gender does not apply for things)
- Grammatical gender, subject verb agreement, agglutination and inflection are quite common outside the realm of analytical languages
- Word context issue is almost a solved problem in latest translation models, only present in MinT due to its limitation about contexts and anaphora resolution.(Broad context translation with self attention - in literature examples like “interest”, “bank” are often used)
Sep 23 2025
If I dont use buildservice but copy the rust binary to toolforge product and run it with the following service template, service is starting successfullly
The Cloud-Services project tag is not intended to have any tasks. Please check the list on https://phabricator.wikimedia.org/project/profile/832/ and replace it with a more specific project tag to this task. Thanks!
Sep 22 2025
Infobox historic site (https://www.wikidata.org/wiki/Q12857484) has templatedata in English, but no templatedata in Tamil. So cxserver has to extract template params from the template source code.
Sep 15 2025
Sep 11 2025
Sep 10 2025
Sep 9 2025
Another example. Here the infobox is not completely missing. It is shown as an indicator in source column.
Since LiftWing hosting plan is pending and under consideration by Machine-Learning-Team , I setup https://ovms.wmcloud.org/ with upstream docker image and above shellscript. Wrote an nginx proxy configuration for landing page, API key authentication and /api/v1 mounting. OpenAI api compatible APIs are available. This instance uses 8 CPU cores, 32GB RAM, 20GB Disk(models are in scratch volume). This wmcloud instance does not cancel this ticket, and for experimentation purpose.
This patch to prepare a WMF production image is outdated again as new version of Debian is released.
The model repository setup is easy with the new versions. OVMS can pull models from huggingface repos and setup all configurations. I wrote a shellscript to get all listed models in it and start the server. This script is used with the official docker images of OVMS. https://gerrit.wikimedia.org/r/c/machinelearning/liftwing/inference-services/+/1151645 will require updates based on this
Sep 3 2025
Node 22 stabilizes the fetch API. It is now feature compatible with browsers fetch API. This is generally good, but it also adds more restrictions to what a valid http request can be. The header field we are setting to pass the wikipedia domain to that wiki proxy is HOST (see the configuration). This is problematic because HOST is a forbidden header.
Aug 28 2025
Jul 28 2025
Just pointing out an additional detail on 'easy to translate':
Jul 24 2025
For example, the "Add a Link" model needs to be trained on links that already exist within articles on a wiki, so there is a Machine Learning dependency and a chance that some wikis will be too small for the model to be properly trained.
Jul 1 2025
Update: New version of Opevino and Openvino model server was released a few days ago. I updated my production bookworm based docker image patch: https://gerrit.wikimedia.org/r/c/operations/docker-images/production-images/+/1153988 to that version. This new version adds support for agentic AI(tool calling and MCP).
Jun 24 2025
@Wangombe , I reviewed it and proposed some changes
Jun 10 2025
I found one genuine reason why the progress value can be different. Suppose there are 10 source sections and you translate 5. The any value would be 0.5, If you modified all the sections, the mt value would be 0(just assume so) and human value would 1. When you come back a few days later, the source article can have 11 sections. Then any calculated at the time of restoration would be 0.45(5/11) . Have a look at the case #2 in the above comment. It is an example of this scenario.
Note that the is attribute based custom elements are not widely supported: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/is
Jun 9 2025
Some observations from initial attempt to debug:
Jun 6 2025
Here is the screencast of everything working together: https://drive.google.com/file/d/1YDSvTm3ePv585-ittck2tYWH2XZ-AHLx/view
(MP4 video, 15mins, 88MB)
Jun 5 2025
Updates: I successfully created a production docker image on top of WMF production wookworm image.
Jun 4 2025
I am trying to build a production docker image with WMF debian bookworm+python3.11+openvino 2025.1.0+ OVMS 2025.1.0. I am referring the Ubuntu Dockerfile.
Jun 3 2025
Thanks @kevinbazira and @isarantopoulos for these details. Very useful information.
May 29 2025
Regarding the KServe API and Openvino model server:
I tried to integrate Openvino model server to liftwing. Learnings for the first iteration(see the above WIP patch):
May 28 2025
This is a good idea.
I would suggest to use a simple client side memory for the recent selections - like localstorage and avoid server side storage(which require database, and big effort and resulting maintanance cost and tech debt).
I think it is acceptable to not have the recent selections when user switch browsers/computers.
May 22 2025
May 8 2025
We do have a machine translation system for kaa - Karakalpak powered by MADLAD-400 model.
The benefits of webcomponents compared to html tags is well documented. Webcomponents are html stanadard and supported by all browsers. Ofcourse, you can achieve the same features with html tags and javascript - with trade-offs. I would like to see them supported in mediawiki as they are part of web standard.
May 6 2025
May 5 2025
I used this documentation https://www.mediawiki.org/wiki/VisualEditor/Hooks for code search
Apr 30 2025
Apr 29 2025
The 45% thresholds are extreme case. It means you cannot publish a translation that has >45% machine translation. This demands heavy editing from translator. We also don't tell the translator about these percentages(T251887).
In my opinition, a simpler, consistant and predictable threshold level is better. If T is threshold for errors, make T-10 as the warning threshold, irrespective of value of T.
Apr 28 2025
Please use same campaign parameter. The ArticlePlaceholder patch passes articleplaceholder as campaign param. CX Config and event source config should use the same. article_placeholder does not match.
Apr 7 2025
Following discussions with the team, we've concluded that dynamic configuration is not a use case currently supported by Wikimedia. Our configurations are static, managed through updates and deployments. The
conf.yaml file facilitates this by allowing for varied configurations across different deployments, as it's separate from the codebase.
Mar 25 2025
Mar 24 2025
Mar 20 2025
. It let me start translating, and only when I went to publish did it warn me that I would be overwriting an existing article. This seems like a step back from the behaviour of the old dashboard, where at least it would warn me before I started translating.
Mar 19 2025
@jhsoby I was testing this again, and I don't see the issue now.
More importantly, the CX dashboard's new version is coming up. It will replace the current dashboard.
The following URL can be used to access new dashboard.
You can access it in https://no.wikipedia.org/w/index.php?title=Special:ContentTranslation&unified-dashboard=1&filter-type=automatic&filter-id=previous-edits&active-list=draft&from=en&to=nb#/
Seems working now. The blocking of retries for 30 mins for all consumers of API seems not an optimal approach. Also see T382376: PageViewInfo caches errors due to the request limit which can lead to denial of service
Mar 18 2025
Mar 17 2025
Thanks for that context. For the reasons I explained above, my advice would be to have DeepL client in your customized version and not in the upstream. Currently, our team or organization does not have a collaboration with DeepL. If this situation changes, we will definitely consider your client code. Thanks!
Mar 13 2025
Hi, DeepL is a proprietary machine translation service and their API key has a price associated with - at least to use in the scale of current traffic of cxserver. For such external Machine translation services, we(WMF) usualy has a partnership. For example, to use Google API, WMF and Google has partnership agreement. For DeepL too, we will need such agreement(legal, branding, pricing).
Mar 11 2025
In T387820#10621300, @Jdlrobson-WMF wrote:Hello is it possible this ticket relates to the train blocker at T388467: TypeError: mtSuggestions.map is not a function ?