Spaces:
Running
Running
add translation shot
Browse files- src/lib/components/Prompt.svelte +2 -1
- src/lib/components/SelectModel.svelte +6 -3
- src/lib/components/text-generation/Preview.svelte +2 -3
- src/lib/components/translation/Form.svelte +15 -0
- src/lib/components/translation/Response.svelte +66 -0
- src/lib/utils/models.ts +28 -0
- src/lib/utils/type.ts +1 -0
- src/routes/api/translation/+server.ts +38 -0
- src/routes/image-generation/+page.svelte +7 -2
- src/routes/text-generation/+page.svelte +5 -0
- src/routes/text-generation/translation/+page.svelte +54 -3
src/lib/components/Prompt.svelte
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
<script lang="ts">
|
2 |
export let value: string;
|
3 |
export let placeholder: string = "Ask me anything...";
|
|
|
4 |
export let onChange: (v: string) => void
|
5 |
</script>
|
6 |
|
@@ -9,7 +10,7 @@
|
|
9 |
for="prompt"
|
10 |
class="font-sans text-slate-400 font-regular text-sm"
|
11 |
>
|
12 |
-
Prompt:
|
13 |
</label>
|
14 |
<textarea
|
15 |
id="prompt"
|
|
|
1 |
<script lang="ts">
|
2 |
export let value: string;
|
3 |
export let placeholder: string = "Ask me anything...";
|
4 |
+
export let label: string | undefined = "Prompt";
|
5 |
export let onChange: (v: string) => void
|
6 |
</script>
|
7 |
|
|
|
10 |
for="prompt"
|
11 |
class="font-sans text-slate-400 font-regular text-sm"
|
12 |
>
|
13 |
+
{label ?? 'Prompt'}:
|
14 |
</label>
|
15 |
<textarea
|
16 |
id="prompt"
|
src/lib/components/SelectModel.svelte
CHANGED
@@ -39,7 +39,10 @@
|
|
39 |
height={22}
|
40 |
class="rounded-full"
|
41 |
/>
|
42 |
-
<p>{selectedModel
|
|
|
|
|
|
|
43 |
</div>
|
44 |
{:else}
|
45 |
<p class="opacity-70">Select a model</p>
|
@@ -52,7 +55,7 @@
|
|
52 |
class:opacity-0={!open}
|
53 |
>
|
54 |
<div class="bg-slate-900 border border-slate-700/80 text-white p-2 font-code rounded-lg">
|
55 |
-
{#each items as { id, logo}}
|
56 |
<button
|
57 |
class={`w-full flex items-center justify-start gap-3 p-2 cursor-pointer hover:bg-slate-800/60 rounded-lg ${selectedModel?.id === id && 'bg-slate-800/60'}`}
|
58 |
on:click={() => handleSelect(id)}
|
@@ -64,7 +67,7 @@
|
|
64 |
height={22}
|
65 |
class="rounded-full"
|
66 |
/>
|
67 |
-
<p>{id}</p>
|
68 |
</button>
|
69 |
{/each}
|
70 |
</div>
|
|
|
39 |
height={22}
|
40 |
class="rounded-full"
|
41 |
/>
|
42 |
+
<p>{selectedModel?.label ?? selectedModel?.id}</p>
|
43 |
+
{#if selectedModel?.label}
|
44 |
+
<p class="text-slate-400 text-xs">({selectedModel?.id})</p>
|
45 |
+
{/if}
|
46 |
</div>
|
47 |
{:else}
|
48 |
<p class="opacity-70">Select a model</p>
|
|
|
55 |
class:opacity-0={!open}
|
56 |
>
|
57 |
<div class="bg-slate-900 border border-slate-700/80 text-white p-2 font-code rounded-lg">
|
58 |
+
{#each items as { id, logo, label }}
|
59 |
<button
|
60 |
class={`w-full flex items-center justify-start gap-3 p-2 cursor-pointer hover:bg-slate-800/60 rounded-lg ${selectedModel?.id === id && 'bg-slate-800/60'}`}
|
61 |
on:click={() => handleSelect(id)}
|
|
|
67 |
height={22}
|
68 |
class="rounded-full"
|
69 |
/>
|
70 |
+
<p>{label ?? id}</p>
|
71 |
</button>
|
72 |
{/each}
|
73 |
</div>
|
src/lib/components/text-generation/Preview.svelte
CHANGED
@@ -6,8 +6,7 @@
|
|
6 |
</script>
|
7 |
|
8 |
<div class="text-white p-6 font-code text-xs !leading-loose">
|
9 |
-
{
|
10 |
-
{
|
11 |
-
<span>{res[0]?.generated_text?.replace(body?.inputs, "")}</span>
|
12 |
{/if}
|
13 |
</div>
|
|
|
6 |
</script>
|
7 |
|
8 |
<div class="text-white p-6 font-code text-xs !leading-loose">
|
9 |
+
{#if res?.[0]?.translation_text}
|
10 |
+
{res[0]?.translation_text}
|
|
|
11 |
{/if}
|
12 |
</div>
|
src/lib/components/translation/Form.svelte
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import Prompt from "$lib/components/Prompt.svelte";
|
3 |
+
import SelectModel from "$lib/components/SelectModel.svelte";
|
4 |
+
import { TRANSLATION_MODELS } from "$lib/utils/models";
|
5 |
+
|
6 |
+
export let form: Record<string, any>;
|
7 |
+
export let onForm: (form: Record<string, any>) => void;
|
8 |
+
</script>
|
9 |
+
|
10 |
+
<SelectModel value={form.model} items={TRANSLATION_MODELS} onChange={(model) => onForm({ ...form, model })} />
|
11 |
+
<Prompt
|
12 |
+
placeholder="Enter your text here..."
|
13 |
+
value={form.inputs}
|
14 |
+
onChange={(inputs) => onForm({ ...form, inputs })}
|
15 |
+
/>
|
src/lib/components/translation/Response.svelte
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import Icon from '@iconify/svelte';
|
3 |
+
import Highlight from "svelte-highlight";
|
4 |
+
import json from "svelte-highlight/languages/json";
|
5 |
+
import "svelte-highlight/styles/night-owl.css"
|
6 |
+
|
7 |
+
import Loading from "$lib/components/Loading.svelte"
|
8 |
+
import CodePreview from '$lib/components/CodePreview.svelte';
|
9 |
+
import Preview from '$lib/components/text-generation/Preview.svelte';
|
10 |
+
|
11 |
+
export let loading: boolean;
|
12 |
+
export let res: any;
|
13 |
+
export let form: Record<string, any>;
|
14 |
+
export let body: Record<string, any>;
|
15 |
+
export let endpoint: string;
|
16 |
+
|
17 |
+
let tab = 0
|
18 |
+
|
19 |
+
$: code = JSON.stringify(res ?? {}, null, 2)
|
20 |
+
|
21 |
+
let TABS = [
|
22 |
+
{
|
23 |
+
label: "Formatted preview",
|
24 |
+
icon: "material-symbols:preview",
|
25 |
+
},
|
26 |
+
{
|
27 |
+
label: "Code example",
|
28 |
+
icon: "carbon:code",
|
29 |
+
},
|
30 |
+
];
|
31 |
+
</script>
|
32 |
+
|
33 |
+
<div class="lg:h-screen flex flex-col relative">
|
34 |
+
<div class="w-full jsonResponse relative">
|
35 |
+
<div class="bg-slate-950 w-full uppercase px-5 py-4 text-zinc-400 text-sm font-semibold border-b border-slate-900 flex items-center justify-start gap-2">
|
36 |
+
<Icon icon="carbon:json" class="w-5 h-5" />
|
37 |
+
Response
|
38 |
+
</div>
|
39 |
+
<Highlight language={json} {code}>
|
40 |
+
</Highlight>
|
41 |
+
{#if loading}
|
42 |
+
<Loading>
|
43 |
+
<p class="text-slate-400 text-lg mt-4">Processing...</p>
|
44 |
+
</Loading>
|
45 |
+
{/if}
|
46 |
+
</div>
|
47 |
+
<div class="bg-slate-950 overflow-auto flex-1">
|
48 |
+
<div class="w-full uppercase text-zinc-400 text-sm font-semibold border-t border-slate-900 flex items-start sticky top-0 bg-slate-950">
|
49 |
+
{#each TABS as { label, icon }, idx }
|
50 |
+
<button
|
51 |
+
class={`flex items-center justify-start gap-2 px-5 border-r py-4 border-slate-900 bg-slate-900/40 cursor-pointer hover:bg-slate-900/60 transition-all duration-200 ${tab === idx ? '!bg-slate-950 hover:bg-slate-900/40' : 'border-b'}`}
|
52 |
+
on:click={() => tab = idx}
|
53 |
+
>
|
54 |
+
<Icon icon={icon} class="w-5 h-5" />
|
55 |
+
{label}
|
56 |
+
</button>
|
57 |
+
{/each}
|
58 |
+
<div class="flex flex-1 w-full pointer-events-none text-slate-950 border-b border-slate-900 h-[53px] bg-slate-900/40"></div>
|
59 |
+
</div>
|
60 |
+
{#if tab === 0}
|
61 |
+
<Preview body={body} res={res} />
|
62 |
+
{:else if tab === 1}
|
63 |
+
<CodePreview body={form} endpoint={endpoint} />
|
64 |
+
{/if}
|
65 |
+
</div>
|
66 |
+
</div>
|
src/lib/utils/models.ts
CHANGED
@@ -20,4 +20,32 @@ export const IMAGE_GENERATIONS: Array<Model> = [
|
|
20 |
id: "stabilityai/stable-diffusion-xl-base-1.0",
|
21 |
logo: "https://aeiljuispo.cloudimg.io/v7/https://cdn-uploads.huggingface.co/production/uploads/643feeb67bc3fbde1385cc25/7vmYr2XwVcPtkLzac_jxQ.png?w=200&h=200&f=face"
|
22 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
]
|
|
|
20 |
id: "stabilityai/stable-diffusion-xl-base-1.0",
|
21 |
logo: "https://aeiljuispo.cloudimg.io/v7/https://cdn-uploads.huggingface.co/production/uploads/643feeb67bc3fbde1385cc25/7vmYr2XwVcPtkLzac_jxQ.png?w=200&h=200&f=face"
|
22 |
},
|
23 |
+
]
|
24 |
+
|
25 |
+
export const TRANSLATION_MODELS: Array<Model> = [
|
26 |
+
{
|
27 |
+
id: "Helsinki-NLP/opus-mt-fr-en",
|
28 |
+
label: "French to English",
|
29 |
+
logo: "https://aeiljuispo.cloudimg.io/v7/https://cdn-uploads.huggingface.co/production/uploads/1588345309691-5dd96eb166059660ed1ee413.png?w=200&h=200&f=face",
|
30 |
+
}, {
|
31 |
+
id: "Helsinki-NLP/opus-mt-en-fr",
|
32 |
+
label: "English to French",
|
33 |
+
logo: "https://aeiljuispo.cloudimg.io/v7/https://cdn-uploads.huggingface.co/production/uploads/1588345309691-5dd96eb166059660ed1ee413.png?w=200&h=200&f=face",
|
34 |
+
}, {
|
35 |
+
id: "Helsinki-NLP/opus-mt-de-en",
|
36 |
+
label: "German to English",
|
37 |
+
logo: "https://aeiljuispo.cloudimg.io/v7/https://cdn-uploads.huggingface.co/production/uploads/1588345309691-5dd96eb166059660ed1ee413.png?w=200&h=200&f=face",
|
38 |
+
}, {
|
39 |
+
id: "Helsinki-NLP/opus-mt-en-de",
|
40 |
+
label: "English to German",
|
41 |
+
logo: "https://aeiljuispo.cloudimg.io/v7/https://cdn-uploads.huggingface.co/production/uploads/1588345309691-5dd96eb166059660ed1ee413.png?w=200&h=200&f=face",
|
42 |
+
}, {
|
43 |
+
id: "Helsinki-NLP/opus-mt-es-en",
|
44 |
+
label: "Spanish to English",
|
45 |
+
logo: "https://aeiljuispo.cloudimg.io/v7/https://cdn-uploads.huggingface.co/production/uploads/1588345309691-5dd96eb166059660ed1ee413.png?w=200&h=200&f=face",
|
46 |
+
}, {
|
47 |
+
id: "Helsinki-NLP/opus-mt-en-es",
|
48 |
+
label: "English to Spanish",
|
49 |
+
logo: "https://aeiljuispo.cloudimg.io/v7/https://cdn-uploads.huggingface.co/production/uploads/1588345309691-5dd96eb166059660ed1ee413.png?w=200&h=200&f=face",
|
50 |
+
}
|
51 |
]
|
src/lib/utils/type.ts
CHANGED
@@ -1,4 +1,5 @@
|
|
1 |
export interface Model {
|
2 |
id: string;
|
3 |
logo: string;
|
|
|
4 |
}
|
|
|
1 |
export interface Model {
|
2 |
id: string;
|
3 |
logo: string;
|
4 |
+
label?: string;
|
5 |
}
|
src/routes/api/translation/+server.ts
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { error, json, type RequestEvent } from '@sveltejs/kit';
|
2 |
+
import { env } from '$env/dynamic/private'
|
3 |
+
|
4 |
+
/** @type {import('./$types').RequestHandler} */
|
5 |
+
export async function POST({ request }: RequestEvent) {
|
6 |
+
const body = await request?.json().catch(() => {});
|
7 |
+
|
8 |
+
if (!body?.model) {
|
9 |
+
throw error(400, 'missing model value')
|
10 |
+
}
|
11 |
+
|
12 |
+
if (!body?.inputs || body.inputs === null) {
|
13 |
+
throw error(400, 'missing inputs value')
|
14 |
+
}
|
15 |
+
|
16 |
+
const response = await fetch(env.SECRET_INFERENCE_API_URL + "/models/" + body.model, {
|
17 |
+
method: "POST",
|
18 |
+
headers: {
|
19 |
+
Authorization: `Bearer ${env.SECRET_HF_TOKEN}`,
|
20 |
+
'Content-Type': 'application/json',
|
21 |
+
['x-use-cache']: "0"
|
22 |
+
},
|
23 |
+
body: JSON.stringify(body),
|
24 |
+
})
|
25 |
+
.then((res) => res.json())
|
26 |
+
.then((res) => res)
|
27 |
+
.catch((error) => {
|
28 |
+
return {
|
29 |
+
error: error.message,
|
30 |
+
}
|
31 |
+
})
|
32 |
+
|
33 |
+
if ("error" in response) {
|
34 |
+
error(400, response.error as string)
|
35 |
+
}
|
36 |
+
|
37 |
+
return json(response)
|
38 |
+
}
|
src/routes/image-generation/+page.svelte
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
<script lang="ts">
|
2 |
import Form from "$lib/components/image-generation/Form.svelte";
|
3 |
import Response from "$lib/components/image-generation/Response.svelte";
|
|
|
4 |
|
5 |
let loading: boolean = false;
|
6 |
let data: string | ArrayBuffer | null = ''
|
@@ -21,6 +22,7 @@
|
|
21 |
const onchange = (newForm: Record<string, any>) => form = newForm
|
22 |
|
23 |
const onsubmit = async () => {
|
|
|
24 |
loading = true
|
25 |
const request = await fetch('/api/image-generation', {
|
26 |
method: 'POST',
|
@@ -46,12 +48,15 @@
|
|
46 |
<main class="min-h-screen w-full grid grid-cols-2">
|
47 |
<div class="p-6 lg:p-10 w-full flex flex-col gap-6 lg:overflow-auto lg:h-screen">
|
48 |
<Form form={form} onForm={onchange} />
|
49 |
-
<div>
|
50 |
<button
|
51 |
-
class="bg-gradient-to-r from-slate-900/50 to-slate-900 border border-slate-800/40 text-white rounded-lg text-base transition-all duration-200 leading-relaxed outline-none relative py-3 px-6"
|
52 |
disabled={loading}
|
53 |
on:click={onsubmit}
|
54 |
>
|
|
|
|
|
|
|
55 |
Submit
|
56 |
</button>
|
57 |
</div>
|
|
|
1 |
<script lang="ts">
|
2 |
import Form from "$lib/components/image-generation/Form.svelte";
|
3 |
import Response from "$lib/components/image-generation/Response.svelte";
|
4 |
+
import Loading from "$lib/components/Loading.svelte";
|
5 |
|
6 |
let loading: boolean = false;
|
7 |
let data: string | ArrayBuffer | null = ''
|
|
|
22 |
const onchange = (newForm: Record<string, any>) => form = newForm
|
23 |
|
24 |
const onsubmit = async () => {
|
25 |
+
if (loading) return
|
26 |
loading = true
|
27 |
const request = await fetch('/api/image-generation', {
|
28 |
method: 'POST',
|
|
|
48 |
<main class="min-h-screen w-full grid grid-cols-2">
|
49 |
<div class="p-6 lg:p-10 w-full flex flex-col gap-6 lg:overflow-auto lg:h-screen">
|
50 |
<Form form={form} onForm={onchange} />
|
51 |
+
<div class="flex justify-end">
|
52 |
<button
|
53 |
+
class="w-full bg-gradient-to-r from-slate-900/50 to-slate-900 border border-slate-800/40 text-white rounded-lg text-base transition-all duration-200 leading-relaxed outline-none relative py-3 px-6"
|
54 |
disabled={loading}
|
55 |
on:click={onsubmit}
|
56 |
>
|
57 |
+
{#if loading}
|
58 |
+
<Loading />
|
59 |
+
{/if}
|
60 |
Submit
|
61 |
</button>
|
62 |
</div>
|
src/routes/text-generation/+page.svelte
CHANGED
@@ -1,4 +1,5 @@
|
|
1 |
<script lang="ts">
|
|
|
2 |
import Form from "$lib/components/text-generation/Form.svelte";
|
3 |
import Response from "$lib/components/text-generation/Response.svelte";
|
4 |
|
@@ -22,6 +23,7 @@
|
|
22 |
const onchange = (newForm: Record<string, any>) => form = newForm
|
23 |
|
24 |
const onsubmit = async () => {
|
|
|
25 |
loading = true
|
26 |
const request = await fetch('/api/text-generation', {
|
27 |
method: 'POST',
|
@@ -46,6 +48,9 @@
|
|
46 |
disabled={loading}
|
47 |
on:click={onsubmit}
|
48 |
>
|
|
|
|
|
|
|
49 |
Submit
|
50 |
</button>
|
51 |
</div>
|
|
|
1 |
<script lang="ts">
|
2 |
+
import Loading from "$lib/components/Loading.svelte";
|
3 |
import Form from "$lib/components/text-generation/Form.svelte";
|
4 |
import Response from "$lib/components/text-generation/Response.svelte";
|
5 |
|
|
|
23 |
const onchange = (newForm: Record<string, any>) => form = newForm
|
24 |
|
25 |
const onsubmit = async () => {
|
26 |
+
if (loading) return
|
27 |
loading = true
|
28 |
const request = await fetch('/api/text-generation', {
|
29 |
method: 'POST',
|
|
|
48 |
disabled={loading}
|
49 |
on:click={onsubmit}
|
50 |
>
|
51 |
+
{#if loading}
|
52 |
+
<Loading />
|
53 |
+
{/if}
|
54 |
Submit
|
55 |
</button>
|
56 |
</div>
|
src/routes/text-generation/translation/+page.svelte
CHANGED
@@ -1,3 +1,54 @@
|
|
1 |
-
<
|
2 |
-
|
3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import Response from "$lib/components/translation/Response.svelte";
|
3 |
+
import Loading from "$lib/components/Loading.svelte";
|
4 |
+
import Form from "$lib/components/translation/Form.svelte";
|
5 |
+
|
6 |
+
let loading: boolean = false;
|
7 |
+
let data: Record<string, any> = {}
|
8 |
+
let bodyRequest: Record<string, any> = {}
|
9 |
+
|
10 |
+
let form: Record<string, any> = {
|
11 |
+
model: "Helsinki-NLP/opus-mt-fr-en",
|
12 |
+
inputs: null,
|
13 |
+
}
|
14 |
+
|
15 |
+
const onchange = (newForm: Record<string, any>) => form = newForm
|
16 |
+
|
17 |
+
const onsubmit = async () => {
|
18 |
+
if (loading) return
|
19 |
+
loading = true
|
20 |
+
const request = await fetch('/api/text-generation', {
|
21 |
+
method: 'POST',
|
22 |
+
body: JSON.stringify(form),
|
23 |
+
headers: {
|
24 |
+
"Content-Type": "application/json"
|
25 |
+
}
|
26 |
+
})
|
27 |
+
const response = await request.clone().json().catch(() => ({}))
|
28 |
+
console.log(response)
|
29 |
+
data = response
|
30 |
+
bodyRequest = form
|
31 |
+
loading = false
|
32 |
+
}
|
33 |
+
</script>
|
34 |
+
|
35 |
+
<main class="min-h-screen w-full grid grid-cols-1 lg:grid-cols-2">
|
36 |
+
<div class="p-6 lg:p-10 w-full flex flex-col gap-6 lg:overflow-auto lg:h-screen">
|
37 |
+
<Form form={form} onForm={onchange} />
|
38 |
+
<div class="flex justify-end">
|
39 |
+
<button
|
40 |
+
class="w-full bg-gradient-to-r from-slate-900/50 to-slate-900 border border-slate-800/40 text-white rounded-lg text-base transition-all duration-200 leading-relaxed outline-none relative py-3 px-6"
|
41 |
+
disabled={loading}
|
42 |
+
on:click={onsubmit}
|
43 |
+
>
|
44 |
+
{#if loading}
|
45 |
+
<Loading />
|
46 |
+
{/if}
|
47 |
+
Translate
|
48 |
+
</button>
|
49 |
+
</div>
|
50 |
+
</div>
|
51 |
+
<div class="border-t lg:border-t-0 lg:border-l border-slate-900 bg-slate-950">
|
52 |
+
<Response loading={loading} res={data} body={bodyRequest} form={form} endpoint={form.model} />
|
53 |
+
</div>
|
54 |
+
</main>
|