mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-02-06 18:45:08 +08:00
Compare commits
5 Commits
cb731dce34
...
37ac7576f1
| Author | SHA1 | Date | |
|---|---|---|---|
| 37ac7576f1 | |||
| c832e0b858 | |||
| 5d015e48c1 | |||
| b58e882eaa | |||
| 1bc33009c7 |
@ -24,7 +24,7 @@ from flask import request, Response
|
|||||||
from flask_login import login_required, current_user
|
from flask_login import login_required, current_user
|
||||||
|
|
||||||
from agent.component import LLM
|
from agent.component import LLM
|
||||||
from api.db import FileType
|
from api.db import CanvasCategory, FileType
|
||||||
from api.db.services.canvas_service import CanvasTemplateService, UserCanvasService, API4ConversationService
|
from api.db.services.canvas_service import CanvasTemplateService, UserCanvasService, API4ConversationService
|
||||||
from api.db.services.document_service import DocumentService
|
from api.db.services.document_service import DocumentService
|
||||||
from api.db.services.file_service import FileService
|
from api.db.services.file_service import FileService
|
||||||
@ -45,14 +45,14 @@ from rag.utils.redis_conn import REDIS_CONN
|
|||||||
@manager.route('/templates', methods=['GET']) # noqa: F821
|
@manager.route('/templates', methods=['GET']) # noqa: F821
|
||||||
@login_required
|
@login_required
|
||||||
def templates():
|
def templates():
|
||||||
return get_json_result(data=[c.to_dict() for c in CanvasTemplateService.get_all()])
|
return get_json_result(data=[c.to_dict() for c in CanvasTemplateService.query(canvas_category=CanvasCategory.Agent)])
|
||||||
|
|
||||||
|
|
||||||
@manager.route('/list', methods=['GET']) # noqa: F821
|
@manager.route('/list', methods=['GET']) # noqa: F821
|
||||||
@login_required
|
@login_required
|
||||||
def canvas_list():
|
def canvas_list():
|
||||||
return get_json_result(data=sorted([c.to_dict() for c in \
|
return get_json_result(data=sorted([c.to_dict() for c in \
|
||||||
UserCanvasService.query(user_id=current_user.id)], key=lambda x: x["update_time"]*-1)
|
UserCanvasService.query(user_id=current_user.id, canvas_category=CanvasCategory.Agent)], key=lambda x: x["update_time"]*-1)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ def save():
|
|||||||
req["dsl"] = json.loads(req["dsl"])
|
req["dsl"] = json.loads(req["dsl"])
|
||||||
if "id" not in req:
|
if "id" not in req:
|
||||||
req["user_id"] = current_user.id
|
req["user_id"] = current_user.id
|
||||||
if UserCanvasService.query(user_id=current_user.id, title=req["title"].strip()):
|
if UserCanvasService.query(user_id=current_user.id, title=req["title"].strip(), canvas_category=CanvasCategory.Agent):
|
||||||
return get_data_error_result(message=f"{req['title'].strip()} already exists.")
|
return get_data_error_result(message=f"{req['title'].strip()} already exists.")
|
||||||
req["id"] = get_uuid()
|
req["id"] = get_uuid()
|
||||||
if not UserCanvasService.save(**req):
|
if not UserCanvasService.save(**req):
|
||||||
@ -91,7 +91,7 @@ def save():
|
|||||||
code=RetCode.OPERATING_ERROR)
|
code=RetCode.OPERATING_ERROR)
|
||||||
UserCanvasService.update_by_id(req["id"], req)
|
UserCanvasService.update_by_id(req["id"], req)
|
||||||
# save version
|
# save version
|
||||||
UserCanvasVersionService.insert( user_canvas_id=req["id"], dsl=req["dsl"], title="{0}_{1}".format(req["title"], time.strftime("%Y_%m_%d_%H_%M_%S")))
|
UserCanvasVersionService.insert(user_canvas_id=req["id"], dsl=req["dsl"], title="{0}_{1}".format(req["title"], time.strftime("%Y_%m_%d_%H_%M_%S")))
|
||||||
UserCanvasVersionService.delete_all_versions(req["id"])
|
UserCanvasVersionService.delete_all_versions(req["id"])
|
||||||
return get_json_result(data=req)
|
return get_json_result(data=req)
|
||||||
|
|
||||||
@ -395,7 +395,7 @@ def list_canvas():
|
|||||||
tenants = TenantService.get_joined_tenants_by_user_id(current_user.id)
|
tenants = TenantService.get_joined_tenants_by_user_id(current_user.id)
|
||||||
canvas, total = UserCanvasService.get_by_tenant_ids(
|
canvas, total = UserCanvasService.get_by_tenant_ids(
|
||||||
[m["tenant_id"] for m in tenants], current_user.id, page_number,
|
[m["tenant_id"] for m in tenants], current_user.id, page_number,
|
||||||
items_per_page, orderby, desc, keywords)
|
items_per_page, orderby, desc, keywords, canvas_category=CanvasCategory.Agent)
|
||||||
return get_json_result(data={"canvas": canvas, "total": total})
|
return get_json_result(data={"canvas": canvas, "total": total})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return server_error_response(e)
|
return server_error_response(e)
|
||||||
|
|||||||
@ -74,8 +74,10 @@ class TaskStatus(StrEnum):
|
|||||||
DONE = "3"
|
DONE = "3"
|
||||||
FAIL = "4"
|
FAIL = "4"
|
||||||
|
|
||||||
|
|
||||||
VALID_TASK_STATUS = {TaskStatus.UNSTART, TaskStatus.RUNNING, TaskStatus.CANCEL, TaskStatus.DONE, TaskStatus.FAIL}
|
VALID_TASK_STATUS = {TaskStatus.UNSTART, TaskStatus.RUNNING, TaskStatus.CANCEL, TaskStatus.DONE, TaskStatus.FAIL}
|
||||||
|
|
||||||
|
|
||||||
class ParserType(StrEnum):
|
class ParserType(StrEnum):
|
||||||
PRESENTATION = "presentation"
|
PRESENTATION = "presentation"
|
||||||
LAWS = "laws"
|
LAWS = "laws"
|
||||||
@ -105,10 +107,19 @@ class CanvasType(StrEnum):
|
|||||||
DocBot = "docbot"
|
DocBot = "docbot"
|
||||||
|
|
||||||
|
|
||||||
|
class CanvasCategory(StrEnum):
|
||||||
|
Agent = "agent_canvas"
|
||||||
|
DataFlow = "dataflow_canvas"
|
||||||
|
|
||||||
|
VALID_CAVAS_CATEGORIES = {CanvasCategory.Agent, CanvasCategory.DataFlow}
|
||||||
|
|
||||||
|
|
||||||
class MCPServerType(StrEnum):
|
class MCPServerType(StrEnum):
|
||||||
SSE = "sse"
|
SSE = "sse"
|
||||||
STREAMABLE_HTTP = "streamable-http"
|
STREAMABLE_HTTP = "streamable-http"
|
||||||
|
|
||||||
|
|
||||||
VALID_MCP_SERVER_TYPES = {MCPServerType.SSE, MCPServerType.STREAMABLE_HTTP}
|
VALID_MCP_SERVER_TYPES = {MCPServerType.SSE, MCPServerType.STREAMABLE_HTTP}
|
||||||
|
|
||||||
|
|
||||||
KNOWLEDGEBASE_FOLDER_NAME=".knowledgebase"
|
KNOWLEDGEBASE_FOLDER_NAME=".knowledgebase"
|
||||||
|
|||||||
@ -245,22 +245,21 @@ class JsonSerializedField(SerializedField):
|
|||||||
|
|
||||||
class RetryingPooledMySQLDatabase(PooledMySQLDatabase):
|
class RetryingPooledMySQLDatabase(PooledMySQLDatabase):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.max_retries = kwargs.pop('max_retries', 5)
|
self.max_retries = kwargs.pop("max_retries", 5)
|
||||||
self.retry_delay = kwargs.pop('retry_delay', 1)
|
self.retry_delay = kwargs.pop("retry_delay", 1)
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def execute_sql(self, sql, params=None, commit=True):
|
def execute_sql(self, sql, params=None, commit=True):
|
||||||
from peewee import OperationalError
|
from peewee import OperationalError
|
||||||
|
|
||||||
for attempt in range(self.max_retries + 1):
|
for attempt in range(self.max_retries + 1):
|
||||||
try:
|
try:
|
||||||
return super().execute_sql(sql, params, commit)
|
return super().execute_sql(sql, params, commit)
|
||||||
except OperationalError as e:
|
except OperationalError as e:
|
||||||
if e.args[0] in (2013, 2006) and attempt < self.max_retries:
|
if e.args[0] in (2013, 2006) and attempt < self.max_retries:
|
||||||
logging.warning(
|
logging.warning(f"Lost connection (attempt {attempt + 1}/{self.max_retries}): {e}")
|
||||||
f"Lost connection (attempt {attempt+1}/{self.max_retries}): {e}"
|
|
||||||
)
|
|
||||||
self._handle_connection_loss()
|
self._handle_connection_loss()
|
||||||
time.sleep(self.retry_delay * (2 ** attempt))
|
time.sleep(self.retry_delay * (2**attempt))
|
||||||
else:
|
else:
|
||||||
logging.error(f"DB execution failure: {e}")
|
logging.error(f"DB execution failure: {e}")
|
||||||
raise
|
raise
|
||||||
@ -272,16 +271,15 @@ class RetryingPooledMySQLDatabase(PooledMySQLDatabase):
|
|||||||
|
|
||||||
def begin(self):
|
def begin(self):
|
||||||
from peewee import OperationalError
|
from peewee import OperationalError
|
||||||
|
|
||||||
for attempt in range(self.max_retries + 1):
|
for attempt in range(self.max_retries + 1):
|
||||||
try:
|
try:
|
||||||
return super().begin()
|
return super().begin()
|
||||||
except OperationalError as e:
|
except OperationalError as e:
|
||||||
if e.args[0] in (2013, 2006) and attempt < self.max_retries:
|
if e.args[0] in (2013, 2006) and attempt < self.max_retries:
|
||||||
logging.warning(
|
logging.warning(f"Lost connection during transaction (attempt {attempt + 1}/{self.max_retries})")
|
||||||
f"Lost connection during transaction (attempt {attempt+1}/{self.max_retries})"
|
|
||||||
)
|
|
||||||
self._handle_connection_loss()
|
self._handle_connection_loss()
|
||||||
time.sleep(self.retry_delay * (2 ** attempt))
|
time.sleep(self.retry_delay * (2**attempt))
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@ -815,6 +813,7 @@ class UserCanvas(DataBaseModel):
|
|||||||
permission = CharField(max_length=16, null=False, help_text="me|team", default="me", index=True)
|
permission = CharField(max_length=16, null=False, help_text="me|team", default="me", index=True)
|
||||||
description = TextField(null=True, help_text="Canvas description")
|
description = TextField(null=True, help_text="Canvas description")
|
||||||
canvas_type = CharField(max_length=32, null=True, help_text="Canvas type", index=True)
|
canvas_type = CharField(max_length=32, null=True, help_text="Canvas type", index=True)
|
||||||
|
canvas_category = CharField(max_length=32, null=False, default="agent_canvas", help_text="Canvas category: agent_canvas|dataflow_canvas", index=True)
|
||||||
dsl = JSONField(null=True, default={})
|
dsl = JSONField(null=True, default={})
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -827,6 +826,7 @@ class CanvasTemplate(DataBaseModel):
|
|||||||
title = JSONField(null=True, default=dict, help_text="Canvas title")
|
title = JSONField(null=True, default=dict, help_text="Canvas title")
|
||||||
description = JSONField(null=True, default=dict, help_text="Canvas description")
|
description = JSONField(null=True, default=dict, help_text="Canvas description")
|
||||||
canvas_type = CharField(max_length=32, null=True, help_text="Canvas type", index=True)
|
canvas_type = CharField(max_length=32, null=True, help_text="Canvas type", index=True)
|
||||||
|
canvas_category = CharField(max_length=32, null=False, default="agent_canvas", help_text="Canvas category: agent_canvas|dataflow_canvas", index=True)
|
||||||
dsl = JSONField(null=True, default={})
|
dsl = JSONField(null=True, default={})
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -1029,4 +1029,12 @@ def migrate_db():
|
|||||||
migrate(migrator.alter_column_type("canvas_template", "description", JSONField(null=True, default=dict, help_text="Canvas description")))
|
migrate(migrator.alter_column_type("canvas_template", "description", JSONField(null=True, default=dict, help_text="Canvas description")))
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
try:
|
||||||
|
migrate(migrator.add_column("user_canvas", "canvas_category", CharField(max_length=32, null=False, default="agent_canvas", help_text="agent_canvas|dataflow_canvas", index=True)))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
migrate(migrator.add_column("canvas_template", "canvas_category", CharField(max_length=32, null=False, default="agent_canvas", help_text="agent_canvas|dataflow_canvas", index=True)))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
logging.disable(logging.NOTSET)
|
logging.disable(logging.NOTSET)
|
||||||
|
|||||||
@ -18,7 +18,7 @@ import logging
|
|||||||
import time
|
import time
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from agent.canvas import Canvas
|
from agent.canvas import Canvas
|
||||||
from api.db import TenantPermission
|
from api.db import CanvasCategory, TenantPermission
|
||||||
from api.db.db_models import DB, CanvasTemplate, User, UserCanvas, API4Conversation
|
from api.db.db_models import DB, CanvasTemplate, User, UserCanvas, API4Conversation
|
||||||
from api.db.services.api_service import API4ConversationService
|
from api.db.services.api_service import API4ConversationService
|
||||||
from api.db.services.common_service import CommonService
|
from api.db.services.common_service import CommonService
|
||||||
@ -31,6 +31,12 @@ from peewee import fn
|
|||||||
class CanvasTemplateService(CommonService):
|
class CanvasTemplateService(CommonService):
|
||||||
model = CanvasTemplate
|
model = CanvasTemplate
|
||||||
|
|
||||||
|
class DataFlowTemplateService(CommonService):
|
||||||
|
"""
|
||||||
|
Alias of CanvasTemplateService
|
||||||
|
"""
|
||||||
|
model = CanvasTemplate
|
||||||
|
|
||||||
|
|
||||||
class UserCanvasService(CommonService):
|
class UserCanvasService(CommonService):
|
||||||
model = UserCanvas
|
model = UserCanvas
|
||||||
@ -38,13 +44,14 @@ class UserCanvasService(CommonService):
|
|||||||
@classmethod
|
@classmethod
|
||||||
@DB.connection_context()
|
@DB.connection_context()
|
||||||
def get_list(cls, tenant_id,
|
def get_list(cls, tenant_id,
|
||||||
page_number, items_per_page, orderby, desc, id, title):
|
page_number, items_per_page, orderby, desc, id, title, canvas_category=CanvasCategory.Agent):
|
||||||
agents = cls.model.select()
|
agents = cls.model.select()
|
||||||
if id:
|
if id:
|
||||||
agents = agents.where(cls.model.id == id)
|
agents = agents.where(cls.model.id == id)
|
||||||
if title:
|
if title:
|
||||||
agents = agents.where(cls.model.title == title)
|
agents = agents.where(cls.model.title == title)
|
||||||
agents = agents.where(cls.model.user_id == tenant_id)
|
agents = agents.where(cls.model.user_id == tenant_id)
|
||||||
|
agents = agents.where(cls.model.canvas_category == canvas_category)
|
||||||
if desc:
|
if desc:
|
||||||
agents = agents.order_by(cls.model.getter_by(orderby).desc())
|
agents = agents.order_by(cls.model.getter_by(orderby).desc())
|
||||||
else:
|
else:
|
||||||
@ -71,6 +78,7 @@ class UserCanvasService(CommonService):
|
|||||||
cls.model.create_time,
|
cls.model.create_time,
|
||||||
cls.model.create_date,
|
cls.model.create_date,
|
||||||
cls.model.update_date,
|
cls.model.update_date,
|
||||||
|
cls.model.canvas_category,
|
||||||
User.nickname,
|
User.nickname,
|
||||||
User.avatar.alias('tenant_avatar'),
|
User.avatar.alias('tenant_avatar'),
|
||||||
]
|
]
|
||||||
@ -87,7 +95,7 @@ class UserCanvasService(CommonService):
|
|||||||
@DB.connection_context()
|
@DB.connection_context()
|
||||||
def get_by_tenant_ids(cls, joined_tenant_ids, user_id,
|
def get_by_tenant_ids(cls, joined_tenant_ids, user_id,
|
||||||
page_number, items_per_page,
|
page_number, items_per_page,
|
||||||
orderby, desc, keywords,
|
orderby, desc, keywords, canvas_category=CanvasCategory.Agent,
|
||||||
):
|
):
|
||||||
fields = [
|
fields = [
|
||||||
cls.model.id,
|
cls.model.id,
|
||||||
@ -98,7 +106,8 @@ class UserCanvasService(CommonService):
|
|||||||
cls.model.permission,
|
cls.model.permission,
|
||||||
User.nickname,
|
User.nickname,
|
||||||
User.avatar.alias('tenant_avatar'),
|
User.avatar.alias('tenant_avatar'),
|
||||||
cls.model.update_time
|
cls.model.update_time,
|
||||||
|
cls.model.canvas_category,
|
||||||
]
|
]
|
||||||
if keywords:
|
if keywords:
|
||||||
agents = cls.model.select(*fields).join(User, on=(cls.model.user_id == User.id)).where(
|
agents = cls.model.select(*fields).join(User, on=(cls.model.user_id == User.id)).where(
|
||||||
@ -113,6 +122,7 @@ class UserCanvasService(CommonService):
|
|||||||
TenantPermission.TEAM.value)) | (
|
TenantPermission.TEAM.value)) | (
|
||||||
cls.model.user_id == user_id))
|
cls.model.user_id == user_id))
|
||||||
)
|
)
|
||||||
|
agents = agents.where(cls.model.canvas_category == canvas_category)
|
||||||
if desc:
|
if desc:
|
||||||
agents = agents.order_by(cls.model.getter_by(orderby).desc())
|
agents = agents.order_by(cls.model.getter_by(orderby).desc())
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -13,6 +13,32 @@ A component that enables users to integrate Python or JavaScript codes into thei
|
|||||||
|
|
||||||
A **Code** component is essential when you need to integrate complex code logic (Python or JavaScript) into your Agent for dynamic data processing.
|
A **Code** component is essential when you need to integrate complex code logic (Python or JavaScript) into your Agent for dynamic data processing.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
### 1. Ensure gVisor is properly installed
|
||||||
|
|
||||||
|
We use gVisor to isolate code execution from the host system. Please follow [the official installation guide](https://gvisor.dev/docs/user_guide/install/) to install gVisor, ensuring your operating system is compatible before proceeding.
|
||||||
|
|
||||||
|
### 2. Ensure Sandbox is properly installed
|
||||||
|
|
||||||
|
RAGFlow Sandbox is a secure, pluggable code execution backend. It serves as the code executor for the **Code** component. Please follow the [instructions here](https://github.com/infiniflow/ragflow/tree/main/sandbox) to install RAGFlow Sandbox.
|
||||||
|
|
||||||
|
:::tip NOTE
|
||||||
|
If your RAGFlow Sandbox is not working, please be sure to consult the [Troubleshooting](#troubleshooting) section in this document. We assure you that it addresses 99.99% of the issues!
|
||||||
|
:::
|
||||||
|
|
||||||
|
### 3. (Optional) Install necessary dependencies
|
||||||
|
|
||||||
|
If you need to import your own Python or JavaScript packages into Sandbox, please follow the commands provided in the [How to import my own Python or JavaScript packages into Sandbox?](#how-to-import-my-own-python-or-javascript-packages-into-sandbox) section to install the additional dependencies.
|
||||||
|
|
||||||
|
### 4. Enable Sandbox-specific settings in RAGFlow
|
||||||
|
|
||||||
|
Ensure all Sandbox-specific settings are enabled in **ragflow/docker/.env**.
|
||||||
|
|
||||||
|
### 5. Restart the service after making changes
|
||||||
|
|
||||||
|
Any changes to the configuration or environment *require* a full service restart to take effect.
|
||||||
|
|
||||||
## Configurations
|
## Configurations
|
||||||
|
|
||||||
### Input
|
### Input
|
||||||
@ -55,4 +81,112 @@ You define the output variable(s) of the **Code** component here.
|
|||||||
|
|
||||||
The defined output variable(s) will be auto-populated here.
|
The defined output variable(s) will be auto-populated here.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### `HTTPConnectionPool(host='sandbox-executor-manager', port=9385): Read timed out.`
|
||||||
|
|
||||||
|
**Root cause**
|
||||||
|
|
||||||
|
- You did not properly install gVisor and `runsc` was not recognized as a valid Docker runtime.
|
||||||
|
- You did not pull the required base images for the runners and no runner was started.
|
||||||
|
|
||||||
|
**Solution**
|
||||||
|
|
||||||
|
For the gVisor issue:
|
||||||
|
|
||||||
|
1. Install [gVisor](https://gvisor.dev/docs/user_guide/install/).
|
||||||
|
2. Restart Docker.
|
||||||
|
3. Run the following to double check:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm --runtime=runsc hello-world
|
||||||
|
```
|
||||||
|
|
||||||
|
For the base image issue, pull the required base images:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker pull infiniflow/sandbox-base-nodejs:latest
|
||||||
|
docker pull infiniflow/sandbox-base-python:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### `HTTPConnectionPool(host='none', port=9385): Max retries exceeded.`
|
||||||
|
|
||||||
|
**Root cause**
|
||||||
|
|
||||||
|
`sandbox-executor-manager` is not mapped in `/etc/hosts`.
|
||||||
|
|
||||||
|
**Solution**
|
||||||
|
|
||||||
|
Add a new entry to `/etc/hosts`:
|
||||||
|
|
||||||
|
`127.0.0.1 es01 infinity mysql minio redis sandbox-executor-manager`
|
||||||
|
|
||||||
|
### `Container pool is busy`
|
||||||
|
|
||||||
|
**Root cause**
|
||||||
|
|
||||||
|
All runners are currently in use, executing tasks.
|
||||||
|
|
||||||
|
**Solution**
|
||||||
|
|
||||||
|
Please try again shortly or increase the pool size in the configuration to improve availability and reduce waiting times.
|
||||||
|
|
||||||
|
|
||||||
|
## Frequently asked questions
|
||||||
|
|
||||||
|
### How to import my own Python or JavaScript packages into Sandbox?
|
||||||
|
|
||||||
|
To import your Python packages, update **sandbox_base_image/python/requirements.txt** to install the required dependencies. For example, to add the `openpyxl` package, proceed with the following command lines:
|
||||||
|
|
||||||
|
```bash {4,6}
|
||||||
|
(ragflow) ➜ ragflow/sandbox main ✓ pwd # make sure you are in the right directory
|
||||||
|
/home/infiniflow/workspace/ragflow/sandbox
|
||||||
|
|
||||||
|
(ragflow) ➜ ragflow/sandbox main ✓ echo "openpyxl" >> sandbox_base_image/python/requirements.txt # add the package to the requirements.txt file
|
||||||
|
|
||||||
|
(ragflow) ➜ ragflow/sandbox main ✗ cat sandbox_base_image/python/requirements.txt # make sure the package is added
|
||||||
|
numpy
|
||||||
|
pandas
|
||||||
|
requests
|
||||||
|
openpyxl # here it is
|
||||||
|
|
||||||
|
(ragflow) ➜ ragflow/sandbox main ✗ make # rebuild the docker image, this command will rebuild the iamge and start the service immediately. To build image only, using `make build` instead.
|
||||||
|
|
||||||
|
(ragflow) ➜ ragflow/sandbox main ✗ docker exec -it sandbox_python_0 /bin/bash # entering container to check if the package is installed
|
||||||
|
|
||||||
|
|
||||||
|
# in the container
|
||||||
|
nobody@ffd8a7dd19da:/workspace$ python # launch python shell
|
||||||
|
Python 3.11.13 (main, Aug 12 2025, 22:46:03) [GCC 12.2.0] on linux
|
||||||
|
Type "help", "copyright", "credits" or "license" for more information.
|
||||||
|
>>> import openpyxl # import the package to verify installation
|
||||||
|
>>>
|
||||||
|
# That's okay!
|
||||||
|
```
|
||||||
|
|
||||||
|
To import your JavaScript packages, navigate to `sandbox_base_image/nodejs` and use `npm` to install the required packages. For example, to add the `lodash` package, run the following commands:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
(ragflow) ➜ ragflow/sandbox main ✓ pwd
|
||||||
|
/home/infiniflow/workspace/ragflow/sandbox
|
||||||
|
|
||||||
|
(ragflow) ➜ ragflow/sandbox main ✓ cd sandbox_base_image/nodejs
|
||||||
|
|
||||||
|
(ragflow) ➜ ragflow/sandbox/sandbox_base_image/nodejs main ✓ npm install lodash
|
||||||
|
|
||||||
|
(ragflow) ➜ ragflow/sandbox/sandbox_base_image/nodejs main ✓ cd ../.. # go back to sandbox root directory
|
||||||
|
|
||||||
|
(ragflow) ➜ ragflow/sandbox main ✗ make # rebuild the docker image, this command will rebuild the iamge and start the service immediately. To build image only, using `make build` instead.
|
||||||
|
|
||||||
|
(ragflow) ➜ ragflow/sandbox main ✗ docker exec -it sandbox_nodejs_0 /bin/bash # entering container to check if the package is installed
|
||||||
|
|
||||||
|
# in the container
|
||||||
|
nobody@dd4bbcabef63:/workspace$ npm list lodash # verify via npm list
|
||||||
|
/workspace
|
||||||
|
`-- lodash@4.17.21 extraneous
|
||||||
|
|
||||||
|
nobody@dd4bbcabef63:/workspace$ ls node_modules | grep lodash # or verify via listing node_modules
|
||||||
|
lodash
|
||||||
|
|
||||||
|
# That's okay!
|
||||||
|
```
|
||||||
|
|||||||
@ -27,7 +27,7 @@ The corresponding configuration panel appears to the right of the canvas. Use th
|
|||||||
|
|
||||||
### 2. Input query variable(s)
|
### 2. Input query variable(s)
|
||||||
|
|
||||||
The **Retrieval** component relies on query variables to specify its queries.
|
The **Retrieval** component depends on query variables to specify its queries.
|
||||||
|
|
||||||
:::caution IMPORTANT
|
:::caution IMPORTANT
|
||||||
- If you use the **Retrieval** component as a standalone workflow module, input query variables in the **Input Variables** text box.
|
- If you use the **Retrieval** component as a standalone workflow module, input query variables in the **Input Variables** text box.
|
||||||
@ -42,7 +42,7 @@ You can specify one or multiple knowledge bases to retrieve data from. If select
|
|||||||
|
|
||||||
### 4. Expand **Advanced Settings** to configure the retrieval method
|
### 4. Expand **Advanced Settings** to configure the retrieval method
|
||||||
|
|
||||||
By default, a combination of weighted keyword similarity and weighted vector cosine similarity is used during retrieval. If a rerank model is selected, a combination of weighted keyword similarity and weighted reranking score will be used for retrieval.
|
By default, a combination of weighted keyword similarity and weighted vector cosine similarity is used for retrieval. If a rerank model is selected, a combination of weighted keyword similarity and weighted reranking score will be used instead.
|
||||||
|
|
||||||
As a starter, you can skip this step to stay with the default retrieval method.
|
As a starter, you can skip this step to stay with the default retrieval method.
|
||||||
|
|
||||||
@ -57,9 +57,9 @@ If your user query is different from the languages of the knowledge bases, you c
|
|||||||
|
|
||||||
### 6. Test retrieval results
|
### 6. Test retrieval results
|
||||||
|
|
||||||
Click the triangle button on the top of canvas to test the retrieval results.
|
Click the **Run** button on the top of canvas to test the retrieval results.
|
||||||
|
|
||||||
### 6. Choose the next component
|
### 7. Choose the next component
|
||||||
|
|
||||||
When necessary, click the **+** button on the **Retrieval** component to choose the next component in the worflow from the dropdown list.
|
When necessary, click the **+** button on the **Retrieval** component to choose the next component in the worflow from the dropdown list.
|
||||||
|
|
||||||
|
|||||||
@ -1534,6 +1534,7 @@ class LiteLLMBase(ABC):
|
|||||||
"model": self.model_name,
|
"model": self.model_name,
|
||||||
"messages": history,
|
"messages": history,
|
||||||
"api_key": self.api_key,
|
"api_key": self.api_key,
|
||||||
|
"num_retries": self.max_retries,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
}
|
}
|
||||||
if stream:
|
if stream:
|
||||||
|
|||||||
@ -24,3 +24,5 @@ export enum AgentGlobals {
|
|||||||
SysConversationTurns = 'sys.conversation_turns',
|
SysConversationTurns = 'sys.conversation_turns',
|
||||||
SysFiles = 'sys.files',
|
SysFiles = 'sys.files',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const AgentGlobalsSysQueryWithBrace = `{${AgentGlobals.SysQuery}}`;
|
||||||
|
|||||||
@ -225,6 +225,14 @@ function AgentCanvas({ drawerVisible, hideDrawer }: IProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const OnConnectEnd = (event: MouseEvent | TouchEvent) => {
|
const OnConnectEnd = (event: MouseEvent | TouchEvent) => {
|
||||||
|
const target = event.target as HTMLElement;
|
||||||
|
// Clicking Handle will also trigger OnConnectEnd.
|
||||||
|
// To solve the problem that the operator on the right side added by clicking Handle will overlap with the original operator, this event is blocked here.
|
||||||
|
// TODO: However, a better way is to add both operators in the same way as OnConnectEnd.
|
||||||
|
if (target?.classList.contains('react-flow__handle')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ('clientX' in event && 'clientY' in event) {
|
if ('clientX' in event && 'clientY' in event) {
|
||||||
const { clientX, clientY } = event;
|
const { clientX, clientY } = event;
|
||||||
setDropdownPosition({ x: clientX, y: clientY });
|
setDropdownPosition({ x: clientX, y: clientY });
|
||||||
|
|||||||
@ -55,31 +55,33 @@ function OperatorItemList({
|
|||||||
const onNodeCreated = useContext(OnNodeCreatedContext);
|
const onNodeCreated = useContext(OnNodeCreatedContext);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const handleClick = (operator: Operator) => {
|
const handleClick =
|
||||||
const contextData = handleContext || {
|
(operator: Operator): React.MouseEventHandler<HTMLElement> =>
|
||||||
nodeId: '',
|
(e) => {
|
||||||
id: '',
|
const contextData = handleContext || {
|
||||||
type: 'source' as const,
|
nodeId: '',
|
||||||
position: Position.Right,
|
id: '',
|
||||||
isFromConnectionDrag: true,
|
type: 'source' as const,
|
||||||
|
position: Position.Right,
|
||||||
|
isFromConnectionDrag: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockEvent = mousePosition
|
||||||
|
? {
|
||||||
|
clientX: mousePosition.x,
|
||||||
|
clientY: mousePosition.y,
|
||||||
|
}
|
||||||
|
: e;
|
||||||
|
|
||||||
|
const newNodeId = addCanvasNode(operator, contextData)(mockEvent);
|
||||||
|
|
||||||
|
if (onNodeCreated && newNodeId) {
|
||||||
|
onNodeCreated(newNodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
hideModal?.();
|
||||||
};
|
};
|
||||||
|
|
||||||
const mockEvent = mousePosition
|
|
||||||
? {
|
|
||||||
clientX: mousePosition.x,
|
|
||||||
clientY: mousePosition.y,
|
|
||||||
}
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
const newNodeId = addCanvasNode(operator, contextData)(mockEvent);
|
|
||||||
|
|
||||||
if (onNodeCreated && newNodeId) {
|
|
||||||
onNodeCreated(newNodeId);
|
|
||||||
}
|
|
||||||
|
|
||||||
hideModal?.();
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderOperatorItem = (operator: Operator) => {
|
const renderOperatorItem = (operator: Operator) => {
|
||||||
const commonContent = (
|
const commonContent = (
|
||||||
<div className="hover:bg-background-card py-1 px-3 cursor-pointer rounded-sm flex gap-2 items-center justify-start">
|
<div className="hover:bg-background-card py-1 px-3 cursor-pointer rounded-sm flex gap-2 items-center justify-start">
|
||||||
@ -92,12 +94,12 @@ function OperatorItemList({
|
|||||||
<Tooltip key={operator}>
|
<Tooltip key={operator}>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
{isCustomDropdown ? (
|
{isCustomDropdown ? (
|
||||||
<li onClick={() => handleClick(operator)}>{commonContent}</li>
|
<li onClick={handleClick(operator)}>{commonContent}</li>
|
||||||
) : (
|
) : (
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
key={operator}
|
key={operator}
|
||||||
className="hover:bg-background-card py-1 px-3 cursor-pointer rounded-sm flex gap-2 items-center justify-start"
|
className="hover:bg-background-card py-1 px-3 cursor-pointer rounded-sm flex gap-2 items-center justify-start"
|
||||||
onClick={() => handleClick(operator)}
|
onClick={handleClick(operator)}
|
||||||
onSelect={() => hideModal?.()}
|
onSelect={() => hideModal?.()}
|
||||||
>
|
>
|
||||||
<OperatorIcon name={operator} />
|
<OperatorIcon name={operator} />
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import {
|
|||||||
} from '@/components/similarity-slider';
|
} from '@/components/similarity-slider';
|
||||||
import {
|
import {
|
||||||
AgentGlobals,
|
AgentGlobals,
|
||||||
|
AgentGlobalsSysQueryWithBrace,
|
||||||
CodeTemplateStrMap,
|
CodeTemplateStrMap,
|
||||||
ProgrammingLanguage,
|
ProgrammingLanguage,
|
||||||
} from '@/constants/agent';
|
} from '@/constants/agent';
|
||||||
@ -247,7 +248,7 @@ const initialQueryBaseValues = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const initialRetrievalValues = {
|
export const initialRetrievalValues = {
|
||||||
query: AgentGlobals.SysQuery,
|
query: AgentGlobalsSysQueryWithBrace,
|
||||||
top_n: 8,
|
top_n: 8,
|
||||||
top_k: 1024,
|
top_k: 1024,
|
||||||
kb_ids: [],
|
kb_ids: [],
|
||||||
|
|||||||
Reference in New Issue
Block a user