public static List <string> GetSimilarFiles(string file_name, string folder, double threshold)
        {
            List <string> similar_files = new List <string>();
            string        file_string;

            if (File.Exists(file_name))
            {
                file_string = File.ReadAllText(file_name);
            }
            else
            {
                return(similar_files);
            }

            if (Directory.Exists(folder))
            {
                var l = new NormalizedLevenshtein();

                foreach (string file in Directory.GetFiles(folder))
                {
                    if (file != file_name && (Path.GetExtension(file) == ".html" || Path.GetExtension(file) == ".htm"))
                    {
                        string check_file = File.ReadAllText(file);
                        double similarity = l.Similarity(file_string, check_file);

                        if (similarity > threshold)
                        {
                            similar_files.Add(file);
                        }
                    }
                }
            }

            return(similar_files);
        }
예제 #2
0
        public static async Task <object> SubmitGuess(
            [HttpTrigger(AuthorizationLevel.Anonymous, "post")] Guess guess,
            [Table("clues", "{clueId}", Clue.RowKeyValue)] Clue clue,
            [Table("guesses")] IAsyncCollector <Guess> guesses,
            [SignalR(HubName = "trivia")] IAsyncCollector <SignalRMessage> signalRMessages)
        {
            var l          = new NormalizedLevenshtein();
            var similarity = l.Similarity(NormalizeString(clue.Answer), NormalizeString(guess.Value));

            await guesses.AddAsync(guess);

            var result = new
            {
                guess.SessionId,
                ClueId     = clue.PartitionKey,
                Guess      = guess.Value,
                IsCorrect  = similarity > 0.75,
                Similarity = similarity
            };

            await signalRMessages.AddAsync(new SignalRMessage
            {
                Target    = "newGuess",
                Arguments = new object[]
                {
                    new {
                        clueId    = result.ClueId,
                        isCorrect = result.IsCorrect
                    }
                }
            });

            return(result);
        }
예제 #3
0
        public void TestDistance()
        {
            var instance = new NormalizedLevenshtein();

            NullEmptyTests.TestDistance(instance);

            // TODO: regular (non-null/empty) distance tests
        }
예제 #4
0
        public void TestSimilarity()
        {
            var instance = new NormalizedLevenshtein();

            NullEmptyTests.TestSimilarity(instance);

            // TODO: regular (non-null/empty) similarity tests
        }
예제 #5
0
파일: Helpers.cs 프로젝트: N0D4N/JazzBot
 public static bool IsCommandSimilar(Command command, string notFoundCommand, NormalizedLevenshtein normalizedLevenshtein, double goodDistance = 0.33)
 {
     return(normalizedLevenshtein.Distance(command.Name, notFoundCommand) <= goodDistance
            ||
            command?.Aliases?.Any(x => normalizedLevenshtein.Distance(x, notFoundCommand) <= goodDistance) == true
            ||
            normalizedLevenshtein.Distance(command.QualifiedName, notFoundCommand) <= goodDistance);
 }
예제 #6
0
        public static async Task CommandCorrector(string input, string command, string user = null, bool shouldBeExact = false)
        {
            // def variables
            IDictionary <Command, double> MatchRate = new Dictionary <Command, double>();
            var Match = new NormalizedLevenshtein();

            // filling array with matching rate
            for (int i = 0; i < Commands.List.Count; i++)
            {
                MatchRate.Add(Commands.List[i], Match.Distance(command, Commands.List[i].Key));
            }

            //is there some rate lower than 35%
            if (!MatchRate.Any(q => q.Value <= 0.51d))
            {
                await Respond("@" + input.ToLower().Split("!")[0].Replace(":", "") + " , Não entendi o seu comando, tente !Exclamação para obter a lista de todos os comandos...");

                return;
            }
            else
            {
                //get the minimum match rate (closest command)
                var minimum = MatchRate.Min(q => q.Value);

                var arrayMinimum = MatchRate.Where(q => q.Value == minimum);

                if (arrayMinimum.Count() == 1)
                {
                    if (shouldBeExact)
                    {
                        await Respond("@" + user + " , O comando " + command + " está incorreto; " + arrayMinimum.ElementAt(0).Key.Description);
                    }
                    else
                    {
                        var Tinput = input.ToLower().Split(command)[1];
                        var Tuser  = input.ToLower().Split("!")[0].Replace(":", "");

                        await Respond("@" + Tuser + " , Seu commando foi corrigido para " + arrayMinimum.ElementAt(0).Key.Key + ", tente !Exclamação para obter a lista de todos os comandos...");

                        arrayMinimum.ElementAt(0).Key.Action.Invoke(Tinput, Tuser);
                    }
                }
                else
                {
                    string text = "@" + input.ToLower().Split("!")[0].Replace(":", "") + " , Não entendi o seu comando, não seria ";
                    foreach (var item in arrayMinimum)
                    {
                        text += item.Key.Key + " ou ";
                    }

                    text += "tente !Exclamação para ver todos os comandos...";

                    await Respond(text);
                }
            }
        }
        public void HouseAnalysis(CallsInfo[] calls)
        {
            _logger.LogInformation("Анализ наличия номера дома");

            var l = new NormalizedLevenshtein();

            foreach (var call in calls)
            {
                if (call.Text == null)
                {
                    continue;
                }

                var words = call.Text.Split(' ');

                foreach (var announcement in call.Announcements)
                {
                    if (announcement.House == default)
                    {
                        continue;
                    }

                    double max_similarity = default;
                    string best_word      = default;

                    foreach (var word in words)
                    {
                        var similarity = l.Similarity(word.ToLower(), announcement.House.ToLower());
                        if (similarity >= max_similarity)
                        {
                            best_word      = word;
                            max_similarity = similarity;
                        }
                    }

                    //if (max_similarity == 1)
                    {
                        announcement.Features.Add(new FeatureInfo
                        {
                            Name   = FeatureInfo.HOUSE,
                            Weight = max_similarity,
                            Data   = best_word ?? ""
                        });
                    }
                }
            }

            _logger.LogInformation("Закончили");
        }
예제 #8
0
        public async Task <string> Update()
        {
            var l             = new NormalizedLevenshtein();
            var staticVendors = _tmdb.PacingVendor.ToList().Select(i => i.Vendor).OrderBy(o => o).ToList();
            var sDate         = DateTime.Now.AddDays(-7);
            var eDate         = DateTime.Now;
            var advVendors    = (await Client.LoadMediaOrdersAsync(ServerName, DatabaseName, 0, UserName, Password, "A", sDate, sDate.Month, sDate.Year, eDate, eDate.Month, eDate.Year, true, false, false, false, false, false, "")).Select(i => i.VendorName).Distinct();
            var res           = advVendors.Where(s => !staticVendors.Any(e =>
            {
                var ts = s.Replace(".com", "").Split("/")[0].ToLower();
                var te = e.Replace(".com", "").Split("/")[0].ToLower();
                return(l.Distance(ts, te) < 0.2 || ts.Contains(te) || te.Contains(ts));
            })).OrderBy(o => o).ToList();

            return("Span: Week\n" + string.Join('\n', res));
        }
        public void NormalizedLevenshteinAnalysis(CallsInfo[] calls)
        {
            _logger.LogInformation("Анализ похожих методом NormalizedLevenshtein");

            var l = new NormalizedLevenshtein();

            foreach (var call in calls)
            {
                if (call.Text == null)
                {
                    continue;
                }

                var words = call.Text.Split(' ');

                foreach (var announcement in call.Announcements)
                {
                    if (announcement.Street == default)
                    {
                        continue;
                    }

                    double max_similarity = default;
                    string best_word      = default;

                    foreach (var word in words)
                    {
                        var similarity = l.Similarity(word.ToLower(), announcement.Street.ToLower());
                        if (similarity >= max_similarity)
                        {
                            best_word      = word;
                            max_similarity = similarity;
                        }
                    }

                    announcement.Features.Add(new FeatureInfo
                    {
                        Name   = FeatureInfo.LEVENSTAIN,
                        Weight = max_similarity,
                        Data   = best_word ?? ""
                    });
                }
            }

            _logger.LogInformation("Закончили");
        }
