feat: 对接 Spark 大模型

This commit is contained in:
2024-04-01 17:03:03 +08:00
parent d20b518f5b
commit 3ded5f8e7a
12 changed files with 328 additions and 67 deletions

44
components/Markdown.vue Normal file
View 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', '&nbsp;&nbsp;&nbsp;&nbsp;'))"
></article>
</template>
<style scoped>
</style>

View File

@@ -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: {

View File

@@ -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>

View File

@@ -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
}

View File

@@ -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

View File

@@ -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
View 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)
})
})

View File

@@ -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"

View File

@@ -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>

View File

@@ -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
View 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
View File

@@ -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==