From 10f4b2d26072a1a91a83418d4122347913a99b97 Mon Sep 17 00:00:00 2001 From: dua Date: Mon, 15 Sep 2025 11:25:25 +0200 Subject: [PATCH 1/7] added function for: analysis result send to the importer and save analysis result as cache --- .../templates/wiki/analysisResultFragment.ftl | 18 ++ .../uce/analysis/DUUIPipeline.java | 2 +- .../uce/analysis/RunDUUIPipeline.java | 257 ++++++++++++++++++ .../src/main/resources/defaultUceConfig.json | 2 +- .../org/texttechnologylab/uce/web/App.java | 1 + .../uce/web/routes/AnalysisApi.java | 47 ++++ 6 files changed, 325 insertions(+), 2 deletions(-) diff --git a/uce.portal/resources/templates/wiki/analysisResultFragment.ftl b/uce.portal/resources/templates/wiki/analysisResultFragment.ftl index 7e012f0c..592ab90e 100644 --- a/uce.portal/resources/templates/wiki/analysisResultFragment.ftl +++ b/uce.portal/resources/templates/wiki/analysisResultFragment.ftl @@ -1,4 +1,22 @@ +<#if analysisId??> +
+ +
+ + <#if DUUI??> <#if DUUI.modelGroups?has_content> <#if DUUI.isTopic> diff --git a/uce.portal/uce.analysis/src/main/java/org/texttechnologylab/uce/analysis/DUUIPipeline.java b/uce.portal/uce.analysis/src/main/java/org/texttechnologylab/uce/analysis/DUUIPipeline.java index 3cb3d72a..8c666e80 100644 --- a/uce.portal/uce.analysis/src/main/java/org/texttechnologylab/uce/analysis/DUUIPipeline.java +++ b/uce.portal/uce.analysis/src/main/java/org/texttechnologylab/uce/analysis/DUUIPipeline.java @@ -120,7 +120,7 @@ public JCas getLanguage(String inputText) throws Exception { HashMap urls = new HashMap<>(); urls.put("LanguageDetection", "http://language.service.component.duui.texttechnologylab.org"); DUUIComposer composer = setListComposer(urls); - cas = runPipeline(cas, composer); + //cas = runPipeline(cas, composer); // Assuming the language detection component sets the language in the JCas String language = "en"; language = cas.getDocumentLanguage(); diff --git a/uce.portal/uce.analysis/src/main/java/org/texttechnologylab/uce/analysis/RunDUUIPipeline.java b/uce.portal/uce.analysis/src/main/java/org/texttechnologylab/uce/analysis/RunDUUIPipeline.java index 02687feb..74a6bdc7 100644 --- a/uce.portal/uce.analysis/src/main/java/org/texttechnologylab/uce/analysis/RunDUUIPipeline.java +++ b/uce.portal/uce.analysis/src/main/java/org/texttechnologylab/uce/analysis/RunDUUIPipeline.java @@ -8,11 +8,36 @@ import org.texttechnologylab.uce.analysis.modules.*; import org.texttechnologylab.uce.analysis.typeClasses.TextClass; + + + +import java.time.Instant; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +// Added imports (save .jcas, HTTP import, logging) +//import java.nio.file.Path; +//import java.nio.file.Paths; +//import java.nio.file.Files; +//import java.io.OutputStream; +import java.io.InputStream; +import java.io.DataOutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; + import java.util.*; public class RunDUUIPipeline { + private static final AnalysisCache analysisCache = new AnalysisCache(); + private static final ThreadLocal lastAnalysisIdTL = new ThreadLocal<>(); + public static AnalysisSession getCachedSession(String analysisId) { return analysisCache.get(analysisId); } + + private static String getCurrentUserId() { + // TODO: replace with your auth/session identity + return "user-unknown"; + } public DUUIInformation getModelResources(List modelGroups, String inputText, String claim, String coherenceText, String stanceText, String systemPrompt) throws Exception { ModelResources modelResources = new ModelResources(); @@ -189,10 +214,13 @@ public DUUIInformation getModelResources(List modelGroups, String inputT newCas.setDocumentText(text); cas = newCas; + System.out.println("[CAS] Created secondary JCas for special models (fact/coherence/stance/LLM)"); + } // run pipeline DUUIComposer composer = pipeline.setComposer(modelInfosMap); JCas result = pipeline.runPipeline(cas, composer); + System.out.println("[CAS] Final result JCas created via pipeline.runPipeline(cas, composer)"); // get results Object[] results = pipeline.getJCasResults(result, modelInfosList, ttlabScorerGroups, cohmetrixScorerGroups); // print results @@ -232,9 +260,28 @@ public DUUIInformation getModelResources(List modelGroups, String inputT if (isCohmetrix) { duuiInformation.setCohMetrixGroups(cohmetrixScorerGroups); } + String analysisId = UUID.randomUUID().toString(); + String userId = getCurrentUserId(); + String title = "Analysis " + Instant.now(); + + byte[] xmiBytes = toXmiBytes(result); + AnalysisSession session = new AnalysisSession( + analysisId, userId, title, /*externalId*/ null, + result, /*xmiBytes*/ xmiBytes + ); + analysisCache.put(session); + lastAnalysisIdTL.set(analysisId); + System.out.println("[CACHE] Added analysisId=" + analysisId + " (stored in memory; TTL=45min)"); return duuiInformation; } + public AnalysisResponse getModelResourcesWithHandle(List modelGroups, String inputText, String claim, + String coherenceText, String stanceText, String systemPrompt) throws Exception { + DUUIInformation info = getModelResources(modelGroups, inputText, claim, coherenceText, stanceText, systemPrompt); + String id = lastAnalysisIdTL.get(); + return new AnalysisResponse(id, info); + } + public static void main(String[] args) throws Exception { ModelResources modelResources = new ModelResources(); List modelGroups = modelResources.getGroupedModelObjects(); @@ -256,5 +303,215 @@ public static void main(String[] args) throws Exception { DUUIInformation duuiInformation = new RunDUUIPipeline().getModelResources(modelGroupNames, inputText, claim, coherenceText, stanceText, systemPrompt); } + public static final class AnalysisResponse { + public final String analysisId; + public final DUUIInformation duuiInformation; + + public AnalysisResponse(String analysisId, DUUIInformation duuiInformation) { + this.analysisId = analysisId; + this.duuiInformation = duuiInformation; + } + } + + + //AnalysisSession + public static final class AnalysisSession { + public final String analysisId; + public final String userId; + public final long createdAtMillis; + public final String title; + public final String externalId; + public final JCas jcas; + public final byte[] xmiBytes; + + public AnalysisSession(String analysisId, String userId, String title, String externalId, + JCas jcas, byte[] xmiBytes) { + this.analysisId = analysisId; + this.userId = userId; + this.title = title; + this.externalId = externalId; + this.createdAtMillis = System.currentTimeMillis(); + this.jcas = jcas; + this.xmiBytes = xmiBytes; + } + } + + + // AnalysisCache + public static final class AnalysisCache { + private final Map map = new ConcurrentHashMap<>(); + private final long ttlMillis = 45 * 60 * 1000L; // 45 minutes + + public void put(AnalysisSession s) { map.put(s.analysisId, s); } + + public AnalysisSession get(String id) { // Retrieve a session from the cache + AnalysisSession s = map.get(id); + if (s == null) return null; + + if (System.currentTimeMillis() - s.createdAtMillis > ttlMillis) { // If this session is older than 45 minutes -> expire it + map.remove(id); + return null; + } + return s; + } + + public void remove(String id) { map.remove(id); } //Manually remove a session by ID + + + public void cleanupExpired() { // cleanup all expired sessions + long now = System.currentTimeMillis(); + for (var entry : map.entrySet()) { + AnalysisSession s = entry.getValue(); + if (now - s.createdAtMillis > ttlMillis) { + map.remove(entry.getKey()); + System.out.println("[CRON] Removed expired session: " + s.analysisId); + } + } + } + } + private static final java.util.concurrent.ScheduledExecutorService scheduler = //Cron job for automatic cleanup every 5 minutes + java.util.concurrent.Executors.newScheduledThreadPool(1); + + static { + scheduler.scheduleAtFixedRate(() -> { + try { + analysisCache.cleanupExpired(); + } catch (Exception e) { + System.err.println("[CACHE] Cache cleanup failed: " + e.getMessage()); + } + }, 5, 5, java.util.concurrent.TimeUnit.MINUTES); + + scheduler.scheduleAtFixedRate(() -> { + System.out.println("[CACHE] Running cache cleanup task..."); + analysisCache.cleanupExpired(); // your cleanup method + }, 1, 5, TimeUnit.MINUTES); + + + } + + + private static byte[] toXmiBytes(org.apache.uima.jcas.JCas jcas) throws Exception { + java.io.ByteArrayOutputStream bos = new java.io.ByteArrayOutputStream(); + org.apache.uima.cas.impl.XmiCasSerializer ser = + new org.apache.uima.cas.impl.XmiCasSerializer(jcas.getTypeSystem()); + org.apache.uima.util.XMLSerializer xmlSer = + new org.apache.uima.util.XMLSerializer(bos, true); + xmlSer.setOutputProperty(javax.xml.transform.OutputKeys.VERSION, "1.1"); + ser.serialize(jcas.getCas(), xmlSer.getContentHandler()); + return bos.toByteArray(); + } + + + // When we send CAS to the importer via HTTP, we want to capture the response. + // This small class acts like a container for the HTTP response details + private static class HttpResult { + final int status; + final String body; + final String locationHeader; + HttpResult(int status, String body, String locationHeader) { + this.status = status; this.body = body; this.locationHeader = locationHeader; + } + } + + + // Send CAS via HTTP + private static HttpResult postMultipart(String urlStr, + Map fields, + String fileField, String filename, + String fileContentType, byte[] fileBytes) throws Exception { + String boundary = "----JAVA-" + UUID.randomUUID(); //Generate a boundary string to separate parts in multipart body + URL url = new URL(urlStr); //Open HTTP connection to the importer endpoint + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setDoOutput(true); + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); + + try (DataOutputStream out = new DataOutputStream(conn.getOutputStream())) { //Write request body + // text fields + for (var e : fields.entrySet()) { + out.writeBytes("--" + boundary + "\r\n"); + out.writeBytes("Content-Disposition: form-data; name=\"" + e.getKey() + "\"\r\n\r\n"); + out.write(e.getValue().getBytes(StandardCharsets.UTF_8)); + out.writeBytes("\r\n"); + } + // file field + out.writeBytes("--" + boundary + "\r\n"); + out.writeBytes("Content-Disposition: form-data; name=\"" + fileField + "\"; filename=\"" + filename + "\"\r\n"); + out.writeBytes("Content-Type: " + fileContentType + "\r\n\r\n"); + out.write(fileBytes); + out.writeBytes("\r\n"); + out.writeBytes("--" + boundary + "--\r\n"); + out.flush(); + } + + int status = conn.getResponseCode(); //Read the HTTP response from the importer + String location = conn.getHeaderField("Location"); + String body; + + try (InputStream in = (status >= 200 && status < 400) ? conn.getInputStream() : conn.getErrorStream()) { + body = (in != null) ? new String(in.readAllBytes(), StandardCharsets.UTF_8) : ""; + } + conn.disconnect(); + return new HttpResult(status, body, location); + } + + public static HttpResult sendToImporterViaHttp(String importUrl, //Send cached CAS to importer + String analysisId, + long corpusId, + String documentId, + String casView) throws Exception { + AnalysisSession s = getCachedSession(analysisId); + if (s == null) throw new IllegalArgumentException("No cached session for id: " + analysisId); + + java.io.ByteArrayOutputStream bos = new java.io.ByteArrayOutputStream(); // Convert JCas -> XMI bytes + org.apache.uima.cas.impl.XmiCasSerializer ser = + new org.apache.uima.cas.impl.XmiCasSerializer(s.jcas.getTypeSystem()); + org.apache.uima.util.XMLSerializer xmlSer = + new org.apache.uima.util.XMLSerializer(bos, /*prettyPrint*/ true); + xmlSer.setOutputProperty(javax.xml.transform.OutputKeys.VERSION, "1.1"); + ser.serialize(s.jcas.getCas(), xmlSer.getContentHandler()); + byte[] casBytes = bos.toByteArray(); + + Map fields = new LinkedHashMap<>(); // Form-data fields + fields.put("analysisId", analysisId); + fields.put("corpusId", Long.toString(corpusId)); + if (documentId != null && !documentId.isBlank()) fields.put("documentId", documentId); + if (casView != null && !casView.isBlank()) fields.put("casView", casView); + + String corpusConfigJson = System.getenv("UCE_CORPUS_CONFIG_JSON"); // Include corpusConfig + if (corpusConfigJson == null || corpusConfigJson.isBlank()) { + String cfgPath = System.getenv("UCE_CORPUS_CONFIG_PATH"); + if (cfgPath != null && !cfgPath.isBlank()) { + corpusConfigJson = java.nio.file.Files.readString( + java.nio.file.Path.of(cfgPath), + java.nio.charset.StandardCharsets.UTF_8 + ); + } + } + if (corpusConfigJson != null && !corpusConfigJson.isBlank()) { + fields.put("corpusConfig", corpusConfigJson); + } + + // Send multipart as XMI + String filename = "cas_" + analysisId + ".xmi"; + System.out.println("[IMPORT][HTTP] POST " + importUrl + + " corpusId=" + corpusId + " analysisId=" + analysisId + + " documentId=" + documentId + " casView=" + casView + + " file=" + filename + " (" + casBytes.length + " bytes)"); + + HttpResult res = postMultipart( + importUrl, + fields, + "file", + filename, + "application/xml", + casBytes + ); + System.out.println("[IMPORT][HTTP] status=" + res.status + + (res.locationHeader != null ? " Location=" + res.locationHeader : "") + + (res.body != null && !res.body.isBlank() ? " body=" + res.body : "")); + return res; + } + } diff --git a/uce.portal/uce.common/src/main/resources/defaultUceConfig.json b/uce.portal/uce.common/src/main/resources/defaultUceConfig.json index b9ff7a68..7280bb23 100644 --- a/uce.portal/uce.common/src/main/resources/defaultUceConfig.json +++ b/uce.portal/uce.common/src/main/resources/defaultUceConfig.json @@ -79,7 +79,7 @@ "enableAnalysisEngine": true }, "authentication": { - "isActivated": true, + "isActivated": false, "publicUrl": "http://localhost:8080", "redirectUrl": "http://localhost:4567/auth" }, diff --git a/uce.portal/uce.web/src/main/java/org/texttechnologylab/uce/web/App.java b/uce.portal/uce.web/src/main/java/org/texttechnologylab/uce/web/App.java index 00766037..9652ae1e 100644 --- a/uce.portal/uce.web/src/main/java/org/texttechnologylab/uce/web/App.java +++ b/uce.portal/uce.web/src/main/java/org/texttechnologylab/uce/web/App.java @@ -469,6 +469,7 @@ private static void initSparkRoutes(ApplicationContext context, ApiRegistry regi get("/setHistory", (ctx) -> (registry.get(AnalysisApi.class)).setHistory(ctx)); post("/callHistory", (ctx) -> (registry.get(AnalysisApi.class)).callHistory(ctx)); post("/callHistoryText", (ctx) -> (registry.get(AnalysisApi.class)).callHistoryText(ctx)); + post("/importCas", (registry.get(AnalysisApi.class)).importCas); //added the importCas path }); path("/corpusUniverse", () -> { diff --git a/uce.portal/uce.web/src/main/java/org/texttechnologylab/uce/web/routes/AnalysisApi.java b/uce.portal/uce.web/src/main/java/org/texttechnologylab/uce/web/routes/AnalysisApi.java index 866242bc..99d47a94 100644 --- a/uce.portal/uce.web/src/main/java/org/texttechnologylab/uce/web/routes/AnalysisApi.java +++ b/uce.portal/uce.web/src/main/java/org/texttechnologylab/uce/web/routes/AnalysisApi.java @@ -3,6 +3,7 @@ import com.google.gson.Gson; import freemarker.template.Configuration; import io.javalin.http.Context; +import io.javalin.http.Handler; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.context.ApplicationContext; @@ -56,10 +57,14 @@ public void runPipeline(Context ctx) { model.put("inputLLM", inputLLM); RunDUUIPipeline pipeline = new RunDUUIPipeline(); + RunDUUIPipeline.AnalysisResponse resp = + pipeline.getModelResourcesWithHandle(selectedModels, inputText, inputClaim, + inputCoherence, inputStance, inputLLM); DUUIInformation DataRequest = pipeline.getModelResources(selectedModels, inputText, inputClaim, inputCoherence, inputStance, inputLLM); model.put("DUUI", DataRequest); model.put("SuccessRequest", true); model.put("modelGroups", DataRequest.getModelGroups()); + model.put("analysisId", resp.analysisId); // set history history.addDuuiInformation(String.valueOf(counter), DataRequest); @@ -180,5 +185,47 @@ public void callHistoryText(Context ctx) { ctx.render("defaultError.ftl"); } } + // NEW IMPORT ROUTE (Javalin) + @Authentication(required = Authentication.Requirement.LOGGED_IN, + route = Authentication.RouteTypes.POST, + path = "/api/analysis/importCas" + ) + public Handler importCas = ctx -> { + try { + String analysisId = ctx.queryParam("analysisId"); + if (analysisId == null || analysisId.isBlank()) { + ctx.status(400).result("Missing analysisId"); + return; + } + + // Lookup cached session + RunDUUIPipeline.AnalysisSession session = RunDUUIPipeline.getCachedSession(analysisId); + if (session == null) { + ctx.status(404).result("No cached CAS found for analysisId=" + analysisId); + return; + } + + // send to importer + long corpusId = Long.parseLong(System.getenv().getOrDefault("UCE_IMPORT_CORPUS_ID", "1")); + String documentId = null; // String documentId = "doc-" + analysisId; + String casView = null; + + try { + RunDUUIPipeline.sendToImporterViaHttp( + "http://localhost:4567/api/ie/upload/uima", + analysisId, corpusId, documentId, casView + ); + } catch (Exception e) { + e.printStackTrace(); + ctx.status(500).result("Importer HTTP failed: " + e.getMessage()); + return; + } + + ctx.status(200).result("CAS imported successfully for analysisId=" + analysisId); + } catch (Exception ex) { + logger.error("Error importing CAS", ex); + ctx.status(500).result("Error importing CAS: " + ex.getMessage()); + } + }; } From e68ec44a356b58ccee51785689fe59e84f43996b Mon Sep 17 00:00:00 2001 From: dua Date: Mon, 15 Sep 2025 12:43:31 +0200 Subject: [PATCH 2/7] enabled pipeline run again --- .../java/org/texttechnologylab/uce/analysis/DUUIPipeline.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uce.portal/uce.analysis/src/main/java/org/texttechnologylab/uce/analysis/DUUIPipeline.java b/uce.portal/uce.analysis/src/main/java/org/texttechnologylab/uce/analysis/DUUIPipeline.java index 8c666e80..3cb3d72a 100644 --- a/uce.portal/uce.analysis/src/main/java/org/texttechnologylab/uce/analysis/DUUIPipeline.java +++ b/uce.portal/uce.analysis/src/main/java/org/texttechnologylab/uce/analysis/DUUIPipeline.java @@ -120,7 +120,7 @@ public JCas getLanguage(String inputText) throws Exception { HashMap urls = new HashMap<>(); urls.put("LanguageDetection", "http://language.service.component.duui.texttechnologylab.org"); DUUIComposer composer = setListComposer(urls); - //cas = runPipeline(cas, composer); + cas = runPipeline(cas, composer); // Assuming the language detection component sets the language in the JCas String language = "en"; language = cas.getDocumentLanguage(); From ea1b98786c9745ba17ff6e0a5ce7d804adf551b4 Mon Sep 17 00:00:00 2001 From: dua Date: Mon, 15 Sep 2025 15:02:42 +0200 Subject: [PATCH 3/7] replaced system.out with logger.info --- .../uce/analysis/RunDUUIPipeline.java | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/uce.portal/uce.analysis/src/main/java/org/texttechnologylab/uce/analysis/RunDUUIPipeline.java b/uce.portal/uce.analysis/src/main/java/org/texttechnologylab/uce/analysis/RunDUUIPipeline.java index 74a6bdc7..6cfaf868 100644 --- a/uce.portal/uce.analysis/src/main/java/org/texttechnologylab/uce/analysis/RunDUUIPipeline.java +++ b/uce.portal/uce.analysis/src/main/java/org/texttechnologylab/uce/analysis/RunDUUIPipeline.java @@ -1,6 +1,8 @@ package org.texttechnologylab.uce.analysis; import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Sentence; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.apache.uima.fit.factory.JCasFactory; import org.apache.uima.fit.util.JCasUtil; import org.apache.uima.jcas.JCas; @@ -14,11 +16,6 @@ import java.time.Instant; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; -// Added imports (save .jcas, HTTP import, logging) -//import java.nio.file.Path; -//import java.nio.file.Paths; -//import java.nio.file.Files; -//import java.io.OutputStream; import java.io.InputStream; import java.io.DataOutputStream; import java.net.HttpURLConnection; @@ -31,6 +28,8 @@ public class RunDUUIPipeline { private static final AnalysisCache analysisCache = new AnalysisCache(); private static final ThreadLocal lastAnalysisIdTL = new ThreadLocal<>(); + private static final Logger logger = LogManager.getLogger(RunDUUIPipeline.class); + public static AnalysisSession getCachedSession(String analysisId) { return analysisCache.get(analysisId); } @@ -214,13 +213,13 @@ public DUUIInformation getModelResources(List modelGroups, String inputT newCas.setDocumentText(text); cas = newCas; - System.out.println("[CAS] Created secondary JCas for special models (fact/coherence/stance/LLM)"); + logger.info("[CAS] Created secondary JCas for special models (fact/coherence/stance/LLM)"); } // run pipeline DUUIComposer composer = pipeline.setComposer(modelInfosMap); JCas result = pipeline.runPipeline(cas, composer); - System.out.println("[CAS] Final result JCas created via pipeline.runPipeline(cas, composer)"); + logger.info("[CAS] Final result JCas created via pipeline.runPipeline(cas, composer)"); // get results Object[] results = pipeline.getJCasResults(result, modelInfosList, ttlabScorerGroups, cohmetrixScorerGroups); // print results @@ -271,7 +270,7 @@ public DUUIInformation getModelResources(List modelGroups, String inputT ); analysisCache.put(session); lastAnalysisIdTL.set(analysisId); - System.out.println("[CACHE] Added analysisId=" + analysisId + " (stored in memory; TTL=45min)"); + logger.info("[CACHE] Added analysisId=" + analysisId + " (stored in memory; TTL=45min)"); return duuiInformation; } @@ -364,7 +363,7 @@ public void cleanupExpired() { // cleanup all expired sessions AnalysisSession s = entry.getValue(); if (now - s.createdAtMillis > ttlMillis) { map.remove(entry.getKey()); - System.out.println("[CRON] Removed expired session: " + s.analysisId); + logger.info("[CRON] Removed expired session: " + s.analysisId); } } } @@ -377,12 +376,12 @@ public void cleanupExpired() { // cleanup all expired sessions try { analysisCache.cleanupExpired(); } catch (Exception e) { - System.err.println("[CACHE] Cache cleanup failed: " + e.getMessage()); + logger.error("[CACHE] Cache cleanup failed: " + e.getMessage()); } }, 5, 5, java.util.concurrent.TimeUnit.MINUTES); scheduler.scheduleAtFixedRate(() -> { - System.out.println("[CACHE] Running cache cleanup task..."); + logger.info("[CACHE] Running cache cleanup task..."); analysisCache.cleanupExpired(); // your cleanup method }, 1, 5, TimeUnit.MINUTES); @@ -494,7 +493,7 @@ public static HttpResult sendToImporterViaHttp(String importUrl, //Send cached C // Send multipart as XMI String filename = "cas_" + analysisId + ".xmi"; - System.out.println("[IMPORT][HTTP] POST " + importUrl + logger.info("[IMPORT][HTTP] POST " + importUrl + " corpusId=" + corpusId + " analysisId=" + analysisId + " documentId=" + documentId + " casView=" + casView + " file=" + filename + " (" + casBytes.length + " bytes)"); @@ -507,7 +506,7 @@ public static HttpResult sendToImporterViaHttp(String importUrl, //Send cached C "application/xml", casBytes ); - System.out.println("[IMPORT][HTTP] status=" + res.status + logger.info("[IMPORT][HTTP] status=" + res.status + (res.locationHeader != null ? " Location=" + res.locationHeader : "") + (res.body != null && !res.body.isBlank() ? " body=" + res.body : "")); return res; From 9f1d81c7f5487b75dd5ab5b7e8beaa68620bf8e7 Mon Sep 17 00:00:00 2001 From: dua Date: Thu, 18 Sep 2025 13:08:35 +0200 Subject: [PATCH 4/7] Added input field for corpusId --- .../templates/wiki/analysisResultFragment.ftl | 38 ++++++++++--------- .../uce/web/routes/AnalysisApi.java | 31 ++++++--------- 2 files changed, 32 insertions(+), 37 deletions(-) diff --git a/uce.portal/resources/templates/wiki/analysisResultFragment.ftl b/uce.portal/resources/templates/wiki/analysisResultFragment.ftl index 592ab90e..4cbcec2c 100644 --- a/uce.portal/resources/templates/wiki/analysisResultFragment.ftl +++ b/uce.portal/resources/templates/wiki/analysisResultFragment.ftl @@ -1,22 +1,26 @@ <#if analysisId??> -
- -
+
+ + + +
- - + + <#if DUUI??> <#if DUUI.modelGroups?has_content> <#if DUUI.isTopic> diff --git a/uce.portal/uce.web/src/main/java/org/texttechnologylab/uce/web/routes/AnalysisApi.java b/uce.portal/uce.web/src/main/java/org/texttechnologylab/uce/web/routes/AnalysisApi.java index 99d47a94..b3952aa3 100644 --- a/uce.portal/uce.web/src/main/java/org/texttechnologylab/uce/web/routes/AnalysisApi.java +++ b/uce.portal/uce.web/src/main/java/org/texttechnologylab/uce/web/routes/AnalysisApi.java @@ -185,7 +185,7 @@ public void callHistoryText(Context ctx) { ctx.render("defaultError.ftl"); } } - // NEW IMPORT ROUTE (Javalin) + // IMPORT ROUTE @Authentication(required = Authentication.Requirement.LOGGED_IN, route = Authentication.RouteTypes.POST, path = "/api/analysis/importCas" @@ -206,26 +206,17 @@ public void callHistoryText(Context ctx) { } // send to importer - long corpusId = Long.parseLong(System.getenv().getOrDefault("UCE_IMPORT_CORPUS_ID", "1")); - String documentId = null; // String documentId = "doc-" + analysisId; - String casView = null; - - try { - RunDUUIPipeline.sendToImporterViaHttp( - "http://localhost:4567/api/ie/upload/uima", - analysisId, corpusId, documentId, casView - ); - } catch (Exception e) { - e.printStackTrace(); - ctx.status(500).result("Importer HTTP failed: " + e.getMessage()); - return; - } - + long corpusId = Long.parseLong(ctx.queryParam("corpusId")); // from ?corpusId=... + RunDUUIPipeline.sendToImporterViaHttp( + "http://localhost:4567/api/ie/upload/uima", + analysisId, corpusId, analysisId, null + ); ctx.status(200).result("CAS imported successfully for analysisId=" + analysisId); - - } catch (Exception ex) { - logger.error("Error importing CAS", ex); - ctx.status(500).result("Error importing CAS: " + ex.getMessage()); + } catch (NumberFormatException nfe) { + ctx.status(400).result("corpusId is required and must be a number"); + } catch (Exception e) { + logger.error("Error importing CAS", e); + ctx.status(500).result("Error importing CAS: " + e.getMessage()); } }; } From 38f76b057311659649bb7fbbbbe6d35d470b76a1 Mon Sep 17 00:00:00 2001 From: dua Date: Mon, 22 Sep 2025 12:18:23 +0200 Subject: [PATCH 5/7] derive importer URL from request host; remove hardcoded localhost removed un-used fields --- .../uce/analysis/RunDUUIPipeline.java | 22 +------------------ .../uce/web/routes/AnalysisApi.java | 10 ++++----- 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/uce.portal/uce.analysis/src/main/java/org/texttechnologylab/uce/analysis/RunDUUIPipeline.java b/uce.portal/uce.analysis/src/main/java/org/texttechnologylab/uce/analysis/RunDUUIPipeline.java index 6cfaf868..5174f85d 100644 --- a/uce.portal/uce.analysis/src/main/java/org/texttechnologylab/uce/analysis/RunDUUIPipeline.java +++ b/uce.portal/uce.analysis/src/main/java/org/texttechnologylab/uce/analysis/RunDUUIPipeline.java @@ -462,14 +462,7 @@ public static HttpResult sendToImporterViaHttp(String importUrl, //Send cached C AnalysisSession s = getCachedSession(analysisId); if (s == null) throw new IllegalArgumentException("No cached session for id: " + analysisId); - java.io.ByteArrayOutputStream bos = new java.io.ByteArrayOutputStream(); // Convert JCas -> XMI bytes - org.apache.uima.cas.impl.XmiCasSerializer ser = - new org.apache.uima.cas.impl.XmiCasSerializer(s.jcas.getTypeSystem()); - org.apache.uima.util.XMLSerializer xmlSer = - new org.apache.uima.util.XMLSerializer(bos, /*prettyPrint*/ true); - xmlSer.setOutputProperty(javax.xml.transform.OutputKeys.VERSION, "1.1"); - ser.serialize(s.jcas.getCas(), xmlSer.getContentHandler()); - byte[] casBytes = bos.toByteArray(); + byte[] casBytes = toXmiBytes(s.jcas); Map fields = new LinkedHashMap<>(); // Form-data fields fields.put("analysisId", analysisId); @@ -477,19 +470,6 @@ public static HttpResult sendToImporterViaHttp(String importUrl, //Send cached C if (documentId != null && !documentId.isBlank()) fields.put("documentId", documentId); if (casView != null && !casView.isBlank()) fields.put("casView", casView); - String corpusConfigJson = System.getenv("UCE_CORPUS_CONFIG_JSON"); // Include corpusConfig - if (corpusConfigJson == null || corpusConfigJson.isBlank()) { - String cfgPath = System.getenv("UCE_CORPUS_CONFIG_PATH"); - if (cfgPath != null && !cfgPath.isBlank()) { - corpusConfigJson = java.nio.file.Files.readString( - java.nio.file.Path.of(cfgPath), - java.nio.charset.StandardCharsets.UTF_8 - ); - } - } - if (corpusConfigJson != null && !corpusConfigJson.isBlank()) { - fields.put("corpusConfig", corpusConfigJson); - } // Send multipart as XMI String filename = "cas_" + analysisId + ".xmi"; diff --git a/uce.portal/uce.web/src/main/java/org/texttechnologylab/uce/web/routes/AnalysisApi.java b/uce.portal/uce.web/src/main/java/org/texttechnologylab/uce/web/routes/AnalysisApi.java index b3952aa3..26a0ba7b 100644 --- a/uce.portal/uce.web/src/main/java/org/texttechnologylab/uce/web/routes/AnalysisApi.java +++ b/uce.portal/uce.web/src/main/java/org/texttechnologylab/uce/web/routes/AnalysisApi.java @@ -60,7 +60,7 @@ public void runPipeline(Context ctx) { RunDUUIPipeline.AnalysisResponse resp = pipeline.getModelResourcesWithHandle(selectedModels, inputText, inputClaim, inputCoherence, inputStance, inputLLM); - DUUIInformation DataRequest = pipeline.getModelResources(selectedModels, inputText, inputClaim, inputCoherence, inputStance, inputLLM); + DUUIInformation DataRequest = resp.duuiInformation; model.put("DUUI", DataRequest); model.put("SuccessRequest", true); model.put("modelGroups", DataRequest.getModelGroups()); @@ -207,10 +207,10 @@ public void callHistoryText(Context ctx) { // send to importer long corpusId = Long.parseLong(ctx.queryParam("corpusId")); // from ?corpusId=... - RunDUUIPipeline.sendToImporterViaHttp( - "http://localhost:4567/api/ie/upload/uima", - analysisId, corpusId, analysisId, null - ); + String importPath = "/api/ie/upload/uima"; + String importUrl = ctx.scheme() + "://" + ctx.host() + importPath; + + RunDUUIPipeline.sendToImporterViaHttp(importUrl, analysisId, corpusId, analysisId, null); ctx.status(200).result("CAS imported successfully for analysisId=" + analysisId); } catch (NumberFormatException nfe) { ctx.status(400).result("corpusId is required and must be a number"); From f47df35f3e5c163be94877a1883d70b820f79a28 Mon Sep 17 00:00:00 2001 From: dua Date: Thu, 2 Oct 2025 11:00:43 +0200 Subject: [PATCH 6/7] Restored importer_cache_branch changes after stash --- .../src/main/resources/corpusConfig.json | 2 +- .../src/main/resources/corpusConfig2.json | 45 +++++++++++++++++++ .../uce/web/routes/ImportExportApi.java | 12 +++-- 3 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 uce.portal/uce.common/src/main/resources/corpusConfig2.json diff --git a/uce.portal/uce.common/src/main/resources/corpusConfig.json b/uce.portal/uce.common/src/main/resources/corpusConfig.json index ba5592b2..1df15fc7 100644 --- a/uce.portal/uce.common/src/main/resources/corpusConfig.json +++ b/uce.portal/uce.common/src/main/resources/corpusConfig.json @@ -3,7 +3,7 @@ "author": "[author/owner of the corpus]", "language": "[de-DE, en-EN, ...]", "description": "", - "addToExistingCorpus": false, + "addToExistingCorpus": true, "annotations": { "annotatorMetadata": false, diff --git a/uce.portal/uce.common/src/main/resources/corpusConfig2.json b/uce.portal/uce.common/src/main/resources/corpusConfig2.json new file mode 100644 index 00000000..3a18c818 --- /dev/null +++ b/uce.portal/uce.common/src/main/resources/corpusConfig2.json @@ -0,0 +1,45 @@ +{ + "name": "[corpus_2]", + "author": "[author/owner of the corpus]", + "language": "[de-DE, en-EN, ...]", + "description": "", + "addToExistingCorpus": false, + + "annotations": { + "annotatorMetadata": false, + "uceMetadata": false, + "logicalLinks": false, + + "OCRPage": false, + "OCRParagraph": false, + "OCRBlock": false, + "OCRLine": false, + + "srLink": false, + "namedEntity": false, + "sentiment": false, + "emotion": false, + "geoNames": false, + "lemma": false, + "sentence": false, + "taxon": { + "annotated": false, + "//comment": "[Are the taxons annotated with biofid onthologies through the 'identifier' property?]", + "biofidOnthologyAnnotated": false + }, + "time": false, + "wikipediaLink": false, + "completeNegation": false, + "unifiedTopic": false + + }, + "other": { + "//comment": "[Is this corpus also available on https://sammlungen.ub.uni-frankfurt.de/? Either true or false]", + "availableOnFrankfurtUniversityCollection": false, + + "includeKeywordDistribution": false, + "enableEmbeddings": false, + "enableRAGBot": false, + "enableS3Storage": false + } +} \ No newline at end of file diff --git a/uce.portal/uce.web/src/main/java/org/texttechnologylab/uce/web/routes/ImportExportApi.java b/uce.portal/uce.web/src/main/java/org/texttechnologylab/uce/web/routes/ImportExportApi.java index bca4b9f7..5124599c 100644 --- a/uce.portal/uce.web/src/main/java/org/texttechnologylab/uce/web/routes/ImportExportApi.java +++ b/uce.portal/uce.web/src/main/java/org/texttechnologylab/uce/web/routes/ImportExportApi.java @@ -68,9 +68,11 @@ public void uploadUIMA(Context ctx) { // First, we need to know which corpus this document should be added to. var corpusId = ExceptionUtils.tryCatchLog( () -> Long.parseLong(new String(ctx.req().getPart("corpusId").getInputStream().readAllBytes(), StandardCharsets.UTF_8)), - (ex) -> logger.error("Error getting the corpusId this document should be added to. Aborting.", ex)); + (ex) -> logger.error("Error getting corpusId from request.", ex)); + if (corpusId == null) { - ctx.result("Parameter corpusId didn't exist. Without it, the document cannot be uploaded."); + ctx.status(400); + ctx.result("Parameter corpusId didn't exist; cannot upload document."); return; } @@ -85,9 +87,11 @@ public void uploadUIMA(Context ctx) { var corpus = ExceptionUtils.tryCatchLog( () -> db.getCorpusById(corpusId), - (ex) -> logger.error("Couldn't fetch corpus when uploading new document to corpusId " + corpusId, ex)); + (ex) -> logger.error("Couldn't fetch corpus with id " + corpusId, ex)); + if (corpus == null) { - ctx.result("Corpus with id " + corpusId + " wasn't found in the database; can't upload document."); + ctx.status(404); + ctx.result("Corpus with id " + corpusId + " wasn't found in the database."); return; } From e46ae617648ee6bcf1fadfbc144858c99702c6da Mon Sep 17 00:00:00 2001 From: dua Date: Thu, 2 Oct 2025 13:33:53 +0200 Subject: [PATCH 7/7] Changed corpus ID input to dropdown --- .../templates/wiki/analysisResultFragment.ftl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/uce.portal/resources/templates/wiki/analysisResultFragment.ftl b/uce.portal/resources/templates/wiki/analysisResultFragment.ftl index 4cbcec2c..2db15fd2 100644 --- a/uce.portal/resources/templates/wiki/analysisResultFragment.ftl +++ b/uce.portal/resources/templates/wiki/analysisResultFragment.ftl @@ -1,14 +1,19 @@ <#if analysisId??>
- - + + +