Compare commits
10 Commits
84df2adf56
...
ae462bc9dc
Author | SHA1 | Date |
---|---|---|
|
ae462bc9dc | |
|
c4ad60528c | |
|
ca0948d382 | |
|
0a61254d65 | |
|
eaa4ad1aa2 | |
|
84a16792d7 | |
|
5825b76756 | |
|
b5463870ff | |
|
4262a2f829 | |
|
7c97ad1d6f |
|
@ -19,7 +19,7 @@ Cargo.lock
|
||||||
|
|
||||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||||
*.pdb
|
*.pdb
|
||||||
*.trie
|
.trie
|
||||||
|
|
||||||
.idea/
|
.idea/
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
|
@ -70,6 +70,34 @@ deploy:
|
||||||
|
|
||||||
**回答:** Ragflow原生解析器心跳触发的问题,不影响正常使用,可忽略,官方回答可参考:https://github.com/infiniflow/ragflow/issues/6700
|
**回答:** Ragflow原生解析器心跳触发的问题,不影响正常使用,可忽略,官方回答可参考:https://github.com/infiniflow/ragflow/issues/6700
|
||||||
|
|
||||||
|
## 问题 11:为什么添加ollama时,无法联通?
|
||||||
|
|
||||||
|
**回答:** ollama需要预先设置为对所有网络接口开放
|
||||||
|
|
||||||
|
修改配置文件:
|
||||||
|
```bash
|
||||||
|
vim /etc/systemd/system/ollama.service
|
||||||
|
```
|
||||||
|
|
||||||
|
[Service] 下添加:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
Environment="OLLAMA_HOST=0.0.0.0"
|
||||||
|
```
|
||||||
|
|
||||||
|
重新载入配置文件,重启ollama。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl restart ollama
|
||||||
|
```
|
||||||
|
|
||||||
|
## 问题 12:在后台知识库连接测试中显示 text-embedding-v3,无法连通?
|
||||||
|
|
||||||
|
**回答:** 出现此情况原因是使用 ragflow 创建的初始用户(创建时间最早的用户),默认自带了通义千问的模型配置,可登陆此用户,在模型管理中移除通义千问的模型配置,并添加新的嵌入模型配置,后台会自动读取最新添加的模型配置信息。
|
||||||
|
|
||||||
|
嵌入模型仅支持 bge-m3 模型,联网API仅支持硅基流动平台,可免费调用该嵌入模型:https://cloud.siliconflow.cn/i/bjDoFhPf
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -159,24 +159,6 @@ def delete_document(doc_id):
|
||||||
return error_response(str(e))
|
return error_response(str(e))
|
||||||
|
|
||||||
|
|
||||||
@knowledgebase_bp.route("/documents/<doc_id>/parse", methods=["POST"])
|
|
||||||
def parse_document(doc_id):
|
|
||||||
"""开始解析文档"""
|
|
||||||
# 处理 OPTIONS 预检请求
|
|
||||||
if request.method == "OPTIONS":
|
|
||||||
response = success_response({})
|
|
||||||
# 添加 CORS 相关头
|
|
||||||
response.headers.add("Access-Control-Allow-Methods", "POST")
|
|
||||||
response.headers.add("Access-Control-Allow-Headers", "Content-Type,Authorization")
|
|
||||||
return response
|
|
||||||
|
|
||||||
try:
|
|
||||||
result = KnowledgebaseService.async_parse_document(doc_id)
|
|
||||||
return success_response(data=result)
|
|
||||||
except Exception as e:
|
|
||||||
return error_response(str(e), code=500)
|
|
||||||
|
|
||||||
|
|
||||||
@knowledgebase_bp.route("/documents/<doc_id>/parse/progress", methods=["GET"])
|
@knowledgebase_bp.route("/documents/<doc_id>/parse/progress", methods=["GET"])
|
||||||
def get_parse_progress(doc_id):
|
def get_parse_progress(doc_id):
|
||||||
"""获取文档解析进度"""
|
"""获取文档解析进度"""
|
||||||
|
@ -242,8 +224,8 @@ def set_system_embedding_config_route():
|
||||||
|
|
||||||
|
|
||||||
@knowledgebase_bp.route("/documents/<doc_id>/parse", methods=["POST"])
|
@knowledgebase_bp.route("/documents/<doc_id>/parse", methods=["POST"])
|
||||||
def parse_document_async(doc_id): # 函数名改为 async 以区分
|
def parse_document(doc_id):
|
||||||
"""开始异步解析单个文档"""
|
"""开始解析文档"""
|
||||||
if request.method == "OPTIONS":
|
if request.method == "OPTIONS":
|
||||||
response = success_response({})
|
response = success_response({})
|
||||||
response.headers.add("Access-Control-Allow-Methods", "POST")
|
response.headers.add("Access-Control-Allow-Methods", "POST")
|
||||||
|
@ -251,7 +233,7 @@ def parse_document_async(doc_id): # 函数名改为 async 以区分
|
||||||
return response
|
return response
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = KnowledgebaseService.parse_document(doc_id) # 调用同步版本
|
result = KnowledgebaseService.parse_document(doc_id)
|
||||||
if result.get("success"):
|
if result.get("success"):
|
||||||
return success_response(data={"message": f"文档 {doc_id} 同步解析完成。", "details": result})
|
return success_response(data={"message": f"文档 {doc_id} 同步解析完成。", "details": result})
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
from peewee import Model
|
from typing import Any, Dict, Type, TypeVar
|
||||||
from typing import Type, TypeVar, Dict, Any
|
|
||||||
|
from peewee import Model
|
||||||
|
|
||||||
|
T = TypeVar("T", bound=Model)
|
||||||
|
|
||||||
T = TypeVar('T', bound=Model)
|
|
||||||
|
|
||||||
class BaseService:
|
class BaseService:
|
||||||
model: Type[T]
|
model: Type[T]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_by_id(cls, id: str) -> T:
|
def get_by_id(cls, id: str) -> T:
|
||||||
return cls.model.get_by_id(id)
|
return cls.model.get_by_id(id)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def insert(cls, data: Dict[str, Any]) -> T:
|
def insert(cls, data: Dict[str, Any]) -> T:
|
||||||
return cls.model.create(**data)
|
return cls.model.create(**data)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def delete_by_id(cls, id: str) -> int:
|
def delete_by_id(cls, id: str) -> int:
|
||||||
return cls.model.delete().where(cls.model.id == id).execute()
|
return cls.model.delete().where(cls.model.id == id).execute()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def query(cls, **kwargs) -> list[T]:
|
def query(cls, **kwargs) -> list[T]:
|
||||||
return list(cls.model.select().where(*[
|
return list(cls.model.select().where(*[getattr(cls.model, k) == v for k, v in kwargs.items()]))
|
||||||
getattr(cls.model, k) == v for k, v in kwargs.items()
|
|
||||||
]))
|
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
from peewee import *
|
from peewee import *
|
||||||
|
|
||||||
from .base_service import BaseService
|
from .base_service import BaseService
|
||||||
from .models import File2Document
|
from .models import File2Document
|
||||||
|
|
||||||
|
|
||||||
class File2DocumentService(BaseService):
|
class File2DocumentService(BaseService):
|
||||||
model = File2Document
|
model = File2Document
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_mapping(cls, file_id: str, document_id: str) -> File2Document:
|
def create_mapping(cls, file_id: str, document_id: str) -> File2Document:
|
||||||
return cls.insert({
|
return cls.insert({"file_id": file_id, "document_id": document_id})
|
||||||
'file_id': file_id,
|
|
||||||
'document_id': document_id
|
|
||||||
})
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_by_document_id(cls, document_id: str) -> list[File2Document]:
|
def get_by_document_id(cls, document_id: str) -> list[File2Document]:
|
||||||
return cls.query(document_id=document_id)
|
return cls.query(document_id=document_id)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_by_file_id(cls, file_id: str) -> list[File2Document]:
|
def get_by_file_id(cls, file_id: str) -> list[File2Document]:
|
||||||
return cls.query(file_id=file_id)
|
return cls.query(file_id=file_id)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
|
|
@ -484,11 +484,8 @@ def perform_parse(doc_id, doc_info, file_info, embedding_config, kb_info):
|
||||||
|
|
||||||
# 4. 更新文本块的图像信息
|
# 4. 更新文本块的图像信息
|
||||||
if image_info_list and chunk_ids_list:
|
if image_info_list and chunk_ids_list:
|
||||||
conn = None
|
|
||||||
cursor = None
|
|
||||||
try:
|
try:
|
||||||
conn = get_db_connection()
|
|
||||||
cursor = conn.cursor()
|
|
||||||
|
|
||||||
# 为每个文本块找到最近的图片
|
# 为每个文本块找到最近的图片
|
||||||
for i, chunk_id in enumerate(chunk_ids_list):
|
for i, chunk_id in enumerate(chunk_ids_list):
|
||||||
|
@ -516,11 +513,7 @@ def perform_parse(doc_id, doc_info, file_info, embedding_config, kb_info):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[Parser-ERROR] 更新文本块图片关联失败: {e}")
|
logger.error(f"[Parser-ERROR] 更新文本块图片关联失败: {e}")
|
||||||
raise Exception(f"[Parser-ERROR] 更新文本块图片关联失败: {e}")
|
raise Exception(f"[Parser-ERROR] 更新文本块图片关联失败: {e}")
|
||||||
finally:
|
|
||||||
if cursor:
|
|
||||||
cursor.close()
|
|
||||||
if conn:
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
# 5. 更新最终状态
|
# 5. 更新最终状态
|
||||||
process_duration = time.time() - start_time
|
process_duration = time.time() - start_time
|
||||||
|
|
Binary file not shown.
|
@ -711,12 +711,19 @@ class KnowledgebaseService:
|
||||||
cursor = conn.cursor(dictionary=True)
|
cursor = conn.cursor(dictionary=True)
|
||||||
|
|
||||||
# 先检查文档是否存在
|
# 先检查文档是否存在
|
||||||
|
# check_query = """
|
||||||
|
# SELECT
|
||||||
|
# d.kb_id,
|
||||||
|
# kb.created_by AS tenant_id -- 获取 tenant_id (knowledgebase的创建者)
|
||||||
|
# FROM document d
|
||||||
|
# JOIN knowledgebase kb ON d.kb_id = kb.id -- JOIN knowledgebase 表
|
||||||
|
# WHERE d.id = %s
|
||||||
|
# """
|
||||||
check_query = """
|
check_query = """
|
||||||
SELECT
|
SELECT
|
||||||
d.kb_id,
|
d.kb_id,
|
||||||
kb.created_by AS tenant_id -- 获取 tenant_id (knowledgebase的创建者)
|
d.created_by AS tenant_id
|
||||||
FROM document d
|
FROM document d
|
||||||
JOIN knowledgebase kb ON d.kb_id = kb.id -- JOIN knowledgebase 表
|
|
||||||
WHERE d.id = %s
|
WHERE d.id = %s
|
||||||
"""
|
"""
|
||||||
cursor.execute(check_query, (doc_id,))
|
cursor.execute(check_query, (doc_id,))
|
||||||
|
@ -1041,7 +1048,7 @@ class KnowledgebaseService:
|
||||||
SELECT llm_name, api_key, api_base
|
SELECT llm_name, api_key, api_base
|
||||||
FROM tenant_llm
|
FROM tenant_llm
|
||||||
WHERE tenant_id = %s AND model_type = 'embedding'
|
WHERE tenant_id = %s AND model_type = 'embedding'
|
||||||
ORDER BY create_time DESC # 如果一个用户可能有多个embedding配置,取最早的
|
ORDER BY create_time DESC
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
"""
|
"""
|
||||||
cursor.execute(query_embedding_config, (earliest_user_id,))
|
cursor.execute(query_embedding_config, (earliest_user_id,))
|
||||||
|
|
|
@ -11,7 +11,7 @@ export function createTableDataApi(data: Tables.CreateOrUpdateTableRequestData)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 删 */
|
/** 删 */
|
||||||
export function deleteTableDataApi(id: number) {
|
export function deleteTableDataApi(id: string) {
|
||||||
return request({
|
return request({
|
||||||
url: `api/v1/users/${id}`,
|
url: `api/v1/users/${id}`,
|
||||||
method: "delete"
|
method: "delete"
|
||||||
|
@ -42,7 +42,7 @@ export function getTableDataApi(params: Tables.TableRequestData) {
|
||||||
* @param password 新密码
|
* @param password 新密码
|
||||||
* @returns BaseResponse
|
* @returns BaseResponse
|
||||||
*/
|
*/
|
||||||
export function resetPasswordApi(userId: number, password: string) {
|
export function resetPasswordApi(userId: string, password: string) {
|
||||||
return request({
|
return request({
|
||||||
url: `api/v1/users/${userId}/reset-password`,
|
url: `api/v1/users/${userId}/reset-password`,
|
||||||
method: "put",
|
method: "put",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export interface CreateOrUpdateTableRequestData {
|
export interface CreateOrUpdateTableRequestData {
|
||||||
id?: number
|
id?: string
|
||||||
username: string
|
username: string
|
||||||
email?: string
|
email?: string
|
||||||
password?: string
|
password?: string
|
||||||
|
@ -21,7 +21,7 @@ export interface TableRequestData {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TableData {
|
export interface TableData {
|
||||||
id: number
|
id: string
|
||||||
username: string
|
username: string
|
||||||
email: string
|
email: string
|
||||||
createTime: string
|
createTime: string
|
||||||
|
|
|
@ -39,7 +39,7 @@ const formRules: FormRules<CreateOrUpdateTableRequestData> = {
|
||||||
// #region 重置密码
|
// #region 重置密码
|
||||||
const resetPasswordDialogVisible = ref<boolean>(false)
|
const resetPasswordDialogVisible = ref<boolean>(false)
|
||||||
const resetPasswordFormRef = ref<FormInstance | null>(null)
|
const resetPasswordFormRef = ref<FormInstance | null>(null)
|
||||||
const currentUserId = ref<number | undefined>(undefined) // 用于存储当前要重置密码的用户ID
|
const currentUserId = ref<string | undefined>(undefined) // 用于存储当前要重置密码的用户ID
|
||||||
const resetPasswordFormData = reactive({
|
const resetPasswordFormData = reactive({
|
||||||
password: ""
|
password: ""
|
||||||
})
|
})
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue