Erweiterungen
This commit is contained in:
34
Dockerfile
34
Dockerfile
@@ -1,30 +1,4 @@
|
||||
FROM ghcr.io/jqlang/jq:latest AS jq-stage
|
||||
|
||||
FROM eclipse-temurin:21-jdk AS build
|
||||
COPY --from=jq-stage /jq /usr/bin/jq
|
||||
# Test that jq works after copying
|
||||
RUN jq --version
|
||||
|
||||
ENV HOME=/app
|
||||
RUN mkdir -p $HOME
|
||||
WORKDIR $HOME
|
||||
COPY . $HOME
|
||||
|
||||
# If you have a Vaadin Pro key, pass it as a secret with id "proKey":
|
||||
#
|
||||
# $ docker build --secret id=proKey,src=$HOME/.vaadin/proKey .
|
||||
#
|
||||
# If you have a Vaadin Offline key, pass it as a secret with id "offlineKey":
|
||||
#
|
||||
# $ docker build --secret id=offlineKey,src=$HOME/.vaadin/offlineKey .
|
||||
|
||||
RUN --mount=type=cache,target=/root/.m2 \
|
||||
--mount=type=secret,id=proKey \
|
||||
--mount=type=secret,id=offlineKey \
|
||||
sh -c 'PRO_KEY=$(jq -r ".proKey // empty" /run/secrets/proKey 2>/dev/null || echo "") && \
|
||||
OFFLINE_KEY=$(cat /run/secrets/offlineKey 2>/dev/null || echo "") && \
|
||||
./mvnw clean package -DskipTests -Dvaadin.proKey=${PRO_KEY} -Dvaadin.offlineKey=${OFFLINE_KEY}'
|
||||
|
||||
FROM eclipse-temurin:21-jre-alpine
|
||||
COPY --from=build /app/target/*.jar app.jar
|
||||
ENTRYPOINT ["java", "-jar", "/app.jar", "--spring.profiles.active=prod"]
|
||||
FROM eclipse-temurin:21-jre
|
||||
COPY target/*.jar app.jar
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["java", "-jar", "/app.jar", "--spring.profiles.active=production"]
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -4,7 +4,7 @@
|
||||
<!-- Project from https://start.vaadin.com/65cb55a1-ddc8-4889-a49a-7208c5f943e7 -->
|
||||
<groupId>de.assecutor.aimailassistant</groupId>
|
||||
<artifactId>aimailassistant</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<version>0.8.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -33,6 +33,8 @@ public class OrderEmail {
|
||||
|
||||
private boolean deleted;
|
||||
|
||||
private boolean analyzing;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String summaryJson;
|
||||
|
||||
@@ -117,6 +119,14 @@ public class OrderEmail {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
public boolean isAnalyzing() {
|
||||
return analyzing;
|
||||
}
|
||||
|
||||
public void setAnalyzing(boolean analyzing) {
|
||||
this.analyzing = analyzing;
|
||||
}
|
||||
|
||||
public String getSummaryJson() {
|
||||
return summaryJson;
|
||||
}
|
||||
|
||||
@@ -304,23 +304,31 @@ public class ImapEmailService {
|
||||
orderEmail.setFromAddress("unknown@unknown.com");
|
||||
}
|
||||
|
||||
// Save first to get ID
|
||||
// Save first with analyzing=true
|
||||
orderEmail.setAnalyzing(true);
|
||||
orderEmail = orderEmailRepository.save(orderEmail);
|
||||
|
||||
// Notify UI about new email (shows "Analyse läuft")
|
||||
EmailBroadcaster.broadcast();
|
||||
|
||||
// Process with LLM
|
||||
try {
|
||||
OrderSummary summary = llmService.summarizeEmail(orderEmail);
|
||||
orderEmail.setSummaryJson(llmService.serializeSummary(summary));
|
||||
orderEmail.setType(summary.getOrderType());
|
||||
orderEmail.setAnalyzing(false);
|
||||
// processed bleibt false - wird erst gesetzt wenn der Benutzer die Email öffnet
|
||||
orderEmailRepository.save(orderEmail);
|
||||
log.info("Email processed successfully: {} (Type: {})", subject, summary.getOrderType());
|
||||
|
||||
// Notify UI about new email
|
||||
// Notify UI that analysis is complete
|
||||
EmailBroadcaster.broadcast();
|
||||
} catch (Exception e) {
|
||||
log.error("Error processing email with LLM: {}", subject, e);
|
||||
// Email is saved but not processed - still notify UI
|
||||
// Mark as no longer analyzing even on error
|
||||
orderEmail.setAnalyzing(false);
|
||||
orderEmailRepository.save(orderEmail);
|
||||
// Notify UI
|
||||
EmailBroadcaster.broadcast();
|
||||
}
|
||||
|
||||
|
||||
@@ -186,7 +186,11 @@ public class MainView extends VerticalLayout {
|
||||
String bgClass;
|
||||
String textClass;
|
||||
|
||||
if (email.isConfirmed()) {
|
||||
if (email.isAnalyzing()) {
|
||||
statusText = "Analyse läuft";
|
||||
bgClass = LumoUtility.Background.CONTRAST_10;
|
||||
textClass = LumoUtility.TextColor.SECONDARY;
|
||||
} else if (email.isConfirmed()) {
|
||||
statusText = "Bearbeitet";
|
||||
bgClass = LumoUtility.Background.SUCCESS_10;
|
||||
textClass = LumoUtility.TextColor.SUCCESS;
|
||||
@@ -248,6 +252,12 @@ public class MainView extends VerticalLayout {
|
||||
}
|
||||
|
||||
private void openDetailDialog(OrderEmail email) {
|
||||
if (email.isAnalyzing()) {
|
||||
Notification.show("Die Email wird noch analysiert. Bitte warten Sie, bis die Analyse abgeschlossen ist.",
|
||||
3000, Notification.Position.MIDDLE);
|
||||
return;
|
||||
}
|
||||
|
||||
OrderDetailDialog dialog = new OrderDetailDialog(
|
||||
email,
|
||||
llmService,
|
||||
|
||||
@@ -1063,14 +1063,17 @@ public class OrderDetailDialog extends Dialog {
|
||||
// Read-only mode: only show close and delete buttons
|
||||
getFooter().add(deleteButton, spacer, closeButton);
|
||||
} else {
|
||||
Button reanalyzeButton = new Button("Erneut analysieren", new Icon(VaadinIcon.REFRESH), e -> reanalyzeEmail());
|
||||
reanalyzeButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
|
||||
|
||||
if (orderEmail.getType() == EmailType.QUOTE_REQUEST) {
|
||||
Button sendOfferButton = new Button("Angebot senden", e -> sendOffer());
|
||||
sendOfferButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||
getFooter().add(deleteButton, spacer, closeButton, sendOfferButton);
|
||||
getFooter().add(deleteButton, reanalyzeButton, spacer, closeButton, sendOfferButton);
|
||||
} else {
|
||||
Button acceptButton = new Button("Auftrag annehmen", e -> acceptOrder());
|
||||
acceptButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||
getFooter().add(deleteButton, spacer, closeButton, acceptButton);
|
||||
getFooter().add(deleteButton, reanalyzeButton, spacer, closeButton, acceptButton);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1115,6 +1118,53 @@ public class OrderDetailDialog extends Dialog {
|
||||
}
|
||||
}
|
||||
|
||||
private void reanalyzeEmail() {
|
||||
Notification loadingNotification = Notification.show(
|
||||
"Email wird erneut analysiert...",
|
||||
0,
|
||||
Notification.Position.MIDDLE
|
||||
);
|
||||
|
||||
getUI().ifPresent(ui -> {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
OrderSummary newSummary = llmService.summarizeEmail(orderEmail);
|
||||
|
||||
ui.access(() -> {
|
||||
loadingNotification.close();
|
||||
|
||||
if (newSummary != null) {
|
||||
summary = newSummary;
|
||||
orderEmail.setSummaryJson(llmService.serializeSummary(summary));
|
||||
orderEmail.setType(summary.getOrderType());
|
||||
onProcessed.accept(orderEmail);
|
||||
|
||||
// UI komplett neu aufbauen
|
||||
remove(contentLayout);
|
||||
getFooter().removeAll();
|
||||
contentLayout = createContent();
|
||||
add(contentLayout);
|
||||
createFooter();
|
||||
|
||||
Notification.show("Analyse abgeschlossen", 3000, Notification.Position.BOTTOM_START);
|
||||
} else {
|
||||
Notification.show("Analyse fehlgeschlagen", 3000, Notification.Position.MIDDLE);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
ui.access(() -> {
|
||||
loadingNotification.close();
|
||||
Notification.show(
|
||||
"Fehler bei der Analyse: " + e.getMessage(),
|
||||
5000,
|
||||
Notification.Position.MIDDLE
|
||||
);
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
});
|
||||
}
|
||||
|
||||
private void sendOffer() {
|
||||
// Validierung prüfen
|
||||
if (binder != null && !binder.isValid()) {
|
||||
|
||||
Reference in New Issue
Block a user