Skip to content

Commit c5e5189

Browse files
UI sync with current codeGen backend (opea-project#2252)
Signed-off-by: WenjiaoYue <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent b611e10 commit c5e5189

File tree

5 files changed

+407
-100
lines changed

5 files changed

+407
-100
lines changed

CodeGen/docker_compose/intel/cpu/xeon/compose.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ services:
6666
ipc: host
6767
restart: always
6868
codegen-xeon-ui-server:
69-
image: ${REGISTRY:-opea}/codegen-gradio-ui:${TAG:-latest}
69+
image: ${REGISTRY:-opea}/codegen-ui:${TAG:-latest}
7070
container_name: codegen-xeon-ui-server
7171
depends_on:
7272
- codegen-xeon-backend-server

CodeGen/docker_compose/intel/cpu/xeon/compose_tgi.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ services:
6666
ipc: host
6767
restart: always
6868
codegen-xeon-ui-server:
69-
image: ${REGISTRY:-opea}/codegen-gradio-ui:${TAG:-latest}
69+
image: ${REGISTRY:-opea}/codegen-ui:${TAG:-latest}
7070
container_name: codegen-xeon-ui-server
7171
depends_on:
7272
- codegen-xeon-backend-server

CodeGen/tests/test_compose_on_xeon.sh

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ function build_docker_images() {
2727
popd && sleep 1s
2828

2929
echo "Build all the images with --no-cache, check docker_image_build.log for details..."
30-
service_list="codegen codegen-gradio-ui llm-textgen dataprep retriever embedding"
30+
service_list="codegen codegen-ui llm-textgen dataprep retriever embedding"
3131

3232
docker compose -f build.yaml build ${service_list} --no-cache > ${LOG_PATH}/docker_image_build.log
3333

@@ -174,6 +174,8 @@ function validate_frontend() {
174174
npm install && npm ci && npx playwright install --with-deps
175175
node -v && npm -v && pip list
176176

177+
export no_proxy="localhost,127.0.0.1,$ip_address"
178+
177179
exit_status=0
178180
npx playwright test || exit_status=$?
179181

@@ -244,8 +246,12 @@ function main() {
244246
validate_megaservice
245247
echo "::endgroup::"
246248

247-
echo "::group::validate_gradio"
248-
validate_gradio
249+
# echo "::group::validate_gradio"
250+
# validate_gradio
251+
# echo "::endgroup::"
252+
253+
echo "::group::validate_ui"
254+
validate_frontend
249255
echo "::endgroup::"
250256

251257
stop_docker "${docker_compose_files[${i}]}"

CodeGen/ui/svelte/src/lib/modules/chat/Output.svelte

Lines changed: 185 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,24 @@
3737
import bash from "svelte-highlight/languages/bash";
3838
import sql from "svelte-highlight/languages/sql";
3939
import { marked } from "marked";
40-
export let label = "";
40+
import { afterUpdate, onMount } from "svelte";
41+
4142
export let output = "";
42-
export let languages = "Python";
43+
export let lang = "Python";
4344
export let isCode = false;
45+
export let md_output = "";
46+
export let segments: Segment[] = [];
4447
48+
let outputEl: HTMLDivElement;
4549
let copyText = "copy";
50+
let shouldAutoscroll = true;
51+
52+
type Segment = {
53+
id: number;
54+
type: "text" | "code";
55+
content: string;
56+
lang?: string;
57+
};
4658
4759
const languagesTag = {
4860
Typescript: typescript,
@@ -65,53 +77,194 @@
6577
Lua: lua,
6678
Bash: bash,
6779
Sql: sql,
68-
} as { [key: string]: any };
69-
70-
function copyToClipboard(text) {
71-
const textArea = document.createElement("textarea");
72-
textArea.value = text;
73-
document.body.appendChild(textArea);
74-
textArea.select();
75-
document.execCommand("copy");
76-
document.body.removeChild(textArea);
80+
} as const;
81+
82+
type LangKey = keyof typeof languagesTag;
83+
84+
const aliasMap: Record<string, LangKey> = {
85+
javascript: "Javascript",
86+
js: "Javascript",
87+
jsx: "Javascript",
88+
typescript: "Typescript",
89+
ts: "Typescript",
90+
tsx: "Typescript",
91+
92+
python: "Python",
93+
py: "Python",
94+
95+
c: "C",
96+
"c++": "Cpp",
97+
cpp: "Cpp",
98+
cxx: "Cpp",
99+
csharp: "Csharp",
100+
"c#": "Csharp",
101+
102+
go: "Go",
103+
golang: "Go",
104+
java: "Java",
105+
swift: "Swift",
106+
ruby: "Ruby",
107+
rust: "Rust",
108+
php: "Php",
109+
kotlin: "Kotlin",
110+
objectivec: "Objectivec",
111+
objc: "Objectivec",
112+
"objective-c": "Objectivec",
113+
perl: "Perl",
114+
matlab: "Matlab",
115+
r: "R",
116+
lua: "Lua",
117+
118+
bash: "Bash",
119+
sh: "Bash",
120+
shell: "Bash",
121+
zsh: "Bash",
122+
123+
sql: "Sql",
124+
};
125+
126+
$: normalizedLangKey = (() => {
127+
const raw = (lang ?? "").toString().trim();
128+
if (!raw) return null;
129+
const lower = raw.toLowerCase();
130+
131+
if (lower in aliasMap) return aliasMap[lower];
132+
133+
const hit = (Object.keys(languagesTag) as LangKey[]).find(
134+
(k) => k.toLowerCase() === lower
135+
);
136+
return hit ?? null;
137+
})();
138+
139+
$: fullText = buildFullText();
140+
141+
function atBottom(el: HTMLElement, threshold = 8) {
142+
return el.scrollHeight - el.scrollTop - el.clientHeight <= threshold;
143+
}
144+
145+
function handleScroll() {
146+
if (!outputEl) return;
147+
shouldAutoscroll = atBottom(outputEl);
77148
}
78149
79-
function handelCopy() {
80-
copyToClipboard(output);
150+
function scrollToBottom() {
151+
if (!outputEl) return;
152+
requestAnimationFrame(() =>
153+
requestAnimationFrame(() => {
154+
if (outputEl.scrollHeight) {
155+
outputEl.scrollTop = outputEl.scrollHeight;
156+
}
157+
})
158+
);
159+
}
160+
161+
onMount(() => {
162+
scrollToBottom();
163+
});
164+
165+
afterUpdate(() => {
166+
if (shouldAutoscroll) scrollToBottom();
167+
});
168+
async function copyAllFromDiv() {
169+
await navigator.clipboard.writeText(outputEl.innerText);
81170
copyText = "copied!";
82-
setTimeout(() => {
83-
copyText = "copy";
84-
}, 1000);
171+
setTimeout(() => (copyText = "copy"), 1000);
172+
}
173+
174+
function copyToClipboard(text: string) {
175+
if (navigator?.clipboard?.writeText) {
176+
navigator.clipboard.writeText(text);
177+
} else {
178+
const textArea = document.createElement("textarea");
179+
textArea.value = text;
180+
document.body.appendChild(textArea);
181+
textArea.select();
182+
document.execCommand("copy");
183+
document.body.removeChild(textArea);
184+
}
185+
}
186+
187+
function normalizeToKey(raw?: string | null) {
188+
const s = (raw ?? "").trim().toLowerCase();
189+
if (!s) return null;
190+
if (s in aliasMap) return aliasMap[s as keyof typeof aliasMap];
191+
const hit = (
192+
Object.keys(languagesTag) as (keyof typeof languagesTag)[]
193+
).find((k) => k.toLowerCase() === s);
194+
return hit ?? null;
195+
}
196+
197+
function buildFullText(): string {
198+
if (segments && segments.length > 0) {
199+
return segments
200+
.map((seg) => {
201+
if (seg.type === "code") {
202+
const key = normalizeToKey(seg.lang) ?? "text";
203+
return ["```" + key.toLowerCase(), seg.content, "```"].join("\n");
204+
}
205+
return seg.content;
206+
})
207+
.join("\n\n");
208+
}
209+
210+
const parts: string[] = [];
211+
if (isCode && output) {
212+
const key = (normalizedLangKey ?? "text").toLowerCase();
213+
parts.push(["```" + key, output, "```"].join("\n"));
214+
}
215+
if (md_output) {
216+
parts.push(md_output);
217+
}
218+
return parts.join("\n\n");
85219
}
86220
</script>
87221

88222
<div class="flex w-full flex-col" data-testid="code-output">
89-
<span
90-
class=" mb-2 flex h-[3rem] w-full items-center justify-center bg-[#5856D6] px-8 py-2 text-center text-[0.89rem] uppercase leading-tight opacity-80"
91-
>{label}</span
92-
>
93-
94223
<div
95224
class="flex justify-end border-2 border-none border-b-gray-800 bg-[#1C1C1C] px-3 text-white"
96225
>
97226
<button
98227
class="rounded border border-none py-1 text-[0.8rem] text-[#abb2bf]"
99-
on:click={() => {
100-
handelCopy();
101-
}}>{copyText}</button
228+
on:click={copyAllFromDiv}>{copyText}</button
102229
>
103230
</div>
231+
104232
<div
105-
class="code-format-style hiddenScroll h-[22rem] divide-y overflow-auto bg-[#011627]"
233+
class="
234+
hiddenScroll h-[22rem] overflow-auto
235+
bg-[#011627] p-5 text-[13px]
236+
leading-5
237+
"
238+
bind:this={outputEl}
239+
on:scroll={handleScroll}
106240
>
107-
{#if isCode}
108-
<Highlight language={python} code={output} let:highlighted>
109-
<LineNumbers {highlighted} wrapLines hideBorder />
110-
</Highlight>
241+
{#if segments && segments.length > 0}
242+
{#each segments as seg (seg.id)}
243+
{#if seg.type === "code"}
244+
<div class="relative border-t border-[#0c2233]">
245+
<Highlight
246+
language={languagesTag[normalizeToKey(seg.lang) ?? "Python"]}
247+
code={seg.content}
248+
let:highlighted
249+
>
250+
<LineNumbers {highlighted} wrapLines hideBorder />
251+
</Highlight>
252+
</div>
253+
{:else}
254+
<div>{@html marked(seg.content)}</div>
255+
{/if}
256+
{/each}
111257
{:else}
112-
<div class="bg-[#282c34] text-[#abb2bf]">
113-
{@html marked(output)}
114-
</div>
258+
{#if isCode && output}
259+
<Highlight language={python} code={output} let:highlighted>
260+
<LineNumbers {highlighted} wrapLines hideBorder />
261+
</Highlight>
262+
{/if}
263+
{#if md_output}
264+
<div class="bg-[#282c34] py-2 text-[#abb2bf]">
265+
{@html marked(md_output)}
266+
</div>
267+
{/if}
115268
{/if}
116269
</div>
117270
</div>
@@ -120,17 +273,8 @@
120273
.hiddenScroll::-webkit-scrollbar {
121274
display: none;
122275
}
123-
124276
.hiddenScroll {
125277
-ms-overflow-style: none; /* IE and Edge */
126278
scrollbar-width: none; /* Firefox */
127279
}
128-
129-
.code-format-style {
130-
resize: none;
131-
font-size: 16px;
132-
border: solid rgba(128, 0, 128, 0) 4px;
133-
box-shadow: 0 0 8px rgba(0, 0, 0, 0.19);
134-
transition: 0.1s linear;
135-
}
136280
</style>

0 commit comments

Comments
 (0)