mirror of
https://github.com/langgenius/dify.git
synced 2024-11-16 03:32:23 +08:00
chore(api): Introduce Ruff Formatter. (#7291)
This commit is contained in:
parent
8f16165f92
commit
3571292fbf
4
.github/workflows/style.yml
vendored
4
.github/workflows/style.yml
vendored
|
@ -45,6 +45,10 @@ jobs:
|
||||||
if: steps.changed-files.outputs.any_changed == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
run: poetry run -C api dotenv-linter ./api/.env.example ./web/.env.example
|
run: poetry run -C api dotenv-linter ./api/.env.example ./web/.env.example
|
||||||
|
|
||||||
|
- name: Ruff formatter check
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
run: poetry run -C api ruff format --check ./api
|
||||||
|
|
||||||
- name: Lint hints
|
- name: Lint hints
|
||||||
if: failure()
|
if: failure()
|
||||||
run: echo "Please run 'dev/reformat' to fix the fixable linting errors."
|
run: echo "Please run 'dev/reformat' to fix the fixable linting errors."
|
||||||
|
|
151
api/app.py
151
api/app.py
|
@ -1,6 +1,6 @@
|
||||||
import os
|
import os
|
||||||
|
|
||||||
if os.environ.get("DEBUG", "false").lower() != 'true':
|
if os.environ.get("DEBUG", "false").lower() != "true":
|
||||||
from gevent import monkey
|
from gevent import monkey
|
||||||
|
|
||||||
monkey.patch_all()
|
monkey.patch_all()
|
||||||
|
@ -57,7 +57,7 @@ warnings.simplefilter("ignore", ResourceWarning)
|
||||||
if os.name == "nt":
|
if os.name == "nt":
|
||||||
os.system('tzutil /s "UTC"')
|
os.system('tzutil /s "UTC"')
|
||||||
else:
|
else:
|
||||||
os.environ['TZ'] = 'UTC'
|
os.environ["TZ"] = "UTC"
|
||||||
time.tzset()
|
time.tzset()
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,13 +70,14 @@ class DifyApp(Flask):
|
||||||
# -------------
|
# -------------
|
||||||
|
|
||||||
|
|
||||||
config_type = os.getenv('EDITION', default='SELF_HOSTED') # ce edition first
|
config_type = os.getenv("EDITION", default="SELF_HOSTED") # ce edition first
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------
|
# ----------------------------
|
||||||
# Application Factory Function
|
# Application Factory Function
|
||||||
# ----------------------------
|
# ----------------------------
|
||||||
|
|
||||||
|
|
||||||
def create_flask_app_with_configs() -> Flask:
|
def create_flask_app_with_configs() -> Flask:
|
||||||
"""
|
"""
|
||||||
create a raw flask app
|
create a raw flask app
|
||||||
|
@ -92,7 +93,7 @@ def create_flask_app_with_configs() -> Flask:
|
||||||
elif isinstance(value, int | float | bool):
|
elif isinstance(value, int | float | bool):
|
||||||
os.environ[key] = str(value)
|
os.environ[key] = str(value)
|
||||||
elif value is None:
|
elif value is None:
|
||||||
os.environ[key] = ''
|
os.environ[key] = ""
|
||||||
|
|
||||||
return dify_app
|
return dify_app
|
||||||
|
|
||||||
|
@ -100,10 +101,10 @@ def create_flask_app_with_configs() -> Flask:
|
||||||
def create_app() -> Flask:
|
def create_app() -> Flask:
|
||||||
app = create_flask_app_with_configs()
|
app = create_flask_app_with_configs()
|
||||||
|
|
||||||
app.secret_key = app.config['SECRET_KEY']
|
app.secret_key = app.config["SECRET_KEY"]
|
||||||
|
|
||||||
log_handlers = None
|
log_handlers = None
|
||||||
log_file = app.config.get('LOG_FILE')
|
log_file = app.config.get("LOG_FILE")
|
||||||
if log_file:
|
if log_file:
|
||||||
log_dir = os.path.dirname(log_file)
|
log_dir = os.path.dirname(log_file)
|
||||||
os.makedirs(log_dir, exist_ok=True)
|
os.makedirs(log_dir, exist_ok=True)
|
||||||
|
@ -111,23 +112,24 @@ def create_app() -> Flask:
|
||||||
RotatingFileHandler(
|
RotatingFileHandler(
|
||||||
filename=log_file,
|
filename=log_file,
|
||||||
maxBytes=1024 * 1024 * 1024,
|
maxBytes=1024 * 1024 * 1024,
|
||||||
backupCount=5
|
backupCount=5,
|
||||||
),
|
),
|
||||||
logging.StreamHandler(sys.stdout)
|
logging.StreamHandler(sys.stdout),
|
||||||
]
|
]
|
||||||
|
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=app.config.get('LOG_LEVEL'),
|
level=app.config.get("LOG_LEVEL"),
|
||||||
format=app.config.get('LOG_FORMAT'),
|
format=app.config.get("LOG_FORMAT"),
|
||||||
datefmt=app.config.get('LOG_DATEFORMAT'),
|
datefmt=app.config.get("LOG_DATEFORMAT"),
|
||||||
handlers=log_handlers,
|
handlers=log_handlers,
|
||||||
force=True
|
force=True,
|
||||||
)
|
)
|
||||||
log_tz = app.config.get('LOG_TZ')
|
log_tz = app.config.get("LOG_TZ")
|
||||||
if log_tz:
|
if log_tz:
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
|
|
||||||
timezone = pytz.timezone(log_tz)
|
timezone = pytz.timezone(log_tz)
|
||||||
|
|
||||||
def time_converter(seconds):
|
def time_converter(seconds):
|
||||||
|
@ -162,24 +164,24 @@ def initialize_extensions(app):
|
||||||
@login_manager.request_loader
|
@login_manager.request_loader
|
||||||
def load_user_from_request(request_from_flask_login):
|
def load_user_from_request(request_from_flask_login):
|
||||||
"""Load user based on the request."""
|
"""Load user based on the request."""
|
||||||
if request.blueprint not in ['console', 'inner_api']:
|
if request.blueprint not in ["console", "inner_api"]:
|
||||||
return None
|
return None
|
||||||
# Check if the user_id contains a dot, indicating the old format
|
# Check if the user_id contains a dot, indicating the old format
|
||||||
auth_header = request.headers.get('Authorization', '')
|
auth_header = request.headers.get("Authorization", "")
|
||||||
if not auth_header:
|
if not auth_header:
|
||||||
auth_token = request.args.get('_token')
|
auth_token = request.args.get("_token")
|
||||||
if not auth_token:
|
if not auth_token:
|
||||||
raise Unauthorized('Invalid Authorization token.')
|
raise Unauthorized("Invalid Authorization token.")
|
||||||
else:
|
else:
|
||||||
if ' ' not in auth_header:
|
if " " not in auth_header:
|
||||||
raise Unauthorized('Invalid Authorization header format. Expected \'Bearer <api-key>\' format.')
|
raise Unauthorized("Invalid Authorization header format. Expected 'Bearer <api-key>' format.")
|
||||||
auth_scheme, auth_token = auth_header.split(None, 1)
|
auth_scheme, auth_token = auth_header.split(None, 1)
|
||||||
auth_scheme = auth_scheme.lower()
|
auth_scheme = auth_scheme.lower()
|
||||||
if auth_scheme != 'bearer':
|
if auth_scheme != "bearer":
|
||||||
raise Unauthorized('Invalid Authorization header format. Expected \'Bearer <api-key>\' format.')
|
raise Unauthorized("Invalid Authorization header format. Expected 'Bearer <api-key>' format.")
|
||||||
|
|
||||||
decoded = PassportService().verify(auth_token)
|
decoded = PassportService().verify(auth_token)
|
||||||
user_id = decoded.get('user_id')
|
user_id = decoded.get("user_id")
|
||||||
|
|
||||||
account = AccountService.load_logged_in_account(account_id=user_id, token=auth_token)
|
account = AccountService.load_logged_in_account(account_id=user_id, token=auth_token)
|
||||||
if account:
|
if account:
|
||||||
|
@ -190,10 +192,11 @@ def load_user_from_request(request_from_flask_login):
|
||||||
@login_manager.unauthorized_handler
|
@login_manager.unauthorized_handler
|
||||||
def unauthorized_handler():
|
def unauthorized_handler():
|
||||||
"""Handle unauthorized requests."""
|
"""Handle unauthorized requests."""
|
||||||
return Response(json.dumps({
|
return Response(
|
||||||
'code': 'unauthorized',
|
json.dumps({"code": "unauthorized", "message": "Unauthorized."}),
|
||||||
'message': "Unauthorized."
|
status=401,
|
||||||
}), status=401, content_type="application/json")
|
content_type="application/json",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# register blueprint routers
|
# register blueprint routers
|
||||||
|
@ -204,38 +207,36 @@ def register_blueprints(app):
|
||||||
from controllers.service_api import bp as service_api_bp
|
from controllers.service_api import bp as service_api_bp
|
||||||
from controllers.web import bp as web_bp
|
from controllers.web import bp as web_bp
|
||||||
|
|
||||||
CORS(service_api_bp,
|
CORS(
|
||||||
allow_headers=['Content-Type', 'Authorization', 'X-App-Code'],
|
service_api_bp,
|
||||||
methods=['GET', 'PUT', 'POST', 'DELETE', 'OPTIONS', 'PATCH']
|
allow_headers=["Content-Type", "Authorization", "X-App-Code"],
|
||||||
|
methods=["GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH"],
|
||||||
)
|
)
|
||||||
app.register_blueprint(service_api_bp)
|
app.register_blueprint(service_api_bp)
|
||||||
|
|
||||||
CORS(web_bp,
|
CORS(
|
||||||
resources={
|
web_bp,
|
||||||
r"/*": {"origins": app.config['WEB_API_CORS_ALLOW_ORIGINS']}},
|
resources={r"/*": {"origins": app.config["WEB_API_CORS_ALLOW_ORIGINS"]}},
|
||||||
supports_credentials=True,
|
supports_credentials=True,
|
||||||
allow_headers=['Content-Type', 'Authorization', 'X-App-Code'],
|
allow_headers=["Content-Type", "Authorization", "X-App-Code"],
|
||||||
methods=['GET', 'PUT', 'POST', 'DELETE', 'OPTIONS', 'PATCH'],
|
methods=["GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH"],
|
||||||
expose_headers=['X-Version', 'X-Env']
|
expose_headers=["X-Version", "X-Env"],
|
||||||
)
|
)
|
||||||
|
|
||||||
app.register_blueprint(web_bp)
|
app.register_blueprint(web_bp)
|
||||||
|
|
||||||
CORS(console_app_bp,
|
CORS(
|
||||||
resources={
|
console_app_bp,
|
||||||
r"/*": {"origins": app.config['CONSOLE_CORS_ALLOW_ORIGINS']}},
|
resources={r"/*": {"origins": app.config["CONSOLE_CORS_ALLOW_ORIGINS"]}},
|
||||||
supports_credentials=True,
|
supports_credentials=True,
|
||||||
allow_headers=['Content-Type', 'Authorization'],
|
allow_headers=["Content-Type", "Authorization"],
|
||||||
methods=['GET', 'PUT', 'POST', 'DELETE', 'OPTIONS', 'PATCH'],
|
methods=["GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH"],
|
||||||
expose_headers=['X-Version', 'X-Env']
|
expose_headers=["X-Version", "X-Env"],
|
||||||
)
|
)
|
||||||
|
|
||||||
app.register_blueprint(console_app_bp)
|
app.register_blueprint(console_app_bp)
|
||||||
|
|
||||||
CORS(files_bp,
|
CORS(files_bp, allow_headers=["Content-Type"], methods=["GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH"])
|
||||||
allow_headers=['Content-Type'],
|
|
||||||
methods=['GET', 'PUT', 'POST', 'DELETE', 'OPTIONS', 'PATCH']
|
|
||||||
)
|
|
||||||
app.register_blueprint(files_bp)
|
app.register_blueprint(files_bp)
|
||||||
|
|
||||||
app.register_blueprint(inner_api_bp)
|
app.register_blueprint(inner_api_bp)
|
||||||
|
@ -245,29 +246,29 @@ def register_blueprints(app):
|
||||||
app = create_app()
|
app = create_app()
|
||||||
celery = app.extensions["celery"]
|
celery = app.extensions["celery"]
|
||||||
|
|
||||||
if app.config.get('TESTING'):
|
if app.config.get("TESTING"):
|
||||||
print("App is running in TESTING mode")
|
print("App is running in TESTING mode")
|
||||||
|
|
||||||
|
|
||||||
@app.after_request
|
@app.after_request
|
||||||
def after_request(response):
|
def after_request(response):
|
||||||
"""Add Version headers to the response."""
|
"""Add Version headers to the response."""
|
||||||
response.set_cookie('remember_token', '', expires=0)
|
response.set_cookie("remember_token", "", expires=0)
|
||||||
response.headers.add('X-Version', app.config['CURRENT_VERSION'])
|
response.headers.add("X-Version", app.config["CURRENT_VERSION"])
|
||||||
response.headers.add('X-Env', app.config['DEPLOY_ENV'])
|
response.headers.add("X-Env", app.config["DEPLOY_ENV"])
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
@app.route('/health')
|
@app.route("/health")
|
||||||
def health():
|
def health():
|
||||||
return Response(json.dumps({
|
return Response(
|
||||||
'pid': os.getpid(),
|
json.dumps({"pid": os.getpid(), "status": "ok", "version": app.config["CURRENT_VERSION"]}),
|
||||||
'status': 'ok',
|
status=200,
|
||||||
'version': app.config['CURRENT_VERSION']
|
content_type="application/json",
|
||||||
}), status=200, content_type="application/json")
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/threads')
|
@app.route("/threads")
|
||||||
def threads():
|
def threads():
|
||||||
num_threads = threading.active_count()
|
num_threads = threading.active_count()
|
||||||
threads = threading.enumerate()
|
threads = threading.enumerate()
|
||||||
|
@ -278,32 +279,34 @@ def threads():
|
||||||
thread_id = thread.ident
|
thread_id = thread.ident
|
||||||
is_alive = thread.is_alive()
|
is_alive = thread.is_alive()
|
||||||
|
|
||||||
thread_list.append({
|
thread_list.append(
|
||||||
'name': thread_name,
|
{
|
||||||
'id': thread_id,
|
"name": thread_name,
|
||||||
'is_alive': is_alive
|
"id": thread_id,
|
||||||
})
|
"is_alive": is_alive,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'pid': os.getpid(),
|
"pid": os.getpid(),
|
||||||
'thread_num': num_threads,
|
"thread_num": num_threads,
|
||||||
'threads': thread_list
|
"threads": thread_list,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@app.route('/db-pool-stat')
|
@app.route("/db-pool-stat")
|
||||||
def pool_stat():
|
def pool_stat():
|
||||||
engine = db.engine
|
engine = db.engine
|
||||||
return {
|
return {
|
||||||
'pid': os.getpid(),
|
"pid": os.getpid(),
|
||||||
'pool_size': engine.pool.size(),
|
"pool_size": engine.pool.size(),
|
||||||
'checked_in_connections': engine.pool.checkedin(),
|
"checked_in_connections": engine.pool.checkedin(),
|
||||||
'checked_out_connections': engine.pool.checkedout(),
|
"checked_out_connections": engine.pool.checkedout(),
|
||||||
'overflow_connections': engine.pool.overflow(),
|
"overflow_connections": engine.pool.overflow(),
|
||||||
'connection_timeout': engine.pool.timeout(),
|
"connection_timeout": engine.pool.timeout(),
|
||||||
'recycle_time': db.engine.pool._recycle
|
"recycle_time": db.engine.pool._recycle,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
app.run(host='0.0.0.0', port=5001)
|
app.run(host="0.0.0.0", port=5001)
|
||||||
|
|
407
api/commands.py
407
api/commands.py
|
@ -27,32 +27,29 @@ from models.provider import Provider, ProviderModel
|
||||||
from services.account_service import RegisterService, TenantService
|
from services.account_service import RegisterService, TenantService
|
||||||
|
|
||||||
|
|
||||||
@click.command('reset-password', help='Reset the account password.')
|
@click.command("reset-password", help="Reset the account password.")
|
||||||
@click.option('--email', prompt=True, help='The email address of the account whose password you need to reset')
|
@click.option("--email", prompt=True, help="The email address of the account whose password you need to reset")
|
||||||
@click.option('--new-password', prompt=True, help='the new password.')
|
@click.option("--new-password", prompt=True, help="the new password.")
|
||||||
@click.option('--password-confirm', prompt=True, help='the new password confirm.')
|
@click.option("--password-confirm", prompt=True, help="the new password confirm.")
|
||||||
def reset_password(email, new_password, password_confirm):
|
def reset_password(email, new_password, password_confirm):
|
||||||
"""
|
"""
|
||||||
Reset password of owner account
|
Reset password of owner account
|
||||||
Only available in SELF_HOSTED mode
|
Only available in SELF_HOSTED mode
|
||||||
"""
|
"""
|
||||||
if str(new_password).strip() != str(password_confirm).strip():
|
if str(new_password).strip() != str(password_confirm).strip():
|
||||||
click.echo(click.style('sorry. The two passwords do not match.', fg='red'))
|
click.echo(click.style("sorry. The two passwords do not match.", fg="red"))
|
||||||
return
|
return
|
||||||
|
|
||||||
account = db.session.query(Account). \
|
account = db.session.query(Account).filter(Account.email == email).one_or_none()
|
||||||
filter(Account.email == email). \
|
|
||||||
one_or_none()
|
|
||||||
|
|
||||||
if not account:
|
if not account:
|
||||||
click.echo(click.style('sorry. the account: [{}] not exist .'.format(email), fg='red'))
|
click.echo(click.style("sorry. the account: [{}] not exist .".format(email), fg="red"))
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
valid_password(new_password)
|
valid_password(new_password)
|
||||||
except:
|
except:
|
||||||
click.echo(
|
click.echo(click.style("sorry. The passwords must match {} ".format(password_pattern), fg="red"))
|
||||||
click.style('sorry. The passwords must match {} '.format(password_pattern), fg='red'))
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# generate password salt
|
# generate password salt
|
||||||
|
@ -65,80 +62,87 @@ def reset_password(email, new_password, password_confirm):
|
||||||
account.password = base64_password_hashed
|
account.password = base64_password_hashed
|
||||||
account.password_salt = base64_salt
|
account.password_salt = base64_salt
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
click.echo(click.style('Congratulations! Password has been reset.', fg='green'))
|
click.echo(click.style("Congratulations! Password has been reset.", fg="green"))
|
||||||
|
|
||||||
|
|
||||||
@click.command('reset-email', help='Reset the account email.')
|
@click.command("reset-email", help="Reset the account email.")
|
||||||
@click.option('--email', prompt=True, help='The old email address of the account whose email you need to reset')
|
@click.option("--email", prompt=True, help="The old email address of the account whose email you need to reset")
|
||||||
@click.option('--new-email', prompt=True, help='the new email.')
|
@click.option("--new-email", prompt=True, help="the new email.")
|
||||||
@click.option('--email-confirm', prompt=True, help='the new email confirm.')
|
@click.option("--email-confirm", prompt=True, help="the new email confirm.")
|
||||||
def reset_email(email, new_email, email_confirm):
|
def reset_email(email, new_email, email_confirm):
|
||||||
"""
|
"""
|
||||||
Replace account email
|
Replace account email
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
if str(new_email).strip() != str(email_confirm).strip():
|
if str(new_email).strip() != str(email_confirm).strip():
|
||||||
click.echo(click.style('Sorry, new email and confirm email do not match.', fg='red'))
|
click.echo(click.style("Sorry, new email and confirm email do not match.", fg="red"))
|
||||||
return
|
return
|
||||||
|
|
||||||
account = db.session.query(Account). \
|
account = db.session.query(Account).filter(Account.email == email).one_or_none()
|
||||||
filter(Account.email == email). \
|
|
||||||
one_or_none()
|
|
||||||
|
|
||||||
if not account:
|
if not account:
|
||||||
click.echo(click.style('sorry. the account: [{}] not exist .'.format(email), fg='red'))
|
click.echo(click.style("sorry. the account: [{}] not exist .".format(email), fg="red"))
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
email_validate(new_email)
|
email_validate(new_email)
|
||||||
except:
|
except:
|
||||||
click.echo(
|
click.echo(click.style("sorry. {} is not a valid email. ".format(email), fg="red"))
|
||||||
click.style('sorry. {} is not a valid email. '.format(email), fg='red'))
|
|
||||||
return
|
return
|
||||||
|
|
||||||
account.email = new_email
|
account.email = new_email
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
click.echo(click.style('Congratulations!, email has been reset.', fg='green'))
|
click.echo(click.style("Congratulations!, email has been reset.", fg="green"))
|
||||||
|
|
||||||
|
|
||||||
@click.command('reset-encrypt-key-pair', help='Reset the asymmetric key pair of workspace for encrypt LLM credentials. '
|
@click.command(
|
||||||
'After the reset, all LLM credentials will become invalid, '
|
"reset-encrypt-key-pair",
|
||||||
'requiring re-entry.'
|
help="Reset the asymmetric key pair of workspace for encrypt LLM credentials. "
|
||||||
'Only support SELF_HOSTED mode.')
|
"After the reset, all LLM credentials will become invalid, "
|
||||||
@click.confirmation_option(prompt=click.style('Are you sure you want to reset encrypt key pair?'
|
"requiring re-entry."
|
||||||
' this operation cannot be rolled back!', fg='red'))
|
"Only support SELF_HOSTED mode.",
|
||||||
|
)
|
||||||
|
@click.confirmation_option(
|
||||||
|
prompt=click.style(
|
||||||
|
"Are you sure you want to reset encrypt key pair?" " this operation cannot be rolled back!", fg="red"
|
||||||
|
)
|
||||||
|
)
|
||||||
def reset_encrypt_key_pair():
|
def reset_encrypt_key_pair():
|
||||||
"""
|
"""
|
||||||
Reset the encrypted key pair of workspace for encrypt LLM credentials.
|
Reset the encrypted key pair of workspace for encrypt LLM credentials.
|
||||||
After the reset, all LLM credentials will become invalid, requiring re-entry.
|
After the reset, all LLM credentials will become invalid, requiring re-entry.
|
||||||
Only support SELF_HOSTED mode.
|
Only support SELF_HOSTED mode.
|
||||||
"""
|
"""
|
||||||
if dify_config.EDITION != 'SELF_HOSTED':
|
if dify_config.EDITION != "SELF_HOSTED":
|
||||||
click.echo(click.style('Sorry, only support SELF_HOSTED mode.', fg='red'))
|
click.echo(click.style("Sorry, only support SELF_HOSTED mode.", fg="red"))
|
||||||
return
|
return
|
||||||
|
|
||||||
tenants = db.session.query(Tenant).all()
|
tenants = db.session.query(Tenant).all()
|
||||||
for tenant in tenants:
|
for tenant in tenants:
|
||||||
if not tenant:
|
if not tenant:
|
||||||
click.echo(click.style('Sorry, no workspace found. Please enter /install to initialize.', fg='red'))
|
click.echo(click.style("Sorry, no workspace found. Please enter /install to initialize.", fg="red"))
|
||||||
return
|
return
|
||||||
|
|
||||||
tenant.encrypt_public_key = generate_key_pair(tenant.id)
|
tenant.encrypt_public_key = generate_key_pair(tenant.id)
|
||||||
|
|
||||||
db.session.query(Provider).filter(Provider.provider_type == 'custom', Provider.tenant_id == tenant.id).delete()
|
db.session.query(Provider).filter(Provider.provider_type == "custom", Provider.tenant_id == tenant.id).delete()
|
||||||
db.session.query(ProviderModel).filter(ProviderModel.tenant_id == tenant.id).delete()
|
db.session.query(ProviderModel).filter(ProviderModel.tenant_id == tenant.id).delete()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
click.echo(click.style('Congratulations! '
|
click.echo(
|
||||||
'the asymmetric key pair of workspace {} has been reset.'.format(tenant.id), fg='green'))
|
click.style(
|
||||||
|
"Congratulations! " "the asymmetric key pair of workspace {} has been reset.".format(tenant.id),
|
||||||
|
fg="green",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@click.command('vdb-migrate', help='migrate vector db.')
|
@click.command("vdb-migrate", help="migrate vector db.")
|
||||||
@click.option('--scope', default='all', prompt=False, help='The scope of vector database to migrate, Default is All.')
|
@click.option("--scope", default="all", prompt=False, help="The scope of vector database to migrate, Default is All.")
|
||||||
def vdb_migrate(scope: str):
|
def vdb_migrate(scope: str):
|
||||||
if scope in ['knowledge', 'all']:
|
if scope in ["knowledge", "all"]:
|
||||||
migrate_knowledge_vector_database()
|
migrate_knowledge_vector_database()
|
||||||
if scope in ['annotation', 'all']:
|
if scope in ["annotation", "all"]:
|
||||||
migrate_annotation_vector_database()
|
migrate_annotation_vector_database()
|
||||||
|
|
||||||
|
|
||||||
|
@ -146,7 +150,7 @@ def migrate_annotation_vector_database():
|
||||||
"""
|
"""
|
||||||
Migrate annotation datas to target vector database .
|
Migrate annotation datas to target vector database .
|
||||||
"""
|
"""
|
||||||
click.echo(click.style('Start migrate annotation data.', fg='green'))
|
click.echo(click.style("Start migrate annotation data.", fg="green"))
|
||||||
create_count = 0
|
create_count = 0
|
||||||
skipped_count = 0
|
skipped_count = 0
|
||||||
total_count = 0
|
total_count = 0
|
||||||
|
@ -154,98 +158,103 @@ def migrate_annotation_vector_database():
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
# get apps info
|
# get apps info
|
||||||
apps = db.session.query(App).filter(
|
apps = (
|
||||||
App.status == 'normal'
|
db.session.query(App)
|
||||||
).order_by(App.created_at.desc()).paginate(page=page, per_page=50)
|
.filter(App.status == "normal")
|
||||||
|
.order_by(App.created_at.desc())
|
||||||
|
.paginate(page=page, per_page=50)
|
||||||
|
)
|
||||||
except NotFound:
|
except NotFound:
|
||||||
break
|
break
|
||||||
|
|
||||||
page += 1
|
page += 1
|
||||||
for app in apps:
|
for app in apps:
|
||||||
total_count = total_count + 1
|
total_count = total_count + 1
|
||||||
click.echo(f'Processing the {total_count} app {app.id}. '
|
click.echo(
|
||||||
+ f'{create_count} created, {skipped_count} skipped.')
|
f"Processing the {total_count} app {app.id}. " + f"{create_count} created, {skipped_count} skipped."
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
click.echo('Create app annotation index: {}'.format(app.id))
|
click.echo("Create app annotation index: {}".format(app.id))
|
||||||
app_annotation_setting = db.session.query(AppAnnotationSetting).filter(
|
app_annotation_setting = (
|
||||||
AppAnnotationSetting.app_id == app.id
|
db.session.query(AppAnnotationSetting).filter(AppAnnotationSetting.app_id == app.id).first()
|
||||||
).first()
|
)
|
||||||
|
|
||||||
if not app_annotation_setting:
|
if not app_annotation_setting:
|
||||||
skipped_count = skipped_count + 1
|
skipped_count = skipped_count + 1
|
||||||
click.echo('App annotation setting is disabled: {}'.format(app.id))
|
click.echo("App annotation setting is disabled: {}".format(app.id))
|
||||||
continue
|
continue
|
||||||
# get dataset_collection_binding info
|
# get dataset_collection_binding info
|
||||||
dataset_collection_binding = db.session.query(DatasetCollectionBinding).filter(
|
dataset_collection_binding = (
|
||||||
DatasetCollectionBinding.id == app_annotation_setting.collection_binding_id
|
db.session.query(DatasetCollectionBinding)
|
||||||
).first()
|
.filter(DatasetCollectionBinding.id == app_annotation_setting.collection_binding_id)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
if not dataset_collection_binding:
|
if not dataset_collection_binding:
|
||||||
click.echo('App annotation collection binding is not exist: {}'.format(app.id))
|
click.echo("App annotation collection binding is not exist: {}".format(app.id))
|
||||||
continue
|
continue
|
||||||
annotations = db.session.query(MessageAnnotation).filter(MessageAnnotation.app_id == app.id).all()
|
annotations = db.session.query(MessageAnnotation).filter(MessageAnnotation.app_id == app.id).all()
|
||||||
dataset = Dataset(
|
dataset = Dataset(
|
||||||
id=app.id,
|
id=app.id,
|
||||||
tenant_id=app.tenant_id,
|
tenant_id=app.tenant_id,
|
||||||
indexing_technique='high_quality',
|
indexing_technique="high_quality",
|
||||||
embedding_model_provider=dataset_collection_binding.provider_name,
|
embedding_model_provider=dataset_collection_binding.provider_name,
|
||||||
embedding_model=dataset_collection_binding.model_name,
|
embedding_model=dataset_collection_binding.model_name,
|
||||||
collection_binding_id=dataset_collection_binding.id
|
collection_binding_id=dataset_collection_binding.id,
|
||||||
)
|
)
|
||||||
documents = []
|
documents = []
|
||||||
if annotations:
|
if annotations:
|
||||||
for annotation in annotations:
|
for annotation in annotations:
|
||||||
document = Document(
|
document = Document(
|
||||||
page_content=annotation.question,
|
page_content=annotation.question,
|
||||||
metadata={
|
metadata={"annotation_id": annotation.id, "app_id": app.id, "doc_id": annotation.id},
|
||||||
"annotation_id": annotation.id,
|
|
||||||
"app_id": app.id,
|
|
||||||
"doc_id": annotation.id
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
documents.append(document)
|
documents.append(document)
|
||||||
|
|
||||||
vector = Vector(dataset, attributes=['doc_id', 'annotation_id', 'app_id'])
|
vector = Vector(dataset, attributes=["doc_id", "annotation_id", "app_id"])
|
||||||
click.echo(f"Start to migrate annotation, app_id: {app.id}.")
|
click.echo(f"Start to migrate annotation, app_id: {app.id}.")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
vector.delete()
|
vector.delete()
|
||||||
click.echo(
|
click.echo(click.style(f"Successfully delete vector index for app: {app.id}.", fg="green"))
|
||||||
click.style(f'Successfully delete vector index for app: {app.id}.',
|
|
||||||
fg='green'))
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
click.echo(
|
click.echo(click.style(f"Failed to delete vector index for app {app.id}.", fg="red"))
|
||||||
click.style(f'Failed to delete vector index for app {app.id}.',
|
|
||||||
fg='red'))
|
|
||||||
raise e
|
raise e
|
||||||
if documents:
|
if documents:
|
||||||
try:
|
try:
|
||||||
click.echo(click.style(
|
|
||||||
f'Start to created vector index with {len(documents)} annotations for app {app.id}.',
|
|
||||||
fg='green'))
|
|
||||||
vector.create(documents)
|
|
||||||
click.echo(
|
click.echo(
|
||||||
click.style(f'Successfully created vector index for app {app.id}.', fg='green'))
|
click.style(
|
||||||
|
f"Start to created vector index with {len(documents)} annotations for app {app.id}.",
|
||||||
|
fg="green",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
vector.create(documents)
|
||||||
|
click.echo(click.style(f"Successfully created vector index for app {app.id}.", fg="green"))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
click.echo(click.style(f'Failed to created vector index for app {app.id}.', fg='red'))
|
click.echo(click.style(f"Failed to created vector index for app {app.id}.", fg="red"))
|
||||||
raise e
|
raise e
|
||||||
click.echo(f'Successfully migrated app annotation {app.id}.')
|
click.echo(f"Successfully migrated app annotation {app.id}.")
|
||||||
create_count += 1
|
create_count += 1
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
click.echo(
|
click.echo(
|
||||||
click.style('Create app annotation index error: {} {}'.format(e.__class__.__name__, str(e)),
|
click.style(
|
||||||
fg='red'))
|
"Create app annotation index error: {} {}".format(e.__class__.__name__, str(e)), fg="red"
|
||||||
|
)
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
click.echo(
|
click.echo(
|
||||||
click.style(f'Congratulations! Create {create_count} app annotation indexes, and skipped {skipped_count} apps.',
|
click.style(
|
||||||
fg='green'))
|
f"Congratulations! Create {create_count} app annotation indexes, and skipped {skipped_count} apps.",
|
||||||
|
fg="green",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def migrate_knowledge_vector_database():
|
def migrate_knowledge_vector_database():
|
||||||
"""
|
"""
|
||||||
Migrate vector database datas to target vector database .
|
Migrate vector database datas to target vector database .
|
||||||
"""
|
"""
|
||||||
click.echo(click.style('Start migrate vector db.', fg='green'))
|
click.echo(click.style("Start migrate vector db.", fg="green"))
|
||||||
create_count = 0
|
create_count = 0
|
||||||
skipped_count = 0
|
skipped_count = 0
|
||||||
total_count = 0
|
total_count = 0
|
||||||
|
@ -253,87 +262,77 @@ def migrate_knowledge_vector_database():
|
||||||
page = 1
|
page = 1
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
datasets = db.session.query(Dataset).filter(Dataset.indexing_technique == 'high_quality') \
|
datasets = (
|
||||||
.order_by(Dataset.created_at.desc()).paginate(page=page, per_page=50)
|
db.session.query(Dataset)
|
||||||
|
.filter(Dataset.indexing_technique == "high_quality")
|
||||||
|
.order_by(Dataset.created_at.desc())
|
||||||
|
.paginate(page=page, per_page=50)
|
||||||
|
)
|
||||||
except NotFound:
|
except NotFound:
|
||||||
break
|
break
|
||||||
|
|
||||||
page += 1
|
page += 1
|
||||||
for dataset in datasets:
|
for dataset in datasets:
|
||||||
total_count = total_count + 1
|
total_count = total_count + 1
|
||||||
click.echo(f'Processing the {total_count} dataset {dataset.id}. '
|
click.echo(
|
||||||
+ f'{create_count} created, {skipped_count} skipped.')
|
f"Processing the {total_count} dataset {dataset.id}. "
|
||||||
|
+ f"{create_count} created, {skipped_count} skipped."
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
click.echo('Create dataset vdb index: {}'.format(dataset.id))
|
click.echo("Create dataset vdb index: {}".format(dataset.id))
|
||||||
if dataset.index_struct_dict:
|
if dataset.index_struct_dict:
|
||||||
if dataset.index_struct_dict['type'] == vector_type:
|
if dataset.index_struct_dict["type"] == vector_type:
|
||||||
skipped_count = skipped_count + 1
|
skipped_count = skipped_count + 1
|
||||||
continue
|
continue
|
||||||
collection_name = ''
|
collection_name = ""
|
||||||
if vector_type == VectorType.WEAVIATE:
|
if vector_type == VectorType.WEAVIATE:
|
||||||
dataset_id = dataset.id
|
dataset_id = dataset.id
|
||||||
collection_name = Dataset.gen_collection_name_by_id(dataset_id)
|
collection_name = Dataset.gen_collection_name_by_id(dataset_id)
|
||||||
index_struct_dict = {
|
index_struct_dict = {"type": VectorType.WEAVIATE, "vector_store": {"class_prefix": collection_name}}
|
||||||
"type": VectorType.WEAVIATE,
|
|
||||||
"vector_store": {"class_prefix": collection_name}
|
|
||||||
}
|
|
||||||
dataset.index_struct = json.dumps(index_struct_dict)
|
dataset.index_struct = json.dumps(index_struct_dict)
|
||||||
elif vector_type == VectorType.QDRANT:
|
elif vector_type == VectorType.QDRANT:
|
||||||
if dataset.collection_binding_id:
|
if dataset.collection_binding_id:
|
||||||
dataset_collection_binding = db.session.query(DatasetCollectionBinding). \
|
dataset_collection_binding = (
|
||||||
filter(DatasetCollectionBinding.id == dataset.collection_binding_id). \
|
db.session.query(DatasetCollectionBinding)
|
||||||
one_or_none()
|
.filter(DatasetCollectionBinding.id == dataset.collection_binding_id)
|
||||||
|
.one_or_none()
|
||||||
|
)
|
||||||
if dataset_collection_binding:
|
if dataset_collection_binding:
|
||||||
collection_name = dataset_collection_binding.collection_name
|
collection_name = dataset_collection_binding.collection_name
|
||||||
else:
|
else:
|
||||||
raise ValueError('Dataset Collection Bindings is not exist!')
|
raise ValueError("Dataset Collection Bindings is not exist!")
|
||||||
else:
|
else:
|
||||||
dataset_id = dataset.id
|
dataset_id = dataset.id
|
||||||
collection_name = Dataset.gen_collection_name_by_id(dataset_id)
|
collection_name = Dataset.gen_collection_name_by_id(dataset_id)
|
||||||
index_struct_dict = {
|
index_struct_dict = {"type": VectorType.QDRANT, "vector_store": {"class_prefix": collection_name}}
|
||||||
"type": VectorType.QDRANT,
|
|
||||||
"vector_store": {"class_prefix": collection_name}
|
|
||||||
}
|
|
||||||
dataset.index_struct = json.dumps(index_struct_dict)
|
dataset.index_struct = json.dumps(index_struct_dict)
|
||||||
|
|
||||||
elif vector_type == VectorType.MILVUS:
|
elif vector_type == VectorType.MILVUS:
|
||||||
dataset_id = dataset.id
|
dataset_id = dataset.id
|
||||||
collection_name = Dataset.gen_collection_name_by_id(dataset_id)
|
collection_name = Dataset.gen_collection_name_by_id(dataset_id)
|
||||||
index_struct_dict = {
|
index_struct_dict = {"type": VectorType.MILVUS, "vector_store": {"class_prefix": collection_name}}
|
||||||
"type": VectorType.MILVUS,
|
|
||||||
"vector_store": {"class_prefix": collection_name}
|
|
||||||
}
|
|
||||||
dataset.index_struct = json.dumps(index_struct_dict)
|
dataset.index_struct = json.dumps(index_struct_dict)
|
||||||
elif vector_type == VectorType.RELYT:
|
elif vector_type == VectorType.RELYT:
|
||||||
dataset_id = dataset.id
|
dataset_id = dataset.id
|
||||||
collection_name = Dataset.gen_collection_name_by_id(dataset_id)
|
collection_name = Dataset.gen_collection_name_by_id(dataset_id)
|
||||||
index_struct_dict = {
|
index_struct_dict = {"type": "relyt", "vector_store": {"class_prefix": collection_name}}
|
||||||
"type": 'relyt',
|
|
||||||
"vector_store": {"class_prefix": collection_name}
|
|
||||||
}
|
|
||||||
dataset.index_struct = json.dumps(index_struct_dict)
|
dataset.index_struct = json.dumps(index_struct_dict)
|
||||||
elif vector_type == VectorType.TENCENT:
|
elif vector_type == VectorType.TENCENT:
|
||||||
dataset_id = dataset.id
|
dataset_id = dataset.id
|
||||||
collection_name = Dataset.gen_collection_name_by_id(dataset_id)
|
collection_name = Dataset.gen_collection_name_by_id(dataset_id)
|
||||||
index_struct_dict = {
|
index_struct_dict = {"type": VectorType.TENCENT, "vector_store": {"class_prefix": collection_name}}
|
||||||
"type": VectorType.TENCENT,
|
|
||||||
"vector_store": {"class_prefix": collection_name}
|
|
||||||
}
|
|
||||||
dataset.index_struct = json.dumps(index_struct_dict)
|
dataset.index_struct = json.dumps(index_struct_dict)
|
||||||
elif vector_type == VectorType.PGVECTOR:
|
elif vector_type == VectorType.PGVECTOR:
|
||||||
dataset_id = dataset.id
|
dataset_id = dataset.id
|
||||||
collection_name = Dataset.gen_collection_name_by_id(dataset_id)
|
collection_name = Dataset.gen_collection_name_by_id(dataset_id)
|
||||||
index_struct_dict = {
|
index_struct_dict = {"type": VectorType.PGVECTOR, "vector_store": {"class_prefix": collection_name}}
|
||||||
"type": VectorType.PGVECTOR,
|
|
||||||
"vector_store": {"class_prefix": collection_name}
|
|
||||||
}
|
|
||||||
dataset.index_struct = json.dumps(index_struct_dict)
|
dataset.index_struct = json.dumps(index_struct_dict)
|
||||||
elif vector_type == VectorType.OPENSEARCH:
|
elif vector_type == VectorType.OPENSEARCH:
|
||||||
dataset_id = dataset.id
|
dataset_id = dataset.id
|
||||||
collection_name = Dataset.gen_collection_name_by_id(dataset_id)
|
collection_name = Dataset.gen_collection_name_by_id(dataset_id)
|
||||||
index_struct_dict = {
|
index_struct_dict = {
|
||||||
"type": VectorType.OPENSEARCH,
|
"type": VectorType.OPENSEARCH,
|
||||||
"vector_store": {"class_prefix": collection_name}
|
"vector_store": {"class_prefix": collection_name},
|
||||||
}
|
}
|
||||||
dataset.index_struct = json.dumps(index_struct_dict)
|
dataset.index_struct = json.dumps(index_struct_dict)
|
||||||
elif vector_type == VectorType.ANALYTICDB:
|
elif vector_type == VectorType.ANALYTICDB:
|
||||||
|
@ -341,16 +340,13 @@ def migrate_knowledge_vector_database():
|
||||||
collection_name = Dataset.gen_collection_name_by_id(dataset_id)
|
collection_name = Dataset.gen_collection_name_by_id(dataset_id)
|
||||||
index_struct_dict = {
|
index_struct_dict = {
|
||||||
"type": VectorType.ANALYTICDB,
|
"type": VectorType.ANALYTICDB,
|
||||||
"vector_store": {"class_prefix": collection_name}
|
"vector_store": {"class_prefix": collection_name},
|
||||||
}
|
}
|
||||||
dataset.index_struct = json.dumps(index_struct_dict)
|
dataset.index_struct = json.dumps(index_struct_dict)
|
||||||
elif vector_type == VectorType.ELASTICSEARCH:
|
elif vector_type == VectorType.ELASTICSEARCH:
|
||||||
dataset_id = dataset.id
|
dataset_id = dataset.id
|
||||||
index_name = Dataset.gen_collection_name_by_id(dataset_id)
|
index_name = Dataset.gen_collection_name_by_id(dataset_id)
|
||||||
index_struct_dict = {
|
index_struct_dict = {"type": "elasticsearch", "vector_store": {"class_prefix": index_name}}
|
||||||
"type": 'elasticsearch',
|
|
||||||
"vector_store": {"class_prefix": index_name}
|
|
||||||
}
|
|
||||||
dataset.index_struct = json.dumps(index_struct_dict)
|
dataset.index_struct = json.dumps(index_struct_dict)
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Vector store {vector_type} is not supported.")
|
raise ValueError(f"Vector store {vector_type} is not supported.")
|
||||||
|
@ -361,29 +357,41 @@ def migrate_knowledge_vector_database():
|
||||||
try:
|
try:
|
||||||
vector.delete()
|
vector.delete()
|
||||||
click.echo(
|
click.echo(
|
||||||
click.style(f'Successfully delete vector index {collection_name} for dataset {dataset.id}.',
|
click.style(
|
||||||
fg='green'))
|
f"Successfully delete vector index {collection_name} for dataset {dataset.id}.", fg="green"
|
||||||
|
)
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
click.echo(
|
click.echo(
|
||||||
click.style(f'Failed to delete vector index {collection_name} for dataset {dataset.id}.',
|
click.style(
|
||||||
fg='red'))
|
f"Failed to delete vector index {collection_name} for dataset {dataset.id}.", fg="red"
|
||||||
|
)
|
||||||
|
)
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
dataset_documents = db.session.query(DatasetDocument).filter(
|
dataset_documents = (
|
||||||
|
db.session.query(DatasetDocument)
|
||||||
|
.filter(
|
||||||
DatasetDocument.dataset_id == dataset.id,
|
DatasetDocument.dataset_id == dataset.id,
|
||||||
DatasetDocument.indexing_status == 'completed',
|
DatasetDocument.indexing_status == "completed",
|
||||||
DatasetDocument.enabled == True,
|
DatasetDocument.enabled == True,
|
||||||
DatasetDocument.archived == False,
|
DatasetDocument.archived == False,
|
||||||
).all()
|
)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
|
||||||
documents = []
|
documents = []
|
||||||
segments_count = 0
|
segments_count = 0
|
||||||
for dataset_document in dataset_documents:
|
for dataset_document in dataset_documents:
|
||||||
segments = db.session.query(DocumentSegment).filter(
|
segments = (
|
||||||
|
db.session.query(DocumentSegment)
|
||||||
|
.filter(
|
||||||
DocumentSegment.document_id == dataset_document.id,
|
DocumentSegment.document_id == dataset_document.id,
|
||||||
DocumentSegment.status == 'completed',
|
DocumentSegment.status == "completed",
|
||||||
DocumentSegment.enabled == True
|
DocumentSegment.enabled == True,
|
||||||
).all()
|
)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
|
||||||
for segment in segments:
|
for segment in segments:
|
||||||
document = Document(
|
document = Document(
|
||||||
|
@ -393,7 +401,7 @@ def migrate_knowledge_vector_database():
|
||||||
"doc_hash": segment.index_node_hash,
|
"doc_hash": segment.index_node_hash,
|
||||||
"document_id": segment.document_id,
|
"document_id": segment.document_id,
|
||||||
"dataset_id": segment.dataset_id,
|
"dataset_id": segment.dataset_id,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
documents.append(document)
|
documents.append(document)
|
||||||
|
@ -401,37 +409,43 @@ def migrate_knowledge_vector_database():
|
||||||
|
|
||||||
if documents:
|
if documents:
|
||||||
try:
|
try:
|
||||||
click.echo(click.style(
|
click.echo(
|
||||||
f'Start to created vector index with {len(documents)} documents of {segments_count} segments for dataset {dataset.id}.',
|
click.style(
|
||||||
fg='green'))
|
f"Start to created vector index with {len(documents)} documents of {segments_count} segments for dataset {dataset.id}.",
|
||||||
|
fg="green",
|
||||||
|
)
|
||||||
|
)
|
||||||
vector.create(documents)
|
vector.create(documents)
|
||||||
click.echo(
|
click.echo(
|
||||||
click.style(f'Successfully created vector index for dataset {dataset.id}.', fg='green'))
|
click.style(f"Successfully created vector index for dataset {dataset.id}.", fg="green")
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
click.echo(click.style(f'Failed to created vector index for dataset {dataset.id}.', fg='red'))
|
click.echo(click.style(f"Failed to created vector index for dataset {dataset.id}.", fg="red"))
|
||||||
raise e
|
raise e
|
||||||
db.session.add(dataset)
|
db.session.add(dataset)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
click.echo(f'Successfully migrated dataset {dataset.id}.')
|
click.echo(f"Successfully migrated dataset {dataset.id}.")
|
||||||
create_count += 1
|
create_count += 1
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
db.session.rollback()
|
db.session.rollback()
|
||||||
click.echo(
|
click.echo(
|
||||||
click.style('Create dataset index error: {} {}'.format(e.__class__.__name__, str(e)),
|
click.style("Create dataset index error: {} {}".format(e.__class__.__name__, str(e)), fg="red")
|
||||||
fg='red'))
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
click.echo(
|
click.echo(
|
||||||
click.style(f'Congratulations! Create {create_count} dataset indexes, and skipped {skipped_count} datasets.',
|
click.style(
|
||||||
fg='green'))
|
f"Congratulations! Create {create_count} dataset indexes, and skipped {skipped_count} datasets.", fg="green"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@click.command('convert-to-agent-apps', help='Convert Agent Assistant to Agent App.')
|
@click.command("convert-to-agent-apps", help="Convert Agent Assistant to Agent App.")
|
||||||
def convert_to_agent_apps():
|
def convert_to_agent_apps():
|
||||||
"""
|
"""
|
||||||
Convert Agent Assistant to Agent App.
|
Convert Agent Assistant to Agent App.
|
||||||
"""
|
"""
|
||||||
click.echo(click.style('Start convert to agent apps.', fg='green'))
|
click.echo(click.style("Start convert to agent apps.", fg="green"))
|
||||||
|
|
||||||
proceeded_app_ids = []
|
proceeded_app_ids = []
|
||||||
|
|
||||||
|
@ -466,7 +480,7 @@ def convert_to_agent_apps():
|
||||||
break
|
break
|
||||||
|
|
||||||
for app in apps:
|
for app in apps:
|
||||||
click.echo('Converting app: {}'.format(app.id))
|
click.echo("Converting app: {}".format(app.id))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
app.mode = AppMode.AGENT_CHAT.value
|
app.mode = AppMode.AGENT_CHAT.value
|
||||||
|
@ -478,137 +492,139 @@ def convert_to_agent_apps():
|
||||||
)
|
)
|
||||||
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
click.echo(click.style('Converted app: {}'.format(app.id), fg='green'))
|
click.echo(click.style("Converted app: {}".format(app.id), fg="green"))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
click.echo(
|
click.echo(click.style("Convert app error: {} {}".format(e.__class__.__name__, str(e)), fg="red"))
|
||||||
click.style('Convert app error: {} {}'.format(e.__class__.__name__,
|
|
||||||
str(e)), fg='red'))
|
|
||||||
|
|
||||||
click.echo(click.style('Congratulations! Converted {} agent apps.'.format(len(proceeded_app_ids)), fg='green'))
|
click.echo(click.style("Congratulations! Converted {} agent apps.".format(len(proceeded_app_ids)), fg="green"))
|
||||||
|
|
||||||
|
|
||||||
@click.command('add-qdrant-doc-id-index', help='add qdrant doc_id index.')
|
@click.command("add-qdrant-doc-id-index", help="add qdrant doc_id index.")
|
||||||
@click.option('--field', default='metadata.doc_id', prompt=False, help='index field , default is metadata.doc_id.')
|
@click.option("--field", default="metadata.doc_id", prompt=False, help="index field , default is metadata.doc_id.")
|
||||||
def add_qdrant_doc_id_index(field: str):
|
def add_qdrant_doc_id_index(field: str):
|
||||||
click.echo(click.style('Start add qdrant doc_id index.', fg='green'))
|
click.echo(click.style("Start add qdrant doc_id index.", fg="green"))
|
||||||
vector_type = dify_config.VECTOR_STORE
|
vector_type = dify_config.VECTOR_STORE
|
||||||
if vector_type != "qdrant":
|
if vector_type != "qdrant":
|
||||||
click.echo(click.style('Sorry, only support qdrant vector store.', fg='red'))
|
click.echo(click.style("Sorry, only support qdrant vector store.", fg="red"))
|
||||||
return
|
return
|
||||||
create_count = 0
|
create_count = 0
|
||||||
|
|
||||||
try:
|
try:
|
||||||
bindings = db.session.query(DatasetCollectionBinding).all()
|
bindings = db.session.query(DatasetCollectionBinding).all()
|
||||||
if not bindings:
|
if not bindings:
|
||||||
click.echo(click.style('Sorry, no dataset collection bindings found.', fg='red'))
|
click.echo(click.style("Sorry, no dataset collection bindings found.", fg="red"))
|
||||||
return
|
return
|
||||||
import qdrant_client
|
import qdrant_client
|
||||||
from qdrant_client.http.exceptions import UnexpectedResponse
|
from qdrant_client.http.exceptions import UnexpectedResponse
|
||||||
from qdrant_client.http.models import PayloadSchemaType
|
from qdrant_client.http.models import PayloadSchemaType
|
||||||
|
|
||||||
from core.rag.datasource.vdb.qdrant.qdrant_vector import QdrantConfig
|
from core.rag.datasource.vdb.qdrant.qdrant_vector import QdrantConfig
|
||||||
|
|
||||||
for binding in bindings:
|
for binding in bindings:
|
||||||
if dify_config.QDRANT_URL is None:
|
if dify_config.QDRANT_URL is None:
|
||||||
raise ValueError('Qdrant url is required.')
|
raise ValueError("Qdrant url is required.")
|
||||||
qdrant_config = QdrantConfig(
|
qdrant_config = QdrantConfig(
|
||||||
endpoint=dify_config.QDRANT_URL,
|
endpoint=dify_config.QDRANT_URL,
|
||||||
api_key=dify_config.QDRANT_API_KEY,
|
api_key=dify_config.QDRANT_API_KEY,
|
||||||
root_path=current_app.root_path,
|
root_path=current_app.root_path,
|
||||||
timeout=dify_config.QDRANT_CLIENT_TIMEOUT,
|
timeout=dify_config.QDRANT_CLIENT_TIMEOUT,
|
||||||
grpc_port=dify_config.QDRANT_GRPC_PORT,
|
grpc_port=dify_config.QDRANT_GRPC_PORT,
|
||||||
prefer_grpc=dify_config.QDRANT_GRPC_ENABLED
|
prefer_grpc=dify_config.QDRANT_GRPC_ENABLED,
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
client = qdrant_client.QdrantClient(**qdrant_config.to_qdrant_params())
|
client = qdrant_client.QdrantClient(**qdrant_config.to_qdrant_params())
|
||||||
# create payload index
|
# create payload index
|
||||||
client.create_payload_index(binding.collection_name, field,
|
client.create_payload_index(binding.collection_name, field, field_schema=PayloadSchemaType.KEYWORD)
|
||||||
field_schema=PayloadSchemaType.KEYWORD)
|
|
||||||
create_count += 1
|
create_count += 1
|
||||||
except UnexpectedResponse as e:
|
except UnexpectedResponse as e:
|
||||||
# Collection does not exist, so return
|
# Collection does not exist, so return
|
||||||
if e.status_code == 404:
|
if e.status_code == 404:
|
||||||
click.echo(click.style(f'Collection not found, collection_name:{binding.collection_name}.', fg='red'))
|
click.echo(
|
||||||
|
click.style(f"Collection not found, collection_name:{binding.collection_name}.", fg="red")
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
# Some other error occurred, so re-raise the exception
|
# Some other error occurred, so re-raise the exception
|
||||||
else:
|
else:
|
||||||
click.echo(click.style(f'Failed to create qdrant index, collection_name:{binding.collection_name}.', fg='red'))
|
click.echo(
|
||||||
|
click.style(
|
||||||
|
f"Failed to create qdrant index, collection_name:{binding.collection_name}.", fg="red"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
click.echo(click.style('Failed to create qdrant client.', fg='red'))
|
click.echo(click.style("Failed to create qdrant client.", fg="red"))
|
||||||
|
|
||||||
click.echo(
|
click.echo(click.style(f"Congratulations! Create {create_count} collection indexes.", fg="green"))
|
||||||
click.style(f'Congratulations! Create {create_count} collection indexes.',
|
|
||||||
fg='green'))
|
|
||||||
|
|
||||||
|
|
||||||
@click.command('create-tenant', help='Create account and tenant.')
|
@click.command("create-tenant", help="Create account and tenant.")
|
||||||
@click.option('--email', prompt=True, help='The email address of the tenant account.')
|
@click.option("--email", prompt=True, help="The email address of the tenant account.")
|
||||||
@click.option('--language', prompt=True, help='Account language, default: en-US.')
|
@click.option("--language", prompt=True, help="Account language, default: en-US.")
|
||||||
def create_tenant(email: str, language: Optional[str] = None):
|
def create_tenant(email: str, language: Optional[str] = None):
|
||||||
"""
|
"""
|
||||||
Create tenant account
|
Create tenant account
|
||||||
"""
|
"""
|
||||||
if not email:
|
if not email:
|
||||||
click.echo(click.style('Sorry, email is required.', fg='red'))
|
click.echo(click.style("Sorry, email is required.", fg="red"))
|
||||||
return
|
return
|
||||||
|
|
||||||
# Create account
|
# Create account
|
||||||
email = email.strip()
|
email = email.strip()
|
||||||
|
|
||||||
if '@' not in email:
|
if "@" not in email:
|
||||||
click.echo(click.style('Sorry, invalid email address.', fg='red'))
|
click.echo(click.style("Sorry, invalid email address.", fg="red"))
|
||||||
return
|
return
|
||||||
|
|
||||||
account_name = email.split('@')[0]
|
account_name = email.split("@")[0]
|
||||||
|
|
||||||
if language not in languages:
|
if language not in languages:
|
||||||
language = 'en-US'
|
language = "en-US"
|
||||||
|
|
||||||
# generate random password
|
# generate random password
|
||||||
new_password = secrets.token_urlsafe(16)
|
new_password = secrets.token_urlsafe(16)
|
||||||
|
|
||||||
# register account
|
# register account
|
||||||
account = RegisterService.register(
|
account = RegisterService.register(email=email, name=account_name, password=new_password, language=language)
|
||||||
email=email,
|
|
||||||
name=account_name,
|
|
||||||
password=new_password,
|
|
||||||
language=language
|
|
||||||
)
|
|
||||||
|
|
||||||
TenantService.create_owner_tenant_if_not_exist(account)
|
TenantService.create_owner_tenant_if_not_exist(account)
|
||||||
|
|
||||||
click.echo(click.style('Congratulations! Account and tenant created.\n'
|
click.echo(
|
||||||
'Account: {}\nPassword: {}'.format(email, new_password), fg='green'))
|
click.style(
|
||||||
|
"Congratulations! Account and tenant created.\n" "Account: {}\nPassword: {}".format(email, new_password),
|
||||||
|
fg="green",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@click.command('upgrade-db', help='upgrade the database')
|
@click.command("upgrade-db", help="upgrade the database")
|
||||||
def upgrade_db():
|
def upgrade_db():
|
||||||
click.echo('Preparing database migration...')
|
click.echo("Preparing database migration...")
|
||||||
lock = redis_client.lock(name='db_upgrade_lock', timeout=60)
|
lock = redis_client.lock(name="db_upgrade_lock", timeout=60)
|
||||||
if lock.acquire(blocking=False):
|
if lock.acquire(blocking=False):
|
||||||
try:
|
try:
|
||||||
click.echo(click.style('Start database migration.', fg='green'))
|
click.echo(click.style("Start database migration.", fg="green"))
|
||||||
|
|
||||||
# run db migration
|
# run db migration
|
||||||
import flask_migrate
|
import flask_migrate
|
||||||
|
|
||||||
flask_migrate.upgrade()
|
flask_migrate.upgrade()
|
||||||
|
|
||||||
click.echo(click.style('Database migration successful!', fg='green'))
|
click.echo(click.style("Database migration successful!", fg="green"))
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.exception(f'Database migration failed, error: {e}')
|
logging.exception(f"Database migration failed, error: {e}")
|
||||||
finally:
|
finally:
|
||||||
lock.release()
|
lock.release()
|
||||||
else:
|
else:
|
||||||
click.echo('Database migration skipped')
|
click.echo("Database migration skipped")
|
||||||
|
|
||||||
|
|
||||||
@click.command('fix-app-site-missing', help='Fix app related site missing issue.')
|
@click.command("fix-app-site-missing", help="Fix app related site missing issue.")
|
||||||
def fix_app_site_missing():
|
def fix_app_site_missing():
|
||||||
"""
|
"""
|
||||||
Fix app related site missing issue.
|
Fix app related site missing issue.
|
||||||
"""
|
"""
|
||||||
click.echo(click.style('Start fix app related site missing issue.', fg='green'))
|
click.echo(click.style("Start fix app related site missing issue.", fg="green"))
|
||||||
|
|
||||||
failed_app_ids = []
|
failed_app_ids = []
|
||||||
while True:
|
while True:
|
||||||
|
@ -639,15 +655,14 @@ where sites.id is null limit 1000"""
|
||||||
app_was_created.send(app, account=account)
|
app_was_created.send(app, account=account)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
failed_app_ids.append(app_id)
|
failed_app_ids.append(app_id)
|
||||||
click.echo(click.style('Fix app {} related site missing issue failed!'.format(app_id), fg='red'))
|
click.echo(click.style("Fix app {} related site missing issue failed!".format(app_id), fg="red"))
|
||||||
logging.exception(f'Fix app related site missing issue failed, error: {e}')
|
logging.exception(f"Fix app related site missing issue failed, error: {e}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not processed_count:
|
if not processed_count:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
click.echo(click.style("Congratulations! Fix app related site missing issue successful!", fg="green"))
|
||||||
click.echo(click.style('Congratulations! Fix app related site missing issue successful!', fg='green'))
|
|
||||||
|
|
||||||
|
|
||||||
def register_commands(app):
|
def register_commands(app):
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
HIDDEN_VALUE = '[__HIDDEN__]'
|
HIDDEN_VALUE = "[__HIDDEN__]"
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
language_timezone_mapping = {
|
language_timezone_mapping = {
|
||||||
'en-US': 'America/New_York',
|
"en-US": "America/New_York",
|
||||||
'zh-Hans': 'Asia/Shanghai',
|
"zh-Hans": "Asia/Shanghai",
|
||||||
'zh-Hant': 'Asia/Taipei',
|
"zh-Hant": "Asia/Taipei",
|
||||||
'pt-BR': 'America/Sao_Paulo',
|
"pt-BR": "America/Sao_Paulo",
|
||||||
'es-ES': 'Europe/Madrid',
|
"es-ES": "Europe/Madrid",
|
||||||
'fr-FR': 'Europe/Paris',
|
"fr-FR": "Europe/Paris",
|
||||||
'de-DE': 'Europe/Berlin',
|
"de-DE": "Europe/Berlin",
|
||||||
'ja-JP': 'Asia/Tokyo',
|
"ja-JP": "Asia/Tokyo",
|
||||||
'ko-KR': 'Asia/Seoul',
|
"ko-KR": "Asia/Seoul",
|
||||||
'ru-RU': 'Europe/Moscow',
|
"ru-RU": "Europe/Moscow",
|
||||||
'it-IT': 'Europe/Rome',
|
"it-IT": "Europe/Rome",
|
||||||
'uk-UA': 'Europe/Kyiv',
|
"uk-UA": "Europe/Kyiv",
|
||||||
'vi-VN': 'Asia/Ho_Chi_Minh',
|
"vi-VN": "Asia/Ho_Chi_Minh",
|
||||||
'ro-RO': 'Europe/Bucharest',
|
"ro-RO": "Europe/Bucharest",
|
||||||
'pl-PL': 'Europe/Warsaw',
|
"pl-PL": "Europe/Warsaw",
|
||||||
'hi-IN': 'Asia/Kolkata',
|
"hi-IN": "Asia/Kolkata",
|
||||||
'tr-TR': 'Europe/Istanbul',
|
"tr-TR": "Europe/Istanbul",
|
||||||
'fa-IR': 'Asia/Tehran',
|
"fa-IR": "Asia/Tehran",
|
||||||
}
|
}
|
||||||
|
|
||||||
languages = list(language_timezone_mapping.keys())
|
languages = list(language_timezone_mapping.keys())
|
||||||
|
@ -26,6 +26,5 @@ def supported_language(lang):
|
||||||
if lang in languages:
|
if lang in languages:
|
||||||
return lang
|
return lang
|
||||||
|
|
||||||
error = ('{lang} is not a valid language.'
|
error = "{lang} is not a valid language.".format(lang=lang)
|
||||||
.format(lang=lang))
|
|
||||||
raise ValueError(error)
|
raise ValueError(error)
|
||||||
|
|
|
@ -5,82 +5,79 @@ from models.model import AppMode
|
||||||
default_app_templates = {
|
default_app_templates = {
|
||||||
# workflow default mode
|
# workflow default mode
|
||||||
AppMode.WORKFLOW: {
|
AppMode.WORKFLOW: {
|
||||||
'app': {
|
"app": {
|
||||||
'mode': AppMode.WORKFLOW.value,
|
"mode": AppMode.WORKFLOW.value,
|
||||||
'enable_site': True,
|
"enable_site": True,
|
||||||
'enable_api': True
|
"enable_api": True,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
# completion default mode
|
# completion default mode
|
||||||
AppMode.COMPLETION: {
|
AppMode.COMPLETION: {
|
||||||
'app': {
|
"app": {
|
||||||
'mode': AppMode.COMPLETION.value,
|
"mode": AppMode.COMPLETION.value,
|
||||||
'enable_site': True,
|
"enable_site": True,
|
||||||
'enable_api': True
|
"enable_api": True,
|
||||||
},
|
},
|
||||||
'model_config': {
|
"model_config": {
|
||||||
'model': {
|
"model": {
|
||||||
"provider": "openai",
|
"provider": "openai",
|
||||||
"name": "gpt-4o",
|
"name": "gpt-4o",
|
||||||
"mode": "chat",
|
"mode": "chat",
|
||||||
"completion_params": {}
|
"completion_params": {},
|
||||||
},
|
},
|
||||||
'user_input_form': json.dumps([
|
"user_input_form": json.dumps(
|
||||||
|
[
|
||||||
{
|
{
|
||||||
"paragraph": {
|
"paragraph": {
|
||||||
"label": "Query",
|
"label": "Query",
|
||||||
"variable": "query",
|
"variable": "query",
|
||||||
"required": True,
|
"required": True,
|
||||||
"default": ""
|
"default": "",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]),
|
]
|
||||||
'pre_prompt': '{{query}}'
|
),
|
||||||
|
"pre_prompt": "{{query}}",
|
||||||
},
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
# chat default mode
|
# chat default mode
|
||||||
AppMode.CHAT: {
|
AppMode.CHAT: {
|
||||||
'app': {
|
"app": {
|
||||||
'mode': AppMode.CHAT.value,
|
"mode": AppMode.CHAT.value,
|
||||||
'enable_site': True,
|
"enable_site": True,
|
||||||
'enable_api': True
|
"enable_api": True,
|
||||||
},
|
},
|
||||||
'model_config': {
|
"model_config": {
|
||||||
'model': {
|
"model": {
|
||||||
"provider": "openai",
|
"provider": "openai",
|
||||||
"name": "gpt-4o",
|
"name": "gpt-4o",
|
||||||
"mode": "chat",
|
"mode": "chat",
|
||||||
"completion_params": {}
|
"completion_params": {},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
# advanced-chat default mode
|
# advanced-chat default mode
|
||||||
AppMode.ADVANCED_CHAT: {
|
AppMode.ADVANCED_CHAT: {
|
||||||
'app': {
|
"app": {
|
||||||
'mode': AppMode.ADVANCED_CHAT.value,
|
"mode": AppMode.ADVANCED_CHAT.value,
|
||||||
'enable_site': True,
|
"enable_site": True,
|
||||||
'enable_api': True
|
"enable_api": True,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
# agent-chat default mode
|
# agent-chat default mode
|
||||||
AppMode.AGENT_CHAT: {
|
AppMode.AGENT_CHAT: {
|
||||||
'app': {
|
"app": {
|
||||||
'mode': AppMode.AGENT_CHAT.value,
|
"mode": AppMode.AGENT_CHAT.value,
|
||||||
'enable_site': True,
|
"enable_site": True,
|
||||||
'enable_api': True
|
"enable_api": True,
|
||||||
},
|
},
|
||||||
'model_config': {
|
"model_config": {
|
||||||
'model': {
|
"model": {
|
||||||
"provider": "openai",
|
"provider": "openai",
|
||||||
"name": "gpt-4o",
|
"name": "gpt-4o",
|
||||||
"mode": "chat",
|
"mode": "chat",
|
||||||
"completion_params": {}
|
"completion_params": {},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,6 @@ from contextvars import ContextVar
|
||||||
|
|
||||||
from core.workflow.entities.variable_pool import VariablePool
|
from core.workflow.entities.variable_pool import VariablePool
|
||||||
|
|
||||||
tenant_id: ContextVar[str] = ContextVar('tenant_id')
|
tenant_id: ContextVar[str] = ContextVar("tenant_id")
|
||||||
|
|
||||||
workflow_variable_pool: ContextVar[VariablePool] = ContextVar('workflow_variable_pool')
|
workflow_variable_pool: ContextVar[VariablePool] = ContextVar("workflow_variable_pool")
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
from blinker import signal
|
from blinker import signal
|
||||||
|
|
||||||
# sender: app
|
# sender: app
|
||||||
app_was_created = signal('app-was-created')
|
app_was_created = signal("app-was-created")
|
||||||
|
|
||||||
# sender: app, kwargs: app_model_config
|
# sender: app, kwargs: app_model_config
|
||||||
app_model_config_was_updated = signal('app-model-config-was-updated')
|
app_model_config_was_updated = signal("app-model-config-was-updated")
|
||||||
|
|
||||||
# sender: app, kwargs: published_workflow
|
# sender: app, kwargs: published_workflow
|
||||||
app_published_workflow_was_updated = signal('app-published-workflow-was-updated')
|
app_published_workflow_was_updated = signal("app-published-workflow-was-updated")
|
||||||
|
|
||||||
# sender: app, kwargs: synced_draft_workflow
|
# sender: app, kwargs: synced_draft_workflow
|
||||||
app_draft_workflow_was_synced = signal('app-draft-workflow-was-synced')
|
app_draft_workflow_was_synced = signal("app-draft-workflow-was-synced")
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from blinker import signal
|
from blinker import signal
|
||||||
|
|
||||||
# sender: dataset
|
# sender: dataset
|
||||||
dataset_was_deleted = signal('dataset-was-deleted')
|
dataset_was_deleted = signal("dataset-was-deleted")
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from blinker import signal
|
from blinker import signal
|
||||||
|
|
||||||
# sender: document
|
# sender: document
|
||||||
document_was_deleted = signal('document-was-deleted')
|
document_was_deleted = signal("document-was-deleted")
|
||||||
|
|
|
@ -5,5 +5,11 @@ from tasks.clean_dataset_task import clean_dataset_task
|
||||||
@dataset_was_deleted.connect
|
@dataset_was_deleted.connect
|
||||||
def handle(sender, **kwargs):
|
def handle(sender, **kwargs):
|
||||||
dataset = sender
|
dataset = sender
|
||||||
clean_dataset_task.delay(dataset.id, dataset.tenant_id, dataset.indexing_technique,
|
clean_dataset_task.delay(
|
||||||
dataset.index_struct, dataset.collection_binding_id, dataset.doc_form)
|
dataset.id,
|
||||||
|
dataset.tenant_id,
|
||||||
|
dataset.indexing_technique,
|
||||||
|
dataset.index_struct,
|
||||||
|
dataset.collection_binding_id,
|
||||||
|
dataset.doc_form,
|
||||||
|
)
|
||||||
|
|
|
@ -5,7 +5,7 @@ from tasks.clean_document_task import clean_document_task
|
||||||
@document_was_deleted.connect
|
@document_was_deleted.connect
|
||||||
def handle(sender, **kwargs):
|
def handle(sender, **kwargs):
|
||||||
document_id = sender
|
document_id = sender
|
||||||
dataset_id = kwargs.get('dataset_id')
|
dataset_id = kwargs.get("dataset_id")
|
||||||
doc_form = kwargs.get('doc_form')
|
doc_form = kwargs.get("doc_form")
|
||||||
file_id = kwargs.get('file_id')
|
file_id = kwargs.get("file_id")
|
||||||
clean_document_task.delay(document_id, dataset_id, doc_form, file_id)
|
clean_document_task.delay(document_id, dataset_id, doc_form, file_id)
|
||||||
|
|
|
@ -14,21 +14,25 @@ from models.dataset import Document
|
||||||
@document_index_created.connect
|
@document_index_created.connect
|
||||||
def handle(sender, **kwargs):
|
def handle(sender, **kwargs):
|
||||||
dataset_id = sender
|
dataset_id = sender
|
||||||
document_ids = kwargs.get('document_ids', None)
|
document_ids = kwargs.get("document_ids", None)
|
||||||
documents = []
|
documents = []
|
||||||
start_at = time.perf_counter()
|
start_at = time.perf_counter()
|
||||||
for document_id in document_ids:
|
for document_id in document_ids:
|
||||||
logging.info(click.style('Start process document: {}'.format(document_id), fg='green'))
|
logging.info(click.style("Start process document: {}".format(document_id), fg="green"))
|
||||||
|
|
||||||
document = db.session.query(Document).filter(
|
document = (
|
||||||
|
db.session.query(Document)
|
||||||
|
.filter(
|
||||||
Document.id == document_id,
|
Document.id == document_id,
|
||||||
Document.dataset_id == dataset_id
|
Document.dataset_id == dataset_id,
|
||||||
).first()
|
)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
|
||||||
if not document:
|
if not document:
|
||||||
raise NotFound('Document not found')
|
raise NotFound("Document not found")
|
||||||
|
|
||||||
document.indexing_status = 'parsing'
|
document.indexing_status = "parsing"
|
||||||
document.processing_started_at = datetime.datetime.now(datetime.timezone.utc).replace(tzinfo=None)
|
document.processing_started_at = datetime.datetime.now(datetime.timezone.utc).replace(tzinfo=None)
|
||||||
documents.append(document)
|
documents.append(document)
|
||||||
db.session.add(document)
|
db.session.add(document)
|
||||||
|
@ -38,8 +42,8 @@ def handle(sender, **kwargs):
|
||||||
indexing_runner = IndexingRunner()
|
indexing_runner = IndexingRunner()
|
||||||
indexing_runner.run(documents)
|
indexing_runner.run(documents)
|
||||||
end_at = time.perf_counter()
|
end_at = time.perf_counter()
|
||||||
logging.info(click.style('Processed dataset: {} latency: {}'.format(dataset_id, end_at - start_at), fg='green'))
|
logging.info(click.style("Processed dataset: {} latency: {}".format(dataset_id, end_at - start_at), fg="green"))
|
||||||
except DocumentIsPausedException as ex:
|
except DocumentIsPausedException as ex:
|
||||||
logging.info(click.style(str(ex), fg='yellow'))
|
logging.info(click.style(str(ex), fg="yellow"))
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -10,7 +10,7 @@ def handle(sender, **kwargs):
|
||||||
installed_app = InstalledApp(
|
installed_app = InstalledApp(
|
||||||
tenant_id=app.tenant_id,
|
tenant_id=app.tenant_id,
|
||||||
app_id=app.id,
|
app_id=app.id,
|
||||||
app_owner_tenant_id=app.tenant_id
|
app_owner_tenant_id=app.tenant_id,
|
||||||
)
|
)
|
||||||
db.session.add(installed_app)
|
db.session.add(installed_app)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
|
@ -7,15 +7,15 @@ from models.model import Site
|
||||||
def handle(sender, **kwargs):
|
def handle(sender, **kwargs):
|
||||||
"""Create site record when an app is created."""
|
"""Create site record when an app is created."""
|
||||||
app = sender
|
app = sender
|
||||||
account = kwargs.get('account')
|
account = kwargs.get("account")
|
||||||
site = Site(
|
site = Site(
|
||||||
app_id=app.id,
|
app_id=app.id,
|
||||||
title=app.name,
|
title=app.name,
|
||||||
icon=app.icon,
|
icon=app.icon,
|
||||||
icon_background=app.icon_background,
|
icon_background=app.icon_background,
|
||||||
default_language=account.interface_language,
|
default_language=account.interface_language,
|
||||||
customize_token_strategy='not_allow',
|
customize_token_strategy="not_allow",
|
||||||
code=Site.generate_code(16)
|
code=Site.generate_code(16),
|
||||||
)
|
)
|
||||||
|
|
||||||
db.session.add(site)
|
db.session.add(site)
|
||||||
|
|
|
@ -8,7 +8,7 @@ from models.provider import Provider, ProviderType
|
||||||
@message_was_created.connect
|
@message_was_created.connect
|
||||||
def handle(sender, **kwargs):
|
def handle(sender, **kwargs):
|
||||||
message = sender
|
message = sender
|
||||||
application_generate_entity = kwargs.get('application_generate_entity')
|
application_generate_entity = kwargs.get("application_generate_entity")
|
||||||
|
|
||||||
if not isinstance(application_generate_entity, ChatAppGenerateEntity | AgentChatAppGenerateEntity):
|
if not isinstance(application_generate_entity, ChatAppGenerateEntity | AgentChatAppGenerateEntity):
|
||||||
return
|
return
|
||||||
|
@ -39,7 +39,7 @@ def handle(sender, **kwargs):
|
||||||
elif quota_unit == QuotaUnit.CREDITS:
|
elif quota_unit == QuotaUnit.CREDITS:
|
||||||
used_quota = 1
|
used_quota = 1
|
||||||
|
|
||||||
if 'gpt-4' in model_config.model:
|
if "gpt-4" in model_config.model:
|
||||||
used_quota = 20
|
used_quota = 20
|
||||||
else:
|
else:
|
||||||
used_quota = 1
|
used_quota = 1
|
||||||
|
@ -50,6 +50,6 @@ def handle(sender, **kwargs):
|
||||||
Provider.provider_name == model_config.provider,
|
Provider.provider_name == model_config.provider,
|
||||||
Provider.provider_type == ProviderType.SYSTEM.value,
|
Provider.provider_type == ProviderType.SYSTEM.value,
|
||||||
Provider.quota_type == system_configuration.current_quota_type.value,
|
Provider.quota_type == system_configuration.current_quota_type.value,
|
||||||
Provider.quota_limit > Provider.quota_used
|
Provider.quota_limit > Provider.quota_used,
|
||||||
).update({'quota_used': Provider.quota_used + used_quota})
|
).update({"quota_used": Provider.quota_used + used_quota})
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
|
@ -8,8 +8,8 @@ from events.app_event import app_draft_workflow_was_synced
|
||||||
@app_draft_workflow_was_synced.connect
|
@app_draft_workflow_was_synced.connect
|
||||||
def handle(sender, **kwargs):
|
def handle(sender, **kwargs):
|
||||||
app = sender
|
app = sender
|
||||||
for node_data in kwargs.get('synced_draft_workflow').graph_dict.get('nodes', []):
|
for node_data in kwargs.get("synced_draft_workflow").graph_dict.get("nodes", []):
|
||||||
if node_data.get('data', {}).get('type') == NodeType.TOOL.value:
|
if node_data.get("data", {}).get("type") == NodeType.TOOL.value:
|
||||||
try:
|
try:
|
||||||
tool_entity = ToolEntity(**node_data["data"])
|
tool_entity = ToolEntity(**node_data["data"])
|
||||||
tool_runtime = ToolManager.get_tool_runtime(
|
tool_runtime = ToolManager.get_tool_runtime(
|
||||||
|
@ -23,7 +23,7 @@ def handle(sender, **kwargs):
|
||||||
tool_runtime=tool_runtime,
|
tool_runtime=tool_runtime,
|
||||||
provider_name=tool_entity.provider_name,
|
provider_name=tool_entity.provider_name,
|
||||||
provider_type=tool_entity.provider_type,
|
provider_type=tool_entity.provider_type,
|
||||||
identity_id=f'WORKFLOW.{app.id}.{node_data.get("id")}'
|
identity_id=f'WORKFLOW.{app.id}.{node_data.get("id")}',
|
||||||
)
|
)
|
||||||
manager.delete_tool_parameters_cache()
|
manager.delete_tool_parameters_cache()
|
||||||
except:
|
except:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from blinker import signal
|
from blinker import signal
|
||||||
|
|
||||||
# sender: document
|
# sender: document
|
||||||
document_index_created = signal('document-index-created')
|
document_index_created = signal("document-index-created")
|
||||||
|
|
|
@ -7,13 +7,11 @@ from models.model import AppModelConfig
|
||||||
@app_model_config_was_updated.connect
|
@app_model_config_was_updated.connect
|
||||||
def handle(sender, **kwargs):
|
def handle(sender, **kwargs):
|
||||||
app = sender
|
app = sender
|
||||||
app_model_config = kwargs.get('app_model_config')
|
app_model_config = kwargs.get("app_model_config")
|
||||||
|
|
||||||
dataset_ids = get_dataset_ids_from_model_config(app_model_config)
|
dataset_ids = get_dataset_ids_from_model_config(app_model_config)
|
||||||
|
|
||||||
app_dataset_joins = db.session.query(AppDatasetJoin).filter(
|
app_dataset_joins = db.session.query(AppDatasetJoin).filter(AppDatasetJoin.app_id == app.id).all()
|
||||||
AppDatasetJoin.app_id == app.id
|
|
||||||
).all()
|
|
||||||
|
|
||||||
removed_dataset_ids = []
|
removed_dataset_ids = []
|
||||||
if not app_dataset_joins:
|
if not app_dataset_joins:
|
||||||
|
@ -29,16 +27,12 @@ def handle(sender, **kwargs):
|
||||||
if removed_dataset_ids:
|
if removed_dataset_ids:
|
||||||
for dataset_id in removed_dataset_ids:
|
for dataset_id in removed_dataset_ids:
|
||||||
db.session.query(AppDatasetJoin).filter(
|
db.session.query(AppDatasetJoin).filter(
|
||||||
AppDatasetJoin.app_id == app.id,
|
AppDatasetJoin.app_id == app.id, AppDatasetJoin.dataset_id == dataset_id
|
||||||
AppDatasetJoin.dataset_id == dataset_id
|
|
||||||
).delete()
|
).delete()
|
||||||
|
|
||||||
if added_dataset_ids:
|
if added_dataset_ids:
|
||||||
for dataset_id in added_dataset_ids:
|
for dataset_id in added_dataset_ids:
|
||||||
app_dataset_join = AppDatasetJoin(
|
app_dataset_join = AppDatasetJoin(app_id=app.id, dataset_id=dataset_id)
|
||||||
app_id=app.id,
|
|
||||||
dataset_id=dataset_id
|
|
||||||
)
|
|
||||||
db.session.add(app_dataset_join)
|
db.session.add(app_dataset_join)
|
||||||
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
@ -51,7 +45,7 @@ def get_dataset_ids_from_model_config(app_model_config: AppModelConfig) -> set:
|
||||||
|
|
||||||
agent_mode = app_model_config.agent_mode_dict
|
agent_mode = app_model_config.agent_mode_dict
|
||||||
|
|
||||||
tools = agent_mode.get('tools', []) or []
|
tools = agent_mode.get("tools", []) or []
|
||||||
for tool in tools:
|
for tool in tools:
|
||||||
if len(list(tool.keys())) != 1:
|
if len(list(tool.keys())) != 1:
|
||||||
continue
|
continue
|
||||||
|
@ -63,11 +57,11 @@ def get_dataset_ids_from_model_config(app_model_config: AppModelConfig) -> set:
|
||||||
|
|
||||||
# get dataset from dataset_configs
|
# get dataset from dataset_configs
|
||||||
dataset_configs = app_model_config.dataset_configs_dict
|
dataset_configs = app_model_config.dataset_configs_dict
|
||||||
datasets = dataset_configs.get('datasets', {}) or {}
|
datasets = dataset_configs.get("datasets", {}) or {}
|
||||||
for dataset in datasets.get('datasets', []) or []:
|
for dataset in datasets.get("datasets", []) or []:
|
||||||
keys = list(dataset.keys())
|
keys = list(dataset.keys())
|
||||||
if len(keys) == 1 and keys[0] == 'dataset':
|
if len(keys) == 1 and keys[0] == "dataset":
|
||||||
if dataset['dataset'].get('id'):
|
if dataset["dataset"].get("id"):
|
||||||
dataset_ids.add(dataset['dataset'].get('id'))
|
dataset_ids.add(dataset["dataset"].get("id"))
|
||||||
|
|
||||||
return dataset_ids
|
return dataset_ids
|
||||||
|
|
|
@ -11,13 +11,11 @@ from models.workflow import Workflow
|
||||||
@app_published_workflow_was_updated.connect
|
@app_published_workflow_was_updated.connect
|
||||||
def handle(sender, **kwargs):
|
def handle(sender, **kwargs):
|
||||||
app = sender
|
app = sender
|
||||||
published_workflow = kwargs.get('published_workflow')
|
published_workflow = kwargs.get("published_workflow")
|
||||||
published_workflow = cast(Workflow, published_workflow)
|
published_workflow = cast(Workflow, published_workflow)
|
||||||
|
|
||||||
dataset_ids = get_dataset_ids_from_workflow(published_workflow)
|
dataset_ids = get_dataset_ids_from_workflow(published_workflow)
|
||||||
app_dataset_joins = db.session.query(AppDatasetJoin).filter(
|
app_dataset_joins = db.session.query(AppDatasetJoin).filter(AppDatasetJoin.app_id == app.id).all()
|
||||||
AppDatasetJoin.app_id == app.id
|
|
||||||
).all()
|
|
||||||
|
|
||||||
removed_dataset_ids = []
|
removed_dataset_ids = []
|
||||||
if not app_dataset_joins:
|
if not app_dataset_joins:
|
||||||
|
@ -33,16 +31,12 @@ def handle(sender, **kwargs):
|
||||||
if removed_dataset_ids:
|
if removed_dataset_ids:
|
||||||
for dataset_id in removed_dataset_ids:
|
for dataset_id in removed_dataset_ids:
|
||||||
db.session.query(AppDatasetJoin).filter(
|
db.session.query(AppDatasetJoin).filter(
|
||||||
AppDatasetJoin.app_id == app.id,
|
AppDatasetJoin.app_id == app.id, AppDatasetJoin.dataset_id == dataset_id
|
||||||
AppDatasetJoin.dataset_id == dataset_id
|
|
||||||
).delete()
|
).delete()
|
||||||
|
|
||||||
if added_dataset_ids:
|
if added_dataset_ids:
|
||||||
for dataset_id in added_dataset_ids:
|
for dataset_id in added_dataset_ids:
|
||||||
app_dataset_join = AppDatasetJoin(
|
app_dataset_join = AppDatasetJoin(app_id=app.id, dataset_id=dataset_id)
|
||||||
app_id=app.id,
|
|
||||||
dataset_id=dataset_id
|
|
||||||
)
|
|
||||||
db.session.add(app_dataset_join)
|
db.session.add(app_dataset_join)
|
||||||
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
@ -54,18 +48,19 @@ def get_dataset_ids_from_workflow(published_workflow: Workflow) -> set:
|
||||||
if not graph:
|
if not graph:
|
||||||
return dataset_ids
|
return dataset_ids
|
||||||
|
|
||||||
nodes = graph.get('nodes', [])
|
nodes = graph.get("nodes", [])
|
||||||
|
|
||||||
# fetch all knowledge retrieval nodes
|
# fetch all knowledge retrieval nodes
|
||||||
knowledge_retrieval_nodes = [node for node in nodes
|
knowledge_retrieval_nodes = [
|
||||||
if node.get('data', {}).get('type') == NodeType.KNOWLEDGE_RETRIEVAL.value]
|
node for node in nodes if node.get("data", {}).get("type") == NodeType.KNOWLEDGE_RETRIEVAL.value
|
||||||
|
]
|
||||||
|
|
||||||
if not knowledge_retrieval_nodes:
|
if not knowledge_retrieval_nodes:
|
||||||
return dataset_ids
|
return dataset_ids
|
||||||
|
|
||||||
for node in knowledge_retrieval_nodes:
|
for node in knowledge_retrieval_nodes:
|
||||||
try:
|
try:
|
||||||
node_data = KnowledgeRetrievalNodeData(**node.get('data', {}))
|
node_data = KnowledgeRetrievalNodeData(**node.get("data", {}))
|
||||||
dataset_ids.update(node_data.dataset_ids)
|
dataset_ids.update(node_data.dataset_ids)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -9,13 +9,13 @@ from models.provider import Provider
|
||||||
@message_was_created.connect
|
@message_was_created.connect
|
||||||
def handle(sender, **kwargs):
|
def handle(sender, **kwargs):
|
||||||
message = sender
|
message = sender
|
||||||
application_generate_entity = kwargs.get('application_generate_entity')
|
application_generate_entity = kwargs.get("application_generate_entity")
|
||||||
|
|
||||||
if not isinstance(application_generate_entity, ChatAppGenerateEntity | AgentChatAppGenerateEntity):
|
if not isinstance(application_generate_entity, ChatAppGenerateEntity | AgentChatAppGenerateEntity):
|
||||||
return
|
return
|
||||||
|
|
||||||
db.session.query(Provider).filter(
|
db.session.query(Provider).filter(
|
||||||
Provider.tenant_id == application_generate_entity.app_config.tenant_id,
|
Provider.tenant_id == application_generate_entity.app_config.tenant_id,
|
||||||
Provider.provider_name == application_generate_entity.model_conf.provider
|
Provider.provider_name == application_generate_entity.model_conf.provider,
|
||||||
).update({'last_used': datetime.now(timezone.utc).replace(tzinfo=None)})
|
).update({"last_used": datetime.now(timezone.utc).replace(tzinfo=None)})
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from blinker import signal
|
from blinker import signal
|
||||||
|
|
||||||
# sender: message, kwargs: conversation
|
# sender: message, kwargs: conversation
|
||||||
message_was_created = signal('message-was-created')
|
message_was_created = signal("message-was-created")
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from blinker import signal
|
from blinker import signal
|
||||||
|
|
||||||
# sender: tenant
|
# sender: tenant
|
||||||
tenant_was_created = signal('tenant-was-created')
|
tenant_was_created = signal("tenant-was-created")
|
||||||
|
|
||||||
# sender: tenant
|
# sender: tenant
|
||||||
tenant_was_updated = signal('tenant-was-updated')
|
tenant_was_updated = signal("tenant-was-updated")
|
||||||
|
|
|
@ -45,18 +45,15 @@ def init_app(app: Flask) -> Celery:
|
||||||
]
|
]
|
||||||
day = app.config["CELERY_BEAT_SCHEDULER_TIME"]
|
day = app.config["CELERY_BEAT_SCHEDULER_TIME"]
|
||||||
beat_schedule = {
|
beat_schedule = {
|
||||||
'clean_embedding_cache_task': {
|
"clean_embedding_cache_task": {
|
||||||
'task': 'schedule.clean_embedding_cache_task.clean_embedding_cache_task',
|
"task": "schedule.clean_embedding_cache_task.clean_embedding_cache_task",
|
||||||
'schedule': timedelta(days=day),
|
"schedule": timedelta(days=day),
|
||||||
|
},
|
||||||
|
"clean_unused_datasets_task": {
|
||||||
|
"task": "schedule.clean_unused_datasets_task.clean_unused_datasets_task",
|
||||||
|
"schedule": timedelta(days=day),
|
||||||
},
|
},
|
||||||
'clean_unused_datasets_task': {
|
|
||||||
'task': 'schedule.clean_unused_datasets_task.clean_unused_datasets_task',
|
|
||||||
'schedule': timedelta(days=day),
|
|
||||||
}
|
}
|
||||||
}
|
celery_app.conf.update(beat_schedule=beat_schedule, imports=imports)
|
||||||
celery_app.conf.update(
|
|
||||||
beat_schedule=beat_schedule,
|
|
||||||
imports=imports
|
|
||||||
)
|
|
||||||
|
|
||||||
return celery_app
|
return celery_app
|
||||||
|
|
|
@ -2,15 +2,14 @@ from flask import Flask
|
||||||
|
|
||||||
|
|
||||||
def init_app(app: Flask):
|
def init_app(app: Flask):
|
||||||
if app.config.get('API_COMPRESSION_ENABLED'):
|
if app.config.get("API_COMPRESSION_ENABLED"):
|
||||||
from flask_compress import Compress
|
from flask_compress import Compress
|
||||||
|
|
||||||
app.config['COMPRESS_MIMETYPES'] = [
|
app.config["COMPRESS_MIMETYPES"] = [
|
||||||
'application/json',
|
"application/json",
|
||||||
'image/svg+xml',
|
"image/svg+xml",
|
||||||
'text/html',
|
"text/html",
|
||||||
]
|
]
|
||||||
|
|
||||||
compress = Compress()
|
compress = Compress()
|
||||||
compress.init_app(app)
|
compress.init_app(app)
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,11 @@ from flask_sqlalchemy import SQLAlchemy
|
||||||
from sqlalchemy import MetaData
|
from sqlalchemy import MetaData
|
||||||
|
|
||||||
POSTGRES_INDEXES_NAMING_CONVENTION = {
|
POSTGRES_INDEXES_NAMING_CONVENTION = {
|
||||||
'ix': '%(column_0_label)s_idx',
|
"ix": "%(column_0_label)s_idx",
|
||||||
'uq': '%(table_name)s_%(column_0_name)s_key',
|
"uq": "%(table_name)s_%(column_0_name)s_key",
|
||||||
'ck': '%(table_name)s_%(constraint_name)s_check',
|
"ck": "%(table_name)s_%(constraint_name)s_check",
|
||||||
'fk': '%(table_name)s_%(column_0_name)s_fkey',
|
"fk": "%(table_name)s_%(column_0_name)s_fkey",
|
||||||
'pk': '%(table_name)s_pkey',
|
"pk": "%(table_name)s_pkey",
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata = MetaData(naming_convention=POSTGRES_INDEXES_NAMING_CONVENTION)
|
metadata = MetaData(naming_convention=POSTGRES_INDEXES_NAMING_CONVENTION)
|
||||||
|
|
|
@ -14,67 +14,69 @@ class Mail:
|
||||||
return self._client is not None
|
return self._client is not None
|
||||||
|
|
||||||
def init_app(self, app: Flask):
|
def init_app(self, app: Flask):
|
||||||
if app.config.get('MAIL_TYPE'):
|
if app.config.get("MAIL_TYPE"):
|
||||||
if app.config.get('MAIL_DEFAULT_SEND_FROM'):
|
if app.config.get("MAIL_DEFAULT_SEND_FROM"):
|
||||||
self._default_send_from = app.config.get('MAIL_DEFAULT_SEND_FROM')
|
self._default_send_from = app.config.get("MAIL_DEFAULT_SEND_FROM")
|
||||||
|
|
||||||
if app.config.get('MAIL_TYPE') == 'resend':
|
if app.config.get("MAIL_TYPE") == "resend":
|
||||||
api_key = app.config.get('RESEND_API_KEY')
|
api_key = app.config.get("RESEND_API_KEY")
|
||||||
if not api_key:
|
if not api_key:
|
||||||
raise ValueError('RESEND_API_KEY is not set')
|
raise ValueError("RESEND_API_KEY is not set")
|
||||||
|
|
||||||
api_url = app.config.get('RESEND_API_URL')
|
api_url = app.config.get("RESEND_API_URL")
|
||||||
if api_url:
|
if api_url:
|
||||||
resend.api_url = api_url
|
resend.api_url = api_url
|
||||||
|
|
||||||
resend.api_key = api_key
|
resend.api_key = api_key
|
||||||
self._client = resend.Emails
|
self._client = resend.Emails
|
||||||
elif app.config.get('MAIL_TYPE') == 'smtp':
|
elif app.config.get("MAIL_TYPE") == "smtp":
|
||||||
from libs.smtp import SMTPClient
|
from libs.smtp import SMTPClient
|
||||||
if not app.config.get('SMTP_SERVER') or not app.config.get('SMTP_PORT'):
|
|
||||||
raise ValueError('SMTP_SERVER and SMTP_PORT are required for smtp mail type')
|
if not app.config.get("SMTP_SERVER") or not app.config.get("SMTP_PORT"):
|
||||||
if not app.config.get('SMTP_USE_TLS') and app.config.get('SMTP_OPPORTUNISTIC_TLS'):
|
raise ValueError("SMTP_SERVER and SMTP_PORT are required for smtp mail type")
|
||||||
raise ValueError('SMTP_OPPORTUNISTIC_TLS is not supported without enabling SMTP_USE_TLS')
|
if not app.config.get("SMTP_USE_TLS") and app.config.get("SMTP_OPPORTUNISTIC_TLS"):
|
||||||
|
raise ValueError("SMTP_OPPORTUNISTIC_TLS is not supported without enabling SMTP_USE_TLS")
|
||||||
self._client = SMTPClient(
|
self._client = SMTPClient(
|
||||||
server=app.config.get('SMTP_SERVER'),
|
server=app.config.get("SMTP_SERVER"),
|
||||||
port=app.config.get('SMTP_PORT'),
|
port=app.config.get("SMTP_PORT"),
|
||||||
username=app.config.get('SMTP_USERNAME'),
|
username=app.config.get("SMTP_USERNAME"),
|
||||||
password=app.config.get('SMTP_PASSWORD'),
|
password=app.config.get("SMTP_PASSWORD"),
|
||||||
_from=app.config.get('MAIL_DEFAULT_SEND_FROM'),
|
_from=app.config.get("MAIL_DEFAULT_SEND_FROM"),
|
||||||
use_tls=app.config.get('SMTP_USE_TLS'),
|
use_tls=app.config.get("SMTP_USE_TLS"),
|
||||||
opportunistic_tls=app.config.get('SMTP_OPPORTUNISTIC_TLS')
|
opportunistic_tls=app.config.get("SMTP_OPPORTUNISTIC_TLS"),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise ValueError('Unsupported mail type {}'.format(app.config.get('MAIL_TYPE')))
|
raise ValueError("Unsupported mail type {}".format(app.config.get("MAIL_TYPE")))
|
||||||
else:
|
else:
|
||||||
logging.warning('MAIL_TYPE is not set')
|
logging.warning("MAIL_TYPE is not set")
|
||||||
|
|
||||||
|
|
||||||
def send(self, to: str, subject: str, html: str, from_: Optional[str] = None):
|
def send(self, to: str, subject: str, html: str, from_: Optional[str] = None):
|
||||||
if not self._client:
|
if not self._client:
|
||||||
raise ValueError('Mail client is not initialized')
|
raise ValueError("Mail client is not initialized")
|
||||||
|
|
||||||
if not from_ and self._default_send_from:
|
if not from_ and self._default_send_from:
|
||||||
from_ = self._default_send_from
|
from_ = self._default_send_from
|
||||||
|
|
||||||
if not from_:
|
if not from_:
|
||||||
raise ValueError('mail from is not set')
|
raise ValueError("mail from is not set")
|
||||||
|
|
||||||
if not to:
|
if not to:
|
||||||
raise ValueError('mail to is not set')
|
raise ValueError("mail to is not set")
|
||||||
|
|
||||||
if not subject:
|
if not subject:
|
||||||
raise ValueError('mail subject is not set')
|
raise ValueError("mail subject is not set")
|
||||||
|
|
||||||
if not html:
|
if not html:
|
||||||
raise ValueError('mail html is not set')
|
raise ValueError("mail html is not set")
|
||||||
|
|
||||||
self._client.send({
|
self._client.send(
|
||||||
|
{
|
||||||
"from": from_,
|
"from": from_,
|
||||||
"to": to,
|
"to": to,
|
||||||
"subject": subject,
|
"subject": subject,
|
||||||
"html": html
|
"html": html,
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def init_app(app: Flask):
|
def init_app(app: Flask):
|
||||||
|
|
|
@ -6,18 +6,21 @@ redis_client = redis.Redis()
|
||||||
|
|
||||||
def init_app(app):
|
def init_app(app):
|
||||||
connection_class = Connection
|
connection_class = Connection
|
||||||
if app.config.get('REDIS_USE_SSL'):
|
if app.config.get("REDIS_USE_SSL"):
|
||||||
connection_class = SSLConnection
|
connection_class = SSLConnection
|
||||||
|
|
||||||
redis_client.connection_pool = redis.ConnectionPool(**{
|
redis_client.connection_pool = redis.ConnectionPool(
|
||||||
'host': app.config.get('REDIS_HOST'),
|
**{
|
||||||
'port': app.config.get('REDIS_PORT'),
|
"host": app.config.get("REDIS_HOST"),
|
||||||
'username': app.config.get('REDIS_USERNAME'),
|
"port": app.config.get("REDIS_PORT"),
|
||||||
'password': app.config.get('REDIS_PASSWORD'),
|
"username": app.config.get("REDIS_USERNAME"),
|
||||||
'db': app.config.get('REDIS_DB'),
|
"password": app.config.get("REDIS_PASSWORD"),
|
||||||
'encoding': 'utf-8',
|
"db": app.config.get("REDIS_DB"),
|
||||||
'encoding_errors': 'strict',
|
"encoding": "utf-8",
|
||||||
'decode_responses': False
|
"encoding_errors": "strict",
|
||||||
}, connection_class=connection_class)
|
"decode_responses": False,
|
||||||
|
},
|
||||||
|
connection_class=connection_class,
|
||||||
|
)
|
||||||
|
|
||||||
app.extensions['redis'] = redis_client
|
app.extensions["redis"] = redis_client
|
||||||
|
|
|
@ -5,16 +5,13 @@ from werkzeug.exceptions import HTTPException
|
||||||
|
|
||||||
|
|
||||||
def init_app(app):
|
def init_app(app):
|
||||||
if app.config.get('SENTRY_DSN'):
|
if app.config.get("SENTRY_DSN"):
|
||||||
sentry_sdk.init(
|
sentry_sdk.init(
|
||||||
dsn=app.config.get('SENTRY_DSN'),
|
dsn=app.config.get("SENTRY_DSN"),
|
||||||
integrations=[
|
integrations=[FlaskIntegration(), CeleryIntegration()],
|
||||||
FlaskIntegration(),
|
|
||||||
CeleryIntegration()
|
|
||||||
],
|
|
||||||
ignore_errors=[HTTPException, ValueError],
|
ignore_errors=[HTTPException, ValueError],
|
||||||
traces_sample_rate=app.config.get('SENTRY_TRACES_SAMPLE_RATE', 1.0),
|
traces_sample_rate=app.config.get("SENTRY_TRACES_SAMPLE_RATE", 1.0),
|
||||||
profiles_sample_rate=app.config.get('SENTRY_PROFILES_SAMPLE_RATE', 1.0),
|
profiles_sample_rate=app.config.get("SENTRY_PROFILES_SAMPLE_RATE", 1.0),
|
||||||
environment=app.config.get('DEPLOY_ENV'),
|
environment=app.config.get("DEPLOY_ENV"),
|
||||||
release=f"dify-{app.config.get('CURRENT_VERSION')}-{app.config.get('COMMIT_SHA')}"
|
release=f"dify-{app.config.get('CURRENT_VERSION')}-{app.config.get('COMMIT_SHA')}",
|
||||||
)
|
)
|
||||||
|
|
|
@ -17,31 +17,19 @@ class Storage:
|
||||||
self.storage_runner = None
|
self.storage_runner = None
|
||||||
|
|
||||||
def init_app(self, app: Flask):
|
def init_app(self, app: Flask):
|
||||||
storage_type = app.config.get('STORAGE_TYPE')
|
storage_type = app.config.get("STORAGE_TYPE")
|
||||||
if storage_type == 's3':
|
if storage_type == "s3":
|
||||||
self.storage_runner = S3Storage(
|
self.storage_runner = S3Storage(app=app)
|
||||||
app=app
|
elif storage_type == "azure-blob":
|
||||||
)
|
self.storage_runner = AzureStorage(app=app)
|
||||||
elif storage_type == 'azure-blob':
|
elif storage_type == "aliyun-oss":
|
||||||
self.storage_runner = AzureStorage(
|
self.storage_runner = AliyunStorage(app=app)
|
||||||
app=app
|
elif storage_type == "google-storage":
|
||||||
)
|
self.storage_runner = GoogleStorage(app=app)
|
||||||
elif storage_type == 'aliyun-oss':
|
elif storage_type == "tencent-cos":
|
||||||
self.storage_runner = AliyunStorage(
|
self.storage_runner = TencentStorage(app=app)
|
||||||
app=app
|
elif storage_type == "oci-storage":
|
||||||
)
|
self.storage_runner = OCIStorage(app=app)
|
||||||
elif storage_type == 'google-storage':
|
|
||||||
self.storage_runner = GoogleStorage(
|
|
||||||
app=app
|
|
||||||
)
|
|
||||||
elif storage_type == 'tencent-cos':
|
|
||||||
self.storage_runner = TencentStorage(
|
|
||||||
app=app
|
|
||||||
)
|
|
||||||
elif storage_type == 'oci-storage':
|
|
||||||
self.storage_runner = OCIStorage(
|
|
||||||
app=app
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
self.storage_runner = LocalStorage(app=app)
|
self.storage_runner = LocalStorage(app=app)
|
||||||
|
|
||||||
|
|
|
@ -8,23 +8,22 @@ from extensions.storage.base_storage import BaseStorage
|
||||||
|
|
||||||
|
|
||||||
class AliyunStorage(BaseStorage):
|
class AliyunStorage(BaseStorage):
|
||||||
"""Implementation for aliyun storage.
|
"""Implementation for aliyun storage."""
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, app: Flask):
|
def __init__(self, app: Flask):
|
||||||
super().__init__(app)
|
super().__init__(app)
|
||||||
|
|
||||||
app_config = self.app.config
|
app_config = self.app.config
|
||||||
self.bucket_name = app_config.get('ALIYUN_OSS_BUCKET_NAME')
|
self.bucket_name = app_config.get("ALIYUN_OSS_BUCKET_NAME")
|
||||||
oss_auth_method = aliyun_s3.Auth
|
oss_auth_method = aliyun_s3.Auth
|
||||||
region = None
|
region = None
|
||||||
if app_config.get('ALIYUN_OSS_AUTH_VERSION') == 'v4':
|
if app_config.get("ALIYUN_OSS_AUTH_VERSION") == "v4":
|
||||||
oss_auth_method = aliyun_s3.AuthV4
|
oss_auth_method = aliyun_s3.AuthV4
|
||||||
region = app_config.get('ALIYUN_OSS_REGION')
|
region = app_config.get("ALIYUN_OSS_REGION")
|
||||||
oss_auth = oss_auth_method(app_config.get('ALIYUN_OSS_ACCESS_KEY'), app_config.get('ALIYUN_OSS_SECRET_KEY'))
|
oss_auth = oss_auth_method(app_config.get("ALIYUN_OSS_ACCESS_KEY"), app_config.get("ALIYUN_OSS_SECRET_KEY"))
|
||||||
self.client = aliyun_s3.Bucket(
|
self.client = aliyun_s3.Bucket(
|
||||||
oss_auth,
|
oss_auth,
|
||||||
app_config.get('ALIYUN_OSS_ENDPOINT'),
|
app_config.get("ALIYUN_OSS_ENDPOINT"),
|
||||||
self.bucket_name,
|
self.bucket_name,
|
||||||
connect_timeout=30,
|
connect_timeout=30,
|
||||||
region=region,
|
region=region,
|
||||||
|
|
|
@ -9,16 +9,15 @@ from extensions.storage.base_storage import BaseStorage
|
||||||
|
|
||||||
|
|
||||||
class AzureStorage(BaseStorage):
|
class AzureStorage(BaseStorage):
|
||||||
"""Implementation for azure storage.
|
"""Implementation for azure storage."""
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, app: Flask):
|
def __init__(self, app: Flask):
|
||||||
super().__init__(app)
|
super().__init__(app)
|
||||||
app_config = self.app.config
|
app_config = self.app.config
|
||||||
self.bucket_name = app_config.get('AZURE_BLOB_CONTAINER_NAME')
|
self.bucket_name = app_config.get("AZURE_BLOB_CONTAINER_NAME")
|
||||||
self.account_url = app_config.get('AZURE_BLOB_ACCOUNT_URL')
|
self.account_url = app_config.get("AZURE_BLOB_ACCOUNT_URL")
|
||||||
self.account_name = app_config.get('AZURE_BLOB_ACCOUNT_NAME')
|
self.account_name = app_config.get("AZURE_BLOB_ACCOUNT_NAME")
|
||||||
self.account_key = app_config.get('AZURE_BLOB_ACCOUNT_KEY')
|
self.account_key = app_config.get("AZURE_BLOB_ACCOUNT_KEY")
|
||||||
|
|
||||||
def save(self, filename, data):
|
def save(self, filename, data):
|
||||||
client = self._sync_client()
|
client = self._sync_client()
|
||||||
|
@ -39,6 +38,7 @@ class AzureStorage(BaseStorage):
|
||||||
blob = client.get_blob_client(container=self.bucket_name, blob=filename)
|
blob = client.get_blob_client(container=self.bucket_name, blob=filename)
|
||||||
blob_data = blob.download_blob()
|
blob_data = blob.download_blob()
|
||||||
yield from blob_data.chunks()
|
yield from blob_data.chunks()
|
||||||
|
|
||||||
return generate(filename)
|
return generate(filename)
|
||||||
|
|
||||||
def download(self, filename, target_filepath):
|
def download(self, filename, target_filepath):
|
||||||
|
@ -62,17 +62,17 @@ class AzureStorage(BaseStorage):
|
||||||
blob_container.delete_blob(filename)
|
blob_container.delete_blob(filename)
|
||||||
|
|
||||||
def _sync_client(self):
|
def _sync_client(self):
|
||||||
cache_key = 'azure_blob_sas_token_{}_{}'.format(self.account_name, self.account_key)
|
cache_key = "azure_blob_sas_token_{}_{}".format(self.account_name, self.account_key)
|
||||||
cache_result = redis_client.get(cache_key)
|
cache_result = redis_client.get(cache_key)
|
||||||
if cache_result is not None:
|
if cache_result is not None:
|
||||||
sas_token = cache_result.decode('utf-8')
|
sas_token = cache_result.decode("utf-8")
|
||||||
else:
|
else:
|
||||||
sas_token = generate_account_sas(
|
sas_token = generate_account_sas(
|
||||||
account_name=self.account_name,
|
account_name=self.account_name,
|
||||||
account_key=self.account_key,
|
account_key=self.account_key,
|
||||||
resource_types=ResourceTypes(service=True, container=True, object=True),
|
resource_types=ResourceTypes(service=True, container=True, object=True),
|
||||||
permission=AccountSasPermissions(read=True, write=True, delete=True, list=True, add=True, create=True),
|
permission=AccountSasPermissions(read=True, write=True, delete=True, list=True, add=True, create=True),
|
||||||
expiry=datetime.now(timezone.utc).replace(tzinfo=None) + timedelta(hours=1)
|
expiry=datetime.now(timezone.utc).replace(tzinfo=None) + timedelta(hours=1),
|
||||||
)
|
)
|
||||||
redis_client.set(cache_key, sas_token, ex=3000)
|
redis_client.set(cache_key, sas_token, ex=3000)
|
||||||
return BlobServiceClient(account_url=self.account_url, credential=sas_token)
|
return BlobServiceClient(account_url=self.account_url, credential=sas_token)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"""Abstract interface for file storage implementations."""
|
"""Abstract interface for file storage implementations."""
|
||||||
|
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from collections.abc import Generator
|
from collections.abc import Generator
|
||||||
|
|
||||||
|
@ -6,8 +7,8 @@ from flask import Flask
|
||||||
|
|
||||||
|
|
||||||
class BaseStorage(ABC):
|
class BaseStorage(ABC):
|
||||||
"""Interface for file storage.
|
"""Interface for file storage."""
|
||||||
"""
|
|
||||||
app = None
|
app = None
|
||||||
|
|
||||||
def __init__(self, app: Flask):
|
def __init__(self, app: Flask):
|
||||||
|
|
|
@ -11,16 +11,16 @@ from extensions.storage.base_storage import BaseStorage
|
||||||
|
|
||||||
|
|
||||||
class GoogleStorage(BaseStorage):
|
class GoogleStorage(BaseStorage):
|
||||||
"""Implementation for google storage.
|
"""Implementation for google storage."""
|
||||||
"""
|
|
||||||
def __init__(self, app: Flask):
|
def __init__(self, app: Flask):
|
||||||
super().__init__(app)
|
super().__init__(app)
|
||||||
app_config = self.app.config
|
app_config = self.app.config
|
||||||
self.bucket_name = app_config.get('GOOGLE_STORAGE_BUCKET_NAME')
|
self.bucket_name = app_config.get("GOOGLE_STORAGE_BUCKET_NAME")
|
||||||
service_account_json_str = app_config.get('GOOGLE_STORAGE_SERVICE_ACCOUNT_JSON_BASE64')
|
service_account_json_str = app_config.get("GOOGLE_STORAGE_SERVICE_ACCOUNT_JSON_BASE64")
|
||||||
# if service_account_json_str is empty, use Application Default Credentials
|
# if service_account_json_str is empty, use Application Default Credentials
|
||||||
if service_account_json_str:
|
if service_account_json_str:
|
||||||
service_account_json = base64.b64decode(service_account_json_str).decode('utf-8')
|
service_account_json = base64.b64decode(service_account_json_str).decode("utf-8")
|
||||||
# convert str to object
|
# convert str to object
|
||||||
service_account_obj = json.loads(service_account_json)
|
service_account_obj = json.loads(service_account_json)
|
||||||
self.client = GoogleCloudStorage.Client.from_service_account_info(service_account_obj)
|
self.client = GoogleCloudStorage.Client.from_service_account_info(service_account_obj)
|
||||||
|
@ -43,9 +43,10 @@ class GoogleStorage(BaseStorage):
|
||||||
def generate(filename: str = filename) -> Generator:
|
def generate(filename: str = filename) -> Generator:
|
||||||
bucket = self.client.get_bucket(self.bucket_name)
|
bucket = self.client.get_bucket(self.bucket_name)
|
||||||
blob = bucket.get_blob(filename)
|
blob = bucket.get_blob(filename)
|
||||||
with closing(blob.open(mode='rb')) as blob_stream:
|
with closing(blob.open(mode="rb")) as blob_stream:
|
||||||
while chunk := blob_stream.read(4096):
|
while chunk := blob_stream.read(4096):
|
||||||
yield chunk
|
yield chunk
|
||||||
|
|
||||||
return generate()
|
return generate()
|
||||||
|
|
||||||
def download(self, filename, target_filepath):
|
def download(self, filename, target_filepath):
|
||||||
|
|
|
@ -8,21 +8,20 @@ from extensions.storage.base_storage import BaseStorage
|
||||||
|
|
||||||
|
|
||||||
class LocalStorage(BaseStorage):
|
class LocalStorage(BaseStorage):
|
||||||
"""Implementation for local storage.
|
"""Implementation for local storage."""
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, app: Flask):
|
def __init__(self, app: Flask):
|
||||||
super().__init__(app)
|
super().__init__(app)
|
||||||
folder = self.app.config.get('STORAGE_LOCAL_PATH')
|
folder = self.app.config.get("STORAGE_LOCAL_PATH")
|
||||||
if not os.path.isabs(folder):
|
if not os.path.isabs(folder):
|
||||||
folder = os.path.join(app.root_path, folder)
|
folder = os.path.join(app.root_path, folder)
|
||||||
self.folder = folder
|
self.folder = folder
|
||||||
|
|
||||||
def save(self, filename, data):
|
def save(self, filename, data):
|
||||||
if not self.folder or self.folder.endswith('/'):
|
if not self.folder or self.folder.endswith("/"):
|
||||||
filename = self.folder + filename
|
filename = self.folder + filename
|
||||||
else:
|
else:
|
||||||
filename = self.folder + '/' + filename
|
filename = self.folder + "/" + filename
|
||||||
|
|
||||||
folder = os.path.dirname(filename)
|
folder = os.path.dirname(filename)
|
||||||
os.makedirs(folder, exist_ok=True)
|
os.makedirs(folder, exist_ok=True)
|
||||||
|
@ -31,10 +30,10 @@ class LocalStorage(BaseStorage):
|
||||||
f.write(data)
|
f.write(data)
|
||||||
|
|
||||||
def load_once(self, filename: str) -> bytes:
|
def load_once(self, filename: str) -> bytes:
|
||||||
if not self.folder or self.folder.endswith('/'):
|
if not self.folder or self.folder.endswith("/"):
|
||||||
filename = self.folder + filename
|
filename = self.folder + filename
|
||||||
else:
|
else:
|
||||||
filename = self.folder + '/' + filename
|
filename = self.folder + "/" + filename
|
||||||
|
|
||||||
if not os.path.exists(filename):
|
if not os.path.exists(filename):
|
||||||
raise FileNotFoundError("File not found")
|
raise FileNotFoundError("File not found")
|
||||||
|
@ -46,10 +45,10 @@ class LocalStorage(BaseStorage):
|
||||||
|
|
||||||
def load_stream(self, filename: str) -> Generator:
|
def load_stream(self, filename: str) -> Generator:
|
||||||
def generate(filename: str = filename) -> Generator:
|
def generate(filename: str = filename) -> Generator:
|
||||||
if not self.folder or self.folder.endswith('/'):
|
if not self.folder or self.folder.endswith("/"):
|
||||||
filename = self.folder + filename
|
filename = self.folder + filename
|
||||||
else:
|
else:
|
||||||
filename = self.folder + '/' + filename
|
filename = self.folder + "/" + filename
|
||||||
|
|
||||||
if not os.path.exists(filename):
|
if not os.path.exists(filename):
|
||||||
raise FileNotFoundError("File not found")
|
raise FileNotFoundError("File not found")
|
||||||
|
@ -61,10 +60,10 @@ class LocalStorage(BaseStorage):
|
||||||
return generate()
|
return generate()
|
||||||
|
|
||||||
def download(self, filename, target_filepath):
|
def download(self, filename, target_filepath):
|
||||||
if not self.folder or self.folder.endswith('/'):
|
if not self.folder or self.folder.endswith("/"):
|
||||||
filename = self.folder + filename
|
filename = self.folder + filename
|
||||||
else:
|
else:
|
||||||
filename = self.folder + '/' + filename
|
filename = self.folder + "/" + filename
|
||||||
|
|
||||||
if not os.path.exists(filename):
|
if not os.path.exists(filename):
|
||||||
raise FileNotFoundError("File not found")
|
raise FileNotFoundError("File not found")
|
||||||
|
@ -72,17 +71,17 @@ class LocalStorage(BaseStorage):
|
||||||
shutil.copyfile(filename, target_filepath)
|
shutil.copyfile(filename, target_filepath)
|
||||||
|
|
||||||
def exists(self, filename):
|
def exists(self, filename):
|
||||||
if not self.folder or self.folder.endswith('/'):
|
if not self.folder or self.folder.endswith("/"):
|
||||||
filename = self.folder + filename
|
filename = self.folder + filename
|
||||||
else:
|
else:
|
||||||
filename = self.folder + '/' + filename
|
filename = self.folder + "/" + filename
|
||||||
|
|
||||||
return os.path.exists(filename)
|
return os.path.exists(filename)
|
||||||
|
|
||||||
def delete(self, filename):
|
def delete(self, filename):
|
||||||
if not self.folder or self.folder.endswith('/'):
|
if not self.folder or self.folder.endswith("/"):
|
||||||
filename = self.folder + filename
|
filename = self.folder + filename
|
||||||
else:
|
else:
|
||||||
filename = self.folder + '/' + filename
|
filename = self.folder + "/" + filename
|
||||||
if os.path.exists(filename):
|
if os.path.exists(filename):
|
||||||
os.remove(filename)
|
os.remove(filename)
|
||||||
|
|
|
@ -12,13 +12,13 @@ class OCIStorage(BaseStorage):
|
||||||
def __init__(self, app: Flask):
|
def __init__(self, app: Flask):
|
||||||
super().__init__(app)
|
super().__init__(app)
|
||||||
app_config = self.app.config
|
app_config = self.app.config
|
||||||
self.bucket_name = app_config.get('OCI_BUCKET_NAME')
|
self.bucket_name = app_config.get("OCI_BUCKET_NAME")
|
||||||
self.client = boto3.client(
|
self.client = boto3.client(
|
||||||
's3',
|
"s3",
|
||||||
aws_secret_access_key=app_config.get('OCI_SECRET_KEY'),
|
aws_secret_access_key=app_config.get("OCI_SECRET_KEY"),
|
||||||
aws_access_key_id=app_config.get('OCI_ACCESS_KEY'),
|
aws_access_key_id=app_config.get("OCI_ACCESS_KEY"),
|
||||||
endpoint_url=app_config.get('OCI_ENDPOINT'),
|
endpoint_url=app_config.get("OCI_ENDPOINT"),
|
||||||
region_name=app_config.get('OCI_REGION')
|
region_name=app_config.get("OCI_REGION"),
|
||||||
)
|
)
|
||||||
|
|
||||||
def save(self, filename, data):
|
def save(self, filename, data):
|
||||||
|
@ -27,9 +27,9 @@ class OCIStorage(BaseStorage):
|
||||||
def load_once(self, filename: str) -> bytes:
|
def load_once(self, filename: str) -> bytes:
|
||||||
try:
|
try:
|
||||||
with closing(self.client) as client:
|
with closing(self.client) as client:
|
||||||
data = client.get_object(Bucket=self.bucket_name, Key=filename)['Body'].read()
|
data = client.get_object(Bucket=self.bucket_name, Key=filename)["Body"].read()
|
||||||
except ClientError as ex:
|
except ClientError as ex:
|
||||||
if ex.response['Error']['Code'] == 'NoSuchKey':
|
if ex.response["Error"]["Code"] == "NoSuchKey":
|
||||||
raise FileNotFoundError("File not found")
|
raise FileNotFoundError("File not found")
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
@ -40,12 +40,13 @@ class OCIStorage(BaseStorage):
|
||||||
try:
|
try:
|
||||||
with closing(self.client) as client:
|
with closing(self.client) as client:
|
||||||
response = client.get_object(Bucket=self.bucket_name, Key=filename)
|
response = client.get_object(Bucket=self.bucket_name, Key=filename)
|
||||||
yield from response['Body'].iter_chunks()
|
yield from response["Body"].iter_chunks()
|
||||||
except ClientError as ex:
|
except ClientError as ex:
|
||||||
if ex.response['Error']['Code'] == 'NoSuchKey':
|
if ex.response["Error"]["Code"] == "NoSuchKey":
|
||||||
raise FileNotFoundError("File not found")
|
raise FileNotFoundError("File not found")
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
return generate()
|
return generate()
|
||||||
|
|
||||||
def download(self, filename, target_filepath):
|
def download(self, filename, target_filepath):
|
||||||
|
|
|
@ -10,23 +10,23 @@ from extensions.storage.base_storage import BaseStorage
|
||||||
|
|
||||||
|
|
||||||
class S3Storage(BaseStorage):
|
class S3Storage(BaseStorage):
|
||||||
"""Implementation for s3 storage.
|
"""Implementation for s3 storage."""
|
||||||
"""
|
|
||||||
def __init__(self, app: Flask):
|
def __init__(self, app: Flask):
|
||||||
super().__init__(app)
|
super().__init__(app)
|
||||||
app_config = self.app.config
|
app_config = self.app.config
|
||||||
self.bucket_name = app_config.get('S3_BUCKET_NAME')
|
self.bucket_name = app_config.get("S3_BUCKET_NAME")
|
||||||
if app_config.get('S3_USE_AWS_MANAGED_IAM'):
|
if app_config.get("S3_USE_AWS_MANAGED_IAM"):
|
||||||
session = boto3.Session()
|
session = boto3.Session()
|
||||||
self.client = session.client('s3')
|
self.client = session.client("s3")
|
||||||
else:
|
else:
|
||||||
self.client = boto3.client(
|
self.client = boto3.client(
|
||||||
's3',
|
"s3",
|
||||||
aws_secret_access_key=app_config.get('S3_SECRET_KEY'),
|
aws_secret_access_key=app_config.get("S3_SECRET_KEY"),
|
||||||
aws_access_key_id=app_config.get('S3_ACCESS_KEY'),
|
aws_access_key_id=app_config.get("S3_ACCESS_KEY"),
|
||||||
endpoint_url=app_config.get('S3_ENDPOINT'),
|
endpoint_url=app_config.get("S3_ENDPOINT"),
|
||||||
region_name=app_config.get('S3_REGION'),
|
region_name=app_config.get("S3_REGION"),
|
||||||
config=Config(s3={'addressing_style': app_config.get('S3_ADDRESS_STYLE')})
|
config=Config(s3={"addressing_style": app_config.get("S3_ADDRESS_STYLE")}),
|
||||||
)
|
)
|
||||||
|
|
||||||
def save(self, filename, data):
|
def save(self, filename, data):
|
||||||
|
@ -35,9 +35,9 @@ class S3Storage(BaseStorage):
|
||||||
def load_once(self, filename: str) -> bytes:
|
def load_once(self, filename: str) -> bytes:
|
||||||
try:
|
try:
|
||||||
with closing(self.client) as client:
|
with closing(self.client) as client:
|
||||||
data = client.get_object(Bucket=self.bucket_name, Key=filename)['Body'].read()
|
data = client.get_object(Bucket=self.bucket_name, Key=filename)["Body"].read()
|
||||||
except ClientError as ex:
|
except ClientError as ex:
|
||||||
if ex.response['Error']['Code'] == 'NoSuchKey':
|
if ex.response["Error"]["Code"] == "NoSuchKey":
|
||||||
raise FileNotFoundError("File not found")
|
raise FileNotFoundError("File not found")
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
@ -48,12 +48,13 @@ class S3Storage(BaseStorage):
|
||||||
try:
|
try:
|
||||||
with closing(self.client) as client:
|
with closing(self.client) as client:
|
||||||
response = client.get_object(Bucket=self.bucket_name, Key=filename)
|
response = client.get_object(Bucket=self.bucket_name, Key=filename)
|
||||||
yield from response['Body'].iter_chunks()
|
yield from response["Body"].iter_chunks()
|
||||||
except ClientError as ex:
|
except ClientError as ex:
|
||||||
if ex.response['Error']['Code'] == 'NoSuchKey':
|
if ex.response["Error"]["Code"] == "NoSuchKey":
|
||||||
raise FileNotFoundError("File not found")
|
raise FileNotFoundError("File not found")
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
return generate()
|
return generate()
|
||||||
|
|
||||||
def download(self, filename, target_filepath):
|
def download(self, filename, target_filepath):
|
||||||
|
|
|
@ -7,18 +7,17 @@ from extensions.storage.base_storage import BaseStorage
|
||||||
|
|
||||||
|
|
||||||
class TencentStorage(BaseStorage):
|
class TencentStorage(BaseStorage):
|
||||||
"""Implementation for tencent cos storage.
|
"""Implementation for tencent cos storage."""
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, app: Flask):
|
def __init__(self, app: Flask):
|
||||||
super().__init__(app)
|
super().__init__(app)
|
||||||
app_config = self.app.config
|
app_config = self.app.config
|
||||||
self.bucket_name = app_config.get('TENCENT_COS_BUCKET_NAME')
|
self.bucket_name = app_config.get("TENCENT_COS_BUCKET_NAME")
|
||||||
config = CosConfig(
|
config = CosConfig(
|
||||||
Region=app_config.get('TENCENT_COS_REGION'),
|
Region=app_config.get("TENCENT_COS_REGION"),
|
||||||
SecretId=app_config.get('TENCENT_COS_SECRET_ID'),
|
SecretId=app_config.get("TENCENT_COS_SECRET_ID"),
|
||||||
SecretKey=app_config.get('TENCENT_COS_SECRET_KEY'),
|
SecretKey=app_config.get("TENCENT_COS_SECRET_KEY"),
|
||||||
Scheme=app_config.get('TENCENT_COS_SCHEME'),
|
Scheme=app_config.get("TENCENT_COS_SCHEME"),
|
||||||
)
|
)
|
||||||
self.client = CosS3Client(config)
|
self.client = CosS3Client(config)
|
||||||
|
|
||||||
|
@ -26,19 +25,19 @@ class TencentStorage(BaseStorage):
|
||||||
self.client.put_object(Bucket=self.bucket_name, Body=data, Key=filename)
|
self.client.put_object(Bucket=self.bucket_name, Body=data, Key=filename)
|
||||||
|
|
||||||
def load_once(self, filename: str) -> bytes:
|
def load_once(self, filename: str) -> bytes:
|
||||||
data = self.client.get_object(Bucket=self.bucket_name, Key=filename)['Body'].get_raw_stream().read()
|
data = self.client.get_object(Bucket=self.bucket_name, Key=filename)["Body"].get_raw_stream().read()
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def load_stream(self, filename: str) -> Generator:
|
def load_stream(self, filename: str) -> Generator:
|
||||||
def generate(filename: str = filename) -> Generator:
|
def generate(filename: str = filename) -> Generator:
|
||||||
response = self.client.get_object(Bucket=self.bucket_name, Key=filename)
|
response = self.client.get_object(Bucket=self.bucket_name, Key=filename)
|
||||||
yield from response['Body'].get_stream(chunk_size=4096)
|
yield from response["Body"].get_stream(chunk_size=4096)
|
||||||
|
|
||||||
return generate()
|
return generate()
|
||||||
|
|
||||||
def download(self, filename, target_filepath):
|
def download(self, filename, target_filepath):
|
||||||
response = self.client.get_object(Bucket=self.bucket_name, Key=filename)
|
response = self.client.get_object(Bucket=self.bucket_name, Key=filename)
|
||||||
response['Body'].get_stream_to_file(target_filepath)
|
response["Body"].get_stream_to_file(target_filepath)
|
||||||
|
|
||||||
def exists(self, filename):
|
def exists(self, filename):
|
||||||
return self.client.object_exists(Bucket=self.bucket_name, Key=filename)
|
return self.client.object_exists(Bucket=self.bucket_name, Key=filename)
|
||||||
|
|
|
@ -5,7 +5,7 @@ from libs.helper import TimestampField
|
||||||
annotation_fields = {
|
annotation_fields = {
|
||||||
"id": fields.String,
|
"id": fields.String,
|
||||||
"question": fields.String,
|
"question": fields.String,
|
||||||
"answer": fields.Raw(attribute='content'),
|
"answer": fields.Raw(attribute="content"),
|
||||||
"hit_count": fields.Integer,
|
"hit_count": fields.Integer,
|
||||||
"created_at": TimestampField,
|
"created_at": TimestampField,
|
||||||
# 'account': fields.Nested(simple_account_fields, allow_null=True)
|
# 'account': fields.Nested(simple_account_fields, allow_null=True)
|
||||||
|
@ -21,8 +21,8 @@ annotation_hit_history_fields = {
|
||||||
"score": fields.Float,
|
"score": fields.Float,
|
||||||
"question": fields.String,
|
"question": fields.String,
|
||||||
"created_at": TimestampField,
|
"created_at": TimestampField,
|
||||||
"match": fields.String(attribute='annotation_question'),
|
"match": fields.String(attribute="annotation_question"),
|
||||||
"response": fields.String(attribute='annotation_content')
|
"response": fields.String(attribute="annotation_content"),
|
||||||
}
|
}
|
||||||
|
|
||||||
annotation_hit_history_list_fields = {
|
annotation_hit_history_list_fields = {
|
||||||
|
|
|
@ -8,16 +8,16 @@ class HiddenAPIKey(fields.Raw):
|
||||||
api_key = obj.api_key
|
api_key = obj.api_key
|
||||||
# If the length of the api_key is less than 8 characters, show the first and last characters
|
# If the length of the api_key is less than 8 characters, show the first and last characters
|
||||||
if len(api_key) <= 8:
|
if len(api_key) <= 8:
|
||||||
return api_key[0] + '******' + api_key[-1]
|
return api_key[0] + "******" + api_key[-1]
|
||||||
# If the api_key is greater than 8 characters, show the first three and the last three characters
|
# If the api_key is greater than 8 characters, show the first three and the last three characters
|
||||||
else:
|
else:
|
||||||
return api_key[:3] + '******' + api_key[-3:]
|
return api_key[:3] + "******" + api_key[-3:]
|
||||||
|
|
||||||
|
|
||||||
api_based_extension_fields = {
|
api_based_extension_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'name': fields.String,
|
"name": fields.String,
|
||||||
'api_endpoint': fields.String,
|
"api_endpoint": fields.String,
|
||||||
'api_key': HiddenAPIKey,
|
"api_key": HiddenAPIKey,
|
||||||
'created_at': TimestampField
|
"created_at": TimestampField,
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,157 +3,153 @@ from flask_restful import fields
|
||||||
from libs.helper import TimestampField
|
from libs.helper import TimestampField
|
||||||
|
|
||||||
app_detail_kernel_fields = {
|
app_detail_kernel_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'name': fields.String,
|
"name": fields.String,
|
||||||
'description': fields.String,
|
"description": fields.String,
|
||||||
'mode': fields.String(attribute='mode_compatible_with_agent'),
|
"mode": fields.String(attribute="mode_compatible_with_agent"),
|
||||||
'icon': fields.String,
|
"icon": fields.String,
|
||||||
'icon_background': fields.String,
|
"icon_background": fields.String,
|
||||||
}
|
}
|
||||||
|
|
||||||
related_app_list = {
|
related_app_list = {
|
||||||
'data': fields.List(fields.Nested(app_detail_kernel_fields)),
|
"data": fields.List(fields.Nested(app_detail_kernel_fields)),
|
||||||
'total': fields.Integer,
|
"total": fields.Integer,
|
||||||
}
|
}
|
||||||
|
|
||||||
model_config_fields = {
|
model_config_fields = {
|
||||||
'opening_statement': fields.String,
|
"opening_statement": fields.String,
|
||||||
'suggested_questions': fields.Raw(attribute='suggested_questions_list'),
|
"suggested_questions": fields.Raw(attribute="suggested_questions_list"),
|
||||||
'suggested_questions_after_answer': fields.Raw(attribute='suggested_questions_after_answer_dict'),
|
"suggested_questions_after_answer": fields.Raw(attribute="suggested_questions_after_answer_dict"),
|
||||||
'speech_to_text': fields.Raw(attribute='speech_to_text_dict'),
|
"speech_to_text": fields.Raw(attribute="speech_to_text_dict"),
|
||||||
'text_to_speech': fields.Raw(attribute='text_to_speech_dict'),
|
"text_to_speech": fields.Raw(attribute="text_to_speech_dict"),
|
||||||
'retriever_resource': fields.Raw(attribute='retriever_resource_dict'),
|
"retriever_resource": fields.Raw(attribute="retriever_resource_dict"),
|
||||||
'annotation_reply': fields.Raw(attribute='annotation_reply_dict'),
|
"annotation_reply": fields.Raw(attribute="annotation_reply_dict"),
|
||||||
'more_like_this': fields.Raw(attribute='more_like_this_dict'),
|
"more_like_this": fields.Raw(attribute="more_like_this_dict"),
|
||||||
'sensitive_word_avoidance': fields.Raw(attribute='sensitive_word_avoidance_dict'),
|
"sensitive_word_avoidance": fields.Raw(attribute="sensitive_word_avoidance_dict"),
|
||||||
'external_data_tools': fields.Raw(attribute='external_data_tools_list'),
|
"external_data_tools": fields.Raw(attribute="external_data_tools_list"),
|
||||||
'model': fields.Raw(attribute='model_dict'),
|
"model": fields.Raw(attribute="model_dict"),
|
||||||
'user_input_form': fields.Raw(attribute='user_input_form_list'),
|
"user_input_form": fields.Raw(attribute="user_input_form_list"),
|
||||||
'dataset_query_variable': fields.String,
|
"dataset_query_variable": fields.String,
|
||||||
'pre_prompt': fields.String,
|
"pre_prompt": fields.String,
|
||||||
'agent_mode': fields.Raw(attribute='agent_mode_dict'),
|
"agent_mode": fields.Raw(attribute="agent_mode_dict"),
|
||||||
'prompt_type': fields.String,
|
"prompt_type": fields.String,
|
||||||
'chat_prompt_config': fields.Raw(attribute='chat_prompt_config_dict'),
|
"chat_prompt_config": fields.Raw(attribute="chat_prompt_config_dict"),
|
||||||
'completion_prompt_config': fields.Raw(attribute='completion_prompt_config_dict'),
|
"completion_prompt_config": fields.Raw(attribute="completion_prompt_config_dict"),
|
||||||
'dataset_configs': fields.Raw(attribute='dataset_configs_dict'),
|
"dataset_configs": fields.Raw(attribute="dataset_configs_dict"),
|
||||||
'file_upload': fields.Raw(attribute='file_upload_dict'),
|
"file_upload": fields.Raw(attribute="file_upload_dict"),
|
||||||
'created_at': TimestampField
|
"created_at": TimestampField,
|
||||||
}
|
}
|
||||||
|
|
||||||
app_detail_fields = {
|
app_detail_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'name': fields.String,
|
"name": fields.String,
|
||||||
'description': fields.String,
|
"description": fields.String,
|
||||||
'mode': fields.String(attribute='mode_compatible_with_agent'),
|
"mode": fields.String(attribute="mode_compatible_with_agent"),
|
||||||
'icon': fields.String,
|
"icon": fields.String,
|
||||||
'icon_background': fields.String,
|
"icon_background": fields.String,
|
||||||
'enable_site': fields.Boolean,
|
"enable_site": fields.Boolean,
|
||||||
'enable_api': fields.Boolean,
|
"enable_api": fields.Boolean,
|
||||||
'model_config': fields.Nested(model_config_fields, attribute='app_model_config', allow_null=True),
|
"model_config": fields.Nested(model_config_fields, attribute="app_model_config", allow_null=True),
|
||||||
'tracing': fields.Raw,
|
"tracing": fields.Raw,
|
||||||
'created_at': TimestampField
|
"created_at": TimestampField,
|
||||||
}
|
}
|
||||||
|
|
||||||
prompt_config_fields = {
|
prompt_config_fields = {
|
||||||
'prompt_template': fields.String,
|
"prompt_template": fields.String,
|
||||||
}
|
}
|
||||||
|
|
||||||
model_config_partial_fields = {
|
model_config_partial_fields = {
|
||||||
'model': fields.Raw(attribute='model_dict'),
|
"model": fields.Raw(attribute="model_dict"),
|
||||||
'pre_prompt': fields.String,
|
"pre_prompt": fields.String,
|
||||||
}
|
}
|
||||||
|
|
||||||
tag_fields = {
|
tag_fields = {"id": fields.String, "name": fields.String, "type": fields.String}
|
||||||
'id': fields.String,
|
|
||||||
'name': fields.String,
|
|
||||||
'type': fields.String
|
|
||||||
}
|
|
||||||
|
|
||||||
app_partial_fields = {
|
app_partial_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'name': fields.String,
|
"name": fields.String,
|
||||||
'max_active_requests': fields.Raw(),
|
"max_active_requests": fields.Raw(),
|
||||||
'description': fields.String(attribute='desc_or_prompt'),
|
"description": fields.String(attribute="desc_or_prompt"),
|
||||||
'mode': fields.String(attribute='mode_compatible_with_agent'),
|
"mode": fields.String(attribute="mode_compatible_with_agent"),
|
||||||
'icon': fields.String,
|
"icon": fields.String,
|
||||||
'icon_background': fields.String,
|
"icon_background": fields.String,
|
||||||
'model_config': fields.Nested(model_config_partial_fields, attribute='app_model_config', allow_null=True),
|
"model_config": fields.Nested(model_config_partial_fields, attribute="app_model_config", allow_null=True),
|
||||||
'created_at': TimestampField,
|
"created_at": TimestampField,
|
||||||
'tags': fields.List(fields.Nested(tag_fields))
|
"tags": fields.List(fields.Nested(tag_fields)),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
app_pagination_fields = {
|
app_pagination_fields = {
|
||||||
'page': fields.Integer,
|
"page": fields.Integer,
|
||||||
'limit': fields.Integer(attribute='per_page'),
|
"limit": fields.Integer(attribute="per_page"),
|
||||||
'total': fields.Integer,
|
"total": fields.Integer,
|
||||||
'has_more': fields.Boolean(attribute='has_next'),
|
"has_more": fields.Boolean(attribute="has_next"),
|
||||||
'data': fields.List(fields.Nested(app_partial_fields), attribute='items')
|
"data": fields.List(fields.Nested(app_partial_fields), attribute="items"),
|
||||||
}
|
}
|
||||||
|
|
||||||
template_fields = {
|
template_fields = {
|
||||||
'name': fields.String,
|
"name": fields.String,
|
||||||
'icon': fields.String,
|
"icon": fields.String,
|
||||||
'icon_background': fields.String,
|
"icon_background": fields.String,
|
||||||
'description': fields.String,
|
"description": fields.String,
|
||||||
'mode': fields.String,
|
"mode": fields.String,
|
||||||
'model_config': fields.Nested(model_config_fields),
|
"model_config": fields.Nested(model_config_fields),
|
||||||
}
|
}
|
||||||
|
|
||||||
template_list_fields = {
|
template_list_fields = {
|
||||||
'data': fields.List(fields.Nested(template_fields)),
|
"data": fields.List(fields.Nested(template_fields)),
|
||||||
}
|
}
|
||||||
|
|
||||||
site_fields = {
|
site_fields = {
|
||||||
'access_token': fields.String(attribute='code'),
|
"access_token": fields.String(attribute="code"),
|
||||||
'code': fields.String,
|
"code": fields.String,
|
||||||
'title': fields.String,
|
"title": fields.String,
|
||||||
'icon': fields.String,
|
"icon": fields.String,
|
||||||
'icon_background': fields.String,
|
"icon_background": fields.String,
|
||||||
'description': fields.String,
|
"description": fields.String,
|
||||||
'default_language': fields.String,
|
"default_language": fields.String,
|
||||||
'chat_color_theme': fields.String,
|
"chat_color_theme": fields.String,
|
||||||
'chat_color_theme_inverted': fields.Boolean,
|
"chat_color_theme_inverted": fields.Boolean,
|
||||||
'customize_domain': fields.String,
|
"customize_domain": fields.String,
|
||||||
'copyright': fields.String,
|
"copyright": fields.String,
|
||||||
'privacy_policy': fields.String,
|
"privacy_policy": fields.String,
|
||||||
'custom_disclaimer': fields.String,
|
"custom_disclaimer": fields.String,
|
||||||
'customize_token_strategy': fields.String,
|
"customize_token_strategy": fields.String,
|
||||||
'prompt_public': fields.Boolean,
|
"prompt_public": fields.Boolean,
|
||||||
'app_base_url': fields.String,
|
"app_base_url": fields.String,
|
||||||
'show_workflow_steps': fields.Boolean,
|
"show_workflow_steps": fields.Boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
app_detail_fields_with_site = {
|
app_detail_fields_with_site = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'name': fields.String,
|
"name": fields.String,
|
||||||
'description': fields.String,
|
"description": fields.String,
|
||||||
'mode': fields.String(attribute='mode_compatible_with_agent'),
|
"mode": fields.String(attribute="mode_compatible_with_agent"),
|
||||||
'icon': fields.String,
|
"icon": fields.String,
|
||||||
'icon_background': fields.String,
|
"icon_background": fields.String,
|
||||||
'enable_site': fields.Boolean,
|
"enable_site": fields.Boolean,
|
||||||
'enable_api': fields.Boolean,
|
"enable_api": fields.Boolean,
|
||||||
'model_config': fields.Nested(model_config_fields, attribute='app_model_config', allow_null=True),
|
"model_config": fields.Nested(model_config_fields, attribute="app_model_config", allow_null=True),
|
||||||
'site': fields.Nested(site_fields),
|
"site": fields.Nested(site_fields),
|
||||||
'api_base_url': fields.String,
|
"api_base_url": fields.String,
|
||||||
'created_at': TimestampField,
|
"created_at": TimestampField,
|
||||||
'deleted_tools': fields.List(fields.String),
|
"deleted_tools": fields.List(fields.String),
|
||||||
}
|
}
|
||||||
|
|
||||||
app_site_fields = {
|
app_site_fields = {
|
||||||
'app_id': fields.String,
|
"app_id": fields.String,
|
||||||
'access_token': fields.String(attribute='code'),
|
"access_token": fields.String(attribute="code"),
|
||||||
'code': fields.String,
|
"code": fields.String,
|
||||||
'title': fields.String,
|
"title": fields.String,
|
||||||
'icon': fields.String,
|
"icon": fields.String,
|
||||||
'icon_background': fields.String,
|
"icon_background": fields.String,
|
||||||
'description': fields.String,
|
"description": fields.String,
|
||||||
'default_language': fields.String,
|
"default_language": fields.String,
|
||||||
'customize_domain': fields.String,
|
"customize_domain": fields.String,
|
||||||
'copyright': fields.String,
|
"copyright": fields.String,
|
||||||
'privacy_policy': fields.String,
|
"privacy_policy": fields.String,
|
||||||
'custom_disclaimer': fields.String,
|
"custom_disclaimer": fields.String,
|
||||||
'customize_token_strategy': fields.String,
|
"customize_token_strategy": fields.String,
|
||||||
'prompt_public': fields.Boolean,
|
"prompt_public": fields.Boolean,
|
||||||
'show_workflow_steps': fields.Boolean,
|
"show_workflow_steps": fields.Boolean,
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,205 +6,202 @@ from libs.helper import TimestampField
|
||||||
|
|
||||||
class MessageTextField(fields.Raw):
|
class MessageTextField(fields.Raw):
|
||||||
def format(self, value):
|
def format(self, value):
|
||||||
return value[0]['text'] if value else ''
|
return value[0]["text"] if value else ""
|
||||||
|
|
||||||
|
|
||||||
feedback_fields = {
|
feedback_fields = {
|
||||||
'rating': fields.String,
|
"rating": fields.String,
|
||||||
'content': fields.String,
|
"content": fields.String,
|
||||||
'from_source': fields.String,
|
"from_source": fields.String,
|
||||||
'from_end_user_id': fields.String,
|
"from_end_user_id": fields.String,
|
||||||
'from_account': fields.Nested(simple_account_fields, allow_null=True),
|
"from_account": fields.Nested(simple_account_fields, allow_null=True),
|
||||||
}
|
}
|
||||||
|
|
||||||
annotation_fields = {
|
annotation_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'question': fields.String,
|
"question": fields.String,
|
||||||
'content': fields.String,
|
"content": fields.String,
|
||||||
'account': fields.Nested(simple_account_fields, allow_null=True),
|
"account": fields.Nested(simple_account_fields, allow_null=True),
|
||||||
'created_at': TimestampField
|
"created_at": TimestampField,
|
||||||
}
|
}
|
||||||
|
|
||||||
annotation_hit_history_fields = {
|
annotation_hit_history_fields = {
|
||||||
'annotation_id': fields.String(attribute='id'),
|
"annotation_id": fields.String(attribute="id"),
|
||||||
'annotation_create_account': fields.Nested(simple_account_fields, allow_null=True),
|
"annotation_create_account": fields.Nested(simple_account_fields, allow_null=True),
|
||||||
'created_at': TimestampField
|
"created_at": TimestampField,
|
||||||
}
|
}
|
||||||
|
|
||||||
message_file_fields = {
|
message_file_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'type': fields.String,
|
"type": fields.String,
|
||||||
'url': fields.String,
|
"url": fields.String,
|
||||||
'belongs_to': fields.String(default='user'),
|
"belongs_to": fields.String(default="user"),
|
||||||
}
|
}
|
||||||
|
|
||||||
agent_thought_fields = {
|
agent_thought_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'chain_id': fields.String,
|
"chain_id": fields.String,
|
||||||
'message_id': fields.String,
|
"message_id": fields.String,
|
||||||
'position': fields.Integer,
|
"position": fields.Integer,
|
||||||
'thought': fields.String,
|
"thought": fields.String,
|
||||||
'tool': fields.String,
|
"tool": fields.String,
|
||||||
'tool_labels': fields.Raw,
|
"tool_labels": fields.Raw,
|
||||||
'tool_input': fields.String,
|
"tool_input": fields.String,
|
||||||
'created_at': TimestampField,
|
"created_at": TimestampField,
|
||||||
'observation': fields.String,
|
"observation": fields.String,
|
||||||
'files': fields.List(fields.String),
|
"files": fields.List(fields.String),
|
||||||
}
|
}
|
||||||
|
|
||||||
message_detail_fields = {
|
message_detail_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'conversation_id': fields.String,
|
"conversation_id": fields.String,
|
||||||
'inputs': fields.Raw,
|
"inputs": fields.Raw,
|
||||||
'query': fields.String,
|
"query": fields.String,
|
||||||
'message': fields.Raw,
|
"message": fields.Raw,
|
||||||
'message_tokens': fields.Integer,
|
"message_tokens": fields.Integer,
|
||||||
'answer': fields.String(attribute='re_sign_file_url_answer'),
|
"answer": fields.String(attribute="re_sign_file_url_answer"),
|
||||||
'answer_tokens': fields.Integer,
|
"answer_tokens": fields.Integer,
|
||||||
'provider_response_latency': fields.Float,
|
"provider_response_latency": fields.Float,
|
||||||
'from_source': fields.String,
|
"from_source": fields.String,
|
||||||
'from_end_user_id': fields.String,
|
"from_end_user_id": fields.String,
|
||||||
'from_account_id': fields.String,
|
"from_account_id": fields.String,
|
||||||
'feedbacks': fields.List(fields.Nested(feedback_fields)),
|
"feedbacks": fields.List(fields.Nested(feedback_fields)),
|
||||||
'workflow_run_id': fields.String,
|
"workflow_run_id": fields.String,
|
||||||
'annotation': fields.Nested(annotation_fields, allow_null=True),
|
"annotation": fields.Nested(annotation_fields, allow_null=True),
|
||||||
'annotation_hit_history': fields.Nested(annotation_hit_history_fields, allow_null=True),
|
"annotation_hit_history": fields.Nested(annotation_hit_history_fields, allow_null=True),
|
||||||
'created_at': TimestampField,
|
"created_at": TimestampField,
|
||||||
'agent_thoughts': fields.List(fields.Nested(agent_thought_fields)),
|
"agent_thoughts": fields.List(fields.Nested(agent_thought_fields)),
|
||||||
'message_files': fields.List(fields.Nested(message_file_fields), attribute='files'),
|
"message_files": fields.List(fields.Nested(message_file_fields), attribute="files"),
|
||||||
'metadata': fields.Raw(attribute='message_metadata_dict'),
|
"metadata": fields.Raw(attribute="message_metadata_dict"),
|
||||||
'status': fields.String,
|
"status": fields.String,
|
||||||
'error': fields.String,
|
"error": fields.String,
|
||||||
}
|
}
|
||||||
|
|
||||||
feedback_stat_fields = {
|
feedback_stat_fields = {"like": fields.Integer, "dislike": fields.Integer}
|
||||||
'like': fields.Integer,
|
|
||||||
'dislike': fields.Integer
|
|
||||||
}
|
|
||||||
|
|
||||||
model_config_fields = {
|
model_config_fields = {
|
||||||
'opening_statement': fields.String,
|
"opening_statement": fields.String,
|
||||||
'suggested_questions': fields.Raw,
|
"suggested_questions": fields.Raw,
|
||||||
'model': fields.Raw,
|
"model": fields.Raw,
|
||||||
'user_input_form': fields.Raw,
|
"user_input_form": fields.Raw,
|
||||||
'pre_prompt': fields.String,
|
"pre_prompt": fields.String,
|
||||||
'agent_mode': fields.Raw,
|
"agent_mode": fields.Raw,
|
||||||
}
|
}
|
||||||
|
|
||||||
simple_configs_fields = {
|
simple_configs_fields = {
|
||||||
'prompt_template': fields.String,
|
"prompt_template": fields.String,
|
||||||
}
|
}
|
||||||
|
|
||||||
simple_model_config_fields = {
|
simple_model_config_fields = {
|
||||||
'model': fields.Raw(attribute='model_dict'),
|
"model": fields.Raw(attribute="model_dict"),
|
||||||
'pre_prompt': fields.String,
|
"pre_prompt": fields.String,
|
||||||
}
|
}
|
||||||
|
|
||||||
simple_message_detail_fields = {
|
simple_message_detail_fields = {
|
||||||
'inputs': fields.Raw,
|
"inputs": fields.Raw,
|
||||||
'query': fields.String,
|
"query": fields.String,
|
||||||
'message': MessageTextField,
|
"message": MessageTextField,
|
||||||
'answer': fields.String,
|
"answer": fields.String,
|
||||||
}
|
}
|
||||||
|
|
||||||
conversation_fields = {
|
conversation_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'status': fields.String,
|
"status": fields.String,
|
||||||
'from_source': fields.String,
|
"from_source": fields.String,
|
||||||
'from_end_user_id': fields.String,
|
"from_end_user_id": fields.String,
|
||||||
'from_end_user_session_id': fields.String(),
|
"from_end_user_session_id": fields.String(),
|
||||||
'from_account_id': fields.String,
|
"from_account_id": fields.String,
|
||||||
'read_at': TimestampField,
|
"read_at": TimestampField,
|
||||||
'created_at': TimestampField,
|
"created_at": TimestampField,
|
||||||
'annotation': fields.Nested(annotation_fields, allow_null=True),
|
"annotation": fields.Nested(annotation_fields, allow_null=True),
|
||||||
'model_config': fields.Nested(simple_model_config_fields),
|
"model_config": fields.Nested(simple_model_config_fields),
|
||||||
'user_feedback_stats': fields.Nested(feedback_stat_fields),
|
"user_feedback_stats": fields.Nested(feedback_stat_fields),
|
||||||
'admin_feedback_stats': fields.Nested(feedback_stat_fields),
|
"admin_feedback_stats": fields.Nested(feedback_stat_fields),
|
||||||
'message': fields.Nested(simple_message_detail_fields, attribute='first_message')
|
"message": fields.Nested(simple_message_detail_fields, attribute="first_message"),
|
||||||
}
|
}
|
||||||
|
|
||||||
conversation_pagination_fields = {
|
conversation_pagination_fields = {
|
||||||
'page': fields.Integer,
|
"page": fields.Integer,
|
||||||
'limit': fields.Integer(attribute='per_page'),
|
"limit": fields.Integer(attribute="per_page"),
|
||||||
'total': fields.Integer,
|
"total": fields.Integer,
|
||||||
'has_more': fields.Boolean(attribute='has_next'),
|
"has_more": fields.Boolean(attribute="has_next"),
|
||||||
'data': fields.List(fields.Nested(conversation_fields), attribute='items')
|
"data": fields.List(fields.Nested(conversation_fields), attribute="items"),
|
||||||
}
|
}
|
||||||
|
|
||||||
conversation_message_detail_fields = {
|
conversation_message_detail_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'status': fields.String,
|
"status": fields.String,
|
||||||
'from_source': fields.String,
|
"from_source": fields.String,
|
||||||
'from_end_user_id': fields.String,
|
"from_end_user_id": fields.String,
|
||||||
'from_account_id': fields.String,
|
"from_account_id": fields.String,
|
||||||
'created_at': TimestampField,
|
"created_at": TimestampField,
|
||||||
'model_config': fields.Nested(model_config_fields),
|
"model_config": fields.Nested(model_config_fields),
|
||||||
'message': fields.Nested(message_detail_fields, attribute='first_message'),
|
"message": fields.Nested(message_detail_fields, attribute="first_message"),
|
||||||
}
|
}
|
||||||
|
|
||||||
conversation_with_summary_fields = {
|
conversation_with_summary_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'status': fields.String,
|
"status": fields.String,
|
||||||
'from_source': fields.String,
|
"from_source": fields.String,
|
||||||
'from_end_user_id': fields.String,
|
"from_end_user_id": fields.String,
|
||||||
'from_end_user_session_id': fields.String,
|
"from_end_user_session_id": fields.String,
|
||||||
'from_account_id': fields.String,
|
"from_account_id": fields.String,
|
||||||
'name': fields.String,
|
"name": fields.String,
|
||||||
'summary': fields.String(attribute='summary_or_query'),
|
"summary": fields.String(attribute="summary_or_query"),
|
||||||
'read_at': TimestampField,
|
"read_at": TimestampField,
|
||||||
'created_at': TimestampField,
|
"created_at": TimestampField,
|
||||||
'annotated': fields.Boolean,
|
"annotated": fields.Boolean,
|
||||||
'model_config': fields.Nested(simple_model_config_fields),
|
"model_config": fields.Nested(simple_model_config_fields),
|
||||||
'message_count': fields.Integer,
|
"message_count": fields.Integer,
|
||||||
'user_feedback_stats': fields.Nested(feedback_stat_fields),
|
"user_feedback_stats": fields.Nested(feedback_stat_fields),
|
||||||
'admin_feedback_stats': fields.Nested(feedback_stat_fields)
|
"admin_feedback_stats": fields.Nested(feedback_stat_fields),
|
||||||
}
|
}
|
||||||
|
|
||||||
conversation_with_summary_pagination_fields = {
|
conversation_with_summary_pagination_fields = {
|
||||||
'page': fields.Integer,
|
"page": fields.Integer,
|
||||||
'limit': fields.Integer(attribute='per_page'),
|
"limit": fields.Integer(attribute="per_page"),
|
||||||
'total': fields.Integer,
|
"total": fields.Integer,
|
||||||
'has_more': fields.Boolean(attribute='has_next'),
|
"has_more": fields.Boolean(attribute="has_next"),
|
||||||
'data': fields.List(fields.Nested(conversation_with_summary_fields), attribute='items')
|
"data": fields.List(fields.Nested(conversation_with_summary_fields), attribute="items"),
|
||||||
}
|
}
|
||||||
|
|
||||||
conversation_detail_fields = {
|
conversation_detail_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'status': fields.String,
|
"status": fields.String,
|
||||||
'from_source': fields.String,
|
"from_source": fields.String,
|
||||||
'from_end_user_id': fields.String,
|
"from_end_user_id": fields.String,
|
||||||
'from_account_id': fields.String,
|
"from_account_id": fields.String,
|
||||||
'created_at': TimestampField,
|
"created_at": TimestampField,
|
||||||
'annotated': fields.Boolean,
|
"annotated": fields.Boolean,
|
||||||
'introduction': fields.String,
|
"introduction": fields.String,
|
||||||
'model_config': fields.Nested(model_config_fields),
|
"model_config": fields.Nested(model_config_fields),
|
||||||
'message_count': fields.Integer,
|
"message_count": fields.Integer,
|
||||||
'user_feedback_stats': fields.Nested(feedback_stat_fields),
|
"user_feedback_stats": fields.Nested(feedback_stat_fields),
|
||||||
'admin_feedback_stats': fields.Nested(feedback_stat_fields)
|
"admin_feedback_stats": fields.Nested(feedback_stat_fields),
|
||||||
}
|
}
|
||||||
|
|
||||||
simple_conversation_fields = {
|
simple_conversation_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'name': fields.String,
|
"name": fields.String,
|
||||||
'inputs': fields.Raw,
|
"inputs": fields.Raw,
|
||||||
'status': fields.String,
|
"status": fields.String,
|
||||||
'introduction': fields.String,
|
"introduction": fields.String,
|
||||||
'created_at': TimestampField
|
"created_at": TimestampField,
|
||||||
}
|
}
|
||||||
|
|
||||||
conversation_infinite_scroll_pagination_fields = {
|
conversation_infinite_scroll_pagination_fields = {
|
||||||
'limit': fields.Integer,
|
"limit": fields.Integer,
|
||||||
'has_more': fields.Boolean,
|
"has_more": fields.Boolean,
|
||||||
'data': fields.List(fields.Nested(simple_conversation_fields))
|
"data": fields.List(fields.Nested(simple_conversation_fields)),
|
||||||
}
|
}
|
||||||
|
|
||||||
conversation_with_model_config_fields = {
|
conversation_with_model_config_fields = {
|
||||||
**simple_conversation_fields,
|
**simple_conversation_fields,
|
||||||
'model_config': fields.Raw,
|
"model_config": fields.Raw,
|
||||||
}
|
}
|
||||||
|
|
||||||
conversation_with_model_config_infinite_scroll_pagination_fields = {
|
conversation_with_model_config_infinite_scroll_pagination_fields = {
|
||||||
'limit': fields.Integer,
|
"limit": fields.Integer,
|
||||||
'has_more': fields.Boolean,
|
"has_more": fields.Boolean,
|
||||||
'data': fields.List(fields.Nested(conversation_with_model_config_fields))
|
"data": fields.List(fields.Nested(conversation_with_model_config_fields)),
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,19 +3,19 @@ from flask_restful import fields
|
||||||
from libs.helper import TimestampField
|
from libs.helper import TimestampField
|
||||||
|
|
||||||
conversation_variable_fields = {
|
conversation_variable_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'name': fields.String,
|
"name": fields.String,
|
||||||
'value_type': fields.String(attribute='value_type.value'),
|
"value_type": fields.String(attribute="value_type.value"),
|
||||||
'value': fields.String,
|
"value": fields.String,
|
||||||
'description': fields.String,
|
"description": fields.String,
|
||||||
'created_at': TimestampField,
|
"created_at": TimestampField,
|
||||||
'updated_at': TimestampField,
|
"updated_at": TimestampField,
|
||||||
}
|
}
|
||||||
|
|
||||||
paginated_conversation_variable_fields = {
|
paginated_conversation_variable_fields = {
|
||||||
'page': fields.Integer,
|
"page": fields.Integer,
|
||||||
'limit': fields.Integer,
|
"limit": fields.Integer,
|
||||||
'total': fields.Integer,
|
"total": fields.Integer,
|
||||||
'has_more': fields.Boolean,
|
"has_more": fields.Boolean,
|
||||||
'data': fields.List(fields.Nested(conversation_variable_fields), attribute='data'),
|
"data": fields.List(fields.Nested(conversation_variable_fields), attribute="data"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,64 +2,56 @@ from flask_restful import fields
|
||||||
|
|
||||||
from libs.helper import TimestampField
|
from libs.helper import TimestampField
|
||||||
|
|
||||||
integrate_icon_fields = {
|
integrate_icon_fields = {"type": fields.String, "url": fields.String, "emoji": fields.String}
|
||||||
'type': fields.String,
|
|
||||||
'url': fields.String,
|
|
||||||
'emoji': fields.String
|
|
||||||
}
|
|
||||||
|
|
||||||
integrate_page_fields = {
|
integrate_page_fields = {
|
||||||
'page_name': fields.String,
|
"page_name": fields.String,
|
||||||
'page_id': fields.String,
|
"page_id": fields.String,
|
||||||
'page_icon': fields.Nested(integrate_icon_fields, allow_null=True),
|
"page_icon": fields.Nested(integrate_icon_fields, allow_null=True),
|
||||||
'is_bound': fields.Boolean,
|
"is_bound": fields.Boolean,
|
||||||
'parent_id': fields.String,
|
"parent_id": fields.String,
|
||||||
'type': fields.String
|
"type": fields.String,
|
||||||
}
|
}
|
||||||
|
|
||||||
integrate_workspace_fields = {
|
integrate_workspace_fields = {
|
||||||
'workspace_name': fields.String,
|
"workspace_name": fields.String,
|
||||||
'workspace_id': fields.String,
|
"workspace_id": fields.String,
|
||||||
'workspace_icon': fields.String,
|
"workspace_icon": fields.String,
|
||||||
'pages': fields.List(fields.Nested(integrate_page_fields))
|
"pages": fields.List(fields.Nested(integrate_page_fields)),
|
||||||
}
|
}
|
||||||
|
|
||||||
integrate_notion_info_list_fields = {
|
integrate_notion_info_list_fields = {
|
||||||
'notion_info': fields.List(fields.Nested(integrate_workspace_fields)),
|
"notion_info": fields.List(fields.Nested(integrate_workspace_fields)),
|
||||||
}
|
}
|
||||||
|
|
||||||
integrate_icon_fields = {
|
integrate_icon_fields = {"type": fields.String, "url": fields.String, "emoji": fields.String}
|
||||||
'type': fields.String,
|
|
||||||
'url': fields.String,
|
|
||||||
'emoji': fields.String
|
|
||||||
}
|
|
||||||
|
|
||||||
integrate_page_fields = {
|
integrate_page_fields = {
|
||||||
'page_name': fields.String,
|
"page_name": fields.String,
|
||||||
'page_id': fields.String,
|
"page_id": fields.String,
|
||||||
'page_icon': fields.Nested(integrate_icon_fields, allow_null=True),
|
"page_icon": fields.Nested(integrate_icon_fields, allow_null=True),
|
||||||
'parent_id': fields.String,
|
"parent_id": fields.String,
|
||||||
'type': fields.String
|
"type": fields.String,
|
||||||
}
|
}
|
||||||
|
|
||||||
integrate_workspace_fields = {
|
integrate_workspace_fields = {
|
||||||
'workspace_name': fields.String,
|
"workspace_name": fields.String,
|
||||||
'workspace_id': fields.String,
|
"workspace_id": fields.String,
|
||||||
'workspace_icon': fields.String,
|
"workspace_icon": fields.String,
|
||||||
'pages': fields.List(fields.Nested(integrate_page_fields)),
|
"pages": fields.List(fields.Nested(integrate_page_fields)),
|
||||||
'total': fields.Integer
|
"total": fields.Integer,
|
||||||
}
|
}
|
||||||
|
|
||||||
integrate_fields = {
|
integrate_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'provider': fields.String,
|
"provider": fields.String,
|
||||||
'created_at': TimestampField,
|
"created_at": TimestampField,
|
||||||
'is_bound': fields.Boolean,
|
"is_bound": fields.Boolean,
|
||||||
'disabled': fields.Boolean,
|
"disabled": fields.Boolean,
|
||||||
'link': fields.String,
|
"link": fields.String,
|
||||||
'source_info': fields.Nested(integrate_workspace_fields)
|
"source_info": fields.Nested(integrate_workspace_fields),
|
||||||
}
|
}
|
||||||
|
|
||||||
integrate_list_fields = {
|
integrate_list_fields = {
|
||||||
'data': fields.List(fields.Nested(integrate_fields)),
|
"data": fields.List(fields.Nested(integrate_fields)),
|
||||||
}
|
}
|
|
@ -3,73 +3,64 @@ from flask_restful import fields
|
||||||
from libs.helper import TimestampField
|
from libs.helper import TimestampField
|
||||||
|
|
||||||
dataset_fields = {
|
dataset_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'name': fields.String,
|
"name": fields.String,
|
||||||
'description': fields.String,
|
"description": fields.String,
|
||||||
'permission': fields.String,
|
"permission": fields.String,
|
||||||
'data_source_type': fields.String,
|
"data_source_type": fields.String,
|
||||||
'indexing_technique': fields.String,
|
"indexing_technique": fields.String,
|
||||||
'created_by': fields.String,
|
"created_by": fields.String,
|
||||||
'created_at': TimestampField,
|
"created_at": TimestampField,
|
||||||
}
|
}
|
||||||
|
|
||||||
reranking_model_fields = {
|
reranking_model_fields = {"reranking_provider_name": fields.String, "reranking_model_name": fields.String}
|
||||||
'reranking_provider_name': fields.String,
|
|
||||||
'reranking_model_name': fields.String
|
|
||||||
}
|
|
||||||
|
|
||||||
keyword_setting_fields = {
|
keyword_setting_fields = {"keyword_weight": fields.Float}
|
||||||
'keyword_weight': fields.Float
|
|
||||||
}
|
|
||||||
|
|
||||||
vector_setting_fields = {
|
vector_setting_fields = {
|
||||||
'vector_weight': fields.Float,
|
"vector_weight": fields.Float,
|
||||||
'embedding_model_name': fields.String,
|
"embedding_model_name": fields.String,
|
||||||
'embedding_provider_name': fields.String,
|
"embedding_provider_name": fields.String,
|
||||||
}
|
}
|
||||||
|
|
||||||
weighted_score_fields = {
|
weighted_score_fields = {
|
||||||
'keyword_setting': fields.Nested(keyword_setting_fields),
|
"keyword_setting": fields.Nested(keyword_setting_fields),
|
||||||
'vector_setting': fields.Nested(vector_setting_fields),
|
"vector_setting": fields.Nested(vector_setting_fields),
|
||||||
}
|
}
|
||||||
|
|
||||||
dataset_retrieval_model_fields = {
|
dataset_retrieval_model_fields = {
|
||||||
'search_method': fields.String,
|
"search_method": fields.String,
|
||||||
'reranking_enable': fields.Boolean,
|
"reranking_enable": fields.Boolean,
|
||||||
'reranking_mode': fields.String,
|
"reranking_mode": fields.String,
|
||||||
'reranking_model': fields.Nested(reranking_model_fields),
|
"reranking_model": fields.Nested(reranking_model_fields),
|
||||||
'weights': fields.Nested(weighted_score_fields, allow_null=True),
|
"weights": fields.Nested(weighted_score_fields, allow_null=True),
|
||||||
'top_k': fields.Integer,
|
"top_k": fields.Integer,
|
||||||
'score_threshold_enabled': fields.Boolean,
|
"score_threshold_enabled": fields.Boolean,
|
||||||
'score_threshold': fields.Float
|
"score_threshold": fields.Float,
|
||||||
}
|
}
|
||||||
|
|
||||||
tag_fields = {
|
tag_fields = {"id": fields.String, "name": fields.String, "type": fields.String}
|
||||||
'id': fields.String,
|
|
||||||
'name': fields.String,
|
|
||||||
'type': fields.String
|
|
||||||
}
|
|
||||||
|
|
||||||
dataset_detail_fields = {
|
dataset_detail_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'name': fields.String,
|
"name": fields.String,
|
||||||
'description': fields.String,
|
"description": fields.String,
|
||||||
'provider': fields.String,
|
"provider": fields.String,
|
||||||
'permission': fields.String,
|
"permission": fields.String,
|
||||||
'data_source_type': fields.String,
|
"data_source_type": fields.String,
|
||||||
'indexing_technique': fields.String,
|
"indexing_technique": fields.String,
|
||||||
'app_count': fields.Integer,
|
"app_count": fields.Integer,
|
||||||
'document_count': fields.Integer,
|
"document_count": fields.Integer,
|
||||||
'word_count': fields.Integer,
|
"word_count": fields.Integer,
|
||||||
'created_by': fields.String,
|
"created_by": fields.String,
|
||||||
'created_at': TimestampField,
|
"created_at": TimestampField,
|
||||||
'updated_by': fields.String,
|
"updated_by": fields.String,
|
||||||
'updated_at': TimestampField,
|
"updated_at": TimestampField,
|
||||||
'embedding_model': fields.String,
|
"embedding_model": fields.String,
|
||||||
'embedding_model_provider': fields.String,
|
"embedding_model_provider": fields.String,
|
||||||
'embedding_available': fields.Boolean,
|
"embedding_available": fields.Boolean,
|
||||||
'retrieval_model_dict': fields.Nested(dataset_retrieval_model_fields),
|
"retrieval_model_dict": fields.Nested(dataset_retrieval_model_fields),
|
||||||
'tags': fields.List(fields.Nested(tag_fields))
|
"tags": fields.List(fields.Nested(tag_fields)),
|
||||||
}
|
}
|
||||||
|
|
||||||
dataset_query_detail_fields = {
|
dataset_query_detail_fields = {
|
||||||
|
@ -79,7 +70,5 @@ dataset_query_detail_fields = {
|
||||||
"source_app_id": fields.String,
|
"source_app_id": fields.String,
|
||||||
"created_by_role": fields.String,
|
"created_by_role": fields.String,
|
||||||
"created_by": fields.String,
|
"created_by": fields.String,
|
||||||
"created_at": TimestampField
|
"created_at": TimestampField,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,75 +4,73 @@ from fields.dataset_fields import dataset_fields
|
||||||
from libs.helper import TimestampField
|
from libs.helper import TimestampField
|
||||||
|
|
||||||
document_fields = {
|
document_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'position': fields.Integer,
|
"position": fields.Integer,
|
||||||
'data_source_type': fields.String,
|
"data_source_type": fields.String,
|
||||||
'data_source_info': fields.Raw(attribute='data_source_info_dict'),
|
"data_source_info": fields.Raw(attribute="data_source_info_dict"),
|
||||||
'data_source_detail_dict': fields.Raw(attribute='data_source_detail_dict'),
|
"data_source_detail_dict": fields.Raw(attribute="data_source_detail_dict"),
|
||||||
'dataset_process_rule_id': fields.String,
|
"dataset_process_rule_id": fields.String,
|
||||||
'name': fields.String,
|
"name": fields.String,
|
||||||
'created_from': fields.String,
|
"created_from": fields.String,
|
||||||
'created_by': fields.String,
|
"created_by": fields.String,
|
||||||
'created_at': TimestampField,
|
"created_at": TimestampField,
|
||||||
'tokens': fields.Integer,
|
"tokens": fields.Integer,
|
||||||
'indexing_status': fields.String,
|
"indexing_status": fields.String,
|
||||||
'error': fields.String,
|
"error": fields.String,
|
||||||
'enabled': fields.Boolean,
|
"enabled": fields.Boolean,
|
||||||
'disabled_at': TimestampField,
|
"disabled_at": TimestampField,
|
||||||
'disabled_by': fields.String,
|
"disabled_by": fields.String,
|
||||||
'archived': fields.Boolean,
|
"archived": fields.Boolean,
|
||||||
'display_status': fields.String,
|
"display_status": fields.String,
|
||||||
'word_count': fields.Integer,
|
"word_count": fields.Integer,
|
||||||
'hit_count': fields.Integer,
|
"hit_count": fields.Integer,
|
||||||
'doc_form': fields.String,
|
"doc_form": fields.String,
|
||||||
}
|
}
|
||||||
|
|
||||||
document_with_segments_fields = {
|
document_with_segments_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'position': fields.Integer,
|
"position": fields.Integer,
|
||||||
'data_source_type': fields.String,
|
"data_source_type": fields.String,
|
||||||
'data_source_info': fields.Raw(attribute='data_source_info_dict'),
|
"data_source_info": fields.Raw(attribute="data_source_info_dict"),
|
||||||
'data_source_detail_dict': fields.Raw(attribute='data_source_detail_dict'),
|
"data_source_detail_dict": fields.Raw(attribute="data_source_detail_dict"),
|
||||||
'dataset_process_rule_id': fields.String,
|
"dataset_process_rule_id": fields.String,
|
||||||
'name': fields.String,
|
"name": fields.String,
|
||||||
'created_from': fields.String,
|
"created_from": fields.String,
|
||||||
'created_by': fields.String,
|
"created_by": fields.String,
|
||||||
'created_at': TimestampField,
|
"created_at": TimestampField,
|
||||||
'tokens': fields.Integer,
|
"tokens": fields.Integer,
|
||||||
'indexing_status': fields.String,
|
"indexing_status": fields.String,
|
||||||
'error': fields.String,
|
"error": fields.String,
|
||||||
'enabled': fields.Boolean,
|
"enabled": fields.Boolean,
|
||||||
'disabled_at': TimestampField,
|
"disabled_at": TimestampField,
|
||||||
'disabled_by': fields.String,
|
"disabled_by": fields.String,
|
||||||
'archived': fields.Boolean,
|
"archived": fields.Boolean,
|
||||||
'display_status': fields.String,
|
"display_status": fields.String,
|
||||||
'word_count': fields.Integer,
|
"word_count": fields.Integer,
|
||||||
'hit_count': fields.Integer,
|
"hit_count": fields.Integer,
|
||||||
'completed_segments': fields.Integer,
|
"completed_segments": fields.Integer,
|
||||||
'total_segments': fields.Integer
|
"total_segments": fields.Integer,
|
||||||
}
|
}
|
||||||
|
|
||||||
dataset_and_document_fields = {
|
dataset_and_document_fields = {
|
||||||
'dataset': fields.Nested(dataset_fields),
|
"dataset": fields.Nested(dataset_fields),
|
||||||
'documents': fields.List(fields.Nested(document_fields)),
|
"documents": fields.List(fields.Nested(document_fields)),
|
||||||
'batch': fields.String
|
"batch": fields.String,
|
||||||
}
|
}
|
||||||
|
|
||||||
document_status_fields = {
|
document_status_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'indexing_status': fields.String,
|
"indexing_status": fields.String,
|
||||||
'processing_started_at': TimestampField,
|
"processing_started_at": TimestampField,
|
||||||
'parsing_completed_at': TimestampField,
|
"parsing_completed_at": TimestampField,
|
||||||
'cleaning_completed_at': TimestampField,
|
"cleaning_completed_at": TimestampField,
|
||||||
'splitting_completed_at': TimestampField,
|
"splitting_completed_at": TimestampField,
|
||||||
'completed_at': TimestampField,
|
"completed_at": TimestampField,
|
||||||
'paused_at': TimestampField,
|
"paused_at": TimestampField,
|
||||||
'error': fields.String,
|
"error": fields.String,
|
||||||
'stopped_at': TimestampField,
|
"stopped_at": TimestampField,
|
||||||
'completed_segments': fields.Integer,
|
"completed_segments": fields.Integer,
|
||||||
'total_segments': fields.Integer,
|
"total_segments": fields.Integer,
|
||||||
}
|
}
|
||||||
|
|
||||||
document_status_fields_list = {
|
document_status_fields_list = {"data": fields.List(fields.Nested(document_status_fields))}
|
||||||
'data': fields.List(fields.Nested(document_status_fields))
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
from flask_restful import fields
|
from flask_restful import fields
|
||||||
|
|
||||||
simple_end_user_fields = {
|
simple_end_user_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'type': fields.String,
|
"type": fields.String,
|
||||||
'is_anonymous': fields.Boolean,
|
"is_anonymous": fields.Boolean,
|
||||||
'session_id': fields.String,
|
"session_id": fields.String,
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,17 +3,17 @@ from flask_restful import fields
|
||||||
from libs.helper import TimestampField
|
from libs.helper import TimestampField
|
||||||
|
|
||||||
upload_config_fields = {
|
upload_config_fields = {
|
||||||
'file_size_limit': fields.Integer,
|
"file_size_limit": fields.Integer,
|
||||||
'batch_count_limit': fields.Integer,
|
"batch_count_limit": fields.Integer,
|
||||||
'image_file_size_limit': fields.Integer,
|
"image_file_size_limit": fields.Integer,
|
||||||
}
|
}
|
||||||
|
|
||||||
file_fields = {
|
file_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'name': fields.String,
|
"name": fields.String,
|
||||||
'size': fields.Integer,
|
"size": fields.Integer,
|
||||||
'extension': fields.String,
|
"extension": fields.String,
|
||||||
'mime_type': fields.String,
|
"mime_type": fields.String,
|
||||||
'created_by': fields.String,
|
"created_by": fields.String,
|
||||||
'created_at': TimestampField,
|
"created_at": TimestampField,
|
||||||
}
|
}
|
|
@ -3,39 +3,39 @@ from flask_restful import fields
|
||||||
from libs.helper import TimestampField
|
from libs.helper import TimestampField
|
||||||
|
|
||||||
document_fields = {
|
document_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'data_source_type': fields.String,
|
"data_source_type": fields.String,
|
||||||
'name': fields.String,
|
"name": fields.String,
|
||||||
'doc_type': fields.String,
|
"doc_type": fields.String,
|
||||||
}
|
}
|
||||||
|
|
||||||
segment_fields = {
|
segment_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'position': fields.Integer,
|
"position": fields.Integer,
|
||||||
'document_id': fields.String,
|
"document_id": fields.String,
|
||||||
'content': fields.String,
|
"content": fields.String,
|
||||||
'answer': fields.String,
|
"answer": fields.String,
|
||||||
'word_count': fields.Integer,
|
"word_count": fields.Integer,
|
||||||
'tokens': fields.Integer,
|
"tokens": fields.Integer,
|
||||||
'keywords': fields.List(fields.String),
|
"keywords": fields.List(fields.String),
|
||||||
'index_node_id': fields.String,
|
"index_node_id": fields.String,
|
||||||
'index_node_hash': fields.String,
|
"index_node_hash": fields.String,
|
||||||
'hit_count': fields.Integer,
|
"hit_count": fields.Integer,
|
||||||
'enabled': fields.Boolean,
|
"enabled": fields.Boolean,
|
||||||
'disabled_at': TimestampField,
|
"disabled_at": TimestampField,
|
||||||
'disabled_by': fields.String,
|
"disabled_by": fields.String,
|
||||||
'status': fields.String,
|
"status": fields.String,
|
||||||
'created_by': fields.String,
|
"created_by": fields.String,
|
||||||
'created_at': TimestampField,
|
"created_at": TimestampField,
|
||||||
'indexing_at': TimestampField,
|
"indexing_at": TimestampField,
|
||||||
'completed_at': TimestampField,
|
"completed_at": TimestampField,
|
||||||
'error': fields.String,
|
"error": fields.String,
|
||||||
'stopped_at': TimestampField,
|
"stopped_at": TimestampField,
|
||||||
'document': fields.Nested(document_fields),
|
"document": fields.Nested(document_fields),
|
||||||
}
|
}
|
||||||
|
|
||||||
hit_testing_record_fields = {
|
hit_testing_record_fields = {
|
||||||
'segment': fields.Nested(segment_fields),
|
"segment": fields.Nested(segment_fields),
|
||||||
'score': fields.Float,
|
"score": fields.Float,
|
||||||
'tsne_position': fields.Raw
|
"tsne_position": fields.Raw,
|
||||||
}
|
}
|
|
@ -3,23 +3,21 @@ from flask_restful import fields
|
||||||
from libs.helper import TimestampField
|
from libs.helper import TimestampField
|
||||||
|
|
||||||
app_fields = {
|
app_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'name': fields.String,
|
"name": fields.String,
|
||||||
'mode': fields.String,
|
"mode": fields.String,
|
||||||
'icon': fields.String,
|
"icon": fields.String,
|
||||||
'icon_background': fields.String
|
"icon_background": fields.String,
|
||||||
}
|
}
|
||||||
|
|
||||||
installed_app_fields = {
|
installed_app_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'app': fields.Nested(app_fields),
|
"app": fields.Nested(app_fields),
|
||||||
'app_owner_tenant_id': fields.String,
|
"app_owner_tenant_id": fields.String,
|
||||||
'is_pinned': fields.Boolean,
|
"is_pinned": fields.Boolean,
|
||||||
'last_used_at': TimestampField,
|
"last_used_at": TimestampField,
|
||||||
'editable': fields.Boolean,
|
"editable": fields.Boolean,
|
||||||
'uninstallable': fields.Boolean
|
"uninstallable": fields.Boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
installed_app_list_fields = {
|
installed_app_list_fields = {"installed_apps": fields.List(fields.Nested(installed_app_fields))}
|
||||||
'installed_apps': fields.List(fields.Nested(installed_app_fields))
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,38 +2,32 @@ from flask_restful import fields
|
||||||
|
|
||||||
from libs.helper import TimestampField
|
from libs.helper import TimestampField
|
||||||
|
|
||||||
simple_account_fields = {
|
simple_account_fields = {"id": fields.String, "name": fields.String, "email": fields.String}
|
||||||
'id': fields.String,
|
|
||||||
'name': fields.String,
|
|
||||||
'email': fields.String
|
|
||||||
}
|
|
||||||
|
|
||||||
account_fields = {
|
account_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'name': fields.String,
|
"name": fields.String,
|
||||||
'avatar': fields.String,
|
"avatar": fields.String,
|
||||||
'email': fields.String,
|
"email": fields.String,
|
||||||
'is_password_set': fields.Boolean,
|
"is_password_set": fields.Boolean,
|
||||||
'interface_language': fields.String,
|
"interface_language": fields.String,
|
||||||
'interface_theme': fields.String,
|
"interface_theme": fields.String,
|
||||||
'timezone': fields.String,
|
"timezone": fields.String,
|
||||||
'last_login_at': TimestampField,
|
"last_login_at": TimestampField,
|
||||||
'last_login_ip': fields.String,
|
"last_login_ip": fields.String,
|
||||||
'created_at': TimestampField
|
"created_at": TimestampField,
|
||||||
}
|
}
|
||||||
|
|
||||||
account_with_role_fields = {
|
account_with_role_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'name': fields.String,
|
"name": fields.String,
|
||||||
'avatar': fields.String,
|
"avatar": fields.String,
|
||||||
'email': fields.String,
|
"email": fields.String,
|
||||||
'last_login_at': TimestampField,
|
"last_login_at": TimestampField,
|
||||||
'last_active_at': TimestampField,
|
"last_active_at": TimestampField,
|
||||||
'created_at': TimestampField,
|
"created_at": TimestampField,
|
||||||
'role': fields.String,
|
"role": fields.String,
|
||||||
'status': fields.String,
|
"status": fields.String,
|
||||||
}
|
}
|
||||||
|
|
||||||
account_with_role_list_fields = {
|
account_with_role_list_fields = {"accounts": fields.List(fields.Nested(account_with_role_fields))}
|
||||||
'accounts': fields.List(fields.Nested(account_with_role_fields))
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,83 +3,79 @@ from flask_restful import fields
|
||||||
from fields.conversation_fields import message_file_fields
|
from fields.conversation_fields import message_file_fields
|
||||||
from libs.helper import TimestampField
|
from libs.helper import TimestampField
|
||||||
|
|
||||||
feedback_fields = {
|
feedback_fields = {"rating": fields.String}
|
||||||
'rating': fields.String
|
|
||||||
}
|
|
||||||
|
|
||||||
retriever_resource_fields = {
|
retriever_resource_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'message_id': fields.String,
|
"message_id": fields.String,
|
||||||
'position': fields.Integer,
|
"position": fields.Integer,
|
||||||
'dataset_id': fields.String,
|
"dataset_id": fields.String,
|
||||||
'dataset_name': fields.String,
|
"dataset_name": fields.String,
|
||||||
'document_id': fields.String,
|
"document_id": fields.String,
|
||||||
'document_name': fields.String,
|
"document_name": fields.String,
|
||||||
'data_source_type': fields.String,
|
"data_source_type": fields.String,
|
||||||
'segment_id': fields.String,
|
"segment_id": fields.String,
|
||||||
'score': fields.Float,
|
"score": fields.Float,
|
||||||
'hit_count': fields.Integer,
|
"hit_count": fields.Integer,
|
||||||
'word_count': fields.Integer,
|
"word_count": fields.Integer,
|
||||||
'segment_position': fields.Integer,
|
"segment_position": fields.Integer,
|
||||||
'index_node_hash': fields.String,
|
"index_node_hash": fields.String,
|
||||||
'content': fields.String,
|
"content": fields.String,
|
||||||
'created_at': TimestampField
|
"created_at": TimestampField,
|
||||||
}
|
}
|
||||||
|
|
||||||
feedback_fields = {
|
feedback_fields = {"rating": fields.String}
|
||||||
'rating': fields.String
|
|
||||||
}
|
|
||||||
|
|
||||||
agent_thought_fields = {
|
agent_thought_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'chain_id': fields.String,
|
"chain_id": fields.String,
|
||||||
'message_id': fields.String,
|
"message_id": fields.String,
|
||||||
'position': fields.Integer,
|
"position": fields.Integer,
|
||||||
'thought': fields.String,
|
"thought": fields.String,
|
||||||
'tool': fields.String,
|
"tool": fields.String,
|
||||||
'tool_labels': fields.Raw,
|
"tool_labels": fields.Raw,
|
||||||
'tool_input': fields.String,
|
"tool_input": fields.String,
|
||||||
'created_at': TimestampField,
|
"created_at": TimestampField,
|
||||||
'observation': fields.String,
|
"observation": fields.String,
|
||||||
'files': fields.List(fields.String)
|
"files": fields.List(fields.String),
|
||||||
}
|
}
|
||||||
|
|
||||||
retriever_resource_fields = {
|
retriever_resource_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'message_id': fields.String,
|
"message_id": fields.String,
|
||||||
'position': fields.Integer,
|
"position": fields.Integer,
|
||||||
'dataset_id': fields.String,
|
"dataset_id": fields.String,
|
||||||
'dataset_name': fields.String,
|
"dataset_name": fields.String,
|
||||||
'document_id': fields.String,
|
"document_id": fields.String,
|
||||||
'document_name': fields.String,
|
"document_name": fields.String,
|
||||||
'data_source_type': fields.String,
|
"data_source_type": fields.String,
|
||||||
'segment_id': fields.String,
|
"segment_id": fields.String,
|
||||||
'score': fields.Float,
|
"score": fields.Float,
|
||||||
'hit_count': fields.Integer,
|
"hit_count": fields.Integer,
|
||||||
'word_count': fields.Integer,
|
"word_count": fields.Integer,
|
||||||
'segment_position': fields.Integer,
|
"segment_position": fields.Integer,
|
||||||
'index_node_hash': fields.String,
|
"index_node_hash": fields.String,
|
||||||
'content': fields.String,
|
"content": fields.String,
|
||||||
'created_at': TimestampField
|
"created_at": TimestampField,
|
||||||
}
|
}
|
||||||
|
|
||||||
message_fields = {
|
message_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'conversation_id': fields.String,
|
"conversation_id": fields.String,
|
||||||
'inputs': fields.Raw,
|
"inputs": fields.Raw,
|
||||||
'query': fields.String,
|
"query": fields.String,
|
||||||
'answer': fields.String(attribute='re_sign_file_url_answer'),
|
"answer": fields.String(attribute="re_sign_file_url_answer"),
|
||||||
'feedback': fields.Nested(feedback_fields, attribute='user_feedback', allow_null=True),
|
"feedback": fields.Nested(feedback_fields, attribute="user_feedback", allow_null=True),
|
||||||
'retriever_resources': fields.List(fields.Nested(retriever_resource_fields)),
|
"retriever_resources": fields.List(fields.Nested(retriever_resource_fields)),
|
||||||
'created_at': TimestampField,
|
"created_at": TimestampField,
|
||||||
'agent_thoughts': fields.List(fields.Nested(agent_thought_fields)),
|
"agent_thoughts": fields.List(fields.Nested(agent_thought_fields)),
|
||||||
'message_files': fields.List(fields.Nested(message_file_fields), attribute='files'),
|
"message_files": fields.List(fields.Nested(message_file_fields), attribute="files"),
|
||||||
'status': fields.String,
|
"status": fields.String,
|
||||||
'error': fields.String,
|
"error": fields.String,
|
||||||
}
|
}
|
||||||
|
|
||||||
message_infinite_scroll_pagination_fields = {
|
message_infinite_scroll_pagination_fields = {
|
||||||
'limit': fields.Integer,
|
"limit": fields.Integer,
|
||||||
'has_more': fields.Boolean,
|
"has_more": fields.Boolean,
|
||||||
'data': fields.List(fields.Nested(message_fields))
|
"data": fields.List(fields.Nested(message_fields)),
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,31 +3,31 @@ from flask_restful import fields
|
||||||
from libs.helper import TimestampField
|
from libs.helper import TimestampField
|
||||||
|
|
||||||
segment_fields = {
|
segment_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'position': fields.Integer,
|
"position": fields.Integer,
|
||||||
'document_id': fields.String,
|
"document_id": fields.String,
|
||||||
'content': fields.String,
|
"content": fields.String,
|
||||||
'answer': fields.String,
|
"answer": fields.String,
|
||||||
'word_count': fields.Integer,
|
"word_count": fields.Integer,
|
||||||
'tokens': fields.Integer,
|
"tokens": fields.Integer,
|
||||||
'keywords': fields.List(fields.String),
|
"keywords": fields.List(fields.String),
|
||||||
'index_node_id': fields.String,
|
"index_node_id": fields.String,
|
||||||
'index_node_hash': fields.String,
|
"index_node_hash": fields.String,
|
||||||
'hit_count': fields.Integer,
|
"hit_count": fields.Integer,
|
||||||
'enabled': fields.Boolean,
|
"enabled": fields.Boolean,
|
||||||
'disabled_at': TimestampField,
|
"disabled_at": TimestampField,
|
||||||
'disabled_by': fields.String,
|
"disabled_by": fields.String,
|
||||||
'status': fields.String,
|
"status": fields.String,
|
||||||
'created_by': fields.String,
|
"created_by": fields.String,
|
||||||
'created_at': TimestampField,
|
"created_at": TimestampField,
|
||||||
'indexing_at': TimestampField,
|
"indexing_at": TimestampField,
|
||||||
'completed_at': TimestampField,
|
"completed_at": TimestampField,
|
||||||
'error': fields.String,
|
"error": fields.String,
|
||||||
'stopped_at': TimestampField
|
"stopped_at": TimestampField,
|
||||||
}
|
}
|
||||||
|
|
||||||
segment_list_response = {
|
segment_list_response = {
|
||||||
'data': fields.List(fields.Nested(segment_fields)),
|
"data": fields.List(fields.Nested(segment_fields)),
|
||||||
'has_more': fields.Boolean,
|
"has_more": fields.Boolean,
|
||||||
'limit': fields.Integer
|
"limit": fields.Integer,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,3 @@
|
||||||
from flask_restful import fields
|
from flask_restful import fields
|
||||||
|
|
||||||
tag_fields = {
|
tag_fields = {"id": fields.String, "name": fields.String, "type": fields.String, "binding_count": fields.String}
|
||||||
'id': fields.String,
|
|
||||||
'name': fields.String,
|
|
||||||
'type': fields.String,
|
|
||||||
'binding_count': fields.String
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,18 +7,18 @@ from libs.helper import TimestampField
|
||||||
|
|
||||||
workflow_app_log_partial_fields = {
|
workflow_app_log_partial_fields = {
|
||||||
"id": fields.String,
|
"id": fields.String,
|
||||||
"workflow_run": fields.Nested(workflow_run_for_log_fields, attribute='workflow_run', allow_null=True),
|
"workflow_run": fields.Nested(workflow_run_for_log_fields, attribute="workflow_run", allow_null=True),
|
||||||
"created_from": fields.String,
|
"created_from": fields.String,
|
||||||
"created_by_role": fields.String,
|
"created_by_role": fields.String,
|
||||||
"created_by_account": fields.Nested(simple_account_fields, attribute='created_by_account', allow_null=True),
|
"created_by_account": fields.Nested(simple_account_fields, attribute="created_by_account", allow_null=True),
|
||||||
"created_by_end_user": fields.Nested(simple_end_user_fields, attribute='created_by_end_user', allow_null=True),
|
"created_by_end_user": fields.Nested(simple_end_user_fields, attribute="created_by_end_user", allow_null=True),
|
||||||
"created_at": TimestampField
|
"created_at": TimestampField,
|
||||||
}
|
}
|
||||||
|
|
||||||
workflow_app_log_pagination_fields = {
|
workflow_app_log_pagination_fields = {
|
||||||
'page': fields.Integer,
|
"page": fields.Integer,
|
||||||
'limit': fields.Integer(attribute='per_page'),
|
"limit": fields.Integer(attribute="per_page"),
|
||||||
'total': fields.Integer,
|
"total": fields.Integer,
|
||||||
'has_more': fields.Boolean(attribute='has_next'),
|
"has_more": fields.Boolean(attribute="has_next"),
|
||||||
'data': fields.List(fields.Nested(workflow_app_log_partial_fields), attribute='items')
|
"data": fields.List(fields.Nested(workflow_app_log_partial_fields), attribute="items"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,43 +13,43 @@ class EnvironmentVariableField(fields.Raw):
|
||||||
# Mask secret variables values in environment_variables
|
# Mask secret variables values in environment_variables
|
||||||
if isinstance(value, SecretVariable):
|
if isinstance(value, SecretVariable):
|
||||||
return {
|
return {
|
||||||
'id': value.id,
|
"id": value.id,
|
||||||
'name': value.name,
|
"name": value.name,
|
||||||
'value': encrypter.obfuscated_token(value.value),
|
"value": encrypter.obfuscated_token(value.value),
|
||||||
'value_type': value.value_type.value,
|
"value_type": value.value_type.value,
|
||||||
}
|
}
|
||||||
if isinstance(value, Variable):
|
if isinstance(value, Variable):
|
||||||
return {
|
return {
|
||||||
'id': value.id,
|
"id": value.id,
|
||||||
'name': value.name,
|
"name": value.name,
|
||||||
'value': value.value,
|
"value": value.value,
|
||||||
'value_type': value.value_type.value,
|
"value_type": value.value_type.value,
|
||||||
}
|
}
|
||||||
if isinstance(value, dict):
|
if isinstance(value, dict):
|
||||||
value_type = value.get('value_type')
|
value_type = value.get("value_type")
|
||||||
if value_type not in ENVIRONMENT_VARIABLE_SUPPORTED_TYPES:
|
if value_type not in ENVIRONMENT_VARIABLE_SUPPORTED_TYPES:
|
||||||
raise ValueError(f'Unsupported environment variable value type: {value_type}')
|
raise ValueError(f"Unsupported environment variable value type: {value_type}")
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
conversation_variable_fields = {
|
conversation_variable_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'name': fields.String,
|
"name": fields.String,
|
||||||
'value_type': fields.String(attribute='value_type.value'),
|
"value_type": fields.String(attribute="value_type.value"),
|
||||||
'value': fields.Raw,
|
"value": fields.Raw,
|
||||||
'description': fields.String,
|
"description": fields.String,
|
||||||
}
|
}
|
||||||
|
|
||||||
workflow_fields = {
|
workflow_fields = {
|
||||||
'id': fields.String,
|
"id": fields.String,
|
||||||
'graph': fields.Raw(attribute='graph_dict'),
|
"graph": fields.Raw(attribute="graph_dict"),
|
||||||
'features': fields.Raw(attribute='features_dict'),
|
"features": fields.Raw(attribute="features_dict"),
|
||||||
'hash': fields.String(attribute='unique_hash'),
|
"hash": fields.String(attribute="unique_hash"),
|
||||||
'created_by': fields.Nested(simple_account_fields, attribute='created_by_account'),
|
"created_by": fields.Nested(simple_account_fields, attribute="created_by_account"),
|
||||||
'created_at': TimestampField,
|
"created_at": TimestampField,
|
||||||
'updated_by': fields.Nested(simple_account_fields, attribute='updated_by_account', allow_null=True),
|
"updated_by": fields.Nested(simple_account_fields, attribute="updated_by_account", allow_null=True),
|
||||||
'updated_at': TimestampField,
|
"updated_at": TimestampField,
|
||||||
'tool_published': fields.Boolean,
|
"tool_published": fields.Boolean,
|
||||||
'environment_variables': fields.List(EnvironmentVariableField()),
|
"environment_variables": fields.List(EnvironmentVariableField()),
|
||||||
'conversation_variables': fields.List(fields.Nested(conversation_variable_fields)),
|
"conversation_variables": fields.List(fields.Nested(conversation_variable_fields)),
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ workflow_run_for_log_fields = {
|
||||||
"total_tokens": fields.Integer,
|
"total_tokens": fields.Integer,
|
||||||
"total_steps": fields.Integer,
|
"total_steps": fields.Integer,
|
||||||
"created_at": TimestampField,
|
"created_at": TimestampField,
|
||||||
"finished_at": TimestampField
|
"finished_at": TimestampField,
|
||||||
}
|
}
|
||||||
|
|
||||||
workflow_run_for_list_fields = {
|
workflow_run_for_list_fields = {
|
||||||
|
@ -24,9 +24,9 @@ workflow_run_for_list_fields = {
|
||||||
"elapsed_time": fields.Float,
|
"elapsed_time": fields.Float,
|
||||||
"total_tokens": fields.Integer,
|
"total_tokens": fields.Integer,
|
||||||
"total_steps": fields.Integer,
|
"total_steps": fields.Integer,
|
||||||
"created_by_account": fields.Nested(simple_account_fields, attribute='created_by_account', allow_null=True),
|
"created_by_account": fields.Nested(simple_account_fields, attribute="created_by_account", allow_null=True),
|
||||||
"created_at": TimestampField,
|
"created_at": TimestampField,
|
||||||
"finished_at": TimestampField
|
"finished_at": TimestampField,
|
||||||
}
|
}
|
||||||
|
|
||||||
advanced_chat_workflow_run_for_list_fields = {
|
advanced_chat_workflow_run_for_list_fields = {
|
||||||
|
@ -39,40 +39,40 @@ advanced_chat_workflow_run_for_list_fields = {
|
||||||
"elapsed_time": fields.Float,
|
"elapsed_time": fields.Float,
|
||||||
"total_tokens": fields.Integer,
|
"total_tokens": fields.Integer,
|
||||||
"total_steps": fields.Integer,
|
"total_steps": fields.Integer,
|
||||||
"created_by_account": fields.Nested(simple_account_fields, attribute='created_by_account', allow_null=True),
|
"created_by_account": fields.Nested(simple_account_fields, attribute="created_by_account", allow_null=True),
|
||||||
"created_at": TimestampField,
|
"created_at": TimestampField,
|
||||||
"finished_at": TimestampField
|
"finished_at": TimestampField,
|
||||||
}
|
}
|
||||||
|
|
||||||
advanced_chat_workflow_run_pagination_fields = {
|
advanced_chat_workflow_run_pagination_fields = {
|
||||||
'limit': fields.Integer(attribute='limit'),
|
"limit": fields.Integer(attribute="limit"),
|
||||||
'has_more': fields.Boolean(attribute='has_more'),
|
"has_more": fields.Boolean(attribute="has_more"),
|
||||||
'data': fields.List(fields.Nested(advanced_chat_workflow_run_for_list_fields), attribute='data')
|
"data": fields.List(fields.Nested(advanced_chat_workflow_run_for_list_fields), attribute="data"),
|
||||||
}
|
}
|
||||||
|
|
||||||
workflow_run_pagination_fields = {
|
workflow_run_pagination_fields = {
|
||||||
'limit': fields.Integer(attribute='limit'),
|
"limit": fields.Integer(attribute="limit"),
|
||||||
'has_more': fields.Boolean(attribute='has_more'),
|
"has_more": fields.Boolean(attribute="has_more"),
|
||||||
'data': fields.List(fields.Nested(workflow_run_for_list_fields), attribute='data')
|
"data": fields.List(fields.Nested(workflow_run_for_list_fields), attribute="data"),
|
||||||
}
|
}
|
||||||
|
|
||||||
workflow_run_detail_fields = {
|
workflow_run_detail_fields = {
|
||||||
"id": fields.String,
|
"id": fields.String,
|
||||||
"sequence_number": fields.Integer,
|
"sequence_number": fields.Integer,
|
||||||
"version": fields.String,
|
"version": fields.String,
|
||||||
"graph": fields.Raw(attribute='graph_dict'),
|
"graph": fields.Raw(attribute="graph_dict"),
|
||||||
"inputs": fields.Raw(attribute='inputs_dict'),
|
"inputs": fields.Raw(attribute="inputs_dict"),
|
||||||
"status": fields.String,
|
"status": fields.String,
|
||||||
"outputs": fields.Raw(attribute='outputs_dict'),
|
"outputs": fields.Raw(attribute="outputs_dict"),
|
||||||
"error": fields.String,
|
"error": fields.String,
|
||||||
"elapsed_time": fields.Float,
|
"elapsed_time": fields.Float,
|
||||||
"total_tokens": fields.Integer,
|
"total_tokens": fields.Integer,
|
||||||
"total_steps": fields.Integer,
|
"total_steps": fields.Integer,
|
||||||
"created_by_role": fields.String,
|
"created_by_role": fields.String,
|
||||||
"created_by_account": fields.Nested(simple_account_fields, attribute='created_by_account', allow_null=True),
|
"created_by_account": fields.Nested(simple_account_fields, attribute="created_by_account", allow_null=True),
|
||||||
"created_by_end_user": fields.Nested(simple_end_user_fields, attribute='created_by_end_user', allow_null=True),
|
"created_by_end_user": fields.Nested(simple_end_user_fields, attribute="created_by_end_user", allow_null=True),
|
||||||
"created_at": TimestampField,
|
"created_at": TimestampField,
|
||||||
"finished_at": TimestampField
|
"finished_at": TimestampField,
|
||||||
}
|
}
|
||||||
|
|
||||||
workflow_run_node_execution_fields = {
|
workflow_run_node_execution_fields = {
|
||||||
|
@ -82,21 +82,21 @@ workflow_run_node_execution_fields = {
|
||||||
"node_id": fields.String,
|
"node_id": fields.String,
|
||||||
"node_type": fields.String,
|
"node_type": fields.String,
|
||||||
"title": fields.String,
|
"title": fields.String,
|
||||||
"inputs": fields.Raw(attribute='inputs_dict'),
|
"inputs": fields.Raw(attribute="inputs_dict"),
|
||||||
"process_data": fields.Raw(attribute='process_data_dict'),
|
"process_data": fields.Raw(attribute="process_data_dict"),
|
||||||
"outputs": fields.Raw(attribute='outputs_dict'),
|
"outputs": fields.Raw(attribute="outputs_dict"),
|
||||||
"status": fields.String,
|
"status": fields.String,
|
||||||
"error": fields.String,
|
"error": fields.String,
|
||||||
"elapsed_time": fields.Float,
|
"elapsed_time": fields.Float,
|
||||||
"execution_metadata": fields.Raw(attribute='execution_metadata_dict'),
|
"execution_metadata": fields.Raw(attribute="execution_metadata_dict"),
|
||||||
"extras": fields.Raw,
|
"extras": fields.Raw,
|
||||||
"created_at": TimestampField,
|
"created_at": TimestampField,
|
||||||
"created_by_role": fields.String,
|
"created_by_role": fields.String,
|
||||||
"created_by_account": fields.Nested(simple_account_fields, attribute='created_by_account', allow_null=True),
|
"created_by_account": fields.Nested(simple_account_fields, attribute="created_by_account", allow_null=True),
|
||||||
"created_by_end_user": fields.Nested(simple_end_user_fields, attribute='created_by_end_user', allow_null=True),
|
"created_by_end_user": fields.Nested(simple_end_user_fields, attribute="created_by_end_user", allow_null=True),
|
||||||
"finished_at": TimestampField
|
"finished_at": TimestampField,
|
||||||
}
|
}
|
||||||
|
|
||||||
workflow_run_node_execution_list_fields = {
|
workflow_run_node_execution_list_fields = {
|
||||||
'data': fields.List(fields.Nested(workflow_run_node_execution_fields)),
|
"data": fields.List(fields.Nested(workflow_run_node_execution_fields)),
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,18 @@ ignore = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.ruff.format]
|
[tool.ruff.format]
|
||||||
quote-style = "single"
|
exclude = [
|
||||||
|
"core/**/*.py",
|
||||||
|
"controllers/**/*.py",
|
||||||
|
"models/**/*.py",
|
||||||
|
"utils/**/*.py",
|
||||||
|
"migrations/**/*",
|
||||||
|
"services/**/*.py",
|
||||||
|
"tasks/**/*.py",
|
||||||
|
"tests/**/*.py",
|
||||||
|
"libs/**/*.py",
|
||||||
|
"configs/**/*.py",
|
||||||
|
]
|
||||||
|
|
||||||
[tool.pytest_env]
|
[tool.pytest_env]
|
||||||
OPENAI_API_KEY = "sk-IamNotARealKeyJustForMockTestKawaiiiiiiiiii"
|
OPENAI_API_KEY = "sk-IamNotARealKeyJustForMockTestKawaiiiiiiiiii"
|
||||||
|
|
|
@ -11,27 +11,32 @@ from extensions.ext_database import db
|
||||||
from models.dataset import Embedding
|
from models.dataset import Embedding
|
||||||
|
|
||||||
|
|
||||||
@app.celery.task(queue='dataset')
|
@app.celery.task(queue="dataset")
|
||||||
def clean_embedding_cache_task():
|
def clean_embedding_cache_task():
|
||||||
click.echo(click.style('Start clean embedding cache.', fg='green'))
|
click.echo(click.style("Start clean embedding cache.", fg="green"))
|
||||||
clean_days = int(dify_config.CLEAN_DAY_SETTING)
|
clean_days = int(dify_config.CLEAN_DAY_SETTING)
|
||||||
start_at = time.perf_counter()
|
start_at = time.perf_counter()
|
||||||
thirty_days_ago = datetime.datetime.now() - datetime.timedelta(days=clean_days)
|
thirty_days_ago = datetime.datetime.now() - datetime.timedelta(days=clean_days)
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
embedding_ids = db.session.query(Embedding.id).filter(Embedding.created_at < thirty_days_ago) \
|
embedding_ids = (
|
||||||
.order_by(Embedding.created_at.desc()).limit(100).all()
|
db.session.query(Embedding.id)
|
||||||
|
.filter(Embedding.created_at < thirty_days_ago)
|
||||||
|
.order_by(Embedding.created_at.desc())
|
||||||
|
.limit(100)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
embedding_ids = [embedding_id[0] for embedding_id in embedding_ids]
|
embedding_ids = [embedding_id[0] for embedding_id in embedding_ids]
|
||||||
except NotFound:
|
except NotFound:
|
||||||
break
|
break
|
||||||
if embedding_ids:
|
if embedding_ids:
|
||||||
for embedding_id in embedding_ids:
|
for embedding_id in embedding_ids:
|
||||||
db.session.execute(text(
|
db.session.execute(
|
||||||
"DELETE FROM embeddings WHERE id = :embedding_id"
|
text("DELETE FROM embeddings WHERE id = :embedding_id"), {"embedding_id": embedding_id}
|
||||||
), {'embedding_id': embedding_id})
|
)
|
||||||
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
end_at = time.perf_counter()
|
end_at = time.perf_counter()
|
||||||
click.echo(click.style('Cleaned embedding cache from db success latency: {}'.format(end_at - start_at), fg='green'))
|
click.echo(click.style("Cleaned embedding cache from db success latency: {}".format(end_at - start_at), fg="green"))
|
||||||
|
|
|
@ -12,9 +12,9 @@ from extensions.ext_database import db
|
||||||
from models.dataset import Dataset, DatasetQuery, Document
|
from models.dataset import Dataset, DatasetQuery, Document
|
||||||
|
|
||||||
|
|
||||||
@app.celery.task(queue='dataset')
|
@app.celery.task(queue="dataset")
|
||||||
def clean_unused_datasets_task():
|
def clean_unused_datasets_task():
|
||||||
click.echo(click.style('Start clean unused datasets indexes.', fg='green'))
|
click.echo(click.style("Start clean unused datasets indexes.", fg="green"))
|
||||||
clean_days = dify_config.CLEAN_DAY_SETTING
|
clean_days = dify_config.CLEAN_DAY_SETTING
|
||||||
start_at = time.perf_counter()
|
start_at = time.perf_counter()
|
||||||
thirty_days_ago = datetime.datetime.now() - datetime.timedelta(days=clean_days)
|
thirty_days_ago = datetime.datetime.now() - datetime.timedelta(days=clean_days)
|
||||||
|
@ -22,40 +22,44 @@ def clean_unused_datasets_task():
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
# Subquery for counting new documents
|
# Subquery for counting new documents
|
||||||
document_subquery_new = db.session.query(
|
document_subquery_new = (
|
||||||
Document.dataset_id,
|
db.session.query(Document.dataset_id, func.count(Document.id).label("document_count"))
|
||||||
func.count(Document.id).label('document_count')
|
.filter(
|
||||||
).filter(
|
Document.indexing_status == "completed",
|
||||||
Document.indexing_status == 'completed',
|
|
||||||
Document.enabled == True,
|
Document.enabled == True,
|
||||||
Document.archived == False,
|
Document.archived == False,
|
||||||
Document.updated_at > thirty_days_ago
|
Document.updated_at > thirty_days_ago,
|
||||||
).group_by(Document.dataset_id).subquery()
|
)
|
||||||
|
.group_by(Document.dataset_id)
|
||||||
|
.subquery()
|
||||||
|
)
|
||||||
|
|
||||||
# Subquery for counting old documents
|
# Subquery for counting old documents
|
||||||
document_subquery_old = db.session.query(
|
document_subquery_old = (
|
||||||
Document.dataset_id,
|
db.session.query(Document.dataset_id, func.count(Document.id).label("document_count"))
|
||||||
func.count(Document.id).label('document_count')
|
.filter(
|
||||||
).filter(
|
Document.indexing_status == "completed",
|
||||||
Document.indexing_status == 'completed',
|
|
||||||
Document.enabled == True,
|
Document.enabled == True,
|
||||||
Document.archived == False,
|
Document.archived == False,
|
||||||
Document.updated_at < thirty_days_ago
|
Document.updated_at < thirty_days_ago,
|
||||||
).group_by(Document.dataset_id).subquery()
|
)
|
||||||
|
.group_by(Document.dataset_id)
|
||||||
|
.subquery()
|
||||||
|
)
|
||||||
|
|
||||||
# Main query with join and filter
|
# Main query with join and filter
|
||||||
datasets = (db.session.query(Dataset)
|
datasets = (
|
||||||
.outerjoin(
|
db.session.query(Dataset)
|
||||||
document_subquery_new, Dataset.id == document_subquery_new.c.dataset_id
|
.outerjoin(document_subquery_new, Dataset.id == document_subquery_new.c.dataset_id)
|
||||||
).outerjoin(
|
.outerjoin(document_subquery_old, Dataset.id == document_subquery_old.c.dataset_id)
|
||||||
document_subquery_old, Dataset.id == document_subquery_old.c.dataset_id
|
.filter(
|
||||||
).filter(
|
|
||||||
Dataset.created_at < thirty_days_ago,
|
Dataset.created_at < thirty_days_ago,
|
||||||
func.coalesce(document_subquery_new.c.document_count, 0) == 0,
|
func.coalesce(document_subquery_new.c.document_count, 0) == 0,
|
||||||
func.coalesce(document_subquery_old.c.document_count, 0) > 0
|
func.coalesce(document_subquery_old.c.document_count, 0) > 0,
|
||||||
).order_by(
|
)
|
||||||
Dataset.created_at.desc()
|
.order_by(Dataset.created_at.desc())
|
||||||
).paginate(page=page, per_page=50))
|
.paginate(page=page, per_page=50)
|
||||||
|
)
|
||||||
|
|
||||||
except NotFound:
|
except NotFound:
|
||||||
break
|
break
|
||||||
|
@ -63,10 +67,11 @@ def clean_unused_datasets_task():
|
||||||
break
|
break
|
||||||
page += 1
|
page += 1
|
||||||
for dataset in datasets:
|
for dataset in datasets:
|
||||||
dataset_query = db.session.query(DatasetQuery).filter(
|
dataset_query = (
|
||||||
DatasetQuery.created_at > thirty_days_ago,
|
db.session.query(DatasetQuery)
|
||||||
DatasetQuery.dataset_id == dataset.id
|
.filter(DatasetQuery.created_at > thirty_days_ago, DatasetQuery.dataset_id == dataset.id)
|
||||||
).all()
|
.all()
|
||||||
|
)
|
||||||
if not dataset_query or len(dataset_query) == 0:
|
if not dataset_query or len(dataset_query) == 0:
|
||||||
try:
|
try:
|
||||||
# remove index
|
# remove index
|
||||||
|
@ -74,17 +79,14 @@ def clean_unused_datasets_task():
|
||||||
index_processor.clean(dataset, None)
|
index_processor.clean(dataset, None)
|
||||||
|
|
||||||
# update document
|
# update document
|
||||||
update_params = {
|
update_params = {Document.enabled: False}
|
||||||
Document.enabled: False
|
|
||||||
}
|
|
||||||
|
|
||||||
Document.query.filter_by(dataset_id=dataset.id).update(update_params)
|
Document.query.filter_by(dataset_id=dataset.id).update(update_params)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
click.echo(click.style('Cleaned unused dataset {} from db success!'.format(dataset.id),
|
click.echo(click.style("Cleaned unused dataset {} from db success!".format(dataset.id), fg="green"))
|
||||||
fg='green'))
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
click.echo(
|
click.echo(
|
||||||
click.style('clean dataset index error: {} {}'.format(e.__class__.__name__, str(e)),
|
click.style("clean dataset index error: {} {}".format(e.__class__.__name__, str(e)), fg="red")
|
||||||
fg='red'))
|
)
|
||||||
end_at = time.perf_counter()
|
end_at = time.perf_counter()
|
||||||
click.echo(click.style('Cleaned unused dataset from db success latency: {}'.format(end_at - start_at), fg='green'))
|
click.echo(click.style("Cleaned unused dataset from db success latency: {}".format(end_at - start_at), fg="green"))
|
||||||
|
|
|
@ -11,5 +11,8 @@ fi
|
||||||
# run ruff linter
|
# run ruff linter
|
||||||
ruff check --fix ./api
|
ruff check --fix ./api
|
||||||
|
|
||||||
|
# run ruff formatter
|
||||||
|
ruff format ./api
|
||||||
|
|
||||||
# run dotenv-linter linter
|
# run dotenv-linter linter
|
||||||
dotenv-linter ./api/.env.example ./web/.env.example
|
dotenv-linter ./api/.env.example ./web/.env.example
|
||||||
|
|
Loading…
Reference in New Issue
Block a user