स्वचालित रूप से EasyNMT के साथ मार्कडाउन फ़ाइलों का अनुवाद (हिन्दी (Hindi))

स्वचालित रूप से EasyNMT के साथ मार्कडाउन फ़ाइलों का अनुवाद

Saturday, 03 August 2024

//

7 minute read

परिचय

EasyNMT एक स्थानीय रूप से संस्थापित सेवा है जो मशीन अनुवाद सेवाओं की एक संख्या के लिए एक सरल अंतरफलक प्रदान करता है

आप इस ट्युटोरियल के लिए सभी फ़ाइलों को खोज सकते हैं जिटहब रिपोजिटरी इस परियोजना के लिए

इसका आउटपुट लक्ष्य भाषाओं में नए मार्कडाउन फ़ाइलों का एक बन्च उत्पन्न करता है

अनुवादित डाक

पूर्व आवश्यकताएं

EasyNMT का इंस्टॉलेशन इस टूल्यूटर को अनुसरण करने के लिए जरूरी है. मैं सामान्यतः इसे डोकर सेवा के रूप में चलाता हूँ यहाँ जो यह एक डकर सेवा के रूप में चलाने के लिए कैसे शामिल है.

docker run -d -p 24080:80 --env MAX_WORKERS_BACKEND=6 --env MAX_WORKERS_FRONTEND=6 easynmt/api:2.0-cpu

या यदि आपके पास एनवीजीए GPU उपलब्ध है

docker run -d -p 24080:80 --env MAX_WORKERS_BACKEND=6 --env MAX_WORKERS_FRONTEND=6 easynmt/api:2.0.2-cuda11.3

MAX_WORKERS_BACKEND और MAX _WOSKERS_FRONTEND परिवेश चर EasyNMT को प्रयोग करने वाले कर्मियों की संख्या निर्धारित करते हैं

नोटः EasyNMT यह SMOOTHEST सेवा नहीं है कि चलाया जाए।

ओह और यह भी अनुवाद कर दिया है 'निर्धारणन'EU को प्रस्ताव प्रस्तुत करने के बारे में कुछ बेवकूफ

लोड संतुलन के लिए सहज दृष्टिकोण

आसान एनएमटी संसाधनों के बारे में एक प्यास की जानवर है, तो मेरे MarkdownTranslatorService में मैं एक अति सरल अनियमित आईपी चयनक है जो सिर्फ मशीनों की सूची के आईपी की सूची को चलाने के लिए मैं प्रयोग करता हूँ EasyNMT

आरंभ में यह एक पर मिलता है model_name EasyNMT सेवा पर विधि

    private string[] IPs = translateServiceConfig.IPs;
    public async ValueTask<bool> IsServiceUp(CancellationToken cancellationToken)
    {
        var workingIPs = new List<string>();

        try
        {
            foreach (var ip in IPs)
            {
                logger.LogInformation("Checking service status at {IP}", ip);
                var response = await client.GetAsync($"{ip}/model_name", cancellationToken);
                if (response.IsSuccessStatusCode)
                {
                    workingIPs.Add(ip);
                }
            }

            IPs = workingIPs.ToArray();
            if (!IPs.Any()) return false;
            return true;
        }
        catch (Exception e)
        {
            logger.LogError(e, "Error checking service status");
            return false;
        }
    }

फिर के भीतर Post विधि MarkdownTranslatorService हम अगले एक ढूंढने के लिए कार्य IPs के माध्यम से घुमाएँ

          if(!IPs.Any())
            {
                logger.LogError("No IPs available for translation");
                throw new Exception("No IPs available for translation");
            }
            var ip = IPs[currentIPIndex];
            
            logger.LogInformation("Sending request to {IP}", ip);
        
            // Update the index for the next request
            currentIPIndex = (currentIPIndex + 1) % IPs.Length;

यह कई मशीनों के बीच अनुरोधों को संतुलित लोड करने का एक अति सरल तरीका है।

स्कमिक currentIPIndex = (currentIPIndex + 1) % IPs.Length; सिर्फ आरंभ करने पर 0 और सूची की लंबाई में जा रहा IPs की सूची के माध्यम से घूमता है

एक मार्कडाउन फ़ाइल का अनुवाद

MarkdownTranslatorService में मेरे पास यह कोड है

    public async Task<string> TranslateMarkdown(string markdown, string targetLang, CancellationToken cancellationToken)
    {
        var document = Markdig.Markdown.Parse(markdown);
        var textStrings = ExtractTextStrings(document);
        var batchSize = 10;
        var stringLength = textStrings.Count;
        List<string> translatedStrings = new();
        for (int i = 0; i < stringLength; i += batchSize)
        {
            var batch = textStrings.Skip(i).Take(batchSize).ToArray();
            translatedStrings.AddRange(await Post(batch, targetLang, cancellationToken));
        }


        ReinsertTranslatedStrings(document, translatedStrings.ToArray());
        return document.ToMarkdownString();
    }

जैसा कि आप देख सकते हैं, इसमें कई चरण हैं

  1. var document = Markdig.Markdown.Parse(markdown); यह मार्क डाउन स्ट्रिंग को एक दस्तावेज़ में विश्लेषण करता है
  2. var textStrings = ExtractTextStrings(document); यह दस्तावेज़ से पाठ स्ट्रिंग निकालता है यह विधि का उपयोग करता है
  private bool IsWord(string text)
    {
        var imageExtensions = new[] { ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".svg" };
        if (imageExtensions.Any(text.Contains)) return false;
        return text.Any(char.IsLetter);
    } 

