chore: Add README.md files

This commit is contained in:
Roque Caballero 2025-03-28 17:36:22 +01:00
commit 4ceec902a3
Signed by: roque.caballero
SSH key fingerprint: SHA256:+oco2mi9KAXp5fmBGQyUMk3bBo0scA4b8sL7Gf2pEwo
155 changed files with 19124 additions and 0 deletions

24
demo-05/README.md Normal file
View file

@ -0,0 +1,24 @@
Demo 05 - RAG Part 1
===============================================
Retrieval Augmented Generation (RAG) is a way to extend the knowledge of the LLM used in the AI service.
The RAG pattern is composed of two parts:
* Ingestion: This is the part that stores data in the knowledge base.
* Augmentation: This is the part that adds the retrieved information to the input of the LLM.
# Configuring EasyRag
To configure EasyRag: In the src/main/resources/application.properties file, we have the following configuration:
```
quarkus.langchain4j.easy-rag.path=src/main/resources/rag
quarkus.langchain4j.easy-rag.max-segment-size=100
quarkus.langchain4j.easy-rag.max-overlap-size=25
quarkus.langchain4j.easy-rag.max-results=3
```
* `quarkus.langchain4j.easy-rag.path`: The path to the directory containing the data files.
* `quarkus.langchain4j.easy-rag.max-segment-size`: The maximum number of tokens in a segment. Each document is
split into segments (chunks) to be ingested by the LLM. This parameter defines the maximum number of tokens in a segment.
* `quarkus.langchain4j.easy-rag.max-overlap-size`: The maximum number of tokens to overlap between two segments.
That allows the LLM to have a context between two segments.
* `quarkus.langchain4j.easy-rag.max-results`: The maximum number of results to return when querying the knowledge base.

File diff suppressed because one or more lines are too long

203
demo-05/pom.xml Normal file
View file

