change the scope of blockModelSet from during process to during one time request; add the feature to specify a fixed model in test dialog

This commit is contained in:
geekgeekrun
2025-04-23 02:00:03 +08:00
parent bbd670b674
commit d23b0475dc
4 changed files with 177 additions and 43 deletions

View File

@@ -1,9 +1,9 @@
import { saveGptCompletionRequestRecord } from '@geekgeekrun/sqlite-plugin/dist/handlers'
export const RequestSceneEnum = {
testing: 1,
readNoReplyAutoReminder: 2,
geekAutoStartChatWithBoss: 3
export enum RequestSceneEnum {
testing = 1,
readNoReplyAutoReminder = 2,
geekAutoStartChatWithBoss = 3
}
let dbInitPromise

View File

@@ -555,7 +555,8 @@ export default function initIpc() {
})
async function requestLlm(_, requestPayload) {
return await requestNewMessageContent(requestPayload.messageList, {
requestScene: RequestSceneEnum.testing
requestScene: RequestSceneEnum.testing,
llmConfigIdForPick: requestPayload.llmConfigIdForPick ?? null
})
}
ipcMain.handle('request-llm-for-test', requestLlm)

View File

@@ -27,8 +27,7 @@ export const sendLookForwardReplyEmotion = async (page: Page) => {
await lookForwardReplyEmojiProxy!.click()
}
const blockModelSet = new Set()
const pickLlmConfigFromList = (llmConfigList) => {
const pickLlmConfigFromList = (llmConfigList, blockModelSet) => {
if (llmConfigList.length === 1) {
llmConfigList[0].enabled = true
llmConfigList[0].serveWeight = SINGLE_ITEM_DEFAULT_SERVE_WEIGHT
@@ -115,7 +114,13 @@ export const writeDefaultAutoRemindPrompt = async () => {
await writeStorageFile(autoReminderPromptTemplateFileName, defaultPrompt, { isJson: false })
}
export const requestNewMessageContent = async (chatRecords, { requestScene } = {}) => {
export const requestNewMessageContent = async (
chatRecords,
{
requestScene,
llmConfigIdForPick
}: { requestScene?: RequestSceneEnum; llmConfigIdForPick?: string[] } = {}
) => {
const template = await getValidTemplate()
const resumeObject = (await readConfigFile('resumes.json'))?.[0]
const resumeContent = formatResumeJsonToMarkdown(resumeObject)
@@ -151,9 +156,15 @@ export const requestNewMessageContent = async (chatRecords, { requestScene } = {
const llmRequestRecord: Omit<LlmModelUsageRecord, 'id' | 'providerApiSecretMd5'> & {
providerApiSecret: string
} = {}
const blockModelSet = new Set()
while (!res) {
const llmConfigList = await readConfigFile('llm.json')
llmConfig = pickLlmConfigFromList(llmConfigList)
let llmConfigList = await readConfigFile('llm.json')
if (llmConfigIdForPick?.length) {
llmConfigList = llmConfigList.filter((it) => {
return llmConfigIdForPick.includes(it.id)
})
}
llmConfig = pickLlmConfigFromList(llmConfigList, blockModelSet)
if (!llmConfig) {
throw new Error(`CANNOT_FIND_A_USABLE_MODEL`)
}

View File

@@ -1,41 +1,129 @@
<template>
<div class="h100vh flex flex-col">
<div
ref="scrollElRef"
:style="{
display: 'flex',
flexDirection: 'column',
flex: 1,
overflow: `auto`,
margin: `0 auto`,
alignItems: `flex-end`
alignItems: `flex-end`,
width: '100%'
}"
>
<div class="pb20px"></div>
<div v-for="(item, index) in messageList" :key="index" class="message-item">
{{ item.text }}
<div
v-if="messageList.length"
:style="{
width: '480px',
margin: '0 auto'
}"
>
<div class="pb20px"></div>
<div v-for="(item, index) in messageList" :key="index" flex flex-col flex-items-end>
<div class="message-item-wrap flex flex-col">
<div class="message-item">
{{ item.text }}
</div>
<div
:style="{
width: 'fit-content',
alignSelf: 'flex-end'
}"
font-size-10px
>
{{ item.usedLlmConfig.model }}
</div>
<div
v-if="item?.usedLlmConfig?.providerCompleteApiUrl?.trim()"
:style="{
width: 'fit-content',
overflow: 'hidden',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
alignSelf: 'flex-end',
color: '#bbb'
}"
font-size-10px
w-fit-content
max-w-20em
>
{{ item.usedLlmConfig.providerCompleteApiUrl }}
</div>
</div>
</div>
<div class="pb20px"></div>
</div>
<div v-else w-full h-full flex flex-item-center justify-center>
<el-empty>
<template #description>
<template v-if="!isLoading">
点击下方 <el-button
font-size-16px
h-fit-content
align-baseline
p0
type="text"
@click.prevent="sendLlmGeneratedContent"
>发送开场白</el-button
> 以开始模拟聊天
</template>
<template v-else>请稍候第一条消息正在回复的路上~</template>
</template>
</el-empty>
</div>
<div class="pb20px"></div>
</div>
<div
:style="{
display: 'grid',
gridTemplateColumns: '100px 1fr',
gridTemplateColumns: 'min-content 1fr min-content',
height: `fit-content`,
paddingTop: `10px`,
paddingBottom: `10px`,
backgroundColor: `#f0f0f0`
}"
>
<!-- <el-select v-model="selectedLlmConfig">
<el-option v-for="(it, index) in llmConfigList" :key="index" :label="it">
<div>{{ it.model }}</div>
<div>{{ it.providerCompleteApiUrl }}</div>
<el-select v-model="selectedLlmConfig" ml10px w160px placeholder="随机使用一个模型">
<el-option
v-for="(it, index) in llmConfigListForRender"
:key="index"
:value="it.id"
:label="it.model"
:disabled="!it.enabled"
:style="{
paddingTop: '10px',
paddingBottom: '10px',
height: 'auto',
lineHeight: '1.25em'
}"
>
<div
:style="{
display: 'flex',
justifyContent: 'space-between'
}"
>
<div>{{ it.model }}</div>
<div class="font-size-12px color-#bbb">
{{ formatApiSecret(it.providerApiSecret) || '' }}
</div>
</div>
<div
v-if="it?.providerCompleteApiUrl?.trim?.()"
:style="{
color: '#bbb',
width: '35em',
fontSize: '12px',
overflow: 'hidden',
textOverflow: 'ellipsis'
}"
>
{{ it.providerCompleteApiUrl }}
</div>
</el-option>
</el-select> -->
<el-button ml20px type="text" @click="closeWindow">关闭对话框</el-button>
</el-select>
<el-button
:loading="isLoading"
mr10px
width-fit-content
type="primary"
@click="sendLlmGeneratedContent"
@@ -44,38 +132,57 @@
<template v-else-if="!messageList.length">发送开场白</template>
<template v-else>发送下一句提醒内容</template>
</el-button>
<div></div>
<el-button mr10px type="text" @click="closeWindow">关闭对话框</el-button>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { computed, ref } from 'vue'
import { sleep } from '@geekgeekrun/utils/sleep.mjs'
type MessageItem = {
text: string
generatedBy: string
usedLlmConfig: string
// recordInfo: any
}
const messageList = ref<MessageItem[]>([])
// const llmConfigList = ref([])
// async function getLlmConfigList() {
// debugger
// llmConfigList.value = await electron.ipcRenderer.invoke('get-llm-config-for-test')
// }
// getLlmConfigList().catch(() => {})
// const selectedLlmConfig = ref()
const llmConfigList = ref([])
const llmConfigListForRender = computed(() => {
return [
{
id: null,
model: '随机使用一个模型',
providerCompleteApiUrl: null,
enabled: true
},
...(llmConfigList.value ?? [])
]
})
async function getLlmConfigList() {
llmConfigList.value = await electron.ipcRenderer.invoke('get-llm-config-for-test')
}
getLlmConfigList().catch(() => {})
const selectedLlmConfig = ref(null)
const scrollElRef = ref(null)
const isLoading = ref(false)
async function sendLlmGeneratedContent() {
isLoading.value = true
try {
const response = await electron.ipcRenderer.invoke('request-llm-for-test', {
messageList: JSON.parse(JSON.stringify(messageList.value ?? []))
messageList: JSON.parse(JSON.stringify(messageList.value ?? [])),
llmConfigIdForPick: selectedLlmConfig.value ? [selectedLlmConfig.value] : null
})
console.log(response)
messageList.value.push({
text: response.responseText,
generatedBy: response.usedLlmConfig
usedLlmConfig: response.usedLlmConfig
})
await sleep(50)
;(scrollElRef.value as any as HTMLDivElement)?.scrollTo({
top: scrollElRef.value?.scrollHeight,
behavior: 'smooth'
})
} finally {
isLoading.value = false
@@ -85,17 +192,32 @@ async function sendLlmGeneratedContent() {
function closeWindow() {
electron.ipcRenderer.send(`close-read-no-reply-reminder-llm-mock-window`)
}
function formatApiSecret(text) {
if (typeof text !== 'string' || !text?.trim()) {
return ''
}
if (text === 'ollama') {
return text
}
if (text.length >= 8) {
return `${text.slice(0, 4)}***${text.slice(-4)}`
}
return `***`
}
</script>
<style lang="scss" scoped>
.message-item {
line-height: 1.25em;
font-size: 14px;
background-color: #d1f0ef;
color: #333;
padding: 10px;
border-radius: 8px 8px 0 8px;
margin-top: 20px;
.message-item-wrap {
max-width: 420px;
margin-top: 20px;
.message-item {
line-height: 1.25em;
font-size: 14px;
background-color: #d1f0ef;
color: #333;
padding: 10px;
border-radius: 8px 8px 0 8px;
}
}
</style>