यह जाँचता है कि क्या 'word' वास्तव में एक कार्य है।

  1. var batchSize = 10; यह अनुवाद सेवा के लिए बैच आकार सेट करता है
  2. csharp await Post(batch, targetLang, cancellationToken) यह विधि में कॉल करता है जो बाद EasyNMT सेवा को बैच पोस्ट करता है
    private async Task<string[]> Post(string[] elements, string targetLang, CancellationToken cancellationToken)
    {
        try
        {
            var postObject = new PostRecord(targetLang, elements);
            var response = await client.PostAsJsonAsync("/translate", postObject, cancellationToken);

            var phrase = response.ReasonPhrase;
            response.EnsureSuccessStatusCode();
            var result = await response.Content.ReadFromJsonAsync<PostResponse>(cancellationToken: cancellationToken);

            return result.translated;
        }
        catch (Exception e)
        {
            logger.LogError(e, "Error translating markdown: {Message} for strings {Strings}", e.Message, string.Concat( elements, Environment.NewLine));
            throw;
        }
    }
  1. ReinsertTranslatedStrings(document, translatedStrings.ToArray()); - यह अनुवादित स्ट्रिंग को दस्तावेज़ में वापस जोड़ता है

    private void ReinsertTranslatedStrings(MarkdownDocument document, string[] translatedStrings)
    {
        int index = 0;

        foreach (var node in document.Descendants())
        {
            if (node is LiteralInline literalInline && index < translatedStrings.Length)
            {
                var content = literalInline.Content.ToString();
         
                if (!IsWord(content)) continue;
                literalInline.Content = new Markdig.Helpers.StringSlice(translatedStrings[index]);
                index++;
            }
        }
    }

होस्ट किया गया सेवा

इस सब को चलाने के लिए मैं एक IHostedLifetimeService का उपयोग करता हूँ जो कार्यक्रम में आरंभ होता है

  public async Task StartedAsync(CancellationToken cancellationToken)
    {
        if(!await blogService.IsServiceUp(cancellationToken))
        {
            logger.LogError("Translation service is not available");
            return;
        }
        ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = blogService.IPCount, CancellationToken = cancellationToken};
        var files = Directory.GetFiles(markdownConfig.MarkdownPath, "*.md");

        var outDir = markdownConfig.MarkdownTranslatedPath;

        var languages = translateServiceConfig.Languages;
        foreach(var language in languages)
        {
            await Parallel.ForEachAsync(files, parallelOptions, async (file,ct) =>
            {
                var fileChanged = await file.IsFileChanged(outDir);
                var outName = Path.GetFileNameWithoutExtension(file);

                var outFileName = $"{outDir}/{outName}.{language}.md";
                if (File.Exists(outFileName) && !fileChanged)
                {
                    return;
                }

                var text = await File.ReadAllTextAsync(file, cancellationToken);
                try
                {
                    logger.LogInformation("Translating {File} to {Language}", file, language);
                    var translatedMarkdown = await blogService.TranslateMarkdown(text, language, ct);
                    await File.WriteAllTextAsync(outFileName, translatedMarkdown, cancellationToken);
                }
                catch (Exception e)
                {
                    logger.LogError(e, "Error translating {File} to {Language}", file, language);
                }
            });
        }
       

जैसा कि आप देख सकते हैं यह भी देखने के लिए फ़ाइल की हैश की जाँच करता है कि क्या यह बदल गया है, जब इसे अनुवाद करने से पहले

यह मूल मार्क डाउन फ़ाइल की एक तीव्र हैश को संगणित करके किया जाता है फिर इसे अनुवाद करने के प्रयास से पहले यह देखने के लिए परीक्षण करता है कि क्या फ़ाइल बदली है

    private static async Task<string> ComputeHash(string filePath)
    {
        await using var stream = File.OpenRead(filePath);
        stream.Position = 0;
        var bytes = new byte[stream.Length];
        await stream.ReadAsync(bytes);
        stream.Position = 0;
        var hash = XxHash64.Hash(bytes);
        var hashString = Convert.ToBase64String(hash);
        hashString = InvalidCharsRegex.Replace(hashString, "_");
        return hashString;
    }

प्रोग्राम में सेटअप काफी सरल है


    builder.Services.AddHostedService<BackgroundTranslateService>();
services.AddHttpClient<MarkdownTranslatorService>(options =>
{
    options.Timeout = TimeSpan.FromMinutes(15);
});

मैं होस्ट्ड सर्विस (BackgroundTranslateService) और MarkdownTranslatorService के लिए HttpClient सेटअप किया है एक होस्टेड सेवा एक लंबे समय तक चलाने वाली सेवा है जो पृष्ठभूमि में चलती है।

यहाँ आप देख सकते हैं I'm HttpClient के लिए समय समाप्ति को 15 मिनटों में सेट करने पर यह इसलिए है कि EasyNMT प्रतिक्रिया देने में थोड़ा धीमा हो सकता है।

अंत में

यह एक Markdown फ़ाइल को कई भाषाओं में अनुवाद करने के लिए काफी सरल तरीका है। MarkdownBlogService प्रत्येक ब्लॉग पोस्ट के लिए अनुवादित नाम निकालना

Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.