feat: 模型列表

This commit is contained in:
shaohuzhang1 2023-11-27 18:08:58 +08:00
parent a1acfdc2be
commit 367e92c414
9 changed files with 259 additions and 68 deletions

View File

@ -73,11 +73,8 @@ const postChatOpen: (data: ApplicationFormType) => Promise<Result<any>> = (data)
"message": "string",
}
*/
const postChatMessage: (chat_id: string, message: string) => Promise<Result<any>> = (
chat_id,
message
) => {
return postStream(`${prefix}/chat_message/${chat_id}`, { message })
const postChatMessage: (chat_id: string, message: string) => Promise<any> = (chat_id, message) => {
return postStream(`/api/${prefix}/chat_message/${chat_id}`, { message })
}
export default {
getAllAppilcation,

View File

@ -1,7 +1,7 @@
import { Result } from '@/request/Result'
import { get, post, del, put } from '@/request/index'
import { type Ref } from 'vue'
import type { modelRequest, Provider } from '@/api/type/model'
import type { modelRequest, Provider, ListModelRequest, Model } from '@/api/type/model'
const prefix = '/model'
const prefix_provider = '/provider'
@ -9,9 +9,13 @@ const prefix_provider = '/provider'
*
* @params name, model_type, model_name
*/
const getModel: (data?: modelRequest) => Promise<Result<any>> = (data) => {
return get(`${prefix}`, data)
const getModel: (
request: ListModelRequest,
loading?: Ref<boolean>
) => Promise<Result<Array<Model>>> = (data, loading) => {
return get(`${prefix}`, data, loading)
}
/**
*
*/

View File

@ -1,3 +1,4 @@
import { store } from '@/stores'
interface modelRequest {
name: string
model_type: string
@ -19,4 +20,49 @@ interface Provider {
icon: string
}
export type { modelRequest, Provider }
interface ListModelRequest {
/**
*
*/
name?: string
/**
*
*/
model_type?: string
/**
*
*/
model_name?: string
/**
*
*/
provider?: string
}
interface Model {
/**
* id
*/
id: String
/**
*
*/
name: string
/**
*
*/
model_type: string
/**
*
*/
model_name: string
/**
*
*/
credential: any
/**
*
*/
provider: string
}
export type { modelRequest, Provider, ListModelRequest, Model }

View File

@ -128,22 +128,19 @@ function chatHandle() {
}
function chatMessage(chatId: string) {
applicationApi
.postChatMessage(chatId, inputValue.value)
.then((response) => {
console.log(response.data)
response.data.on('data', (chunk) => {
console.log(chunk)
//
})
// response.data.on('end', () => {
// //
// })
})
.catch(() => {
loading.value = false
})
applicationApi.postChatMessage(chatId, inputValue.value).then(async (response) => {
const reader = response.body.getReader()
while (true) {
const { done, value } = await reader.read()
if (done) {
loading.value = false
break
}
const decoder = new TextDecoder('utf-8')
const str = decoder.decode(value, { stream: true })
console.log('value', JSON.parse(str.replace('data:', '')))
}
})
}
</script>
<style lang="scss" scoped>

View File

@ -3,9 +3,10 @@
<div class="card-header">
<slot name="header">
<div class="title flex align-center">
<AppAvatar class="mr-12" shape="square" :size="32" v-if="showIcon">
<AppAvatar v-if="!slots.icon && showIcon" class="mr-12" shape="square" :size="32">
<img src="@/assets/icon_document.svg" style="width: 58%" alt="" />
</AppAvatar>
<slot v-else name="icon"> </slot>
<h4 class="ellipsis-1">{{ title }}</h4>
</div>
</slot>
@ -23,22 +24,27 @@
</el-card>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import { ref, useSlots } from 'vue'
const slots = useSlots()
defineOptions({ name: 'CardBox' })
const props = defineProps({
title: {
type: String,
default: '标题'
},
description: {
type: String,
default: ''
},
showIcon: {
type: Boolean,
default: true
}
})
const props = withDefaults(
defineProps<{
/**
* 标题
*/
title?: string
/**
* 描述
*/
description?: string
/**
* 是否展示icon
*/
showIcon?: boolean
}>(),
{ title: '标题', description: '', showIcon: true }
)
const show = ref(false)
function cardEnter() {

View File

@ -2,10 +2,18 @@
<div class="common-list">
<el-scrollbar>
<ul v-if="data.length > 0">
<li
v-if="slots.prefix"
@click="clickHandle()"
:class="modelValue === undefined || modelValue === null ? 'active' : ''"
class="cursor"
>
<slot name="prefix"> </slot>
</li>
<template v-for="(item, index) in data" :key="index">
<li
@click.prevent="clickHandle(item, index)"
:class="current === index ? 'active' : ''"
@click.prevent="clickHandle(item)"
:class="modelValue === item ? 'active' : ''"
class="cursor"
>
<slot :row="item" :index="index"> </slot>
@ -17,22 +25,27 @@
</div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import { ref, watch, useSlots } from 'vue'
const slots = useSlots()
defineOptions({ name: 'CommonList' })
const props = defineProps({
data: {
type: Array<any>,
default: () => []
withDefaults(
defineProps<{
modelValue?: any
data: Array<any>
}>(),
{
data: () => []
}
})
)
const emit = defineEmits(['click'])
const emit = defineEmits(['click', 'update:modelValue'])
const current = ref(0)
function clickHandle(row: any, index: number) {
current.value = index
function clickHandle(row?: any) {
emit('click', row)
emit('update:modelValue', row)
}
</script>
<style lang="scss" scoped>

View File

@ -242,5 +242,71 @@ export const iconMap: any = {
)
])
}
},
'app-all-menu': {
iconReader: () => {
return h('i', [
h(
'svg',
{
style: { height: '100%', width: '100%' },
viewBox: '0 0 20 20',
version: '1.1',
xmlns: 'http://www.w3.org/2000/svg'
},
[
h('path', {
d: 'M2.91683 2.0835H8.3335C8.79373 2.0835 9.16683 2.45659 9.16683 2.91683V8.3335C9.16683 8.79373 8.79373 9.16683 8.3335 9.16683H2.91683C2.45659 9.16683 2.0835 8.79373 2.0835 8.3335V2.91683C2.0835 2.45659 2.45659 2.0835 2.91683 2.0835ZM3.75016 3.75016V7.50016H7.50016V3.75016H3.75016Z',
fill: 'currentColor'
}),
h('path', {
d: 'M2.91683 10.8335H8.3335C8.79373 10.8335 9.16683 11.2066 9.16683 11.6668V17.0835C9.16683 17.5437 8.79373 17.9168 8.3335 17.9168H2.91683C2.45659 17.9168 2.0835 17.5437 2.0835 17.0835V11.6668C2.0835 11.2066 2.45659 10.8335 2.91683 10.8335ZM3.75016 16.2502H7.50016V12.5002H3.75016V16.2502Z',
fill: 'currentColor'
}),
h('path', {
d: 'M11.6668 2.0835H17.0835C17.5437 2.0835 17.9168 2.45659 17.9168 2.91683V8.3335C17.9168 8.79373 17.5437 9.16683 17.0835 9.16683H11.6668C11.2066 9.16683 10.8335 8.79373 10.8335 8.3335V2.91683C10.8335 2.45659 11.2066 2.0835 11.6668 2.0835ZM12.5002 7.50016H16.2502V3.75016H12.5002V7.50016Z',
fill: 'currentColor'
}),
h('path', {
d: 'M11.6668 10.8335H17.0835C17.5437 10.8335 17.9168 11.2066 17.9168 11.6668V17.0835C17.9168 17.5437 17.5437 17.9168 17.0835 17.9168H11.6668C11.2066 17.9168 10.8335 17.5437 10.8335 17.0835V11.6668C10.8335 11.2066 11.2066 10.8335 11.6668 10.8335ZM12.5002 12.5002V16.2502H16.2502V12.5002H12.5002Z',
fill: 'currentColor'
})
]
)
])
}
},
'app-all-menu-active': {
iconReader: () => {
return h('i', [
h(
'svg',
{
style: { height: '100%', width: '100%' },
viewBox: '0 0 20 20',
version: '1.1',
xmlns: 'http://www.w3.org/2000/svg'
},
[
h('path', {
d: 'M8.33317 1.6665H2.49984C2.0396 1.6665 1.6665 2.0396 1.6665 2.49984V8.33317C1.6665 8.79341 2.0396 9.1665 2.49984 9.1665H8.33317C8.79341 9.1665 9.1665 8.79341 9.1665 8.33317V2.49984C9.1665 2.0396 8.79341 1.6665 8.33317 1.6665Z',
fill: 'currentColor'
}),
h('path', {
d: 'M8.33317 10.8332H2.49984C2.0396 10.8332 1.6665 11.2063 1.6665 11.6665V17.4998C1.6665 17.9601 2.0396 18.3332 2.49984 18.3332H8.33317C8.79341 18.3332 9.1665 17.9601 9.1665 17.4998V11.6665C9.1665 11.2063 8.79341 10.8332 8.33317 10.8332Z',
fill: 'currentColor'
}),
h('path', {
d: 'M17.4998 1.6665H11.6665C11.2063 1.6665 10.8332 2.0396 10.8332 2.49984V8.33317C10.8332 8.79341 11.2063 9.1665 11.6665 9.1665H17.4998C17.9601 9.1665 18.3332 8.79341 18.3332 8.33317V2.49984C18.3332 2.0396 17.9601 1.6665 17.4998 1.6665Z',
fill: 'currentColor'
}),
h('path', {
d: 'M17.4508 10.8332H11.7155C11.2282 10.8332 10.8332 11.2282 10.8332 11.7155V17.4508C10.8332 17.9381 11.2282 18.3332 11.7155 18.3332H17.4508C17.9381 18.3332 18.3332 17.9381 18.3332 17.4508V11.7155C18.3332 11.2282 17.9381 10.8332 17.4508 10.8332Z',
fill: 'currentColor'
})
]
)
])
}
}
}

View File

@ -38,6 +38,7 @@ instance.interceptors.request.use(
//设置响应拦截器
instance.interceptors.response.use(
(response: any) => {
console.log('instance_response', response)
if (response.data) {
if (response.status !== 200 && !(response.data instanceof Blob)) {
MsgError(response.data.message)
@ -163,13 +164,27 @@ export const del: (
return promise(request({ url: url, method: 'delete', params, data }), loading)
}
export const postStream: (
url: string,
data?: unknown,
params?: unknown,
loading?: NProgress | Ref<boolean>
) => Promise<Result<any> | any> = (url, data, params, loading) => {
return request({ url: url, method: 'post', data, params, responseType: 'stream' })
/**
*
* @param url url地址
* @param data body
* @returns
*/
export const postStream: (url: string, data?: unknown) => Promise<Result<any> | any> = (
url,
data
) => {
const { user } = useStore()
const token = user.getToken()
const headers: HeadersInit = { 'Content-Type': 'application/json' }
if (token) {
headers['AUTHORIZATION'] = `${token}`
}
return fetch(url, {
method: 'POST',
body: data ? JSON.stringify(data) : undefined,
headers: headers
})
}
export const exportExcel: (

View File

@ -3,7 +3,22 @@
<div class="template-manage flex main-calc-height">
<div class="template-manage__left p-8 border-r">
<h4 class="p-16">供应商</h4>
<common-list :data="provider_list" class="mt-8" v-loading="loading" @click="clickHandle">
<common-list
v-model="active_provider"
:data="provider_list"
class="mt-8"
v-loading="loading"
>
<template #prefix>
<div class="flex">
<AppIcon
style="height: 24px; width: 24px"
class="mr-8"
:iconName="active_provider ? 'app-all-menu' : 'app-all-menu-active'"
></AppIcon>
<span>全部模型</span>
</div>
</template>
<template #default="{ row }">
<div class="flex">
<span :innerHTML="row.icon" alt="" style="height: 24px; width: 24px" class="mr-8" />
@ -14,7 +29,22 @@
</div>
<div class="template-manage__right p-24">
<h4>全部模型</h4>
<Demo></Demo>
<card-box :title="model.name" v-for="model in model_list">
<template #icon>
<AppAvatar
class="mr-12"
shape="square"
style="--el-avatar-bg-color: rgba(255, 255, 255, 0)"
:size="32"
>
<span style="height: 24px; width: 24px" :innerHTML="get_model_icon(model)"></span
></AppAvatar>
</template>
<template #description>
{{ model.model_type }}
{{ model.model_name }}
</template>
</card-box>
</div>
</div>
</LayoutContainer>
@ -23,16 +53,33 @@
<script lang="ts" setup>
import { onMounted, ref, reactive, watch } from 'vue'
import ModelApi from '@/api/model'
import type { Provider } from '@/api/type/model'
import type { Provider, Model } from '@/api/type/model'
import AppIcon from '@/components/icons/AppIcon.vue'
const loading = ref<boolean>(false)
const active_provider = ref<Provider>()
const provider_list = ref<Array<Provider>>([])
function clickHandle(row: any) {}
const get_model_icon = (model: Model) => {
return provider_list.value.find((p) => p.provider === model.provider)?.icon
}
const model_list = ref<Array<Model>>([])
watch(
active_provider,
() => {
ModelApi.getModel(
active_provider.value ? { provider: active_provider.value.provider } : {}
).then((ok) => {
model_list.value = ok.data
})
},
{
immediate: true
}
)
onMounted(() => {
ModelApi.getProvider(loading).then((ok) => {
provider_list.value = ok.data
provider_list.value = [...ok.data]
})
})
</script>