Bladeren bron

修复Client端接口问题以及权限问题

tycoding 1 jaar geleden
bovenliggende
commit
e4c550804b

+ 1 - 1
langchat-biz/src/main/java/cn/tycoding/langchat/biz/utils/ClientAuthUtil.java

@@ -66,7 +66,7 @@ public class ClientAuthUtil {
         try {
             return (AigcUser) ClientStpUtil.getSession().get(CacheConst.AUTH_USER_INFO_KEY);
         } catch (Exception e) {
-            throw new AuthException();
+            throw new AuthException(403, "登录已失效,请重新登陆");
         }
     }
 

+ 1 - 9
langchat-client/src/main/java/cn/tycoding/langchat/client/controller/ClientChatEndpoint.java

@@ -30,7 +30,6 @@ import cn.tycoding.langchat.common.dto.PromptConst;
 import cn.tycoding.langchat.common.utils.PromptUtil;
 import cn.tycoding.langchat.common.utils.R;
 import cn.tycoding.langchat.common.utils.StreamEmitter;
-import cn.tycoding.langchat.core.consts.ModelConst;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.*;
@@ -65,14 +64,7 @@ public class ClientChatEndpoint {
             req.setPrompt(PromptUtil.build(req.getMessage(), req.getPromptText()));
         }
 
-        if (req.getModelId().endsWith(ModelConst.IMAGE_SUFFIX)) {
-            AigcOss oss = clientChatService.image(
-                    new ImageR().setPrompt(req.getPrompt()).setModel(req.getModelId()));
-            emitter.send("Image:" + oss);
-            emitter.complete();
-        } else {
-            clientChatService.chat(req);
-        }
+        clientChatService.chat(req);
         return emitter.get();
     }
 

+ 7 - 0
langchat-client/src/main/java/cn/tycoding/langchat/client/controller/ClientModelController.java

@@ -53,4 +53,11 @@ public class ClientModelController {
         list.forEach(i -> i.setApiKey(null));
         return R.ok(list);
     }
+
+    @GetMapping("/getImageModels")
+    public R<List<AigcModel>> getImageModels() {
+        List<AigcModel> list = aigcModelService.getImageModels();
+        list.forEach(i -> i.setApiKey(null));
+        return R.ok(list);
+    }
 }

+ 4 - 5
langchat-common/src/main/java/cn/tycoding/langchat/common/dto/ImageR.java

@@ -28,6 +28,10 @@ import lombok.experimental.Accessors;
 @Accessors(chain = true)
 public class ImageR {
 
+    private String modelId;
+    private String modelName;
+    private String modelProvider;
+
     private Prompt prompt;
 
     /**
@@ -35,11 +39,6 @@ public class ImageR {
      */
     private String message;
 
-    /**
-     * 模型
-     */
-    private String model;
-
     /**
      * 质量
      */

+ 0 - 32
langchat-core/src/main/java/cn/tycoding/langchat/core/consts/ModelConst.java

@@ -23,36 +23,4 @@ package cn.tycoding.langchat.core.consts;
 public interface ModelConst {
 
     String IMAGE_SUFFIX = "_image";
-    String TEXT_SUFFIX = "_text";
-    String EMBED_SUFFIX = "_embed";
-
-    String OPENAI_GPT_3T = "gpt-3.5-turbo";
-    String OPENAI_GPT_4 = "gpt-4";
-    String OPENAI_GPT_4T = "gpt-4-turbo";
-    String OPENAI_GPT_4O = "gpt-4o";
-    String OPENAI_EMBED_3S = "text-embedding-3-small";
-    String OPENAI_EMBED_3L = "text-embedding-3-large";
-    String OPENAI_IMAGE_2 = "dall-e-2";
-    String OPENAI_IMAGE_3 = "dall-e-3";
-
-    String GEMINI_F = "gemini-1.5-flash";
-    String GEMINI_P = "gemini-1.5-pro";
-
-    String AZUREOPENAI_GPT_3T = "gpt-3.5-turbo";
-    String AZUREOPENAI_GPT_4 = "gpt-4";
-    String AZUREOPENAI_GPT_4T = "gpt-4-turbo";
-    String AZUREOPENAI_GPT_4O = "gpt-4o";
-    String AZUREOPENAI_EMBED_3S = "text-embedding-3-small";
-    String AZUREOPENAI_EMBED_3L = "text-embedding-3-large";
-    String AZUREOPENAI_IMAGE_2 = "dall-e-2";
-    String AZUREOPENAI_IMAGE_3 = "dall-e-3";
-
-    String OLLAMA = "ollama";
-    String OLLAMA_TEXT = OLLAMA + TEXT_SUFFIX;
-    String OLLAMA_EMBED = OLLAMA + EMBED_SUFFIX;
-
-    String GEMINI = "gemini";
-    String GEMINI_IMAGE = GEMINI + IMAGE_SUFFIX;
-
-
 }

+ 0 - 11
langchat-core/src/main/java/cn/tycoding/langchat/core/provider/ModelProvider.java

@@ -16,9 +16,6 @@
 
 package cn.tycoding.langchat.core.provider;
 
-import static cn.tycoding.langchat.core.consts.ModelConst.TEXT_SUFFIX;
-
-import dev.langchain4j.model.chat.ChatLanguageModel;
 import dev.langchain4j.model.chat.StreamingChatLanguageModel;
 import dev.langchain4j.model.image.ImageModel;
 import lombok.AllArgsConstructor;
@@ -46,14 +43,6 @@ public class ModelProvider {
         }
     }
 
