ForcePilot/src/knowledge/kb_utils.py

137 lines
4.1 KiB
Python

import os
import time
from pathlib import Path
from typing import Dict, List, Any
from src.utils import hashstr, get_docker_safe_url, logger
from src import config
def split_text_into_chunks(text: str, file_id: str, filename: str,
chunk_size: int = 1000, chunk_overlap: int = 200) -> List[Dict]:
"""
将文本分割成块
Args:
text: 要分割的文本
file_id: 文件ID
filename: 文件名
chunk_size: 块大小
chunk_overlap: 块重叠大小
Returns:
List[Dict]: 分割后的文本块列表
"""
chunks = []
# 简单的分块策略:按段落和长度分割
paragraphs = text.split('\n\n')
current_chunk = ""
chunk_index = 0
for paragraph in paragraphs:
paragraph = paragraph.strip()
if not paragraph:
continue
# 如果当前块加上新段落会超过限制,保存当前块
if len(current_chunk) + len(paragraph) > chunk_size and current_chunk:
chunks.append({
"id": f"{file_id}_chunk_{chunk_index}",
"content": current_chunk.strip(),
"file_id": file_id,
"filename": filename,
"chunk_index": chunk_index,
"source": filename,
"chunk_id": f"{file_id}_chunk_{chunk_index}"
})
# 开始新块,包含重叠内容
if len(current_chunk) > chunk_overlap:
current_chunk = current_chunk[-chunk_overlap:] + "\n\n" + paragraph
else:
current_chunk = paragraph
chunk_index += 1
else:
if current_chunk:
current_chunk += "\n\n" + paragraph
else:
current_chunk = paragraph
# 添加最后一块
if current_chunk.strip():
chunks.append({
"id": f"{file_id}_chunk_{chunk_index}",
"content": current_chunk.strip(),
"file_id": file_id,
"filename": filename,
"chunk_index": chunk_index,
"source": filename,
"chunk_id": f"{file_id}_chunk_{chunk_index}"
})
return chunks
def prepare_item_metadata(item: str, content_type: str, db_id: str) -> Dict:
"""
准备文件或URL的元数据
Args:
item: 文件路径或URL
content_type: 内容类型 ('file''url')
db_id: 数据库ID
Returns:
Dict: 包含元数据的字典
"""
if content_type == "file":
file_path = Path(item)
file_id = f"file_{hashstr(str(file_path) + str(time.time()), 6)}"
file_type = file_path.suffix.lower().replace(".", "")
filename = file_path.name
item_path = str(file_path)
else: # URL
file_id = f"url_{hashstr(item + str(time.time()), 6)}"
file_type = "url"
filename = f"webpage_{hashstr(item, 6)}.md"
item_path = item
return {
"database_id": db_id,
"filename": filename,
"path": item_path,
"file_type": file_type,
"status": "processing",
"created_at": time.time(),
"file_id": file_id
}
def get_embedding_config(embed_info: Dict) -> Dict:
"""
获取嵌入模型配置
Args:
embed_info: 嵌入信息字典
Returns:
Dict: 标准化的嵌入配置
"""
config_dict = {}
if embed_info:
config_dict['model'] = embed_info["name"]
config_dict['api_key'] = os.getenv(embed_info["api_key"], embed_info["api_key"])
config_dict['base_url'] = embed_info["base_url"]
config_dict['dimension'] = embed_info.get("dimension", 1024)
else:
from src.models import select_embedding_model
default_model = select_embedding_model(config.embed_model)
config_dict['model'] = default_model.model
config_dict['api_key'] = default_model.api_key
config_dict['base_url'] = default_model.base_url
config_dict['dimension'] = getattr(default_model, 'dimension', 1024)
logger.debug(f"Embedding config: {config_dict}")
return config_dict