예제 #10
0
        public async Task ExecuteGroup(CommandContext context, [RemainingText, Description("Название тега для отображения")] string name)
        {
            if (string.IsNullOrWhiteSpace(name) || ForbiddenNames.Contains(name.ToLower()))
            {
                throw new DiscordUserInputException("Название тега не может быть пустым, полностью состоять из пробелов или быть называться также как и команды.", nameof(name));
            }

            var gId = (long)context.Guild.Id;

            var tag = await this.Database.Tags.SingleOrDefaultAsync(t => t.Name == name && t.GuildId == gId).ConfigureAwait(false);

            if (tag == null)
            {
                var nL   = new NormalizedLevenshtein();
                var tags = await this.Database.Tags.Where(t => t.GuildId == gId).OrderBy(t => nL.Distance(t.Name, name)).ToArrayAsync().ConfigureAwait(false);

                if (tags?.Any() == false)
                {
                    throw new DiscordUserInputException("Тегов на этом сервере не найдено", nameof(tags));
                }
                string suggestions =
                    (tags.Length >= 10
                                        ?
                     string.Join(", ", tags.Take(10).OrderBy(x => x.Name).Select(xt => Formatter.InlineCode(xt.Name)).Distinct())
                                        :
                     string.Join(", ", tags.OrderBy(x => x.Name).Select(xt => Formatter.InlineCode(xt.Name)).Distinct()));
                await context.RespondAsync($"Нужного тега не найдено, вот некоторые {Formatter.Italic("возможные варианты того что вы искали")}:\n\u200b{suggestions}").ConfigureAwait(false);
            }
            else
            {
                string content = tag.TagContent.Replace("@here", "@\u200bhere").Replace("@everyone", "@\u200beveryone").Trim();
                await context.RespondAsync($"\u200b{content}").ConfigureAwait(false);

                tag.TimesUsed++;
                this.Database.Tags.Update(tag);
                int rowsAffected = await this.Database.SaveChangesAsync();

                if (rowsAffected <= 0)
                {
                    throw new DatabaseException("Не удалось обновить количество использований в базе данных", DatabaseActionType.Save);
                }
            }
        }
예제 #11
0
        public async Task Check()
        {
            string userText = Stopwords.RemoveStopwords(AnsweredText);
            string ansText  = Stopwords.RemoveStopwords(Question.Answer);

            var l          = new NormalizedLevenshtein();
            var similarity = 1 - l.Distance(userText, ansText);

            if (similarity >= 0.8)
            {
                UpdateBuzzCorrect();
            }
            else
            {
                UpdateBuzzIncorrect();
            }

            await UpdateAnswered();
        }
예제 #12
0
        ///// <summary>
        ///// Calcualtes the Levenshtein distance between two strings
        ///// </summary>
        ///// Source: https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#C.23
        ///// Explanation: https://en.wikipedia.org/wiki/Levenshtein_distance
        //private Int32 levenshtein(String a, String b)
        //{

        //    if (string.IsNullOrEmpty(a))
        //    {
        //        if (!string.IsNullOrEmpty(b))
        //        {
        //            return b.Length;
        //        }
        //        return 0;
        //    }

        //    if (string.IsNullOrEmpty(b))
        //    {
        //        if (!string.IsNullOrEmpty(a))
        //        {
        //            return a.Length;
        //        }
        //        return 0;
        //    }

        //    Int32 cost;
        //    Int32[,] d = new int[a.Length + 1, b.Length + 1];
        //    Int32 min1;
        //    Int32 min2;
        //    Int32 min3;

        //    for (Int32 i = 0; i <= d.GetUpperBound(0); i += 1)
        //    {
        //        d[i, 0] = i;
        //    }

        //    for (Int32 i = 0; i <= d.GetUpperBound(1); i += 1)
        //    {
        //        d[0, i] = i;
        //    }

        //    for (Int32 i = 1; i <= d.GetUpperBound(0); i += 1)
        //    {
        //        for (Int32 j = 1; j <= d.GetUpperBound(1); j += 1)
        //        {
        //            cost = Convert.ToInt32(!(a[i - 1] == b[j - 1]));

        //            min1 = d[i - 1, j] + 1;
        //            min2 = d[i, j - 1] + 1;
        //            min3 = d[i - 1, j - 1] + cost;
        //            d[i, j] = Math.Min(Math.Min(min1, min2), min3);
        //        }
        //    }

        //    return d[d.GetUpperBound(0), d.GetUpperBound(1)];

        //}

        ///// <summary>
        ///// String-similarity computed with levenshtein-distance
        ///// </summary>
        //private double similarityLevenshtein(string a, string b)
        //{
        //    if (a.Equals(b))
        //    {
        //        return 1.0;
        //    }
        //    else
        //    {
        //        if (!(a.Length == 0 || b.Length == 0))
        //        {
        //            double sim = 1 - (levenshtein(a, b) / Convert.ToDouble(Math.Min(a.Length, b.Length)));
        //            return sim;
        //        }
        //        else
        //            return 0.0;
        //    }
        //}

        ///// <summary>
        ///// String-similarity computed with Dice Coefficient
        ///// </summary>
        ///// Source: https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Dice%27s_coefficient#C.23
        ///// Explanation: https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient
        //private double similarityDiceCoefficient(string a, string b)
        //{
        //    //Workaround for |a| == |b| == 1
        //    if (a.Length <= 1 && b.Length <= 1)
        //    {
        //        if (a.Equals(b))
        //            return 1.0;
        //        else
        //            return 0.0;
        //    }

        //    HashSet<string> setA = new HashSet<string>();
        //    HashSet<string> setB = new HashSet<string>();

        //    for (int i = 0; i < a.Length - 1; ++i)
        //        setA.Add(a.Substring(i, 2));

        //    for (int i = 0; i < b.Length - 1; ++i)
        //        setB.Add(b.Substring(i, 2));

        //    HashSet<string> intersection = new HashSet<string>(setA);
        //    intersection.IntersectWith(setB);

        //    return (2.0 * intersection.Count) / (setA.Count + setB.Count);
        //}

        /// <summary>
        /// Combines multiple String-similarities with equal weight
        /// </summary>
        private double similarity(string a, string b)
        {
            List <double> similarities = new List <double>();
            double        output       = 0.0;

            var l = new NormalizedLevenshtein();

            similarities.Add(l.Similarity(a, b));
            var jw = new JaroWinkler();

            similarities.Add(jw.Similarity(a, b));
            var jac = new Jaccard();

            similarities.Add(jac.Similarity(a, b));

            foreach (double sim in similarities)
            {
                output += sim;
            }

            return(output / similarities.Count);
        }
