Front End - NLP - work in progress

This commit is contained in:
vysitor 2025-03-17 20:26:18 +01:00
parent be1f993871
commit 5046f2bbe5
23 changed files with 185 additions and 21 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

BIN
src/.DS_Store vendored Normal file

Binary file not shown.

BIN
src/main/.DS_Store vendored Normal file

Binary file not shown.

BIN
src/main/java/.DS_Store vendored Normal file

Binary file not shown.

BIN
src/main/java/org/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -8,6 +8,7 @@ import org.texttechnologylab.project.gruppe_05_1.database.domainimp.speeches.Spe
import org.texttechnologylab.project.gruppe_05_1.domain.html.HtmlSpeech;
import org.texttechnologylab.project.gruppe_05_1.domain.html.Parlamentarier;
import org.texttechnologylab.project.gruppe_05_1.domain.html.ParlamentarierDetails;
import org.texttechnologylab.project.gruppe_05_1.domain.nlp.*;
import org.texttechnologylab.project.gruppe_05_1.domain.speaker.Membership;
import org.texttechnologylab.project.gruppe_05_1.domain.speech.SpeechMetaData;
import org.texttechnologylab.project.gruppe_05_1.util.GeneralUtils;
@ -417,10 +418,19 @@ public class MongoPprUtils {
}
}
/**
* Liefert die Rede-Informationen für die Anzeige einer Rede:
* - die Rede-ID
* - Name und Fraktion des Redners
* - Die Inhalte der Rede
* @param key: Rede ID
* @return
*/
public static HtmlSpeech getSpeechByKey(String key) {
Document filter = new Document("speechKey", key);
Document speechDoc = getSpeechCollection().find(filter).first();
return new HtmlSpeech(speechDoc);
}
}

View file

@ -2,6 +2,8 @@ package org.texttechnologylab.project.gruppe_05_1.domain.html;
import org.bson.Document;
import org.texttechnologylab.project.gruppe_05_1.database.MongoDBHandler;
import org.texttechnologylab.project.gruppe_05_1.domain.nlp.NlpInfo;
import org.texttechnologylab.project.gruppe_05_1.domain.nlp.Topic;
import java.util.ArrayList;
import java.util.List;
@ -13,6 +15,7 @@ public class HtmlSpeech {
String speakerName;
String fraction;
List<SpeechContent> content = new ArrayList<>();
NlpInfo nlp = null;
public HtmlSpeech() {
}
@ -30,6 +33,32 @@ public class HtmlSpeech {
addContent(new SpeechContent(contentDoc));
}
}
Document nlpDoc = (Document) doc.get("analysisResults");
nlp = readNlpInfo(nlpDoc);
}
private NlpInfo readNlpInfo(Document nlpDoc) {
if (nlpDoc == null) return null;
NlpInfo nlp = new NlpInfo();
// TODO: HERE
List<Document> tokensDocs = nlpDoc.get("tokens", MongoDBHandler.DOC_LIST_CLASS);
List<Document> sentencesDocs = nlpDoc.get("sentences", MongoDBHandler.DOC_LIST_CLASS);
List<Document> dependenciesDocs = nlpDoc.get("dependencies", MongoDBHandler.DOC_LIST_CLASS);
List<Document> namedEntitiesDocs = nlpDoc.get("namedEntities", MongoDBHandler.DOC_LIST_CLASS);
List<Document> sentimentsDocs = nlpDoc.get("sentiments", MongoDBHandler.DOC_LIST_CLASS);
List<Document> topicsDocs = nlpDoc.get("topics", MongoDBHandler.DOC_LIST_CLASS);
nlp.setTopics(Topic.readTopicsFromMongo(topicsDocs));
// TODO: Video
return nlp;
}
public String getSpeechKey() {
@ -68,16 +97,26 @@ public class HtmlSpeech {
content.add(contentLine);
}
public NlpInfo getNlp() {
return nlp;
}
public void setNlp(NlpInfo nlp) {
this.nlp = nlp;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof HtmlSpeech that)) return false;
return Objects.equals(speechKey, that.speechKey) && Objects.equals(speakerName, that.speakerName) && Objects.equals(fraction, that.fraction) && Objects.equals(content, that.content);
return Objects.equals(speechKey, that.speechKey) && Objects.equals(speakerName, that.speakerName)
&& Objects.equals(fraction, that.fraction) && Objects.equals(content, that.content)
&& Objects.equals(nlp, that.nlp);
}
@Override
public int hashCode() {
return Objects.hash(speechKey, speakerName, fraction, content);
return Objects.hash(speechKey, speakerName, fraction, content, nlp);
}
@Override
@ -87,6 +126,7 @@ public class HtmlSpeech {
.add("speakerName='" + speakerName + "'")
.add("fraction='" + fraction + "'")
.add("content=" + content)
.add("nlp=" + nlp)
.toString();
}
}

