feat: 添加系统信息配置功能
- 在 API 路由中新增获取和重新加载系统信息配置的接口。 - 实现信息配置的加载逻辑,并提供默认配置。 - 更新前端以支持动态加载和展示信息配置。 - 修改 Dockerfile,移除代理设置。
This commit is contained in:
parent
2760efcbb7
commit
4ecf9a8cd6
@ -35,8 +35,7 @@ COPY ../src /app/src
|
|||||||
COPY ../server /app/server
|
COPY ../server /app/server
|
||||||
|
|
||||||
# 关闭代理设置
|
# 关闭代理设置
|
||||||
ENV http_proxy="" \
|
RUN unset http_proxy https_proxy
|
||||||
https_proxy=""
|
|
||||||
|
|
||||||
# 同步项目
|
# 同步项目
|
||||||
RUN --mount=type=cache,target=/root/.cache/uv \
|
RUN --mount=type=cache,target=/root/.cache/uv \
|
||||||
|
|||||||
@ -1,13 +1,63 @@
|
|||||||
from fastapi import Request, Body, Depends
|
import os
|
||||||
|
import yaml
|
||||||
|
from pathlib import Path
|
||||||
|
from fastapi import Request, Body, Depends, HTTPException
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
|
||||||
from src import config, retriever, knowledge_base, graph_base
|
from src import config, retriever, knowledge_base, graph_base
|
||||||
from server.utils.auth_middleware import get_admin_user, get_superadmin_user
|
from server.utils.auth_middleware import get_admin_user, get_superadmin_user
|
||||||
from server.models.user_model import User
|
from server.models.user_model import User
|
||||||
|
from src.utils.logging_config import logger
|
||||||
|
|
||||||
|
|
||||||
base = APIRouter()
|
base = APIRouter()
|
||||||
|
|
||||||
|
def load_info_config():
|
||||||
|
"""加载信息配置文件"""
|
||||||
|
try:
|
||||||
|
# 配置文件路径
|
||||||
|
config_path = Path("src/static/info.local.yaml")
|
||||||
|
|
||||||
|
# 检查文件是否存在
|
||||||
|
if not config_path.exists():
|
||||||
|
logger.warning(f"配置文件 {config_path} 不存在,使用默认配置")
|
||||||
|
return get_default_info_config()
|
||||||
|
|
||||||
|
# 读取配置文件
|
||||||
|
with open(config_path, 'r', encoding='utf-8') as file:
|
||||||
|
config = yaml.safe_load(file)
|
||||||
|
|
||||||
|
# logger.info(f"成功加载信息配置文件: {config_path}")
|
||||||
|
return config
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"加载信息配置文件失败: {e}")
|
||||||
|
return get_default_info_config()
|
||||||
|
|
||||||
|
def get_default_info_config():
|
||||||
|
"""获取默认信息配置"""
|
||||||
|
return {
|
||||||
|
"organization": {
|
||||||
|
"name": "江南大学",
|
||||||
|
"short_name": "语析",
|
||||||
|
"logo": "/favicon.svg",
|
||||||
|
"avatar": "/avatar.jpg"
|
||||||
|
},
|
||||||
|
"branding": {
|
||||||
|
"title": "Yuxi-Know",
|
||||||
|
"subtitle": "大模型驱动的知识库管理工具",
|
||||||
|
"description": "结合知识库与知识图谱,提供更准确、更全面的回答"
|
||||||
|
},
|
||||||
|
"features": [
|
||||||
|
"📚 灵活知识库",
|
||||||
|
"🕸️ 知识图谱集成",
|
||||||
|
"🤖 多模型支持"
|
||||||
|
],
|
||||||
|
"footer": {
|
||||||
|
"copyright": "© 江南大学 2025 [WIP] v0.12.138"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@base.get("/")
|
@base.get("/")
|
||||||
async def route_index():
|
async def route_index():
|
||||||
return {"message": "You Got It!"}
|
return {"message": "You Got It!"}
|
||||||
@ -58,4 +108,32 @@ def get_log(current_user: User = Depends(get_admin_user)):
|
|||||||
log = ''.join(last_lines)
|
log = ''.join(last_lines)
|
||||||
return {"log": log, "message": "success", "log_file": LOG_FILE}
|
return {"log": log, "message": "success", "log_file": LOG_FILE}
|
||||||
|
|
||||||
|
@base.get("/info")
|
||||||
|
async def get_info_config():
|
||||||
|
"""获取系统信息配置(公开接口,无需认证)"""
|
||||||
|
try:
|
||||||
|
config = load_info_config()
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"data": config
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"获取信息配置失败: {e}")
|
||||||
|
raise HTTPException(status_code=500, detail="获取信息配置失败")
|
||||||
|
|
||||||
|
@base.get("/info/reload")
|
||||||
|
async def reload_info_config():
|
||||||
|
"""重新加载信息配置(管理员接口)"""
|
||||||
|
# 注:这里暂时不添加权限验证,后续可以根据需要添加
|
||||||
|
try:
|
||||||
|
config = load_info_config()
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"message": "配置重新加载成功",
|
||||||
|
"data": config
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"重新加载信息配置失败: {e}")
|
||||||
|
raise HTTPException(status_code=500, detail="重新加载信息配置失败")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,8 @@ PUBLIC_PATHS = [
|
|||||||
r"^/api/auth/initialize$", # 初始化系统
|
r"^/api/auth/initialize$", # 初始化系统
|
||||||
r"^/api$", # Health Check
|
r"^/api$", # Health Check
|
||||||
r"^/api/login$", # 登录页面
|
r"^/api/login$", # 登录页面
|
||||||
|
r"^/api/info$", # 获取系统信息配置
|
||||||
|
r"^/api/info/.*$", # 系统信息配置相关接口
|
||||||
]
|
]
|
||||||
|
|
||||||
# 获取数据库会话
|
# 获取数据库会话
|
||||||
|
|||||||
26
src/static/info.template.yaml
Normal file
26
src/static/info.template.yaml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# 单位信息配置文件
|
||||||
|
# 用于配置网站的基本信息、品牌信息等
|
||||||
|
# 修改后需要重启服务生效
|
||||||
|
|
||||||
|
# 组织信息
|
||||||
|
organization:
|
||||||
|
name: "江南语析" # 完整组织名称
|
||||||
|
short_name: "语析" # 简短名称
|
||||||
|
logo: "/favicon.svg" # Logo文件路径
|
||||||
|
avatar: "/avatar.jpg" # 头像文件路径
|
||||||
|
|
||||||
|
# 品牌信息
|
||||||
|
branding:
|
||||||
|
title: "Yuxi-Know" # 系统标题
|
||||||
|
subtitle: "大模型驱动的知识库管理工具" # 副标题
|
||||||
|
description: "结合知识库与知识图谱,提供更准确、更全面的回答" # 描述信息
|
||||||
|
|
||||||
|
# 功能特性
|
||||||
|
features:
|
||||||
|
- "📚 灵活知识库"
|
||||||
|
- "🕸️ 知识图谱集成"
|
||||||
|
- "🤖 多模型支持"
|
||||||
|
|
||||||
|
# 页脚信息
|
||||||
|
footer:
|
||||||
|
copyright: "© 江南语析 2025 [WIP] v0.12.138"
|
||||||
1
web/public/jnu.svg
Normal file
1
web/public/jnu.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 30 KiB |
@ -46,6 +46,21 @@ export const configApi = {
|
|||||||
getConfig: () => apiGet('/api/config'),
|
getConfig: () => apiGet('/api/config'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 系统信息配置API
|
||||||
|
export const infoApi = {
|
||||||
|
/**
|
||||||
|
* 获取系统信息配置
|
||||||
|
* @returns {Promise} - 系统信息配置
|
||||||
|
*/
|
||||||
|
getInfoConfig: () => apiGet('/api/info'),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重新加载信息配置
|
||||||
|
* @returns {Promise} - 重新加载结果
|
||||||
|
*/
|
||||||
|
reloadInfoConfig: () => apiGet('/api/info/reload')
|
||||||
|
}
|
||||||
|
|
||||||
// 健康检查API
|
// 健康检查API
|
||||||
export const healthApi = {
|
export const healthApi = {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -10,11 +10,13 @@ import { Bot, Waypoints, LibraryBig, MessageSquareMore, Settings } from 'lucide-
|
|||||||
|
|
||||||
import { useConfigStore } from '@/stores/config'
|
import { useConfigStore } from '@/stores/config'
|
||||||
import { useDatabaseStore } from '@/stores/database'
|
import { useDatabaseStore } from '@/stores/database'
|
||||||
|
import { useInfoStore } from '@/stores/info'
|
||||||
import DebugComponent from '@/components/DebugComponent.vue'
|
import DebugComponent from '@/components/DebugComponent.vue'
|
||||||
import UserInfoComponent from '@/components/UserInfoComponent.vue'
|
import UserInfoComponent from '@/components/UserInfoComponent.vue'
|
||||||
|
|
||||||
const configStore = useConfigStore()
|
const configStore = useConfigStore()
|
||||||
const databaseStore = useDatabaseStore()
|
const databaseStore = useDatabaseStore()
|
||||||
|
const infoStore = useInfoStore()
|
||||||
|
|
||||||
const layoutSettings = reactive({
|
const layoutSettings = reactive({
|
||||||
showDebug: false,
|
showDebug: false,
|
||||||
@ -51,7 +53,10 @@ const fetchGithubStars = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
|
// 加载信息配置
|
||||||
|
await infoStore.loadInfoConfig()
|
||||||
|
// 加载其他配置
|
||||||
getRemoteConfig()
|
getRemoteConfig()
|
||||||
getRemoteDatabase()
|
getRemoteDatabase()
|
||||||
fetchGithubStars() // Fetch GitHub stars on mount
|
fetchGithubStars() // Fetch GitHub stars on mount
|
||||||
@ -115,8 +120,8 @@ const mainList = [{
|
|||||||
<div class="header" :class="{ 'top-bar': layoutSettings.useTopBar }">
|
<div class="header" :class="{ 'top-bar': layoutSettings.useTopBar }">
|
||||||
<div class="logo circle">
|
<div class="logo circle">
|
||||||
<router-link to="/">
|
<router-link to="/">
|
||||||
<img src="/avatar.jpg">
|
<img :src="infoStore.organization.avatar">
|
||||||
<span class="logo-text">语析</span>
|
<span class="logo-text">{{ infoStore.organization.short_name }}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav">
|
<div class="nav">
|
||||||
|
|||||||
@ -9,9 +9,17 @@ import 'ant-design-vue/dist/reset.css';
|
|||||||
import './assets/main.css'
|
import './assets/main.css'
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
const pinia = createPinia()
|
||||||
|
|
||||||
app.use(createPinia())
|
app.use(pinia)
|
||||||
app.use(router)
|
app.use(router)
|
||||||
app.use(Antd)
|
app.use(Antd)
|
||||||
|
|
||||||
|
// 预加载信息配置
|
||||||
|
import { useInfoStore } from '@/stores/info'
|
||||||
|
const infoStore = useInfoStore()
|
||||||
|
infoStore.loadInfoConfig().then(() => {
|
||||||
|
console.log('应用信息配置预加载完成')
|
||||||
|
})
|
||||||
|
|
||||||
app.mount('#app')
|
app.mount('#app')
|
||||||
|
|||||||
108
web/src/stores/info.js
Normal file
108
web/src/stores/info.js
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { infoApi } from '@/apis/public_api'
|
||||||
|
|
||||||
|
export const useInfoStore = defineStore('info', () => {
|
||||||
|
// 状态
|
||||||
|
const infoConfig = ref({})
|
||||||
|
const isLoading = ref(false)
|
||||||
|
const isLoaded = ref(false)
|
||||||
|
|
||||||
|
// 计算属性 - 组织信息
|
||||||
|
const organization = computed(() => infoConfig.value.organization || {
|
||||||
|
name: "江南语析",
|
||||||
|
short_name: "语析",
|
||||||
|
logo: "/favicon.svg",
|
||||||
|
avatar: "/avatar.jpg"
|
||||||
|
})
|
||||||
|
|
||||||
|
// 计算属性 - 品牌信息
|
||||||
|
const branding = computed(() => infoConfig.value.branding || {
|
||||||
|
title: "Yuxi-Know",
|
||||||
|
subtitle: "大模型驱动的知识库管理工具",
|
||||||
|
description: "结合知识库与知识图谱,提供更准确、更全面的回答"
|
||||||
|
})
|
||||||
|
|
||||||
|
// 计算属性 - 功能特性
|
||||||
|
const features = computed(() => infoConfig.value.features || [
|
||||||
|
"📚 灵活知识库",
|
||||||
|
"🕸️ 知识图谱集成",
|
||||||
|
"🤖 多模型支持"
|
||||||
|
])
|
||||||
|
|
||||||
|
// 计算属性 - 页脚信息
|
||||||
|
const footer = computed(() => infoConfig.value.footer || {
|
||||||
|
copyright: "© 江南大学 2025 [WIP] v0.12.138"
|
||||||
|
})
|
||||||
|
|
||||||
|
// 动作方法
|
||||||
|
function setInfoConfig(newConfig) {
|
||||||
|
infoConfig.value = newConfig
|
||||||
|
isLoaded.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadInfoConfig(force = false) {
|
||||||
|
// 如果已经加载过且不强制刷新,则不重新加载
|
||||||
|
if (isLoaded.value && !force) {
|
||||||
|
return infoConfig.value
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
isLoading.value = true
|
||||||
|
const response = await infoApi.getInfoConfig()
|
||||||
|
|
||||||
|
if (response.success && response.data) {
|
||||||
|
setInfoConfig(response.data)
|
||||||
|
console.log('信息配置加载成功:', response.data)
|
||||||
|
return response.data
|
||||||
|
} else {
|
||||||
|
console.warn('信息配置加载失败,使用默认配置')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载信息配置时发生错误:', error)
|
||||||
|
return null
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function reloadInfoConfig() {
|
||||||
|
try {
|
||||||
|
isLoading.value = true
|
||||||
|
const response = await infoApi.reloadInfoConfig()
|
||||||
|
|
||||||
|
if (response.success && response.data) {
|
||||||
|
setInfoConfig(response.data)
|
||||||
|
console.log('信息配置重新加载成功:', response.data)
|
||||||
|
return response.data
|
||||||
|
} else {
|
||||||
|
console.warn('信息配置重新加载失败')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('重新加载信息配置时发生错误:', error)
|
||||||
|
return null
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
// 状态
|
||||||
|
infoConfig,
|
||||||
|
isLoading,
|
||||||
|
isLoaded,
|
||||||
|
|
||||||
|
// 计算属性
|
||||||
|
organization,
|
||||||
|
branding,
|
||||||
|
features,
|
||||||
|
footer,
|
||||||
|
|
||||||
|
// 方法
|
||||||
|
setInfoConfig,
|
||||||
|
loadInfoConfig,
|
||||||
|
reloadInfoConfig
|
||||||
|
}
|
||||||
|
})
|
||||||
@ -3,8 +3,8 @@
|
|||||||
<div class="hero-section">
|
<div class="hero-section">
|
||||||
<div class="glass-header">
|
<div class="glass-header">
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
<img src="/favicon.svg" alt="江南语析" class="logo-img" />
|
<img :src="infoStore.organization.logo" :alt="infoStore.organization.name" class="logo-img" />
|
||||||
<span style="font-size: 1.3rem; font-weight: bold;">江南语析</span>
|
<span style="font-size: 1.3rem; font-weight: bold;">{{ infoStore.organization.name }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="github-link">
|
<div class="github-link">
|
||||||
<a href="https://github.com/xerrors/Yuxi-Know" target="_blank">
|
<a href="https://github.com/xerrors/Yuxi-Know" target="_blank">
|
||||||
@ -17,13 +17,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="hero-content">
|
<div class="hero-content">
|
||||||
<h1 class="title">{{ title }}</h1>
|
<h1 class="title">{{ infoStore.branding.title }}</h1>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<p class="subtitle">大模型驱动的知识库管理工具</p>
|
<p class="subtitle">{{ infoStore.branding.subtitle }}</p>
|
||||||
<p class="features">
|
<p class="features">
|
||||||
<span>📚 灵活知识库</span>
|
<span v-for="feature in infoStore.features" :key="feature">{{ feature }}</span>
|
||||||
<span>🕸️ 知识图谱集成</span>
|
|
||||||
<span>🤖 多模型支持</span>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<button class="start-button" @click="goToChat">开始对话</button>
|
<button class="start-button" @click="goToChat">开始对话</button>
|
||||||
@ -36,14 +34,14 @@
|
|||||||
<div class="preview-overlay">
|
<div class="preview-overlay">
|
||||||
<div class="overlay-content">
|
<div class="overlay-content">
|
||||||
<h3>强大的问答能力</h3>
|
<h3>强大的问答能力</h3>
|
||||||
<p>结合知识库与知识图谱,提供更准确、更全面的回答</p>
|
<p>{{ infoStore.branding.description }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
<p>© 江南语析 2025 [WIP] v0.12.138</p>
|
<p>{{ infoStore.footer.copyright }}</p>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -52,11 +50,12 @@
|
|||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { useUserStore } from '@/stores/user'
|
import { useUserStore } from '@/stores/user'
|
||||||
|
import { useInfoStore } from '@/stores/info'
|
||||||
import { chatApi } from '@/apis/auth_api'
|
import { chatApi } from '@/apis/auth_api'
|
||||||
|
|
||||||
const title = ref('Yuxi-Know')
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
const infoStore = useInfoStore()
|
||||||
const githubStars = ref(0)
|
const githubStars = ref(0)
|
||||||
const isLoadingStars = ref(false)
|
const isLoadingStars = ref(false)
|
||||||
|
|
||||||
@ -113,7 +112,10 @@ const fetchGithubStars = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
|
// 加载信息配置
|
||||||
|
await infoStore.loadInfoConfig()
|
||||||
|
// 获取GitHub stars
|
||||||
fetchGithubStars()
|
fetchGithubStars()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user