Skip to content

Commit

Permalink
Merge pull request #5284 from inception-project/feature/5283-Improve-…
Browse files Browse the repository at this point in the history
…usability-of-interactive-recommender-sidebar

#5283 - Improve usability of interactive recommender sidebar
  • Loading branch information
reckart authored Feb 9, 2025
2 parents c94a404 + 8a67511 commit 0802f71
Show file tree
Hide file tree
Showing 57 changed files with 1,043 additions and 310 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
package de.tudarmstadt.ukp.inception.active.learning.log;

import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

import de.tudarmstadt.ukp.inception.active.learning.config.ActiveLearningAutoConfiguration;
Expand Down Expand Up @@ -58,32 +57,35 @@ public long getProject(ActiveLearningRecommendationEvent aEvent)
@Override
public String getDetails(ActiveLearningRecommendationEvent aEvent) throws IOException
{
ActiveLearningRecommendationDetails details = new ActiveLearningRecommendationDetails();
details.ann = new AnnotationDetails();
details.ann.setBegin(aEvent.getCurrentRecommendation().getBegin());
details.ann.setEnd(aEvent.getCurrentRecommendation().getEnd());
details.ann.setText(aEvent.getCurrentRecommendation().getCoveredText());
details.ann.setType(aEvent.getLayer().getName());
details.annotationFeature = aEvent.getAnnotationFeature();
details.userAction = aEvent.getAction();
details.currentLabel = aEvent.getCurrentRecommendation().getLabel();
details.score = aEvent.getCurrentRecommendation().getScore();
details.recommenderId = aEvent.getCurrentRecommendation().getRecommenderId();
var ann = new AnnotationDetails();
ann.setBegin(aEvent.getCurrentRecommendation().getBegin());
ann.setEnd(aEvent.getCurrentRecommendation().getEnd());
ann.setText(aEvent.getCurrentRecommendation().getCoveredText());
ann.setType(aEvent.getLayer().getName());

var allLabelList = aEvent.getAllRecommendations().stream() //
.map(ao -> ao.getLabel()) //
.collect(Collectors.joining(", "));

var details = new ActiveLearningRecommendationDetails( //
ann, //
aEvent.getAnnotationFeature(), //
aEvent.getAction(), //
aEvent.getCurrentRecommendation().getLabel(), //
aEvent.getCurrentRecommendation().getScore(), //
aEvent.getCurrentRecommendation().getRecommenderId(), //
allLabelList);

List<String> allLabelList = aEvent.getAllRecommendations().stream().map(ao -> ao.getLabel())
.collect(Collectors.toList());
details.allLabels = String.join(", ", allLabelList);
return JSONUtil.toJsonString(details);
}

public static class ActiveLearningRecommendationDetails
{
public AnnotationDetails ann;
public String annotationFeature;
public LearningRecordUserAction userAction;
public String currentLabel;
public double score;
public long recommenderId;
public String allLabels;
}
record ActiveLearningRecommendationDetails( //
AnnotationDetails ann, //
String annotationFeature, //
LearningRecordUserAction userAction, //
String currentLabel, //
double score, //
long recommenderId, //
String allLabels)
{}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,14 @@
*/
package de.tudarmstadt.ukp.inception.active.learning.log;

import static java.util.stream.Collectors.joining;

import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

import de.tudarmstadt.ukp.inception.active.learning.config.ActiveLearningAutoConfiguration;
import de.tudarmstadt.ukp.inception.active.learning.event.ActiveLearningSuggestionOfferedEvent;
import de.tudarmstadt.ukp.inception.log.adapter.EventLoggingAdapter;
import de.tudarmstadt.ukp.inception.log.model.AnnotationDetails;
import de.tudarmstadt.ukp.inception.recommendation.api.model.LearningRecordUserAction;
import de.tudarmstadt.ukp.inception.support.json.JSONUtil;

/**
Expand Down Expand Up @@ -58,31 +57,35 @@ public long getProject(ActiveLearningSuggestionOfferedEvent aEvent)
@Override
public String getDetails(ActiveLearningSuggestionOfferedEvent aEvent) throws IOException
{
Details details = new Details();
details.ann = new AnnotationDetails();
details.ann.setBegin(aEvent.getCurrentRecommendation().getBegin());
details.ann.setEnd(aEvent.getCurrentRecommendation().getEnd());
details.ann.setText(aEvent.getCurrentRecommendation().getCoveredText());
details.ann.setType(aEvent.getLayer().getName());
details.annotationFeature = aEvent.getAnnotationFeature();
details.currentLabel = aEvent.getCurrentRecommendation().getLabel();
details.score = aEvent.getCurrentRecommendation().getScore();
details.recommenderId = aEvent.getCurrentRecommendation().getRecommenderId();
var rec = aEvent.getCurrentRecommendation();

var ann = new AnnotationDetails();
ann.setBegin(rec.getBegin());
ann.setEnd(rec.getEnd());
ann.setText(rec.getCoveredText());
ann.setType(aEvent.getLayer().getName());

var allLabels = aEvent.getAllRecommendations().stream() //
.map(ao -> ao.getLabel()) //
.collect(joining(", "));

var details = new Details( //
ann, //
aEvent.getAnnotationFeature(), //
rec.getLabel(), //
rec.getScore(), //
rec.getRecommenderId(), //
allLabels);

List<String> allLabelList = aEvent.getAllRecommendations().stream().map(ao -> ao.getLabel())
.collect(Collectors.toList());
details.allLabels = String.join(", ", allLabelList);
return JSONUtil.toJsonString(details);
}

public static class Details
{
public AnnotationDetails ann;
public String annotationFeature;
public LearningRecordUserAction userAction;
public String currentLabel;
public double score;
public long recommenderId;
public String allLabels;
}
record Details( //
AnnotationDetails ann, //
String annotationFeature, //
String currentLabel, //
double score, //
long recommenderId, //
String allLabels)
{}
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,28 @@ public String getName()
}

@Override
public boolean accepts(AnnotationLayer aLayer, AnnotationFeature aFeature)
public boolean accepts(AnnotationLayer aLayer)
{
if (aLayer == null || aFeature == null) {
if (aLayer == null) {
return false;
}

return asList(SINGLE_TOKEN, TOKENS, CHARACTERS).contains(aLayer.getAnchoringMode())
&& SpanLayerSupport.TYPE.equals(aLayer.getType())
&& aFeature.getType().startsWith(PREFIX);
&& SpanLayerSupport.TYPE.equals(aLayer.getType());
}

@Override
public boolean accepts(AnnotationFeature aFeature)
{
if (aFeature == null) {
return false;
}

if (!accepts(aFeature.getLayer())) {
return false;
}

return aFeature.getType().startsWith(PREFIX);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,25 @@ public String getName()
}

@Override
public boolean accepts(AnnotationLayer aLayer, AnnotationFeature aFeature)
public boolean accepts(AnnotationLayer aLayer)
{
if (aLayer == null || aFeature == null) {
if (aLayer == null) {
return false;
}

return (asList(SINGLE_TOKEN, TOKENS).contains(aLayer.getAnchoringMode()))
&& !aLayer.isCrossSentence() && SpanLayerSupport.TYPE.equals(aLayer.getType())
&& CAS.TYPE_NAME_STRING.equals(aFeature.getType()) || aFeature.isVirtualFeature();
&& !aLayer.isCrossSentence() && SpanLayerSupport.TYPE.equals(aLayer.getType());
}

@Override
public boolean accepts(AnnotationFeature aFeature)
{
if (aFeature == null) {
return false;
}

return accepts(aFeature.getLayer()) && CAS.TYPE_NAME_STRING.equals(aFeature.getType())
|| aFeature.isVirtualFeature();
}
}
// end::classDefinition[]
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,19 @@ protected String exchange(List<ChatMessage> aMessages, ResponseFormat aResponsef
var request = AzureAiChatCompletionRequest.builder() //
.withApiKey(((ApiKeyAuthenticationTraits) traits.getAuthentication()).getApiKey()) //
.withMessages(messages) //
.withFormat(format) //
.build();
var response = client.generate(traits.getUrl(), request).trim();
.withFormat(format);

var options = traits.getOptions();
// https://platform.openai.com/docs/api-reference/chat/create recommends to set temperature
// or top_p but not both.
if (!options.containsKey(AzureAiChatCompletionRequest.TEMPERATURE.getName())
&& !options.containsKey(AzureAiChatCompletionRequest.TOP_P.getName())) {
request.withOption(AzureAiChatCompletionRequest.TEMPERATURE, 0.0d);
}
request.withOption(AzureAiChatCompletionRequest.SEED, 0xdeadbeef);
request.withExtraOptions(options);

var response = client.generate(traits.getUrl(), request.build()).trim();
LOG.trace("Azure AI OpenAI responds: [{}]", response);
return response;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,29 @@ public String getName()
@Override
public RecommendationEngine build(Recommender aRecommender)
{
AzureAiOpenAiRecommenderTraits traits = readTraits(aRecommender);
var traits = readTraits(aRecommender);
return new AzureAiOpenAiRecommender(aRecommender, traits, client, schemaService);
}

@Override
public boolean accepts(AnnotationLayer aLayer, AnnotationFeature aFeature)
public boolean accepts(AnnotationLayer aLayer)
{
return (SpanLayerSupport.TYPE.equals(aFeature.getLayer().getType())
|| DocumentMetadataLayerSupport.TYPE.equals(aFeature.getLayer().getType()))
&& TYPE_NAME_STRING.equals(aFeature.getType());
if (aLayer == null) {
return false;
}

return (SpanLayerSupport.TYPE.equals(aLayer.getType())
|| DocumentMetadataLayerSupport.TYPE.equals(aLayer.getType()));
}

@Override
public boolean accepts(AnnotationFeature aFeature)
{
if (aFeature == null) {
return false;
}

return accepts(aFeature.getLayer()) && TYPE_NAME_STRING.equals(aFeature.getType());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public class AzureAiChatCompletionRequest
public static final Option<Double> FREQUENCY_PENALTY = new DoubleOption("frequency_penalty",
-2.0d, 2.0d);
public static final Option<Double> TEMPERATURE = new DoubleOption("temperature", 0.0d, 2.0d);
public static final Option<Double> TOP_P = new DoubleOption("top_p", 0.0d, 1.0d);

public static List<Option<?>> getAllOptions()
{
Expand All @@ -53,6 +54,7 @@ public static List<Option<?>> getAllOptions()
private final @JsonInclude(NON_NULL) AzureAiGenerateResponseFormat format;
private final @JsonInclude(NON_NULL) @JsonProperty("frequency_penalty") Double frequencyPenalty;
private final @JsonInclude(NON_NULL) @JsonProperty("temperature") Double temperature;
private final @JsonInclude(NON_NULL) @JsonProperty("top_p") Double topP;
private final @JsonInclude(NON_NULL) @JsonProperty("seed") Integer seed;

private final List<AzureAiChatCompletionMessage> messages;
Expand All @@ -66,6 +68,7 @@ private AzureAiChatCompletionRequest(Builder builder)
frequencyPenalty = FREQUENCY_PENALTY.get(builder.options);
temperature = TEMPERATURE.get(builder.options);
seed = SEED.get(builder.options);
topP = TOP_P.get(builder.options);
}

public String getApiKey()
Expand All @@ -88,6 +91,26 @@ public List<AzureAiChatCompletionMessage> getMessages()
return messages;
}

public Double getFrequencyPenalty()
{
return frequencyPenalty;
}

public Double getTemperature()
{
return temperature;
}

public Double getTopP()
{
return topP;
}

public Integer getSeed()
{
return seed;
}

public static Builder builder()
{
return new Builder();
Expand Down Expand Up @@ -159,6 +182,21 @@ public <T> Builder withOption(Option<T> aOption, T aValue)
return this;
}

public <T> Builder withExtraOptions(Map<String, Object> aOptions)
{
if (aOptions != null) {
for (var setting : aOptions.entrySet()) {
var opt = getAllOptions().stream()
.filter(o -> o.getName().equals(setting.getKey())).findFirst();
if (opt.isPresent()) {
withOption((Option) opt.get(), setting.getValue());
}
}
}

return this;
}

public AzureAiChatCompletionRequest build()
{
return new AzureAiChatCompletionRequest(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ private void applyPreset(Form<ChatGptRecommenderTraits> aForm, Preset aPreset,

private String getPromptHints()
{
return traits.getObject().getPromptingMode().getHints();
var promptingMode = traits.getObject().getPromptingMode();
return promptingMode != null ? promptingMode.getHints() : null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
*/
package de.tudarmstadt.ukp.inception.recommendation.imls.llm.chatgpt;