View file

@ -1,7 +1,9 @@
package org.texttechnologylab.project.gruppe_05_1.domain.nlp;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.StringJoiner;
public class NlpInfo {
List<Token> tokens;
@ -10,7 +12,7 @@ public class NlpInfo {
List<NamedEntity> namedEntities;
Sentiment overallSentiment; // Sentiment for the whole text ; kann null sein!
List<Sentiment> sentiments; // sentiments for the respective sentences (eine Liste von 0..n Elementen)
List<Topic> topic;
List<Topic> topics;
List<Pos> posList;
VideoInformation videoInformation;
@ -63,12 +65,12 @@ public class NlpInfo {
this.sentiments = sentiments;
}
public List<Topic> getTopic() {
return topic;
public List<Topic> getTopics() {
return topics;
}
public void setTopic(List<Topic> topic) {
this.topic = topic;
public void setTopics(List<Topic> topics) {
this.topics = topics;
}
public List<Pos> getPosList() {
@ -94,12 +96,28 @@ public class NlpInfo {
return Objects.equals(tokens, nlpInfo.tokens) && Objects.equals(sentences, nlpInfo.sentences)
&& Objects.equals(dependencies, nlpInfo.dependencies) && Objects.equals(namedEntities, nlpInfo.namedEntities)
&& Objects.equals(overallSentiment, nlpInfo.overallSentiment) && Objects.equals(sentiments, nlpInfo.sentiments)
&& Objects.equals(topic, nlpInfo.topic) && Objects.equals(posList, nlpInfo.posList)
&& Objects.equals(topics, nlpInfo.topics) && Objects.equals(posList, nlpInfo.posList)
&& Objects.equals(videoInformation, nlpInfo.videoInformation);
}
@Override
public int hashCode() {
return Objects.hash(tokens, sentences, dependencies, namedEntities, overallSentiment, sentiments, topic, posList, videoInformation);
return Objects.hash(tokens, sentences, dependencies, namedEntities, overallSentiment, sentiments, topics, posList, videoInformation);
}
@Override
public String toString() {
return new StringJoiner(", ", NlpInfo.class.getSimpleName() + "[", "]")
.add("tokens=" + tokens)
.add("sentences=" + sentences)
.add("dependencies=" + dependencies)
.add("namedEntities=" + namedEntities)
.add("overallSentiment=" + overallSentiment)
.add("sentiments=" + sentiments)
.add("topics=" + topics)
.add("posList=" + posList)
.add("videoInformation=" + videoInformation)
.toString();
}
}

View file

@ -1,18 +1,19 @@
package org.texttechnologylab.project.gruppe_05_1.domain.nlp;
import java.util.Objects;
import java.util.StringJoiner;
import org.bson.Document;
import java.util.*;
import java.util.stream.Collectors;
public class Topic {
String topic;
double score;
// tags TODO
Double score;
String text;
public Topic() {
}
public Topic(String topic, double score, String text) {
public Topic(String topic, Double score, String text) {
this.topic = topic;
this.score = score;
this.text = text;
@ -26,11 +27,11 @@ public class Topic {
this.topic = topic;
}
public double getScore() {
public Double getScore() {
return score;
}
public void setScore(double score) {
public void setScore(Double score) {
this.score = score;
}
@ -62,4 +63,45 @@ public class Topic {
.add("text='" + text + "'")
.toString();
}
/**
* Die Topics-Dokumente (Speech --> analysisResults --> topics) aus der MongoDB lesen
* @param topicsDocs Eine Liste von Mongo-Dokumenten
* @return Eine Liste der Topics
*/
public static List<Topic> readTopicsFromMongo(List<Document> topicsDocs) {
List<Topic> topics = new ArrayList<>();
for (Document doc : topicsDocs) {
topics.add(new Topic(doc.getString("topic"),
doc.getDouble("score"),
doc.getString("text")
));
}
return topics;
}
/**
* Topic-Informationen "verdichten":
* Ausgangssituation: eine Liste mit mehreren Topics. Ein Topic kann in dieser Liste mehrfach vorkommen.
* Man will wissen, welche Score hat jeden Topic. Hier werden die Werte der jeweiligen Topics summiert.
*
* @param topicsList
* @return Map<String, Double>
*/
public static Map<String, Double> condenseTopicInformation(List<Topic> topicsList) {
Map<String, Double> condensedTopicInfo = new HashMap<>();
for (Topic t : topicsList) {
Double oldValue = condensedTopicInfo.get(t.getTopic());
if (oldValue != null) {
condensedTopicInfo.replace(t.getTopic(), oldValue + t.getScore());
} else {
condensedTopicInfo.put(t.getTopic(), t.getScore());
}
}
return condensedTopicInfo;
}
}

View file

@ -5,12 +5,14 @@ import io.javalin.openapi.*;
import org.texttechnologylab.project.gruppe_05_1.database.MongoPprUtils;
import org.texttechnologylab.project.gruppe_05_1.domain.html.HtmlSpeech;
import org.texttechnologylab.project.gruppe_05_1.domain.html.ParlamentarierDetails;
import org.texttechnologylab.project.gruppe_05_1.domain.nlp.Topic;
import org.texttechnologylab.project.gruppe_05_1.domain.speech.SpeechMetaData;
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.Speech;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class SpeechController {
/**
@ -68,6 +70,15 @@ public class SpeechController {
HtmlSpeech speech = MongoPprUtils.getSpeechByKey(redeId);
attributes.put("s", speech);
// NLP: Topic
if ((speech.getNlp() != null) && (speech.getNlp().getTopics() != null)) {
Map<String, Double> topics = Topic.condenseTopicInformation(speech.getNlp().getTopics()); // Daten "verdichten"...
speech.getNlp().setTopics(
topics.entrySet().stream()
.map(me -> new Topic(me.getKey(), me.getValue(), null))
.collect(Collectors.toList()));
}
ctx.render("speech.ftl", attributes);
}

View file

@ -0,0 +1,35 @@
<#if s.nlp.topics??>
<h3>Topics Information (als Bubble Chart)</h3>
<#assign condenseTopicInformation = s.nlp.topics>
<#include "topicsBubbleChart.ftl">
<#else>
<h3>Keine Topics Information für diese Rede verfügbar</h3>
</#if>
<#if s.nlp.posList??>
<h3>POS Information (als Bar Chart)</h3>
<#assign posList = s.nlp.posList>
<#include "posBarChart.ftl">
<#else>
<h3>Keine POS Information verfügbar für diese Rede verfügbar</h3>
</#if>
<#if s.nlp.sentiments??>
<h3>SentimentsInformation (als Radar Chart)</h3>
<#assign overallSentiment = s.nlp.overallSentiment>
<#assign sentiments = s.nlp.sentiments>
<#include "sentimentsRadarChart.ftl">
<#else>
<h3>Keine Sentiments Information für diese Rede verfügbar</h3>
</#if>
<#if s.nlp.namedEntities??>
<h3>Named Entities Information (als Sunburst Chart)</h3>
<#assign nea = s.nlp.namedEntities>
<#include "namedEntitiesSunburstChart.ftl">
<#else>
<h3>Keine Named Entities Information für diese Rede verfügbar</h3>
</#if>

View file

@ -22,11 +22,19 @@
<h2>Rede ${s.speechKey} </h2>
<main>
<#list s.content as c>
<#include "speechContent.ftl">
</#list>
</main>
<#list s.content as c>
<#include "speechContent.ftl">
</#list>
<br><br>
<#if s.nlp??>
<h2>NLP Information</h2>
<#assign nlp = "${s.nlp}">
<#include "nlp.ftl">
<#else>
<h2>Keine NLP Information verfügbar für diese Rede</h2>
</#if>
<br> <br>
</body>

BIN
src/main/resources/.DS_Store vendored Normal file

Binary file not shown.