Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New External API Extraction Feature #379

Draft
wants to merge 65 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
6dbdc32
Added proxy retriever for external open_clip feature
lucaro Dec 11, 2022
1997b98
Added LevenshteinScoringTextRetriever
lucaro Dec 17, 2022
afc5fe5
Changed query string encoding in LevenshteinScoringTextRetriever
lucaro Dec 17, 2022
2cc9b81
Changed query string encoding in LevenshteinScoringTextRetriever again
lucaro Dec 17, 2022
875fe63
Added a way to specify the host of the external clip text instance vi…
sauterl Dec 19, 2022
60a5f6a
Merge remote-tracking branch 'origin/main' into VBS23
Spiess Apr 21, 2023
a71b74d
refactored AudioSegmentExporter
faberf Jun 8, 2023
168b480
Added isExtractable and refactored AudioSpectogramExporter as an example
faberf Jun 8, 2023
f589f94
added the correct file extension and dataurlprefix
faberf Jun 8, 2023
d2c1c12
- starting work on external api feature
silvanheller May 15, 2023
94f0c8f
updating with development stuff & adding model key
silvanheller May 16, 2023
0017dc9
Initial Implementation
faberf May 17, 2023
c8d6950
implemented client to python endpoint
faberf May 17, 2023
b544368
working commit, refactored external api support
faberf Jun 1, 2023
761d8ae
fixing getRows() which had infinite recursion
silvanheller May 17, 2023
58b953f
adding logging for faulty queries
silvanheller May 22, 2023
89e0fcd
adding logging for faulty queries
silvanheller May 22, 2023
539cdc5
moving logger to trace
silvanheller May 22, 2023
55a147b
clarifying documentation
silvanheller May 30, 2023
546b23c
first cleanup
silvanheller Jun 5, 2023
7d27038
working commit for rewrite of external-api-extraction
faberf Jun 8, 2023
2dee77f
Fixed windows-path issues in extraction item container for live-extra…
sauterl Jun 13, 2023
63f1f5c
Added Documentation
faberf Jun 13, 2023
a90e507
Merge branch 'main' into refactoring_exporters
faberf Jun 13, 2023
c95a02f
- starting work on external api feature
silvanheller May 15, 2023
99cb177
updating with development stuff & adding model key
silvanheller May 16, 2023
5589e5a
Initial Implementation
faberf May 17, 2023
89efaa9
implemented client to python endpoint
faberf May 17, 2023
c3e0f26
working commit, refactored external api support
faberf Jun 1, 2023
396a7cc
fixing getRows() which had infinite recursion
silvanheller May 17, 2023
37ff7ee
adding logging for faulty queries
silvanheller May 22, 2023
e3873b0
adding logging for faulty queries
silvanheller May 22, 2023
21fec92
moving logger to trace
silvanheller May 22, 2023
4649563
clarifying documentation
silvanheller May 30, 2023
fabc2ee
first cleanup
silvanheller Jun 5, 2023
1c5bed8
working commit for rewrite of external-api-extraction
faberf Jun 8, 2023
0b21390
Merge branch 'external-api-extraction' of github.com:vitrivr/cineast …
faberf Jun 13, 2023
c16433b
fixed message template
faberf Aug 23, 2023
78b06cc
templates are now stripped
faberf Sep 11, 2023
8987321
added FESVectorFeature
faberf Sep 11, 2023
d6d4c3f
removed alpha channel from video frames
faberf Sep 11, 2023
ca26e6e
Merged dev
lucaro Oct 8, 2023
6424616
Merge remote-tracking branch 'origin/main' into VBS24
lucaro Oct 8, 2023
8c85619
First sketch of handler for vector lookup
lucaro Oct 8, 2023
fb97e26
gitflow-feature-stash: externalclip
net-cscience-raphael Oct 26, 2023
bae673c
conda environment
net-cscience-raphael Oct 26, 2023
6d29951
added extraction for external clip
net-cscience-raphael Oct 26, 2023
823da7a
updated ffmeg due to access violations on some windows systems
net-cscience-raphael Oct 26, 2023
99adc01
Merge branch 'feature/externalclip' into external-api-extraction
net-cscience-raphael Nov 27, 2023
5280763
changed feature vector
net-cscience-raphael Nov 27, 2023
443c1ec
Added lighting and normal mapping to the lwjgl renderer (#386)
net-cscience-raphael Feb 26, 2024
78764d5
Ads exception handling for textures in 3d model
net-cscience-raphael Mar 4, 2024
ccab60f
ads external open ml clip for 3d models
net-cscience-raphael Mar 4, 2024
043acd3
ads error handling loading shaders
net-cscience-raphael Mar 4, 2024
850f4f0
Added depth to parent folder name generator
net-cscience-raphael Mar 5, 2024
3713e92
Added timeout to render process
net-cscience-raphael Mar 6, 2024
2276f9e
logging
net-cscience-raphael Mar 11, 2024
543e1fc
Added TimeLimitedFunction to perform a timeout if loading with extern…
net-cscience-raphael Mar 12, 2024
ae927e1
Ads documentation to TimeLimitedFunction
net-cscience-raphael Mar 12, 2024
d0fa44f
Changed scene render datatype from u_int to int
net-cscience-raphael Mar 25, 2024
2e8731c
and back do unsigned
net-cscience-raphael Mar 25, 2024
c582799
3d-debug non cachable error from lassimp ibrary
net-cscience-raphael Jun 12, 2024
42242c7
fixes the crash on runtime
net-cscience-raphael Jun 17, 2024
26bd3ff
Fault tolerance for model inconsitency
net-cscience-raphael Jul 1, 2024
436fbef
Added logging to time limited function
net-cscience-raphael Jul 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,5 @@ resources/

#IIIF
iiif-media-*/

cineast-api/src/main/python/__pycache__/
2 changes: 2 additions & 0 deletions cineast-api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ dependencies {
implementation group: 'com.fasterxml.jackson.module', name: 'jackson-module-kotlin', version: version_jackson
implementation group: 'de.svenkubiak', name: 'jBCrypt', version: version_jbcrypt
implementation group: 'org.vitrivr', name: 'cineast-proto', version: version_cineast_proto
implementation group: 'tech.molecules', name: 'external-umap-java', version: '1.0'


}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import org.vitrivr.cineast.api.rest.handlers.actions.tag.FindTagsAllGetHandler;
import org.vitrivr.cineast.api.rest.handlers.actions.tag.FindTagsByIdsPostHandler;
import org.vitrivr.cineast.api.rest.handlers.actions.tag.FindTagsGetHandler;
import org.vitrivr.cineast.api.rest.handlers.actions.vector.LoadVectorsForIdsPostHandler;
import org.vitrivr.cineast.api.rest.handlers.interfaces.DeleteRestHandler;
import org.vitrivr.cineast.api.rest.handlers.interfaces.DocumentedRestHandler;
import org.vitrivr.cineast.api.rest.handlers.interfaces.GetRestHandler;
Expand Down Expand Up @@ -427,7 +428,9 @@ private void registerRestOperations() {
new SelectFromTablePostHandler(),
new CountRowsGetHandler(),
/* Status */
new StatusInvocationHandler()
new StatusInvocationHandler(),
/* Vector */
new LoadVectorsForIdsPostHandler(Config.sharedConfig().getDatabase().getSelectorSupplier())
));
}