@ -0,0 +1,203 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ch.phoenixtechnologies</groupId>
<artifactId>ai-lc4j-workshop</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>demo-05</artifactId>
<properties>
<java.version>21</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Plugin versions -->
<compiler-plugin.version>3.14.0</compiler-plugin.version>
<enforcer-plugin.version>3.5.0</enforcer-plugin.version>
<surefire-plugin.version>3.5.2</surefire-plugin.version>
<spotless-maven-plugin.version>2.44.3</spotless-maven-plugin.version>
<palantir-java-format.version>2.50.0</palantir-java-format.version>
<release-plugin.version>3.1.1</release-plugin.version>
<!-- Quarkus version -->
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>3.19.2</quarkus.platform.version>
<!-- LangChain4j-->
<quarkus-langchain4j.version>0.25.0</quarkus-langchain4j.version>
<!-- Test dependency versions -->
<assertj.version>3.27.3</assertj.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.quarkiverse.langchain4j</groupId>
<artifactId>quarkus-langchain4j-bom</artifactId>
<version>${quarkus-langchain4j.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-config-yaml</artifactId>
</dependency>
<dependency>
<groupId>io.quarkiverse.langchain4j</groupId>
<artifactId>quarkus-langchain4j-openai</artifactId>
</dependency>
<dependency>
<groupId>io.quarkiverse.langchain4j</groupId>
<artifactId>quarkus-langchain4j-easy-rag</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-websockets-next</artifactId>
</dependency>
<!-- UI -->
<dependency>
<groupId>org.mvnpm</groupId>
<artifactId>importmap</artifactId>
<version>1.0.8</version>
</dependency>
<dependency>
<groupId>org.mvnpm.at.mvnpm</groupId>
<artifactId>vaadin-webcomponents</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mvnpm</groupId>
<artifactId>es-module-shims</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mvnpm</groupId>
<artifactId>wc-chatbot</artifactId>
<version>0.2.0</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.platform.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>build</goal>
<goal>generate-code</goal>
<goal>generate-code-tests</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
<release>${java.version}</release>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<version>${enforcer-plugin.version}</version>
<executions>
<execution>
<id>ban-bad-log4j-versions</id>
<phase>validate</phase>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<bannedDependencies>
<excludes>
<exclude>org.apache.logging.log4j:log4j-core:(,2.17.1)</exclude>
</excludes>
</bannedDependencies>
</rules>
<fail>true</fail>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
<version>${spotless-maven-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
<phase>compile</phase>
</execution>
</executions>
<configuration>
<java>
<removeUnusedImports />
<palantirJavaFormat>
<version>${palantir-java-format.version}</version>
<style>PALANTIR</style>
<formatJavadoc>false</formatJavadoc>
</palantirJavaFormat>
</java>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>${release-plugin.version}</version>
<configuration>
<tagNameFormat>@{project.version}</tagNameFormat>
<checkModificationExcludes>mvnw</checkModificationExcludes>
<scmReleaseCommitComment>chore: release @{releaseLabel}</scmReleaseCommitComment>
<scmDevelopmentCommitComment>chore: prepare for next development iteration [skip ci]</scmDevelopmentCommitComment>
</configuration>
</plugin>
</plugins>
</build>
</project>

View file

@ -0,0 +1,12 @@
package ch.phoenixtechnologies.lc4j.openai.runtime.config;
import io.smallrye.config.ConfigMapping;
@ConfigMapping(prefix = "l4j.custom-embedding-model")
public interface CustomEmbeddingModelConfig {
String baseUrl();
String apiKey();
String modelName();
}

View file

@ -0,0 +1,26 @@
package ch.phoenixtechnologies.lc4j.openai.runtime.config;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.openai.OpenAiEmbeddingModel;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Produces;
@ApplicationScoped
public class CustomEmbeddingModelProducer {
private final CustomEmbeddingModelConfig config;
public CustomEmbeddingModelProducer(CustomEmbeddingModelConfig config) {
this.config = config;
}
@Produces
public EmbeddingModel getModel() {
return OpenAiEmbeddingModel.builder()
.apiKey(config.apiKey())
.baseUrl(config.baseUrl())
.modelName(config.modelName())
.logRequests(true)
.logResponses(true)
.build();
}
}

View file

@ -0,0 +1,18 @@
package ch.phoenixtechnologies.lc4j.workshop;
import dev.langchain4j.service.SystemMessage;
import io.quarkiverse.langchain4j.RegisterAiService;
import io.smallrye.mutiny.Multi;
import jakarta.enterprise.context.SessionScoped;
@SessionScoped
@RegisterAiService
public interface CustomerSupportAgent {
@SystemMessage(
"""
You are a customer support agent of a IT company 'Phoenix Technologies AG based in Switzerland.
You are friendly, polite and concise.
If the question is unrelated to IT services, you should politely redirect the customer to the right department.
""")
Multi<String> chat(String userMessage);
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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);

View 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

View file

@ -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';

View 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>

View file

@ -0,0 +1,27 @@
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
#model-name: gpt-4o-mini
temperature: 1.0
#max-tokens: 1000
#frequency-penalty: 2
frequency-penalty: 0
log-requests: true
log-responses: true
easy-rag:
max-segment-size: 100
max-overlap-size: 25
max-results: 3
path: src/main/resources/rag
reuse-embeddings:
enabled: true
l4j:
custom-embedding-model:
model-name: inference-multilingual-e5l
base-url: https://inference-multilingual-e5l-maas.apps.ai.kvant.cloud/v1
api-key: #PUT_YOUR_TOKEN_HERE

View file

@ -0,0 +1,37 @@
Phoenix Technologies IT Services Terms of Use
1. Introduction
These Terms of Service (“Terms”) govern the access or use by you, an individual, from within any country in the world, of applications, websites, content, products, and services (“Services”) made available by Phoenix Technologies IT Services, a company registered in the United States of America.
2. The Services
Phoenix Technologies provides IT Services to the end user. We reserve the right to temporarily or permanently discontinue the Services at any time and are not liable for any modification, suspension or discontinuation of the Services.
3. Bookings
3.1 Users may make a booking through our website or mobile application.
3.2 You must provide accurate, current and complete information during the reservation process. You are responsible for all charges incurred under your account.
3.3 All bookings are subject to IT service availability.
4. Cancellation Policy
4.1 Reservations can be cancelled up to 11 days prior to the start of the booking period.
4.2 If the booking period is less than 4 days, cancellations are not permitted.
5. Use of Service
5.1 All services rented from Phoenix Technologies must not be used:
for any illegal purpose or in connection with any criminal offense.
for using in profit organization.
for selling it to a third party.
outside of Switzerland or EU.
6. Liability
6.1 Users will be held liable for any damage, loss, or theft that occurs during the rental period.
6.2 We do not accept liability for any indirect or consequential loss, damage, or expense including but not limited to loss of profits.
7. Governing Law
These terms will be governed by and construed in accordance with the laws of the Switzerland, and any disputes relating to these terms will be subject to the exclusive jurisdiction of the courts of Switzerland.
8. Changes to These Terms
We may revise these terms of use at any time by amending this page. You are expected to check this page from time to time to take notice of any changes we made.
9. Acceptance of These Terms
By using the Services, you acknowledge that you have read and understand these Terms and agree to be bound by them.
If you do not agree to these Terms, please do not use or access our Services.