yangg 8 сар өмнө
parent
commit
1e0e67c5f5
41 өөрчлөгдсөн 599 нэмэгдсэн , 151 устгасан
  1. 1 1
      .env.development
  2. 0 0
      dist/index.html
  3. 0 0
      dist/static/css/app.63259125.css
  4. 0 0
      dist/static/css/chunk-0ec56e2a.e30e9787.css
  5. 0 0
      dist/static/css/chunk-138f7583.7131743c.css
  6. 0 0
      dist/static/css/chunk-15506e7b.d40db7bc.css
  7. 0 0
      dist/static/css/chunk-21725832.65b6e7c2.css
  8. 0 0
      dist/static/css/chunk-23d4d74d.e30e9787.css
  9. 0 0
      dist/static/css/chunk-4ac7f82e.7131743c.css
  10. 0 1
      dist/static/css/chunk-4d4d84bc.8479d7a3.css
  11. 0 0
      dist/static/css/chunk-86317d32.360612b2.css
  12. 0 0
      dist/static/css/chunk-a577192a.6044f932.css
  13. 0 0
      dist/static/css/chunk-ad361d30.ba3e57b5.css
  14. 0 0
      dist/static/css/chunk-d09dbc1a.6f8877c6.css
  15. 0 0
      dist/static/js/app.882d681d.js
  16. 0 0
      dist/static/js/app.8c4f1eab.js
  17. 0 0
      dist/static/js/chunk-0ec56e2a.ca5a391c.js
  18. 0 0
      dist/static/js/chunk-138f7583.a0b27197.js
  19. 0 0
      dist/static/js/chunk-15506e7b.49cd7a04.js
  20. 0 0
      dist/static/js/chunk-21725832.e3db9632.js
  21. 0 0
      dist/static/js/chunk-23d4d74d.133be1a1.js
  22. 0 0
      dist/static/js/chunk-4ac7f82e.7b922ed0.js
  23. 0 1
      dist/static/js/chunk-4d4d84bc.a416a7b0.js
  24. 0 0
      dist/static/js/chunk-53655b96.dc709f35.js
  25. 0 0
      dist/static/js/chunk-6ef8d49b.8170e52b.js
  26. 0 0
      dist/static/js/chunk-86317d32.f3b9c27a.js
  27. 0 0
      dist/static/js/chunk-a577192a.827c6062.js
  28. 0 0
      dist/static/js/chunk-ad361d30.298cb249.js
  29. 0 0
      dist/static/js/chunk-b5e03698.6375d10c.js
  30. 0 0
      dist/static/js/chunk-d09c27ba.b4dc3f9d.js
  31. 0 0
      dist/static/js/chunk-d09dbc1a.3056dbeb.js
  32. 0 0
      dist/static/js/chunk-libs.76f3ffd8.js
  33. 30 0
      src/api/knowledge.js
  34. BIN
      src/assets/images/人工智能.png
  35. 77 5
      src/components/webAi/css/ChatBox.css
  36. 191 65
      src/components/webAi/index.vue
  37. 207 20
      src/components/webAi/js/ChatBox.js
  38. 3 0
      src/layout/components/Navbar.vue
  39. 2 2
      src/router/index.js
  40. 20 9
      src/views/chatPage/index.vue
  41. 68 47
      src/views/document/create.vue

+ 1 - 1
.env.development

@@ -2,5 +2,5 @@
 ENV = 'development'
 port = 8080
 # base api
-VUE_APP_BASE_API = 'http://58.246.234.210:8084'
+VUE_APP_BASE_API = 'http://192.168.1.199:8084'
 #192.168.1.199

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/index.html


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/static/css/app.63259125.css


+ 0 - 0
dist/static/css/chunk-09f78c22.e30e9787.css → dist/static/css/chunk-0ec56e2a.e30e9787.css


+ 0 - 0
dist/static/css/chunk-059ccbc0.d6fdc4e5.css → dist/static/css/chunk-138f7583.7131743c.css


+ 0 - 0
dist/static/css/chunk-d09c27ba.d40db7bc.css → dist/static/css/chunk-15506e7b.d40db7bc.css


+ 0 - 0
dist/static/css/chunk-b5e03698.65b6e7c2.css → dist/static/css/chunk-21725832.65b6e7c2.css


