LIMA
Libre Multilingual Analyzer — C++ API
Loading...
Searching...
No Matches
lima.cpp
Go to the documentation of this file.
1// Copyright 2019-2022 CEA LIST
2// SPDX-FileCopyrightText: 2019-2022 CEA LIST <gael.de-chalendar@cea.fr>
3//
4// SPDX-License-Identifier: MIT
5
6/****************************************************************************
7**
8** Copyright (C) 2018 The Qt Company Ltd.
9** Contact: https://www.qt.io/licensing/
10**
11** This file is part of the Qt for Python examples of the Qt Toolkit.
12**
13** $QT_BEGIN_LICENSE:BSD$
14** Commercial License Usage
15** Licensees holding valid commercial Qt licenses may use this file in
16** accordance with the commercial license agreement provided with the
17** Software or, alternatively, in accordance with the terms contained in
18** a written agreement between you and The Qt Company. For licensing terms
19** and conditions see https://www.qt.io/terms-conditions. For further
20** information use the contact form at https://www.qt.io/contact-us.
21**
22** BSD License Usage
23** Alternatively, you may use this file under the terms of the BSD license
24** as follows:
25**
26** "Redistribution and use in source and binary forms, with or without
27** modification, are permitted provided that the following conditions are
28** met:
29** * Redistributions of source code must retain the above copyright
30** notice, this list of conditions and the following disclaimer.
31** * Redistributions in binary form must reproduce the above copyright
32** notice, this list of conditions and the following disclaimer in
33** the documentation and/or other materials provided with the
34** distribution.
35** * Neither the name of The Qt Company Ltd nor the names of its
36** contributors may be used to endorse or promote products derived
37** from this software without specific prior written permission.
38**
39**
40** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
43** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
44** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
46** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
51**
52** $QT_END_LICENSE$
53**
54****************************************************************************/
55
56#include "lima.h"
58#include "common/LimaCommon.h"
59#include "common/LimaVersion.h"
65#include "common/QsLog/QsLog.h"
74
93#include <deque>
94#include <fstream>
95#include <iostream>
96#include <iomanip>
97#include <map>
98#include <memory>
99#include <set>
100#include <string>
101#include <vector>
102
103#include <boost/algorithm/string.hpp>
104#include <boost/algorithm/string/find_format.hpp>
105#include <boost/algorithm/string/finder.hpp>
106#include <boost/format.hpp>
107
108#include <QtCore/QCoreApplication>
109#include <QtCore/QString>
110
111#include <QtCore>
112
113using namespace Lima::LinguisticProcessing;
116using namespace Lima::Common::AnnotationGraphs;
117using namespace Lima::Common::MediaticData;
120using namespace Lima::Common::Misc;
121using namespace Lima::Common::PropertyCode;
123using namespace Lima;
124
126{
127 template<typename FindResultT>
128 std::string operator()(const FindResultT& Match) const
129 {
130 std::string s;
131 for (typename FindResultT::const_iterator i = Match.begin();
132 i != Match.end();
133 i++) {
134 s += boost::str(boost::format("\\x%02x") % static_cast<int>(*i));
135 }
136 return s;
137 }
138};
139
140std::shared_ptr< std::ostringstream > openHandlerOutputString(
142 const std::set<std::string>&dumpers,
143 const std::string& dumperId);
144
145int run(int aargc,char** aargv);
146
148{
149 friend class LimaAnalyzer;
150public:
151 LimaAnalyzerPrivate(const QStringList& qlangs,
152 const QStringList& qpipelines,
153 const QString& modulePath,
154 const QString& user_config_path,
155 const QString& user_resources_path,
156 const QString& meta);
160
161 void initMetaData();
162
163 bool addPipelineUnit(const std::string& pipeline,
164 const std::string& media,
165 const std::string& jsonGroupString);
166
167 const std::string analyzeText(const std::string& text,
168 const std::string& lang,
169 const std::string& pipeline,
170 const std::string& meta);
171
172 void collectDependencyInformations(std::shared_ptr<Lima::AnalysisContent> analysis);
174 std::shared_ptr<Lima::AnalysisContent> analysis);
175
179 QString getNeType(LinguisticGraphVertex posGraphVertex);
180
181 std::pair<QString, int> getConllRelName(LinguisticGraphVertex v);
182
184
186
188
190
192 void reset();
193
194 QJsonObject objectFromString(const QString& in);
195
197
198 const FsaStringsPool* sp = nullptr;
199 MediaId medId;
200
201
202 const LanguageData* languageData = nullptr;
207 std::shared_ptr<SyntacticData> syntacticData = nullptr;
208 std::map< LinguisticGraphVertex,
209 std::pair<LinguisticGraphVertex,
211 QMap<QString, QString> conllLimaDepMapping;
212
213
214 std::map<LinguisticGraphVertex, int> vertexToToken;
215
217 // Fixed members that do not change at each analysis
218 std::map<std::string, AbstractAnalysisHandler*> handlers;
219 std::unique_ptr<BowTextWriter> bowTextWriter = nullptr;
220 std::unique_ptr<BowTextHandler> bowTextHandler = nullptr;
221 std::unique_ptr<SimpleStreamHandler> simpleStreamHandler = nullptr;
222 std::unique_ptr<SimpleStreamHandler> fullXmlSimpleStreamHandler = nullptr;
223 std::unique_ptr<LTRTextHandler> ltrTextHandler = nullptr;
224 std::set<std::string> dumpers = {"text"};
225 std::shared_ptr< AbstractLinguisticProcessingClient > m_client;
226 std::map<std::string,std::string> metaData;
227 // Store constructor parameters to be able to implement copy constructor
228 QStringList qlangs;
229 QStringList qpipelines;
230 QString modulePath;
233 QString meta;
234};
235
236
238 const QStringList& iqpipelines,
239 const QString& imodulePath,
240 const QString& iuser_config_path,
241 const QString& iuser_resources_path,
242 const QString& imeta) :
243 qlangs(iqlangs), qpipelines(iqpipelines), modulePath(imodulePath),
244 user_config_path(iuser_config_path), user_resources_path(iuser_resources_path), meta(imeta)
245{
246 int argc = 1;
247 char* argv[2] = {(char*)("LimaAnalyzer"), NULL};
248 QCoreApplication app(argc, argv);
249
250 if(iqlangs.size() == 0)
251 {
252 throw LimaException("Must initialize at least one language");
253 }
254 if(iqpipelines.size() == 0)
255 {
256 throw LimaException("Must initialize at least one pipeline");
257 }
258
259 QStringList additionalPaths({modulePath+"/config"});
260 // Add here LIMA_CONF content in front, otherwise it will be ignored
261 auto limaConf = QString::fromUtf8(qgetenv("LIMA_CONF").constData());
262 if (!limaConf.isEmpty())
263 additionalPaths = limaConf.split(LIMA_PATH_SEPARATOR, Qt::SkipEmptyParts) + additionalPaths;
264 // Add then the user path in front again such that it takes precedence on environment variable
265 if (!user_config_path.isEmpty())
266 additionalPaths.push_front(user_config_path);
267 auto configDirs = buildConfigurationDirectoriesList(QStringList({"lima"}),
268 additionalPaths);
269 auto configPath = configDirs.join(LIMA_PATH_SEPARATOR);
270
271 QStringList additionalResourcePaths({modulePath+"/resources"});
272 // Add here LIMA_RESOURCES content in front, otherwise it will be ignored
273 auto limaRes = QString::fromUtf8(qgetenv("LIMA_RESOURCES").constData());
274 if (!limaRes.isEmpty())
275 additionalResourcePaths = limaRes.split(LIMA_PATH_SEPARATOR, Qt::SkipEmptyParts) + additionalResourcePaths;
276 if (!user_resources_path.isEmpty())
277 additionalResourcePaths.push_front(user_resources_path);
278 auto resourcesDirs = buildResourcesDirectoriesList(QStringList({"lima"}),
279 additionalResourcePaths);
280 auto resourcesPath = resourcesDirs.join(LIMA_PATH_SEPARATOR);
281
282 QsLogging::initQsLog(configPath);
283 // std::cerr << "QsLog initialized " << configPath.toStdString() << std::endl;
284 // Necessary to initialize factories
286 // std::cerr << "LimaAnalyzerPrivate::LimaAnalyzerPrivate() plugins manager created" << std::endl;
287 if (!Lima::AmosePluginsManager::changeable().loadPlugins(configPath))
288 {
289 throw InvalidConfiguration("loadLibrary method failed.");
290 }
291 // qDebug() << "Amose plugins are now initialized";
292
293
294 std::string lpConfigFile = "lima-analysis.xml";
295 std::string commonConfigFile = "lima-common.xml";
296 std::string clientId = "lima-coreclient";
297
298 std::string strConfigPath;
299
300 initMetaData();
301
302 std::deque<std::string> pipelines;
303 for (const auto& pipeline: qpipelines)
304 pipelines.push_back(pipeline.toStdString());
305
306
307 // uint64_t beginTime=TimeUtils::getCurrentTime();
308
309 std::deque<std::string> langs;
310 for (const auto& lang: qlangs)
311 langs.push_back(lang.toStdString());
312 // std::cerr << "LimaAnalyzerPrivate::LimaAnalyzerPrivate() "
313 // << resourcesPath.toUtf8().constData() << ", "
314 // << configPath.toUtf8().constData() << ", "
315 // << commonConfigFile << ", "
316 // << qlangs.join(",").toStdString() << std::endl;
317 // initialize common. Forward the parsed meta data as options so that e.g.
318 // "udlang" (the treebank selecting the deeplima models, passed as
319 // meta "udlang:eng-UD_English-EWT") is available to the process units at init
320 // time via MediaticData::getOptionValue.
321 Common::MediaticData::MediaticData::changeable().init(
322 resourcesPath.toUtf8().constData(),
323 configPath.toUtf8().constData(),
324 commonConfigFile,
325 langs,
326 metaData);
327 // std::cerr << "MediaticData initialized" << std::endl;
328
329 bool clientFactoryConfigured = false;
330 Q_FOREACH(QString configDir, configDirs)
331 {
332 if (QFileInfo::exists(configDir + "/" + lpConfigFile.c_str()))
333 {
334 // std::cerr << "LimaAnalyzerPrivate::LimaAnalyzerPrivate() configuring "
335 // << (configDir + "/" + lpConfigFile.c_str()).toUtf8().constData() << ", "
336 // << clientId << std::endl;
337
338 // initialize linguistic processing
340 (configDir + "/" + lpConfigFile.c_str()));
341 LinguisticProcessingClientFactory::changeable().configureClientFactory(
342 clientId,
343 lpconfig,
344 langs,
345 pipelines);
346 clientFactoryConfigured = true;
347 break;
348 }
349 }
350 if(!clientFactoryConfigured)
351 {
352 std::cerr << "No LinguisticProcessingClientFactory were configured with"
353 << configDirs.join(LIMA_PATH_SEPARATOR).toStdString()
354 << "and" << lpConfigFile << std::endl;
355 throw LimaException("Configuration failure");
356 }
357 // std::cerr << "Client factory configured" << std::endl;
358
359 m_client = std::shared_ptr< AbstractLinguisticProcessingClient >(
360 std::dynamic_pointer_cast<AbstractLinguisticProcessingClient>(
361 LinguisticProcessingClientFactory::single().createClient(clientId)));
362
363 // Set the handlers
364 bowTextWriter = std::make_unique<BowTextWriter>();
365 handlers.insert(std::make_pair("bowTextWriter", bowTextWriter.get()));
366 bowTextHandler = std::make_unique<BowTextHandler>();
367 handlers.insert(std::make_pair("bowTextHandler", bowTextHandler.get()));
368 simpleStreamHandler = std::make_unique<SimpleStreamHandler>();
369 handlers.insert(std::make_pair("simpleStreamHandler", simpleStreamHandler.get()));
370 fullXmlSimpleStreamHandler = std::make_unique<SimpleStreamHandler>();
371 handlers.insert(std::make_pair("fullXmlSimpleStreamHandler", fullXmlSimpleStreamHandler.get()));
372 ltrTextHandler= std::make_unique<LTRTextHandler>();
373 handlers.insert(std::make_pair("ltrTextHandler", ltrTextHandler.get()));
374 // std::cerr << "LimaAnalyzerPrivate constructor done" << std::endl;
375
376}
377
378LimaAnalyzer::LimaAnalyzer(const std::string& langs,
379 const std::string& pipelines,
380 const std::string& modulePath,
381 const std::string& user_config_path,
382 const std::string& user_resources_path,
383 const std::string& meta)
384{
385 try
386 {
387 QStringList qlangs = QString::fromStdString(langs).split(",", Qt::SkipEmptyParts);
388 QStringList qpipelines = QString::fromStdString(pipelines).split(",", Qt::SkipEmptyParts);
389 m_d = new LimaAnalyzerPrivate(qlangs, qpipelines,
390 QString::fromStdString(modulePath),
391 QString::fromStdString(user_config_path),
392 QString::fromStdString(user_resources_path),
393 QString::fromStdString(meta));
394 }
395 catch (const Lima::LimaException& e)
396 {
397 std::cerr << "Lima internal error: " << e.what() << std::endl;
398 m_d = nullptr;
399 error = true;
400 errorMessage = e.what();
401 }
402}
403
405{
406 delete m_d;
407}
408
410{
411 try
412 {
413 m_d = new LimaAnalyzerPrivate(a.m_d->qlangs, a.m_d->qpipelines,
414 a.m_d->modulePath,
415 a.m_d->user_config_path,
416 a.m_d->user_resources_path,
417 a.m_d->meta);
418 }
419 catch (const Lima::LimaException& e)
420 {
421 std::cerr << "Lima internal error: " << e.what() << std::endl;
422 m_d = nullptr;
423 error = true;
424 errorMessage = e.what();
425 }
426 // std::cerr << "LimaAnalyzer::LimaAnalyzer copy constructor" << std::endl;
427}
428
430{
431 try
432 {
433 // std::cerr << "LimaAnalyzer::operator=" << std::endl;
434 delete m_d;
435 m_d = new LimaAnalyzerPrivate(a.m_d->qlangs, a.m_d->qpipelines,
436 a.m_d->modulePath,
437 a.m_d->user_config_path,
438 a.m_d->user_resources_path,
439 a.m_d->meta);
440 return *this;
441 }
442 catch (const Lima::LimaException& e)
443 {
444 std::cerr << "Lima internal error: " << e.what() << std::endl;
445 m_d = nullptr;
446 error = true;
447 errorMessage = e.what();
448 }
449 return *this;
450}
451
453{
454 previousNeType = "O";
455 sp = nullptr;
456 medId = 0;
457 languageData = nullptr;
458 syntacticData = nullptr;
459 propertyAccessor = nullptr;
460 posGraph = nullptr;
461 anaGraph = nullptr;
462 annotationData = nullptr;
463 propertyCodeManager = nullptr;
465 conllLimaDepMapping.clear();
466 vertexToToken.clear();
467}
468
470{
471 // parse 'meta' argument to add metadata
472 if (!meta.isEmpty())
473 {
474 auto metas = meta.split(",", Qt::SkipEmptyParts);
475 for (const auto& aMeta: metas)
476 {
477 auto kv = aMeta.split(":");
478 if (kv.size() != 2)
479 {
480 std::cerr << "meta argument '"<< aMeta.toStdString() << "' is not of the form XXX:YYY: ignored" << std::endl;
481 }
482 else
483 {
484 metaData[kv[0].toStdString()] = kv[1].toStdString();
485 }
486 }
487 }
488}
489
490bool LimaAnalyzer::addPipelineUnit(const std::string& pipeline,
491 const std::string& media,
492 const std::string& jsonGroupString)
493{
494 if (! m_d->addPipelineUnit(pipeline, media, jsonGroupString))
495 {
496 error = true;
497 errorMessage = std::string("addPipelineUnit failed:") + pipeline + ", "
498 + media + ",\n" + jsonGroupString;
499 return false;
500 }
501 return true;
502}
503
504QJsonObject LimaAnalyzerPrivate::objectFromString(const QString& in)
505{
506 QJsonObject obj;
507
508 QJsonDocument doc = QJsonDocument::fromJson(in.toUtf8());
509
510 // check validity of the document
511 if(!doc.isNull())
512 {
513 if(doc.isObject())
514 {
515 obj = doc.object();
516 }
517 else
518 {
519 qDebug() << "Document is not an object" << Qt::endl;
520 }
521 }
522 else
523 {
524 qDebug() << "Invalid JSON...\n" << in << Qt::endl;
525 }
526
527 return obj;
528}
529
530bool LimaAnalyzerPrivate::addPipelineUnit(const std::string& pipeline,
531 const std::string& media,
532 const std::string& jsonGroupString)
533{
534 auto jsonGroup = QJsonDocument::fromJson(QByteArray::fromStdString(jsonGroupString)).object();
536 auto pipe = MediaProcessors::changeable().getPipelineForId(mediaid, pipeline);
537 auto managers = Lima::MediaProcessors::single().managers();
538 // QString jsonGroupString =
539 // "{ \"name\":\"cpptftokenizer\", "
540 // " \"class\":\"CppUppsalaTensorFlowTokenizer\", "
541 // " \"model_prefix\": \"tokenizer-eng\" }";
542
543 GroupConfigurationStructure unitConfig(jsonGroup);
544
545 // managers (Manager*) used in init of ProcessUnits are stored in
546 // m_pipelineManagers of MediaProcessors
547 auto pu = MediaProcessUnit::Factory::getFactory(
548 jsonGroup["class"].toString().toStdString())->create(
549 unitConfig,
550 managers[mediaid]);
551 pipe->push_back(pu);
552
553 return true;
554}
555
556std::string LimaAnalyzer::analyzeText(const std::string& text,
557 const std::string& lang,
558 const std::string& pipeline,
559 const std::string& meta)
560{
561 // std::cerr << "LimaAnalyzer::analyzeText" << std::endl;
562 if (m_d == nullptr || error)
563 {
564 error = true;
565 errorMessage = "Invalid Lima analyzer. Previous error message was: " + errorMessage;
566 return "";
567 }
568 try
569 {
570 return m_d->analyzeText(text, lang, pipeline, meta);
571 }
572 catch (const Lima::LimaException& e)
573 {
574 std::cerr << "Lima internal error: " << e.what() << std::endl;
575 error = true;
576 errorMessage = e.what();
577 return "";
578 }
579}
580
581const std::string LimaAnalyzerPrivate::analyzeText(const std::string& text,
582 const std::string& lang,
583 const std::string& pipeline,
584 const std::string& meta)
585{
586 auto txtofs = openHandlerOutputString(simpleStreamHandler.get(), dumpers, "text");
587
588 auto localMetaData = metaData;
589 localMetaData["FileName"]="param";
590 auto qmeta = QString::fromStdString(meta).split(",", Qt::SkipEmptyParts);
591 for (const auto& m: qmeta)
592 {
593 auto kv = m.split(":");
594 if (kv.size() == 2)
595 localMetaData[kv[0].toStdString()] = kv[1].toStdString();
596 }
597
598 auto localLang = lang;
599 if (localLang.size() == 0)
600 {
601 localLang = qlangs[0].toStdString();
602 }
603 auto localPipeline = pipeline;
604 if (localPipeline.size() == 0)
605 {
606 localPipeline = qpipelines[0].toStdString();
607 }
608 localMetaData["Lang"] = localLang;
609
610 QString contentText = QString::fromUtf8(text.c_str());
611 if (contentText.isEmpty())
612 {
613 std::cerr << "Empty input ! " << std::endl;
614 }
615 else
616 {
617 // analyze it
618 // std::cerr << "Analyzing " << contentText.toStdString() << std::endl;
619 m_client->analyze(contentText, localMetaData, localPipeline, handlers);
620 }
621 auto result = txtofs->str();
622 // std::cerr << "LimaAnalyzerPrivate::analyzeText result: " << result << std::endl;
623 simpleStreamHandler->setOut(nullptr);
624 return result;
625}
626
627std::shared_ptr< std::ostringstream > openHandlerOutputString(
629 const std::set<std::string>&dumpers,
630 const std::string& dumperId)
631{
632 auto ofs = std::make_shared< std::ostringstream >();
633 if (dumpers.find(dumperId)!=dumpers.end())
634 {
635 handler->setOut(ofs.get());
636 }
637 else
638 {
640 LERROR << dumperId << "is not in the dumpers list";
641 }
642 return ofs;
643}
644
646{
647#ifdef DEBUG_LP
649 LDEBUG << "getFeats";
650#endif
651 auto managers = propertyCodeManager->getPropertyManagers();
652
653 QStringList featuresList;
654 for (auto i = managers.cbegin(); i != managers.cend(); i++)
655 {
656 auto key = QString::fromUtf8(i->first.c_str());
657 if (key != "MACRO" && key != "MICRO")
658 {
659 const auto& pa = propertyCodeManager->getPropertyAccessor(key.toStdString());
660 LinguisticCode lc = morphoData.firstValue(pa);
661 auto value = QString::fromUtf8(i->second.getPropertySymbolicValue(lc).c_str());
662 if (value != "NONE")
663 {
664 featuresList << QString("%1=%2").arg(key).arg(value);
665 }
666 }
667 }
668
669 featuresList.sort();
670 QString features;
671 QTextStream featuresStream(&features);
672 if (featuresList.isEmpty())
673 {
674 features = "_";
675 }
676 else
677 {
678 for (auto featuresListIt = featuresList.cbegin(); featuresListIt != featuresList.cend(); featuresListIt++)
679 {
680 if (featuresListIt != featuresList.cbegin())
681 {
682 featuresStream << "|";
683 }
684 featuresStream << *featuresListIt;
685 }
686 }
687#ifdef DEBUG_LP
688 LDEBUG << "LimaAnalyzerPrivate::getFeats features:" << features;
689#endif
690
691 return features;
692}
693
694void LimaAnalyzerPrivate::collectDependencyInformations(std::shared_ptr<Lima::AnalysisContent> analysis)
695{
696#ifdef DEBUG_LP
698 LDEBUG << "LimaAnalyzerPrivate::collectVertexDependencyInformations";
699#endif
700
701 auto posGraphData = std::dynamic_pointer_cast<LinguisticAnalysisStructure::AnalysisGraph>(analysis->getData("PosGraph"));
702 if (posGraphData == nullptr)
703 {
704 std::cerr << "Error: PosGraph has not been produced: check pipeline";
705 return;
706 }
707
708 auto firstVertex = posGraphData->firstVertex();
709 auto lastVertex = posGraphData->lastVertex();
710 auto v = firstVertex;
711 auto [it, it_end] = boost::out_edges(v, *posGraph);
712 if (it != it_end)
713 {
714 v = boost::target(*it, *posGraph);
715 }
716 else
717 {
718 v = lastVertex;
719 }
720
721 syntacticData = std::dynamic_pointer_cast<SyntacticData>(analysis->getData("SyntacticData"));
722 if (syntacticData == nullptr)
723 {
724 syntacticData = std::make_shared<SyntacticData>(posGraphData.get(), nullptr);
725 syntacticData->setupDependencyGraph();
726 analysis->setData("SyntacticData", syntacticData);
727 }
728 int tokenId = 0;
729
730 while (v != lastVertex)
731 {
732 QString neType = getNeType(v);
733 QString neIOB = "O";
734 // Collect NE vertices and output them instead of a single line for
735 // current v. NE vertices can not only be PosGraph
736 // vertices (and thus can just call dumpPosGraphVertex
737 // recursively) but also AnalysisGraph vertices. In the latter case, data
738 // come partly from the AnalysisGraph and partly from the PosGraph
739 // Furthermore, named entities can be recursive...
740 if (neType != "_")
741 {
742 auto matches = annotationData->matches("PosGraph", v, "annot");
743 if (!matches.empty())
744 {
745 for (const auto& vx: matches)
746 {
747 if (annotationData->hasAnnotation(vx, QString::fromUtf8("SpecificEntity")))
748 {
749 auto se = annotationData->annotation(vx, QString::fromUtf8("SpecificEntity"))
750 .pointerValue<SpecificEntityAnnotation>();
751 previousNeType = "O";
752 // bool first = true;
753 for (const auto& vse : se->vertices())
754 {
756 vertexToToken[vse] = tokenId;
757 // first = false;
758 }
759 break;
760 }
761 }
762 }
763 else
764 {
765 auto anaVertices = annotationData->matches("PosGraph", v, "AnalysisGraph");
766 auto anaVertex = *anaVertices.begin();
767 if (annotationData->hasAnnotation(anaVertex, QString::fromUtf8("SpecificEntity")))
768 {
769 auto se = annotationData->annotation(anaVertex, QString::fromUtf8("SpecificEntity"))
771 // All retrieved lines/tokens have the same netype. Depending on the
772 // output style (CoNLL 2003, CoNLL-U, …), the generated line is different
773 // and the ne-Type includes or not BIO information using in this case the
774 // previousNeType member.
775 previousNeType = "O";
776 // bool first = true;
777 vertexToToken[v] = tokenId;
778 tokenId++;
779 for (const auto& vse : se->vertices())
780 {
781 auto posVertices = annotationData->matches("AnalysisGraph", vse, "PosGraph");
782 auto posVertex = *posVertices.begin();
783 // @TODO Should follow instructions here to output all MWE:
784 // https://universaldependencies.org/format.html#words-tokens-and-empty-nodes
785
786 // TODO Get correct UD dep relation for relations inside the named entity
787 // and for the token that must be linked to the outside. For this one, the
788 // relation is the one which links to posGraphVertex to the rest of the pos
789 // graph.
790 auto [conllRelName, targetConllId] = getConllRelName(v);
791
792 vertexToToken[posVertex] = tokenId;
793 // std::cerr << "docFrom_analysis pushing token" << std::endl;
794 // first = false;
795 }
796 previousNeType = neType;
797 }
798 }
799 }
800 else
801 {
802 vertexToToken[v] = tokenId;
803 tokenId++;
804 }
805
807
808 auto [it, it_end] = boost::out_edges(v, *posGraph);
809 if (it != it_end)
810 {
811 v = boost::target(*it, *posGraph);
812 }
813 else
814 {
815 v = lastVertex;
816 }
817
818 }
819}
820
822 std::shared_ptr<Lima::AnalysisContent> /*analysis*/)
823{
824 auto dcurrent = syntacticData->depVertexForTokenVertex(v);
825 auto depGraph = syntacticData->dependencyGraph();
826 for (auto [dit, dit_end] = boost::out_edges(dcurrent, *depGraph); dit != dit_end; dit++)
827 {
828 auto typeMap = get(edge_deprel_type, *depGraph);
829 auto type = typeMap[*dit];
830 auto syntRelName = languageData->getSyntacticRelationName(type);
831 auto dest = syntacticData->tokenVertexForDepVertex(
832 boost::target(*dit, *depGraph));
833 if (syntRelName != "")
834 {
835 vertexDependencyInformations.insert(std::make_pair(v, std::make_pair(dest, syntRelName)));
836 }
837 }
838}
839
841{
842 // std::cerr << "LimaAnalyzerPrivate::getNeType "<< posGraphVertex << std::endl;
843 auto neType = QString::fromUtf8("_") ;
844 if (annotationData != nullptr)
845 {
846 // Check if the PosGraph vertex holds a specific entity
847 // std::cerr << "LimaAnalyzerPrivate::getNeType call matches with " << "PosGraph"
848 // << " and " << posGraphVertex << std::endl;
849 auto matches = annotationData->matches("PosGraph", posGraphVertex, "annot");
850 // std::cerr << "LimaAnalyzerPrivate::getNeType got" << matches.size() << " matches" << std::endl;
851 for (const auto& vx: matches)
852 {
853 // std::cerr << "LimaAnalyzerPrivate::getNeType on match " << vx << std::endl;
854 if (annotationData->hasAnnotation(vx, QString::fromUtf8("SpecificEntity")))
855 {
856 auto se = annotationData->annotation(vx, QString::fromUtf8("SpecificEntity")).
857 pointerValue<SpecificEntityAnnotation>();
858 neType = MedData::single().getEntityName(se->getType());
859 break;
860 }
861 }
862 if (neType == "_")
863 {
864 // The PosGraph vertex did not hold a specific entity,
865 // check if the AnalysisGraph vertex does
866 // std::cerr << "LimaAnalyzerPrivate::getNeType checking AnalysisGraph" << std::endl;
867 auto anaVertices = annotationData->matches("PosGraph", posGraphVertex, "AnalysisGraph");
868 // note: anaVertices size should be 0 or 1
869 for (const auto& anaVertex: anaVertices)
870 {
871 // std::cerr << "LimaAnalyzerPrivate::getNeType on AnalysisGraph vertex " << anaVertex << std::endl;
872 auto matches = annotationData->matches("AnalysisGraph", anaVertex, "annot");
873 for (const auto& vx: matches)
874 {
875 // std::cerr << "LimaAnalyzerPrivate::getNeType on ana match " << vx << std::endl;
876 if (annotationData->hasAnnotation(vx, QString::fromUtf8("SpecificEntity")))
877 {
878 auto se = annotationData->annotation(vx, QString::fromUtf8("SpecificEntity"))
879 .pointerValue<SpecificEntityAnnotation>();
880 neType = MedData::single().getEntityName(se->getType());
881 break;
882 }
883 }
884 if (neType != "_") break;
885 }
886 }
887 }
888 // std::cerr << "LimaAnalyzerPrivate::getNeType for " << posGraphVertex << ". result = " << neType << std::endl;
889 return neType;
890}
891
893{
894#ifdef DEBUG_LP
896 LDEBUG << "LimaAnalyzerPrivate::getConllRelName" << v << vertexDependencyInformations.count(v);
897#endif
898 QString conllRelName = "_";
899 int targetConllId = 0;
900 if (vertexDependencyInformations.count(v) != 0)
901 {
902 auto target = vertexDependencyInformations.find(v)->second.first;
903#ifdef DEBUG_LP
904 LDEBUG << "LimaAnalyzerPrivate::getConllRelName target saved for" << v << "is" << target;
905#endif
906 if (vertexToToken.find(target) != vertexToToken.end())
907 {
908 targetConllId = vertexToToken.find(target)->second;
909 }
910 else
911 {
913 LERROR << "LimaAnalyzerPrivate::getConllRelName target" << target << "not found in segmentation mapping";
914 }
915#ifdef DEBUG_LP
916 LDEBUG << "LimaAnalyzerPrivate::getConllRelName conll target saved for " << v << " is " << targetConllId;
917#endif
918 auto relName = QString::fromStdString(vertexDependencyInformations.find(v)->second.second);
919#ifdef DEBUG_LP
920 LDEBUG << "LimaAnalyzerPrivate::getConllRelName the lima dependency tag for " << v << " is " << relName;
921#endif
922 if (conllLimaDepMapping.contains(relName))
923 {
924 conllRelName = conllLimaDepMapping[relName];
925 }
926 else
927 {
928 conllRelName = relName;
929// LERROR << "LimaAnalyzerPrivate::getConllRelName" << relName << "not found in mapping";
930 }
931
932 // There is no way for vertex to have 0 as head.
933 if (conllRelName == "root")
934 {
935 targetConllId = 0;
936 }
937 }
938 else
939 {
940#ifdef DEBUG_LP
941 LDEBUG << "LimaAnalyzerPrivate::getConllRelName no target saved for" << v;
942#endif
943 }
944#ifdef DEBUG_LP
945 LDEBUG << "LimaAnalyzerPrivate::getConllRelName result for" << v << "is" << conllRelName << targetConllId;
946#endif
947 return { conllRelName, targetConllId };
948}
949
951 LinguisticGraphVertex v) const
952{
953 // check only entity found in current graph (not previous graph such as AnalysisGraph)
954
955 for (const auto& vx: annotationData->matches("PosGraph", v, "annot"))
956 {
957 if (annotationData->hasAnnotation(vx, QString::fromUtf8("SpecificEntity")))
958 {
959 //BoWToken* se = createSpecificEntity(v,*it, annotationData, anagraph, posgraph, offsetBegin);
960 auto se = annotationData->annotation(
961 vx,
962 QString::fromUtf8("SpecificEntity")).pointerValue<SpecificEntityAnnotation>();
963 if (se != nullptr)
964 {
965 return se;
966 }
967 }
968 }
969 return nullptr;
970
971}
972
974{
975 auto ft = get(vertex_token, *graph, v);
976 bool SpaceAfter = true;
977 LinguisticGraphOutEdgeIt outIter, outIterEnd;
978 for (auto [outIter, outIterEnd] = boost::out_edges(v, *graph);
979 outIter != outIterEnd; outIter++)
980 {
981 auto next = boost::target(*outIter, *graph);
982 auto nt = get(vertex_token, *graph, next);
983 if( nt != nullptr && (nt->position() == ft->position()+ft->length()) )
984 {
985 SpaceAfter = false;
986 break;
987 }
988 }
989 return SpaceAfter;
990}
991
993{
994 return QString::fromUtf8(static_cast<const LangData&>(
995 MedData::single().mediaData(medId)).getPropertyCodeManager()
996 .getPropertyManager("MICRO")
997 .getPropertySymbolicValue(morphoData.firstValue(
998 *propertyAccessor)).c_str());
999}
This file is the main header file for the data related to annotation graphs.
A graph that stores the relations of syntactic dependency between the elements of a DependencyGraph.
@ edge_deprel_type
#define LIMA_PATH_SEPARATOR
Definition FileUtils.h:25
#define LDEBUG
Definition LimaCommon.h:157
#define LERROR
Definition LimaCommon.h:161
@ vertex_token
LinguisticGraph::vertex_descriptor LinguisticGraphVertex
LinguisticGraph::out_edge_iterator LinguisticGraphOutEdgeIt
boost::adjacency_list< boost::vecS, boost::vecS, boost::bidirectionalS, LinguisticVertexProperties > LinguisticGraph
Property to identify the chains in the graph.
#define DUMPERLOGINIT
Data used for the syntactic analyzis of texts.
const FsaStringsPool * sp
Definition lima.cpp:198
LinguisticGraph * posGraph
Definition lima.cpp:204
std::unique_ptr< LTRTextHandler > ltrTextHandler
Definition lima.cpp:223
std::unique_ptr< BowTextWriter > bowTextWriter
Definition lima.cpp:219
void initMetaData()
Definition lima.cpp:469
QMap< QString, QString > conllLimaDepMapping
Definition lima.cpp:211
QString getNeType(LinguisticGraphVertex posGraphVertex)
Gets the named entity type for the PosGraph vertex posGraphVertex if it is a specific entity.
Definition lima.cpp:840
const std::string analyzeText(const std::string &text, const std::string &lang, const std::string &pipeline, const std::string &meta)
Definition lima.cpp:581
LimaAnalyzerPrivate & operator=(const LimaAnalyzerPrivate &a)=delete
QString previousNeType
Definition lima.cpp:196
const LanguageData * languageData
Definition lima.cpp:202
std::map< LinguisticGraphVertex, int > vertexToToken
Definition lima.cpp:214
AnnotationData * annotationData
Definition lima.cpp:206
QStringList qlangs
Definition lima.cpp:228
void collectDependencyInformations(std::shared_ptr< Lima::AnalysisContent > analysis)
Definition lima.cpp:694
std::unique_ptr< SimpleStreamHandler > fullXmlSimpleStreamHandler
Definition lima.cpp:222
std::map< std::string, AbstractAnalysisHandler * > handlers
Definition lima.cpp:218
std::shared_ptr< SyntacticData > syntacticData
Definition lima.cpp:207
QJsonObject objectFromString(const QString &in)
Definition lima.cpp:504
const SpecificEntityAnnotation * getSpecificEntityAnnotation(LinguisticGraphVertex v) const
Definition lima.cpp:950
~LimaAnalyzerPrivate()=default
LimaAnalyzerPrivate(const LimaAnalyzerPrivate &a)=delete
QString modulePath
Definition lima.cpp:230
std::unique_ptr< BowTextHandler > bowTextHandler
Definition lima.cpp:220
std::pair< QString, int > getConllRelName(LinguisticGraphVertex v)
Definition lima.cpp:892
bool addPipelineUnit(const std::string &pipeline, const std::string &media, const std::string &jsonGroupString)
Definition lima.cpp:530
const Common::PropertyCode::PropertyAccessor * propertyAccessor
Definition lima.cpp:203
QString getFeats(const LinguisticAnalysisStructure::MorphoSyntacticData &morphoData)
Definition lima.cpp:645
const PropertyCodeManager * propertyCodeManager
Definition lima.cpp:216
void reset()
Reset all members used to store analysis states.
Definition lima.cpp:452
QString getMicro(LinguisticAnalysisStructure::MorphoSyntacticData &morphoData)
Definition lima.cpp:992
QStringList qpipelines
Definition lima.cpp:229
std::shared_ptr< AbstractLinguisticProcessingClient > m_client
Definition lima.cpp:225
void collectVertexDependencyInformations(LinguisticGraphVertex v, std::shared_ptr< Lima::AnalysisContent > analysis)
Definition lima.cpp:821
std::set< std::string > dumpers
Definition lima.cpp:224
std::map< std::string, std::string > metaData
Definition lima.cpp:226
LinguisticGraph * anaGraph
Definition lima.cpp:205
LimaAnalyzerPrivate(const QStringList &qlangs, const QStringList &qpipelines, const QString &modulePath, const QString &user_config_path, const QString &user_resources_path, const QString &meta)
Definition lima.cpp:237
QString user_resources_path
Definition lima.cpp:232
std::unique_ptr< SimpleStreamHandler > simpleStreamHandler
Definition lima.cpp:221
bool hasSpaceAfter(LinguisticGraphVertex v, LinguisticGraph *graph)
Definition lima.cpp:973
QString user_config_path
Definition lima.cpp:231
std::map< LinguisticGraphVertex, std::pair< LinguisticGraphVertex, std::string > > vertexDependencyInformations
Definition lima.cpp:210
std::string errorMessage
Definition lima.h:90
LimaAnalyzer & operator=(const LimaAnalyzer &a)
Definition lima.cpp:429
LimaAnalyzer(const std::string &langs, const std::string &pipelines, const std::string &modulePath, const std::string &user_config_path="", const std::string &user_resources_path="", const std::string &meta="")
Definition lima.cpp:378
friend class LimaAnalyzerPrivate
Definition lima.h:67
~LimaAnalyzer()
Definition lima.cpp:404
std::string analyzeText(const std::string &text, const std::string &lang="", const std::string &pipeline="", const std::string &meta="")
Definition lima.cpp:556
bool addPipelineUnit(const std::string &pipeline, const std::string &media, const std::string &jsonGroupString)
Definition lima.cpp:490
bool error
Definition lima.h:89
virtual void setOut(std::ostream *out)=0
set the output stream.
Holds an annotation graph and gives an API to manipulate it.
std::set< AnnotationGraphVertex > matches(const std::string &first, AnnotationGraphVertex firstVx, const std::string &second) const
Gets the set of vertices matched in the second graph by the given vertex of the first graph.
const GenericAnnotation & annotation(AnnotationGraphVertex v1, AnnotationGraphVertex v2, const LimaString &annot) const
Holds linguistic data for one language.
const std::string & getSyntacticRelationName(SyntacticRelationId id) const
holds data about codes and names for grammatical categories, etc.
const std::string & getMediaId(MediaId idNum) const
LimaString getEntityName(const EntityType &type) const
Provide function to read write and check a property.
Provide tools to parse a property file, and deal with the property coding system.
const std::map< std::string, PropertyManager > & getPropertyManagers() const
Get the map of all PropertyManagers.
const PropertyAccessor & getPropertyAccessor(const std::string &propertyName) const
Get the PropertyAccessor associated to a property.
Parser class for the lima's xml configuration files.
Use this exception to signal an error in one of the configuration files.
Definition LimaCommon.h:345
The main LIMA exception class.
Definition LimaCommon.h:262
virtual const char * what() const override
Definition LimaCommon.h:280
LinguisticCode firstValue(const Common::PropertyCode::PropertyAccessor &propertyAccessor) const
Return the first non empty value for the given accessor.
A representation of a specific entity to store in the annotation graph.
const std::map< MediaId, MediaProcessUnit::Manager * > & managers() const
static const AmosePluginsManager & single()
const singleton accessor
Definition Singleton.h:51
static AmosePluginsManager & changeable()
singleton accessor
Definition Singleton.h:71
originally detectGroupConfigurationStructure.h in detectlibraries
bool hasAnnotation(AnnotationGraphVertex v, const LimaString &annot) const
int run(int aargc, char **aargv)
Definition main.cpp:31
std::shared_ptr< std::ostringstream > openHandlerOutputString(AbstractTextualAnalysisHandler *handler, const std::set< std::string > &dumpers, const std::string &dumperId)
Definition lima.cpp:627
QStringList buildResourcesDirectoriesList(const QStringList &projects, const QStringList &paths)
Build a list of resources directories from a list of project names and a list of paths.
QStringList buildConfigurationDirectoriesList(const QStringList &projects, const QStringList &paths)
Build a list of configuration directories from a list of project names and a list of paths.
NAUTITIA.
LIMA_COMMONQSLOG_EXPORT bool initQsLog(const QString &configString)
std::string operator()(const FindResultT &Match) const
Definition lima.cpp:128