diff --git a/examples/rag-playground/src/components/app/app.css b/examples/rag-playground/src/components/app/app.css
index ee45f20..1269e3b 100644
--- a/examples/rag-playground/src/components/app/app.css
+++ b/examples/rag-playground/src/components/app/app.css
@@ -3,17 +3,154 @@
height: 100%;
display: flex;
- flex-direction: row;
+ flex-direction: column;
+ justify-content: flex-start;
+ align-items: center;
+}
+
+* {
+ box-sizing: border-box;
+}
+
+.svg-icon {
+ display: flex;
justify-content: center;
align-items: center;
+ width: 1em;
+ height: 1em;
+
+ transition: transform 80ms linear;
+ transform-origin: center;
+ & svg {
+ width: 100%;
+ height: 100%;
+ }
+}
+
+.main-app {
+ display: grid;
+ grid-template-columns: 1fr min-content 1fr;
+ grid-template-rows: 1fr min-content 1fr;
+ height: calc(100vh - 5px);
+ max-height: 820px;
+ width: 100vw;
box-sizing: border-box;
+ overflow-x: hidden;
+ position: relative;
+ background-color: hsl(216, 77%, 27%);
+}
+
+.text-left {
+ grid-row: 2/3;
+ grid-column: 1/2;
+ display: flex;
+ justify-content: flex-end;
+ margin-top: 50px;
+ padding-right: 12px;
+ color: #e0e0e0;
}
-.app-container {
- width: min(1000px, 100vw - 50px);
- height: min(650px, 100vw - 50px);
- border-radius: 10px;
- border: 1px solid var(--gray-400);
- /* box-shadow: var(--shadow-border-light); */
+.app-wrapper {
+ grid-row: 2/3;
+ grid-column: 2/3;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+ max-height: 950px;
+
+ & mememo-playground {
+ border-radius: 10px;
+ /* border: 1px solid var(--gray-400); */
+ background-color: white;
+
+ width: min(1050px, 100vw - 50px);
+ height: min(650px, 100vw - 50px);
+ }
+
+ .app-title {
+ color: white;
+ width: 100%;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: flex-end;
+ padding: 0 10px 8px;
+ user-select: none;
+ -webkit-user-select: none;
+ line-height: 1;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+
+ .title-left {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 8px;
+ }
+
+ .app-title {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 8px;
+ }
+
+ .app-info {
+ display: flex;
+ align-items: baseline;
+ gap: 10px;
+ }
+
+ .app-name {
+ font-size: 32px;
+ font-weight: 800;
+ }
+
+ .app-tagline {
+ font-size: 26px;
+ font-weight: 200;
+ color: #fff;
+ display: flex;
+ flex-flow: row;
+
+ & a {
+ color: unset;
+ font-style: unset;
+ text-decoration: unset;
+ }
+
+ .mememo-logo {
+ margin-left: 9px;
+ display: flex;
+ flex-flow: row;
+ gap: 5px;
+ position: relative;
+
+ &::after {
+ content: '';
+ position: absolute;
+ top: 105%;
+ left: 50%;
+ transform: translate(-50%, 0);
+ width: 105%;
+ height: 2px;
+ background-color: hsla(0, 100%, 100%, 0.5);
+ }
+ }
+ }
+ }
+}
+
+.text-right {
+ grid-row: 2/3;
+ grid-column: 3/4;
+ display: flex;
+ justify-content: flex-start;
+ padding-left: 12px;
+ margin-top: 80px;
+ color: #e0e0e0;
}
diff --git a/examples/rag-playground/src/components/app/app.ts b/examples/rag-playground/src/components/app/app.ts
index 5507850..d03e379 100644
--- a/examples/rag-playground/src/components/app/app.ts
+++ b/examples/rag-playground/src/components/app/app.ts
@@ -4,6 +4,7 @@ import { unsafeHTML } from 'lit/directives/unsafe-html.js';
import '../playground/playground';
import componentCSS from './app.css?inline';
+import logoIcon from '../../images/icon-logo.svg?raw';
/**
* App element.
@@ -47,8 +48,38 @@ export class MememoRagPlayground extends LitElement {
render() {
return html`
-
`;
diff --git a/examples/rag-playground/src/components/playground/playground.css b/examples/rag-playground/src/components/playground/playground.css
index 580e871..23a84d1 100644
--- a/examples/rag-playground/src/components/playground/playground.css
+++ b/examples/rag-playground/src/components/playground/playground.css
@@ -24,6 +24,7 @@
minmax(300px, 400px);
--arrow-color: var(--gray-300);
+ --arrow-color-activated: var(--blue-300);
--border-radius: 5px;
--block-shadow: 0px 0px 2px hsla(0, 0%, 0%, 0.1),
0px 0px 6px hsla(0, 0%, 0%, 0.05);
@@ -118,6 +119,28 @@
}
}
+@keyframes animate-loader-left-right {
+ 0% {
+ left: 0;
+ transform: translateX(-100%);
+ }
+ 100% {
+ left: 100%;
+ transform: translateX(0%);
+ }
+}
+
+@keyframes animate-loader-top-bottom {
+ 0% {
+ top: 0;
+ transform: translateY(-100%);
+ }
+ 100% {
+ top: 100%;
+ transform: translateY(0%);
+ }
+}
+
.flow {
display: flex;
align-items: center;
@@ -125,6 +148,14 @@
z-index: 1;
position: relative;
+ &.running {
+ .background {
+ .line-loader {
+ display: inline-block;
+ }
+ }
+ }
+
&.input-text {
grid-row: 1 / 2;
grid-column: 2 / 5;
@@ -153,6 +184,18 @@
align-items: center;
width: 100%;
+ &.activated {
+ .background {
+ .start-rectangle {
+ background-color: var(--arrow-color-activated);
+ }
+
+ .end-triangle {
+ border-left: 20px solid var(--arrow-color-activated);
+ }
+ }
+ }
+
.background {
position: relative;
width: 100%;
@@ -166,13 +209,9 @@
width: 100%;
height: 30px;
- display: inline-block;
+ display: none;
overflow: hidden;
z-index: 2;
-
- &.hidden {
- display: none;
- }
}
.line-loader::after {
@@ -192,18 +231,7 @@
top: 0;
left: 0;
box-sizing: border-box;
- animation: animate-loader 1500ms ease-out infinite;
- }
-
- @keyframes animate-loader {
- 0% {
- left: 0;
- transform: translateX(-100%);
- }
- 100% {
- left: 100%;
- transform: translateX(0%);
- }
+ animation: animate-loader-left-right 1500ms ease-out infinite;
}
.start-rectangle {
@@ -241,6 +269,18 @@
align-items: center;
height: 100%;
+ &.activated {
+ .background {
+ .start-rectangle {
+ background-color: var(--arrow-color-activated);
+ }
+
+ .end-triangle {
+ border-top: 20px solid var(--arrow-color-activated);
+ }
+ }
+ }
+
.background {
position: relative;
height: 100%;
@@ -254,21 +294,17 @@
height: 100%;
width: 30px;
- display: inline-block;
+ display: none;
overflow: hidden;
z-index: 2;
-
- &.hidden {
- display: none;
- }
}
.line-loader::after {
content: '';
- height: 100px;
- width: 100%;
+ width: 30px;
+ height: 100%;
background: linear-gradient(
- 90deg,
+ 180deg,
hsla(0, 100%, 100%, 0) 0%,
hsla(0, 100%, 100%, 0) 10%,
hsla(0, 100%, 100%, 0.5) 50%,
@@ -280,18 +316,7 @@
top: 0;
left: 0;
box-sizing: border-box;
- animation: animate-loader 1500ms ease-out infinite;
- }
-
- @keyframes animate-loader {
- 0% {
- left: 0;
- transform: translateX(-100%);
- }
- 100% {
- left: 100%;
- transform: translateX(0%);
- }
+ animation: animate-loader-top-bottom 1500ms ease-out infinite;
}
.start-rectangle {
@@ -323,16 +348,43 @@
}
}
+.header {
+ font-size: var(--font-u1);
+ color: var(--gray-600);
+ line-height: 1.25;
+ font-weight: 800;
+}
+
+.svg-icon {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 1em;
+ height: 1em;
+
+ transition: transform 80ms linear;
+ transform-origin: center;
+
+ & svg {
+ width: 100%;
+ height: 100%;
+ }
+}
+
.search-box {
border-radius: var(--border-radius);
box-shadow: var(--block-shadow);
border: 1px solid hsla(0deg, 0%, 0%, 0.08);
- background-color: white;
+ background-color: var(--gray-900);
padding: 5px 10px;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
+
+ .header {
+ color: white;
+ }
}
.model-box {
diff --git a/examples/rag-playground/src/components/playground/playground.ts b/examples/rag-playground/src/components/playground/playground.ts
index aa23f80..223de48 100644
--- a/examples/rag-playground/src/components/playground/playground.ts
+++ b/examples/rag-playground/src/components/playground/playground.ts
@@ -30,6 +30,7 @@ import '../text-viewer/text-viewer';
import componentCSS from './playground.css?inline';
import EmbeddingWorkerInline from '../../workers/embedding?worker&inline';
import promptTemplatesJSON from '../../config/promptTemplates.json';
+import logoIcon from '../../images/icon-logo.svg?raw';
interface DatasetInfo {
dataURL: string;
@@ -42,6 +43,13 @@ enum Dataset {
Arxiv = 'arxiv'
}
+enum Arrow {
+ Search = 'search',
+ Input = 'input',
+ Document = 'document',
+ Output = 'output'
+}
+
const promptTemplate = promptTemplatesJSON as Record
;
const datasets: Record = {
@@ -105,6 +113,13 @@ export class MememoPlayground extends LitElement {
value: TextGenMessage | PromiseLike
) => {};
+ arrowElements: Record = {
+ [Arrow.Document]: null,
+ [Arrow.Input]: null,
+ [Arrow.Search]: null,
+ [Arrow.Output]: null
+ };
+
//==========================================================================||
// Lifecycle Methods ||
//==========================================================================||
@@ -184,6 +199,22 @@ export class MememoPlayground extends LitElement {
resizeObserver.observe(userContainer);
resizeObserver.observe(promptContainer);
resizeObserver.observe(outputContainer);
+
+ // Track the arrow elements
+ this.arrowElements = {
+ [Arrow.Document]: this.shadowRoot.querySelector(
+ '.flow.text-prompt'
+ ) as HTMLElement,
+ [Arrow.Input]: this.shadowRoot.querySelector(
+ '.flow.input-prompt'
+ ) as HTMLElement,
+ [Arrow.Search]: this.shadowRoot.querySelector(
+ '.flow.input-text'
+ ) as HTMLElement,
+ [Arrow.Output]: this.shadowRoot.querySelector(
+ '.flow.prompt-output'
+ ) as HTMLElement
+ };
}
/**
@@ -223,15 +254,10 @@ export class MememoPlayground extends LitElement {
throw Error('textViewerComponent is not initialized.');
}
- this.textViewerComponent.semanticSearch(embedding, this.topK, 0.5);
- }
+ // Loading the arrow
+ this.arrowElements[Arrow.Search]?.classList.add('running');
- /**
- * Augment the prompt using relevant documents
- * @param relevantDocuments Documents that are relevant to the user query
- */
- compilePrompt(relevantDocuments: string[]) {
- console.log(relevantDocuments);
+ this.textViewerComponent.semanticSearch(embedding, this.topK, 0.5);
}
//==========================================================================||
@@ -246,6 +272,9 @@ export class MememoPlayground extends LitElement {
// Extract embeddings for the user query
this.getEmbedding([this.userQuery]);
+
+ // Activate arrows
+ this.arrowElements[Arrow.Input]?.classList.add('activated');
}
/**
@@ -262,8 +291,10 @@ export class MememoPlayground extends LitElement {
semanticSearchFinishedHandler(e: CustomEvent) {
this.relevantDocuments = e.detail;
- // Start to run the complied prompt
- // Need to wait for the prompt component to update the prompt
+ // Activate arrows
+ this.arrowElements[Arrow.Search]?.classList.remove('running');
+ this.arrowElements[Arrow.Search]?.classList.add('activated');
+ this.arrowElements[Arrow.Document]?.classList.add('activated');
}
embeddingWorkerMessageHandler(e: MessageEvent) {
@@ -290,6 +321,12 @@ export class MememoPlayground extends LitElement {
//==========================================================================||
// Private Helpers ||
//==========================================================================||
+ _deactivateAllArrows() {
+ for (const key of Object.values(Arrow)) {
+ this.arrowElements[key]?.classList.remove('activated');
+ }
+ }
+
/**
* Run the given prompt using the preferred model
* @returns A promise of the prompt inference
@@ -297,6 +334,9 @@ export class MememoPlayground extends LitElement {
_runPrompt(curPrompt: string, temperature = 0.2) {
let runRequest: Promise;
+ // Show a loader
+ this.arrowElements[Arrow.Output]?.classList.add('running');
+
switch (this.userConfig.preferredLLM) {
case SupportedRemoteModel['gpt-3.5']: {
runRequest = textGenGpt(
@@ -378,7 +418,7 @@ export class MememoPlayground extends LitElement {
}
runRequest.then(
- message => {
+ async message => {
switch (message.command) {
case 'finishTextGen': {
// Success
@@ -389,7 +429,15 @@ export class MememoPlayground extends LitElement {
console.info(message.payload.result);
}
+ await new Promise(resolve => {
+ setTimeout(resolve, 5000);
+ });
+
this.llmOutput = message.payload.result;
+
+ // Activate arrows
+ this.arrowElements[Arrow.Output]?.classList.remove('running');
+ this.arrowElements[Arrow.Output]?.classList.add('activated');
break;
}
@@ -412,11 +460,14 @@ export class MememoPlayground extends LitElement {
) =>
this.userQueryRunClickHandler(e)}
+ @queryEdited=${() => this._deactivateAllArrows()}
>
@@ -438,11 +489,14 @@ export class MememoPlayground extends LitElement {
@runButtonClicked=${(e: CustomEvent) => {
this.promptRunClickHandler(e);
}}
+ @promptEdited=${() => this._deactivateAllArrows()}
>