예제 #13
0
        protected async Task <ContentStatus> StartContentBoardMission(string name)
        {
            if (!await GoToMainScreen())
            {
                Logger.LogError("Couldn't go to main screen.");
            }

            if (!await WaitUntilVisible("MAIN_MENU_ENTER"))
            {
                Logger.LogError("Cannot find enter button.. Not on main screen?");
                return(null);
            }

            await Task.Delay(500);

            Game.Click("CONTENT_STATUS_BOARD_BUTTON");
            if (!await WaitUntilVisible("CONTENT_STATUS_BOARD_MENU_HEADER"))
            {
                Logger.LogError("Failed to navigate to content status board");
                return(null);
            }

            await Task.Delay(500);

            for (int i = 0; i < 3; i++)
            {
                for (var row = 0; row < 5; row++)
                {
                    for (var col = 0; col < 3; col++)
                    {
                        var nameElement = Repository["CONTENT_STATUS_BOARD_ITEM_NAME_DYN", col, row];
                        var missionName = Game.GetText(nameElement);
                        missionName = missionName.Contains("\n") ? missionName.Split('\n')[0] : missionName;
                        var nl         = new NormalizedLevenshtein();
                        var similarity = nl.Similarity(name, missionName);
                        if (similarity >= 0.8) // 80% should be fine. names are different enough.
                        {
                            var status      = Game.GetText(Repository["CONTENT_STATUS_BOARD_ITEM_STATUS_DYN", col, row]);
                            var isCompleted = missionName.Contains("\n") &&
                                              nl.Similarity("RESETS IN", missionName.TrimEnd().Split('\n').Last()) > 0.8;
                            //var isCompleted = Game.IsVisible(Repository["CONTENT_STATUS_BOARD_ITEM_NAME_COMPLETED_DYN", col, row]);
                            var statusEntry = new ContentStatus(name, isCompleted, status);

                            Logger.LogDebug($"Clicking on element because it matches expected: {name} actual: {missionName} similarity: {similarity}");
                            Game.Click(nameElement);

                            await Task.Delay(1000); // waiting briefly for page to change.

                            if (Game.IsVisible(UIds.GENERIC_MISSION_CUSTOM_OFFER_FOR_AGENTS))
                            {
                                Game.Click(UIds.GENERIC_MISSION_CUSTOM_OFFER_FOR_AGENTS_CLOSE);
                                await Task.Delay(1000);
                            }
                            return(statusEntry);
                        }
                        else
                        {
                            Logger.LogDebug($"Found mission {missionName}. But its not what we are looking for. Similarity {similarity}");
                        }
                    }
                }
                Game.Drag("CONTENT_STATUS_BOARD_DRAG_START", "CONTENT_STATUS_BOARD_DRAG_END");
            }
            return(null);
        }
예제 #14
0
        public static double Similarity(this string expected, string actual)
        {
            var nl = new NormalizedLevenshtein();

            return(nl.Similarity(expected, actual));
        }
예제 #15
0
        private void MergeIntoDestination()
        {
            XmlNodeList nodes;
            var         levenshtein = new NormalizedLevenshtein();
            var         root        = _destDoc.DocumentElement;

            if (_replace)
            {
                nodes = root.SelectNodes("//xliff:trans-unit", _nsmgr);
            }
            else
            {
                nodes = root.SelectNodes("//xliff:trans-unit[not(xliff:target)]", _nsmgr);
            }

            foreach (XmlNode node in nodes)
            {
                var id = node.Attributes["id"].Value;
                if (_translations.ContainsKey(id))
                {
                    var source      = node.SelectSingleNode("xliff:source", _nsmgr);
                    var transSource = _translations[id].SelectSingleNode($"./xliff:source", _nsmgr);
                    var transTarget = _translations[id].SelectSingleNode($"./xliff:target", _nsmgr);

                    if (source.InnerText != transSource.InnerText)
                    {
                        var percentSimilar = Math.Round((1 - levenshtein.Distance(source.InnerText, transSource.InnerText)) * 100);
                        if (_verbose)
                        {
                            Console.WriteLine($"Sources mismatch in id='{id}' Similarity {percentSimilar}%.");
                            Console.WriteLine($" Source file='{transSource.InnerText}'");
                            Console.WriteLine($" Target file='{source.InnerText}'");
                        }
                        if (percentSimilar < _fuzzy)
                        {
                            if (_verbose)
                            {
                                Console.WriteLine($"Skipping");
                            }
                            continue;
                        }
                    }

                    if (_replace)
                    {
                        var oldTarget = node.SelectSingleNode("xliff:target", _nsmgr);
                        if (oldTarget != null)
                        {
                            node.RemoveChild(oldTarget);
                        }
                    }

                    if (source.NextSibling.Name != "#significant-whitespace")
                    {
                        XmlSignificantWhitespace sigws = _destDoc.CreateSignificantWhitespace("\n          ");
                        node.InsertAfter(sigws, source);
                    }
                    XmlNode target = _destDoc.ImportNode(transTarget, true);
                    node.InsertAfter(target, source.NextSibling);
                    if (target.NextSibling.Name != "#significant-whitespace")
                    {
                        XmlSignificantWhitespace sigws = _destDoc.CreateSignificantWhitespace("\n          ");
                        node.InsertAfter(sigws, target);
                    }
                }
            }
        }
예제 #16
0
        public async Task PlayNext(CommandContext context, [RemainingText, Description("Название песни")] string songName)
        {
            if (string.IsNullOrWhiteSpace(songName))
            {
                throw new DiscordUserInputException("Название песни не должно быть пустым", nameof(songName));
            }

            var songs = new List <Songs>();

            lock (this.Bot.UpdateMusicLock)
            {
                songs = this.Database.Playlist.ToList();
            }
            var playNexts = new List <PlayNextElement>();
            var nL        = new NormalizedLevenshtein();

            foreach (var song in songs)
            {
                playNexts.Add(new PlayNextElement(song.Path, song.Name, nL.Distance(song.Name, songName)));
            }
            playNexts = playNexts.OrderBy(s => s.Coefficient).ToList();
            var interactivity = context.Client.GetInteractivity();
            var description   = new StringBuilder();

            for (int i = 0; i < 10; i++)
            {
                description.AppendLine($"\n№ {i + 1}; Name: {playNexts[i].Title}.");
            }

            var listMsg = await context.RespondAsync(embed : EmbedTemplates.ExecutedByEmbed(context.Member, context.Guild.CurrentMember)
                                                     .WithTitle("Предолагаемый список песен")
                                                     .WithDescription(description.ToString())
                                                     .WithFooter($"Отправьте {Formatter.InlineCode("0")} для отмены")).ConfigureAwait(false);

            var msg = await interactivity.WaitForMessageAsync(xm => xm.Author.Id == context.User.Id, TimeSpan.FromSeconds(45));

            if (!msg.TimedOut)
            {
                if (int.TryParse(msg.Result.Content, out int res))
                {
                    if (res >= 1 && res <= playNexts.Count)
                    {
                        var pNData = this.GuildMusic.MusicSources[(int)MusicSourceType.PlayNextData] as PlayNextData;
                        pNData.Enqueue(playNexts[res - 1].PathToFile);

                        await listMsg.ModifyAsync(embed : EmbedTemplates.ExecutedByEmbed(context.Member, context.Guild.CurrentMember)
                                                  .WithTitle($"Следующей песней будет {playNexts[res - 1].Title}").Build()).ConfigureAwait(false);
                    }
                    else if (res == 0)
                    {
                        await listMsg.ModifyAsync("Выбор отменен", null).ConfigureAwait(false);
                    }
                    else
                    {
                        await listMsg.ModifyAsync("Данное число выходит за границы", null).ConfigureAwait(false);
                    }
                }
                else
                {
                    await listMsg.ModifyAsync("Ответ не является числом или время вышло", null).ConfigureAwait(false);
                }
            }
            await Task.Delay(TimeSpan.FromSeconds(30));

            await listMsg.DeleteAsync();
        }
