feat: 对接 Spark 大模型
This commit is contained in:
44
components/Markdown.vue
Normal file
44
components/Markdown.vue
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import md from 'markdown-it'
|
||||||
|
import hljs from "highlight.js";
|
||||||
|
import 'highlight.js/styles/github-dark-dimmed.min.css';
|
||||||
|
|
||||||
|
const renderer = md({
|
||||||
|
html: true,
|
||||||
|
linkify: true,
|
||||||
|
typographer: true,
|
||||||
|
breaks: true,
|
||||||
|
highlight: function (str, lang) {
|
||||||
|
if (lang && hljs.getLanguage(lang)) {
|
||||||
|
try {
|
||||||
|
return (
|
||||||
|
`<pre class="hljs" style="overflow-x: auto"><code>${
|
||||||
|
hljs.highlight(str, {language: lang, ignoreIllegals: true}).value
|
||||||
|
}</code></pre>`
|
||||||
|
)
|
||||||
|
} catch (_) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return '<pre class="hljs"><code>' + md().utils.escapeHtml(str) + '</code></pre>';
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
source: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<article
|
||||||
|
class="prose dark:prose-invert max-w-none prose-sm prose-neutral"
|
||||||
|
v-html="renderer.render(source.replaceAll('\t', ' '))"
|
||||||
|
></article>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type {ChatSession} from "~/components/aigc/chat/index";
|
|
||||||
import type {PropType} from "vue";
|
import type {PropType} from "vue";
|
||||||
|
import type {ChatSession} from "~/typings/llm";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
active: {
|
active: {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type {PropType} from "vue";
|
import type {PropType} from "vue";
|
||||||
import type {ChatMessage} from "~/components/aigc/chat/index";
|
import type {ChatMessage} from "~/typings/llm";
|
||||||
import MessageResponding from "~/components/Icon/MessageResponding.vue";
|
import MessageResponding from "~/components/Icon/MessageResponding.vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -24,6 +24,9 @@ const message_avatar = computed(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
const message_background = computed(() => {
|
const message_background = computed(() => {
|
||||||
|
if (props.message?.interrupted) {
|
||||||
|
return 'bg-red-200/50 dark:bg-red-800/20 border-red-300 dark:!border-red-500/50'
|
||||||
|
}
|
||||||
switch (props.message?.role) {
|
switch (props.message?.role) {
|
||||||
case 'user':
|
case 'user':
|
||||||
return 'bg-primary-100 dark:bg-primary-800'
|
return 'bg-primary-100 dark:bg-primary-800'
|
||||||
@@ -47,15 +50,23 @@ const message_background = computed(() => {
|
|||||||
:class="message_background"
|
:class="message_background"
|
||||||
:key="message.content"
|
:key="message.content"
|
||||||
>
|
>
|
||||||
<span v-if="message.content">
|
<div v-if="message.content">
|
||||||
{{ message.content }}
|
<!-- <span v-if="message.interrupted">-->
|
||||||
</span>
|
<!-- <svg class="inline -mt-0.5 opacity-80" xmlns="http://www.w3.org/2000/svg" width="1.2em"-->
|
||||||
|
<!-- height="1.2em" viewBox="0 0 24 24">-->
|
||||||
|
<!-- <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"-->
|
||||||
|
<!-- d="M12 9v4m-1.637-9.409L2.257 17.125a1.914 1.914 0 0 0 1.636 2.871h16.214a1.914 1.914 0 0 0 1.636-2.87L13.637 3.59a1.914 1.914 0 0 0-3.274 0zM12 16h.01"/>-->
|
||||||
|
<!-- </svg>-->
|
||||||
|
<!-- {{ message.content }}-->
|
||||||
|
<!-- </span>-->
|
||||||
|
<Markdown :source="message.content"/>
|
||||||
|
</div>
|
||||||
<span v-else>
|
<span v-else>
|
||||||
<MessageResponding class="text-xl text-neutral-500 dark:text-neutral-300 mx-2"/>
|
<MessageResponding class="text-xl text-neutral-500 dark:text-neutral-300 mx-2"/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
<div class="chat-inside-extra">
|
<div v-if="message.create_at" class="chat-inside-extra">
|
||||||
{{ dayjs(message.create_at * 1000).format('YYYY-MM-DD HH:mm:ss') }}
|
{{ dayjs(message.create_at * 1000).format('YYYY-MM-DD HH:mm:ss') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
20
components/aigc/chat/index.d.ts
vendored
20
components/aigc/chat/index.d.ts
vendored
@@ -1,20 +0,0 @@
|
|||||||
export type ChatSessionId = string
|
|
||||||
export type ChatMessageId = string
|
|
||||||
|
|
||||||
export interface ChatSession {
|
|
||||||
id: ChatSessionId
|
|
||||||
subject: string
|
|
||||||
create_at: number
|
|
||||||
messages: ChatMessage[]
|
|
||||||
last_input?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type MessageRole = 'user' | 'assistant' | 'system'
|
|
||||||
|
|
||||||
export interface ChatMessage {
|
|
||||||
id: ChatMessageId
|
|
||||||
role: MessageRole
|
|
||||||
content: string
|
|
||||||
create_at: number
|
|
||||||
interrupted?: boolean
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import type {ResultBlockMeta} from '~/components/aigc/drawing';
|
import type {ResultBlockMeta} from '~/components/aigc/drawing';
|
||||||
import type {ChatSession} from "~/components/aigc/chat";
|
import type {ChatSession} from "~/typings/llm";
|
||||||
|
|
||||||
export interface HistoryItem {
|
export interface HistoryItem {
|
||||||
fid: string
|
fid: string
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
export const useIdGenerator = () => {
|
|
||||||
const generateUUID = () => {
|
|
||||||
// noinspection SpellCheckingInspection
|
|
||||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
||||||
const r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8)
|
|
||||||
return v.toString(16)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const generateMathRandom = () => {
|
|
||||||
return Math.random().toString(36).slice(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
generateUUID,
|
|
||||||
generateMathRandom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
31
composables/useLLM.ts
Normal file
31
composables/useLLM.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import {type ChatMessage, llmModels, type LLMSpark, type MessageRole, type ModelTag} from "~/typings/llm";
|
||||||
|
import {useFetchWrapped} from "~/composables/useFetchWrapped";
|
||||||
|
|
||||||
|
export interface LLMRequestOptions {
|
||||||
|
modelTag: ModelTag
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useLLM = (context: ChatMessage[], options: LLMRequestOptions): Promise<string> => new Promise((resolve, reject) => {
|
||||||
|
const {modelTag} = options
|
||||||
|
const model = llmModels.find(model => model.tag === modelTag)
|
||||||
|
if (!model) return reject('model specified is not available')
|
||||||
|
const loginState = useLoginState()
|
||||||
|
useFetchWrapped<LLMSpark.request | AuthedRequest, BaseResponse<LLMSpark.response>>(
|
||||||
|
model.endpoint,
|
||||||
|
{
|
||||||
|
token: loginState.token || '',
|
||||||
|
user_id: loginState.user.id,
|
||||||
|
prompt: JSON.stringify(context.filter(c => c.content && !c.interrupted).map(c => ({
|
||||||
|
role: c.role,
|
||||||
|
content: c.content
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
).then(res => {
|
||||||
|
if (res.ret !== 200) return reject(res.msg || 'unknown error')
|
||||||
|
if (res.data.request_msg) return resolve(res.data.request_msg)
|
||||||
|
if (res.data.request_fail) return reject(res.data.request_fail?.header?.message || 'unknown error')
|
||||||
|
return reject('unknown error')
|
||||||
|
}).catch(err => {
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -15,7 +15,10 @@
|
|||||||
"@iconify-json/svg-spinners": "^1.1.2",
|
"@iconify-json/svg-spinners": "^1.1.2",
|
||||||
"@iconify-json/tabler": "^1.1.105",
|
"@iconify-json/tabler": "^1.1.105",
|
||||||
"@nuxt/ui": "^2.14.1",
|
"@nuxt/ui": "^2.14.1",
|
||||||
|
"@uniiem/uuid": "^0.2.1",
|
||||||
|
"highlight.js": "^11.9.0",
|
||||||
"idb-keyval": "^6.2.1",
|
"idb-keyval": "^6.2.1",
|
||||||
|
"markdown-it": "^14.1.0",
|
||||||
"nuxt": "^3.10.3",
|
"nuxt": "^3.10.3",
|
||||||
"radix-vue": "^1.4.9",
|
"radix-vue": "^1.4.9",
|
||||||
"vue": "^3.4.19",
|
"vue": "^3.4.19",
|
||||||
@@ -26,6 +29,8 @@
|
|||||||
"@nuxtjs/google-fonts": "^3.2.0",
|
"@nuxtjs/google-fonts": "^3.2.0",
|
||||||
"@pinia-plugin-persistedstate/nuxt": "^1.2.0",
|
"@pinia-plugin-persistedstate/nuxt": "^1.2.0",
|
||||||
"@pinia/nuxt": "^0.5.1",
|
"@pinia/nuxt": "^0.5.1",
|
||||||
|
"@tailwindcss/typography": "^0.5.12",
|
||||||
|
"@types/markdown-it": "^13.0.7",
|
||||||
"@vite-pwa/nuxt": "^0.5.0",
|
"@vite-pwa/nuxt": "^0.5.0",
|
||||||
"dayjs-nuxt": "^2.1.9",
|
"dayjs-nuxt": "^2.1.9",
|
||||||
"sass": "^1.72.0"
|
"sass": "^1.72.0"
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import ChatItem from "~/components/aigc/chat/ChatItem.vue";
|
import ChatItem from "~/components/aigc/chat/ChatItem.vue";
|
||||||
import type {ChatMessage, ChatMessageId, ChatSessionId} from "~/components/aigc/chat";
|
|
||||||
import Message from "~/components/aigc/chat/Message.vue";
|
import Message from "~/components/aigc/chat/Message.vue";
|
||||||
import {useIdGenerator} from "~/composables/useIdGenerator";
|
import type {ChatMessage, ChatMessageId, ChatSessionId} from "~/typings/llm";
|
||||||
import {useHistory} from "~/composables/useHistory";
|
import {useHistory} from "~/composables/useHistory";
|
||||||
|
import {uuidv4} from "@uniiem/uuid";
|
||||||
|
import {useLLM} from "~/composables/useLLM";
|
||||||
|
|
||||||
useHead({
|
useHead({
|
||||||
title: '聊天 | XSH AI'
|
title: '聊天 | XSH AI'
|
||||||
@@ -11,7 +12,6 @@ useHead({
|
|||||||
|
|
||||||
const dayjs = useDayjs()
|
const dayjs = useDayjs()
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
const {generateUUID} = useIdGenerator()
|
|
||||||
const historyStore = useHistory()
|
const historyStore = useHistory()
|
||||||
const {chatSessions} = storeToRefs(historyStore)
|
const {chatSessions} = storeToRefs(historyStore)
|
||||||
const {setChatSessions} = historyStore
|
const {setChatSessions} = historyStore
|
||||||
@@ -23,7 +23,15 @@ const messagesWrapperRef = ref<HTMLDivElement | null>(null)
|
|||||||
const user_input = ref('')
|
const user_input = ref('')
|
||||||
const responding = ref(false)
|
const responding = ref(false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定 ID 的会话数据
|
||||||
|
* @param chatSessionId
|
||||||
|
*/
|
||||||
const getSessionCopyById = (chatSessionId: ChatSessionId) => chatSessions.value.find(s => s.id === chatSessionId);
|
const getSessionCopyById = (chatSessionId: ChatSessionId) => chatSessions.value.find(s => s.id === chatSessionId);
|
||||||
|
/**
|
||||||
|
* 切换当前会话
|
||||||
|
* @param chatSessionId 指定会话 ID,不传则切换到列表中第一个会话
|
||||||
|
*/
|
||||||
const selectCurrentSessionId = (chatSessionId?: ChatSessionId) => {
|
const selectCurrentSessionId = (chatSessionId?: ChatSessionId) => {
|
||||||
if (chatSessions.value.length > 0) {
|
if (chatSessions.value.length > 0) {
|
||||||
if (chatSessionId) { // 切换到指定 ID
|
if (chatSessionId) { // 切换到指定 ID
|
||||||
@@ -48,11 +56,17 @@ const selectCurrentSessionId = (chatSessionId?: ChatSessionId) => {
|
|||||||
} else {
|
} else {
|
||||||
handleClickCreateSession()
|
handleClickCreateSession()
|
||||||
}
|
}
|
||||||
|
nextTick(() => {
|
||||||
|
scrollToMessageListBottom()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理新建会话操作
|
||||||
|
*/
|
||||||
const handleClickCreateSession = () => {
|
const handleClickCreateSession = () => {
|
||||||
// 生成一个新的会话 ID
|
// 生成一个新的会话 ID
|
||||||
const sessionId = generateUUID()
|
const sessionId = uuidv4()
|
||||||
// 插入新会话数据
|
// 插入新会话数据
|
||||||
setChatSessions([
|
setChatSessions([
|
||||||
{
|
{
|
||||||
@@ -67,6 +81,10 @@ const handleClickCreateSession = () => {
|
|||||||
selectCurrentSessionId(sessionId)
|
selectCurrentSessionId(sessionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理发送消息操作
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
const handleClickSend = (event: any) => {
|
const handleClickSend = (event: any) => {
|
||||||
if (event.ctrlKey) {
|
if (event.ctrlKey) {
|
||||||
return;
|
return;
|
||||||
@@ -84,7 +102,7 @@ const handleClickSend = (event: any) => {
|
|||||||
}
|
}
|
||||||
// 插入用户消息
|
// 插入用户消息
|
||||||
insetMessage({
|
insetMessage({
|
||||||
id: generateUUID(),
|
id: uuidv4(),
|
||||||
role: 'user',
|
role: 'user',
|
||||||
content: user_input.value,
|
content: user_input.value,
|
||||||
create_at: dayjs().unix(),
|
create_at: dayjs().unix(),
|
||||||
@@ -94,16 +112,20 @@ const handleClickSend = (event: any) => {
|
|||||||
responding.value = true
|
responding.value = true
|
||||||
// 插入空助手消息(加载状态)
|
// 插入空助手消息(加载状态)
|
||||||
const assistantReplyId = insetMessage({
|
const assistantReplyId = insetMessage({
|
||||||
id: generateUUID(),
|
id: uuidv4(),
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: '',
|
content: '',
|
||||||
create_at: dayjs().unix(),
|
|
||||||
})
|
})
|
||||||
// mock
|
// 请求模型回复
|
||||||
setTimeout(() => {
|
useLLM(getMessages(), {
|
||||||
modifyMessageContent(assistantReplyId, '草,走,忽略!ጿ ኈ ቼ ዽ ጿ')
|
modelTag: 'spark3_5'
|
||||||
|
}).then(reply => {
|
||||||
|
modifyMessageContent(assistantReplyId, reply)
|
||||||
|
}).catch(err => {
|
||||||
|
modifyMessageContent(assistantReplyId, err, true)
|
||||||
|
}).finally(() => {
|
||||||
responding.value = false
|
responding.value = false
|
||||||
}, 1000)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const scrollToMessageListBottom = () => {
|
const scrollToMessageListBottom = () => {
|
||||||
@@ -127,12 +149,21 @@ const insetMessage = (message: ChatMessage): ChatMessageId => {
|
|||||||
return message.id
|
return message.id
|
||||||
}
|
}
|
||||||
|
|
||||||
const modifyMessageContent = (messageId: ChatMessageId, content: string) => {
|
const getMessages = () => getSessionCopyById(currentSessionId.value!)?.messages || []
|
||||||
|
|
||||||
|
const modifyMessageContent = (
|
||||||
|
messageId: ChatMessageId,
|
||||||
|
content: string,
|
||||||
|
interrupted: boolean = false,
|
||||||
|
updateTime: boolean = true
|
||||||
|
) => {
|
||||||
setChatSessions(chatSessions.value.map(s => s.id === currentSessionId.value ? {
|
setChatSessions(chatSessions.value.map(s => s.id === currentSessionId.value ? {
|
||||||
...s,
|
...s,
|
||||||
messages: s.messages.map(m => m.id === messageId ? {
|
messages: s.messages.map(m => m.id === messageId ? {
|
||||||
...m,
|
...m,
|
||||||
content,
|
content,
|
||||||
|
interrupted,
|
||||||
|
create_at: updateTime ? dayjs().unix() : m.create_at,
|
||||||
} : m)
|
} : m)
|
||||||
} : s))
|
} : s))
|
||||||
scrollToMessageListBottom()
|
scrollToMessageListBottom()
|
||||||
@@ -188,7 +219,7 @@ onMounted(() => {
|
|||||||
<div class="flex flex-col gap-8 px-4 py-8">
|
<div class="flex flex-col gap-8 px-4 py-8">
|
||||||
<TransitionGroup name="message">
|
<TransitionGroup name="message">
|
||||||
<Message
|
<Message
|
||||||
v-for="message in getSessionCopyById(currentSessionId!)?.messages || []"
|
v-for="message in getMessages() || []"
|
||||||
:message="message"
|
:message="message"
|
||||||
:key="message.id"
|
:key="message.id"
|
||||||
/>
|
/>
|
||||||
@@ -234,8 +265,4 @@ onMounted(() => {
|
|||||||
.message-enter-from {
|
.message-enter-from {
|
||||||
@apply translate-y-4 opacity-0;
|
@apply translate-y-4 opacity-0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-leave-to {
|
|
||||||
@apply -translate-y-4 opacity-0;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import type {Config} from 'tailwindcss'
|
import type {Config} from 'tailwindcss'
|
||||||
import defaultTheme from 'tailwindcss/defaultTheme'
|
import typography from '@tailwindcss/typography'
|
||||||
|
|
||||||
export default <Partial<Config>>{
|
export default <Partial<Config>>{
|
||||||
theme: {
|
theme: {
|
||||||
@@ -19,6 +19,7 @@ export default <Partial<Config>>{
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
plugins: [typography],
|
||||||
safelist: [
|
safelist: [
|
||||||
{
|
{
|
||||||
pattern: /^bg-/,
|
pattern: /^bg-/,
|
||||||
|
|||||||
83
typings/llm.ts
Normal file
83
typings/llm.ts
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
export type ChatSessionId = string
|
||||||
|
export type ChatMessageId = string
|
||||||
|
|
||||||
|
export type ModelTag =
|
||||||
|
'spark1_5' |
|
||||||
|
'spark3_0' |
|
||||||
|
'spark3_5'
|
||||||
|
|
||||||
|
export interface LLMModal {
|
||||||
|
tag: ModelTag
|
||||||
|
name: string
|
||||||
|
description: string
|
||||||
|
endpoint: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace LLMSpark {
|
||||||
|
export interface request {
|
||||||
|
prompt: string
|
||||||
|
}
|
||||||
|
export interface response {
|
||||||
|
request_msg?: string
|
||||||
|
request_fail?: {
|
||||||
|
header?: {
|
||||||
|
code: number
|
||||||
|
message: string
|
||||||
|
sid: string
|
||||||
|
status: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// answer: string
|
||||||
|
// last_data: {
|
||||||
|
// payload: {
|
||||||
|
// usage: {
|
||||||
|
// text: {
|
||||||
|
// completion_tokens: number
|
||||||
|
// prompt_tokens: number
|
||||||
|
// question_tokens: number
|
||||||
|
// total_tokens: number
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const llmModels: Readonly<LLMModal[]> = Object.freeze([
|
||||||
|
{
|
||||||
|
tag: 'spark1_5',
|
||||||
|
name: 'Spark 1.5',
|
||||||
|
description: 'Spark 1.5',
|
||||||
|
endpoint: 'App.Assistant_Spark.Chat_1_5'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tag: 'spark3_0',
|
||||||
|
name: 'Spark 3.0',
|
||||||
|
description: 'Spark 3.0',
|
||||||
|
endpoint: 'App.Assistant_Spark.Chat_3_0'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tag: 'spark3_5',
|
||||||
|
name: 'Spark 3.5',
|
||||||
|
description: 'Spark 3.5',
|
||||||
|
endpoint: 'App.Assistant_Spark.Chat_3_5'
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
export interface ChatSession {
|
||||||
|
id: ChatSessionId
|
||||||
|
subject: string
|
||||||
|
create_at: number
|
||||||
|
messages: ChatMessage[]
|
||||||
|
last_input?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type MessageRole = 'user' | 'assistant' | 'system'
|
||||||
|
|
||||||
|
export interface ChatMessage {
|
||||||
|
id: ChatMessageId
|
||||||
|
role: MessageRole
|
||||||
|
content: string
|
||||||
|
create_at?: number
|
||||||
|
interrupted?: boolean
|
||||||
|
}
|
||||||
105
yarn.lock
105
yarn.lock
@@ -2255,6 +2255,16 @@
|
|||||||
lodash.merge "^4.6.2"
|
lodash.merge "^4.6.2"
|
||||||
postcss-selector-parser "6.0.10"
|
postcss-selector-parser "6.0.10"
|
||||||
|
|
||||||
|
"@tailwindcss/typography@^0.5.12":
|
||||||
|
version "0.5.12"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.12.tgz#c0532fd594427b7f4e8e38eff7bf272c63a1dca4"
|
||||||
|
integrity sha512-CNwpBpconcP7ppxmuq3qvaCxiRWnbhANpY/ruH4L5qs2GCiVDJXde/pjj2HWPV1+Q4G9+V/etrwUYopdcjAlyg==
|
||||||
|
dependencies:
|
||||||
|
lodash.castarray "^4.4.0"
|
||||||
|
lodash.isplainobject "^4.0.6"
|
||||||
|
lodash.merge "^4.6.2"
|
||||||
|
postcss-selector-parser "6.0.10"
|
||||||
|
|
||||||
"@tanstack/virtual-core@3.1.2":
|
"@tanstack/virtual-core@3.1.2":
|
||||||
version "3.1.2"
|
version "3.1.2"
|
||||||
resolved "https://registry.npmmirror.com/@tanstack/virtual-core/-/virtual-core-3.1.2.tgz#ca76f28f826fbd3310f88c3cd355d9c4aba80abb"
|
resolved "https://registry.npmmirror.com/@tanstack/virtual-core/-/virtual-core-3.1.2.tgz#ca76f28f826fbd3310f88c3cd355d9c4aba80abb"
|
||||||
@@ -2302,6 +2312,24 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
|
"@types/linkify-it@*":
|
||||||
|
version "3.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.5.tgz#1e78a3ac2428e6d7e6c05c1665c242023a4601d8"
|
||||||
|
integrity sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==
|
||||||
|
|
||||||
|
"@types/markdown-it@^13.0.7":
|
||||||
|
version "13.0.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-13.0.7.tgz#4a495115f470075bd4434a0438ac477a49c2e152"
|
||||||
|
integrity sha512-U/CBi2YUUcTHBt5tjO2r5QV/x0Po6nsYwQU4Y04fBS6vfoImaiZ6f8bi3CjTCxBPQSO1LMyUqkByzi8AidyxfA==
|
||||||
|
dependencies:
|
||||||
|
"@types/linkify-it" "*"
|
||||||
|
"@types/mdurl" "*"
|
||||||
|
|
||||||
|
"@types/mdurl@*":
|
||||||
|
version "1.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-1.0.5.tgz#3e0d2db570e9fb6ccb2dc8fde0be1d79ac810d39"
|
||||||
|
integrity sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==
|
||||||
|
|
||||||
"@types/node@*":
|
"@types/node@*":
|
||||||
version "20.11.20"
|
version "20.11.20"
|
||||||
resolved "https://registry.npmmirror.com/@types/node/-/node-20.11.20.tgz#f0a2aee575215149a62784210ad88b3a34843659"
|
resolved "https://registry.npmmirror.com/@types/node/-/node-20.11.20.tgz#f0a2aee575215149a62784210ad88b3a34843659"
|
||||||
@@ -2372,6 +2400,11 @@
|
|||||||
hookable "^5.5.3"
|
hookable "^5.5.3"
|
||||||
unhead "1.8.10"
|
unhead "1.8.10"
|
||||||
|
|
||||||
|
"@uniiem/uuid@^0.2.1":
|
||||||
|
version "0.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@uniiem/uuid/-/uuid-0.2.1.tgz#2ffa44624968cda47ef744770b2b58f5e5e558f8"
|
||||||
|
integrity sha512-p8DOA3BTkZgvgtOCtK5x7Y2l+GRTFhYrOua70YPiEEUomQFirwxpWrQBst+7oB/iPTeY1zHuF6MKl+mxi0R00A==
|
||||||
|
|
||||||
"@vercel/nft@^0.24.3":
|
"@vercel/nft@^0.24.3":
|
||||||
version "0.24.4"
|
version "0.24.4"
|
||||||
resolved "https://registry.npmmirror.com/@vercel/nft/-/nft-0.24.4.tgz#b8942340c7821e6ff7bdf943b559642dbc9cae78"
|
resolved "https://registry.npmmirror.com/@vercel/nft/-/nft-0.24.4.tgz#b8942340c7821e6ff7bdf943b559642dbc9cae78"
|
||||||
@@ -3668,7 +3701,7 @@ enhanced-resolve@^5.14.1:
|
|||||||
graceful-fs "^4.2.4"
|
graceful-fs "^4.2.4"
|
||||||
tapable "^2.2.0"
|
tapable "^2.2.0"
|
||||||
|
|
||||||
entities@^4.2.0, entities@^4.5.0:
|
entities@^4.2.0, entities@^4.4.0, entities@^4.5.0:
|
||||||
version "4.5.0"
|
version "4.5.0"
|
||||||
resolved "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
|
resolved "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
|
||||||
integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
|
integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
|
||||||
@@ -4372,6 +4405,11 @@ hasown@^2.0.0, hasown@^2.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
function-bind "^1.1.2"
|
function-bind "^1.1.2"
|
||||||
|
|
||||||
|
highlight.js@^11.9.0:
|
||||||
|
version "11.9.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.9.0.tgz#04ab9ee43b52a41a047432c8103e2158a1b8b5b0"
|
||||||
|
integrity sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==
|
||||||
|
|
||||||
hookable@^5.5.3:
|
hookable@^5.5.3:
|
||||||
version "5.5.3"
|
version "5.5.3"
|
||||||
resolved "https://registry.npmmirror.com/hookable/-/hookable-5.5.3.tgz#6cfc358984a1ef991e2518cb9ed4a778bbd3215d"
|
resolved "https://registry.npmmirror.com/hookable/-/hookable-5.5.3.tgz#6cfc358984a1ef991e2518cb9ed4a778bbd3215d"
|
||||||
@@ -5087,6 +5125,13 @@ lines-and-columns@^1.1.6:
|
|||||||
resolved "https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
|
resolved "https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
|
||||||
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
|
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
|
||||||
|
|
||||||
|
linkify-it@^5.0.0:
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-5.0.0.tgz#9ef238bfa6dc70bd8e7f9572b52d369af569b421"
|
||||||
|
integrity sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==
|
||||||
|
dependencies:
|
||||||
|
uc.micro "^2.0.0"
|
||||||
|
|
||||||
listhen@^1.5.5:
|
listhen@^1.5.5:
|
||||||
version "1.7.2"
|
version "1.7.2"
|
||||||
resolved "https://registry.npmmirror.com/listhen/-/listhen-1.7.2.tgz#66b81740692269d5d8cafdc475020f2fc51afbae"
|
resolved "https://registry.npmmirror.com/listhen/-/listhen-1.7.2.tgz#66b81740692269d5d8cafdc475020f2fc51afbae"
|
||||||
@@ -5274,6 +5319,18 @@ make-fetch-happen@^13.0.0:
|
|||||||
promise-retry "^2.0.1"
|
promise-retry "^2.0.1"
|
||||||
ssri "^10.0.0"
|
ssri "^10.0.0"
|
||||||
|
|
||||||
|
markdown-it@^14.1.0:
|
||||||
|
version "14.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-14.1.0.tgz#3c3c5992883c633db4714ccb4d7b5935d98b7d45"
|
||||||
|
integrity sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==
|
||||||
|
dependencies:
|
||||||
|
argparse "^2.0.1"
|
||||||
|
entities "^4.4.0"
|
||||||
|
linkify-it "^5.0.0"
|
||||||
|
mdurl "^2.0.0"
|
||||||
|
punycode.js "^2.3.1"
|
||||||
|
uc.micro "^2.1.0"
|
||||||
|
|
||||||
mdn-data@2.0.28:
|
mdn-data@2.0.28:
|
||||||
version "2.0.28"
|
version "2.0.28"
|
||||||
resolved "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.28.tgz#5ec48e7bef120654539069e1ae4ddc81ca490eba"
|
resolved "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.28.tgz#5ec48e7bef120654539069e1ae4ddc81ca490eba"
|
||||||
@@ -5284,6 +5341,11 @@ mdn-data@2.0.30:
|
|||||||
resolved "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc"
|
resolved "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc"
|
||||||
integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==
|
integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==
|
||||||
|
|
||||||
|
mdurl@^2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-2.0.0.tgz#80676ec0433025dd3e17ee983d0fe8de5a2237e0"
|
||||||
|
integrity sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==
|
||||||
|
|
||||||
media-typer@0.3.0:
|
media-typer@0.3.0:
|
||||||
version "0.3.0"
|
version "0.3.0"
|
||||||
resolved "https://registry.npmmirror.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
resolved "https://registry.npmmirror.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
||||||
@@ -6484,6 +6546,11 @@ protocols@^2.0.0, protocols@^2.0.1:
|
|||||||
resolved "https://registry.npmmirror.com/protocols/-/protocols-2.0.1.tgz#8f155da3fc0f32644e83c5782c8e8212ccf70a86"
|
resolved "https://registry.npmmirror.com/protocols/-/protocols-2.0.1.tgz#8f155da3fc0f32644e83c5782c8e8212ccf70a86"
|
||||||
integrity sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==
|
integrity sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==
|
||||||
|
|
||||||
|
punycode.js@^2.3.1:
|
||||||
|
version "2.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/punycode.js/-/punycode.js-2.3.1.tgz#6b53e56ad75588234e79f4affa90972c7dd8cdb7"
|
||||||
|
integrity sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==
|
||||||
|
|
||||||
punycode@^2.1.0:
|
punycode@^2.1.0:
|
||||||
version "2.3.1"
|
version "2.3.1"
|
||||||
resolved "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
|
resolved "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
|
||||||
@@ -7143,7 +7210,16 @@ streamx@^2.15.0:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
bare-events "^2.2.0"
|
bare-events "^2.2.0"
|
||||||
|
|
||||||
"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
"string-width-cjs@npm:string-width@^4.2.0":
|
||||||
|
version "4.2.3"
|
||||||
|
resolved "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||||
|
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||||
|
dependencies:
|
||||||
|
emoji-regex "^8.0.0"
|
||||||
|
is-fullwidth-code-point "^3.0.0"
|
||||||
|
strip-ansi "^6.0.1"
|
||||||
|
|
||||||
|
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
||||||
version "4.2.3"
|
version "4.2.3"
|
||||||
resolved "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
resolved "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||||
@@ -7226,7 +7302,14 @@ stringify-object@^3.3.0:
|
|||||||
is-obj "^1.0.1"
|
is-obj "^1.0.1"
|
||||||
is-regexp "^1.0.0"
|
is-regexp "^1.0.0"
|
||||||
|
|
||||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
|
||||||
|
version "6.0.1"
|
||||||
|
resolved "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||||
|
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||||
|
dependencies:
|
||||||
|
ansi-regex "^5.0.1"
|
||||||
|
|
||||||
|
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||||
version "6.0.1"
|
version "6.0.1"
|
||||||
resolved "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
resolved "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||||
@@ -7591,6 +7674,11 @@ typed-array-length@^1.0.4:
|
|||||||
is-typed-array "^1.1.13"
|
is-typed-array "^1.1.13"
|
||||||
possible-typed-array-names "^1.0.0"
|
possible-typed-array-names "^1.0.0"
|
||||||
|
|
||||||
|
uc.micro@^2.0.0, uc.micro@^2.1.0:
|
||||||
|
version "2.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-2.1.0.tgz#f8d3f7d0ec4c3dea35a7e3c8efa4cb8b45c9e7ee"
|
||||||
|
integrity sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==
|
||||||
|
|
||||||
ufo@^1.1.2, ufo@^1.2.0, ufo@^1.3.0, ufo@^1.3.1, ufo@^1.3.2, ufo@^1.4.0:
|
ufo@^1.1.2, ufo@^1.2.0, ufo@^1.3.0, ufo@^1.3.1, ufo@^1.3.2, ufo@^1.4.0:
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.npmmirror.com/ufo/-/ufo-1.4.0.tgz#39845b31be81b4f319ab1d99fd20c56cac528d32"
|
resolved "https://registry.npmmirror.com/ufo/-/ufo-1.4.0.tgz#39845b31be81b4f319ab1d99fd20c56cac528d32"
|
||||||
@@ -8263,7 +8351,16 @@ workbox-window@7.0.0, workbox-window@^7.0.0:
|
|||||||
"@types/trusted-types" "^2.0.2"
|
"@types/trusted-types" "^2.0.2"
|
||||||
workbox-core "7.0.0"
|
workbox-core "7.0.0"
|
||||||
|
|
||||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
|
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
|
||||||
|
version "7.0.0"
|
||||||
|
resolved "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||||
|
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||||
|
dependencies:
|
||||||
|
ansi-styles "^4.0.0"
|
||||||
|
string-width "^4.1.0"
|
||||||
|
strip-ansi "^6.0.0"
|
||||||
|
|
||||||
|
wrap-ansi@^7.0.0:
|
||||||
version "7.0.0"
|
version "7.0.0"
|
||||||
resolved "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
resolved "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||||
|
|||||||
Reference in New Issue
Block a user