+ 0 - 0
dist/static/css/chunk-10bfc27e.6044f932.css → dist/static/css/chunk-23d4d74d.e30e9787.css


+ 0 - 0
dist/static/css/chunk-48e21f21.d6fdc4e5.css → dist/static/css/chunk-4ac7f82e.7131743c.css


+ 0 - 1
dist/static/css/chunk-4d4d84bc.8479d7a3.css

@@ -1 +0,0 @@
-[data-v-7dfc5ed1] .chat-container{height:100vh}[data-v-7dfc5ed1] .messages{margin-bottom:0;height:calc(100vh - 120px)}[data-v-7dfc5ed1] .input-container{max-width:1200px}

+ 0 - 0
dist/static/css/chunk-13ebf84f.360612b2.css → dist/static/css/chunk-86317d32.360612b2.css


+ 0 - 0
dist/static/css/chunk-41d431f5.e30e9787.css → dist/static/css/chunk-a577192a.6044f932.css


+ 0 - 0
dist/static/css/chunk-53655b96.ba3e57b5.css → dist/static/css/chunk-ad361d30.ba3e57b5.css


+ 0 - 0
dist/static/css/chunk-277ceec9.6f8877c6.css → dist/static/css/chunk-d09dbc1a.6f8877c6.css


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/static/js/app.882d681d.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/static/js/app.8c4f1eab.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/static/js/chunk-0ec56e2a.ca5a391c.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/static/js/chunk-138f7583.a0b27197.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/static/js/chunk-15506e7b.49cd7a04.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/static/js/chunk-21725832.e3db9632.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/static/js/chunk-23d4d74d.133be1a1.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/static/js/chunk-4ac7f82e.7b922ed0.js


+ 0 - 1
dist/static/js/chunk-4d4d84bc.a416a7b0.js

@@ -1 +0,0 @@
-(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-4d4d84bc"],{"12c2":function(n,t,o){},"14df":function(n,t,o){"use strict";o("12c2")},c8cf:function(n,t,o){"use strict";o.r(t);var c=function(){var n=this,t=n.$createElement,o=n._self._c||t;return o("div",[o("ChatBox")],1)},e=[],a=o("c3b3"),d=o("ecd9"),i={components:{ChatBox:a["default"],LoginModal:d["default"]},data:function(){return{showLoginModal:!1}},mounted:function(){},methods:{checkAIData:function(){var n=localStorage.getItem("AIData");this.showLoginModal=!n},handleLoginSuccess:function(){this.showLoginModal=!1}}},u=i,s=(o("14df"),o("2877")),f=Object(s["a"])(u,c,e,!1,null,"7dfc5ed1",null);t["default"]=f.exports}}]);

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/static/js/chunk-53655b96.dc709f35.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/static/js/chunk-6ef8d49b.8170e52b.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/static/js/chunk-86317d32.f3b9c27a.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/static/js/chunk-a577192a.827c6062.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/static/js/chunk-ad361d30.298cb249.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/static/js/chunk-b5e03698.6375d10c.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/static/js/chunk-d09c27ba.b4dc3f9d.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/static/js/chunk-d09dbc1a.3056dbeb.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
dist/static/js/chunk-libs.76f3ffd8.js


+ 30 - 0
src/api/knowledge.js

@@ -196,4 +196,34 @@ export function selectType0(data) {
     method: 'post',
     data
   })
+}
+
+/* 获取模型列表 */
+
+export function modelList(data) {
+  return request({
+    url: 'model/search',
+    method: 'post',
+    data
+  })
+}
+
+/* 生成应用  chatbot/configSave */
+
+export function configSave(data) {
+  return request({
+    url: 'chatbot/configSave/',
+    method: 'post',
+    data
+  })
+}
+
+/* 查询配置列表 */
+
+export function configList(data) {
+  return request({
+    url: '/chatbot/configuration/list/',
+    method: 'post',
+    data
+  })
 }

BIN
src/assets/images/人工智能.png


+ 77 - 5
src/components/webAi/css/ChatBox.css

@@ -3,18 +3,90 @@
     position: relative;
     display: flex;
     flex-direction: column;