예제 #17
0
        private async void ButtonValid_Click(object sender, RoutedEventArgs e)
        {
            string      inputString   = myInputTextBox.Text;
            LImagesMots selectedImage = Images[flipView.SelectedIndex];

            string[] lines        = inputString.Split('\r');
            string   voiceString  = inputString;
            double   ratingResult = 0.0;

            foreach (var L in lines)
            {
                var    l        = new NormalizedLevenshtein();
                double distance = l.Similarity(L, selectedImage.ImageText);
                // distance est entre 0 [PERFECT] et 1
                if (distance > ratingResult)
                {
                    ratingResult = distance;
                }

                log.Trace("Compare " + L + ", " + selectedImage.ImageText);
                log.Trace("results =" + l.Similarity(L, selectedImage.ImageText));
                if (L == selectedImage.ImageText)
                {
                    voiceString = L;
                }
            }

            // transformation du result 0..1 en 0..5 (5 est 5 etoile)
            log.Trace("ratingResults =" + ratingResult + "  ---");
            log.Trace("5*ratingResult =" + 5 * (ratingResult) + "  ---");

            ratingResult = 5 * ratingResult;
            int ratingResultInt = (int)ratingResult;

            log.Trace(" (int)ratingResult =" + ratingResult + "  ---");

            string bravoText = "";

            switch (ratingResultInt)
            {
            case 5:
                bravoText = " BRAVO !!, ";
                break;

            case 4:
                bravoText = " PRESQUE !!";
                break;

            case 2:
            case 3:
                bravoText = " ESSAYE ENCORE !!";
                break;

            case 0:
            case 1:
                bravoText           = " RECOMMENCE !!";
                myInputTextBox.Text = "";
                break;

            default:
                bravoText = " DEFAULT !!";
                break;
            }
            Flyout tmpFlyout = Resources["MyFlyout"] as Flyout;

            MyRating.Value    = ratingResultInt;
            MyResultText.Text = bravoText;
            voiceString       = string.Concat(bravoText + ",", voiceString);
            myInputTextBox.Focus(FocusState.Programmatic);
            myInputTextBox.IsTextScaleFactorEnabled = false;

            await letterPlayer_m.speachAsync(voiceString);

            tmpFlyout.ShowAt(myInputTextBox);
            // rend le focus a la text box
            myInputTextBox.Focus(FocusState.Programmatic);
        }
