Skip to content

Commit b67ad04

Browse files
author
haniyakonain
committed
feat: improve UI and handle partial extraction results
- Redesign extractor selection with dropdown and custom panel - Allow partial results when some extractors fail - Add X-Extraction-Warnings response header - Include warning comments in text-based output formats - Enhanced error logging per extractor
1 parent 7485d00 commit b67ad04

File tree

1 file changed

+58
-9
lines changed

1 file changed

+58
-9
lines changed

server/src/main/scala/org/dbpedia/extraction/server/resources/Extraction.scala

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,54 @@ val extractors = Server.getInstance().getAvailableExtractorNames(language)
7070
<option value="rdf-json">RDF/JSON</option>
7171
</select><br/>
7272
Select Extractors:<br/>
73-
<label for="mappings">Mappings Only <input type="checkbox" name="extractors" value="mappings" id="mappings"/></label><br/>
74-
<label for="custom">All Enabled Extractors <input type="checkbox" name="extractors" value="custom" id="custom"/></label><br/>
75-
{extractors.map(extractor => {
76-
val sanitizedId = extractor.replaceAll("[^a-zA-Z0-9_-]", "_")
77-
<span>
78-
<label for={sanitizedId}>{extractor} <input type="checkbox" name="extractors" value={extractor} id={sanitizedId}/></label><br/>
79-
</span>
73+
<select id="extractorMode" onchange="toggleCustomExtractors()">
74+
<option value="mappings">Mappings Only </option>
75+
<option value="custom">All Enabled Extractors</option>
76+
<option value="custom-selection">Custom</option>
77+
</select><br/>
78+
<div id="customExtractors" style="display:none; margin-top:10px; padding:10px; border:1px solid #ddd; background-color:#f9f9f9;">
79+
<strong>Select extractors to combine:</strong><br/>
80+
<label><input type="checkbox" name="extractors" value="mappings" id="cb-mappings"/> Mappings Only</label><br/>
81+
<label><input type="checkbox" name="extractors" value="custom" id="cb-custom"/> All Enabled Extractors</label><br/>
82+
{extractors.map(extractor => {
83+
val sanitizedId = "cb-" + extractor.replaceAll("[^a-zA-Z0-9_-]", "_")
84+
<label><input type="checkbox" name="extractors" value={extractor} id={sanitizedId}/> {extractor}</label><br/>
8085
})}
86+
</div>
8187
<input type="submit" value="Extract" />
8288
</form>
89+
<script type="text/javascript">
90+
{scala.xml.Unparsed("""
91+
function toggleCustomExtractors() {
92+
var mode = document.getElementById('extractorMode').value;
93+
var customDiv = document.getElementById('customExtractors');
94+
95+
if (mode === 'custom-selection') {
96+
customDiv.style.display = 'block';
97+
} else {
98+
customDiv.style.display = 'none';
99+
}
100+
}
101+
102+
document.querySelector('form').addEventListener('submit', function(e) {
103+
var mode = document.getElementById('extractorMode').value;
104+
105+
if (mode === 'mappings') {
106+
var input = document.createElement('input');
107+
input.type = 'hidden';
108+
input.name = 'extractors';
109+
input.value = 'mappings';
110+
this.appendChild(input);
111+
} else if (mode === 'custom') {
112+
var input = document.createElement('input');
113+
input.type = 'hidden';
114+
input.name = 'extractors';
115+
input.value = 'custom';
116+
this.appendChild(input);
117+
}
118+
});
119+
""")}
120+
</script>
83121
</div>
84122
</div>
85123
</body>
@@ -251,23 +289,34 @@ name match {
251289
}
252290

253291
if (errors.nonEmpty) {
292+
logger.warning(s"Partial extraction completed with errors: ${errors.mkString("; ")}")
293+
if (collector.quads.isEmpty) {
254294
val errorMessage = if (errors.size == 1) errors.head
255295
else s"Multiple extractor errors:\n${errors.mkString("\n")}"
256296
val statusCode = if (errors.exists(_.contains("not found"))) Response.Status.BAD_REQUEST
257297
else Response.Status.INTERNAL_SERVER_ERROR
258298
throw new WebApplicationException(new Exception(errorMessage), statusCode)
299+
}
259300
}
260301

261302
val writer = new StringWriter
262303
val formatter = createFormatter(finalFormat, writer)
304+
305+
if (errors.nonEmpty && (finalFormat.contains("turtle") || finalFormat.contains("n-triples") || finalFormat.contains("n-quads"))) {
306+
writer.write("# Warning: Partial results - some extractors failed:\n")
307+
errors.foreach(err => writer.write(s"# - $err\n"))
308+
writer.write("\n")
309+
}
310+
263311
val finalDestination = new DeduplicatingDestination(new WriterDestination(() => writer, formatter))
264312
finalDestination.open()
265313
finalDestination.write(collector.quads)
266314
finalDestination.close()
267315

268-
Response.ok(writer.toString)
316+
val responseBuilder = Response.ok(writer.toString)
269317
.header(HttpHeaders.CONTENT_TYPE, contentType + "; charset=UTF-8")
270-
.build()
318+
if (errors.nonEmpty) responseBuilder.header("X-Extraction-Warnings", errors.mkString("; "))
319+
responseBuilder.build()
271320

272321
case specificExtractor =>
273322
val writer = new StringWriter

0 commit comments

Comments
 (0)