+    margin-bottom: 150px;
      /* 或者按照实际需要调整高度 */
 }
 .chat-container .header{
-    display: flex;
-    justify-content: flex-end;
+  width: 90%;
+    margin: 10px auto 0;
+    border: 1px solid #d7d7d7;
+    border-radius: 10px;
+}
+.form-container {
+  max-width: 1200px; /* 或者其他适合你布局的宽度 */
+  margin: 0 auto; /* 这会使容器水平居中 */
+  padding: 0 15px; /* 添加一些左右内边距 */
+}
+
+.el-form-item {
+  margin-bottom: 15px;
+}
+
+.el-select {
+  width: 100%;
 }
-.chat-container .header ::v-deep .el-select .el-input--medium .el-input__inner{
+.generate-button {
+  margin-top: 10px; /* 在小屏幕上给按钮一些上边距 */
+  margin-right: 25px;
+}
+
+@media (max-width: 768px) {
+  .selection-summary {
+    flex-direction: column;
+  }
+  
+  .generate-button {
+    margin-left: 0;
+    margin-top: 15px;
+    align-self: flex-end; /* 在小屏幕上将按钮右对齐 */
+  }
+}
+.selection-summary {
+  background-color: #f2f2f2;
+  border-radius: 4px;
+  padding: 15px;
+  margin: 15px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  border-radius:10px;
+}
+
+.summary-content {
+  flex-grow: 1;
+}
+
+.summary-label {
+  font-weight: bold;
+  color: #7f7f7f;
+  margin-right: 10px;
+}
+
+.summary-text {
+  color: #606266;
+  margin: 0;
+  margin-top: 3px;
+  font-size: 14px;
+}
+.title{
+  width: 90%;
+  margin: 0 auto 15px;
+  display: flex;
+  align-items: center;
+
+}
+.title_info{
+  cursor: pointer;
+  color: #1296db;
+  font-size: 14px;
+  margin-left: 10px;
+}
+/* .chat-container .header ::v-deep .el-select .el-input--medium .el-input__inner{
     border: none;
 }
 .chat-container .header ::v-deep .el-select .el-input--medium .el-input__suffix .el-input__suffix-inner{
     display: none;
-}
+} */
 .chat-container .content {
     display: flex;
     justify-content: flex-start;
@@ -229,7 +301,7 @@
   }
 .input-container {
     position: absolute; /* 改为绝对定位 */
-    bottom: 10px; /* 距离底部的距离 */
+    bottom: -115px; /* 距离底部的距离 */
     left: 50%;
     transform: translateX(-50%);
     width: 90%; /* 设置宽度为弹窗宽度的90% */

+ 191 - 65
src/components/webAi/index.vue

@@ -1,18 +1,145 @@
 <template>
-  <div class="chat-container" >
-    <div class="header" style="margin-top: 15px;">
-      <el-select v-model="AImodel" placeholder="请选择模型">
-        <el-option label="请选择模型" value="1"> </el-option>
-      </el-select>
-      <el-select v-model="AIknowledgeBase" placeholder="请选择知识库">
-        <el-option label="请选择知识库" value="1"> </el-option>
-      </el-select>
-      <el-select v-model="AIFile" placeholder="请选择文件">
-        <el-option label="请选择文件" value="1"> </el-option>
-      </el-select>
+  <div class="chat-container">
+    <div class="header" style="margin-top: 15px" v-if="$route.name !== 'ai'">
+      <el-form
+        :inline="true"
+        :model="AIform"
+        :rules="rules"
+        ref="AIformRef"
+        class="demo-form-inline"
+        style="margin-top: 15px"
+        label-position="right"
+        label-width="90px"
+      >
+        <el-form-item label="应用名称:" prop="chat_name">
+          <el-input
+            v-model="AIform.chat_name"
+            placeholder="请输入应用名称"
+          ></el-input>
+        </el-form-item>
+        <el-row :gutter="24">
+          <el-col :span="9">
+            <el-form-item label="模型库:" prop="modelLibrary">
+              <el-select
+                v-model="AIform.modelLibrary"
+                placeholder="ollama"
+                style="width: 100%"
+              >
+                <el-option label="ollama" value="ollama"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="9">
+            <el-form-item label="模型类型:" prop="model_type">
+              <el-select
+                v-model="AIform.model_type"
+                placeholder="请输入选择"
+                style="width: 100%"
+              >
+                <el-option label="chat" value="chat"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="模型名称:" prop="model_name">
+              <el-select
+                v-model="AIform.model_name"
+                placeholder="请输入选择"
+                style="width: 100%"
+              >
+                <el-option
+                  v-for="(item, index) in modelNameList"
+                  :label="item.name"
+                  :value="item.name"
+                  :key="index"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="24">
+          <el-col :span="9">
+            <el-form-item label="知识库:" prop="knowledge_base_names">
+              <el-select
+                v-model="AIform.knowledge_base_names"
+                multiple
+                placeholder="请选择知识库"
+                style="width: 100%"
+                @change="handleKnowledgeBaseChange"
+              >
+                <el-option
+                  v-for="(item, index) in kneList"
+                  :label="item.name"
+                  :value="item.id"
+                  :key="index"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="9">
+            <el-form-item label="文档目录:" prop="document_directories">
+              <el-select
+                v-model="AIform.document_directories"
+                placeholder="请选择文档目录"
+                style="width: 100%"
+                :disabled="!AIform.knowledge_base_names.length"
+                @change="handleDirectoryChange"
+              >
+                <el-option
+                  v-for="(dir, index) in directoryList"
+                  :label="dir.name"
+                  :value="dir.id"
+                  :key="index"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="文  档:" prop="documents">
+              <el-select
+                v-model="AIform.documents"
+                multiple
+                placeholder="请选择文档"
+                style="width: 100%"
+                :disabled="!AIform.document_directories"
+              >
+                <el-option
+                  v-for="(doc, index) in documentList"
+                  :label="doc.name"
+                  :value="doc.id"
+                  :key="index"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div class="selection-summary">
+        <div class="summary-content">
+          <span class="summary-label">当前选择了:</span>
+          <p class="summary-text">
+            模型库: OLLAMA 模型类型: CHAT 模型名称:
+            <span>{{ AIform.modelName }}</span>
+          </p>
+          <p class="summary-text">
+            知识库:<span>{{ AIform.knowledge_base_names }}</span> 文档:
+            <span>{{ AIform.documents }}</span>
+          </p>
+        </div>
+        <el-button
+          type="primary"
+          class="generate-button"
+          @click="generateApplication"
+          >生成应用</el-button
+        >
+      </div>
+    </div>
+    <div class="title" v-if="$route.name !== 'ai'">
+      <h1>我的聊天应用</h1>
+      <span class="title_info">选择其他应用</span>
     </div>
     <div class="content">
-      <div class="left">
+      <!-- <div class="left">
         <div class="chat-history">
           <div
             v-for="(chat, index) in chatHistory"
@@ -33,64 +160,63 @@
                 <div class="chat-message">{{ chat.message }}</div>
                 <div class="chat-preview">{{ chat.preview }}</div>
               </div>
-              <!-- <div class="more-options">...</div> -->
             </div>
           </div>
         </div>
-      </div>
-      <div class="right" style="position: relative">
-        <div class="messages">
-          <ul>
-            <li
-              v-for="message in messages"
-              :key="message.id"
-              :class="[
-                message.user,
-                message.user === 'user' ? 'user-message' : '',
-              ]"
-            >
-              <!-- 添加判断,如果是机器人的消息也显示头像 -->
-              <div class="message_name">
-                <div
-                  class="avatar"
-                  :class="{
-                    'user-avatar': message.user === 'user',
-                    'bot-avatar': message.user === 'bot',
-                  }"
-                ></div>
-                <div class="name">
-                  <span
-                    class="sender-name"
-                    style="color: #666666"
-                    v-if="message.user === 'user'"
-                    >你</span
-                  >
-                  <span class="sender-name" v-if="message.user === 'bot'"
-                    >轻良AI助理</span
-                  >
-                </div>
-              </div>
-              <!-- 使用 v-html 来渲染 Markdown 文本 -->
-              <div class="message-content">
-                <div
-                  class="message-text"
-                  v-html="renderMarkdown(message.message)"
-                  @click="handleLinkClick"
-                ></div>
+      </div> -->
+      <!--  <div class="right" style="position: relative"> -->
+      <div class="messages">
+        <ul>
+          <li
+            v-for="message in messages"
+            :key="message.id"
+            :class="[
+              message.user,
+              message.user === 'user' ? 'user-message' : '',
+            ]"
+          >
+            <!-- 添加判断,如果是机器人的消息也显示头像 -->
+            <div class="message_name">
+              <div
+                class="avatar"
+                :class="{
+                  'user-avatar': message.user === 'user',
+                  'bot-avatar': message.user === 'bot',
+                }"
+              ></div>
+              <div class="name">
+                <span
+                  class="sender-name"
+                  style="color: #666666"
+                  v-if="message.user === 'user'"
+                  >你</span
+                >
+                <span class="sender-name" v-if="message.user === 'bot'"
+                  >轻良AI助理</span
+                >
               </div>