예제 #18
0
        private async Task Commands_CommandErrored(CommandErrorEventArgs e)
        {
            e.Context.Client.DebugLogger.LogMessage(LogLevel.Error, this.Bot.LogName, $"{e.Context.User.Username} tried executing '{e.Command?.QualifiedName ?? "<unknown command>"}' but it errored: {e.Exception.GetType()}: {e.Exception.Message ?? "<no message>"}", DateTime.Now);


            var ex = e.Exception;

            while (ex is AggregateException || ex.InnerException != null)
            {
                ex = ex.InnerException;
            }

            // Check if exception is result of command prechecks.
            switch (ex)
            {
            case ChecksFailedException exep:
            {
                var failedchecks = exep.FailedChecks.First();
                switch (failedchecks)
                {
                // Bot is lacking permissions.
                case RequireBotPermissionsAttribute reqbotperm:
                {
                    string permissionsLacking = reqbotperm.Permissions.ToPermissionString();
                    var    emoji = DiscordEmoji.FromName(e.Context.Client, ":no_entry:");
                    await e.Context.RespondAsync(embed : EmbedTemplates.CommandErrorEmbed(e.Context.Member, e.Command)
                                                 .WithTitle($"{emoji} Боту не хватает прав")
                                                 .WithDescription(permissionsLacking)).ConfigureAwait(false);

                    break;
                }

                // User is lacking permissions.
                case RequireUserPermissionsAttribute requserperm:
                {
                    string permissionsLacking = requserperm.Permissions.ToPermissionString();
                    var    emoji = DiscordEmoji.FromName(e.Context.Client, ":no_entry:");

                    await e.Context.RespondAsync(embed : EmbedTemplates.CommandErrorEmbed(e.Context.Member, e.Command)
                                                 .WithTitle($"{emoji} Вам не хватает прав")
                                                 .WithDescription(permissionsLacking)).ConfigureAwait(false);

                    break;
                }

                // User is not owner of the bot.
                case RequireOwnerAttribute reqowner:
                {
                    var emoji = DiscordEmoji.FromName(e.Context.Client, ":no_entry:");
                    await e.Context.RespondAsync(embed : EmbedTemplates.CommandErrorEmbed(e.Context.Member, e.Command)
                                                 .WithTitle($"{emoji} Команда доступна только владельцу")).ConfigureAwait(false);

                    break;
                }

                // User is not owner or don't have permissions.
                case OwnerOrPermissionAttribute ownerOrPermission:
                {
                    string permissionsLacking = ownerOrPermission.Permissions.ToPermissionString();
                    var    emoji = DiscordEmoji.FromName(e.Context.Client, ":no_entry:");
                    await e.Context.RespondAsync(embed : EmbedTemplates.CommandErrorEmbed(e.Context.Member, e.Command)
                                                 .WithTitle($"{emoji} Вы не являетесь владельцем или вам не хватает прав")
                                                 .WithDescription(permissionsLacking)).ConfigureAwait(false);

                    break;
                }

                // Command shouldn't be executed so fast.
                case CooldownAttribute cooldown:
                {
                    await e.Context.RespondAsync(embed : EmbedTemplates.CommandErrorEmbed(e.Context.Member, e.Command)
                                                 .WithDescription("Вы пытаетесь использовать команду слишком часто, таймер - " +
                                                                  $"не больше {cooldown.MaxUses} раз в {cooldown.Reset.TotalMinutes} минут")).ConfigureAwait(false);

                    break;
                }

                // User wasn't connected to voice channel. Optionally to the same voice channel as bot
                case RequireVoiceConnectionAttribute requireVoice:
                {
                    await e.Context.RespondAsync(embed : EmbedTemplates.CommandErrorEmbed(e.Context.Member, e.Command)
                                                 .WithDescription($"Вы должны быть подключены к {(requireVoice.SameVoiceChannelAsBot ? "тому же голосовому каналу что и бот" : "голосовому каналу")}")).ConfigureAwait(false);

                    break;
                }

                default:
                {
                    await e.Context.RespondAsync(embed : EmbedTemplates.CommandErrorEmbed(e.Context.Member, e.Command)
                                                 .WithDescription($"Вам не хватает прав, чтобы узнать каких используйте {Formatter.InlineCode($"{this.Bot.Config.Discord.Prefixes.RandomElement()}help {e.Command.QualifiedName}")}"));

                    break;
                }
                }

                break;
            }

            case DatabaseException dbEx:
            {
                var description = new StringBuilder("Произошла ошибка в работе БД, возможно стоит попробовать чуть позже.");
                description.AppendLine(string.IsNullOrWhiteSpace(dbEx.Message)
                                                ? $"Тип действия: {dbEx.ActionType.ToString()}"
                                                : $"Сообщение - {Formatter.InlineCode(dbEx.Message)}. Тип действия: {dbEx.ActionType.ToString()}");

                await e.Context.RespondAsync(embed : EmbedTemplates.CommandErrorEmbed(e.Context.Member, e.Command)
                                             .WithDescription(description.ToString())).ConfigureAwait(false);

                break;
            }

            case DiscordUserInputException inputEx:
            {
                await e.Context.RespondAsync($"{inputEx.Message}. Название параметра {inputEx.ArgumentName}").ConfigureAwait(false);

                break;
            }

            case CommandNotFoundException commandNotFoundException:
            {
                var cmdName           = commandNotFoundException.CommandName;
                var suggestedCommands = new List <Command>();
                var nL = new NormalizedLevenshtein();

                // Let's assumme that 0.33 is good Levenshtein distance

                foreach (var cmd in this.Commands.RegisteredCommands.Values.Distinct())
                {
                    if (cmd is CommandGroup cmdGroup)
                    {
                        foreach (var children in cmdGroup.Children)
                        {
                            if (Helpers.IsCommandSimilar(children, cmdName, nL))
                            {
                                suggestedCommands.Add(children);
                            }
                        }
                        if (cmdGroup.IsExecutableWithoutSubcommands && Helpers.IsCommandSimilar(cmdGroup, cmdName, nL))
                        {
                            suggestedCommands.Add(cmdGroup);
                        }
                    }
                    else
                    {
                        if (Helpers.IsCommandSimilar(cmd, cmdName, nL))
                        {
                            suggestedCommands.Add(cmd);
                        }
                    }
                }

                if (suggestedCommands.Any())
                {
                    suggestedCommands.OrderBy(x => x.QualifiedName);
                    var description = new StringBuilder();
                    description.AppendLine($"Команды с названием {Formatter.InlineCode(cmdName)} не найдено. Вот возможные варианты того, что вы имели в виду:");
                    foreach (var cmd in suggestedCommands)
                    {
                        description.AppendLine(Formatter.InlineCode(cmd.QualifiedName));
                    }

                    await e.Context.RespondAsync(embed : EmbedTemplates.ErrorEmbed()
                                                 .WithDescription(description.ToString())).ConfigureAwait(false);
                }
                break;
            }

            case InvalidOperationException invOpEx when invOpEx.Message == "No matching subcommands were found, and this group is not executable.":
            {
                //Ignore.
                break;
            }

            default:
            {
                var embed = EmbedTemplates.CommandErrorEmbed(e.Context.Member, e.Command)
                            .WithTitle("Произошла непредвиденная ошибка в работе команды")
                            .WithDescription($"Message: \n{Formatter.InlineCode(ex.Message)}\n в \n{Formatter.InlineCode(ex.Source)}");
                await e.Context.RespondAsync(embed : embed).ConfigureAwait(false);

                await this.Bot.ErrorChannel.SendMessageAsync(embed : embed).ConfigureAwait(false);

                break;
            }
            }
        }
