准备实现富文本编辑器
This commit is contained in:
parent
5a2a699a51
commit
ea44620dee
BIN
chi_sim.traineddata
Normal file
BIN
chi_sim.traineddata
Normal file
Binary file not shown.
BIN
eng.traineddata
Normal file
BIN
eng.traineddata
Normal file
Binary file not shown.
115
renderer/src/components/k-rich-textarea/index.vue
Normal file
115
renderer/src/components/k-rich-textarea/index.vue
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
<template>
|
||||||
|
<div class="k-rich-textarea">
|
||||||
|
<div
|
||||||
|
ref="editor"
|
||||||
|
contenteditable="true"
|
||||||
|
class="rich-editor"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
@input="handleInput"
|
||||||
|
@keydown.enter="handleKeydown"
|
||||||
|
@compositionstart="handleCompositionStart"
|
||||||
|
@compositionend="handleCompositionEnd"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, defineProps, defineEmits, watch } from 'vue';
|
||||||
|
import type { RichTextItem } from './textarea.dto';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: Array as () => RichTextItem[],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '输入消息...'
|
||||||
|
},
|
||||||
|
customClass: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue', 'pressEnter']);
|
||||||
|
|
||||||
|
const editor = ref<HTMLElement | null>(null);
|
||||||
|
|
||||||
|
const renderRichText = (items: RichTextItem[]) => {
|
||||||
|
return items.map(item => {
|
||||||
|
if (item.type === 'prompt' || item.type === 'resource') {
|
||||||
|
return `<span class="rich-item rich-item-${item.type}">${item.text}</span>`;
|
||||||
|
}
|
||||||
|
return item.text;
|
||||||
|
}).join('');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInput = (event: Event) => {
|
||||||
|
if (editor.value) {
|
||||||
|
console.log(editor.value);
|
||||||
|
|
||||||
|
const items: RichTextItem[] = [];
|
||||||
|
// 解析编辑器内容并转换为 RichTextItem[]
|
||||||
|
// ... 实现解析逻辑
|
||||||
|
emit('update:modelValue', items);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(() => props.modelValue, (newValue) => {
|
||||||
|
if (editor.value) {
|
||||||
|
editor.value.innerHTML = renderRichText(newValue);
|
||||||
|
}
|
||||||
|
}, { immediate: true });
|
||||||
|
|
||||||
|
const isComposing = ref(false);
|
||||||
|
|
||||||
|
const handleKeydown = (event: KeyboardEvent) => {
|
||||||
|
if (event.key === 'Enter' && !event.shiftKey && !isComposing.value) {
|
||||||
|
event.preventDefault();
|
||||||
|
emit('pressEnter', event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCompositionStart = () => {
|
||||||
|
isComposing.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCompositionEnd = () => {
|
||||||
|
isComposing.value = false;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.k-rich-textarea {
|
||||||
|
border-radius: .9em;
|
||||||
|
border: 1px solid #DCDFE6;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rich-editor {
|
||||||
|
min-height: 100px;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rich-editor:empty::before {
|
||||||
|
content: attr(placeholder);
|
||||||
|
color: #C0C4CC;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rich-item {
|
||||||
|
padding: 2px 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rich-item-prompt {
|
||||||
|
background-color: #e8f0fe;
|
||||||
|
color: #1a73e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rich-item-resource {
|
||||||
|
background-color: #f1f3f4;
|
||||||
|
color: #202124;
|
||||||
|
}
|
||||||
|
</style>
|
17
renderer/src/components/k-rich-textarea/textarea.dto.ts
Normal file
17
renderer/src/components/k-rich-textarea/textarea.dto.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
interface PromptTextItem {
|
||||||
|
type: 'prompt'
|
||||||
|
text: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ResourceTextItem {
|
||||||
|
type: 'resource'
|
||||||
|
text: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TextItem {
|
||||||
|
type: 'text'
|
||||||
|
text: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RichTextItem = PromptTextItem | ResourceTextItem | TextItem;
|
@ -59,6 +59,8 @@ function whenGetPromptResponse(msg: PromptsGetResponse) {
|
|||||||
try {
|
try {
|
||||||
const content = msg.messages[0].content;
|
const content = msg.messages[0].content;
|
||||||
|
|
||||||
|
selectPrompt.value = undefined;
|
||||||
|
|
||||||
if (content) {
|
if (content) {
|
||||||
emits('update:modelValue', props.modelValue + content);
|
emits('update:modelValue', props.modelValue + content);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<Model />
|
<Model />
|
||||||
<SystemPrompt />
|
<SystemPrompt />
|
||||||
<ToolUse />
|
<ToolUse />
|
||||||
<Prompt v-model="val" />
|
<Prompt v-model="modelValue" />
|
||||||
<Websearch />
|
<Websearch />
|
||||||
<Temperature />
|
<Temperature />
|
||||||
<ContextLength />
|
<ContextLength />
|
||||||
@ -11,7 +11,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineProps, provide, ref } from 'vue';
|
import { defineProps, defineEmits, provide, ref, computed } from 'vue';
|
||||||
import { llmManager } from '@/views/setting/llm';
|
import { llmManager } from '@/views/setting/llm';
|
||||||
import { tabs } from '../../panel';
|
import { tabs } from '../../panel';
|
||||||
import type { ChatSetting, ChatStorage } from '../chat';
|
import type { ChatSetting, ChatStorage } from '../chat';
|
||||||
@ -35,7 +35,17 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const val = ref('');
|
const emits = defineEmits(['update:modelValue']);
|
||||||
|
|
||||||
|
const modelValue = computed({
|
||||||
|
get() {
|
||||||
|
return props.modelValue;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
emits('update:modelValue', value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
const tab = tabs.content[props.tabId];
|
const tab = tabs.content[props.tabId];
|
||||||
const tabStorage = tab.storage as ChatStorage & { settings: ChatSetting };
|
const tabStorage = tab.storage as ChatStorage & { settings: ChatSetting };
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"currentIndex": 1,
|
"currentIndex": 0,
|
||||||
"tabs": [
|
"tabs": [
|
||||||
{
|
{
|
||||||
"name": "交互测试",
|
"name": "交互测试",
|
||||||
@ -9,50 +9,7 @@
|
|||||||
"storage": {
|
"storage": {
|
||||||
"messages": [],
|
"messages": [],
|
||||||
"settings": {
|
"settings": {
|
||||||
"modelIndex": 15,
|
"modelIndex": 0,
|
||||||
"enableTools": [
|
|
||||||
{
|
|
||||||
"name": "add",
|
|
||||||
"description": "对两个数字进行实数域的加法",
|
|
||||||
"enabled": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "multiply",
|
|
||||||
"description": "对两个数字进行实数域的乘法运算",
|
|
||||||
"enabled": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "is_even",
|
|
||||||
"description": "判断一个整数是否为偶数",
|
|
||||||
"enabled": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "capitalize",
|
|
||||||
"description": "将字符串首字母大写",
|
|
||||||
"enabled": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "get_weather_by_city_code",
|
|
||||||
"description": "根据城市天气预报的城市编码 (int),获取指定城市的天气信息",
|
|
||||||
"enabled": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"enableWebSearch": false,
|
|
||||||
"temperature": 0.7,
|
|
||||||
"contextLength": 20,
|
|
||||||
"systemPrompt": ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "交互测试",
|
|
||||||
"icon": "icon-robot",
|
|
||||||
"type": "blank",
|
|
||||||
"componentIndex": 3,
|
|
||||||
"storage": {
|
|
||||||
"messages": [],
|
|
||||||
"settings": {
|
|
||||||
"modelIndex": 15,
|
|
||||||
"enableTools": [
|
"enableTools": [
|
||||||
{
|
{
|
||||||
"name": "add",
|
"name": "add",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user