From 64282897a3ec1dc6f4bbd5941dba803fbbebb130 Mon Sep 17 00:00:00 2001 From: vmonakhov Date: Wed, 5 Feb 2025 20:48:13 +0300 Subject: [PATCH 1/6] Refactoring --- src/components/CognateAnalysisModal/index.js | 150 +++++++++++++------ src/pages/Perspective/component.js | 8 + 2 files changed, 115 insertions(+), 43 deletions(-) diff --git a/src/components/CognateAnalysisModal/index.js b/src/components/CognateAnalysisModal/index.js index 8195f4dd..1f6999c2 100644 --- a/src/components/CognateAnalysisModal/index.js +++ b/src/components/CognateAnalysisModal/index.js @@ -270,6 +270,7 @@ const computeNeuroCognateAnalysisMutation = gql` $matchTranslations: Boolean $baseLanguageId: LingvodocID $inputPairs: ObjectVal + $truthThreshold: Float ) { neuro_cognate_analysis( source_perspective_id: $sourcePerspectiveId @@ -277,6 +278,7 @@ const computeNeuroCognateAnalysisMutation = gql` match_translations: $matchTranslations base_language_id: $baseLanguageId input_pairs: $inputPairs + truth_threshold: $truthThreshold ) { triumph message @@ -659,6 +661,7 @@ class MLPerspectiveSelection extends React.Component { render() { const { + mode, treePathList, perspective, textFieldsOptions, @@ -727,21 +730,25 @@ class MLPerspectiveSelection extends React.Component { className="lingvo-dropdown-select lingvo-dropdown-select_cognate" /> -
{this.context("Source lexeme field (optional)")}:
-
- { + lexemeFieldIdStrMap[p_key] = value; + this.setState({ lexemeFieldIdStrMap }); + }} + icon={} + className="lingvo-dropdown-select lingvo-dropdown-select_cognate" + /> +
+ + )} )} @@ -953,6 +960,7 @@ class MLSelection extends React.Component { render() { const { mode, + computing, language_list, perspectiveSelectionMap, transcriptionFieldIdStrMap, @@ -1077,6 +1085,7 @@ class MLSelection extends React.Component { icon={} fluid placeholder={this.context("Add language")} + disabled={computing} search selection options={available_language_list @@ -1393,7 +1402,9 @@ class CognateAnalysisModal extends React.Component { sg_count: null, sg_entry_map: null, - sg_current_page: 1 + sg_current_page: 1, + + truthThreshold: 0.97 }; this.initialize_single = this.initialize_single.bind(this); @@ -1428,7 +1439,8 @@ class CognateAnalysisModal extends React.Component { this.props.mode === "multi_reconstruction" || this.props.mode === "multi_suggestions" || this.props.mode === "multi_swadesh" || - this.props.mode === "multi_morphology"; + this.props.mode === "multi_morphology" || + this.props.mode === "multi_neuro_suggestions"; (multi ? this.initialize_multi : this.initialize_single)(); this.setState({ lang_mode: multi ? "multi" : "single" }); @@ -1521,7 +1533,10 @@ class CognateAnalysisModal extends React.Component { /* If we are selecting perspectives for cognate suggestions, and the source perspective is not * published, we won't be able to proceed and therefore we need not bother with initialization. */ - if (mode === "suggestions" && english_status !== "Published" && english_status !== "Limited access") { + if ((mode === "suggestions" || mode === "neuro_suggestions") && + english_status !== "Published" && + english_status !== "Limited access") { + this.setState({ initialized: true }); return; } @@ -1586,7 +1601,9 @@ class CognateAnalysisModal extends React.Component { /* If we are selecting perspectives for cognate suggestions, and the source perspective is not * published, we won't be able to proceed and therefore we need not bother with initialization. */ - if (mode === "multi_suggestions" && english_status !== "Published" && english_status !== "Limited access") { + if ((mode === "multi_suggestions" || mode === "multi_neuro_suggestions") && + english_status !== "Published" && english_status !== "Limited access") { + this.setState({ initialized: true }); return; } @@ -2157,7 +2174,7 @@ class CognateAnalysisModal extends React.Component { } } - handleNeuroResult({ data: { neuro_cognate_analysis }}) + handleNeuroResult({ neuro_cognate_analysis }) { const { triumph, message, suggestion_list, perspective_name_list, transcription_count } = neuro_cognate_analysis; const suggestion_list_cur = (this.state.suggestion_list ?? []).concat(suggestion_list); @@ -2165,7 +2182,8 @@ class CognateAnalysisModal extends React.Component { const { sg_select_list, sg_state_list, sg_count, sg_entry_map } = this.state; if (!triumph && message.length) { - window.logger.err(message); + window.logger.err(this.context(message)); + return false; } if (triumph && suggestion_list.length) { @@ -2179,15 +2197,16 @@ class CognateAnalysisModal extends React.Component { dictionary_count: perspective_name_list.length, suggestion_field_id: this.state.groupFieldIdStr.split(','), ...this.handleSuggestionResult({ suggestion_list, sg_select_list, sg_state_list, sg_count, sg_entry_map }), - //computing: false, cleanResult: false, result: "" }); + + return true; } handleCognateResult({ data: { cognate_analysis }}) { - const {suggestion_list} = cognate_analysis + const {suggestion_list} = cognate_analysis; /* Updating state with computed analysis info. */ this.setState({ @@ -2373,11 +2392,11 @@ class CognateAnalysisModal extends React.Component { } catch(error_data) { this.handleError(error_data); } - } else if (this.props.mode === "neuro_suggestions") { + } else if (this.props.mode === "neuro_suggestions" || this.props.mode === "multi_neuro_suggestions") { const info = perspectiveInfoList.find(inf => isEqual(inf[1], perspectiveId)); - if (info && info.length > 3) { + if (perspectiveInfoList.length > 1 && info && info.length > 3) { this.props.client.query({ query: wordsQuery, variables: { @@ -2401,23 +2420,44 @@ class CognateAnalysisModal extends React.Component { const start = Date.now(); const total = groups.length; - this.setState({ computing: true, total }); + // Initialize states for new process + this.setState({ + computing: true, + result: null, + estimate: null, + suggestion_list: null, + sg_select_list: null, + sg_state_list: null, + sg_count: null, + sg_entry_map: null, + dictionary_count: 0, + transcription_count: 0, + total + }); for (const [done, pairs] of groups.entries()) { this.setState({ done }); - //console.log("Running " + (done+1) + "th"); - await computeNeuroCognateAnalysis({ + + const { data, error } = await computeNeuroCognateAnalysis({ variables: { inputPairs: pairs, matchTranslations: this.state.matchTranslationsFlag, sourcePerspectiveId: perspectiveId, baseLanguageId: this.baseLanguageId, + truthThreshold: this.state.truthThreshold, perspectiveInfoList } - }).then( - data => this.handleNeuroResult(data), - error_data => this.handleError(error_data) - ) + }); + + if (error) { + this.handleError(error); + return; + } + + if (!this.handleNeuroResult(data)) { + this.setState({ computing: false }); + return; + } const duration = (Date.now() - start) / 1000; const estimate = duration / (done + 1) * total - duration; @@ -2426,17 +2466,18 @@ class CognateAnalysisModal extends React.Component { const minutes = Math.round((estimate - days * 86400 - hours * 3600) / 60); this.setState({ estimate: `${days}d:${hours}h:${minutes}m` }); - - //console.log("Done " + (done+1) + "th\n"); } - this.setState({ computing: false, estimate: null }); }); + } else { - window.logger.err("No source perspective is selected!"); - this.setState({ computing: false }); + + window.logger.err(this.context("No source perspective and/or perspective(s) for comparing is selected")); } + this.setState({ computing: false }); + } else { + /* Otherwise we will launch it as usual and then will wait for results to display them. */ this.setState({ computing: true }); @@ -2508,17 +2549,32 @@ class CognateAnalysisModal extends React.Component { match_translations_render() { return ( <> + { + this.setState({ truthThreshold: value }); + }} + className="lingvo-labeled-input" + style={{ marginBottom: "1em" }} + />
{ this.setState({ matchTranslationsFlag: checked }); }} className="lingvo-checkbox lingvo-checkbox_labeled" />
- { this.props.mode !== "neuro_suggestions" && ( + { this.props.mode !== "neuro_suggestions" && this.props.mode !== "multi_neuro_suggestions" && ( <>
@@ -2583,6 +2639,7 @@ class CognateAnalysisModal extends React.Component { { this.setState({ debugFlag: checked }); }} @@ -2593,6 +2650,7 @@ class CognateAnalysisModal extends React.Component { { this.setState({ intermediateFlag: checked }); }} @@ -2708,6 +2766,7 @@ class CognateAnalysisModal extends React.Component { )} - {!error_flag && this.props.mode === "multi_suggestions" && this.match_translations_render()} + {!error_flag && + (this.props.mode === "multi_suggestions" || this.props.mode === "multi_neuro_suggestions") && + this.match_translations_render()} {!error_flag && this.props.user.id == 1 && this.admin_section_render()} @@ -2920,8 +2981,8 @@ class CognateAnalysisModal extends React.Component { />
- {map( - suggestion_list.slice(start_index, start_index + SUGGESTIONS_PER_PAGE), + { suggestion_list && + map(suggestion_list.slice(start_index, start_index + SUGGESTIONS_PER_PAGE), ( [perspective_index, word, word_entry_id, word_group, single_list, group_list], @@ -3095,7 +3156,7 @@ class CognateAnalysisModal extends React.Component { status += ` ${done}/${total}`; } if (estimate) { - status += ` (${estimate} ${this.context("left")})`; + status += ` (${estimate} ${this.context("left for now")})`; } return ( @@ -3133,6 +3194,8 @@ class CognateAnalysisModal extends React.Component { ? this.context("Composite distance") : mode === "neuro_suggestions" ? this.context("Neuro cognate suggestions") + : mode === "multi_neuro_suggestions" + ? this.context("Neuro cognate multi-language suggestions") : this.context("Cognate analysis")} @@ -3201,7 +3264,8 @@ class CognateAnalysisModal extends React.Component { {this.state.result.length > 0 && mode !== "suggestions" && mode !== "multi_suggestions" && - mode !== "neuro_suggestions" && ( + mode !== "neuro_suggestions" && + mode !== "multi_neuro_suggestions" && (
{this.context("XLSX-exported analysis results")}

diff --git a/src/pages/Perspective/component.js b/src/pages/Perspective/component.js index 83cd26a7..aac3878b 100644 --- a/src/pages/Perspective/component.js +++ b/src/pages/Perspective/component.js @@ -1020,6 +1020,14 @@ const Tools = ({ : "Neuro cognate suggestions (disabled, perspective is not published)" )} + + openCognateAnalysisModal(id, "multi_neuro_suggestions")} disabled={!published}> + {getTranslation( + published + ? "Neuro cognate multi-language suggestions" + : "Neuro cognate multi-language suggestions (disabled, perspective is not published)" + )} + )} From 77266547d1fe502ffc4d822694165514cc02aee6 Mon Sep 17 00:00:00 2001 From: vmonakhov Date: Wed, 5 Feb 2025 23:07:10 +0300 Subject: [PATCH 2/6] Stop button --- src/api/i18n.js | 4 + src/components/CognateAnalysisModal/index.js | 108 +++++++++++-------- 2 files changed, 67 insertions(+), 45 deletions(-) diff --git a/src/api/i18n.js b/src/api/i18n.js index 0dfe8574..4ae191c9 100644 --- a/src/api/i18n.js +++ b/src/api/i18n.js @@ -485,6 +485,7 @@ export const stringsToTranslate = [ "Languages databases", "Last modified at", "left", + "left for now", "Left text", "Legend", "Levenshtein distance limit for entity content matching", @@ -609,6 +610,7 @@ export const stringsToTranslate = [ "No filtered verbs", "No groups to select", "No header", + "No input words or words to compare is received", "No instances", "No language degree of endangerment found", "No languages found", @@ -617,6 +619,7 @@ export const stringsToTranslate = [ "no prefix", "No results found.", "No settlement found", + "No source perspective and/or perspective(s) for comparing is selected", "No statistics for the selected period", "No suggestions", "No translations.", @@ -954,6 +957,7 @@ export const stringsToTranslate = [ "Transliteration", "transpnition marker", "Transposition", + "Truth threshold", "Try closing the dialog and opening it again; if the error persists, please contact administrators.", "Try reloading the page; if the error persists, please contact administrators.", "Type", diff --git a/src/components/CognateAnalysisModal/index.js b/src/components/CognateAnalysisModal/index.js index 1f6999c2..13cba03c 100644 --- a/src/components/CognateAnalysisModal/index.js +++ b/src/components/CognateAnalysisModal/index.js @@ -2404,14 +2404,14 @@ class CognateAnalysisModal extends React.Component { xcriptFldId: info[2], xlatFldId: info[3] } - }).then(async ({ data: { words }}) => { + }).then(({ data: { words }}) => { // We are going to get predictions for a group at once // So we don't have to wait for all the process completion, // and we don't have to initialize prediction model for every single word const groups = []; - const group_size = 8; + const group_size = 4; for (let i = 0; i < words.length; i += group_size) { groups.push(words.slice(i, i + group_size)); @@ -2421,61 +2421,72 @@ class CognateAnalysisModal extends React.Component { const total = groups.length; // Initialize states for new process - this.setState({ - computing: true, - result: null, - estimate: null, - suggestion_list: null, - sg_select_list: null, - sg_state_list: null, - sg_count: null, - sg_entry_map: null, - dictionary_count: 0, - transcription_count: 0, - total - }); + this.setState( + { + computing: true, + result: null, + estimate: null, + suggestion_list: null, + sg_select_list: null, + sg_state_list: null, + sg_count: null, + sg_entry_map: null, + dictionary_count: 0, + transcription_count: 0, + total + }, + // Running after setstate + async () => { + for (const [done, pairs] of groups.entries()) { + this.setState({ done }); + + const { data, error } = await computeNeuroCognateAnalysis({ + variables: { + inputPairs: pairs, + matchTranslations: this.state.matchTranslationsFlag, + sourcePerspectiveId: perspectiveId, + baseLanguageId: this.baseLanguageId, + truthThreshold: this.state.truthThreshold, + perspectiveInfoList + } + }); - for (const [done, pairs] of groups.entries()) { - this.setState({ done }); - - const { data, error } = await computeNeuroCognateAnalysis({ - variables: { - inputPairs: pairs, - matchTranslations: this.state.matchTranslationsFlag, - sourcePerspectiveId: perspectiveId, - baseLanguageId: this.baseLanguageId, - truthThreshold: this.state.truthThreshold, - perspectiveInfoList - } - }); + // On Stop button click + if (!this.state.computing) { + return; + } - if (error) { - this.handleError(error); - return; - } + if (error) { + this.handleError(error); + return; + } - if (!this.handleNeuroResult(data)) { - this.setState({ computing: false }); - return; - } + // If any troubles in response + if (!this.handleNeuroResult(data)) { + this.setState({ computing: false }); + return; + } - const duration = (Date.now() - start) / 1000; - const estimate = duration / (done + 1) * total - duration; - const days = Math.trunc(estimate / 86400); - const hours = Math.trunc((estimate - days * 86400) / 3600); - const minutes = Math.round((estimate - days * 86400 - hours * 3600) / 60); + const duration = (Date.now() - start) / 1000; + const estimate = duration / (done + 1) * total - duration; + const days = Math.trunc(estimate / 86400); + const hours = Math.trunc((estimate - days * 86400) / 3600); + const minutes = Math.round((estimate - days * 86400 - hours * 3600) / 60); - this.setState({ estimate: `${days}d:${hours}h:${minutes}m` }); - } + this.setState({ estimate: `${days}d:${hours}h:${minutes}m` }); + } + + this.setState({ computing: false }); + } + ); }); } else { window.logger.err(this.context("No source perspective and/or perspective(s) for comparing is selected")); + this.setState({ computing: false }); } - this.setState({ computing: false }); - } else { /* Otherwise we will launch it as usual and then will wait for results to display them. */ @@ -3202,6 +3213,13 @@ class CognateAnalysisModal extends React.Component { { lang_mode === "none" ? this.browse_files_render() : this.language_render(lang_mode === "multi") } + { (mode === "neuro_suggestions" || mode === "multi_neuro_suggestions") && computing && ( +