예제 #19
0
        protected override async Task RunCore(CancellationToken token)
        {
            if (!await GoToMainScreen(token))
            {
                Logger.LogError("Could not go to main menu");
                return;
            }

            if (!await OpenMenu().ConfigureAwait(false))
            {
                Logger.LogError("Could not open main menu");
                return;
            }

            Game.Click(UIds.MAIN_MENU_CHALLENGES_BUTTON);

            await Task.Delay(1000, token);

            if (!await ClickWhenVisible(UIds.CHALLENGES_DAILY_TRIVIA_TAB))
            {
                Game.OnError(new ElementNotFoundError(Repository[UIds.CHALLENGES_DAILY_TRIVIA_TAB]));
            }

            await Task.Delay(1000, token);

            if (!await WaitUntil(() =>
                                 Game.IsVisible(UIds.CHALLENGES_DAILY_START_BUTTON) ||
                                 Game.IsVisible(UIds.CHALLENGES_DAILY_TRIVIA_BASIC_REWARD), token))
            {
                Logger.LogInformation("Daily trivia already completed");
                return;
            }

            if (Game.IsVisible(UIds.CHALLENGES_DAILY_START_BUTTON))
            {
                Game.Click(UIds.CHALLENGES_DAILY_START_BUTTON);
            }

            await Task.Delay(2000, token);

            var questionStatus = Game.GetText(UIds.CHALLENGES_DAILY_TRIVIA_QUESTION_STATUS);

            if (questionStatus.Contains("/5"))
            {
                Logger.LogInformation("Daily Trivia already started");
            }
            else
            {
                Logger.LogError("Start button did not appear");
                return;
            }

            var nl = new NormalizedLevenshtein();

            while (Game.IsVisible(UIds.CHALLENGES_DAILY_TRIVIA_BASIC_REWARD) && !token.IsCancellationRequested)
            {
                var question = Game.GetText(UIds.CHALLENGES_DAILY_TRIVIA_QUESTION);
                Logger.LogDebug($"Question is: {question}");
                string answer = null;
                double highestSimilarityQuestion = 0;
                foreach (var item in _questionsAndAnswers)
                {
                    var similarity = nl.Similarity(question, item.Question);
                    if (similarity > highestSimilarityQuestion)
                    {
                        highestSimilarityQuestion = similarity;
                        Logger.LogDebug($"Found question that matches better: {item.Question}");
                        answer = item.Answer;
                    }
                }

                Logger.LogDebug($"Expected answer is: {answer}");

                double    highestSimilarityAnswer = 0;
                UiElement bestAnswerElement       = null;
                for (int i = 0; i < 4; i++)
                {
                    var answerId        = Repository[UIds.CHALLENGES_DAILY_TRIVIA_ANSWER_DYN, 0, i];
                    var potentialAnswer = Game.GetText(answerId);
                    var similarity      = nl.Similarity(potentialAnswer, answer);
                    Logger.LogDebug($"Found potential answer '{potentialAnswer}' that has a similarity of: {similarity * 100f}%");
                    if (similarity > highestSimilarityAnswer)
                    {
                        highestSimilarityAnswer = similarity;
                        bestAnswerElement       = answerId;
                    }
                }

                if (bestAnswerElement == null)
                {
                    Logger.LogError("Could not find answer for question.");
                    return;
                }

                Game.Click(bestAnswerElement);
                if (!await WaitUntilVisible(UIds.CHALLENGES_DAILY_TRIVIA_CLOSE_BUTTON))
                {
                    Logger.LogError($"Close button did not appear. Wrong answer? Q: {question} A: {answer}");
                    return;
                }
                await Task.Delay(500, token);

                Game.Click(UIds.CHALLENGES_DAILY_TRIVIA_CLOSE_BUTTON);

                await Task.Delay(2000, token);
            }

            Logger.LogInformation("Daily trivia completed");
        }