Expand Down
183 changes: 112 additions & 71 deletions cineast-api/src/main/java/org/vitrivr/cineast/api/Main.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
package org.vitrivr.cineast.api;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.logging.Logger;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.vitrivr.cineast.core.render.lwjgl.renderer.RenderJob;
import org.vitrivr.cineast.core.render.lwjgl.renderer.RenderWorker;

Expand All @@ -13,83 +20,117 @@
import org.vitrivr.cineast.standalone.monitoring.PrometheusServer;
import org.vitrivr.cineast.standalone.util.CLI;


public class Main {
private static final Logger LOGGER = LogManager.getLogger();

/**
* Entrypoint for Cineast API application.
*
* @param args Program arguments.
*/
public static void main(String[] args) {
/* (Force) load application config. */
if (args.length == 0) {
System.out.println("No config path given, loading default config '" + DEFAULT_CONFIG_PATH + "'");
if (Config.loadConfig(DEFAULT_CONFIG_PATH) == null) {
System.err.println("Failed to load Cineast configuration from '" + DEFAULT_CONFIG_PATH + "'. Cineast API will shutdown...");
System.exit(1);
}
}
/**
* Entrypoint for Cineast API application.
*
* @param args Program arguments.
*/
public static void main(String[] args) {
/* (Force) load application config. */
if (args.length == 0) {
System.out.println("No config path given, loading default config '" + DEFAULT_CONFIG_PATH + "'");
if (Config.loadConfig(DEFAULT_CONFIG_PATH) == null) {
System.err.println("Failed to load Cineast configuration from '" + DEFAULT_CONFIG_PATH + "'. Cineast API will shutdown...");
System.exit(1);
}
}

/* (Force) load application config. */
if (args.length != 0) {
if (Config.loadConfig(args[0]) == null) {
System.err.println("Failed to load Cineast configuration from '" + args[0] + "'. Cineast API will shutdown...");
System.exit(1);
}
}
/* (Force) load application config. */
if (args.length != 0) {
if (Config.loadConfig(args[0]) == null) {
System.err.println("Failed to load Cineast configuration from '" + args[0] + "'. Cineast API will shutdown...");
System.exit(1);
}
}

/* Start API endpoint. */
try {
APIEndpoint.getInstance().start();
} catch (Throwable e) {
e.printStackTrace();
System.err.println("Failed to initialize API endpoint due to an exception: " + e.getMessage());
}
/* Start API endpoint. */
try {
APIEndpoint.getInstance().start();
} catch (Throwable e) {
e.printStackTrace();
System.err.println("Failed to initialize API endpoint due to an exception: " + e.getMessage());
}

/* Start gRPC endpoint. */
try {
GRPCEndpoint.start();
} catch (Throwable e) {
e.printStackTrace();
System.err.println("Failed to initialize gRPC endpoint due to an exception: " + e.getMessage());
}
/* Start gRPC endpoint. */
try {
GRPCEndpoint.start();
} catch (Throwable e) {
e.printStackTrace();
System.err.println("Failed to initialize gRPC endpoint due to an exception: " + e.getMessage());
}

/* Initialize Monitoring */
try {
PrometheusServer.initialize();
} catch (Throwable e) {
e.printStackTrace();
System.err.println("Failed to initialize Monitoring due to an exception: " + e.getMessage());
}
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("Shutting down endpoints...");
APIEndpoint.stop();
GRPCEndpoint.stop();
PrometheusServer.stopServer();
if (RenderWorker.getRenderJobQueue() != null) {
RenderWorker.getRenderJobQueue().add(new RenderJob(JobControlCommand.SHUTDOWN_WORKER));
}
System.out.println("Goodbye!");
}));

if (Config.sharedConfig().getExtractor().getEnableRenderWorker()) {
/* Initialize Renderer */
var renderThread = new Thread(new RenderWorker(new LinkedBlockingDeque<>()), "RenderWorker");
renderThread.start();
}
/* Initialize Monitoring */
try {
PrometheusServer.initialize();
} catch (Throwable e) {
e.printStackTrace();
System.err.println("Failed to initialize Monitoring due to an exception: " + e.getMessage());
}
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("Shutting down endpoints...");
APIEndpoint.stop();
GRPCEndpoint.stop();
PrometheusServer.stopServer();
if (RenderWorker.getRenderJobQueue() != null) {
RenderWorker.getRenderJobQueue().add(new RenderJob(JobControlCommand.SHUTDOWN_WORKER));
}
System.out.println("Goodbye!");
}));

if (Config.sharedConfig().getExtractor().getEnableRenderWorker()) {
/* Initialize Renderer */
var renderThread = new Thread(new RenderWorker(new LinkedBlockingDeque<>()), "RenderWorker");
renderThread.start();
}

if (Config.sharedConfig().getApi().getEnableExternalClip()) {
/* Startup Clip Python Endpoint */
// TODO: Make this configurable
Path condaEnvironmentPath = Path.of( "C:/Users/walten0000/.conda/envs/openclip/python.exe");
Path scriptPath = Path.of( "./cineast-api/src/main/python/serve_open_clip_lion_text_feature_proxy.py");

var processParameters = new ArrayList<String>();
processParameters.add(condaEnvironmentPath.toString());
processParameters.add(scriptPath.toString());

var processBuilder = new ProcessBuilder(processParameters);
//processBuilder.command("python", "./cineast-api/src/main/python/serve_open_clip_lion_text_feature_proxy.py");
processBuilder.redirectErrorStream(true);

var processBuilderThread = new Thread(()->{
Process process = null;
try {
process = processBuilder.start();
process.info();
} catch (IOException e) {
throw new RuntimeException(e);
}
var reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
LOGGER.info("Starting OpenClip Python Endpoint");
reader.lines().forEach(l -> LOGGER.info("External Clip: " + l));

}
);
processBuilderThread.start();

}

try {
/* Start Cineast CLI in interactive mode (blocking). */
if (Config.sharedConfig().getApi().getEnableCli()) {
CLI.start(CineastCli.class);
} else {
while (true) {
Thread.sleep(100);
try {
/* Start Cineast CLI in interactive mode (blocking). */
if (Config.sharedConfig().getApi().getEnableCli()) {
CLI.start(CineastCli.class);
} else {
while (true) {
Thread.sleep(100);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
System.exit(0);
}
System.exit(0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.vitrivr.cineast.api.messages.query;

import java.util.Map;
import org.vitrivr.cineast.api.messages.lookup.IdList;

public record VectorLookup(IdList ids, String feature, String projection, Map<String, String> properties) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.vitrivr.cineast.api.messages.result;

import java.util.List;

public record IdVectorList(List<IdVectorPair> points) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.vitrivr.cineast.api.messages.result;

public record IdVectorPair(String id, float[] vector){

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package org.vitrivr.cineast.api.rest.handlers.actions.vector;

import io.javalin.http.Context;
import io.javalin.plugin.openapi.dsl.OpenApiBuilder;
import io.javalin.plugin.openapi.dsl.OpenApiDocumentation;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.vitrivr.cineast.api.messages.query.VectorLookup;
import org.vitrivr.cineast.api.messages.result.IdVectorList;
import org.vitrivr.cineast.api.messages.result.IdVectorPair;
import org.vitrivr.cineast.api.rest.handlers.interfaces.ParsingPostRestHandler;
import org.vitrivr.cineast.core.data.providers.primitive.PrimitiveTypeProvider;
import org.vitrivr.cineast.core.db.DBSelector;
import org.vitrivr.cineast.core.db.DBSelectorSupplier;
import tagbio.umap.Umap;

public class LoadVectorsForIdsPostHandler implements ParsingPostRestHandler<VectorLookup, IdVectorList> {

private final DBSelectorSupplier selectorSupply;

public LoadVectorsForIdsPostHandler(DBSelectorSupplier selectorSupply) {
this.selectorSupply = selectorSupply;
}

@Override
public OpenApiDocumentation docs() {
return OpenApiBuilder.document()
.operation(op -> {
op.summary("Loads the vectors of a particular feature, applies optional projection");
op.description("Loads the vectors of a particular feature, applies optional projection");
op.operationId("loadVectors");
op.addTagsItem("Vectors");
})
.body(inClass())
.json("200", outClass());
}

@Override
public IdVectorList performPost(VectorLookup input, Context ctx) {

DBSelector selector = this.selectorSupply.get();
selector.open("feature_" + input.feature());
List<Map<String, PrimitiveTypeProvider>> rows = selector.getRows("feature", input.ids().ids(), "vector_lookup");

List<String> ids = new ArrayList<>(input.ids().ids().size());
List<float[]> vectors = new ArrayList<>(input.ids().ids().size());

for (Map<String, PrimitiveTypeProvider> row : rows) {
ids.add(row.get("id").getString());
vectors.add(row.get("feature").getFloatArray());
}

selector.close();

switch (input.projection().toLowerCase()) {
case "umap" -> {

Umap umap = new Umap();

umap.setMetric(
input.properties().getOrDefault("metric", "cosine")
);

umap.setNumberComponents(
Integer.parseInt(
input.properties().getOrDefault("components", "3")
)
);

umap.setNumberNearestNeighbours(
Integer.parseInt(
input.properties().getOrDefault("nearestNeighbours", "15")
)
);

umap.setThreads(
Integer.parseInt(
input.properties().getOrDefault("threads", Runtime.getRuntime().availableProcessors() + "")
)
);

float[][] data = new float[vectors.size()][];

for (int i = 0; i < vectors.size(); ++i) {
data[i] = vectors.get(i);
}

float[][] transformed = umap.fitTransform(data);

List<IdVectorPair> pairs = new ArrayList<>(ids.size());

for (int i = 0; i < ids.size(); ++i) {
pairs.add(new IdVectorPair(ids.get(i), transformed[i]));
}

return new IdVectorList(pairs);

}
case "tsne" -> throw new IllegalStateException("tsne projection not implemented");


case "raw" -> {

List<IdVectorPair> pairs = new ArrayList<>(ids.size());

for (int i = 0; i < ids.size(); ++i) {
pairs.add(new IdVectorPair(ids.get(i), vectors.get(i)));
}

return new IdVectorList(pairs);

}
}

throw new IllegalArgumentException("Projection " + input.projection() + " not known");
}

@Override
public Class<VectorLookup> inClass() {
return VectorLookup.class;
}

@Override
public Class<IdVectorList> outClass() {
return IdVectorList.class;
}

@Override
public String route() {
return "/find/vectors";
}
}
Loading
Loading