-            </li>
-          </ul>
-        </div>
-        <div class="input-container">
-          <textarea
-            v-model="userInput"
-            rows="4"
-            @keydown="handleKeydown"
-            placeholder="发送消息..."
-          ></textarea>
-          <button @click="sendMessage" class="btn">发送</button>
-        </div>
+            </div>
+            <!-- 使用 v-html 来渲染 Markdown 文本 -->
+            <div class="message-content">
+              <div
+                class="message-text"
+                v-html="renderMarkdown(message.message)"
+                @click="handleLinkClick"
+              ></div>
+            </div>
+          </li>
+        </ul>
+      </div>
+      <div class="input-container">
+        <textarea
+          v-model="userInput"
+          rows="4"
+          @keydown="handleKeydown"
+          placeholder="发送消息..."
+        ></textarea>
+        <button @click="sendMessage" class="btn">发送</button>
       </div>
+      <!-- </div> -->
     </div>
 
     <!-- 添加 LoginModal 组件 -->

+ 207 - 20
src/components/webAi/js/ChatBox.js

@@ -1,6 +1,7 @@
 import LoginModal from "@/components/LoginModal";
 import MarkdownIt from "markdown-it";
 import { pcInnerAi,getMinioURl } from "@/api/api";
+import {modelList,listBuckets,selectTypeList,getBucketContents,configSave,configList} from "@/api/knowledge"
 import axios from 'axios';
 const md = new MarkdownIt();
 
