refactor: 优化环境变量获取逻辑,确保默认值处理

- 在多个文件中更新环境变量的获取方式,使用 `or` 语法简化代码,确保在未设置环境变量时使用默认值。
- 移除 `.env.template` 中与 LightRAG 相关的环境变量配置,简化配置文件。
- 更新 `pyproject.toml` 中的项目描述,提供更清晰的项目定位。
- 在文档中增加对图片上传响应格式的详细说明,提升用户理解。
This commit is contained in:
Wenjie Zhang 2025-11-12 19:53:56 +08:00
parent 628b37c73c
commit d999613f41
18 changed files with 49 additions and 45 deletions

View File

@ -26,10 +26,6 @@ MYSQL_DATABASE=database_name
MYSQL_PORT=3306
MYSQL_CHARSET=utf8mb4
# region lightrag
LIGHTRAG_LLM_PROVIDER=
LIGHTRAG_LLM_NAME=
# endregion lightrag
# region neo4j

View File

@ -148,4 +148,20 @@ MYSQL_CHARSET=utf8mb4
智能体会自动识别多模态消息并将其传递给支持图片的模型。如果模型不支持图片,会自动忽略图片内容,只处理文本部分。系统会将图片转换为符合模型要求的格式(通常是 base64 编码的 JPEG 或 PNG确保与主流多模态模型兼容。
目前仅支持上传单个图片,图片直接以 base64 存储在数据库
目前仅支持上传单个图片,图片以 base64 编码形式存储在数据库。系统会自动处理图片的格式转换和压缩,并生成缩略图以优化性能。
### 图片上传响应格式
```json
{
"success": true,
"image_content": "<base64编码的原始图片数据>",
"thumbnail_content": "<base64编码的缩略图数据>",
"width": 1024,
"height": 768,
"format": "JPEG",
"mime_type": "image/jpeg"
}
```
系统会将图片信息与用户查询一同传递给支持多模态的模型,并自动适配模型要求的格式。

View File

@ -26,10 +26,6 @@ LightRAG 知识库可在知识库详情中可视化,但不支持在侧边栏
在 Neo4j 的检索中可以看到,实际上 LightRAG 的节点和边依然是和知识图谱本身构建在了同一个 Neo4j 数据库中,但是使用了特殊的 tag 做区分。这点在后面介绍知识图谱的时候也会额外说明。
系统默认使用 `siliconflow``Qwen/Qwen3-30B-A3B-Instruct-2507` 模型进行图谱构建。可通过环境变量自定义图谱构建模型:
<<< @/../.env.template#lightrag{bash}
## 文档管理

View File

@ -104,14 +104,14 @@ DEFAULT_CHAT_MODEL_PROVIDERS: dict[str, ChatModelProvider] = {
}
```
### 3. 配置环境变量
### 2. 配置环境变量
`.env` 文件中添加对应的环境变量:
```env
CUSTOM_API_KEY_ENV_NAME=your_api_key_here
```
### 4. 重新部署
### 3. 重新部署
```bash
docker compose restart api-dev

View File

@ -1,7 +1,7 @@
[project]
name = "yuxi-know"
version = "0.4.0.dev"
description = "Add your description here"
description = "基于大模型的智能知识库与知识图谱智能体开发平台,融合了 RAG 技术与知识图谱技术,基于 LangGraph v1 + Vue.js + FastAPI + LightRAG 架构构建"
readme = "README.md"
requires-python = ">=3.11"
dependencies = [

View File

@ -19,8 +19,8 @@ def rename_and_resolve_duplicates():
Connects to Milvus, renames collections from 'kb_kb_' to 'kb_',
and resolves duplicates by keeping the collection with more rows.
"""
milvus_uri = os.getenv("MILVUS_URI", "http://localhost:19530")
milvus_token = os.getenv("MILVUS_TOKEN", "")
milvus_uri = os.getenv("MILVUS_URI") or "http://localhost:19530"
milvus_token = os.getenv("MILVUS_TOKEN") or ""
connection_alias = "rename_script"
try:

View File

@ -22,7 +22,7 @@ def load_chat_model(fully_specified_name: str, **kwargs) -> BaseChatModel:
env_var = model_info.env
api_key = os.getenv(env_var, env_var)
api_key = os.getenv(env_var) or env_var
base_url = get_docker_safe_url(model_info.base_url)

View File

@ -30,9 +30,9 @@ def get_connection_manager() -> MySQLConnectionManager:
"user": os.getenv("MYSQL_USER"),
"password": os.getenv("MYSQL_PASSWORD"),
"database": os.getenv("MYSQL_DATABASE"),
"port": int(os.getenv("MYSQL_PORT", "3306")),
"port": int(os.getenv("MYSQL_PORT") or "3306"),
"charset": "utf8mb4",
"description": os.getenv("MYSQL_DATABASE_DESCRIPTION", "默认 MySQL 数据库"),
"description": os.getenv("MYSQL_DATABASE_DESCRIPTION") or "默认 MySQL 数据库",
}
# 验证配置完整性
required_keys = ["host", "user", "password", "database"]

View File

@ -120,7 +120,7 @@ class Config(BaseModel):
def _setup_paths(self):
"""设置配置文件路径"""
self.save_dir = os.getenv("SAVE_DIR", self.save_dir)
self.save_dir = os.getenv("SAVE_DIR") or self.save_dir
self._config_file = Path(self.save_dir) / "config" / "base.toml"
self._config_file.parent.mkdir(parents=True, exist_ok=True)
@ -169,7 +169,7 @@ class Config(BaseModel):
def _handle_environment(self):
"""处理环境变量和运行时状态"""
# 处理模型目录
self.model_dir = os.environ.get("MODEL_DIR", self.model_dir)
self.model_dir = os.environ.get("MODEL_DIR") or self.model_dir
if self.model_dir:
if os.path.exists(self.model_dir):
logger.debug(f"Model directory ({self.model_dir}) contains: {os.listdir(self.model_dir)}")

View File

@ -8,15 +8,13 @@ from lightrag.utils import EmbeddingFunc, setup_logger
from neo4j import GraphDatabase
from pymilvus import connections, utility
from src import config
from src.knowledge.base import KnowledgeBase
from src.knowledge.indexing import process_file_to_markdown, process_url_to_markdown
from src.knowledge.utils.kb_utils import get_embedding_config, prepare_item_metadata
from src.utils import hashstr, logger
from src.utils.datetime_utils import shanghai_now
LIGHTRAG_LLM_PROVIDER = os.getenv("LIGHTRAG_LLM_PROVIDER", "siliconflow")
LIGHTRAG_LLM_NAME = os.getenv("LIGHTRAG_LLM_NAME", "zai-org/GLM-4.5-Air")
class LightRagKB(KnowledgeBase):
"""基于 LightRAG 的知识库实现"""
@ -53,8 +51,8 @@ class LightRagKB(KnowledgeBase):
"""删除数据库同时清除Milvus和Neo4j中的数据"""
# Drop Milvus collection
try:
milvus_uri = os.getenv("MILVUS_URI", "http://localhost:19530")
milvus_token = os.getenv("MILVUS_TOKEN", "")
milvus_uri = os.getenv("MILVUS_URI") or "http://localhost:19530"
milvus_token = os.getenv("MILVUS_TOKEN") or ""
connection_alias = f"lightrag_{hashstr(db_id, 6)}"
connections.connect(alias=connection_alias, uri=milvus_uri, token=milvus_token)
@ -73,9 +71,9 @@ class LightRagKB(KnowledgeBase):
logger.error(f"Failed to drop Milvus collection {db_id}: {e}")
# Delete Neo4j data
neo4j_uri = os.getenv("NEO4J_URI", "bolt://localhost:7687")
neo4j_username = os.getenv("NEO4J_USERNAME", "neo4j")
neo4j_password = os.getenv("NEO4J_PASSWORD", "0123456789")
neo4j_uri = os.getenv("NEO4J_URI") or "bolt://localhost:7687"
neo4j_username = os.getenv("NEO4J_USERNAME") or "neo4j"
neo4j_password = os.getenv("NEO4J_PASSWORD") or "0123456789"
try:
driver = GraphDatabase.driver(neo4j_uri, auth=(neo4j_username, neo4j_password))
@ -118,7 +116,7 @@ class LightRagKB(KnowledgeBase):
if isinstance(metadata.get("language"), str) and metadata.get("language"):
addon_params.setdefault("language", metadata.get("language"))
# 默认语言从环境变量读取,默认 English
addon_params.setdefault("language", os.getenv("SUMMARY_LANGUAGE", "English"))
addon_params.setdefault("language", os.getenv("SUMMARY_LANGUAGE") or "English")
# 创建工作目录
working_dir = os.path.join(self.work_dir, db_id)
@ -181,10 +179,8 @@ class LightRagKB(KnowledgeBase):
model_spec = f"{llm_info['provider']}/{llm_info['model_name']}"
logger.info(f"Using user-selected LLM: {model_spec}")
else:
provider = LIGHTRAG_LLM_PROVIDER
model_name = LIGHTRAG_LLM_NAME
model_spec = f"{provider}/{model_name}"
logger.info(f"Using default LLM from environment: {provider}/{model_name}")
model_spec = config.default_model
logger.info(f"Using default LLM from environment: {model_spec}")
model = select_model(model_spec=model_spec)

View File

@ -40,9 +40,9 @@ class MilvusKB(KnowledgeBase):
# Milvus 配置
# self.milvus_host = kwargs.get('milvus_host', os.getenv('MILVUS_HOST', 'localhost'))
# self.milvus_port = kwargs.get('milvus_port', int(os.getenv('MILVUS_PORT', '19530')))
self.milvus_token = kwargs.get("milvus_token", os.getenv("MILVUS_TOKEN", ""))
self.milvus_uri = kwargs.get("milvus_uri", os.getenv("MILVUS_URI", "http://localhost:19530"))
self.milvus_db = kwargs.get("milvus_db", "yuxi_know")
self.milvus_token = kwargs.get("milvus_token", os.getenv("MILVUS_TOKEN") or "")
self.milvus_uri = kwargs.get("milvus_uri", os.getenv("MILVUS_URI") or "http://localhost:19530")
self.milvus_db = kwargs.get("milvus_db") or "yuxi_know"
# 连接名称
self.connection_alias = f"milvus_{hashstr(work_dir, 6)}"

View File

@ -214,13 +214,13 @@ def get_embedding_config(embed_info: dict) -> dict:
if hasattr(embed_info, "name"):
# EmbedModelInfo 对象
config_dict["model"] = embed_info.name
config_dict["api_key"] = os.getenv(embed_info.api_key, embed_info.api_key)
config_dict["api_key"] = os.getenv(embed_info.api_key) or embed_info.api_key
config_dict["base_url"] = embed_info.base_url
config_dict["dimension"] = embed_info.dimension
else:
# 字典形式
config_dict["model"] = embed_info["name"]
config_dict["api_key"] = os.getenv(embed_info["api_key"], embed_info["api_key"])
config_dict["api_key"] = os.getenv(embed_info["api_key"]) or embed_info["api_key"]
config_dict["base_url"] = embed_info["base_url"]
config_dict["dimension"] = embed_info.get("dimension", 1024)
else:

View File

@ -125,6 +125,6 @@ def get_reranker(model_id, **kwargs):
model_info = config.reranker_names[model_id]
base_url = model_info.base_url
api_key = os.getenv(model_info.api_key, model_info.api_key)
api_key = os.getenv(model_info.api_key) or model_info.api_key
assert api_key, f"{model_info.name} api_key is required"
return OnlineReranker(model_name=model_info.name, api_key=api_key, base_url=base_url, **kwargs)

View File

@ -18,7 +18,7 @@ class MinerUParser(BaseDocumentProcessor):
"""MinerU 文档解析器 - 使用 HTTP API 进行文档理解和解析"""
def __init__(self, server_url: str | None = None):
self.server_url = server_url or os.getenv("MINERU_API_URI", "http://localhost:30001")
self.server_url = server_url or os.getenv("MINERU_API_URI") or "http://localhost:30001"
self.parse_endpoint = f"{self.server_url}/file_parse"
def get_service_name(self) -> str:

View File

@ -20,7 +20,7 @@ class PaddleXDocumentParser(BaseDocumentProcessor):
"""PaddleX 文档解析器 - 使用 PP-StructureV3 进行版面解析"""
def __init__(self, server_url: str | None = None):
self.server_url = server_url or os.getenv("PADDLEX_URI", "http://localhost:8080")
self.server_url = server_url or os.getenv("PADDLEX_URI") or "http://localhost:8080"
self.base_url = self.server_url.rstrip("/")
self.endpoint = f"{self.base_url}/layout-parsing"

View File

@ -37,9 +37,9 @@ class MinIOClient:
def __init__(self):
"""初始化 MinIO 客户端"""
self.endpoint = os.getenv("MINIO_URI", "http://milvus-minio:9000")
self.access_key = os.getenv("MINIO_ACCESS_KEY", "minioadmin")
self.secret_key = os.getenv("MINIO_SECRET_KEY", "minioadmin")
self.endpoint = os.getenv("MINIO_URI") or "http://milvus-minio:9000"
self.access_key = os.getenv("MINIO_ACCESS_KEY") or "minioadmin"
self.secret_key = os.getenv("MINIO_SECRET_KEY") or "minioadmin"
self._client = None
# 设置公开访问端点

View File

@ -4,7 +4,7 @@ from loguru import logger as loguru_logger
from src.utils.datetime_utils import shanghai_now
SAVE_DIR = os.getenv("SAVE_DIR", "saves")
SAVE_DIR = os.getenv("SAVE_DIR") or "saves"
DATETIME = shanghai_now().strftime("%Y-%m-%d")
LOG_FILE = f"{SAVE_DIR}/logs/yuxi-{DATETIME}.log"

View File

@ -1,6 +1,6 @@
{
"name": "yuxi-know-web",
"version": "0.3.0.web",
"version": "0.4.0.web",
"private": true,
"scripts": {
"dev": "vite",