import static de.tudarmstadt.ukp.inception.recommendation.imls.llm.chatgpt.client.ChatCompletionRequest.SEED;
import static de.tudarmstadt.ukp.inception.recommendation.imls.llm.chatgpt.client.ChatCompletionRequest.TEMPERATURE;
import static de.tudarmstadt.ukp.inception.recommendation.imls.llm.chatgpt.client.ChatCompletionRequest.TOP_P;
import static de.tudarmstadt.ukp.inception.recommendation.imls.llm.chatgpt.client.ChatGptResponseFormatType.JSON_SCHEMA;

import java.io.IOException;
Expand Down Expand Up @@ -69,9 +72,17 @@ protected String exchange(List<ChatMessage> aMessages,
.withApiKey(((ApiKeyAuthenticationTraits) traits.getAuthentication()).getApiKey()) //
.withMessages(messages) //
.withResponseFormat(getResponseFormat(aFormat, aJsonSchema)) //
.withOptions(traits.getOptions()) //
.withModel(traits.getModel());

var options = traits.getOptions();
// https://platform.openai.com/docs/api-reference/chat/create recommends to set temperature
// or top_p but not both.
if (!options.containsKey(TEMPERATURE.getName()) && !options.containsKey(TOP_P.getName())) {
request.withOption(TEMPERATURE, 0.0d);
}
request.withOption(SEED, 0xdeadbeef);
request.withExtraOptions(options);

var response = client.chat(traits.getUrl(), request.build()).trim();
LOG.trace("Response: [{}]", response);
return response;
Expand Down
Loading

0 comments on commit 0802f71

Please sign in to comment.