@@ -34,30 +35,66 @@ export default {
       AImodel:'1',//模型
       AIknowledgeBase:"1",//知识库
       AIFile:'1',//文件
-      chatHistory: [
-        {
-          username: "Theresa Rose",
-          avatar: "/path/to/avatar1.jpg",
-          timestamp: "08:33AM",
-          message: "I hope I can finish Frox soon",
-          preview: "Hi, what's new with Frox? Please upload the latest code, and I will check today"
-        },
-        {
-          username: "Theresa Rose",
-          avatar: "/path/to/avatar2.jpg",
-          timestamp: "08:33AM",
-          message: "I hope I can finish Frox soon",
-          preview: "Hi, what's new with Frox? Please upload the latest code, and I will check today"
-        },
-        // Add more chat history items as needed
-      ],
-      currentChatIndex: 0,
+      AIform:{
+        chat_name:'',
+        modelLibrary: 'ollama',
+        model_type: 'chat',
+        model_name: '',
+        knowledge_base_names: [],
+        document_directories: [],
+        documents: [],
+        temperature: 0.7,
+        max_tokens: 150,
+         top_p: 1.0,
+         frequency_penalty: 0.0,
+         presence_penalty: 0.0,
+         response_format: "text",
+         context_window: 2048,
+         user_id: "user123",
+         session_id: "session456",
+         language: "en",
+         timeout: 30,
+         role_name: "Admin",
+         role_description: "Administrator role with full access.",
+         role_permissions: ["read", "write", "delete"]
+      },
+      /* 模型库 */
+      modelList:[],
+      /* 模型类型 */
+      modelTypeList:[],
+      /* 模型名称 */
+      modelNameList:[],
+      /* 知识库 */
+      kneList:[],
+      /* 文档目录 */
+      directoryList: [],
+      /* 文档 */
+       documentList: [],
+       bucket_id:'',
+       rules: {
+        chat_name: [
+          { required: true, message: '请填写应名称', trigger: 'blur' }
+        ],
+        modelName: [
+          { required: true, message: '请选择模型名称', trigger: 'change' }
+        ],
+        knowledge_base_names: [
+          { required: true, message: '请选择至少一个知识库', trigger: 'change' }
+        ],
+        document_directories: [
+          { required: true, message: '请选择文档目录', trigger: 'change' }
+        ],
+        documents: [
+          { required: true, message: '请选择至少一个文档', trigger: 'change' }
+        ]
+      }
     };
   },
   created() {
    // this.connectWebSocket();
   },
   mounted() {
+    /* */
     if(this.$route.name=='ai'){
       /* 外部知识库 */
       const AIData=JSON.parse(sessionStorage.getItem("AIData"))
@@ -69,12 +106,146 @@ export default {
         if(res.status!==200) return
         this.wsUrl=res.data.url
         this.tweaks=res.data.tweaks
-        
       })
-      
     }
