Merge branch 'speech_export_feature'
This commit is contained in:
commit
0af10f2f19
21 changed files with 1230 additions and 7 deletions
|
@ -21,6 +21,7 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import static java.lang.Boolean.FALSE;
|
||||
import static java.lang.Boolean.TRUE;
|
||||
import static org.texttechnologylab.project.gruppe_05_1.export.TeXUtil.isTeXSdkInstalled;
|
||||
import static org.texttechnologylab.project.gruppe_05_1.util.PPRUtils.checkAndProcessNewProtocols;
|
||||
|
||||
public class Main {
|
||||
|
@ -34,11 +35,13 @@ public class Main {
|
|||
private static final FileObjectFactory xmlFactory = FileObjectFactory.getFactory();
|
||||
private static final MongoObjectFactory mongoFactory = MongoObjectFactory.getFactory();
|
||||
|
||||
public static final String RESOURCES_DIR = "src/main/resources";
|
||||
public static final String CONFIG_DIR = "src/main/resources/config";
|
||||
public static final String JAVALIN_TEMPLATE_DIR = "src/main/resources/templates";
|
||||
public static final String JAVALIN_STATIC_FILES_DIR = "src/main/resources/static";
|
||||
public static final String JCAS_SPEECHES_TYPESYSTEM_DIR = "src/main/resources/speeches/TypeSystem";
|
||||
public static final String MEMBER_IMAGES_DIR = "src/main/resources/membersOfParliamentImages/";
|
||||
public static final String TEMP_EXPORT_DIR = "src/main/resources/tempExport/";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
UPLOAD_MEMBER_PHOTOS = Arrays.asList(args).contains("uploadMemberPhotos");
|
||||
|
@ -59,6 +62,12 @@ public class Main {
|
|||
System.out.println(" - Debug Logging: " + DEBUG_LOGGING);
|
||||
System.out.println("--------------------------------------------o");
|
||||
|
||||
if (!isTeXSdkInstalled()) {
|
||||
Logger.orange("-------------------------------------------------o");
|
||||
Logger.orange("TeX SDK not installed. PDF export will not work.");
|
||||
Logger.orange("-------------------------------------------------o");
|
||||
}
|
||||
|
||||
if (ONLY_RUN_WEB) {
|
||||
Logger.info("Starting Web Service...");
|
||||
RESTHandler restHandler = new RESTHandler();
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.mongodb.client.model.Projections;
|
|||
import io.javalin.http.Context;
|
||||
import org.bson.Document;
|
||||
import org.bson.conversions.Bson;
|
||||
import org.texttechnologylab.project.gruppe_05_1.database.domainimpl.mdb.Speaker_MongoDB_Impl;
|
||||
import org.texttechnologylab.project.gruppe_05_1.database.domainimpl.mdb.Speech_MongoDB_Impl;
|
||||
import org.texttechnologylab.project.gruppe_05_1.domain.html.HtmlSpeech;
|
||||
import org.texttechnologylab.project.gruppe_05_1.domain.html.Parlamentarier;
|
||||
|
@ -294,6 +295,15 @@ public class MongoPprUtils {
|
|||
return readParlamentarierDetailsFromSpeaker(doc);
|
||||
}
|
||||
|
||||
public static Speaker_MongoDB_Impl getSpeakerById(String id) {
|
||||
Logger.debug("ID: " + id);
|
||||
Document doc = MongoDBHandler.findFirstDocumentInCollection(getSpeakerCollection(), "_id", id);
|
||||
Logger.debug("Speaker: " + doc);
|
||||
Speaker_MongoDB_Impl speaker = new Speaker_MongoDB_Impl().createSpeakerMongoDBImpl(doc);
|
||||
Logger.debug("Speaker parsed" + speaker);
|
||||
return speaker;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Holt die Details eines Parlamentariers
|
||||
|
@ -638,7 +648,7 @@ public class MongoPprUtils {
|
|||
* @param key: Rede ID
|
||||
* @return
|
||||
*/
|
||||
public static HtmlSpeech getSpeechByKey(String key) {
|
||||
public static HtmlSpeech getHTMLSpeechByKey(String key) {
|
||||
Document filter = new Document("speechKey", key);
|
||||
Document speechDoc = getSpeechCollection().find(filter).first();
|
||||
if (speechDoc == null) {
|
||||
|
@ -649,6 +659,18 @@ public class MongoPprUtils {
|
|||
return new HtmlSpeech(speechDoc);
|
||||
}
|
||||
|
||||
public static Speech getSpeechByKey(String key) {
|
||||
Document filter = new Document("speechKey", key);
|
||||
Document speechDoc = getSpeechCollection().find(filter).first();
|
||||
|
||||
if (speechDoc == null) {
|
||||
Logger.error("Rede " + key + " nicht gefunden");
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Speech_MongoDB_Impl(speechDoc, true);
|
||||
}
|
||||
|
||||
// getMemberPhoto
|
||||
|
||||
/**
|
||||
|
@ -721,6 +743,36 @@ public class MongoPprUtils {
|
|||
Logger.info("Updating Metadata Collection: end");
|
||||
}
|
||||
|
||||
public static List<Speech> getSpeechesBySpeakerId(String speakerId) {
|
||||
List<Speech> speechIds = new ArrayList<>();
|
||||
Document filter = new Document("speakerId", Integer.parseInt(speakerId));
|
||||
List<Document> docs = getSpeechCollection().find(filter).into(new ArrayList<>());
|
||||
for (Document doc : docs) {
|
||||
speechIds.add(new Speech_MongoDB_Impl(doc, true));
|
||||
}
|
||||
return speechIds;
|
||||
}
|
||||
|
||||
public static List<Speech> getAllSpeeches() {
|
||||
List<Speech> speechIds = new ArrayList<>();
|
||||
Document filter = new Document();
|
||||
List<Document> docs = getSpeechCollection().find(filter).into(new ArrayList<>());
|
||||
for (Document doc : docs) {
|
||||
speechIds.add(new Speech_MongoDB_Impl(doc, true));
|
||||
}
|
||||
return speechIds;
|
||||
}
|
||||
|
||||
public static List<Speech> getAllSpeechesWithTopic(String topic) {
|
||||
List<Speech> speechIds = new ArrayList<>();
|
||||
Document filter = new Document("analysisResults.topics.topic", topic);
|
||||
List<Document> docs = getSpeechCollection().find(filter).into(new ArrayList<>());
|
||||
for (Document doc : docs) {
|
||||
speechIds.add(new Speech_MongoDB_Impl(doc, true));
|
||||
}
|
||||
return speechIds;
|
||||
}
|
||||
|
||||
public static List<String> getAllPartiesOfSpeakers() {
|
||||
Document doc = MongoDBHandler.findFirstDocumentInCollection(getMetadataCollection(), "type", "parties_of_speakers");
|
||||
if (doc == null) {return new ArrayList<>();}
|
||||
|
|
|
@ -5,15 +5,59 @@ import org.texttechnologylab.project.gruppe_05_1.database.MongoDBHandler;
|
|||
import org.texttechnologylab.project.gruppe_05_1.database.MongoOperations;
|
||||
import org.texttechnologylab.project.gruppe_05_1.domain.speaker.Membership;
|
||||
import org.texttechnologylab.project.gruppe_05_1.domain.speaker.Speaker;
|
||||
import org.texttechnologylab.project.gruppe_05_1.util.Logger;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.*;
|
||||
|
||||
import static org.texttechnologylab.project.gruppe_05_1.Main.TEMP_EXPORT_DIR;
|
||||
import static org.texttechnologylab.project.gruppe_05_1.database.MongoPprUtils.getMemberPhoto;
|
||||
|
||||
public class Speaker_MongoDB_Impl extends Speaker implements MongoOperations<Speaker> {
|
||||
public Speaker_MongoDB_Impl createSpeakerMongoDBImpl(Document mongoDocument) {
|
||||
this.setId(mongoDocument.getString("_id"));
|
||||
this.setName(mongoDocument.getString("name"));
|
||||
this.setFirstName(mongoDocument.getString("firstName"));
|
||||
this.setTitle(mongoDocument.getString("title"));
|
||||
this.setGeburtsdatum(parseTimestampSafely(mongoDocument.getDate("geburtsdatum")));
|
||||
this.setGeburtsort(mongoDocument.getString("geburtsort"));
|
||||
this.setSterbedatum(parseTimestampSafely(mongoDocument.getDate("sterbedatum")));
|
||||
this.setGeschlecht(mongoDocument.getString("geschlecht"));
|
||||
this.setBeruf(mongoDocument.getString("beruf"));
|
||||
this.setAkademischertitel(mongoDocument.getString("akademischertitel"));
|
||||
this.setFamilienstand(mongoDocument.getString("familienstand"));
|
||||
this.setReligion(mongoDocument.getString("religion"));
|
||||
this.setVita(mongoDocument.getString("vita"));
|
||||
this.setParty(mongoDocument.getString("party"));
|
||||
|
||||
List<Document> memberships = (List<Document>) mongoDocument.get("memberships");
|
||||
List<Membership> membershipList = new ArrayList<>();
|
||||
for (Document membership : memberships) {
|
||||
Membership membershipObj = new Membership();
|
||||
membershipObj.setRole(membership.getString("role"));
|
||||
membershipObj.setMember(membership.getString("member"));
|
||||
membershipObj.setBegin(parseTimestampSafely(membership.getDate("begin")));
|
||||
membershipObj.setEnd(parseTimestampSafely(membership.getDate("end")));
|
||||
membershipObj.setLabel(membership.getString("label"));
|
||||
membershipObj.setWp(membership.getInteger("wp"));
|
||||
membershipList.add(membershipObj);
|
||||
}
|
||||
this.setMemberships(membershipList);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public LocalDate parseTimestampSafely(Date timestamp) {
|
||||
try {
|
||||
return LocalDate.parse(timestamp.toString());
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public Document createEntity(Speaker entity) {
|
||||
|
||||
|
@ -48,4 +92,96 @@ public class Speaker_MongoDB_Impl extends Speaker implements MongoOperations<Spe
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public String toTeX() {
|
||||
// Save image to file
|
||||
File outputFile = null;
|
||||
byte[] imageBytes = null;
|
||||
// Decode the Base64 string to a byte array
|
||||
try {
|
||||
imageBytes = Base64.getDecoder().decode(getMemberPhoto(this.getId()));
|
||||
|
||||
// check if imageBytes is empty
|
||||
if (imageBytes.length != 0) {
|
||||
// Define the output PNG file
|
||||
outputFile = new File(TEMP_EXPORT_DIR + "speaker_photo_" + this.getId() + ".png");
|
||||
|
||||
// Write the decoded byte array to the file
|
||||
try (FileOutputStream fos = new FileOutputStream(outputFile)) {
|
||||
fos.write(imageBytes);
|
||||
Logger.debug("PNG file has been saved successfully.");
|
||||
} catch (IOException e) {
|
||||
Logger.error("Failed to save member PNG file.");
|
||||
Logger.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logger.warn("Failed to decode member photo. Maybe its missing from the DB?");
|
||||
Logger.debug(Arrays.toString(e.getStackTrace()));
|
||||
}
|
||||
|
||||
// Spkeaer metadata LaTeX code with image, Full Name + title, party, religion, dob, dod, pob, gender, ID
|
||||
StringBuilder tex = new StringBuilder();
|
||||
// image on the left, metadata on the right
|
||||
tex.append("\\begin{minipage}{0.5\\textwidth}\n");
|
||||
if (imageBytes != null) {
|
||||
tex.append("\\includegraphics[width=0.5\\textwidth]{").append("speaker_photo_" + this.getId() + ".png").append("}\n");
|
||||
} else {
|
||||
tex.append("(No image available)\n");
|
||||
}
|
||||
tex.append("\\end{minipage}\n");
|
||||
tex.append("\\begin{minipage}{0.5\\textwidth}\n");
|
||||
tex.append("\\begin{tabular}{r l}\n");
|
||||
if (this.getTitle() != null) {
|
||||
tex.append("Name & ").append(this.getTitle()).append(" ").append(this.getFirstName()).append(" ").append(this.getName()).append("\\\\\n");
|
||||
} else {
|
||||
tex.append("Name & ").append(this.getFirstName()).append(" ").append(this.getName()).append("\\\\\n");
|
||||
}
|
||||
tex.append("Fraktion & ").append(this.getParty()).append("\\\\\n");
|
||||
if (this.getReligion() != null) {
|
||||
tex.append("Religion & ").append(this.getReligion()).append("\\\\\n"); // only show if available
|
||||
}
|
||||
if (this.getGeburtsdatum() != null) {
|
||||
tex.append("Geburtsdatum & ").append(this.getGeburtsdatum()).append("\\\\\n");
|
||||
}
|
||||
if (this.getSterbedatum() != null) {
|
||||
tex.append("Sterbedatum & ").append(this.getSterbedatum()).append("\\\\\n"); // only show if available
|
||||
}
|
||||
tex.append("Geburtsort & ").append(this.getGeburtsort()).append("\\\\\n");
|
||||
tex.append("\\end{tabular}\n");
|
||||
tex.append("\\end{minipage}\n");
|
||||
return tex.toString();
|
||||
}
|
||||
|
||||
public Element toXML(org.w3c.dom.Document doc) {
|
||||
Element speakerElement = doc.createElement("speaker");
|
||||
speakerElement.setAttribute("id", this.getId());
|
||||
speakerElement.setAttribute("name", this.getName());
|
||||
speakerElement.setAttribute("firstName", this.getFirstName());
|
||||
speakerElement.setAttribute("title", this.getTitle() != null ? this.getTitle() : "");
|
||||
speakerElement.setAttribute("geburtsdatum", this.getGeburtsdatum() != null ? this.getGeburtsdatum().toString() : "");
|
||||
speakerElement.setAttribute("geburtsort", this.getGeburtsort());
|
||||
speakerElement.setAttribute("sterbedatum", this.getSterbedatum() != null ? this.getSterbedatum().toString() : "");
|
||||
speakerElement.setAttribute("geschlecht", this.getGeschlecht());
|
||||
speakerElement.setAttribute("beruf", this.getBeruf());
|
||||
speakerElement.setAttribute("akademischertitel", this.getAkademischertitel());
|
||||
speakerElement.setAttribute("familienstand", this.getFamilienstand());
|
||||
speakerElement.setAttribute("religion", this.getReligion() != null ? this.getReligion() : "");
|
||||
speakerElement.setAttribute("vita", this.getVita());
|
||||
speakerElement.setAttribute("party", this.getParty());
|
||||
|
||||
List<Membership> memberships = this.getMemberships();
|
||||
for (Membership membership : memberships) {
|
||||
Element membershipElement = doc.createElement("membership");
|
||||
membershipElement.setAttribute("role", membership.getRole());
|
||||
membershipElement.setAttribute("member", membership.getMember());
|
||||
membershipElement.setAttribute("begin", membership.getBegin() != null ? membership.getBegin().toString() : "");
|
||||
membershipElement.setAttribute("end", membership.getEnd() != null ? membership.getEnd().toString() : "");
|
||||
membershipElement.setAttribute("label", membership.getLabel());
|
||||
membershipElement.setAttribute("wp", String.valueOf(membership.getWp()));
|
||||
speakerElement.appendChild(membershipElement);
|
||||
}
|
||||
|
||||
return speakerElement;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,11 +9,16 @@ import org.texttechnologylab.project.gruppe_05_1.database.domainimpl.mdb.speechl
|
|||
import org.texttechnologylab.project.gruppe_05_1.database.domainimpl.mdb.speechline.Line_MongoDB_Impl;
|
||||
import org.texttechnologylab.project.gruppe_05_1.database.domainimpl.mdb.speechline.Speaker_MongoDB_Impl;
|
||||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Impls.Speech_File_Impl;
|
||||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.Content;
|
||||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.Speech;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.texttechnologylab.project.gruppe_05_1.database.MongoPprUtils.getAgendaTitle;
|
||||
import static org.texttechnologylab.project.gruppe_05_1.database.MongoPprUtils.getSessionDateTime;
|
||||
|
||||
public class Speech_MongoDB_Impl extends Speech_File_Impl implements Speech {
|
||||
public Speech_MongoDB_Impl(Document mongoDocument, boolean includeContent) {
|
||||
super(
|
||||
|
@ -80,10 +85,51 @@ public class Speech_MongoDB_Impl extends Speech_File_Impl implements Speech {
|
|||
public String toTeX() {
|
||||
StringBuilder tex = new StringBuilder();
|
||||
|
||||
tex.append("");
|
||||
String speechTitle = "Rede " +
|
||||
this.getSpeechKey() +
|
||||
"/" +
|
||||
getAgendaTitle(this.getSessionId(), this.getAgendaItemId()) +
|
||||
" von " +
|
||||
this.getSpeakerName() +
|
||||
" (" +
|
||||
this.getFraction() +
|
||||
") vom " +
|
||||
getSessionDateTime(this.getSessionId());
|
||||
|
||||
tex.append("\\section*{").append(speechTitle).append("}\n");
|
||||
tex.append("\\addcontentsline{toc}{section}{").append(speechTitle).append("}\n");
|
||||
|
||||
tex.append("$$SPEAKERINFO$$\n");
|
||||
|
||||
tex.append("\\subsection*{NLP Metadata}\n");
|
||||
|
||||
tex.append("$$NLPMETADATA$$\n");
|
||||
|
||||
tex.append("\\subsection*{Speech Content}\n");
|
||||
|
||||
// Add content block of speeches
|
||||
for (Content content: this.getSpeechContents()) {
|
||||
tex.append(content.toTeX());
|
||||
}
|
||||
|
||||
|
||||
return tex.toString();
|
||||
}
|
||||
|
||||
public Element toXML(org.w3c.dom.Document doc) {
|
||||
Element speech = doc.createElement("speech");
|
||||
speech.setAttribute("sessionId", String.valueOf(this.getSessionId()));
|
||||
speech.setAttribute("agendaItemId", String.valueOf(this.getAgendaItemId()));
|
||||
speech.setAttribute("speechId", String.valueOf(this.getSpeechId()));
|
||||
speech.setAttribute("speakerId", String.valueOf(this.getSpeakerId()));
|
||||
speech.setAttribute("speakerName", this.getSpeakerName());
|
||||
speech.setAttribute("fraction", this.getFraction());
|
||||
speech.setAttribute("speechKey", this.getSpeechKey());
|
||||
|
||||
for (Content content: this.getSpeechContents()) {
|
||||
speech.appendChild(content.toXML(doc));
|
||||
}
|
||||
|
||||
return speech;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.texttechnologylab.project.gruppe_05_1.database.domainimpl.mdb.speech
|
|||
import org.bson.Document;
|
||||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Impls.Comment_File_Impl;
|
||||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.Comment;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
|
||||
public class Comment_MongoDB_Impl extends Comment_File_Impl implements Comment {
|
||||
|
@ -14,4 +15,17 @@ public class Comment_MongoDB_Impl extends Comment_File_Impl implements Comment {
|
|||
mongoDocument.getString("commentatorName"),
|
||||
mongoDocument.getString("comment"));
|
||||
}
|
||||
|
||||
public String toTeX() {
|
||||
return "\\textcolor{blue}{Kommentar}: " + this.getComment() + "\\\\\n";
|
||||
}
|
||||
|
||||
public Element toXML(org.w3c.dom.Document doc) {
|
||||
Element comment = doc.createElement("comment");
|
||||
comment.setAttribute("contentId", String.valueOf(this.getContentId()));
|
||||
comment.setAttribute("speechId", String.valueOf(this.getSpeechId()));
|
||||
comment.setAttribute("commentatorName", this.getCommentatorName());
|
||||
comment.setTextContent(this.getComment());
|
||||
return comment;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.texttechnologylab.project.gruppe_05_1.database.domainimpl.mdb.speech
|
|||
import org.bson.Document;
|
||||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Impls.Line_File_Impl;
|
||||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.Line;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
|
||||
public class Line_MongoDB_Impl extends Line_File_Impl implements Line {
|
||||
|
@ -12,4 +13,16 @@ public class Line_MongoDB_Impl extends Line_File_Impl implements Line {
|
|||
mongoDocument.getInteger("speechId"),
|
||||
mongoDocument.getString("content"));
|
||||
}
|
||||
|
||||
public String toTeX() {
|
||||
return this.getContent() + "\\\\\n";
|
||||
}
|
||||
|
||||
public Element toXML(org.w3c.dom.Document doc) {
|
||||
Element line = doc.createElement("line");
|
||||
line.setAttribute("contentId", String.valueOf(this.getContentId()));
|
||||
line.setAttribute("speechId", String.valueOf(this.getSpeechId()));
|
||||
line.setTextContent(this.getContent());
|
||||
return line;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.texttechnologylab.project.gruppe_05_1.database.domainimpl.mdb.speech
|
|||
import org.bson.Document;
|
||||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Impls.Speaker_File_Impl;
|
||||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.Speaker;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
public class Speaker_MongoDB_Impl extends Speaker_File_Impl implements Speaker {
|
||||
public Speaker_MongoDB_Impl(Document mongoDocument) {
|
||||
|
@ -13,4 +14,18 @@ public class Speaker_MongoDB_Impl extends Speaker_File_Impl implements Speaker {
|
|||
mongoDocument.getString("speakerName"),
|
||||
mongoDocument.getString("fraction"));
|
||||
}
|
||||
|
||||
public String toTeX() {
|
||||
return "\\textcolor{darkgreen}{Redner/Rednerin}: " + this.getSpeakerName() + "\\\\\n";
|
||||
}
|
||||
|
||||
public Element toXML(org.w3c.dom.Document doc) {
|
||||
Element speaker = doc.createElement("speaker");
|
||||
speaker.setAttribute("contentId", String.valueOf(this.getContentId()));
|
||||
speaker.setAttribute("speechId", String.valueOf(this.getSpeechId()));
|
||||
speaker.setAttribute("speakerId", String.valueOf(this.getSpeakerId()));
|
||||
speaker.setAttribute("speakerName", this.getSpeakerName());
|
||||
speaker.setAttribute("fraction", this.getFraction());
|
||||
return speaker;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,226 @@
|
|||
package org.texttechnologylab.project.gruppe_05_1.export;
|
||||
|
||||
import org.texttechnologylab.project.gruppe_05_1.database.domainimpl.mdb.Speaker_MongoDB_Impl;
|
||||
import org.texttechnologylab.project.gruppe_05_1.util.Logger;
|
||||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.Speech;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
|
||||
import static org.texttechnologylab.project.gruppe_05_1.Main.RESOURCES_DIR;
|
||||
import static org.texttechnologylab.project.gruppe_05_1.Main.TEMP_EXPORT_DIR;
|
||||
import static org.texttechnologylab.project.gruppe_05_1.database.MongoPprUtils.*;
|
||||
|
||||
public class TeXUtil {
|
||||
private static final String PREAMBLE = readFileContentFromTeXDir();
|
||||
private static final String BEGIN_DOCUMENT = "\\begin{document}\n";
|
||||
private static final String END_DOCUMENT = "\\end{document}";
|
||||
private static final String TABLEOFCONTENTS = "\\tableofcontents\n\\newpage\n";
|
||||
private static final String NEWPAGE = "\\newpage\n";
|
||||
|
||||
private static String readFileContentFromTeXDir() {
|
||||
try {
|
||||
return Files.readString(new File(RESOURCES_DIR, "tex/preamble.tex").toPath());
|
||||
} catch (IOException e) {
|
||||
Logger.error("Failed to read file content from tex directory.");
|
||||
Logger.error(e.getMessage());
|
||||
Logger.debug(Arrays.toString(e.getStackTrace()));
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static String getSpeechToTexComponent(String speechId) {
|
||||
createTempDir();
|
||||
Speech speech = getSpeechByKey(speechId);
|
||||
|
||||
Speaker_MongoDB_Impl speaker = getSpeakerById(String.valueOf(speech.getSpeakerId()));
|
||||
|
||||
StringBuilder tex = new StringBuilder();
|
||||
|
||||
tex.append(speech.toTeX());
|
||||
|
||||
return tex.toString().replace("$$SPEAKERINFO$$", speaker.toTeX());
|
||||
}
|
||||
|
||||
public static String getSpeechToTexComponent(Speech speech) {
|
||||
createTempDir();
|
||||
Speaker_MongoDB_Impl speaker = getSpeakerById(String.valueOf(speech.getSpeakerId()));
|
||||
|
||||
StringBuilder tex = new StringBuilder();
|
||||
|
||||
tex.append(speech.toTeX());
|
||||
|
||||
return tex.toString().replace("$$SPEAKERINFO$$", speaker.toTeX());
|
||||
}
|
||||
|
||||
public static String getExportedSpeechBase64StringBySpeechId(String speechId) throws IOException, InterruptedException {
|
||||
// Read preamble from resources directory tex/preamble.tex
|
||||
return convertTexToBase64PDF(PREAMBLE.replace("$$EXPORTCATEGORY$$", "Speech " + speechId) + BEGIN_DOCUMENT + getSpeechToTexComponent(speechId) + END_DOCUMENT);
|
||||
}
|
||||
|
||||
public static String getBulkExportedSpeechBase64StringFromSpeakerById(String speakerId) throws IOException, InterruptedException {
|
||||
// Fetch all speechIDs from the speaker
|
||||
List<Speech> speechIds = getSpeechesBySpeakerId(speakerId);
|
||||
|
||||
StringBuilder tex = new StringBuilder();
|
||||
|
||||
tex.append(PREAMBLE.replace("$$EXPORTCATEGORY$$", "Speaker ID" + speakerId));
|
||||
tex.append(BEGIN_DOCUMENT);
|
||||
tex.append(TABLEOFCONTENTS);
|
||||
for (Speech speech : speechIds) {
|
||||
tex.append(getSpeechToTexComponent(speech));
|
||||
tex.append(NEWPAGE);
|
||||
}
|
||||
tex.append(END_DOCUMENT);
|
||||
|
||||
return convertTexToBase64PDF(tex.toString());
|
||||
}
|
||||
|
||||
public static String getBulkExportedAllSpeechesBase64String() throws IOException, InterruptedException {
|
||||
// Fetch all speechIDs from the speaker
|
||||
List<Speech> speechIds = getAllSpeeches();
|
||||
|
||||
StringBuilder tex = new StringBuilder();
|
||||
|
||||
tex.append(PREAMBLE.replace("$$EXPORTCATEGORY$$", "all speeches"));
|
||||
tex.append(BEGIN_DOCUMENT);
|
||||
tex.append(TABLEOFCONTENTS);
|
||||
for (Speech speech : speechIds) {
|
||||
tex.append(getSpeechToTexComponent(speech));
|
||||
tex.append(NEWPAGE);
|
||||
}
|
||||
tex.append(END_DOCUMENT);
|
||||
|
||||
return convertTexToBase64PDF(tex.toString());
|
||||
}
|
||||
|
||||
public static String getBulkExportedAllSpeechesWithTopicBase64String(String topic) throws IOException, InterruptedException {
|
||||
// Fetch all speechIDs from the speaker
|
||||
List<Speech> speechIds = getAllSpeechesWithTopic(topic);
|
||||
|
||||
StringBuilder tex = new StringBuilder();
|
||||
|
||||
tex.append(PREAMBLE.replace("$$EXPORTCATEGORY$$", "Speeches with topic " + topic));
|
||||
tex.append(BEGIN_DOCUMENT);
|
||||
tex.append(TABLEOFCONTENTS);
|
||||
for (Speech speech : speechIds) {
|
||||
tex.append(getSpeechToTexComponent(speech));
|
||||
tex.append(NEWPAGE);
|
||||
}
|
||||
tex.append(END_DOCUMENT);
|
||||
|
||||
return convertTexToBase64PDF(tex.toString());
|
||||
}
|
||||
|
||||
public static String getBulkExportedSpeechesBase64String(List<String> speechIds) throws IOException, InterruptedException {
|
||||
StringBuilder tex = new StringBuilder();
|
||||
|
||||
tex.append(PREAMBLE.replace("$$EXPORTCATEGORY$$", "selected speeches"));
|
||||
tex.append(BEGIN_DOCUMENT);
|
||||
tex.append(TABLEOFCONTENTS);
|
||||
for (String speechId : speechIds) {
|
||||
tex.append(getSpeechToTexComponent(speechId));
|
||||
tex.append(NEWPAGE);
|
||||
}
|
||||
tex.append(END_DOCUMENT);
|
||||
|
||||
return convertTexToBase64PDF(tex.toString());
|
||||
}
|
||||
|
||||
public static String convertTexToBase64PDF(String tex) throws IOException, InterruptedException {
|
||||
// Create a temporary directory
|
||||
File tempDir = new File(TEMP_EXPORT_DIR);
|
||||
createTempDir();
|
||||
|
||||
// Format tex string to UTF-8
|
||||
tex = new String(tex.getBytes("UTF-8"));
|
||||
tex = tex.replaceAll("[^\\x00-\\x7F]", ""); // Replace all non-ASCII characters
|
||||
|
||||
// Local datetime stamp
|
||||
String dateTime = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss").format(LocalDateTime.now());
|
||||
// Write the LaTeX content to a temporary .tex file
|
||||
File texFile = new File(tempDir, "speech_export" + dateTime + ".tex");
|
||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(texFile, StandardCharsets.UTF_8))) {
|
||||
writer.write(tex);
|
||||
}
|
||||
|
||||
// Run pdflatex to generate the .pdf file
|
||||
//String command = "pdflatex -interaction=nonstopmode -output-directory=" + tempDir.getAbsolutePath() + " " + texFile.getAbsolutePath();
|
||||
// using latexmk instead of pdflatex to fix TOC not generating properly
|
||||
String command = "latexmk -pdf -interaction=nonstopmode -outdir=" + tempDir.getAbsolutePath() + " " + texFile.getAbsolutePath();
|
||||
Process process = Runtime.getRuntime().exec(command);
|
||||
|
||||
|
||||
BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
Logger.debug("Standard Output:");
|
||||
String s;
|
||||
while ((s = stdInput.readLine()) != null) {
|
||||
Logger.debug(s);
|
||||
}
|
||||
Logger.debug("LaTeX Process ended with exit code " + process.waitFor());
|
||||
|
||||
// Path to the generated PDF file
|
||||
File pdfFile = new File(tempDir, "speech_export" + dateTime + ".pdf");
|
||||
|
||||
// Check if the PDF was created
|
||||
if (!pdfFile.exists()) {
|
||||
throw new IOException("PDF generation failed.");
|
||||
}
|
||||
|
||||
// Read the PDF file into a byte array
|
||||
byte[] pdfBytes = Files.readAllBytes(pdfFile.toPath());
|
||||
|
||||
// Convert the byte array to a Base64 encoded string
|
||||
return Base64.getEncoder().encodeToString(pdfBytes);
|
||||
}
|
||||
|
||||
public static void createTempDir() {
|
||||
File tempDir = new File(TEMP_EXPORT_DIR);
|
||||
if (!tempDir.exists()) {
|
||||
tempDir.mkdirs();
|
||||
}
|
||||
}
|
||||
|
||||
public static void deleteTeXTempDirContents() throws IOException {
|
||||
// Walk through the directory
|
||||
Files.walkFileTree(Path.of(TEMP_EXPORT_DIR), new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
// Delete file
|
||||
Files.delete(file);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
|
||||
// Delete the directory after its contents are deleted
|
||||
Files.delete(dir);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static boolean isTeXSdkInstalled() {
|
||||
try {
|
||||
Process process = Runtime.getRuntime().exec("pdflatex --version");
|
||||
BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
String s;
|
||||
while ((s = stdInput.readLine()) != null) {
|
||||
if (s.contains("pdfTeX")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (IOException ignored) {}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
package org.texttechnologylab.project.gruppe_05_1.export;
|
||||
|
||||
import org.eclipse.jetty.xml.XmlParser;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Node;
|
||||
import org.texttechnologylab.project.gruppe_05_1.database.domainimpl.mdb.Speaker_MongoDB_Impl;
|
||||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.Speech;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import java.io.StringWriter;
|
||||
import java.util.List;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import static org.texttechnologylab.project.gruppe_05_1.database.MongoPprUtils.*;
|
||||
|
||||
public class XMLUtil {
|
||||
public static String documentToString(Document doc) {
|
||||
try {
|
||||
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||
Transformer transformer = transformerFactory.newTransformer();
|
||||
DOMSource source = new DOMSource(doc);
|
||||
|
||||
// Writer to store the XML string
|
||||
StringWriter writer = new StringWriter();
|
||||
StreamResult result = new StreamResult(writer);
|
||||
|
||||
// Perform transformation
|
||||
transformer.transform(source, result);
|
||||
|
||||
return writer.toString();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Document createXmlDocument() throws ParserConfigurationException {
|
||||
// create new doc
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
Document doc = factory.newDocumentBuilder().newDocument();
|
||||
|
||||
Element speechesElement = doc.createElement("speeches");
|
||||
doc.appendChild(speechesElement);
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
public static void addSpeechById(Document doc, String speechId) {
|
||||
// get speeches element
|
||||
Element speechesElement = (Element) doc.getElementsByTagName("speeches").item(0);
|
||||
|
||||
// create new speech element
|
||||
Element speechElement = doc.createElement("speech");
|
||||
speechesElement.appendChild(speechElement);
|
||||
|
||||
Speech speech = getSpeechByKey(speechId);
|
||||
Speaker_MongoDB_Impl speaker = getSpeakerById(String.valueOf(speech.getSpeakerId()));
|
||||
|
||||
speechElement.appendChild(speaker.toXML(doc));
|
||||
speechElement.appendChild(speech.toXML(doc));
|
||||
}
|
||||
|
||||
public static void addSpeechBySpeech(Document doc, Speech speech) {
|
||||
// get speeches element
|
||||
Element speechesElement = (Element) doc.getElementsByTagName("speeches").item(0);
|
||||
|
||||
// create new speech element
|
||||
Element speechElement = doc.createElement("speech");
|
||||
speechesElement.appendChild(speechElement);
|
||||
|
||||
Speaker_MongoDB_Impl speaker = getSpeakerById(String.valueOf(speech.getSpeakerId()));
|
||||
|
||||
speechElement.appendChild(speaker.toXML(doc));
|
||||
speechElement.appendChild(speech.toXML(doc));
|
||||
}
|
||||
|
||||
public static String getExportedSpeechById(String speechId) throws ParserConfigurationException {
|
||||
Document doc = createXmlDocument();
|
||||
|
||||
addSpeechById(doc, speechId);
|
||||
|
||||
return documentToString(doc);
|
||||
}
|
||||
|
||||
public static String getExportedSpeechesFromSpeakerById(String speakerId) throws ParserConfigurationException {
|
||||
Document doc = createXmlDocument();
|
||||
|
||||
List<Speech> speeches = getSpeechesBySpeakerId(speakerId);
|
||||
|
||||
for (Speech speech : speeches) {
|
||||
addSpeechBySpeech(doc, speech);
|
||||
}
|
||||
|
||||
return documentToString(doc);
|
||||
}
|
||||
|
||||
public static String getExportedAllSpeeches() throws ParserConfigurationException {
|
||||
Document doc = createXmlDocument();
|
||||
|
||||
List<Speech> speeches = getAllSpeeches();
|
||||
|
||||
for (Speech speech : speeches) {
|
||||
addSpeechBySpeech(doc, speech);
|
||||
}
|
||||
|
||||
return documentToString(doc);
|
||||
}
|
||||
|
||||
public static String getExportedSpeechesWhithTopic(String topic) throws ParserConfigurationException {
|
||||
Document doc = createXmlDocument();
|
||||
|
||||
List<Speech> speeches = getAllSpeechesWithTopic(topic);
|
||||
|
||||
for (Speech speech : speeches) {
|
||||
addSpeechBySpeech(doc, speech);
|
||||
}
|
||||
|
||||
return documentToString(doc);
|
||||
}
|
||||
|
||||
public static String getExportedSpeechesbyIds(List<String> speechIds) throws ParserConfigurationException {
|
||||
Document doc = createXmlDocument();
|
||||
|
||||
for (String speechId : speechIds) {
|
||||
addSpeechById(doc, speechId);
|
||||
}
|
||||
|
||||
return documentToString(doc);
|
||||
}
|
||||
}
|
|
@ -65,5 +65,17 @@ public class RESTHandler {
|
|||
app.get("/reden/{id}/{redeId}", SpeechController::showSpeech); // zeige eine bestimmte Rede des Parlamentariers an
|
||||
|
||||
app.get("/reden", SpeechController::listAllSpeeches); // zeige alle Reden an (Filtern möglich)
|
||||
|
||||
app.get("/export/pdf/speech/{id}", SpeechesLatexExportController::exportSpeech); // exportiere eine Rede als PDF
|
||||
app.get("/export/pdf/speaker/{id}", SpeechesLatexExportController::exportSpeechesFromSpeaker); // exportiere alle Reden eines Parlamentariers als PDF
|
||||
app.get("/export/pdf/topic/{topic}", SpeechesLatexExportController::exportSpeechesWithTopic); // exportiere alle Reden zu einem Thema als PDF
|
||||
app.get("/export/pdf/all", SpeechesLatexExportController::exportAllSpeeches); // exportiere alle Reden als PDF CAUTION!!!: This will take forever but is required in the exercise
|
||||
app.get("/export/pdf/speeches/{speechIds}", SpeechesLatexExportController::exportSpeeches); // exportiere eine Liste von Reden als PDF
|
||||
|
||||
app.get("/export/xml/speech/{id}", SpeechesXMLExportController::exportSpeech); // exportiere eine Rede als XML
|
||||
app.get("/export/xml/speaker/{id}", SpeechesXMLExportController::exportSpeechesFromSpeaker); // exportiere alle Reden eines Parlamentariers als XML
|
||||
app.get("/export/xml/topic/{topic}", SpeechesXMLExportController::exportSpeechesWithTopic); // exportiere alle Reden zu einem Thema als XML
|
||||
app.get("/export/xml/all", SpeechesXMLExportController::exportAllSpeeches); // exportiere alle Reden als XML
|
||||
app.get("/export/xml/speeches/{speechIds}", SpeechesXMLExportController::exportSpeeches); // exportiere eine Liste von Reden als XML
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ public class SpeechController {
|
|||
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
|
||||
HtmlSpeech speech = MongoPprUtils.getSpeechByKey(redeId);
|
||||
HtmlSpeech speech = MongoPprUtils.getHTMLSpeechByKey(redeId);
|
||||
if (speech == null) {
|
||||
attributes.put("error", "Rede " + redeId + " nicht vorhanden");
|
||||
ctx.render("speech.ftl", attributes);
|
||||
|
|
|
@ -0,0 +1,243 @@
|
|||
package org.texttechnologylab.project.gruppe_05_1.rest;
|
||||
|
||||
import io.javalin.http.Context;
|
||||
import io.javalin.openapi.HttpMethod;
|
||||
import io.javalin.openapi.OpenApi;
|
||||
import io.javalin.openapi.OpenApiResponse;
|
||||
import org.texttechnologylab.project.gruppe_05_1.util.Logger;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
|
||||
import static org.texttechnologylab.project.gruppe_05_1.export.TeXUtil.*;
|
||||
|
||||
public class SpeechesLatexExportController {
|
||||
@OpenApi(
|
||||
summary = "Get a speech as a PDF",
|
||||
description = "Returns a LaTeX generated pdf of a selected speech",
|
||||
operationId = "getSpeechExport",
|
||||
path = "/export/pdf/speech/{id}",
|
||||
methods = HttpMethod.GET,
|
||||
tags = {"Export", "Speeches", "PDF"},
|
||||
responses = {
|
||||
@OpenApiResponse(status = "200")
|
||||
})
|
||||
public static void exportSpeech(Context ctx) {
|
||||
byte[] pdfBytes = new byte[0];
|
||||
try {
|
||||
pdfBytes = Base64.getDecoder().decode(getExportedSpeechBase64StringBySpeechId(ctx.pathParam("id")));
|
||||
} catch (Exception e) {
|
||||
Logger.error("Failed to generate Export of Speech with ID " + ctx.pathParam("id"));
|
||||
Logger.error(e.getMessage());
|
||||
Logger.debug(Arrays.toString(e.getStackTrace()));
|
||||
}
|
||||
|
||||
// Set the response content type to PDF
|
||||
ctx.contentType("application/pdf");
|
||||
|
||||
ByteArrayInputStream stream = new ByteArrayInputStream(pdfBytes);
|
||||
if (stream.available() == 0) {
|
||||
Logger.error("PDF stream is empty.");
|
||||
ctx.result("Internal Server Error");
|
||||
ctx.status(500);
|
||||
return;
|
||||
}
|
||||
// Send the PDF as a response
|
||||
ctx.result(stream);
|
||||
|
||||
try {
|
||||
// delete the temporary folder
|
||||
deleteTeXTempDirContents();
|
||||
} catch (IOException e) {
|
||||
Logger.error("Failed to delete temporary folder.");
|
||||
Logger.error(e.getMessage());
|
||||
Logger.debug(Arrays.toString(e.getStackTrace()));
|
||||
}
|
||||
}
|
||||
|
||||
@OpenApi(
|
||||
summary = "Get all speeches from a speaker as a PDF",
|
||||
description = "Returns a LaTeX generated pdf of all speeches of a selected speech",
|
||||
operationId = "getSpeechesFromSpeakerExport",
|
||||
path = "/export/pdf/speaker/{id}",
|
||||
methods = HttpMethod.GET,
|
||||
tags = {"Export", "Speeches", "PDF"},
|
||||
responses = {
|
||||
@OpenApiResponse(status = "200")
|
||||
})
|
||||
public static void exportSpeechesFromSpeaker(Context ctx) {
|
||||
byte[] pdfBytes = new byte[0];
|
||||
try {
|
||||
pdfBytes = Base64.getDecoder().decode(getBulkExportedSpeechBase64StringFromSpeakerById(ctx.pathParam("id")));
|
||||
} catch (Exception e) {
|
||||
Logger.error("Failed to generate Export of Speeches from Speaker with ID " + ctx.pathParam("id"));
|
||||
Logger.error(e.getMessage());
|
||||
Logger.debug(Arrays.toString(e.getStackTrace()));
|
||||
}
|
||||
|
||||
// Set the response content type to PDF
|
||||
ctx.contentType("application/pdf");
|
||||
|
||||
ByteArrayInputStream stream = new ByteArrayInputStream(pdfBytes);
|
||||
if (stream.available() == 0) {
|
||||
Logger.error("PDF stream is empty.");
|
||||
ctx.result("Internal Server Error");
|
||||
ctx.status(500);
|
||||
return;
|
||||
}
|
||||
// Send the PDF as a response
|
||||
ctx.result(stream);
|
||||
|
||||
try {
|
||||
// delete the temporary folder
|
||||
deleteTeXTempDirContents();
|
||||
Logger.debug("Temporary folder deleted.");
|
||||
} catch (IOException e) {
|
||||
Logger.error("Failed to delete temporary folder.");
|
||||
Logger.error(e.getMessage());
|
||||
Logger.debug(Arrays.toString(e.getStackTrace()));
|
||||
}
|
||||
}
|
||||
|
||||
@OpenApi(
|
||||
summary = "Get all speeches as a PDF",
|
||||
description = "Returns a LaTeX generated pdf of all speeches",
|
||||
operationId = "getAllSpeeches",
|
||||
path = "/export/pdf/all",
|
||||
methods = HttpMethod.GET,
|
||||
tags = {"Export", "Speeches", "PDF"},
|
||||
responses = {
|
||||
@OpenApiResponse(status = "200")
|
||||
})
|
||||
public static void exportAllSpeeches(Context ctx) {
|
||||
byte[] pdfBytes = new byte[0];
|
||||
try {
|
||||
pdfBytes = Base64.getDecoder().decode(getBulkExportedAllSpeechesBase64String());
|
||||
} catch (Exception e) {
|
||||
Logger.error("Failed to generate Export of all Speeches");
|
||||
Logger.error(e.getMessage());
|
||||
Logger.debug(Arrays.toString(e.getStackTrace()));
|
||||
}
|
||||
|
||||
// Set the response content type to PDF
|
||||
ctx.contentType("application/pdf");
|
||||
|
||||
ByteArrayInputStream stream = new ByteArrayInputStream(pdfBytes);
|
||||
if (stream.available() == 0) {
|
||||
Logger.error("PDF stream is empty.");
|
||||
ctx.result("Internal Server Error");
|
||||
ctx.status(500);
|
||||
return;
|
||||
}
|
||||
// Send the PDF as a response
|
||||
ctx.result(stream);
|
||||
|
||||
try {
|
||||
// delete the temporary folder
|
||||
deleteTeXTempDirContents();
|
||||
Logger.debug("Temporary folder deleted.");
|
||||
} catch (IOException e) {
|
||||
Logger.error("Failed to delete temporary folder.");
|
||||
Logger.error(e.getMessage());
|
||||
Logger.debug(Arrays.toString(e.getStackTrace()));
|
||||
}
|
||||
}
|
||||
|
||||
@OpenApi(
|
||||
summary = "Get all speeches with specific topic as a PDF",
|
||||
description = "Returns a LaTeX generated pdf of all speeches with specific topic",
|
||||
operationId = "getAllSpeechesWithTopic",
|
||||
path = "/export/pdf/topic/{topic}",
|
||||
methods = HttpMethod.GET,
|
||||
tags = {"Export", "Speeches", "PDF"},
|
||||
responses = {
|
||||
@OpenApiResponse(status = "200")
|
||||
})
|
||||
public static void exportSpeechesWithTopic(Context ctx) {
|
||||
byte[] pdfBytes = new byte[0];
|
||||
try {
|
||||
pdfBytes = Base64.getDecoder().decode(getBulkExportedAllSpeechesWithTopicBase64String(ctx.pathParam("topic")));
|
||||
} catch (Exception e) {
|
||||
Logger.error("Failed to generate Export of all Speeches with Topic " + ctx.pathParam("topic"));
|
||||
Logger.error(e.getMessage());
|
||||
Logger.debug(Arrays.toString(e.getStackTrace()));
|
||||
}
|
||||
|
||||
// Set the response content type to PDF
|
||||
ctx.contentType("application/pdf");
|
||||
|
||||
ByteArrayInputStream stream = new ByteArrayInputStream(pdfBytes);
|
||||
if (stream.available() == 0) {
|
||||
Logger.error("PDF stream is empty.");
|
||||
ctx.result("Internal Server Error");
|
||||
ctx.status(500);
|
||||
return;
|
||||
}
|
||||
// Send the PDF as a response
|
||||
ctx.result(stream);
|
||||
|
||||
try {
|
||||
// delete the temporary folder
|
||||
deleteTeXTempDirContents();
|
||||
Logger.debug("Temporary folder deleted.");
|
||||
} catch (IOException e) {
|
||||
Logger.error("Failed to delete temporary folder.");
|
||||
Logger.error(e.getMessage());
|
||||
Logger.debug(Arrays.toString(e.getStackTrace()));
|
||||
}
|
||||
}
|
||||
|
||||
@OpenApi(
|
||||
summary = "Get speeches by IDs as a PDF",
|
||||
description = "Returns a LaTeX-generated PDF of the speeches specified by their IDs",
|
||||
operationId = "getSpeechesByIds",
|
||||
path = "/export/pdf/speeches/{speechIds}", // Comma-separated IDs
|
||||
methods = HttpMethod.GET,
|
||||
tags = {"Export", "Speeches", "PDF"},
|
||||
responses = {
|
||||
@OpenApiResponse(status = "200")
|
||||
})
|
||||
public static void exportSpeeches(Context ctx) {
|
||||
byte[] pdfBytes = new byte[0];
|
||||
|
||||
try {
|
||||
// Extract speech IDs from the path
|
||||
String speechIdsParam = ctx.pathParam("speechIds");
|
||||
List<String> speechIds = Arrays.asList(speechIdsParam.split(","));
|
||||
|
||||
// Generate PDF for given speech IDs
|
||||
pdfBytes = Base64.getDecoder().decode(getBulkExportedSpeechesBase64String(speechIds));
|
||||
} catch (Exception e) {
|
||||
Logger.error("Failed to generate export for speeches: " + ctx.pathParam("speechIds"));
|
||||
Logger.error(e.getMessage());
|
||||
Logger.debug(Arrays.toString(e.getStackTrace()));
|
||||
}
|
||||
|
||||
// Set response content type
|
||||
ctx.contentType("application/pdf");
|
||||
|
||||
ByteArrayInputStream stream = new ByteArrayInputStream(pdfBytes);
|
||||
if (stream.available() == 0) {
|
||||
Logger.error("PDF stream is empty.");
|
||||
ctx.result("Internal Server Error");
|
||||
ctx.status(500);
|
||||
return;
|
||||
}
|
||||
|
||||
// Send the PDF as response
|
||||
ctx.result(stream);
|
||||
|
||||
try {
|
||||
// Clean up temporary files
|
||||
deleteTeXTempDirContents();
|
||||
Logger.debug("Temporary folder deleted.");
|
||||
} catch (IOException e) {
|
||||
Logger.error("Failed to delete temporary folder.");
|
||||
Logger.error(e.getMessage());
|
||||
Logger.debug(Arrays.toString(e.getStackTrace()));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
package org.texttechnologylab.project.gruppe_05_1.rest;
|
||||
|
||||
import io.javalin.http.Context;
|
||||
import io.javalin.openapi.HttpMethod;
|
||||
import io.javalin.openapi.OpenApi;
|
||||
import io.javalin.openapi.OpenApiResponse;
|
||||
import org.texttechnologylab.project.gruppe_05_1.util.Logger;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
|
||||
import static org.texttechnologylab.project.gruppe_05_1.export.XMLUtil.*;
|
||||
import static org.texttechnologylab.project.gruppe_05_1.export.TeXUtil.*;
|
||||
|
||||
public class SpeechesXMLExportController {
|
||||
@OpenApi(
|
||||
summary = "Get a speech as XML",
|
||||
description = "Returns an XML file of a selected speech",
|
||||
operationId = "getSpeechExport",
|
||||
path = "/export/xml/speech/{id}",
|
||||
methods = HttpMethod.GET,
|
||||
tags = {"Export", "Speeches", "XML"},
|
||||
responses = {
|
||||
@OpenApiResponse(status = "200")
|
||||
})
|
||||
public static void exportSpeech(Context ctx) {
|
||||
String xmlContent;
|
||||
try {
|
||||
xmlContent = getExportedSpeechById(ctx.pathParam("id"));
|
||||
ByteArrayInputStream stream = new ByteArrayInputStream(xmlContent.getBytes());
|
||||
if (stream.available() == 0) {
|
||||
Logger.error("XML stream is empty.");
|
||||
ctx.result("Internal Server Error");
|
||||
ctx.status(500);
|
||||
return;
|
||||
}
|
||||
ctx.contentType("application/xml");
|
||||
ctx.result(stream);
|
||||
} catch (Exception e) {
|
||||
Logger.error("Failed to generate Export of Speech with ID " + ctx.pathParam("id"));
|
||||
Logger.error(e.getMessage());
|
||||
Logger.debug(Arrays.toString(e.getStackTrace()));
|
||||
ctx.result("Internal Server Error");
|
||||
ctx.status(500);
|
||||
}
|
||||
}
|
||||
|
||||
@OpenApi(
|
||||
summary = "Get all speeches from a speaker as XML",
|
||||
description = "Returns an XML file of all speeches of a selected speech",
|
||||
operationId = "getSpeechesFromSpeakerExport",
|
||||
path = "/export/xml/speaker/{id}",
|
||||
methods = HttpMethod.GET,
|
||||
tags = {"Export", "Speeches", "XML"},
|
||||
responses = {
|
||||
@OpenApiResponse(status = "200")
|
||||
})
|
||||
public static void exportSpeechesFromSpeaker(Context ctx) {
|
||||
String xmlContent;
|
||||
try {
|
||||
xmlContent = getExportedSpeechesFromSpeakerById(ctx.pathParam("id"));
|
||||
ByteArrayInputStream stream = new ByteArrayInputStream(xmlContent.getBytes());
|
||||
if (stream.available() == 0) {
|
||||
Logger.error("XML stream is empty.");
|
||||
ctx.result("Internal Server Error");
|
||||
ctx.status(500);
|
||||
return;
|
||||
}
|
||||
ctx.contentType("application/xml");
|
||||
ctx.result(stream);
|
||||
} catch (Exception e) {
|
||||
Logger.error("Failed to generate Export of Speeches from Speaker with ID " + ctx.pathParam("id"));
|
||||
Logger.error(e.getMessage());
|
||||
Logger.debug(Arrays.toString(e.getStackTrace()));
|
||||
ctx.result("Internal Server Error");
|
||||
ctx.status(500);
|
||||
}
|
||||
}
|
||||
|
||||
@OpenApi(
|
||||
summary = "Get all speeches as XML",
|
||||
description = "Returns an XML file of all speeches",
|
||||
operationId = "getAllSpeeches",
|
||||
path = "/export/xml/all",
|
||||
methods = HttpMethod.GET,
|
||||
tags = {"Export", "Speeches", "XML"},
|
||||
responses = {
|
||||
@OpenApiResponse(status = "200")
|
||||
})
|
||||
public static void exportAllSpeeches(Context ctx) {
|
||||
String xmlContent;
|
||||
try {
|
||||
xmlContent = getExportedAllSpeeches();
|
||||
ByteArrayInputStream stream = new ByteArrayInputStream(xmlContent.getBytes());
|
||||
if (stream.available() == 0) {
|
||||
Logger.error("XML stream is empty.");
|
||||
ctx.result("Internal Server Error");
|
||||
ctx.status(500);
|
||||
return;
|
||||
}
|
||||
ctx.contentType("application/xml");
|
||||
ctx.result(stream);
|
||||
} catch (Exception e) {
|
||||
Logger.error("Failed to generate Export of all Speeches");
|
||||
Logger.error(e.getMessage());
|
||||
Logger.debug(Arrays.toString(e.getStackTrace()));
|
||||
ctx.result("Internal Server Error");
|
||||
ctx.status(500);
|
||||
}
|
||||
}
|
||||
|
||||
@OpenApi(
|
||||
summary = "Get all speeches with specific topic as XML",
|
||||
description = "Returns an XML file of all speeches with specific topic",
|
||||
operationId = "getAllSpeechesWithTopic",
|
||||
path = "/export/xml/topic/{topic}",
|
||||
methods = HttpMethod.GET,
|
||||
tags = {"Export", "Speeches", "XML"},
|
||||
responses = {
|
||||
@OpenApiResponse(status = "200")
|
||||
})
|
||||
public static void exportSpeechesWithTopic(Context ctx) {
|
||||
String xmlContent;
|
||||
try {
|
||||
xmlContent = getExportedSpeechesWhithTopic(ctx.pathParam("topic"));
|
||||
ByteArrayInputStream stream = new ByteArrayInputStream(xmlContent.getBytes());
|
||||
if (stream.available() == 0) {
|
||||
Logger.error("XML stream is empty.");
|
||||
ctx.result("Internal Server Error");
|
||||
ctx.status(500);
|
||||
return;
|
||||
}
|
||||
ctx.contentType("application/xml");
|
||||
ctx.result(stream);
|
||||
} catch (Exception e) {
|
||||
Logger.error("Failed to generate Export of all Speeches");
|
||||
Logger.error(e.getMessage());
|
||||
Logger.debug(Arrays.toString(e.getStackTrace()));
|
||||
ctx.result("Internal Server Error");
|
||||
ctx.status(500);
|
||||
}
|
||||
}
|
||||
|
||||
@OpenApi(
|
||||
summary = "Get speeches by IDs as XML",
|
||||
description = "Returns an XML file of the speeches specified by their IDs",
|
||||
operationId = "getSpeechesByIds",
|
||||
path = "/export/xml/speeches/{speechIds}", // Comma-separated IDs
|
||||
methods = HttpMethod.GET,
|
||||
tags = {"Export", "Speeches", "XML"},
|
||||
responses = {
|
||||
@OpenApiResponse(status = "200")
|
||||
})
|
||||
public static void exportSpeeches(Context ctx) {
|
||||
String xmlContent;
|
||||
try {
|
||||
String speechIdsParam = ctx.pathParam("speechIds");
|
||||
List<String> speechIds = Arrays.asList(speechIdsParam.split(","));
|
||||
xmlContent = getExportedSpeechesbyIds(speechIds);
|
||||
ByteArrayInputStream stream = new ByteArrayInputStream(xmlContent.getBytes());
|
||||
if (stream.available() == 0) {
|
||||
Logger.error("XML stream is empty.");
|
||||
ctx.result("Internal Server Error");
|
||||
ctx.status(500);
|
||||
return;
|
||||
}
|
||||
ctx.contentType("application/xml");
|
||||
ctx.result(stream);
|
||||
} catch (Exception e) {
|
||||
Logger.error("Failed to generate Export of all Speeches");
|
||||
Logger.error(e.getMessage());
|
||||
Logger.debug(Arrays.toString(e.getStackTrace()));
|
||||
ctx.result("Internal Server Error");
|
||||
ctx.status(500);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,4 +28,8 @@ public class Logger {
|
|||
public static void pink(String message) {
|
||||
System.out.println("\u001B[35m" + java.time.LocalTime.now() + " PINK: " + message + "\u001B[0m");
|
||||
}
|
||||
|
||||
public static void orange(String message) {
|
||||
System.out.println("\u001B[38;5;214m" + message + "\u001B[0m");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ package org.texttechnologylab.project.gruppe_05_1.xml.speeches.Impls;
|
|||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.Comment;
|
||||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.Content;
|
||||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.enums.MongoDBEntryType;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
|
||||
public class Comment_File_Impl implements Content, Comment {
|
||||
|
@ -42,4 +44,19 @@ public class Comment_File_Impl implements Content, Comment {
|
|||
public MongoDBEntryType getType() {
|
||||
return MongoDBEntryType.SPEECH_COMMENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toTeX() {
|
||||
return "\\textcolor{blue}{Kommentar}: " + this.getComment() + "\\\n";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Element toXML(Document doc) {
|
||||
Element comment = doc.createElement("comment");
|
||||
comment.setAttribute("contentId", String.valueOf(this.getContentId()));
|
||||
comment.setAttribute("speechId", String.valueOf(this.getSpeechId()));
|
||||
comment.setAttribute("commentatorName", this.getCommentatorName());
|
||||
comment.setTextContent(this.getComment());
|
||||
return comment;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ package org.texttechnologylab.project.gruppe_05_1.xml.speeches.Impls;
|
|||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.Content;
|
||||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.Line;
|
||||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.enums.MongoDBEntryType;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
public class Line_File_Impl implements Content, Line {
|
||||
private final int contentId;
|
||||
|
@ -34,4 +36,18 @@ public class Line_File_Impl implements Content, Line {
|
|||
public MongoDBEntryType getType() {
|
||||
return MongoDBEntryType.SPEECH_LINE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toTeX() {
|
||||
return this.getContent() + "\\\n";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Element toXML(Document doc) {
|
||||
Element line = doc.createElement("line");
|
||||
line.setAttribute("contentId", String.valueOf(this.getContentId()));
|
||||
line.setAttribute("speechId", String.valueOf(this.getSpeechId()));
|
||||
line.setTextContent(this.getContent());
|
||||
return line;
|
||||
}
|
||||
}
|
|
@ -3,6 +3,8 @@ package org.texttechnologylab.project.gruppe_05_1.xml.speeches.Impls;
|
|||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.Content;
|
||||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.Speaker;
|
||||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.enums.MongoDBEntryType;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
|
||||
public class Speaker_File_Impl implements Content, Speaker {
|
||||
|
@ -49,4 +51,20 @@ public class Speaker_File_Impl implements Content, Speaker {
|
|||
public MongoDBEntryType getType() {
|
||||
return MongoDBEntryType.SPEECH_SPEAKER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toTeX() {
|
||||
return "\\textcolor{blue}{Redner/Rednerin}: " + this.getSpeakerName() + "\\\n";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Element toXML(Document doc) {
|
||||
Element speaker = doc.createElement("speaker");
|
||||
speaker.setAttribute("contentId", String.valueOf(this.getContentId()));
|
||||
speaker.setAttribute("speechId", String.valueOf(this.getSpeechId()));
|
||||
speaker.setAttribute("speakerId", String.valueOf(this.getSpeakerId()));
|
||||
speaker.setAttribute("speakerName", this.getSpeakerName());
|
||||
speaker.setAttribute("fraction", this.getFraction());
|
||||
return speaker;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ import org.apache.uima.jcas.JCas;
|
|||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.Content;
|
||||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.Speech;
|
||||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.enums.MongoDBEntryType;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -103,4 +105,40 @@ public class Speech_File_Impl implements Speech {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toTeX() {
|
||||
StringBuilder tex = new StringBuilder();
|
||||
|
||||
tex.append("\\NLP Metadata\\\n");
|
||||
|
||||
tex.append("$$NLPMETADATA$$\n");
|
||||
|
||||
tex.append("\\subsection*{Speech Content}\n");
|
||||
|
||||
// Add content block of speeches
|
||||
for (Content content: this.getSpeechContents()) {
|
||||
tex.append(content.toTeX());
|
||||
}
|
||||
|
||||
|
||||
return tex.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Element toXML(Document doc) {
|
||||
Element speech = doc.createElement("speech");
|
||||
speech.setAttribute("sessionId", String.valueOf(this.getSessionId()));
|
||||
speech.setAttribute("agendaItemId", String.valueOf(this.getAgendaItemId()));
|
||||
speech.setAttribute("speechId", String.valueOf(this.getSpeechId()));
|
||||
speech.setAttribute("speakerId", String.valueOf(this.getSpeakerId()));
|
||||
speech.setAttribute("speakerName", this.getSpeakerName());
|
||||
speech.setAttribute("fraction", this.getFraction());
|
||||
speech.setAttribute("speechKey", this.getSpeechKey());
|
||||
|
||||
for (Content content: this.getSpeechContents()) {
|
||||
speech.appendChild(content.toXML(doc));
|
||||
}
|
||||
|
||||
return speech;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces;
|
||||
|
||||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.enums.MongoDBEntryType;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
public interface Content {
|
||||
/**
|
||||
|
@ -24,4 +25,19 @@ public interface Content {
|
|||
* @return The speech ID.
|
||||
*/
|
||||
int getSpeechId();
|
||||
|
||||
/**
|
||||
* Returns the content as LaTeX.
|
||||
*
|
||||
* @return The content.
|
||||
*/
|
||||
String toTeX();
|
||||
|
||||
/**
|
||||
* Returns the content as XML.
|
||||
*
|
||||
* @param doc The XML document.
|
||||
* @return The content.
|
||||
*/
|
||||
Element toXML(org.w3c.dom.Document doc);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ package org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces;
|
|||
import org.apache.uima.UIMAException;
|
||||
import org.apache.uima.jcas.JCas;
|
||||
import org.texttechnologylab.project.gruppe_05_1.xml.speeches.enums.MongoDBEntryType;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -85,4 +87,8 @@ public interface Speech {
|
|||
String getFullText();
|
||||
|
||||
JCas toCas() throws UIMAException;
|
||||
|
||||
String toTeX();
|
||||
|
||||
Element toXML(Document doc);
|
||||
}
|
||||
|
|
24
src/main/resources/tex/preamble.tex
Normal file
24
src/main/resources/tex/preamble.tex
Normal file
|
@ -0,0 +1,24 @@
|
|||
\documentclass[a4paper]{article}
|
||||
\usepackage{graphicx}
|
||||
\usepackage{fancyhdr}
|
||||
\usepackage{geometry}
|
||||
\usepackage{xcolor}
|
||||
\usepackage[T1]{fontenc}
|
||||
|
||||
\pagestyle{fancy}
|
||||
|
||||
\definecolor{darkgreen}{rgb}{0.0, 0.5, 0.0}
|
||||
|
||||
\geometry{
|
||||
top=2.5cm, % Top margin
|
||||
bottom=3cm, % Bottom margin
|
||||
left=2.5cm, % Left margin
|
||||
right=2.5cm, % Right margin
|
||||
headheight=25pt, % Header height
|
||||
footskip=1.5cm, % Space from the bottom margin to the baseline of the footer
|
||||
headsep=0.5cm, % Space from the top margin to the baseline of the header
|
||||
%showframe, % Uncomment to show how the type block is set on the page
|
||||
}
|
||||
|
||||
\rhead{Multimodal Parliament Explorer}
|
||||
\lhead{PDF Speech Export for $$EXPORTCATEGORY$$}
|
Loading…
Add table
Add a link
Reference in a new issue