chore: Add README.md files
This commit is contained in:
commit
4ceec902a3
155 changed files with 19124 additions and 0 deletions
|
@ -0,0 +1,11 @@
|
|||
package ch.phoenixtechnologies.lc4j.workshop;
|
||||
|
||||
import io.quarkiverse.langchain4j.RegisterAiService;
|
||||
import io.smallrye.mutiny.Multi;
|
||||
import jakarta.enterprise.context.SessionScoped;
|
||||
|
||||
@SessionScoped
|
||||
@RegisterAiService
|
||||
public interface CustomerSupportAgent {
|
||||
Multi<String> chat(String userMessage);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package ch.phoenixtechnologies.lc4j.workshop;
|
||||
|
||||
import io.quarkus.websockets.next.OnOpen;
|
||||
import io.quarkus.websockets.next.OnTextMessage;
|
||||
import io.quarkus.websockets.next.WebSocket;
|
||||
import io.smallrye.mutiny.Multi;
|
||||
|
||||
@WebSocket(path = "/customer-support-agent")
|
||||
public class CustomerSupportAgentWebSocket {
|
||||
private final CustomerSupportAgent agent;
|
||||
|
||||
public CustomerSupportAgentWebSocket(CustomerSupportAgent agent) {
|
||||
this.agent = agent;
|
||||
}
|
||||
|
||||
@OnOpen
|
||||
public String onOpen() {
|
||||
return "Welcome to Phoenix Technologies AI!";
|
||||
}
|
||||
|
||||
@OnTextMessage
|
||||
public Multi<String> onTextMessage(String message) {
|
||||
return agent.chat(message);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package ch.phoenixtechnologies.lc4j.workshop;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import org.mvnpm.importmap.Aggregator;
|
||||
|
||||
@ApplicationScoped
|
||||
@Path("/_importmap")
|
||||
public class ImportmapResource {
|
||||
private static final String JAVASCRIPT_CODE =
|
||||
"""
|
||||
const im = document.createElement('script');
|
||||
im.type = 'importmap';
|
||||
im.textContent = JSON.stringify(%s);
|
||||
document.currentScript.after(im);
|
||||
""";
|
||||
private String importmap;
|
||||
|
||||
@PostConstruct
|
||||
void init() {
|
||||
Aggregator aggregator = new Aggregator();
|
||||
// Add our own mappings
|
||||
aggregator.addMapping("icons/", "/icons/");
|
||||
aggregator.addMapping("components/", "/components/");
|
||||
aggregator.addMapping("fonts/", "/fonts/");
|
||||
this.importmap = aggregator.aggregateAsJson();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/dynamic.importmap")
|
||||
@Produces("application/importmap+json")
|
||||
public String importMap() {
|
||||
return this.importmap;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/dynamic-importmap.js")
|
||||
@Produces("application/javascript")
|
||||
public String importMapJson() {
|
||||
return JAVASCRIPT_CODE.formatted(this.importmap);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
import {css, LitElement} from 'lit';
|
||||
import '@vaadin/icon';
|
||||
import '@vaadin/button';
|
||||
import '@vaadin/text-field';
|
||||
import '@vaadin/text-area';
|
||||
import '@vaadin/form-layout';
|
||||
import '@vaadin/progress-bar';
|
||||
import '@vaadin/checkbox';
|
||||
import '@vaadin/horizontal-layout';
|
||||
import '@vaadin/grid';
|
||||
import '@vaadin/grid/vaadin-grid-sort-column.js';
|
||||
|
||||
export class DemoChat extends LitElement {
|
||||
|
||||
_stripHtml(html) {
|
||||
const div = document.createElement("div");
|
||||
div.innerHTML = html;
|
||||
return div.textContent || div.innerText || "";
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
const chatBot = document.getElementsByTagName("chat-bot")[0];
|
||||
|
||||
const protocol = (window.location.protocol === 'https:') ? 'wss' : 'ws';
|
||||
const socket = new WebSocket(protocol + '://' + window.location.host + '/customer-support-agent');
|
||||
|
||||
const that = this;
|
||||
socket.onmessage = function (event) {
|
||||
chatBot.hideLastLoading();
|
||||
// LLM response
|
||||
let lastMessage;
|
||||
if (chatBot.messages.length > 0) {
|
||||
lastMessage = chatBot.messages[chatBot.messages.length - 1];
|
||||
}
|
||||
if (lastMessage && lastMessage.sender.name === "Bot" && ! lastMessage.loading) {
|
||||
if (! lastMessage.msg) {
|
||||
lastMessage.msg = "";
|
||||
}
|
||||
lastMessage.msg += event.data;
|
||||
let bubbles = chatBot.shadowRoot.querySelectorAll("chat-bubble");
|
||||
let bubble = bubbles.item(bubbles.length - 1);
|
||||
if (lastMessage.message) {
|
||||
bubble.innerHTML = that._stripHtml(lastMessage.message) + lastMessage.msg;
|
||||
} else {
|
||||
bubble.innerHTML = lastMessage.msg;
|
||||
}
|
||||
chatBot.body.scrollTo({ top: chatBot.body.scrollHeight, behavior: 'smooth' })
|
||||
} else {
|
||||
chatBot.sendMessage(event.data, {
|
||||
right: false,
|
||||
sender: {
|
||||
name: "Bot"
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
chatBot.addEventListener("sent", function (e) {
|
||||
if (e.detail.message.sender.name !== "Bot") {
|
||||
// User message
|
||||
const msg = that._stripHtml(e.detail.message.message);
|
||||
socket.send(msg);
|
||||
chatBot.sendMessage("", {
|
||||
right: false,
|
||||
loading: true
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
customElements.define('demo-chat', DemoChat);
|
|
@ -0,0 +1,63 @@
|
|||
import {LitElement, html, css} from 'lit';
|
||||
import '@vaadin/icon';
|
||||
import '@vaadin/button';
|
||||
import '@vaadin/text-field';
|
||||
import '@vaadin/text-area';
|
||||
import '@vaadin/form-layout';
|
||||
import '@vaadin/progress-bar';
|
||||
import '@vaadin/checkbox';
|
||||
import '@vaadin/grid';
|
||||
import '@vaadin/grid/vaadin-grid-sort-column.js';
|
||||
|
||||
export class DemoTitle extends LitElement {
|
||||
|
||||
static styles = css`
|
||||
h2 {
|
||||
font-family: "Red Hat Mono", monospace;
|
||||
font-size: 60px;
|
||||
font-style: normal;
|
||||
font-variant: normal;
|
||||
font-weight: 700;
|
||||
line-height: 26.4px;
|
||||
color: var(--main-highlight-text-color);
|
||||
}
|
||||
|
||||
.title {
|
||||
text-align: center;
|
||||
padding: 1em;
|
||||
background: var(--main-bg-color);
|
||||
}
|
||||
|
||||
.explanation {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 50%;
|
||||
text-align: justify;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.explanation img {
|
||||
max-width: 60%;
|
||||
display: block;
|
||||
float:left;
|
||||
margin-right: 2em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
`
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="title">
|
||||
<h2>Phoenix Technologies</h2>
|
||||
</div>
|
||||
<div class="explanation">
|
||||
<p>Welcome to Phoenix Technologies!</p>
|
||||
<p>Please click the button on the bottom right to start the conversation
|
||||
with an LLM-powered customer support agent.</p>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
customElements.define('demo-title', DemoTitle);
|
1
demo-03/src/main/resources/META-INF/resources/fonts/red-hat-font.min.css
vendored
Normal file
1
demo-03/src/main/resources/META-INF/resources/fonts/red-hat-font.min.css
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
@font-face{font-family:"Red Hat Display";font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/redhatdisplay/v7/8vIQ7wUr0m80wwYf0QCXZzYzUoTg8z6hR4jNCH5Z.woff2) format("woff2");unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:"Red Hat Display";font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/redhatdisplay/v7/8vIQ7wUr0m80wwYf0QCXZzYzUoTg_T6hR4jNCA.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:"Red Hat Display";font-style:normal;font-weight:500;font-display:swap;src:url(https://fonts.gstatic.com/s/redhatdisplay/v7/8vIQ7wUr0m80wwYf0QCXZzYzUoTg8z6hR4jNCH5Z.woff2) format("woff2");unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:"Red Hat Display";font-style:normal;font-weight:500;font-display:swap;src:url(https://fonts.gstatic.com/s/redhatdisplay/v7/8vIQ7wUr0m80wwYf0QCXZzYzUoTg_T6hR4jNCA.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:"Red Hat Display";font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/s/redhatdisplay/v7/8vIQ7wUr0m80wwYf0QCXZzYzUoTg8z6hR4jNCH5Z.woff2) format("woff2");unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:"Red Hat Display";font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/s/redhatdisplay/v7/8vIQ7wUr0m80wwYf0QCXZzYzUoTg_T6hR4jNCA.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:"Red Hat Text";font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/redhattext/v6/RrQXbohi_ic6B3yVSzGBrMxQZqctMc-JPWCN.woff2) format("woff2");unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:"Red Hat Text";font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/redhattext/v6/RrQXbohi_ic6B3yVSzGBrMxQaKctMc-JPQ.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:"Red Hat Text";font-style:normal;font-weight:500;font-display:swap;src:url(https://fonts.gstatic.com/s/redhattext/v6/RrQXbohi_ic6B3yVSzGBrMxQZqctMc-JPWCN.woff2) format("woff2");unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:"Red Hat Text";font-style:normal;font-weight:500;font-display:swap;src:url(https://fonts.gstatic.com/s/redhattext/v6/RrQXbohi_ic6B3yVSzGBrMxQaKctMc-JPQ.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}/*# sourceMappingURL=red-hat-font.css.map */
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,7 @@
|
|||
// import './font-awesome-brands.js';
|
||||
// import './font-awesome-regular.js';
|
||||
import './font-awesome-solid.js';
|
||||
|
||||
// export * from './font-awesome-brands.js';
|
||||
// export * from './font-awesome-regular.js';
|
||||
export * from './font-awesome-solid.js';
|
82
demo-03/src/main/resources/META-INF/resources/index.html
Normal file
82
demo-03/src/main/resources/META-INF/resources/index.html
Normal file
|
@ -0,0 +1,82 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<link rel="shortcut icon" type="image/png" href="favicon.ico">
|
||||
|
||||
<script src="/_importmap/dynamic-importmap.js"></script>
|
||||
|
||||
<script type="module">
|
||||
import 'icons/font-awesome.js';
|
||||
import 'components/demo-title.js';
|
||||
import 'components/demo-chat.js';
|
||||
import 'wc-chatbot';
|
||||
</script>
|
||||
|
||||
<link rel="stylesheet" href="fonts/red-hat-font.min.css">
|
||||
|
||||
<title>Miles of Smiles</title>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--main-bg-color: rgb(246, 242, 242);
|
||||
--main-highlight-text-color: rgba(237, 98, 128);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
font-family: 'Red Hat Text', sans-serif;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
color: var(--lumo-body-text-color);
|
||||
background: var(--main-bg-color);
|
||||
}
|
||||
|
||||
chat-bot {
|
||||
--chatbot-avatar-bg-color: rgba(237, 98, 128);
|
||||
--chatbot-avatar-margin: 10%;
|
||||
--chatbot-header-bg-color: rgba(237, 98, 128);
|
||||
--chatbot-header-title-color: #FFFFFF;
|
||||
--chatbot-body-bg-color: var(--main-bg-color);
|
||||
--chatbot-send-button-color: rgba(237, 98, 128);
|
||||
}
|
||||
|
||||
chat-bot::part(chat-bubble) {
|
||||
--chat-bubble-avatar-color: rgba(237, 98, 128);
|
||||
--chat-bubble-color: rgba(203, 232, 237, 0.71);
|
||||
--chat-bubble-right-color: rgb(157, 238, 244);
|
||||
--chat-bubble-font-color: #333;
|
||||
--chat-bubble-font-right-color: #333;
|
||||
--chat-bubble-delay: 0.2s;
|
||||
}
|
||||
|
||||
.middle {
|
||||
margin-top: 2em;
|
||||
overflow: hidden;
|
||||
width: 50%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<demo-title></demo-title>
|
||||
|
||||
<div class="middle">
|
||||
<demo-chat>
|
||||
<chat-bot></chat-bot>
|
||||
</demo-chat>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
14
demo-03/src/main/resources/application.yaml
Normal file
14
demo-03/src/main/resources/application.yaml
Normal file
|
@ -0,0 +1,14 @@
|
|||
quarkus:
|
||||
langchain4j:
|
||||
openai:
|
||||
api-key: #PUT_YOUR_TOKEN_HERE
|
||||
base-url: https://inference-llama33-70b-maas.apps.ai.kvant.cloud/v1/
|
||||
timeout: 60s
|
||||
chat-model:
|
||||
model-name: inference-llama33-70b
|
||||
temperature: 1.0
|
||||
#max-tokens: 1000
|
||||
#frequency-penalty: 2
|
||||
frequency-penalty: 0
|
||||
log-requests: true
|
||||
log-responses: true
|
Loading…
Add table
Add a link
Reference in a new issue