-    public ChatLanguageModel text(String model) {
-        if (context.containsBean(model)) {
-            return (ChatLanguageModel) context.getBean(model + TEXT_SUFFIX);
-        } else {
-            throw new RuntimeException("No matching model information found, please check the model configuration.");
-        }
-    }
-
     public ImageModel image(String model) {
         if (context.containsBean(model)) {
             return (ImageModel) context.getBean(model);

+ 25 - 5
langchat-core/src/main/java/cn/tycoding/langchat/core/service/impl/LangChatServiceImpl.java

@@ -16,15 +16,16 @@
 
 package cn.tycoding.langchat.core.service.impl;
 
+import cn.hutool.core.lang.UUID;
 import cn.tycoding.langchat.common.dto.ChatReq;
 import cn.tycoding.langchat.common.dto.ImageR;
+import cn.tycoding.langchat.common.exception.ServiceException;
 import cn.tycoding.langchat.core.provider.ModelProvider;
 import cn.tycoding.langchat.core.provider.SearchProvider;
 import cn.tycoding.langchat.core.service.Assistant;
 import cn.tycoding.langchat.core.service.LangChatService;
 import dev.langchain4j.data.image.Image;
 import dev.langchain4j.memory.chat.MessageWindowChatMemory;
-import dev.langchain4j.model.chat.ChatLanguageModel;
 import dev.langchain4j.model.chat.StreamingChatLanguageModel;
 import dev.langchain4j.model.image.ImageModel;
 import dev.langchain4j.model.output.Response;
@@ -40,6 +41,8 @@ import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
+import java.util.concurrent.CompletableFuture;
+
 /**
  * @author tycoding
  * @since 2024/3/8
@@ -85,9 +88,26 @@ public class LangChatServiceImpl implements LangChatService {
 
     @Override
     public String text(ChatReq req) {
+        CompletableFuture<Void> future = new CompletableFuture<>();
+
         try {
-            ChatLanguageModel model = provider.text(req.getModelId());
-            return model.generate(req.getPrompt().text());
+            StreamingChatLanguageModel model = provider.stream(req.getModelId());
+            Assistant assistant = AiServices.builder(Assistant.class)
+                    .streamingChatLanguageModel(model)
+                    .chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(5))
+                    .build();
+
+            StringBuilder text = new StringBuilder();
+            assistant.stream(UUID.randomUUID().toString(), req.getPrompt().text())
+                    .onNext(text::append)
+                    .onComplete((t) -> {
+                        future.complete(null);
+                    })
+                    .onError(future::completeExceptionally)
+                    .start();
+
+            future.join();
+            return text.toString();
         } catch (Exception e) {
             e.printStackTrace();
             return null;
@@ -97,11 +117,11 @@ public class LangChatServiceImpl implements LangChatService {
     @Override
     public Response<Image> image(ImageR req) {
         try {
-            ImageModel model = provider.image(req.getModel());
+            ImageModel model = provider.image(req.getModelId());
             return model.generate(req.getPrompt().text());
         } catch (Exception e) {
             e.printStackTrace();
-            return null;
+            throw new ServiceException("图片生成失败");
         }
     }
 }

+ 6 - 0
langchat-ui-client/src/api/chat.ts

@@ -44,6 +44,12 @@ export function getChatModels() {
   });
 }
 
+export function getImageModels() {
+  return http.get({
+    url: '/client/getImageModels',
+  });
+}
+
 export function genWrite(
   data: ChatR,
   onDownloadProgress?: (progressEvent: AxiosProgressEvent) => void

+ 3 - 9
langchat-ui-client/src/api/models/index.d.ts

@@ -42,16 +42,10 @@ export interface ChatR {
   role?: 'user' | 'assistant' | 'system';
   createTime?: string;
   type?: string;
-  model?: string;
+  modelId?: string;
+  modelName?: string;
+  modelProvider?: string;
   language?: string;
   tone?: string;
   length?: string;
 }
-
-export interface ImageR {
-  message?: string;
-  model?: string;
-  quality?: string;
-  size?: string;
-  style?: string;
-}

+ 9 - 9
langchat-ui-client/src/router/index.ts

@@ -57,15 +57,6 @@ const routes: RouteRecordRaw[] = [
         },
         component: () => import('@/views/modules/image/index.vue'),
       },
-      {
-        path: '/chart',
-        name: 'Chart',
-        meta: {
-          label: t('menu.chart'),
-          icon: 'fluent:data-area-24-regular',
-        },
-        component: () => import('@/views/modules/chart/index.vue'),
-      },
       {
         path: '/mindmap',
         name: 'MindMap',
@@ -75,6 +66,15 @@ const routes: RouteRecordRaw[] = [
         },
         component: () => import('@/views/modules/mindmap/index.vue'),
       },
+      {
+        path: '/chart',
+        name: 'Chart',
+        meta: {
+          label: t('menu.chart'),
+          icon: 'fluent:data-area-24-regular',
+        },
+        component: () => import('@/views/modules/chart/index.vue'),
+      },
     ],
   },
 ];

+ 18 - 1
langchat-ui-client/src/utils/request/index.ts

@@ -71,14 +71,31 @@ function axios<T = any>({
 
     const $message = window['$message'];
     const $dialog = window['$dialog'];
-    const { status } = error.response;
+    const { status, data } = error.response;
     const userStore = useUserStore();
 
+    if (data.code === 403) {
+      $message!.destroyAll();
+      $dialog!.destroyAll();
+      await userStore.logout();
+      $dialog!.warning({
+        title: t('login.title'),
+        content: t('login.content'),
+        positiveText: t('login.positiveText'),
+        negativeText: t('login.negativeText'),
+        onPositiveClick: async () => {
+          await router.push({ name: 'Login' });
+        },
+      });
+      return;
+    }
+
     if (status === 401) {
       // $message!.error('Login failed, please login again');
       // await router.push({ name: 'Login' });
 
       if (isNullOrWhitespace(userStore.token)) {
+        $message!.destroyAll();
         $dialog!.destroyAll();
         $dialog!.warning({
           title: t('login.title'),

+ 4 - 4
langchat-ui-client/src/views/modules/chat/store/chat.d.ts

@@ -1,8 +1,8 @@
 export interface ChatState {
-  modelId: string;
-  modelName: string;
-  modelProvider: string;
-  isGoogleSearch: boolean;
+  modelId?: string;
+  modelName?: string;
+  modelProvider?: string;
+  isGoogleSearch?: boolean;
   isEdit: string; //当前编辑的id
   active: string; //当前激活的id
   siderCollapsed: boolean; //侧边栏展开状态

+ 6 - 2
langchat-ui-client/src/views/modules/doc/components/FileList.vue

@@ -19,8 +19,11 @@
 
   async function fetchData() {
     loading.value = true;
-    fileList.value = await list();
-    loading.value = false;
+    try {
+      fileList.value = await list();
+    } finally {
+      loading.value = false;
+    }
   }
 
   function onSelect(item: any) {
@@ -69,6 +72,7 @@
   const taskCount = ref(0);
   let timerId: string | number | NodeJS.Timeout | undefined;
   let continuePolling = false;
+
   function startTask() {
     continuePolling = true;
     timerId = setInterval(() => {

+ 24 - 11
langchat-ui-client/src/views/modules/image/component/DALL.vue

@@ -1,27 +1,40 @@
 <script lang="ts" setup>
   import { SvgIcon } from '@/components/common';
-  import { genImage } from '@/api/chat';
-  import { ref, toRaw } from 'vue';
+  import { genImage, getImageModels } from '@/api/chat';
+  import { onMounted, ref, toRaw } from 'vue';
   import { isBlank } from '@/utils/is';
   import { useMessage } from 'naive-ui';
-  import { ImageR } from '@/api/models';
 
   const emit = defineEmits(['ok']);
   const loading = ref(false);
   const ms = useMessage();
   const message = ref('');
-  const form = ref<ImageR>({
-    model: 'dall-e-3',
+  const form = ref<any>({
+    modelName: 'dall-e-3',
     quality: 'standard',
     size: '1024x1024',
     style: 'vivid',
   });
 
+  const modelProviders = ref<any[]>([]);
+  onMounted(async () => {
+    modelProviders.value = toRaw(await getImageModels());
+  });
+
   async function onSubmit() {
     if (isBlank(message.value)) {
       ms.error('请输入内容');
       return;
     }
+    const models = toRaw(modelProviders.value).filter((i) => i.model === form.value.modelName);
+    console.log(models);
+    if (models.length === 0) {
+      ms.error('没有找到匹配的模型,请联系管理员');
+      return;
+    }
+    form.value.modelId = models[0].id;
+    form.value.modelProvider = models[0].provider;
+
     loading.value = true;
     ms.success('图片生成中,请稍后...');
     const data = await genImage({
@@ -86,10 +99,10 @@
         <n-button
           v-for="item in modelList"
           :key="item.label"
-          :type="form.model == item.value ? 'success' : 'default'"
+          :type="form.modelName == item.value ? 'success' : 'default'"
           secondary
           size="small"
-          @click="form.model = item.value"
+          @click="form.modelName = item.value"
         >
           {{ item.label }}
         </n-button>
@@ -105,7 +118,7 @@
         <n-button
           v-for="item in qualityList"
           :key="item"
-          :disabled="form.model == 'dall-e-2'"
+          :disabled="form.modelName == 'dall-e-2'"
           :type="form.quality == item.value ? 'success' : 'default'"
           secondary
           size="small"
@@ -126,7 +139,7 @@
           v-for="item in sizeList"
           :key="item"
           :disabled="
-            form.model == 'dall-e-2' && (item.value == '1792x1024' || item.value == '1024x1792')
+            form.modelName == 'dall-e-2' && (item.value == '1792x1024' || item.value == '1024x1792')
           "
           :type="form.size == item.value ? 'success' : 'default'"
           secondary
@@ -147,7 +160,7 @@
         <n-button
           v-for="item in styleList"
           :key="item"
-          :disabled="form.model == 'dall-e-2'"
+          :disabled="form.modelName == 'dall-e-2'"
           :type="form.style == item.value ? 'success' : 'default'"
           secondary
           size="small"
@@ -160,4 +173,4 @@
   </div>
 </template>
 
-<style scoped lang="less"></style>
+<style lang="less" scoped></style>

+ 5 - 2
langchat-ui-client/src/views/modules/mindmap/index.vue

@@ -7,10 +7,11 @@
   import { isBlank } from '@/utils/is';
   import { t } from '@/locales';
   import ModelProvider from '@/views/modules/common/ModelProvider.vue';
+  import { useChatStore } from '@/views/modules/chat/store/useChatStore';
 
-  const model = ref('gpt-4o');
   const ms = useMessage();
   const loading = ref(false);
+  const chatStore = useChatStore();
   const genText = ref('');
 
   async function onGenerate(text: string) {
@@ -22,7 +23,9 @@
     try {
       const { message } = await genMindMap({
         message: text,
-        model: model.value,
+        modelId: chatStore.modelId,
+        modelName: chatStore.modelName,
+        modelProvider: chatStore.modelProvider,
       });
       genText.value = message;
     } finally {

+ 2 - 1
langchat-ui/src/utils/http/axios/index.ts

@@ -201,7 +201,8 @@ const transform: AxiosTransform = {
       }
       if (
         response.status === ResultEnum.UnAuthorization ||
-        response.data.code === ResultEnum.UnAuthorization
+        response.data.code === ResultEnum.UnAuthorization ||
+        response.data.code === 403
       ) {
         const LoginName = PageEnum.BASE_LOGIN_NAME;
 

+ 5 - 2
langchat-upms/src/main/java/cn/tycoding/langchat/upms/utils/AuthUtil.java

@@ -19,6 +19,7 @@ package cn.tycoding.langchat.upms.utils;
 import cn.dev33.satoken.secure.SaSecureUtil;
 import cn.dev33.satoken.stp.StpUtil;
 import cn.tycoding.langchat.common.constant.CacheConst;
+import cn.tycoding.langchat.common.exception.AuthException;
 import cn.tycoding.langchat.upms.dto.UserInfo;
 import cn.tycoding.langchat.upms.entity.SysRole;
 import jakarta.servlet.http.HttpServletRequest;
@@ -26,7 +27,9 @@ import jakarta.servlet.http.HttpServletResponse;
 import org.springframework.web.context.request.RequestContextHolder;
 import org.springframework.web.context.request.ServletRequestAttributes;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
 
 /**
  * 权限相关方法
@@ -88,7 +91,7 @@ public class AuthUtil {
         try {
             return (UserInfo) StpUtil.getSession().get(CacheConst.AUTH_USER_INFO_KEY);
         } catch (Exception e) {
-            return null;
+            throw new AuthException(403, "登录已失效,请重新登陆");
         }
     }