basic llm request stream
This commit is contained in:
1 parent
f74e4d1043
commit
a92cc76a9a
66 files changed
+1496
-158
No files matched your search
Generated
+165
@@ -8,6 +8,7 @@
|
||||
"name": "web",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"@humanspeak/svelte-markdown": "^1.9.2",
|
||||
"oidc-client-ts": "^3.5.0",
|
||||
"svelte-select": "^6.0.0"
|
||||
},
|
||||
@@ -262,6 +263,51 @@
|
||||
"node": ">=18.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanspeak/memory-cache": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@humanspeak/memory-cache/-/memory-cache-1.2.0.tgz",
|
||||
"integrity": "sha512-im7GIIpgjdD6Fx68xCeiXw3XiDv30/WMRAaodMm+ep0ptYfEUd0cdNeTAylHGIRTJIeByKFHdTmPjAktyDM/JQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanspeak/svelte-markdown": {
|
||||
"version": "1.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@humanspeak/svelte-markdown/-/svelte-markdown-1.9.2.tgz",
|
||||
"integrity": "sha512-sczMB4oNSpADBWT6l9AkIErpJDDzGsamzl2/w3J5yAYBWWofLcmVDCti5KY5l0+Cec2p9xyb73qkkukoNmLPWQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@humanspeak/memory-cache": "^1.1.2",
|
||||
"github-slugger": "^2.0.0",
|
||||
"htmlparser2": "^12.0.0",
|
||||
"marked": "^18.0.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/humanspeak"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"katex": ">=0.16.0",
|
||||
"mermaid": ">=10.0.0",
|
||||
"shiki": ">=4.0.0",
|
||||
"svelte": "^5.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"katex": {
|
||||
"optional": true
|
||||
},
|
||||
"mermaid": {
|
||||
"optional": true
|
||||
},
|
||||
"shiki": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/module-importer": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
|
||||
@@ -1722,6 +1768,73 @@
|
||||
"integrity": "sha512-RWrqdArjvPbsATEhOPUo6Wndc/iWnkWKlhIrdlF3zMMYo/c3CVtoaVAyLtWxz5h8nSlkHzxnzV2uLydPXmtF+A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/dom-serializer": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-3.1.1.tgz",
|
||||
"integrity": "sha512-4MEa38/QexBob6gFNwu+EGdWvhJ1OKuNwdYY3Y3NyeWDQfnGeDYQUDfIRzWu5B5gsv03so2Uxd28YC6zrsx3Lw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"domelementtype": "^3.0.0",
|
||||
"domhandler": "^6.0.0",
|
||||
"entities": "^8.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.19.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/domelementtype": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-3.0.0.tgz",
|
||||
"integrity": "sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
],
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=20.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/domhandler": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-6.0.1.tgz",
|
||||
"integrity": "sha512-gYzvtM72ZtxQO0T048kd6HWSbbGCNOUwcnfQ01cqIJ4X2IYKFFHZ5mKvrQETcFXxsRObZulDaKmy//R7TPtsBg==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"domelementtype": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.19.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/domutils": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-4.0.2.tgz",
|
||||
"integrity": "sha512-qI4JLRKnSzqFqr7hAlS5xQDusBCjKSEG4t4+7aNrIQMHBcsC2TGEhuyABJdYkgSewL57PNLYEiibY2iPKhKpaA==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"dom-serializer": "^3.0.0",
|
||||
"domelementtype": "^3.0.0",
|
||||
"domhandler": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.19.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.24.5",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz",
|
||||
@@ -1736,6 +1849,18 @@
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-8.1.0.tgz",
|
||||
"integrity": "sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=20.19.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
@@ -2095,6 +2220,12 @@
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/github-slugger": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz",
|
||||
"integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/glob-parent": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||
@@ -2128,6 +2259,28 @@
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/htmlparser2": {
|
||||
"version": "12.0.0",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-12.0.0.tgz",
|
||||
"integrity": "sha512-Tz7u1i95/g2x2jz81+x0FBVhBhY5aRTvD3tXXdFaljuNdzDLJ8UGNRrTcj2cgQvAg3iW/h77Fz15nLW0L0CrZw==",
|
||||
"funding": [
|
||||
"https://github.com/fb55/htmlparser2?sponsor=1",
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"domelementtype": "^3.0.0",
|
||||
"domhandler": "^6.0.0",
|
||||
"domutils": "^4.0.2",
|
||||
"entities": "^8.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||
@@ -2632,6 +2785,18 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.5.5"
|
||||
}
|
||||
},
|
||||
"node_modules/marked": {
|
||||
"version": "18.0.14",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-18.0.14.tgz",
|
||||
"integrity": "sha512-mBHK6FBHuBAlhgRe88w9F0O1AbwwXJUcQibUbC/QcdTbVGAD7aWza+xt3N6oT/jCZx3/OMeS+8rnuiHZcQ9s7A==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"marked": "bin/marked.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"node_modules/mini-svg-data-uri": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz",
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
"esbuild": "^0.25.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@humanspeak/svelte-markdown": "^1.9.2",
|
||||
"oidc-client-ts": "^3.5.0",
|
||||
"svelte-select": "^6.0.0"
|
||||
}
|
||||
|
||||
@@ -48,15 +48,77 @@ async function request<T>(path: string, options: RequestOptions = {}): Promise<T
|
||||
return res.json();
|
||||
}
|
||||
|
||||
async function* requestStream<T = unknown>(
|
||||
path: string,
|
||||
options: RequestOptions = {}
|
||||
): AsyncGenerator<T, void, undefined> {
|
||||
const { auth = true, headers, ...rest } = options;
|
||||
|
||||
const requestHeaders: HeadersInit = {
|
||||
'Content-Type': 'application/json',
|
||||
...headers,
|
||||
};
|
||||
const fetchHeaders = new Headers(requestHeaders)
|
||||
|
||||
if (auth) {
|
||||
const token = getToken()
|
||||
if (token) {
|
||||
fetchHeaders.append('Authorization', `Bearer ${token}`)
|
||||
}
|
||||
}
|
||||
|
||||
const res = await fetch(`${BASE_URL}${path}`, {
|
||||
...rest,
|
||||
headers: fetchHeaders,
|
||||
});
|
||||
|
||||
if (res.status === 401 ) {
|
||||
logout()
|
||||
goto("/login")
|
||||
//throw new ApiError(401, await safeJson(res));
|
||||
}
|
||||
|
||||
if (!res.ok || !res.body) throw new Error(`HTTP ${res.status}`);
|
||||
|
||||
const reader = res.body!.pipeThrough(new TextDecoderStream()).getReader();
|
||||
let buffer = '';
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
const { value, done } = await reader.read();
|
||||
if (done) break;
|
||||
|
||||
buffer += value;
|
||||
const lines = buffer.split('\n');
|
||||
buffer = lines.pop() ?? ''; // dernière ligne potentiellement incomplète
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.trim()) yield JSON.parse(line) as T;
|
||||
}
|
||||
}
|
||||
if (buffer.trim()) yield JSON.parse(buffer) as T; // reste éventuel
|
||||
} finally {
|
||||
reader.releaseLock();
|
||||
}
|
||||
|
||||
return //res.json();
|
||||
}
|
||||
|
||||
async function safeJson(res: Response) {
|
||||
try { return await res.json(); } catch { return null; }
|
||||
}
|
||||
|
||||
export const api = {
|
||||
get: <T>(path: string, opts?: RequestOptions) => request<T>(path, { ...opts, method: 'GET' }),
|
||||
|
||||
post: <T>(path: string, body?: unknown, opts?: RequestOptions) =>
|
||||
request<T>(path, { ...opts, method: 'POST', body: JSON.stringify(body) }),
|
||||
|
||||
postStream: <T>(path: string, body?: unknown, opts?: RequestOptions) =>
|
||||
requestStream<T>(path, {...opts, method: 'POST', body: JSON.stringify(body) }),
|
||||
|
||||
put: <T>(path: string, body?: unknown, opts?: RequestOptions) =>
|
||||
request<T>(path, { ...opts, method: 'PUT', body: JSON.stringify(body) }),
|
||||
|
||||
delete: <T>(path: string, opts?: RequestOptions) => request<T>(path, { ...opts, method: 'DELETE' }),
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
import { api } from '../client';
|
||||
import type { Chat, Chunk, ChatRequest, ChatWithMessages } from "$lib/types/api"
|
||||
|
||||
export const chatApi = {
|
||||
createChat: (space: string, data: Partial<ChatRequest>) => api.post<Chat>(`/chat/${space}`, data),
|
||||
createChatMessage: (space: string, id: string, data: Partial<ChatRequest>) => api.postStream<Chunk>(`/chat/${space}/${id}`, data),
|
||||
allChats: (space: string, pageNum: number) => api.get<Chat[]>(`/chat/${space}/all/${pageNum}`),
|
||||
getChat: (space: string, id: string) => api.get<ChatWithMessages>(`/chat/${space}/${id}`),
|
||||
subscribe: (space: string, id: string) => api.get<ChatWithMessages>(`/chat/${space}/${id}/subscribe`),
|
||||
deleteChat: (space: string, id: string) => api.delete(`/chat/${space}/${id}`),
|
||||
};
|
||||
@@ -5,8 +5,10 @@
|
||||
|
||||
const closeDrawer = (e: Event) => {
|
||||
e.preventDefault()
|
||||
uiState.sidebarMobileOpen=false
|
||||
uiState.menuContentVisible=false
|
||||
if (uiState.sidebarMobileOpen) {
|
||||
uiState.sidebarMobileOpen=false
|
||||
uiState.menuContentVisible=false
|
||||
}
|
||||
goto(link)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -78,6 +78,49 @@ export interface Agent {
|
||||
_version: string
|
||||
}
|
||||
|
||||
export type Chat = {
|
||||
id: string
|
||||
teamId: string
|
||||
startDatetime: string
|
||||
endDatetime: string
|
||||
agentId: string
|
||||
userId: string
|
||||
taskId: string
|
||||
title: string
|
||||
_date_created: string
|
||||
_date_updated: string
|
||||
_version: string
|
||||
}
|
||||
|
||||
export type Message = {
|
||||
id: string
|
||||
role: string
|
||||
content: string
|
||||
toolCallId: string
|
||||
toolCalls: Array<string>
|
||||
_date_created: string
|
||||
_date_updated: string
|
||||
_version: string
|
||||
}
|
||||
|
||||
export type ChatWithMessages = {
|
||||
chat: Chat
|
||||
messages: Message[]
|
||||
}
|
||||
|
||||
export type Chunk = {
|
||||
done: boolean
|
||||
role: string
|
||||
content: string
|
||||
}
|
||||
|
||||
export type ChatRequest = {
|
||||
agentId: string
|
||||
providerId: string
|
||||
modelId: string
|
||||
prompt: string
|
||||
}
|
||||
|
||||
|
||||
export enum SaveState {
|
||||
None,
|
||||
@@ -86,3 +129,10 @@ export enum SaveState {
|
||||
Saved,
|
||||
Error,
|
||||
}
|
||||
|
||||
|
||||
export type PageRequest = {
|
||||
pageNum: number
|
||||
pageSize: number
|
||||
filters: Map<string, string>
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export const autofocus = (node: HTMLElement) => {
|
||||
node.focus();
|
||||
}
|
||||
@@ -1,8 +1,35 @@
|
||||
<div class="container">
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur?
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur?
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur?
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur?
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur?
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Asperiores, reiciendis quo. Quos animi nisi modi cumque hic illo doloremque totam! Distinctio molestias sint magnam illum nostrum eos, fugit aliquid consequuntur?
|
||||
<script lang="ts">
|
||||
import {autofocus} from "$lib/ui/autofocus"
|
||||
import {chatApi} from "$lib/api/endpoints/chat"
|
||||
import type {Chat} from "$lib/types/api"
|
||||
import type { PageProps } from './$types';
|
||||
import { goto } from "$app/navigation";
|
||||
|
||||
let { data }: PageProps = $props();
|
||||
let chat = $state({} as Chat)
|
||||
let prompt = $state("")
|
||||
|
||||
const handleOnSubmit = async () => {
|
||||
chatApi.createChat(data.spaceId, chat)
|
||||
.then((result)=>{
|
||||
goto(`/${data.spaceId}/${result.id}`, {state: {prompt: prompt }})
|
||||
}).catch((err)=>console.log(err))
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<div class="h-full w-full flex items-center public">
|
||||
<div class="container">
|
||||
<form class="request flex w-full" onsubmit={handleOnSubmit}>
|
||||
<input
|
||||
class="chatinput w-full flex-1 focus:outline-hidden focus:shadow-none focus:ring-0"
|
||||
type="text"
|
||||
placeholder="Demande ce que tu veux"
|
||||
bind:value={prompt}
|
||||
use:autofocus
|
||||
/>
|
||||
<button class="chatbutton">Go</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,3 +1,8 @@
|
||||
export function load() {
|
||||
return { title: 'Conversation' };
|
||||
import type { PageLoad } from "./$types";
|
||||
|
||||
export const load: PageLoad = ({params}) => {
|
||||
return {
|
||||
title: 'Nouvelle conversation',
|
||||
spaceId : params.space,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<script lang="ts">
|
||||
import {autofocus} from "$lib/ui/autofocus"
|
||||
import { onMount } from "svelte"
|
||||
import {page} from "$app/state"
|
||||
import {chatApi} from "$lib/api/endpoints/chat"
|
||||
import type { PageProps } from './$types';
|
||||
import type { Message, Chunk } from "$lib/types/api"
|
||||
import SvelteMarkdown from '@humanspeak/svelte-markdown'
|
||||
|
||||
let prompt = $state("")
|
||||
let { data }: PageProps = $props();
|
||||
let messages = $state([] as Message[])
|
||||
|
||||
onMount(async ()=>{
|
||||
if (page.state.prompt) {
|
||||
console.log(page.state.prompt)
|
||||
await sendRequest(page.state.prompt)
|
||||
}
|
||||
})
|
||||
|
||||
let historyDiv: HTMLDivElement;
|
||||
$effect(() => {
|
||||
if (historyDiv) {
|
||||
console.log("effect")
|
||||
historyDiv.scrollTop = historyDiv.scrollHeight;
|
||||
}
|
||||
});
|
||||
|
||||
const sendRequest = async(theprompt) => {
|
||||
prompt = ""
|
||||
let lastrole=""
|
||||
for await (const chunk of chatApi.createChatMessage(data.spaceId, data.chatId, { prompt: theprompt })) {
|
||||
if (chunk.role!=lastrole) {
|
||||
const currentDate = new Date()
|
||||
messages.push({
|
||||
id: currentDate.getTime(),
|
||||
role: chunk.role,
|
||||
content: chunk.content,
|
||||
})
|
||||
lastrole=chunk.role
|
||||
} else {
|
||||
messages[messages.length-1].content += chunk.content
|
||||
}
|
||||
historyDiv.scrollTop = historyDiv.scrollHeight;
|
||||
}
|
||||
}
|
||||
|
||||
const handleOnSubmit = async ()=>{
|
||||
await sendRequest(prompt)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="h-full w-full flex flex-col">
|
||||
<div id="history" class="flex-1 container overflow-auto" bind:this={historyDiv}>
|
||||
{#each messages as message (message.id)}
|
||||
<div class={["message", "rounded", message.role]}>
|
||||
<div class="message-content">
|
||||
<SvelteMarkdown source={message.content} />
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<div id="prompt" class="container">
|
||||
<form class="request flex w-full" onsubmit={handleOnSubmit}>
|
||||
<input
|
||||
class="chatinput w-full flex-1 focus:outline-hidden focus:shadow-none focus:ring-0"
|
||||
type="text"
|
||||
placeholder="..."
|
||||
bind:value={prompt}
|
||||
use:autofocus
|
||||
/>
|
||||
<button class="chatbutton">Go</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { PageLoad } from "./$types";
|
||||
|
||||
export const load: PageLoad = ({params}) => {
|
||||
return {
|
||||
title: 'Nouvelle conversation',
|
||||
spaceId: params.space,
|
||||
chatId: params.conversation,
|
||||
};
|
||||
}
|
||||
@@ -100,7 +100,6 @@
|
||||
let updSpace = space
|
||||
updSpace.defaultAgentId = agentId
|
||||
teamApi.updateSpace(updSpace.id, updSpace).then((newdata)=>{
|
||||
console.log(newdata)
|
||||
spaceState.spaces.map((s)=>s.id===spaceState.current?newdata:s)
|
||||
space=newdata
|
||||
}).catch((err)=>{
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { auth, setToken } from '$lib/state/auth.svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import { authApi } from "$lib/api/endpoints/auth"
|
||||
import { validateEmail } from "$lib/utilities/validators"
|
||||
|
||||
type Credentials = {
|
||||
email: string
|
||||
@@ -17,7 +18,7 @@
|
||||
})
|
||||
|
||||
const formSubmitEmail = () => {
|
||||
credentials.validemail = true
|
||||
credentials.validemail = validateEmail(credentials.email)
|
||||
}
|
||||
|
||||
const formSubmitPass = (e: Event) => {
|
||||
@@ -43,16 +44,16 @@
|
||||
<form onsubmit={formSubmitEmail}>
|
||||
<div class="flex">
|
||||
<label for="email" class="block mb-2 flex-1">Email</label>
|
||||
<a href="/recover-password" class="text-xs">Mot de passe oublié ?</a>
|
||||
<a href="/recover-password" class="text-xs ">Mot de passe oublié ?</a>
|
||||
</div>
|
||||
<div class="flex flex-row">
|
||||
<input
|
||||
type="text"
|
||||
bind:value={credentials.email}
|
||||
class="textinput mr-1"
|
||||
class="textinput mr-1 flex-1"
|
||||
autofocus
|
||||
/>
|
||||
<button class="bt" title="page suivante">
|
||||
<button class="bt small" title="page suivante">
|
||||
<i class="icon-right-big"></i>
|
||||
</button>
|
||||
</div>
|
||||
@@ -72,10 +73,10 @@
|
||||
<input
|
||||
type="password"
|
||||
bind:value={credentials.password}
|
||||
class="textinput mr-1"
|
||||
class="textinput mr-1 flex-1"
|
||||
autofocus
|
||||
/>
|
||||
<button class="bt">
|
||||
<button class="bt small">
|
||||
Entrer
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@ body {
|
||||
@apply h-full bg-stone-100 text-stone-950 dark:bg-stone-950 dark:text-stone-100;
|
||||
}
|
||||
|
||||
.formelement > label {
|
||||
label {
|
||||
@apply text-xs text-stone-600 uppercase dark:text-stone-400;
|
||||
}
|
||||
hr {
|
||||
@@ -30,9 +30,9 @@ h2 {
|
||||
}
|
||||
.bt {
|
||||
appearance: button;
|
||||
@apply min-w-40 cursor-pointer rounded bg-stone-300 px-4 py-1 transition-all duration-300 hover:bg-stone-200 dark:bg-stone-800 dark:hover:bg-stone-700;
|
||||
@apply min-w-40 cursor-pointer rounded bg-stone-300 px-4 py-1 transition-all duration-300 hover:bg-stone-400 dark:bg-stone-800 dark:hover:bg-stone-700;
|
||||
&.small {
|
||||
@apply min-w-0 px-2 py-1;
|
||||
@apply min-w-2 px-2 py-1;
|
||||
}
|
||||
&.changed,
|
||||
&.saving {
|
||||
@@ -62,10 +62,12 @@ h2 {
|
||||
.public h1 {
|
||||
@apply mb-4 text-3xl font-bold;
|
||||
}
|
||||
.profile a,
|
||||
.public a {
|
||||
.profile a {
|
||||
@apply bg-sky-300 dark:bg-sky-700;
|
||||
}
|
||||
.public a {
|
||||
@apply text-sky-500 dark:text-sky-500;
|
||||
}
|
||||
|
||||
#outer {
|
||||
@apply flex h-full flex-row;
|
||||
@@ -113,10 +115,18 @@ h2 {
|
||||
}
|
||||
}
|
||||
|
||||
.chatinput {
|
||||
@apply w-full rounded-l-xl border-stone-300 bg-stone-50 p-2 text-stone-900 dark:border-stone-700 dark:bg-stone-900 dark:text-stone-100;
|
||||
}
|
||||
|
||||
.chatbutton {
|
||||
@apply min-w-12 cursor-pointer rounded-r-xl bg-stone-300 px-2 py-1 transition-all duration-300 hover:bg-stone-400 dark:bg-stone-700 dark:hover:bg-stone-600;
|
||||
}
|
||||
|
||||
/* form */
|
||||
|
||||
.formgroup {
|
||||
@apply rounded border border-stone-300 bg-stone-100 p-2 text-sm dark:border-stone-700 dark:bg-stone-900;
|
||||
@apply rounded border border-stone-300 bg-stone-200 p-2 text-sm dark:border-stone-700 dark:bg-stone-900;
|
||||
}
|
||||
|
||||
.formelement {
|
||||
@@ -124,11 +134,11 @@ h2 {
|
||||
}
|
||||
|
||||
.textinput {
|
||||
@apply h-8 w-full rounded border-stone-700 bg-stone-50 px-2 py-1 text-sm text-stone-900 dark:bg-stone-950 dark:text-stone-100;
|
||||
@apply h-8 w-full rounded border-stone-300 bg-stone-50 px-2 py-1 text-sm text-stone-900 dark:border-stone-700 dark:bg-stone-950 dark:text-stone-100;
|
||||
}
|
||||
|
||||
.areainput {
|
||||
@apply w-full rounded border-stone-700 bg-stone-50 px-2 py-1 text-sm text-stone-900 dark:bg-stone-950 dark:text-stone-100;
|
||||
@apply w-full rounded border-stone-300 bg-stone-50 px-2 py-1 text-sm text-stone-900 dark:bg-stone-950 dark:text-stone-100;
|
||||
}
|
||||
|
||||
/* svelte select */
|
||||
@@ -261,3 +271,31 @@ h2 {
|
||||
.list-item {
|
||||
@apply list-none;
|
||||
}
|
||||
|
||||
/* chat */
|
||||
|
||||
.message {
|
||||
@apply m-2 rounded p-2;
|
||||
|
||||
&.user {
|
||||
@apply bg-sky-500 dark:text-white;
|
||||
}
|
||||
|
||||
&.assistant {
|
||||
&.reasoning {
|
||||
@apply text-white/50;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.message-content {
|
||||
@apply text-sm;
|
||||
}
|
||||
|
||||
.message-content p {
|
||||
@apply my-2;
|
||||
}
|
||||
|
||||
.message-content pre {
|
||||
@apply my-2 whitespace-pre dark:bg-stone-700;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: [
|
||||
"./src/**/*.{html,js,svelte,ts}",
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
Reference in new issue
Block a user