From e2004438089f5977f7ffd93eb46780d8909ed156 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Philippart?= Date: Wed, 2 Oct 2024 10:08:11 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20=E2=9C=A8=20Add=20Natural=20Language=20?= =?UTF-8?q?Processing=20demo=20in=20Java=20section=20(#81)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * conf: 🛠️ set dependencies version * conf: 🛠️ Exclude some Python config files * feat: ✨ Java NLP example: sentiments analysis --- .gitignore | 1 - ai/ai-endpoints/README.md | 3 +- ai/ai-endpoints/java-nlp/pom.xml | 130 ++++++ .../nlp/sentiment/AISentimentService.java | 18 + .../nlp/sentiment/EmotionEvaluation.java | 405 ++++++++++++++++++ .../sentiment/SentimentsAnalysisResource.java | 29 ++ .../src/main/resources/application.properties | 2 + .../python-langchain-chatbot/README.md | 1 + .../python-langchain-chatbot/requirements.txt | 14 +- 9 files changed, 594 insertions(+), 9 deletions(-) create mode 100644 ai/ai-endpoints/java-nlp/pom.xml create mode 100644 ai/ai-endpoints/java-nlp/src/main/java/com/ovhcloud/examples/aiendpoints/nlp/sentiment/AISentimentService.java create mode 100644 ai/ai-endpoints/java-nlp/src/main/java/com/ovhcloud/examples/aiendpoints/nlp/sentiment/EmotionEvaluation.java create mode 100644 ai/ai-endpoints/java-nlp/src/main/java/com/ovhcloud/examples/aiendpoints/nlp/sentiment/SentimentsAnalysisResource.java create mode 100644 ai/ai-endpoints/java-nlp/src/main/resources/application.properties diff --git a/.gitignore b/.gitignore index 0e398ae..0fd540f 100644 --- a/.gitignore +++ b/.gitignore @@ -28,7 +28,6 @@ venv/ .venv/ __pycache__/ - # JS node_modules/ diff --git a/ai/ai-endpoints/README.md b/ai/ai-endpoints/README.md index c7d646e..9ff244c 100644 --- a/ai/ai-endpoints/README.md +++ b/ai/ai-endpoints/README.md @@ -15,6 +15,7 @@ Don't hesitate to use the source code and give us feedback. ### ☕️ Java demos ☕️ + - [Natural Language Processing](./java-nlp) - [Chatbot with LangChain4j](./java-langchain4j-chatbot/): blocking mode, streaming mode and RAG mode. - [Blocking chatbot](./quarkus-langchain4j/) with LangChain4j and Quarkus - [Streaming chatbot](./quarkus-langchain4j-streaming/) with langChain4j and Quarkus. @@ -27,7 +28,7 @@ Don't hesitate to use the source code and give us feedback. - [Audio Virtual Assistant](./audio-virtual-assistant/) by putting ASR, LLM and TTS working together - [Conversational Memory for chatbot](./python-langchain-conversational-memory/) by using Mistral7B and LangChain Memory module - [Video Translator](./speech-ai-video-translator) with ASR, NMT and TTS to subtitle and dub video voices - - [ASR features](./asr-features) to better understand how Automtic Speech Recognition models work + - [ASR features](./asr-features) to better understand how Automatic Speech Recognition models work - [TTS features](./tts-features) to be able to use all Text To Speech models easily ### 🕸️ Javascript 🕸️ diff --git a/ai/ai-endpoints/java-nlp/pom.xml b/ai/ai-endpoints/java-nlp/pom.xml new file mode 100644 index 0000000..7c22c8d --- /dev/null +++ b/ai/ai-endpoints/java-nlp/pom.xml @@ -0,0 +1,130 @@ + + + + 4.0.0 + + com.ovhcloud.examples.aiendpoints + nlp + 1.0.0-SNAPSHOT + + nlp + https://endpoints.ai.cloud.ovh.net/ + + + UTF-8 + 3.12.1 + 21 + 21 + 21 + quarkus-bom + io.quarkus.platform + 3.11.0 + true + 3.2.5 + + + + + + ${quarkus.platform.group-id} + ${quarkus.platform.artifact-id} + ${quarkus.platform.version} + pom + import + + + + + + + io.quarkus + quarkus-arc + + + io.quarkus + quarkus-rest + + + io.quarkus + quarkus-rest-client-jackson + + + io.quarkus + quarkus-junit5 + test + + + + + + ${quarkus.platform.group-id} + quarkus-maven-plugin + ${quarkus.platform.version} + true + + + + build + generate-code + generate-code-tests + + + + + + maven-compiler-plugin + ${compiler-plugin.version} + + + -parameters + + + + + maven-surefire-plugin + ${surefire-plugin.version} + + + org.jboss.logmanager.LogManager + ${maven.home} + + + + + maven-failsafe-plugin + ${surefire-plugin.version} + + + + integration-test + verify + + + + ${project.build.directory}/${project.build.finalName}-runner + org.jboss.logmanager.LogManager + ${maven.home} + + + + + + + + + + native + + + native + + + + false + native + + + + \ No newline at end of file diff --git a/ai/ai-endpoints/java-nlp/src/main/java/com/ovhcloud/examples/aiendpoints/nlp/sentiment/AISentimentService.java b/ai/ai-endpoints/java-nlp/src/main/java/com/ovhcloud/examples/aiendpoints/nlp/sentiment/AISentimentService.java new file mode 100644 index 0000000..016e0a4 --- /dev/null +++ b/ai/ai-endpoints/java-nlp/src/main/java/com/ovhcloud/examples/aiendpoints/nlp/sentiment/AISentimentService.java @@ -0,0 +1,18 @@ +package com.ovhcloud.examples.aiendpoints.nlp.sentiment; + +import org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam; +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; + +@Path("/api") +@RegisterRestClient(baseUri = "https://roberta-base-go-emotions.endpoints.kepler.ai.cloud.ovh.net") +@ClientHeaderParam(name = "Authorization", value = "Bearer ${ovhcloud.ai-endpoints.token}") +@ClientHeaderParam(name = "Content-Type", value = "application/json") +public interface AISentimentService { + + @POST + @Path("text2emotions") + EmotionEvaluation text2emotions(String text); + +} diff --git a/ai/ai-endpoints/java-nlp/src/main/java/com/ovhcloud/examples/aiendpoints/nlp/sentiment/EmotionEvaluation.java b/ai/ai-endpoints/java-nlp/src/main/java/com/ovhcloud/examples/aiendpoints/nlp/sentiment/EmotionEvaluation.java new file mode 100644 index 0000000..504d819 --- /dev/null +++ b/ai/ai-endpoints/java-nlp/src/main/java/com/ovhcloud/examples/aiendpoints/nlp/sentiment/EmotionEvaluation.java @@ -0,0 +1,405 @@ +package com.ovhcloud.examples.aiendpoints.nlp.sentiment; + +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +public class EmotionEvaluation { + private Double admiration; + private Double amusement; + private Double anger; + private Double annoyance; + private Double approval; + private Double caring; + private Double confusion; + private Double curiosity; + private Double desire; + private Double disappointment; + private Double disapproval; + private Double disgust; + private Double embarrassment; + private Double excitement; + private Double fear; + private Double gratitude; + private Double grief; + private Double joy; + private Double love; + private Double nervousness; + private Double neutral; + private Double optimism; + private Double pride; + private Double realization; + private Double relief; + private Double remorse; + private Double sadness; + private Double surprise; + + // Utilities method + + private SortedMap toSortedMap(EmotionEvaluation emotion) { + Map map = toMap(emotion); + + Comparator valueComparator = new Comparator() { + @Override + public int compare(String o1, String o2) { + return map.get(o2).compareTo(map.get(o1)); // reversed for descending order + } + }; + + SortedMap sortedMap = new TreeMap<>(valueComparator); + sortedMap.putAll(map); + return sortedMap; + } + + public String toEmoji() { + String firstEmotion = toSortedMap(this).firstKey(); + // Transform an emotion name into a corresponding emoji + switch (firstEmotion) { + case "admiration": + return "🥹"; + case "amusement": + return "😆"; + case "anger": + return "😡"; + case "annoyance": + return "🙄"; + case "approval": + return "👍"; + case "caring": + return "🤷‍♂️"; + case "confusion": + return "🤔"; + case "curiosity": + return "🤩"; + case "desire": + return "🥰"; + case "disappointment": + return "😞"; + case "disapproval": + return "😤"; + case "disgust": + return "🤮"; + case "embarrassment": + return "😰"; + case "excitement": + return "🥳"; + case "fear": + return "😱"; + case "gratitude": + return "🙏"; + case "grief": + return "😢"; + case "joy": + return "😁"; + case "love": + return "😍"; + case "nervousness": + return "😨"; + case "neutral": + return "😐"; + case "optimism": + return "🤗"; + case "pride": + return "😎"; + case "realization": + return "🙂‍↔️"; + case "relief": + return "🫣"; + case "remorse": + return "😖"; + case "sadness": + return "😭"; + case "surprise": + return "😮"; + default: + return "⁉️"; + } + } + + private Map toMap(EmotionEvaluation emotion) { + Map map = new HashMap<>(); + map.put("admiration", emotion.getAdmiration()); + map.put("amusement", emotion.getAmusement()); + map.put("anger", emotion.getAnger()); + map.put("annoyance", emotion.getAnnoyance()); + map.put("approval", emotion.getApproval()); + map.put("caring", emotion.getCaring()); + map.put("confusion", emotion.getConfusion()); + map.put("curiosity", emotion.getCuriosity()); + map.put("desire", emotion.getDesire()); + map.put("disappointment", emotion.getDisappointment()); + map.put("disapproval", emotion.getDisapproval()); + map.put("disgust", emotion.getDisgust()); + map.put("embarrassment", emotion.getEmbarrassment()); + map.put("excitement", emotion.getExcitement()); + map.put("fear", emotion.getFear()); + map.put("gratitude", emotion.getGratitude()); + map.put("grief", emotion.getGrief()); + map.put("joy", emotion.getJoy()); + map.put("love", emotion.getLove()); + map.put("nervousness", emotion.getNervousness()); + map.put("optimism", emotion.getOptimism()); + map.put("pride", emotion.getPride()); + map.put("realization", emotion.getRealization()); + map.put("relief", emotion.getRelief()); + map.put("remorse", emotion.getRemorse()); + map.put("sadness", emotion.getSadness()); + map.put("surprise", emotion.getSurprise()); + return map; + } + + // Getters & Setters + public Double getAdmiration() { + return admiration; + } + + public void setAdmiration(Double admiration) { + this.admiration = admiration; + } + + public Double getAmusement() { + return amusement; + } + + public void setAmusement(Double amusement) { + this.amusement = amusement; + } + + public Double getAnger() { + return anger; + } + + public void setAnger(Double anger) { + this.anger = anger; + } + + public Double getAnnoyance() { + return annoyance; + } + + public void setAnnoyance(Double annoyance) { + this.annoyance = annoyance; + } + + public Double getApproval() { + return approval; + } + + public void setApproval(Double approval) { + this.approval = approval; + } + + public Double getCaring() { + return caring; + } + + public void setCaring(Double caring) { + this.caring = caring; + } + + public Double getConfusion() { + return confusion; + } + + public void setConfusion(Double confusion) { + this.confusion = confusion; + } + + public Double getCuriosity() { + return curiosity; + } + + public void setCuriosity(Double curiosity) { + this.curiosity = curiosity; + } + + public Double getDesire() { + return desire; + } + + public void setDesire(Double desire) { + this.desire = desire; + } + + public Double getDisappointment() { + return disappointment; + } + + public void setDisappointment(Double disappointment) { + this.disappointment = disappointment; + } + + public Double getDisapproval() { + return disapproval; + } + + public void setDisapproval(Double disapproval) { + this.disapproval = disapproval; + } + + public Double getDisgust() { + return disgust; + } + + public void setDisgust(Double disgust) { + this.disgust = disgust; + } + + public Double getEmbarrassment() { + return embarrassment; + } + + public void setEmbarrassment(Double embarrassment) { + this.embarrassment = embarrassment; + } + + public Double getExcitement() { + return excitement; + } + + public void setExcitement(Double excitement) { + this.excitement = excitement; + } + + public Double getFear() { + return fear; + } + + public void setFear(Double fear) { + this.fear = fear; + } + + public Double getGratitude() { + return gratitude; + } + + public void setGratitude(Double gratitude) { + this.gratitude = gratitude; + } + + public Double getGrief() { + return grief; + } + + public void setGrief(Double grief) { + this.grief = grief; + } + + public Double getJoy() { + return joy; + } + + public void setJoy(Double joy) { + this.joy = joy; + } + + public Double getLove() { + return love; + } + + public void setLove(Double love) { + this.love = love; + } + + public Double getNervousness() { + return nervousness; + } + + public void setNervousness(Double nervousness) { + this.nervousness = nervousness; + } + + public Double getNeutral() { + return neutral; + } + + public void setNeutral(Double neutral) { + this.neutral = neutral; + } + + public Double getOptimism() { + return optimism; + } + + public void setOptimism(Double optimism) { + this.optimism = optimism; + } + + public Double getPride() { + return pride; + } + + public void setPride(Double pride) { + this.pride = pride; + } + + public Double getRealization() { + return realization; + } + + public void setRealization(Double realization) { + this.realization = realization; + } + + public Double getRelief() { + return relief; + } + + public void setRelief(Double relief) { + this.relief = relief; + } + + public Double getRemorse() { + return remorse; + } + + public void setRemorse(Double remorse) { + this.remorse = remorse; + } + + public Double getSadness() { + return sadness; + } + + public void setSadness(Double sadness) { + this.sadness = sadness; + } + + public Double getSurprise() { + return surprise; + } + + public void setSurprise(Double surprise) { + this.surprise = surprise; + } + + @Override + public String toString() { + return "EmotionEvaluation [admiration=" + admiration + ", amusement=" + amusement + ", anger=" + + anger + ", annoyance=" + annoyance + ", approval=" + approval + ", caring=" + caring + + ", confusion=" + confusion + ", curiosity=" + curiosity + ", desire=" + desire + + ", disappointment=" + disappointment + ", disapproval=" + disapproval + ", disgust=" + + disgust + ", embarrassment=" + embarrassment + ", excitement=" + excitement + ", fear=" + + fear + ", gratitude=" + gratitude + ", grief=" + grief + ", joy=" + joy + ", love=" + love + + ", nervousness=" + nervousness + ", neutral=" + neutral + ", optimism=" + optimism + + ", pride=" + pride + ", realization=" + realization + ", relief=" + relief + ", remorse=" + + remorse + ", sadness=" + sadness + ", surprise=" + surprise + ", getAdmiration()=" + + getAdmiration() + ", getAmusement()=" + getAmusement() + ", getAnger()=" + getAnger() + + ", getAnnoyance()=" + getAnnoyance() + ", getApproval()=" + getApproval() + + ", getClass()=" + getClass() + ", getCaring()=" + getCaring() + ", getConfusion()=" + + getConfusion() + ", getCuriosity()=" + getCuriosity() + ", getDesire()=" + getDesire() + + ", getDisappointment()=" + getDisappointment() + ", getDisapproval()=" + getDisapproval() + + ", getDisgust()=" + getDisgust() + ", getEmbarrassment()=" + getEmbarrassment() + + ", getExcitement()=" + getExcitement() + ", getFear()=" + getFear() + ", getGratitude()=" + + getGratitude() + ", getGrief()=" + getGrief() + ", getJoy()=" + getJoy() + ", getLove()=" + + getLove() + ", hashCode()=" + hashCode() + ", getNervousness()=" + getNervousness() + + ", getNeutral()=" + getNeutral() + ", getOptimism()=" + getOptimism() + ", getPride()=" + + getPride() + ", getRealization()=" + getRealization() + ", getRelief()=" + getRelief() + + ", getRemorse()=" + getRemorse() + ", getSadness()=" + getSadness() + ", getSurprise()=" + + getSurprise() + ", toString()=" + super.toString() + "]"; + } + + +} diff --git a/ai/ai-endpoints/java-nlp/src/main/java/com/ovhcloud/examples/aiendpoints/nlp/sentiment/SentimentsAnalysisResource.java b/ai/ai-endpoints/java-nlp/src/main/java/com/ovhcloud/examples/aiendpoints/nlp/sentiment/SentimentsAnalysisResource.java new file mode 100644 index 0000000..054f6e0 --- /dev/null +++ b/ai/ai-endpoints/java-nlp/src/main/java/com/ovhcloud/examples/aiendpoints/nlp/sentiment/SentimentsAnalysisResource.java @@ -0,0 +1,29 @@ +package com.ovhcloud.examples.aiendpoints.nlp.sentiment; + +import org.eclipse.microprofile.rest.client.inject.RestClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +/** + * Class to do textual sentiments analysis. + */ +@Path("/sentiment") +public class SentimentsAnalysisResource { + + private static final Logger _LOG = LoggerFactory.getLogger(SentimentsAnalysisResource.class); + + @RestClient + private AISentimentService aiSentimentService; + + @POST + @Produces(MediaType.TEXT_PLAIN) + public String getSentiment(String text) { + _LOG.info("Sentiment analysis for text: {}", text); + + return aiSentimentService.text2emotions(text).toEmoji(); + } +} diff --git a/ai/ai-endpoints/java-nlp/src/main/resources/application.properties b/ai/ai-endpoints/java-nlp/src/main/resources/application.properties new file mode 100644 index 0000000..d7f37ce --- /dev/null +++ b/ai/ai-endpoints/java-nlp/src/main/resources/application.properties @@ -0,0 +1,2 @@ +# Token to use OVHcloud AI Endpoints +ovhcloud.ai-endpoints.token=${OVH_AI_ENDPOINTS_ACCESS_TOKEN} \ No newline at end of file diff --git a/ai/ai-endpoints/python-langchain-chatbot/README.md b/ai/ai-endpoints/python-langchain-chatbot/README.md index bd08122..f3bb2c9 100644 --- a/ai/ai-endpoints/python-langchain-chatbot/README.md +++ b/ai/ai-endpoints/python-langchain-chatbot/README.md @@ -3,6 +3,7 @@ This project illustrate how to use[LangChain](https://python.langchain.com/v0.2/ ## How to use the project - set the `OVH_AI_ENDPOINTS_ACCESS_TOKEN` environment variable with your API token (see https://endpoints.ai.cloud.ovh.net/) + - install lib magic: `brew install libmagic` - install the required dependencies: `pip3 install -r requirements.txt` - to use the blocking chatbot: `python3 chat-bot.py --question "What is OVHcloud?"` - to use the streaming chatbot: `python3 chat-bot-streaming.py --question "What is OVHcloud?"` diff --git a/ai/ai-endpoints/python-langchain-chatbot/requirements.txt b/ai/ai-endpoints/python-langchain-chatbot/requirements.txt index b5afad5..c8885d5 100644 --- a/ai/ai-endpoints/python-langchain-chatbot/requirements.txt +++ b/ai/ai-endpoints/python-langchain-chatbot/requirements.txt @@ -1,7 +1,7 @@ -langchain -langchain-mistralai -langchain_community -langchain_chroma -argparse -unstructured -langchainhub \ No newline at end of file +langchain==0.2.16 +langchain-mistralai==0.1.13 +langchain_community==0.2.16 +langchain_chroma==0.1.3 +argparse==1.4.0 +unstructured==0.15.9 +langchainhub==0.1.21 \ No newline at end of file