feat: dynamic URL (#3444)
This commit is contained in:
parent
9b89e8f75c
commit
2ad5883aef
@ -102,11 +102,15 @@ class Config(dict):
|
|||||||
return self.get('LOG_LEVEL', 'DEBUG')
|
return self.get('LOG_LEVEL', 'DEBUG')
|
||||||
|
|
||||||
def get_sandbox_python_package_paths(self):
|
def get_sandbox_python_package_paths(self):
|
||||||
return self.get('SANDBOX_PYTHON_PACKAGE_PATHS', '/opt/py3/lib/python3.11/site-packages,/opt/maxkb-app/sandbox/python-packages,/opt/maxkb/python-packages')
|
return self.get('SANDBOX_PYTHON_PACKAGE_PATHS',
|
||||||
|
'/opt/py3/lib/python3.11/site-packages,/opt/maxkb-app/sandbox/python-packages,/opt/maxkb/python-packages')
|
||||||
|
|
||||||
def get_admin_path(self):
|
def get_admin_path(self):
|
||||||
return self.get('ADMIN_PATH', 'admin')
|
return self.get('ADMIN_PATH', 'admin')
|
||||||
|
|
||||||
|
def get_chat_path(self):
|
||||||
|
return self.get('CHAT_PATH', '/chat')
|
||||||
|
|
||||||
def get_session_timeout(self):
|
def get_session_timeout(self):
|
||||||
return int(self.get('SESSION_TIMEOUT', 28800))
|
return int(self.get('SESSION_TIMEOUT', 28800))
|
||||||
|
|
||||||
|
|||||||
@ -55,7 +55,7 @@ MIDDLEWARE = [
|
|||||||
'django.middleware.security.SecurityMiddleware',
|
'django.middleware.security.SecurityMiddleware',
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
'django.middleware.common.CommonMiddleware',
|
'django.middleware.common.CommonMiddleware',
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
REST_FRAMEWORK = {
|
REST_FRAMEWORK = {
|
||||||
@ -63,7 +63,7 @@ REST_FRAMEWORK = {
|
|||||||
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
|
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
|
||||||
'DEFAULT_AUTHENTICATION_CLASSES': ['common.auth.authenticate.AnonymousAuthentication']
|
'DEFAULT_AUTHENTICATION_CLASSES': ['common.auth.authenticate.AnonymousAuthentication']
|
||||||
}
|
}
|
||||||
STATICFILES_DIRS = [(os.path.join(PROJECT_DIR, 'ui', 'dist')), (os.path.join(PROJECT_DIR, 'chat', 'dist'))]
|
STATICFILES_DIRS = [(os.path.join(PROJECT_DIR, 'ui', 'dist'))]
|
||||||
STATIC_ROOT = os.path.join(BASE_DIR.parent, 'static')
|
STATIC_ROOT = os.path.join(BASE_DIR.parent, 'static')
|
||||||
ROOT_URLCONF = 'maxkb.urls'
|
ROOT_URLCONF = 'maxkb.urls'
|
||||||
APPS_DIR = os.path.join(PROJECT_DIR, 'apps')
|
APPS_DIR = os.path.join(PROJECT_DIR, 'apps')
|
||||||
@ -71,7 +71,7 @@ APPS_DIR = os.path.join(PROJECT_DIR, 'apps')
|
|||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
{
|
{
|
||||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||||
'DIRS': ["apps/static/ui"],
|
'DIRS': ["apps/static/admin"],
|
||||||
'APP_DIRS': True,
|
'APP_DIRS': True,
|
||||||
'OPTIONS': {
|
'OPTIONS': {
|
||||||
'context_processors': [
|
'context_processors': [
|
||||||
|
|||||||
@ -16,7 +16,7 @@ Including another URLconf
|
|||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse,HttpResponseRedirect
|
||||||
from django.urls import path, re_path, include
|
from django.urls import path, re_path, include
|
||||||
from django.views import static
|
from django.views import static
|
||||||
from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView
|
from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView
|
||||||
@ -25,16 +25,21 @@ from rest_framework import status
|
|||||||
from common.result import Result
|
from common.result import Result
|
||||||
from maxkb import settings
|
from maxkb import settings
|
||||||
from maxkb.conf import PROJECT_DIR
|
from maxkb.conf import PROJECT_DIR
|
||||||
|
from maxkb.const import CONFIG
|
||||||
|
|
||||||
|
admin_api_prefix = CONFIG.get_admin_path()[1:] + '/api/'
|
||||||
|
admin_ui_prefix = CONFIG.get_admin_path()
|
||||||
|
chat_api_prefix = CONFIG.get_chat_path()[1:] + '/api/'
|
||||||
|
chat_ui_prefix = CONFIG.get_chat_path()
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("api/", include("users.urls")),
|
path(admin_api_prefix, include("users.urls")),
|
||||||
path("api/", include("tools.urls")),
|
path(admin_api_prefix, include("tools.urls")),
|
||||||
path("api/", include("models_provider.urls")),
|
path(admin_api_prefix, include("models_provider.urls")),
|
||||||
path("api/", include("folders.urls")),
|
path(admin_api_prefix, include("folders.urls")),
|
||||||
path("api/", include("knowledge.urls")),
|
path(admin_api_prefix, include("knowledge.urls")),
|
||||||
path("api/", include("system_manage.urls")),
|
path(admin_api_prefix, include("system_manage.urls")),
|
||||||
path("api/", include("application.urls")),
|
path(admin_api_prefix, include("application.urls")),
|
||||||
path("chat/api/", include("chat.urls")),
|
path(chat_api_prefix, include("chat.urls")),
|
||||||
path('oss/', include('oss.urls')),
|
path('oss/', include('oss.urls')),
|
||||||
]
|
]
|
||||||
urlpatterns += [
|
urlpatterns += [
|
||||||
@ -54,12 +59,14 @@ def pro():
|
|||||||
)
|
)
|
||||||
# 暴露ui静态资源
|
# 暴露ui静态资源
|
||||||
urlpatterns.append(
|
urlpatterns.append(
|
||||||
re_path(r'^ui/(?P<path>.*)$', static.serve, {'document_root': os.path.join(settings.STATIC_ROOT, "ui")},
|
re_path(rf"^{CONFIG.get_admin_path()[1:]}/(?P<path>.*)$", static.serve,
|
||||||
name='ui'),
|
{'document_root': os.path.join(settings.STATIC_ROOT, "admin")},
|
||||||
|
name='admin'),
|
||||||
)
|
)
|
||||||
# 暴露ui静态资源
|
# 暴露ui静态资源
|
||||||
urlpatterns.append(
|
urlpatterns.append(
|
||||||
re_path(r'^chat/(?P<path>.*)$', static.serve, {'document_root': os.path.join(settings.STATIC_ROOT, "chat")},
|
re_path(rf'^{CONFIG.get_chat_path()[1:]}/(?P<path>.*)$', static.serve,
|
||||||
|
{'document_root': os.path.join(settings.STATIC_ROOT, "chat")},
|
||||||
name='chat'),
|
name='chat'),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -79,18 +86,26 @@ def page_not_found(request, exception):
|
|||||||
"""
|
"""
|
||||||
页面不存在处理
|
页面不存在处理
|
||||||
"""
|
"""
|
||||||
if request.path.startswith("/api/"):
|
if request.path.startswith(admin_ui_prefix + '/api/'):
|
||||||
return Result(response_status=status.HTTP_404_NOT_FOUND, code=404, message="HTTP_404_NOT_FOUND")
|
return Result(response_status=status.HTTP_404_NOT_FOUND, code=404, message="HTTP_404_NOT_FOUND")
|
||||||
if request.path.startswith("/chat/api/"):
|
if request.path.startswith(chat_ui_prefix + '/api/'):
|
||||||
return Result(response_status=status.HTTP_404_NOT_FOUND, code=404, message="HTTP_404_NOT_FOUND")
|
return Result(response_status=status.HTTP_404_NOT_FOUND, code=404, message="HTTP_404_NOT_FOUND")
|
||||||
if request.path.startswith('/chat'):
|
if request.path.startswith(chat_ui_prefix):
|
||||||
index_path = os.path.join(PROJECT_DIR, 'apps', "static", 'chat', 'index.html')
|
index_path = os.path.join(PROJECT_DIR, 'apps', "static", 'chat', 'index.html')
|
||||||
|
content = get_index_html(index_path)
|
||||||
|
content.replace("prefix: '/chat'", f"prefix: {CONFIG.get_chat_path()}")
|
||||||
|
if not os.path.exists(index_path):
|
||||||
|
return HttpResponse("页面不存在", status=404)
|
||||||
|
return HttpResponse(content, status=200)
|
||||||
|
elif request.path.startswith(admin_ui_prefix):
|
||||||
|
index_path = os.path.join(PROJECT_DIR, 'apps', "static", 'admin', 'index.html')
|
||||||
|
if not os.path.exists(index_path):
|
||||||
|
return HttpResponse("页面不存在", status=404)
|
||||||
|
content = get_index_html(index_path)
|
||||||
|
content = content.replace("prefix: '/admin'", f"prefix: '{CONFIG.get_admin_path()}'")
|
||||||
|
return HttpResponse(content, status=200)
|
||||||
else:
|
else:
|
||||||
index_path = os.path.join(PROJECT_DIR, 'apps', "static", 'ui', 'index.html')
|
return HttpResponseRedirect(admin_ui_prefix+'/')
|
||||||
if not os.path.exists(index_path):
|
|
||||||
return HttpResponse("页面不存在", status=404)
|
|
||||||
content = get_index_html(index_path)
|
|
||||||
return HttpResponse(content, status=200)
|
|
||||||
|
|
||||||
|
|
||||||
handler404 = page_not_found
|
handler404 = page_not_found
|
||||||
|
|||||||
@ -7,6 +7,11 @@
|
|||||||
<base target="_blank" />
|
<base target="_blank" />
|
||||||
<title>%VITE_APP_TITLE%</title>
|
<title>%VITE_APP_TITLE%</title>
|
||||||
</head>
|
</head>
|
||||||
|
<script>
|
||||||
|
window.MaxKB = {
|
||||||
|
prefix: '/admin',
|
||||||
|
}
|
||||||
|
</script>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<script type="module" src="/src/main.ts"></script>
|
<script type="module" src="/src/main.ts"></script>
|
||||||
@ -7,6 +7,11 @@
|
|||||||
<base target="_blank" />
|
<base target="_blank" />
|
||||||
<title>%VITE_APP_TITLE%</title>
|
<title>%VITE_APP_TITLE%</title>
|
||||||
</head>
|
</head>
|
||||||
|
<script>
|
||||||
|
window.MaxKB = {
|
||||||
|
prefix: '/chat',
|
||||||
|
}
|
||||||
|
</script>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<script type="module" src="/src/chat.ts"></script>
|
<script type="module" src="/src/chat.ts"></script>
|
||||||
6
ui/env.d.ts
vendored
6
ui/env.d.ts
vendored
@ -1 +1,7 @@
|
|||||||
/// <reference types="vite/client" />
|
/// <reference types="vite/client" />
|
||||||
|
interface Window {
|
||||||
|
sendMessage: ?((message: string, other_params_data: any) => void)
|
||||||
|
MaxKB: {
|
||||||
|
prefix: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
6
ui/env/.env
vendored
6
ui/env/.env
vendored
@ -1,5 +1,5 @@
|
|||||||
VITE_APP_NAME=ui
|
VITE_APP_NAME=admin
|
||||||
VITE_BASE_PATH=/ui/
|
VITE_BASE_PATH=/admin/
|
||||||
VITE_APP_PORT=3000
|
VITE_APP_PORT=3000
|
||||||
VITE_APP_TITLE = 'MaxKB'
|
VITE_APP_TITLE = 'MaxKB'
|
||||||
VITE_ENTRY="entry/system/index.html"
|
VITE_ENTRY="admin.html"
|
||||||
2
ui/env/.env.chat
vendored
2
ui/env/.env.chat
vendored
@ -2,4 +2,4 @@ VITE_APP_NAME=chat
|
|||||||
VITE_BASE_PATH=/chat/
|
VITE_BASE_PATH=/chat/
|
||||||
VITE_APP_PORT=3001
|
VITE_APP_PORT=3001
|
||||||
VITE_APP_TITLE = 'MaxKB'
|
VITE_APP_TITLE = 'MaxKB'
|
||||||
VITE_ENTRY="entry/chat/index.html"
|
VITE_ENTRY="chat.html"
|
||||||
@ -177,7 +177,8 @@ const open: (application_id: string, loading?: Ref<boolean>) => Promise<Result<s
|
|||||||
* data
|
* data
|
||||||
*/
|
*/
|
||||||
const chat: (chat_id: string, data: any) => Promise<any> = (chat_id, data) => {
|
const chat: (chat_id: string, data: any) => Promise<any> = (chat_id, data) => {
|
||||||
return postStream(`/api/chat_message/${chat_id}`, data)
|
const prefix = (window.MaxKB?.prefix ? window.MaxKB?.prefix : '/admin') + '/api'
|
||||||
|
return postStream(`${prefix}/chat_message/${chat_id}`, data)
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 获取对话用户认证类型
|
* 获取对话用户认证类型
|
||||||
|
|||||||
@ -40,7 +40,8 @@ const open: (loading?: Ref<boolean>) => Promise<Result<string>> = (loading) => {
|
|||||||
* data
|
* data
|
||||||
*/
|
*/
|
||||||
const chat: (chat_id: string, data: any) => Promise<any> = (chat_id, data) => {
|
const chat: (chat_id: string, data: any) => Promise<any> = (chat_id, data) => {
|
||||||
return postStream(`/chat/api/chat_message/${chat_id}`, data)
|
const prefix = (window.MaxKB?.prefix ? window.MaxKB?.prefix : '/chat') + '/api'
|
||||||
|
return postStream(`${prefix}/chat_message/${chat_id}`, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -4,12 +4,11 @@ import type { NProgress } from 'nprogress'
|
|||||||
import type { Ref } from 'vue'
|
import type { Ref } from 'vue'
|
||||||
import type { Result } from '@/request/Result'
|
import type { Result } from '@/request/Result'
|
||||||
import useStore from '@/stores'
|
import useStore from '@/stores'
|
||||||
import router from '@/router'
|
|
||||||
|
|
||||||
import { ref, type WritableComputedRef } from 'vue'
|
import { ref, type WritableComputedRef } from 'vue'
|
||||||
|
|
||||||
const axiosConfig = {
|
const axiosConfig = {
|
||||||
baseURL: '/chat/api',
|
baseURL: (window.MaxKB?.prefix ? window.MaxKB?.prefix : '/chat') + '/api',
|
||||||
withCredentials: false,
|
withCredentials: false,
|
||||||
timeout: 600000,
|
timeout: 600000,
|
||||||
headers: {},
|
headers: {},
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import router from '@/router'
|
|||||||
import { ref, type WritableComputedRef } from 'vue'
|
import { ref, type WritableComputedRef } from 'vue'
|
||||||
|
|
||||||
const axiosConfig = {
|
const axiosConfig = {
|
||||||
baseURL: '/api',
|
baseURL: (window.MaxKB?.prefix ? window.MaxKB?.prefix : '/admin') + '/api',
|
||||||
withCredentials: false,
|
withCredentials: false,
|
||||||
timeout: 600000,
|
timeout: 600000,
|
||||||
headers: {},
|
headers: {},
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import useStore from '@/stores'
|
|||||||
import { routes } from '@/router/chat/routes'
|
import { routes } from '@/router/chat/routes'
|
||||||
NProgress.configure({ showSpinner: false, speed: 500, minimum: 0.3 })
|
NProgress.configure({ showSpinner: false, speed: 500, minimum: 0.3 })
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(import.meta.env.BASE_URL),
|
history: createWebHistory(window.MaxKB?.prefix ? window.MaxKB?.prefix : import.meta.env.BASE_URL),
|
||||||
routes: routes,
|
routes: routes,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -7,14 +7,13 @@ import {
|
|||||||
createWebHistory,
|
createWebHistory,
|
||||||
type NavigationGuardNext,
|
type NavigationGuardNext,
|
||||||
type RouteLocationNormalized,
|
type RouteLocationNormalized,
|
||||||
type RouteRecordRaw,
|
|
||||||
type RouteRecordName,
|
type RouteRecordName,
|
||||||
} from 'vue-router'
|
} from 'vue-router'
|
||||||
import useStore from '@/stores'
|
import useStore from '@/stores'
|
||||||
import { routes } from '@/router/routes'
|
import { routes } from '@/router/routes'
|
||||||
NProgress.configure({ showSpinner: false, speed: 500, minimum: 0.3 })
|
NProgress.configure({ showSpinner: false, speed: 500, minimum: 0.3 })
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(import.meta.env.BASE_URL),
|
history: createWebHistory(window.MaxKB?.prefix ? window.MaxKB?.prefix : import.meta.env.BASE_URL),
|
||||||
routes: routes,
|
routes: routes,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { model } from '@/permission/model'
|
||||||
import { fileURLToPath, URL } from 'node:url'
|
import { fileURLToPath, URL } from 'node:url'
|
||||||
import type { ProxyOptions } from 'vite'
|
import type { ProxyOptions } from 'vite'
|
||||||
import { defineConfig, loadEnv } from 'vite'
|
import { defineConfig, loadEnv } from 'vite'
|
||||||
@ -6,21 +7,39 @@ import vueJsx from '@vitejs/plugin-vue-jsx'
|
|||||||
import DefineOptions from 'unplugin-vue-define-options/vite'
|
import DefineOptions from 'unplugin-vue-define-options/vite'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { createHtmlPlugin } from 'vite-plugin-html'
|
import { createHtmlPlugin } from 'vite-plugin-html'
|
||||||
|
import fs from 'fs'
|
||||||
// import vueDevTools from 'vite-plugin-vue-devtools'
|
// import vueDevTools from 'vite-plugin-vue-devtools'
|
||||||
const envDir = './env'
|
const envDir = './env'
|
||||||
|
// 自定义插件:重命名入口文件
|
||||||
|
const renameHtmlPlugin = (outDir: string, entry: string) => {
|
||||||
|
return {
|
||||||
|
name: 'rename-html',
|
||||||
|
closeBundle: () => {
|
||||||
|
const buildDir = path.resolve(__dirname, outDir)
|
||||||
|
const oldFile = path.join(buildDir, entry)
|
||||||
|
const newFile = path.join(buildDir, 'index.html')
|
||||||
|
|
||||||
|
// 检查文件是否存在
|
||||||
|
if (fs.existsSync(oldFile)) {
|
||||||
|
// 删除已存在的 index.html
|
||||||
|
if (fs.existsSync(newFile)) {
|
||||||
|
fs.unlinkSync(newFile)
|
||||||
|
}
|
||||||
|
// 重命名文件
|
||||||
|
fs.renameSync(oldFile, newFile)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig(({ mode }) => {
|
export default defineConfig((conf: any) => {
|
||||||
|
const mode = conf.mode
|
||||||
const ENV = loadEnv(mode, envDir)
|
const ENV = loadEnv(mode, envDir)
|
||||||
console.log(ENV)
|
|
||||||
const prefix = process.env.VITE_DYNAMIC_PREFIX || ENV.VITE_BASE_PATH
|
|
||||||
const proxyConf: Record<string, string | ProxyOptions> = {}
|
const proxyConf: Record<string, string | ProxyOptions> = {}
|
||||||
proxyConf['/api'] = {
|
proxyConf['/admin/api'] = {
|
||||||
// target: 'http://47.92.195.88:8080',
|
// target: 'http://47.92.195.88:8080',
|
||||||
target: 'http://127.0.0.1:8080',
|
target: 'http://127.0.0.1:8080',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (path: string) => path.replace(ENV.VITE_BASE_PATH, '/'),
|
|
||||||
}
|
}
|
||||||
proxyConf['/oss'] = {
|
proxyConf['/oss'] = {
|
||||||
target: 'http://127.0.0.1:8080',
|
target: 'http://127.0.0.1:8080',
|
||||||
@ -46,12 +65,19 @@ export default defineConfig(({ mode }) => {
|
|||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (path: string) => path.replace(ENV.VITE_BASE_PATH, '/'),
|
rewrite: (path: string) => path.replace(ENV.VITE_BASE_PATH, '/'),
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
preflight: false,
|
preflight: false,
|
||||||
lintOnSave: false,
|
lintOnSave: false,
|
||||||
base: prefix,
|
base: './',
|
||||||
envDir: envDir,
|
envDir: envDir,
|
||||||
plugins: [vue(), vueJsx(), DefineOptions(), createHtmlPlugin({ template: ENV.VITE_ENTRY })],
|
plugins: [
|
||||||
|
vue(),
|
||||||
|
vueJsx(),
|
||||||
|
DefineOptions(),
|
||||||
|
createHtmlPlugin({ template: ENV.VITE_ENTRY }),
|
||||||
|
renameHtmlPlugin(`dist${ENV.VITE_BASE_PATH}`, ENV.VITE_ENTRY),
|
||||||
|
],
|
||||||
server: {
|
server: {
|
||||||
cors: true,
|
cors: true,
|
||||||
host: '0.0.0.0',
|
host: '0.0.0.0',
|
||||||
@ -62,7 +88,7 @@ export default defineConfig(({ mode }) => {
|
|||||||
build: {
|
build: {
|
||||||
outDir: `dist${ENV.VITE_BASE_PATH}`,
|
outDir: `dist${ENV.VITE_BASE_PATH}`,
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
input: path.resolve(__dirname, ENV.VITE_ENTRY),
|
input: ENV.VITE_ENTRY,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user