mirror of
				https://github.com/yangjian102621/geekai.git
				synced 2025-11-04 08:13:43 +08:00 
			
		
		
		
	support upload file from clipboard
This commit is contained in:
		@@ -1,4 +1,13 @@
 | 
			
		||||
# 更新日志
 | 
			
		||||
## v4.1.1
 | 
			
		||||
* Bug修复:修复 GPT 模型 function call 调用后没有输出的问题
 | 
			
		||||
* 功能新增:允许获取 License 授权用户可以自定义版权信息
 | 
			
		||||
* 功能新增:聊天对话框支持粘贴剪切板内容来上传截图和文件
 | 
			
		||||
* 功能优化:增加 session 和系统配置缓存,确保每个页面只进行一次 session 和 get system config 请求
 | 
			
		||||
* 功能优化:在应用列表页面,无需先添加模型到用户工作区,可以直接使用
 | 
			
		||||
* 功能新增:MJ 绘图失败的任务不会自动删除,而是会在列表页显示失败详细错误信息
 | 
			
		||||
* 功能新增:增加 Suno 文生音乐页面功能
 | 
			
		||||
 | 
			
		||||
## v4.1.0
 | 
			
		||||
* bug修复:修复移动端修改聊天标题不生效的问题
 | 
			
		||||
* Bug修复:修复用户注册不显示用户名的问题
 | 
			
		||||
 
 | 
			
		||||
@@ -139,7 +139,7 @@ func authorizeMiddleware(s *AppServer, client *redis.Client) gin.HandlerFunc {
 | 
			
		||||
 | 
			
		||||
		if tokenString == "" {
 | 
			
		||||
			if needLogin(c) {
 | 
			
		||||
				resp.ERROR(c, "You should put Authorization in request headers")
 | 
			
		||||
				resp.NotAuth(c, "You should put Authorization in request headers")
 | 
			
		||||
				c.Abort()
 | 
			
		||||
				return
 | 
			
		||||
			} else { // 直接放行
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								web/public/images/ext/mp3.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								web/public/images/ext/mp3.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 812 B  | 
							
								
								
									
										
											BIN
										
									
								
								web/public/images/ext/mp4.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								web/public/images/ext/mp4.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 743 B  | 
@@ -241,8 +241,8 @@ watch(() => props.show, (newValue) => {
 | 
			
		||||
 | 
			
		||||
const login = ref(true)
 | 
			
		||||
const data = ref({
 | 
			
		||||
  username: "",
 | 
			
		||||
  password: "",
 | 
			
		||||
  username: process.env.VUE_APP_USER,
 | 
			
		||||
  password: process.env.VUE_APP_PASS,
 | 
			
		||||
  repass: "",
 | 
			
		||||
  code: "",
 | 
			
		||||
  invite_code: ""
 | 
			
		||||
 
 | 
			
		||||
@@ -37,7 +37,11 @@ export function GetFileIcon(ext) {
 | 
			
		||||
        ".pptx": "ppt.png",
 | 
			
		||||
        ".md": "md.png",
 | 
			
		||||
        ".pdf": "pdf.png",
 | 
			
		||||
        ".sql": "sql.png"
 | 
			
		||||
        ".sql": "sql.png",
 | 
			
		||||
        ".mp3": "mp3.png",
 | 
			
		||||
        ".wav": "mp3.png",
 | 
			
		||||
        ".mp4": "mp4.png",
 | 
			
		||||
        ".avi": "mp4.png",
 | 
			
		||||
    }
 | 
			
		||||
    if (files[ext]) {
 | 
			
		||||
        return '/images/ext/' + files[ext]
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,8 @@ axios.interceptors.response.use(
 | 
			
		||||
            } else {
 | 
			
		||||
                removeUserToken()
 | 
			
		||||
            }
 | 
			
		||||
            console.log(error.response.data)
 | 
			
		||||
            error.response.data.message = "请先登录"
 | 
			
		||||
            return Promise.reject(error.response.data)
 | 
			
		||||
        }
 | 
			
		||||
        if (error.response.status === 400) {
 | 
			
		||||
 
 | 
			
		||||
@@ -219,6 +219,7 @@ import {useSharedStore} from "@/store/sharedata";
 | 
			
		||||
import FileSelect from "@/components/FileSelect.vue";
 | 
			
		||||
import FileList from "@/components/FileList.vue";
 | 
			
		||||
import ChatSetting from "@/components/ChatSetting.vue";
 | 
			
		||||
import axios from "axios";
 | 
			
		||||
 | 
			
		||||
const title = ref('ChatGPT-智能助手');
 | 
			
		||||
const models = ref([])
 | 
			
		||||
@@ -342,16 +343,6 @@ const initData = () => {
 | 
			
		||||
    })
 | 
			
		||||
  }).catch(() => {
 | 
			
		||||
    loading.value = false
 | 
			
		||||
    // 加载会话
 | 
			
		||||
    httpGet("/api/chat/list").then((res) => {
 | 
			
		||||
      if (res.data) {
 | 
			
		||||
        chatList.value = res.data;
 | 
			
		||||
        allChats.value = res.data;
 | 
			
		||||
      }
 | 
			
		||||
    }).catch(() => {
 | 
			
		||||
      ElMessage.error("加载会话列表失败!")
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    // 加载模型
 | 
			
		||||
    httpGet('/api/model/list',{id:roleId.value}).then(res => {
 | 
			
		||||
      models.value = res.data
 | 
			
		||||
@@ -368,6 +359,37 @@ const initData = () => {
 | 
			
		||||
      ElMessage.error('获取聊天角色失败: ' + e.messages)
 | 
			
		||||
    })
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  inputRef.value.addEventListener('paste', (event) => {
 | 
			
		||||
    const items = (event.clipboardData || window.clipboardData).items;
 | 
			
		||||
    let fileFound = false;
 | 
			
		||||
    loading.value = true
 | 
			
		||||
 | 
			
		||||
    for (let item of items) {
 | 
			
		||||
      if (item.kind === 'file') {
 | 
			
		||||
        const file = item.getAsFile();
 | 
			
		||||
        fileFound = true;
 | 
			
		||||
 | 
			
		||||
        const formData = new FormData();
 | 
			
		||||
        formData.append('file', file);
 | 
			
		||||
        // 执行上传操作
 | 
			
		||||
        httpPost('/api/upload', formData).then((res) => {
 | 
			
		||||
          files.value.push(res.data)
 | 
			
		||||
          ElMessage.success({message: "上传成功", duration: 500})
 | 
			
		||||
          loading.value = false
 | 
			
		||||
        }).catch((e) => {
 | 
			
		||||
          ElMessage.error('文件上传失败:' + e.message)
 | 
			
		||||
          loading.value = false
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!fileFound) {
 | 
			
		||||
      document.getElementById('status').innerText = 'No file found in paste data.';
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const getRoleById = function (rid) {
 | 
			
		||||
@@ -739,7 +761,7 @@ const onInput = (e) => {
 | 
			
		||||
const autofillPrompt = (text) => {
 | 
			
		||||
  prompt.value = text
 | 
			
		||||
  inputRef.value.focus()
 | 
			
		||||
  // sendMessage()
 | 
			
		||||
  sendMessage()
 | 
			
		||||
}
 | 
			
		||||
// 发送消息
 | 
			
		||||
const sendMessage = function () {
 | 
			
		||||
 
 | 
			
		||||
@@ -492,7 +492,13 @@
 | 
			
		||||
                          <div class="image-slot">
 | 
			
		||||
                            <div class="err-msg-container">
 | 
			
		||||
                              <div class="title">任务失败</div>
 | 
			
		||||
                              <div class="text">{{ slotProp.item['err_msg'] }}</div>
 | 
			
		||||
                              <div class="text">
 | 
			
		||||
                                <el-popover title="错误详情" trigger="hover" :width="250" :content="slotProp.item['err_msg']" placement="top">
 | 
			
		||||
                                  <template #reference>
 | 
			
		||||
                                    {{ slotProp.item['err_msg'] }}
 | 
			
		||||
                                  </template>
 | 
			
		||||
                                </el-popover>
 | 
			
		||||
                              </div>
 | 
			
		||||
                            </div>
 | 
			
		||||
                            <el-button type="danger"  @click="removeImage(slotProp.item)">删除</el-button>
 | 
			
		||||
                          </div>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user