+    /* 获取模型列表 */
+    this.init()
   },
   methods: {
+    /* 生成引用 */
+    generateApplication() {
+      this.$refs.AIformRef.validate(async (valid) => {
+        if (valid) {
+          try {
+            // 创建一个新对象来存储转换后的数据
+            const convertedForm = { ...this.AIform };
+
+            // 将知识库 ID 转换为名称
+            convertedForm.knowledge_base_names = this.safeGetNamesByIds(this.AIform.knowledge_base_names, this.kneList);
+
+            // 将文档 ID 转换为名称
+            convertedForm.documents = this.safeGetNamesByIds(this.AIform.documents, this.documentList);
+
+            // 将文档目录 ID 转换为名称,如果为空则传递 '全部'
+            convertedForm.document_directories = this.safeGetNamesByIds(this.AIform.document_directories, this.directoryList);
+            if (convertedForm.document_directories.length === 0) {
+              convertedForm.document_directories = ['全部'];
+            }
+
+            console.log('Converted form:', convertedForm);
+
+            // 使用 axios 发送 POST 请求
+            const response = await axios.post(`http://192.168.1.199:8084/chatbot/configSave/`, convertedForm, {
+              headers: {
+                'Content-Type': 'application/json'
+              }
+            });
+
+            if (response.status === 200 && response.data.code === 200) {
+              this.$message.success('应用生成成功');
+              // 可选:重定向到新应用或更新 UI
+            } else {
+              this.$message.error(response.data.message || '应用生成失败');
+            }
+          } catch (error) {
+            console.error('Error generating application:', error);
+            this.$message.error('应用生成失败,请稍后重试');
+          }
+        } else {
+          this.$message.error('请填写所有必填字段');
+          return false;
+        }
+      });
+    },
+  
+    // 安全的辅助方法:通过 ID 数组获取名称数组
+    safeGetNamesByIds(ids, list) {
+      if (!Array.isArray(ids)) {
+        console.warn('Expected an array of ids, but received:', ids);
+        return [];
+      }
+      return ids.map(id => {
+        if (id === '001') {
+          return '全部';
+        }
+        const item = list.find(item => item.id === id);
+        return item ? item.name : '';
+      }).filter(name => name !== '');
+    },
+    /* 监听联动 */
+    handleKnowledgeBaseChange(val) {
+      // 重置目录和文档选择
+      this.AIform.document_directories = [];
+      this.AIform.documents = [];
+      this.documentList = [];
+      this.bucket_id=val[0]
+      // 根据选中的知识库加载目录列表
+      // 这里需要调用后端 API 来获取目录列表
+      this.loadDirectoryList(val);
+    },
+    handleDirectoryChange(val) {
+      // 重置文档选择
+      this.AIform.documents = [];
+      
+      // 根据选中的目录加载文档列表
+      // 这里需要调用后端 API 来获取文档列表
+      this.loadDocumentList(val);
+    },
+    async loadDirectoryList(val) {
+      this.directoryList = []; // 清空现有目录列表
+      let totalDocuments = 0;
+      let otherFolderCount = 0;
+      
+      for (const kbId of val) {
+        const typeForm = {
+          page: 1,
+          pageSize: 9999,
+          kb_id: kbId,
+        };
+        
+        try {
+          const res = await selectTypeList(typeForm);
+          // 假设 res.data 包含目录列表
+          if (res.data && Array.isArray(res.data)) {
+            // 将新的目录添加到列表中,避免重复
+            this.directoryList = [...new Set([...this.directoryList, ...res.data])];
+            
+            // 计算总文档数和其他文件夹数量
+            res.data.forEach(folder => {
+              if (folder.id === "other") {
+                otherFolderCount += folder.document_count || 0;
+              } else {
+                totalDocuments += folder.document_count || 0;
+              }
+            });
+          }
+        } catch (error) {
+          console.error(`Error loading directory list for kb_id ${kbId}:`, error);
+          // 可以在这里添加错误处理,比如显示一个错误提示
+        }
+      }
+      
+      // 在列表开头插入"全部"选项
+      this.directoryList.unshift({
+        id: "001",
+        name: "全部",
+        document_count: totalDocuments + otherFolderCount,
+      });
+    },
+    loadDocumentList(val) {
+      let queryForm={
+        page: 1,
+        pageSize: 9999,
+        bucket_id: this.bucket_id,
+        doc_type_id: val[0]=='001'?0 :val[0],
+      }
+      getBucketContents(queryForm).then(res=>{
+        console.log(res);
+        this.documentList=res.data.documents
+      })
+    },
+
+
 /* 聊天记录 */
 selectChat(index) {
   this.currentChatIndex = index;
@@ -422,9 +593,25 @@ newChat() {
         this.websocket.close();
       }
     },
+    /* 获取列表 */
+    init(){
+      /* 模型库 */
+      modelList({model_type:'model'}).then(res=>{
+       this.modelNameList=res.data
+      })
+      /* 知识库 */
+      listBuckets({ user_id: this.$store.state.user.id }).then(res=>{
+        this.kneList=res.data
+      })
+      /* 配置列表 */
+      configList().then(res=>{
+        console.log(res);
+      })
+    }
   },
   updated() {
     const messagesContainer = this.$el.querySelector(".messages");
     messagesContainer.scrollTop = messagesContainer.scrollHeight;
   },
+  
 };

+ 3 - 0
src/layout/components/Navbar.vue

@@ -83,6 +83,9 @@ export default {
   methods: {
     openChatDialog() {
       this.chatDialogVisible = true;
+      /* this.$router.push({
+        path: "/knowledge/chatPage/index",
+      }) */
     },
     toggleSideBar() {
       this.$store.dispatch("app/toggleSideBar");

+ 2 - 2
src/router/index.js

@@ -340,13 +340,13 @@ export const asyncRoutes = [
         hidden:true,
         meta: { title: '知识库配置',  noCache: true ,roles: ['admin']}
       },
-      {
+      /* {
         path: 'chatPage/index',
         component: () => import('@/views/chatPage/index.vue'),
         name: 'chatbot',
       
         meta: { title: '聊天应用',  noCache: true ,roles: ['admin']}
-      }
+      } */
     ]
   },
     {

+ 20 - 9
src/views/chatPage/index.vue

@@ -39,14 +39,25 @@
   };
   </script>
   <style scoped>
-  ::v-deep .chat-container {
+/*   ::v-deep .chat-container {
     height: 100vh;
-  }
-  ::v-deep .messages {
-    margin-bottom: 0;
-    height: calc(100vh - 120px);
-  }
-  ::v-deep .input-container {
-    max-width: 1200px;
-  }
+  } */
+  ::v-deep .chat-container .header {
+  width: 98%;
+  margin: 10px 20px;
+}
+::v-deep .messages {
+  width: 98%;
+  margin-bottom: 0;
+  height: calc(100vh - 120px);
+}
+::v-deep .input-container {
+  max-width: 1200px;
+}
+::v-deep .title {
+  width: 98%;
+  margin: 0 20px 15px;
+  display: flex;
+  align-items: center;
+}
   </style>

+ 68 - 47
src/views/document/create.vue

@@ -1373,17 +1373,14 @@ export default {
     async onTemplateInfo(id) {
       try {
         this.loading = true;
+        // 获取文档信息
         const res = await getDocumentInfo({ id });
 
-        if (res.status !== 200) {
-          throw new Error("Invalid response status");
-        }
-
-        // 确保 res.data 存在
-        if (!res.data) {
-          throw new Error("No data received from getDocumentInfo");
+        if (res.status !== 200 || !res.data) {
+          throw new Error("无效的响应或未收到数据");
         }
 
+        // 设置文档属性
         this.docAttr = {
           id: this.docAttr.id,
           category_id: Number(this.docAttr.category_id),
@@ -1397,71 +1394,95 @@ export default {
           projects: res.data.projects || "",
         };
 
-        // 确保 res.data.data 是有效的 JSON 字符串
-        const templateData = res.data.data ? JSON.parse(res.data.data) : [];
+        // 解析文档数据
+        const documentData = res.data.data ? JSON.parse(res.data.data) : [];
 
         const updatedComs = await Promise.all(
-          templateData.map(async (el) => {
-            if (!el || !el.id) {
-              console.warn("Invalid template item:", el);
+          documentData.map(async (docEl) => {
+            if (!docEl || !docEl.id) {
+              console.warn("无效的文档项:", docEl);
               return null;
             }
 
-            const templateInfo = await getTemplateInfo({ id: el.id });
+            // 获取模板信息
+            const templateInfo = await getTemplateInfo({ id: docEl.id });
+            // 获取公式数据
             const formulaData = await searchFormula({ page: 1, pageSize: 999 });
 
-            // 确保 templateInfo.data 和 templateInfo.data.attrs 存在
-            let attrs =
-              templateInfo.data && templateInfo.data.attrs
-                ? JSON.parse(templateInfo.data.attrs)
-                : [];
+            // 使用模板的 content 作为基础
+            let content = templateInfo.data.content;
+            // 使用模板的 attrs 作为基础,但排除 Directory 类型
+            let attrs = templateInfo.data.attrs
+              ? JSON.parse(templateInfo.data.attrs).filter(
+                  (attr) => attr.type !== "Directory"
+                )
+              : [];
+
+            // 从文档数据中提取所有 Directory 类型的属性
+            const docDirectories = docEl.attrs.filter(
+              (attr) => attr.type === "Directory"
+            );
+
+            // 将文档中的 Directory 属性添加到 attrs 中
+            attrs = [...attrs, ...docDirectories];
+
+            // 解析 content 中的所有项
+            const contentItems = (content.match(/{{([^}]+)}}/g) || []).map(
+              (match) => match.slice(2, -2)
+            );
+            console.log('contentItems',contentItems);
+            // 确保 content 中引用的所有 Directory 项都存在于 attrs 中
+            contentItems.forEach((itemId) => {
+              if (
+                itemId.startsWith("Directory_") &&
+                !attrs.some((attr) => attr.id === itemId)
+              ) {
+                const [, moduleIndex, level] = itemId.split("_");
+                attrs.push({
+                  type: "Directory",
+                  id: itemId,
+                  name: "目录信息",
+                  intro: "目录信息",
+                  number: "",
+                  content: "",
+                  level: parseInt(level),
+                  moduleIndex: parseInt(moduleIndex),
+                });
+              }
+            });
 
+            // 更新公式数据
             attrs = attrs.map((item) => {
-              // 如果是目录类型,保留原始数据,但要确保正确更新
-              if (item.type === "Directory") {
-                const matchingAttr = el.attrs.find(
-                  (e) => e.type === "Directory" && e.id === item.id
+              if (item.type === "formual" && item.data && item.data.id) {
+                const matchedFormula = formulaData.data.dataList.find(
+                  (ite) => ite.id === item.data.id
                 );
-                console.log(el.attrs);
-                if (matchingAttr) {
-                  return { ...item, number: matchingAttr.number };
+                if (matchedFormula) {
+                  return {
+                    ...item,
+                    data: matchedFormula,
+                    formula: matchedFormula.formula,
+                  };
                 }
-                
-                return item;
-              }
-              if (!item || !item.data || !item.data.id) {
-                console.warn("Invalid attribute item:", item);
-                return item; // 保留原始项,即使它可能是无效的
-              }
-
-              const matchedFormula = formulaData.data.dataList.find(
-                (ite) => ite.id === item.data.id
-              );
-              if (matchedFormula) {
-                return {
-                  ...item,
-                  data: matchedFormula,
-                  formula: matchedFormula.formula,
-                };
               }
               return item;
             });
 
-            return { ...el, ...(templateInfo.data || {}), attrs };
+            // 返回更新后的数据,以模板信息为主,但 Directory 项完全使用文档信息
+            return { ...templateInfo.data, attrs, content };
           })
         );
 
-        // 过滤掉 null 值
+        // 过滤掉无效的组件
         this.coms = updatedComs.filter(Boolean);
-        console.log("coms", this.coms);
+        console.log("组件", this.coms);
         console.log("模版", this.docAttr);
         if (this.articleId !== undefined) {
           document.title = `${this.docAttr.title}-轻良实业`;
         }
         this.uptadeSearch();
       } catch (error) {
-        console.error("Error in onTemplateInfo:", error);
-        // 可以在这里添加用户友好的错误提示
+        console.error("加载模板信息时出错:", error);
         this.$message.error("加载模板信息时出错,请稍后重试");
       } finally {
         this.loading = false;

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно