Merge branch 'main' into fix_when_reindex_will_delete_the_files_which_not_exist
This commit is contained in:
commit
f19e64f4c8
20 changed files with 109 additions and 37 deletions
|
|
@ -125,8 +125,8 @@ async def upload():
|
|||
@validate_request("name")
|
||||
async def create():
|
||||
req = await request.json
|
||||
pf_id = await request.json.get("parent_id")
|
||||
input_file_type = await request.json.get("type")
|
||||
pf_id = req.get("parent_id")
|
||||
input_file_type = req.get("type")
|
||||
if not pf_id:
|
||||
root_folder = FileService.get_root_folder(current_user.id)
|
||||
pf_id = root_folder["id"]
|
||||
|
|
|
|||
|
|
@ -34,14 +34,17 @@ from common.file_utils import get_project_base_directory
|
|||
from common import settings
|
||||
from api.common.base64 import encode_to_base64
|
||||
|
||||
DEFAULT_SUPERUSER_NICKNAME = os.getenv("DEFAULT_SUPERUSER_NICKNAME", "admin")
|
||||
DEFAULT_SUPERUSER_EMAIL = os.getenv("DEFAULT_SUPERUSER_EMAIL", "admin@ragflow.io")
|
||||
DEFAULT_SUPERUSER_PASSWORD = os.getenv("DEFAULT_SUPERUSER_PASSWORD", "admin")
|
||||
|
||||
def init_superuser():
|
||||
def init_superuser(nickname=DEFAULT_SUPERUSER_NICKNAME, email=DEFAULT_SUPERUSER_EMAIL, password=DEFAULT_SUPERUSER_PASSWORD, role=UserTenantRole.OWNER):
|
||||
user_info = {
|
||||
"id": uuid.uuid1().hex,
|
||||
"password": encode_to_base64("admin"),
|
||||
"nickname": "admin",
|
||||
"password": encode_to_base64(password),
|
||||
"nickname": nickname,
|
||||
"is_superuser": True,
|
||||
"email": "admin@ragflow.io",
|
||||
"email": email,
|
||||
"creator": "system",
|
||||
"status": "1",
|
||||
}
|
||||
|
|
@ -58,7 +61,7 @@ def init_superuser():
|
|||
"tenant_id": user_info["id"],
|
||||
"user_id": user_info["id"],
|
||||
"invited_by": user_info["id"],
|
||||
"role": UserTenantRole.OWNER
|
||||
"role": role
|
||||
}
|
||||
|
||||
tenant_llm = get_init_tenant_llm(user_info["id"])
|
||||
|
|
@ -70,7 +73,7 @@ def init_superuser():
|
|||
UserTenantService.insert(**usr_tenant)
|
||||
TenantLLMService.insert_many(tenant_llm)
|
||||
logging.info(
|
||||
"Super user initialized. email: admin@ragflow.io, password: admin. Changing the password after login is strongly recommended.")
|
||||
f"Super user initialized. email: {email}, password: {password}. Changing the password after login is strongly recommended.")
|
||||
|
||||
chat_mdl = LLMBundle(tenant["id"], LLMType.CHAT, tenant["llm_id"])
|
||||
msg = chat_mdl.chat(system="", history=[
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ from api.db.services.document_service import DocumentService
|
|||
from common.file_utils import get_project_base_directory
|
||||
from common import settings
|
||||
from api.db.db_models import init_database_tables as init_web_db
|
||||
from api.db.init_data import init_web_data
|
||||
from api.db.init_data import init_web_data, init_superuser
|
||||
from common.versions import get_ragflow_version
|
||||
from common.config_utils import show_configs
|
||||
from common.mcp_tool_call_conn import shutdown_all_mcp_sessions
|
||||
|
|
@ -109,11 +109,16 @@ if __name__ == '__main__':
|
|||
parser.add_argument(
|
||||
"--debug", default=False, help="debug mode", action="store_true"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--init-superuser", default=False, help="init superuser", action="store_true"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
if args.version:
|
||||
print(get_ragflow_version())
|
||||
sys.exit(0)
|
||||
|
||||
if args.init_superuser:
|
||||
init_superuser()
|
||||
RuntimeConfig.DEBUG = args.debug
|
||||
if RuntimeConfig.DEBUG:
|
||||
logging.info("run on debug mode")
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ def _get_or_create_secret_key():
|
|||
import logging
|
||||
|
||||
new_key = secrets.token_hex(32)
|
||||
logging.warning(f"SECURITY WARNING: Using auto-generated SECRET_KEY. Generated key: {new_key}")
|
||||
logging.warning("SECURITY WARNING: Using auto-generated SECRET_KEY.")
|
||||
return new_key
|
||||
|
||||
class StorageFactory:
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ function usage() {
|
|||
echo " --disable-datasync Disables synchronization of datasource workers."
|
||||
echo " --enable-mcpserver Enables the MCP server."
|
||||
echo " --enable-adminserver Enables the Admin server."
|
||||
echo " --init-superuser Initializes the superuser."
|
||||
echo " --consumer-no-beg=<num> Start range for consumers (if using range-based)."
|
||||
echo " --consumer-no-end=<num> End range for consumers (if using range-based)."
|
||||
echo " --workers=<num> Number of task executors to run (if range is not used)."
|
||||
|
|
@ -24,6 +25,7 @@ function usage() {
|
|||
echo " $0 --disable-webserver --workers=2 --host-id=myhost123"
|
||||
echo " $0 --enable-mcpserver"
|
||||
echo " $0 --enable-adminserver"
|
||||
echo " $0 --init-superuser"
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
|
@ -32,6 +34,7 @@ ENABLE_TASKEXECUTOR=1 # Default to enable task executor
|
|||
ENABLE_DATASYNC=1
|
||||
ENABLE_MCP_SERVER=0
|
||||
ENABLE_ADMIN_SERVER=0 # Default close admin server
|
||||
INIT_SUPERUSER_ARGS="" # Default to not initialize superuser
|
||||
CONSUMER_NO_BEG=0
|
||||
CONSUMER_NO_END=0
|
||||
WORKERS=1
|
||||
|
|
@ -83,6 +86,10 @@ for arg in "$@"; do
|
|||
ENABLE_ADMIN_SERVER=1
|
||||
shift
|
||||
;;
|
||||
--init-superuser)
|
||||
INIT_SUPERUSER_ARGS="--init-superuser"
|
||||
shift
|
||||
;;
|
||||
--mcp-host=*)
|
||||
MCP_HOST="${arg#*=}"
|
||||
shift
|
||||
|
|
@ -240,7 +247,7 @@ if [[ "${ENABLE_WEBSERVER}" -eq 1 ]]; then
|
|||
|
||||
echo "Starting ragflow_server..."
|
||||
while true; do
|
||||
"$PY" api/ragflow_server.py &
|
||||
"$PY" api/ragflow_server.py ${INIT_SUPERUSER_ARGS} &
|
||||
wait;
|
||||
sleep 1;
|
||||
done &
|
||||
|
|
|
|||
|
|
@ -23,12 +23,12 @@ server {
|
|||
gzip_disable "MSIE [1-6]\.";
|
||||
|
||||
location ~ ^/api/v1/admin {
|
||||
proxy_pass http://ragflow:9381;
|
||||
proxy_pass http://localhost:9381;
|
||||
include proxy.conf;
|
||||
}
|
||||
|
||||
location ~ ^/(v1|api) {
|
||||
proxy_pass http://ragflow:9380;
|
||||
proxy_pass http://localhost:9380;
|
||||
include proxy.conf;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2122,9 +2122,9 @@ curl --request POST \
|
|||
- `"top_k"`: (*Body parameter*), `integer`
|
||||
The number of chunks engaged in vector cosine computation. Defaults to `1024`.
|
||||
- `"use_kg"`: (*Body parameter*), `boolean`
|
||||
The search includes text chunks related to the knowledge graph of the selected dataset to handle complex multi-hop queries. Defaults to `False`.
|
||||
Whether to search chunks related to the generated knowledge graph for multi-hop queries. Defaults to `False`. Before enabling this, ensure you have successfully constructed a knowledge graph for the specified datasets. See [here](https://ragflow.io/docs/dev/construct_knowledge_graph) for details.
|
||||
- `"toc_enhance"`: (*Body parameter*), `boolean`
|
||||
The search includes table of content enhancement in order to boost rank of relevant chunks. Files parsed with `TOC Enhance` enabled is prerequisite. Defaults to `False`.
|
||||
Whether to search chunks with extracted table of content. Defaults to `False`. Before enabling this, ensure you have enabled `TOC_Enhance` and successfully extracted table of contents for the specified datasets. See [here](https://ragflow.io/docs/dev/enable_table_of_contents) for details.
|
||||
- `"rerank_id"`: (*Body parameter*), `integer`
|
||||
The ID of the rerank model.
|
||||
- `"keyword"`: (*Body parameter*), `boolean`
|
||||
|
|
@ -2140,8 +2140,8 @@ curl --request POST \
|
|||
- `"metadata_condition"`: (*Body parameter*), `object`
|
||||
The metadata condition used for filtering chunks:
|
||||
- `"logic"`: (*Body parameter*), `string`
|
||||
- `"and"` Intersection of the result from each condition (default).
|
||||
- `"or"` union of the result from each condition.
|
||||
- `"and"`: Return only results that satisfy *every* condition (default).
|
||||
- `"or"`: Return results that satisfy *any* condition.
|
||||
- `"conditions"`: (*Body parameter*), `array`
|
||||
A list of metadata filter conditions.
|
||||
- `"name"`: `string` - The metadata field name to filter by, e.g., `"author"`, `"company"`, `"url"`. Ensure this parameter before use. See [Set metadata](../guides/dataset/set_metadata.md) for details.
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ export type SelectWithSearchFlagProps = {
|
|||
allowClear?: boolean;
|
||||
disabled?: boolean;
|
||||
placeholder?: string;
|
||||
emptyData?: string;
|
||||
};
|
||||
|
||||
function findLabelWithoutOptions(
|
||||
|
|
@ -78,6 +79,7 @@ export const SelectWithSearch = forwardRef<
|
|||
allowClear = false,
|
||||
disabled = false,
|
||||
placeholder = t('common.selectPlaceholder'),
|
||||
emptyData = t('common.noDataFound'),
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
|
|
@ -183,8 +185,8 @@ export const SelectWithSearch = forwardRef<
|
|||
className=" placeholder:text-text-disabled"
|
||||
/>
|
||||
)}
|
||||
<CommandList className="mt-2">
|
||||
<CommandEmpty>{t('common.noDataFound')}</CommandEmpty>
|
||||
<CommandList className="mt-2 outline-none">
|
||||
<CommandEmpty>{emptyData}</CommandEmpty>
|
||||
{options.map((group, idx) => {
|
||||
if (group.options) {
|
||||
return (
|
||||
|
|
@ -196,6 +198,9 @@ export const SelectWithSearch = forwardRef<
|
|||
value={option.value}
|
||||
disabled={option.disabled}
|
||||
onSelect={handleSelect}
|
||||
className={
|
||||
value === option.value ? 'bg-bg-card' : ''
|
||||
}
|
||||
>
|
||||
<span className="leading-none">{option.label}</span>
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import * as React from 'react';
|
|||
import { cn } from '@/lib/utils';
|
||||
|
||||
const labelVariants = cva(
|
||||
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-text-secondary',
|
||||
'text-sm font-normal leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-text-secondary',
|
||||
);
|
||||
|
||||
const Label = React.forwardRef<
|
||||
|
|
|
|||
|
|
@ -88,18 +88,18 @@ export const useShowDeleteConfirm = () => {
|
|||
({ title, content, onOk, onCancel }: IProps): Promise<number> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
Modal.show({
|
||||
title: title ?? t('common.deleteModalTitle'),
|
||||
// title: title ?? t('common.deleteModalTitle'),
|
||||
closable: false,
|
||||
visible: true,
|
||||
onVisibleChange: () => {
|
||||
Modal.hide();
|
||||
},
|
||||
footer: null,
|
||||
closable: true,
|
||||
maskClosable: false,
|
||||
okText: t('common.yes'),
|
||||
cancelText: t('common.no'),
|
||||
style: {
|
||||
width: '400px',
|
||||
width: '450px',
|
||||
},
|
||||
okButtonClassName:
|
||||
'bg-state-error text-white hover:bg-state-error hover:text-white',
|
||||
|
|
@ -116,7 +116,14 @@ export const useShowDeleteConfirm = () => {
|
|||
onCancel?.();
|
||||
Modal.hide();
|
||||
},
|
||||
children: content,
|
||||
children: (
|
||||
<div className="flex flex-col justify-start items-start mt-3">
|
||||
<div className="text-lg font-medium">
|
||||
{title ?? t('common.deleteModalTitle')}
|
||||
</div>
|
||||
<div className="text-base font-normal">{content}</div>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -696,6 +696,9 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s
|
|||
tocEnhanceTip: ` During the parsing of the document, table of contents information was generated (see the 'Enable Table of Contents Extraction' option in the General method). This allows the large model to return table of contents items relevant to the user's query, thereby using these items to retrieve related chunks and apply weighting to these chunks during the sorting process. This approach is derived from mimicking the behavioral logic of how humans search for knowledge in books.`,
|
||||
},
|
||||
setting: {
|
||||
modelEmptyTip:
|
||||
'No models available. Please add models from the panel on the right.',
|
||||
sourceEmptyTip: 'No data sources added yet. Select one below to connect.',
|
||||
seconds: 'seconds',
|
||||
minutes: 'minutes',
|
||||
edit: 'Edit',
|
||||
|
|
@ -716,7 +719,7 @@ Example: https://fsn1.your-objectstorage.com`,
|
|||
deleteSourceModalTitle: 'Delete data source',
|
||||
deleteSourceModalContent: `
|
||||
<p>Are you sure you want to delete this data source link?</p>`,
|
||||
deleteSourceModalConfirmText: 'Comfirm',
|
||||
deleteSourceModalConfirmText: 'Confirm',
|
||||
errorMsg: 'Error message',
|
||||
newDocs: 'New Docs',
|
||||
timeStarted: 'Time started',
|
||||
|
|
|
|||
|
|
@ -685,6 +685,8 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于
|
|||
tocEnhanceTip: `解析文档时生成了目录信息(见General方法的‘启用目录抽取’),让大模型返回和用户问题相关的目录项,从而利用目录项拿到相关chunk,对这些chunk在排序中进行加权。这种方法来源于模仿人类查询书本中知识的行为逻辑`,
|
||||
},
|
||||
setting: {
|
||||
modelEmptyTip: '暂无可用模型,请先在右侧面板添加模型。',
|
||||
sourceEmptyTip: '暂未添加任何数据源,请从下方选择一个进行连接。',
|
||||
seconds: '秒',
|
||||
minutes: '分',
|
||||
edit: '编辑',
|
||||
|
|
|
|||
|
|
@ -14,16 +14,28 @@ import { useTranslation } from 'react-i18next';
|
|||
export function ConversationDropdown({
|
||||
children,
|
||||
conversation,
|
||||
removeTemporaryConversation,
|
||||
}: PropsWithChildren & {
|
||||
conversation: IConversation;
|
||||
removeTemporaryConversation?: (conversationId: string) => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { removeConversation } = useRemoveConversation();
|
||||
|
||||
const handleDelete: MouseEventHandler<HTMLDivElement> = useCallback(() => {
|
||||
removeConversation([conversation.id]);
|
||||
}, [conversation.id, removeConversation]);
|
||||
if (conversation.is_new && removeTemporaryConversation) {
|
||||
removeTemporaryConversation(conversation.id);
|
||||
removeConversation([]);
|
||||
} else {
|
||||
removeConversation([conversation.id]);
|
||||
}
|
||||
}, [
|
||||
conversation.id,
|
||||
conversation.is_new,
|
||||
removeConversation,
|
||||
removeTemporaryConversation,
|
||||
]);
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ export function Sessions({
|
|||
const {
|
||||
list: conversationList,
|
||||
addTemporaryConversation,
|
||||
removeTemporaryConversation,
|
||||
handleInputChange,
|
||||
searchString,
|
||||
} = useSelectDerivedConversationList();
|
||||
|
|
@ -97,7 +98,10 @@ export function Sessions({
|
|||
>
|
||||
<CardContent className="px-3 py-2 flex justify-between items-center group gap-1">
|
||||
<div className="truncate">{x.name}</div>
|
||||
<ConversationDropdown conversation={x}>
|
||||
<ConversationDropdown
|
||||
conversation={x}
|
||||
removeTemporaryConversation={removeTemporaryConversation}
|
||||
>
|
||||
<MoreButton></MoreButton>
|
||||
</ConversationDropdown>
|
||||
</CardContent>
|
||||
|
|
|
|||
|
|
@ -80,6 +80,14 @@ export const useSelectDerivedConversationList = () => {
|
|||
});
|
||||
}, [conversationList, dialogId, prologue, t, setNewConversationRouteParams]);
|
||||
|
||||
const removeTemporaryConversation = useCallback((conversationId: string) => {
|
||||
setList((prevList) => {
|
||||
return prevList.filter(
|
||||
(conversation) => conversation.id !== conversationId,
|
||||
);
|
||||
});
|
||||
}, []);
|
||||
|
||||
// When you first enter the page, select the top conversation card
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -89,6 +97,7 @@ export const useSelectDerivedConversationList = () => {
|
|||
return {
|
||||
list,
|
||||
addTemporaryConversation,
|
||||
removeTemporaryConversation,
|
||||
loading,
|
||||
handleInputChange,
|
||||
searchString,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export const UserSettingHeader = ({
|
|||
}) => {
|
||||
return (
|
||||
<>
|
||||
<header className="flex flex-col gap-1 justify-between items-start p-0">
|
||||
<header className="flex flex-col gap-1.5 justify-between items-start p-0">
|
||||
<div className="text-2xl font-medium text-text-primary">{name}</div>
|
||||
{description && (
|
||||
<div className="text-sm text-text-secondary ">{description}</div>
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ const SourceDetailPage = () => {
|
|||
</CardTitle>
|
||||
</CardHeader>
|
||||
<Separator className="border-border-button bg-border-button w-[calc(100%+2rem)] -translate-x-4 -translate-y-4" />
|
||||
<CardContent className="p-2 flex flex-col gap-2 max-h-[calc(100vh-190px)] overflow-y-auto scrollbar-auto">
|
||||
<CardContent className="p-2 flex flex-col gap-10 max-h-[calc(100vh-190px)] overflow-y-auto scrollbar-auto">
|
||||
<div className="max-w-[1200px]">
|
||||
<DynamicForm.Root
|
||||
ref={formRef}
|
||||
|
|
@ -181,8 +181,10 @@ const SourceDetailPage = () => {
|
|||
defaultValues={defaultValues}
|
||||
/>
|
||||
</div>
|
||||
<section className="flex flex-col gap-2 mt-6">
|
||||
<div className="text-2xl text-text-primary">{t('setting.log')}</div>
|
||||
<section className="flex flex-col gap-2">
|
||||
<div className="text-2xl text-text-primary mb-2">
|
||||
{t('setting.log')}
|
||||
</div>
|
||||
<DataSourceLogsTable refresh_freq={detail?.refresh_freq || false} />
|
||||
</section>
|
||||
</CardContent>
|
||||
|
|
|
|||
|
|
@ -120,6 +120,11 @@ const DataSource = () => {
|
|||
<div className="relative">
|
||||
<div className=" flex flex-col gap-4 max-h-[calc(100vh-230px)] overflow-y-auto overflow-x-hidden scrollbar-auto">
|
||||
<div className="flex flex-col gap-3">
|
||||
{categorizedList?.length <= 0 && (
|
||||
<div className="text-text-secondary w-full flex justify-center items-center h-20">
|
||||
{t('setting.sourceEmptyTip')}
|
||||
</div>
|
||||
)}
|
||||
{categorizedList.map((item, index) => (
|
||||
<AddedSourceCard key={index} {...item} />
|
||||
))}
|
||||
|
|
@ -127,9 +132,9 @@ const DataSource = () => {
|
|||
<section className="bg-transparent border-none mt-8">
|
||||
<header className="flex flex-row items-center justify-between space-y-0 p-0 pb-4">
|
||||
{/* <Users className="mr-2 h-5 w-5 text-[#1677ff]" /> */}
|
||||
<CardTitle className="text-2xl font-semibold">
|
||||
<CardTitle className="text-2xl font-semibold ">
|
||||
{t('setting.availableSources')}
|
||||
<div className="text-sm text-text-secondary font-normal">
|
||||
<div className="text-sm text-text-secondary font-normal mt-1.5">
|
||||
{t('setting.availableSourcesDescription')}
|
||||
</div>
|
||||
</CardTitle>
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ const SystemSetting = ({ onOk, loading }: IProps) => {
|
|||
options={options}
|
||||
onChange={(value) => handleFieldChange(id, value)}
|
||||
placeholder={t('selectModelPlaceholder')}
|
||||
emptyData={t('modelEmptyTip')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,12 +1,19 @@
|
|||
import { useLogout } from '@/hooks/login-hooks';
|
||||
import { Routes } from '@/routes';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useNavigate } from 'umi';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useLocation, useNavigate } from 'umi';
|
||||
|
||||
export const useHandleMenuClick = () => {
|
||||
const navigate = useNavigate();
|
||||
const [active, setActive] = useState<Routes>();
|
||||
const { logout } = useLogout();
|
||||
const location = useLocation();
|
||||
useEffect(() => {
|
||||
const path = (location.pathname.split('/')?.[2] || '') as Routes;
|
||||
if (path) {
|
||||
setActive(('/' + path) as Routes);
|
||||
}
|
||||
}, [location]);
|
||||
|
||||
const handleMenuClick = useCallback(
|
||||
(key: Routes) => () => {
|
||||
|
|
@ -20,5 +27,5 @@ export const useHandleMenuClick = () => {
|
|||
[logout, navigate],
|
||||
);
|
||||
|
||||
return { handleMenuClick, active };
|
||||
return { handleMenuClick, active, setActive };
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue