Compare commits

...

5 Commits

@ -12,9 +12,20 @@ type StyleGenerate struct {
// ai生成样式
func (s *StyleGenerate) StyleGenerate(c *gin.Context) {
if res, err := ai_model_cli.RequestStyle(c); err==nil {
response.Success(c, consts.CurdStatusOkMsg, res.(string))
} else {
// 非流式传输
// if res, err := ai_model_cli.RequestStyle(c); err==nil {
// response.Success(c, consts.CurdStatusOkMsg, res.(string))
// } else {
// response.Fail(c, consts.StyleGenerateFailCode, consts.StyleGenerateFailMsg, err)
// }
// 设置 HTTP 头部为 SSE
c.Writer.Header().Set("Content-Type", "text/event-stream")
c.Writer.Header().Set("Cache-Control", "no-cache")
c.Writer.Header().Set("Connection", "keep-alive")
if err := ai_model_cli.RequestStyleStream(c); err != nil {
response.Fail(c, consts.StyleGenerateFailCode, consts.StyleGenerateFailMsg, err)
}
}

@ -15,7 +15,7 @@ import (
func RequestStyle(c *gin.Context) (interface{}, error) {
// userMsg := c.PostForm("user_input")
userMsg:=c.GetString(consts.ValidatorPrefix+"user_input")
userMsg := c.GetString(consts.ValidatorPrefix + "user_input")
qianfan.GetConfig().AccessKey = variable.ConfigYml.GetString("BaiduCE.QianFanAccessKey")
qianfan.GetConfig().SecretKey = variable.ConfigYml.GetString("BaiduCE.QianFanSecretKey")
@ -29,35 +29,140 @@ func RequestStyle(c *gin.Context) (interface{}, error) {
// 读取prompt文件
systemMsgPath := variable.ConfigYml.GetString("BaiduCE.StyleGeneratePromptPath")
// 读取文件内容
prompt, err := os.ReadFile(variable.BasePath+systemMsgPath)
prompt, err := os.ReadFile(variable.BasePath + systemMsgPath)
if err != nil || len(prompt) == 0 {
variable.ZapLog.Error(fmt.Sprintf("读取提示词文件失败: %v", err))
return nil, err
}
// add user history to chat history
userHistory,exist := c.Get(consts.ValidatorPrefix+"chat_history")
if exist&&userHistory!=nil{
// TODO: check if userHistory is of type []struct{Role string;Content string}
userHistory := userHistory.([]struct{Role string;Content string})
if len(userHistory)%2!=0{
userHistory, exist := c.Get(consts.ValidatorPrefix + "chat_history")
if exist && userHistory != nil {
// check if userHistory is of type []struct{Role string;Content string}
historySlice, ok := userHistory.([]interface{})
if !ok || len(historySlice)%2 != 0 {
variable.ZapLog.Error(fmt.Sprintf("用户历史对话格式错误: %v", userHistory))
return nil, fmt.Errorf("用户历史对话格式错误")
}
for _,msg := range userHistory{
chatHistory = append(chatHistory, qianfan.ChatCompletionMessage{Role:msg.Role,Content:msg.Content})
// convert userHistory to []qianfan.ChatCompletionMessage
var chatHistoryConverted []qianfan.ChatCompletionMessage
for _, item := range historySlice {
if itemMap, ok := item.(map[string]interface{}); ok {
role, roleOk := itemMap["role"].(string)
content, contentOk := itemMap["content"].(string)
if roleOk && contentOk {
chatHistoryConverted = append(chatHistoryConverted, qianfan.ChatCompletionMessage{
Role: role,
Content: content,
})
} else {
variable.ZapLog.Error(fmt.Sprintf("用户历史对话格式错误: %v\nrole 或 content 类型断言失败", userHistory))
return nil, fmt.Errorf("用户历史对话格式错误")
}
} else {
variable.ZapLog.Error(fmt.Sprintf("用户历史对话格式错误: %v\n无法将 item 转换为 map[string]interface{}", userHistory))
return nil, fmt.Errorf("用户历史对话格式错误")
}
}
if len(chatHistoryConverted) > 0 && len(chatHistoryConverted)%2 == 0 {
chatHistory = append(chatHistory, chatHistoryConverted...)
}
}
// add user input to chat history
chatHistory = append(chatHistory, qianfan.ChatCompletionUserMessage(userMsg))
// define a stream chat client
response,err:=chat.Do(context.TODO(),&qianfan.ChatCompletionRequest{System: string(prompt),Messages: chatHistory})
response, err := chat.Do(context.TODO(), &qianfan.ChatCompletionRequest{System: string(prompt), Messages: chatHistory})
if err != nil {
variable.ZapLog.Error(fmt.Sprintf("对话失败: %v", err))
return nil, err
}
return response.Result, nil
}
func RequestStyleStream(c *gin.Context) error {
userMsg := c.GetString(consts.ValidatorPrefix + "user_input")
qianfan.GetConfig().AccessKey = variable.ConfigYml.GetString("BaiduCE.QianFanAccessKey")
qianfan.GetConfig().SecretKey = variable.ConfigYml.GetString("BaiduCE.QianFanSecretKey")
chat := qianfan.NewChatCompletion(
qianfan.WithModel("ERNIE-4.0-8K"),
)
chatHistory := []qianfan.ChatCompletionMessage{}
systemMsgPath := variable.ConfigYml.GetString("BaiduCE.StyleGeneratePromptPath")
prompt, err := os.ReadFile(variable.BasePath + systemMsgPath)
if err != nil || len(prompt) == 0 {
variable.ZapLog.Error(fmt.Sprintf("读取提示词文件失败: %v", err))
return err
}
userHistory, exist := c.Get(consts.ValidatorPrefix + "chat_history")
if exist && userHistory != nil {
historySlice, ok := userHistory.([]interface{})
if !ok || len(historySlice)%2 != 0 {
variable.ZapLog.Error(fmt.Sprintf("用户历史对话格式错误: %v", userHistory))
return fmt.Errorf("用户历史对话格式错误")
}
var chatHistoryConverted []qianfan.ChatCompletionMessage
for _, item := range historySlice {
if itemMap, ok := item.(map[string]interface{}); ok {
role, roleOk := itemMap["role"].(string)
content, contentOk := itemMap["content"].(string)
if roleOk && contentOk {
chatHistoryConverted = append(chatHistoryConverted, qianfan.ChatCompletionMessage{
Role: role,
Content: content,
})
} else {
variable.ZapLog.Error(fmt.Sprintf("用户历史对话格式错误: %v\nrole 或 content 类型断言失败", userHistory))
return fmt.Errorf("用户历史对话格式错误")
}
} else {
variable.ZapLog.Error(fmt.Sprintf("用户历史对话格式错误: %v\n无法将 item 转换为 map[string]interface{}", userHistory))
return fmt.Errorf("用户历史对话格式错误")
}
}
if len(chatHistoryConverted) > 0 && len(chatHistoryConverted)%2 == 0 {
chatHistory = append(chatHistory, chatHistoryConverted...)
}
}
chatHistory = append(chatHistory, qianfan.ChatCompletionUserMessage(userMsg))
stream, err := chat.Stream(context.TODO(), &qianfan.ChatCompletionRequest{System: string(prompt), Messages: chatHistory})
if err != nil {
variable.ZapLog.Error(fmt.Sprintf("对话失败: %v", err))
return err
}
defer stream.Close()
c.Writer.Flush()
defer c.Writer.Flush()
for {
response, err := stream.Recv()
if response.IsEnd {
break // 流结束,退出循环
}
if err != nil {
variable.ZapLog.Error(fmt.Sprintf("接收流失败: %v", err))
return err
}
// 将结果写入到响应体
if _,err:=fmt.Fprintf(c.Writer,"%s",response.Result);err!=nil{
variable.ZapLog.Error(fmt.Sprintf("写入流失败: %v", err))
return err
}
// 立即刷新缓冲区,以确保数据立即发送到客户端
c.Writer.Flush()
}
return nil // 正常结束,返回 nil
}

@ -148,6 +148,9 @@ Captcha:
BaiduCE:
ApiKey: "AR1SUIjaKSsCcDjj11QzHDOc" # 生成鉴权签名时使用的 API_KEY
SecretKey: "zvEb5CzpuGCZNdQC1TPmDh3IOWn5aWDT" # 生成鉴权签名时使用的 SECRET_KEY
QianFanAccessKey: "ALTAKOxb5YvHncyFr7Qbuv1cK0" # 访问千帆sdk 时用的 AccessKey
QianFanSecretKey: "1edf17c358574e75b9913ebff7d95b61" # 访问千帆sdk 时用的 SecretKey
# QianFanAccessKey: "ALTAKOxb5YvHncyFr7Qbuv1cK0" # 访问千帆sdk 时用的 AccessKey
QianFanAccessKey: "ALTAK0utWNCwEoQtGHvHYf46yj"
# QianFanSecretKey: "1edf17c358574e75b9913ebff7d95b61" # 访问千帆sdk 时用的 SecretKey
QianFanSecretKey: "cb812e1b6e56420ea858d160e1351869"
StyleGeneratePromptPath: "/storage/app/prompt/style_generate.prompt" # 生成样式的提示词保存路径

@ -1,11 +1,11 @@
### 角色
你是一个设计和 CSS 专家,能够根据用户需求生成精确的 CSS 样式。 如果用户提出与生成CSS样式无关的问题请回答“对不起我无法回答该问题”
### 任务
为以下元素生成 CSS 样式类
你是一个设计和 CSS 专家,能够根据用户需求生成精确的 CSS 样式。只能使用css来生成对应的样式不能修改页面的html代码和使用js代码。 如果用户提出与生成CSS样式无关的问题请回答“对不起我无法回答该问题”
### 知识
不同的样式对应的element如下
标题:<hi>i为标题级别如 h1, h2 等)
文本块:<p>
块引用:<blockquote>
文本:<span>
文本:<span>
代码块:<pre>
所有样式都需在 .ck-content 中定义,格式为:
``` css
@ -14,8 +14,11 @@
[element为不同样式类对应的元素名如文本框对应的element为p]
### 输出
仅输出你编写的 CSS 内容,不要对其进行解释和输出其他内容。!important
只需要精确输出用户需要生成的样式,不要生成用户未指定的样式。
### 示例
生成一个文本块样式,生成的样式如下所示。
#### 示例一
用户输入:生成一个文本块(文本框)样式
输出:
``` css
.ck-content p.info-box {
--background-size: 30px;
@ -28,7 +31,10 @@
box-shadow: 5px 5px 0 #ffe6ef;
}
```
生成一个代码框样式,生成的样式如下所示:
#### 示例二
用户输入:生成一个代码框样式
输出:
```css
.ck-content pre.fancy-code {
border: 0;
@ -52,7 +58,10 @@
box-shadow: 5px 5px 0 #0000001f;
}
```
生成一个块引用样式,生成的样式如下所示
#### 示例三
用户输入:生成一个块引用样式
输出:
```css
.ck-content blockquote.side-quote {
font-family: 'Oswald';
@ -88,4 +97,4 @@
text-align: right;
color: #555;
}
```
```

@ -2,11 +2,7 @@ import { createApp } from 'vue';
import '../public/style.css';
import App from './App.vue';
import { CkeditorPlugin } from '@ckeditor/ckeditor5-vue';
import mitt from 'mitt';
const app = createApp(App);
const emitter = mitt();
app.config.globalProperties.emitter = emitter;
app.use(CkeditorPlugin);
app.mount('#app');

@ -5,9 +5,7 @@
<div class="file-item-icon" >
<img src="@/assets/file_icon.png" alt="">
</div>
<FileTitle>
{{ item.name }}
</FileTitle>
<FileTitle @leftclick="leftclick" @changetitlestate="changetitlestate" @changetitle="changetitle" :item="item" />
</div>
</template>
@ -45,10 +43,24 @@ export default {
const doubleclick = () => {
context.emit('open_file');
}
const changetitlestate = () => {
context.emit('changetitle',props.item);
}
const changetitle = (newname) => {
context.emit('changetitle',{
item:props.item,
newname,
});
}
return {
leftclick,
rightclick,
doubleclick,
changetitle,
changetitlestate,
}
}
}
@ -69,16 +81,6 @@ export default {
height: 6vw;
}
.file-item-title{
width: 6vw;
height: 4vw;
text-align: center;
overflow: hidden;
font-size: 1.2vw;
word-break: break-all;
}
.file-item-selected {
border: 0.1vh solid #99d1ff;
background: #cce8ff;

@ -1,31 +1,51 @@
<template>
<div class="file-item-title">
<slot></slot>
<div class="file-item-title" @click.stop="titleclick">
<input v-if="item.editable" @click.stop="" @dblclick.stop="" type="text" v-model="filename"/>
<div v-else >
{{ filename }}
</div>
</div>
</template>
<script>
import { computed, ref } from 'vue';
export default {
name: 'FileTitle',
props:{
item:{
type:Object,
required:true,
}
},
setup(props,context){
let filename = ref(props.item.name);
let d = computed(() => {
if (!props.item.editable) {
context.emit("changetitle",filename.value);
}
return false;
});
const titleclick = () => {
if (props.item.is_selected) {
context.emit("changetitlestate");
}
else {
context.emit("leftclick");
}
}
return {
titleclick,
filename,
d,
}
}
}
</script>
<style scoped>
.file-item {
width: 8vw;
height: 8vw;
overflow: hidden;
display: inline-block;
margin: 0 0.1vw 1vw 0.1vw;
border: 0.1vh solid white;
}
.file-item-icon > img {
width: 6vw;
height: 6vw;
}
.file-item-title{
width: 6vw;
@ -40,4 +60,11 @@ export default {
border: 0.1vh solid #99d1ff;
background: #cce8ff;
}
input {
width: 6vw;
height: 1.8vw;
overflow: hidden;
font-size: 1.2vw;
}
</style>

@ -5,9 +5,7 @@
<div class="file-item-icon" >
<img src="@/assets/folder_icon.png" alt="">
</div>
<FileTitle>
{{ item.name }}
</FileTitle>
<FileTitle @leftclick="leftclick" @changetitle="changetitle" :item="item" />
</div>
</template>
@ -49,10 +47,15 @@ export default {
context.emit('ls');
}
const changetitle = () => {
context.emit('changetitle',props.item);
}
return {
leftclick,
rightclick,
doubleclick,
changetitle,
}
}
}

@ -38,7 +38,7 @@ import {
LinkImage,
List,
ListProperties,
Markdown,
// Markdown,
MediaEmbed,
Mention,
PageBreak,
@ -82,7 +82,8 @@ import {
getStyle,
getPageContent,
getUserConfigFromBackend,
saveData
saveData,
// markdown2html
} from './utils';
// 导出为docx插件
@ -418,7 +419,7 @@ function setConfig() {
LinkImage,
List,
ListProperties,
Markdown,
// Markdown,
MediaEmbed,
Mention,
PageBreak,

@ -1,5 +1,5 @@
// utils.js
import { MarkdownToHtml } from '@ckeditor/ckeditor5-markdown-gfm/src/markdown2html/markdown2html.js';
// 获取用户配置
export function getUserConfigFromBackend() {
// TODO 请求用户配置
@ -101,6 +101,7 @@ export function saveData(data) {
// resolve();
// }, HTTP_SERVER_LAG );
// } );
console.log('saving...');
console.log(data);
}
@ -121,9 +122,10 @@ export function getStyle() {
// 获取用户编辑的内容 <html>
export function getPageContent() {
const pageContent =document.querySelector("#app > div > div > div.editor-container.editor-container_document-editor.editor-container_include-style > div.editor-container__editor-wrapper > div > div");
return window.editor.getData();
// const pageContent =document.querySelector("#app > div > div > div.editor-container.editor-container_document-editor.editor-container_include-style > div.editor-container__editor-wrapper > div > div");
// const pageContent = document.querySelector("#app > div > div > div > div.editor-container__editor-wrapper > div > div > div");
return pageContent.outerHTML;
// return pageContent.outerHTML;
}
// 获取并应用用户定义的样式
@ -136,3 +138,12 @@ export function getAndApplyUserStyles() {
document.head.appendChild(styleElement);
return styles;
}
// markdown转html 便于将大语言模型的输出一般为markdown格式转换为ckeditor的html格式
// 利用ckeditor markdown插件但不能在CkeditorView.vue中使用
// 否则会改变编辑器数据处理器为markdown即getData()需要传入markdown stringsetData()返回markdown string
export function markdown2html(markdownString){
const markdownToHtml = new MarkdownToHtml();
const htmlString = markdownToHtml.parse(markdownString);
return htmlString;
}

@ -3,7 +3,7 @@
position: fixed;
top: 0;
left: 0;
width: 350px;
width: 450px;
height: 100%;
overflow-y: hidden;
transition: transform 0.3s ease;

@ -1,4 +1,5 @@
import $ from 'jquery';
// import $ from 'jquery';
import axios from 'axios';
const ModulerUser = {
state: {
@ -37,38 +38,40 @@ const ModulerUser = {
},
actions: {
login(context,data){
$.ajax({
url:'http://47.106.113.194:8000/token/',
type:'POST',
axios({
url:'http://1.94.171.222:8000/token/',
method:'POST',
data:{
username:data.username,
password:data.password,
},
success:resp => {
const {access,refresh} = resp;
$.ajax({
url:' http://47.106.113.194:8000/getinfo/',
type:'GET',
})
.then(resp => {
const {access,refresh} = resp.data;
axios({
url:'http://1.94.171.222:8000/getinfo/',
method:'GET',
headers:{
'Authorization': "Bearer " + access,
},
success(resp){
})
.then(resp => {
context.commit('updateUser',{
...resp,
username:resp.data.username,
access:access,
refresh:refresh,
is_login: true,
});
context.commit('forwardPath',"~/users/" + resp.username + '/'
context.commit('forwardPath',resp.data.username + '/'
);
data.success();
}
});
},
error(){
);
})
.catch(() => {
data.error();
}
});
);
}
},
modules: {

@ -297,7 +297,6 @@ import { setConfig } from '../components/plugins'
// import {getUserConfigFromBackend,saveData,getPageContent,getAndApplyUserStyles} from './components/utils';
import { useStore } from 'vuex';
import router from '../router/index.js';
import axios from 'axios';
export default {
name: 'CkeditorView',
@ -327,7 +326,6 @@ export default {
wordSpacing: ''
},
previewStyle: {},
messages: [], //
};
},
mounted() {
@ -347,6 +345,7 @@ export default {
// pageContent
// TODO
editor.setData(pageContent);
window.editor = editor;
},
// sidebar
// /
@ -395,10 +394,6 @@ export default {
displayMessage(text, sender) {
const messagesDiv = document.getElementById('messages');
// messages
const previousButtonsMessage = messagesDiv.querySelectorAll('.preview-buttons');
previousButtonsMessage.forEach(buttons => buttons.remove());
const messageDiv = document.createElement('div');
messageDiv.className = 'message';
// 使 pre text
@ -412,128 +407,214 @@ export default {
// TODO css
preElement.textContent = `文心一言:\n` + preElement.textContent;
messageDiv.style.backgroundColor = '#bdc3c7';
// preview
const previewWrapper = document.createElement('div');
previewWrapper.style.border = '1px solid #ccc';
previewWrapper.style.display = 'flow-root';
// 'preview'
const previewLabel = document.createElement('div');
previewLabel.textContent = 'preview';
previewWrapper.appendChild(previewLabel);
//
const previewStyle = document.createElement('style');
//
// csscss,css,}
const cssRegex = /css([\s\S]*)\}/;
const cssMatch = cssRegex.exec(text);
if (cssMatch) {
previewStyle.textContent = cssMatch[0].replace('css', '');
} else {
previewStyle.textContent = text;
}
previewStyle.textContent = previewStyle.textContent.replace(/\.ck-content/g, '');
document.head.appendChild(previewStyle);
//
let previewElement;
// element tag class name
const styleRegex = /\.ck-content\s+([a-z]+)\.([a-z-]+)\s*\{/g;
let match;
const classNames = [];
while ((match = styleRegex.exec(text)) !== null) {
if (!previewElement) {
previewElement = document.createElement(match[1]);
previewElement.textContent = 'AaBbCcDdEeFf';
previewWrapper.appendChild(previewElement);
}
classNames.push(match[2]);
}
if (previewElement) {
previewElement.className = classNames.join(' ');
}
messagesDiv.appendChild(previewWrapper);
//
const buttonsMessageDiv = document.createElement('div');
buttonsMessageDiv.className = 'preview-buttons';
buttonsMessageDiv.style.display = 'flex';
buttonsMessageDiv.style.justifyContent = 'flex-end';
buttonsMessageDiv.style.marginTop = '10px';
// save
const saveButton = document.createElement('el-button');
saveButton.innerHTML = '<svg t="1731509644125" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6346" width="20" height="20"><path d="M512 1024C229.248 1024 0 794.752 0 512S229.248 0 512 0s512 229.248 512 512-229.248 512-512 512z m0-938.666667C276.352 85.333333 85.333333 276.352 85.333333 512s191.018667 426.666667 426.666667 426.666667 426.666667-191.018667 426.666667-426.666667S747.648 85.333333 512 85.333333z m-3.413333 611.541334a34.944 34.944 0 0 1-9.386667 16.682666 38.058667 38.058667 0 0 1-30.72 11.050667 38.954667 38.954667 0 0 1-40.106667-27.946667L308.053333 576.426667a38.4 38.4 0 0 1 54.186667-54.229334l93.013333 93.184 190.293334-337.365333a42.666667 42.666667 0 0 1 58.88-16.426667c20.608 12.714667 27.392 39.466667 15.36 60.458667l-211.2 374.826667z" fill="#000000" p-id="6347"></path></svg>';
saveButton.style.marginLeft = '10px';
saveButton.style.width = '40px';
saveButton.style.height = '40px';
saveButton.onclick = () => {
// save
// TODO
// 使style
// styleDefinition:[name: 'styleName',element: 'element',classes: [className]]
const styleName = prompt("请输入样式名称:");
// styleDefiniton
const styleDefinition = {
name: styleName,
element: previewElement.tagName,
classes: classNames
};
console.log(styleDefinition);
};
// clear
const clearButton = document.createElement('el-button');
clearButton.innerHTML = '<svg t="1731509926355" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8154" width="20" height="20"><path d="M1011.43552 981.92384l-68.4032-394.40384h23.10144c18.5856 0 33.54624-14.97088 33.54624-33.55648V306.16576c0-18.5856-14.97088-33.55648-33.54624-33.55648H648.6528V37.71392c0-18.5856-14.97088-33.55648-33.55648-33.55648H408.59648c-18.5856 0-33.55648 14.97088-33.55648 33.55648v234.88512H57.5488c-18.5856 0-33.54624 14.97088-33.54624 33.55648v247.79776c0 18.5856 14.97088 33.55648 33.54624 33.55648h23.10144L12.24704 981.9136c-0.38912 1.9456-0.512 3.87072-0.512 5.6832 0 18.5856 14.97088 33.54624 33.55648 33.54624h933.10976c1.93536 0 3.88096-0.12288 5.6832-0.512 18.31936-3.08224 30.57664-20.51072 27.35104-38.7072zM114.33984 362.94656h351.03744V94.50496h92.928v268.4416h351.03744v134.22592H114.33984V362.94656zM718.336 930.816V729.48736c0-5.6832-4.64896-10.33216-10.32192-10.33216h-61.952c-5.67296 0-10.32192 4.64896-10.32192 10.33216V930.816H387.9424V729.48736c0-5.6832-4.64896-10.33216-10.32192-10.33216h-61.952c-5.67296 0-10.32192 4.64896-10.32192 10.33216V930.816H112.78336l58.20416-335.55456h681.5744L910.76608 930.816H718.336z m0 0" fill="#2C2C2C" p-id="8155"></path></svg>';
clearButton.style.marginLeft = '10px';
clearButton.style.width = '40px';
clearButton.style.height = '40px';
clearButton.onclick = () => {
// clear message
const messagesDiv = document.getElementById('messages');
while (messagesDiv.firstChild) {
messagesDiv.removeChild(messagesDiv.firstChild);
}
// style
document.head.removeChild(previewStyle);
};
//
buttonsMessageDiv.appendChild(saveButton);
buttonsMessageDiv.appendChild(clearButton);
messagesDiv.appendChild(buttonsMessageDiv);
}
// messagesDiv.scrollTop = messagesDiv.scrollHeight;
return preElement;
},
sendMessage() {
//
async sendMessage() {
const userInput = document.getElementById('userInput');
const messageText = userInput.value;
if (messageText.trim() === '') return;
//
let chatHistory = [];
const messages = document.getElementById('messages').children;
for (let i = 0; i < messages.length; i++) {
if (i % 4 == 0) {
chatHistory.push({ Role: 'user', Content: messages[i].textContent });
} else if (i % 4 == 1) {
const assistantResponse = messages[i].textContent.replaceAll('文心一言:\n', '');
chatHistory.push({ Role: 'assistant', Content: assistantResponse });
}
}
console.log(chatHistory);
// Display user's message
this.displayMessage(messageText, 'user');
// APIresponse
// messages
// TODO
chat_history = []
// const chat_history = []
try {
const response = await fetch('http://localhost:14514/admin/ai_layout/style_generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
user_input: userInput.value,
...(chatHistory.length > 0 && { chat_history: chatHistory })
})
});
axios({
url:'http://localhost:14514/admin/ai_layout/style_generate',
method: 'POST',
data:{
user_input: userInput.value
if (!response.body) {
// TODO
throw new Error('No response body');
}
})
.then(response => {
// let formatedResponse = response.data.response;
// this.displayMessage(formatedResponse, 'ai');
console.log(response);
this.displayMessage(response.data.data,'ai')
})
.catch(error => {
console.error('Error:', error);
});
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
let result = '';
var messageStream;
/* eslint-disable no-constant-condition */
while (true) {
const { done, value } = await reader.read();
if (done) break;
const slice = decoder.decode(value, { stream: true });
result += slice;
if (!messageStream) {
messageStream = this.displayMessage(slice, 'ai');
} else {
messageStream.textContent += slice;
}
}
console.log('生成的样式:', result);
//
this.previewStyleAtMessages(result);
/* eslint-enable no-constant-condition */
} catch (error) {
console.error('Error:', error);
this.displayError(error);
}
//
userInput.value = '';
},
//
previewStyleAtMessages(style) {
const messagesDiv = document.getElementById('messages');
// preview
const previewWrapper = document.createElement('div');
previewWrapper.style.border = '1px solid #ccc';
previewWrapper.style.display = 'flow-root';
messagesDiv.appendChild(previewWrapper);
// 'preview'
const previewLabel = document.createElement('div');
previewLabel.textContent = 'preview';
previewWrapper.appendChild(previewLabel);
//
const previewStyle = document.createElement('style');
//
// csscss,css,}
const cssRegex = /```css\n([\s\S]*?)```/;
const cssMatch = cssRegex.exec(style);
let cssText; // css
// css
if (cssMatch) {
cssText = cssMatch[0].replace('css', '').replaceAll('```', '');
} else {
cssText = style;
}
previewStyle.textContent = cssText.replace(/\.ck-content/g, '');
previewWrapper.appendChild(previewStyle);
//
let previewElement;
// element tag class name
const styleRegex = /\.ck-content\s+([a-z]+)\.([a-z-]+)\s*\{/g;
let match;
const classNames = [];
while ((match = styleRegex.exec(cssText)) !== null) {
if (!previewElement) {
previewElement = document.createElement(match[1]);
if (match[1] === 'span') {
previewElement.textContent = 'AaBbCcDdEeFf';
} else {
const previewText = document.createElement('p');
previewText.textContent = 'AaBbCcDd';
previewElement.appendChild(previewText);
}
previewWrapper.appendChild(previewElement);
}
// classNameclass
const newClassName = match[2] + "_" + Math.floor(Math.random() * 1000);
previewStyle.textContent = previewStyle.textContent.replaceAll(match[2], newClassName);
classNames.push(newClassName);
}
if (previewElement) {
previewElement.className = classNames.join(' ');
}
//
const buttonsMessageDiv = document.createElement('div');
buttonsMessageDiv.className = 'preview-buttons';
buttonsMessageDiv.style.display = 'flex';
buttonsMessageDiv.style.justifyContent = 'flex-end';
buttonsMessageDiv.style.marginTop = '10px';
// save
const saveButton = document.createElement('el-button');
saveButton.innerHTML = '<svg t="1731509644125" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6346" width="20" height="20"><path d="M512 1024C229.248 1024 0 794.752 0 512S229.248 0 512 0s512 229.248 512 512-229.248 512-512 512z m0-938.666667C276.352 85.333333 85.333333 276.352 85.333333 512s191.018667 426.666667 426.666667 426.666667 426.666667-191.018667 426.666667-426.666667S747.648 85.333333 512 85.333333z m-3.413333 611.541334a34.944 34.944 0 0 1-9.386667 16.682666 38.058667 38.058667 0 0 1-30.72 11.050667 38.954667 38.954667 0 0 1-40.106667-27.946667L308.053333 576.426667a38.4 38.4 0 0 1 54.186667-54.229334l93.013333 93.184 190.293334-337.365333a42.666667 42.666667 0 0 1 58.88-16.426667c20.608 12.714667 27.392 39.466667 15.36 60.458667l-211.2 374.826667z" fill="#000000" p-id="6347"></path></svg>';
saveButton.style.marginLeft = '10px';
saveButton.style.width = '40px';
saveButton.style.height = '40px';
saveButton.onclick = () => {
// save
// TODO
// 使style
// styleDefinition:[name: 'styleName',element: 'element',classes: [className]]
const styleName = prompt("请输入样式名称:");
// styleDefiniton
const styleDefinition = {
name: styleName,
element: previewElement.tagName,
classes: classNames
};
console.log(styleDefinition);
console.log(cssText);// css
};
//
buttonsMessageDiv.appendChild(saveButton);
buttonsMessageDiv.appendChild(this.createClearButton());
messagesDiv.appendChild(buttonsMessageDiv);
},
//
displayError(error) {
const messagesDiv = document.getElementById('messages');
const messageDiv = document.createElement('div');
messageDiv.className = 'message';
//
messageDiv.style.backgroundColor = 'mistyrose'; // mistyrose
// 使 pre text
// css htmlpre set language
const preElement = document.createElement('pre');
//
preElement.textContent = error;
preElement.style = "color:red";
messageDiv.appendChild(preElement);
messagesDiv.appendChild(messageDiv);
//
const buttonsMessageDiv = document.createElement('div');
buttonsMessageDiv.className = 'preview-buttons';
buttonsMessageDiv.style.display = 'flex';
buttonsMessageDiv.style.justifyContent = 'flex-end';
buttonsMessageDiv.style.marginTop = '10px';
buttonsMessageDiv.appendChild(this.createClearButton());
messagesDiv.appendChild(buttonsMessageDiv);
},
createClearButton() {
// clear
const clearButton = document.createElement('el-button');
clearButton.innerHTML = '<svg t="1731509926355" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8154" width="20" height="20"><path d="M1011.43552 981.92384l-68.4032-394.40384h23.10144c18.5856 0 33.54624-14.97088 33.54624-33.55648V306.16576c0-18.5856-14.97088-33.55648-33.54624-33.55648H648.6528V37.71392c0-18.5856-14.97088-33.55648-33.55648-33.55648H408.59648c-18.5856 0-33.55648 14.97088-33.55648 33.55648v234.88512H57.5488c-18.5856 0-33.54624 14.97088-33.54624 33.55648v247.79776c0 18.5856 14.97088 33.55648 33.54624 33.55648h23.10144L12.24704 981.9136c-0.38912 1.9456-0.512 3.87072-0.512 5.6832 0 18.5856 14.97088 33.54624 33.55648 33.54624h933.10976c1.93536 0 3.88096-0.12288 5.6832-0.512 18.31936-3.08224 30.57664-20.51072 27.35104-38.7072zM114.33984 362.94656h351.03744V94.50496h92.928v268.4416h351.03744v134.22592H114.33984V362.94656zM718.336 930.816V729.48736c0-5.6832-4.64896-10.33216-10.32192-10.33216h-61.952c-5.67296 0-10.32192 4.64896-10.32192 10.33216V930.816H387.9424V729.48736c0-5.6832-4.64896-10.33216-10.32192-10.33216h-61.952c-5.67296 0-10.32192 4.64896-10.32192 10.33216V930.816H112.78336l58.20416-335.55456h681.5744L910.76608 930.816H718.336z m0 0" fill="#2C2C2C" p-id="8155"></path></svg>';
clearButton.style.marginLeft = '10px';
clearButton.style.width = '40px';
clearButton.style.height = '40px';
clearButton.onclick = () => {
// clear message
const messagesDiv = document.getElementById('messages');
while (messagesDiv.firstChild) {
messagesDiv.removeChild(messagesDiv.firstChild);
}
};
return clearButton;
}
},
components: {
//

@ -2,15 +2,14 @@
<PathBar @ls="ls" />
<ContentBase @click="leftclick" @contextmenu.prevent="rightclick($event)">
<div v-for="item in items" :key="item.name" class="file-item">
<FolderFiled @select_item='select_item' @filerightclick="filerightclick" @fileleftclick="fileleftclick" @ls="ls" v-if="item.type==='folder'" :item="item" />
<FileFiled @select_item='select_item' @filerightclick="filerightclick" @fileleftclick="fileleftclick" @open_file='open_file' v-if="item.type==='file'" :item="item" />
<FolderFiled @changetitlestate="changetitlestate" @changetitle="changetitle" @select_item='select_item' @filerightclick="filerightclick" @fileleftclick="fileleftclick" @ls="ls" v-if="item.type==='folder'" :item="item" />
<FileFiled @changetitlestate="changetitlestate" @changetitle="changetitle" @select_item='select_item' @filerightclick="filerightclick" @fileleftclick="fileleftclick" @open_file='open_file' v-if="item.type==='file'" :item="item" />
</div>
<RightMenu v-if="menuvisible" @open_file="open_file" @turn_back="turn_back" :menutype="menutype" :menuposition="menuposition" />
</ContentBase>
</template>
<script>
import $ from 'jquery';
import ContentBase from '../components/ContentBase';
import FileFiled from '../components/FileFiled';
import FolderFiled from '../components/FolderFiled';
@ -19,6 +18,7 @@ import PathBar from '../components/PathBar.vue';
import { ref } from 'vue';
import { useStore } from 'vuex';
import router from '@/router/index.js';
import axios from 'axios';
export default {
@ -44,28 +44,35 @@ export default {
const ls = () => {
menuvisible.value = false;
$.ajax({
url:' http://47.106.113.194:8000/operation/command/ls/',
axios({
url:' http://1.94.171.222:8000/operation/command/ls/',
type:'get',
data:{
params:{
'path':store.state.user.path.join(""),
},
success:resp => {
})
.then(resp => {
let tmp = [];
for (let i = 0;i < resp.items.length;i++) {
let item = resp.items[i];
for (let i = 0;i < resp.data.items.length;i++) {
let item = resp.data.items[i];
item.is_selected = false;
item.editable = false;
tmp.push(item);
}
items.value = tmp;
}
});
);
}
const select_item = (item) => {
console.log("select");
let tmp = items.value;
for (let i = 0;i < tmp.length;i++){
if (tmp[i] === item){
if (tmp[i].editable){
//rename
tmp[i].editable = false;
}
if (tmp[i] === item){
tmp[i].is_selected = true;
}
else {
@ -88,18 +95,18 @@ export default {
ls();
}
else {
$.ajax({
url:' http://47.106.113.194:8000/operation/open/',
axios({
url:' http://1.94.171.222:8000/operation/open/',
type:'get',
data:{
params:{
'path':store.state.user.path.join("") + selected_item.name,
},
success:resp => {
store.commit('updateFileContent',resp.content);
console.log(resp);
})
.then(resp => {
store.commit('updateFileContent',resp.data.content);
router.push({name:'ckeditor'});
}
});
);
}
}
@ -141,6 +148,31 @@ export default {
select_item(data.item);
}
const changetitlestate = (item) => {
item.editable = true;
}
const changetitle = (data) => {
data.item.editable = true;
rename(data.item,data.newname);
}
const rename = (item,newname) => {
axios({
url:' http://1.94.171.222:8000/operation/open/',
type:'get',
params:{
'path':store.state.user.path.join("") + item.name,
'newname':newname,
},
})
.then(resp => {
if (resp.data.result === 'success')
ls();
}
);
}
if (store.state.user.is_login){
ls();
}
@ -159,6 +191,8 @@ export default {
rightclick,
open_file,
turn_back,
changetitle,
changetitlestate,
menuvisible,
menuposition,
menutype,

@ -37,7 +37,6 @@ export default {
let error_message = ref('');
const login = () => {
// http://47.106.113.194:8000/token/
store.dispatch('login',{
username:username.value,
password:password.value,

Loading…
Cancel
Save