Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/add-remote-file-upload-api #9906

Merged
merged 20 commits into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
0f077d7
refactor(api): Move setup_required import to wraps module across mult…
laipz8200 Oct 26, 2024
18a5df4
feat(api): Add custom error classes for file handling and update file…
laipz8200 Oct 26, 2024
46f7853
fix(api): Validate text and name parameters in document upload methods
laipz8200 Oct 26, 2024
ee455b7
feat(api): Add RemoteFileUploadApi for uploading remote files
laipz8200 Oct 26, 2024
ba72dad
refactor(api): Rename file directory and update resource paths in con…
laipz8200 Oct 26, 2024
144c5ca
feat(api): Implement RemoteFileUploadApi and add resource routes for …
laipz8200 Oct 26, 2024
94f2b89
fix(api): Update source validation to default to None instead of rais…
laipz8200 Oct 26, 2024
c6f1f1f
feat(api): Add file_fields to RemoteFileUploadApi for consistent resp…
laipz8200 Oct 26, 2024
1c10179
feat(api): Add helper functions for file info extraction and validati…
laipz8200 Oct 28, 2024
7246a99
feat(api): Update RemoteFileUploadApi to use file_fields_with_signed_…
laipz8200 Oct 28, 2024
4501c71
feat(upload_files): add source_url attribute to track file origins
laipz8200 Nov 1, 2024
e24a311
feat(models): change _inputs column type to JSON for better data stru…
laipz8200 Nov 1, 2024
f72ea6e
fix(migrations): Fix old migrations.
laipz8200 Nov 1, 2024
8a82665
chore(migrations): rename index of conversation variables
laipz8200 Nov 1, 2024
618bf99
chore(migrations): Update upload_files.source_url
laipz8200 Nov 1, 2024
72b9fa5
chore(migrations): Change `custom_disclaimer` from VARCHAR to TEXT
laipz8200 Nov 1, 2024
02e8940
chore(migrations): update workflows graph and features, enforce non-n…
laipz8200 Nov 1, 2024
ad1ec76
chore(migrations): update custom_disclaimer to default to empty strin…
laipz8200 Nov 1, 2024
a5a0327
chore(migrations): set default values for graph and features in workf…
laipz8200 Nov 1, 2024
8366683
fix(file_factory): update remote_url to use source_url from row data
laipz8200 Nov 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions api/controllers/common/errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from werkzeug.exceptions import HTTPException


class FilenameNotExistsError(HTTPException):
code = 400
description = "The specified filename does not exist."
58 changes: 58 additions & 0 deletions api/controllers/common/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import mimetypes
import os
import re
import urllib.parse
from uuid import uuid4

import httpx
from pydantic import BaseModel


class FileInfo(BaseModel):
filename: str
extension: str
mimetype: str
size: int


def guess_file_info_from_response(response: httpx.Response):
url = str(response.url)
# Try to extract filename from URL
parsed_url = urllib.parse.urlparse(url)
url_path = parsed_url.path
filename = os.path.basename(url_path)

# If filename couldn't be extracted, use Content-Disposition header
if not filename:
content_disposition = response.headers.get("Content-Disposition")
if content_disposition:
filename_match = re.search(r'filename="?(.+)"?', content_disposition)
if filename_match:
filename = filename_match.group(1)

# If still no filename, generate a unique one
if not filename:
unique_name = str(uuid4())
filename = f"{unique_name}"

# Guess MIME type from filename first, then URL
mimetype, _ = mimetypes.guess_type(filename)
if mimetype is None:
mimetype, _ = mimetypes.guess_type(url)
if mimetype is None:
# If guessing fails, use Content-Type from response headers
mimetype = response.headers.get("Content-Type", "application/octet-stream")

extension = os.path.splitext(filename)[1]

# Ensure filename has an extension
if not extension:
extension = mimetypes.guess_extension(mimetype) or ".bin"
filename = f"{filename}{extension}"

return FileInfo(
filename=filename,
extension=extension,
mimetype=mimetype,
size=int(response.headers.get("Content-Length", -1)),
)
13 changes: 12 additions & 1 deletion api/controllers/console/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,21 @@

from libs.external_api import ExternalApi

from .files import FileApi, FilePreviewApi, FileSupportTypeApi
from .remote_files import RemoteFileInfoApi, RemoteFileUploadApi

bp = Blueprint("console", __name__, url_prefix="/console/api")
api = ExternalApi(bp)

# File
api.add_resource(FileApi, "/files/upload")
api.add_resource(FilePreviewApi, "/files/<uuid:file_id>/preview")
api.add_resource(FileSupportTypeApi, "/files/support-type")

# Remote files
api.add_resource(RemoteFileInfoApi, "/remote-files/<path:url>")
api.add_resource(RemoteFileUploadApi, "/remote-files/upload")

# Import other controllers
from . import admin, apikey, extension, feature, ping, setup, version

Expand Down Expand Up @@ -43,7 +55,6 @@
datasets_document,
datasets_segments,
external,
file,
hit_testing,
website,
)
Expand Down
3 changes: 1 addition & 2 deletions api/controllers/console/apikey.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
from models.model import ApiToken, App

from . import api
from .setup import setup_required
from .wraps import account_initialization_required
from .wraps import account_initialization_required, setup_required

api_key_fields = {
"id": fields.String,
Expand Down
3 changes: 1 addition & 2 deletions api/controllers/console/app/advanced_prompt_template.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
from flask_restful import Resource, reqparse

from controllers.console import api
from controllers.console.setup import setup_required
from controllers.console.wraps import account_initialization_required
from controllers.console.wraps import account_initialization_required, setup_required
from libs.login import login_required
from services.advanced_prompt_template_service import AdvancedPromptTemplateService

Expand Down
3 changes: 1 addition & 2 deletions api/controllers/console/app/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

from controllers.console import api
from controllers.console.app.wraps import get_app_model
from controllers.console.setup import setup_required
from controllers.console.wraps import account_initialization_required
from controllers.console.wraps import account_initialization_required, setup_required
from libs.helper import uuid_value
from libs.login import login_required
from models.model import AppMode
Expand Down
7 changes: 5 additions & 2 deletions api/controllers/console/app/annotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
from controllers.console import api
from controllers.console.app.error import NoFileUploadedError
from controllers.console.datasets.error import TooManyFilesError
from controllers.console.setup import setup_required
from controllers.console.wraps import account_initialization_required, cloud_edition_billing_resource_check
from controllers.console.wraps import (
account_initialization_required,
cloud_edition_billing_resource_check,
setup_required,
)
from extensions.ext_redis import redis_client
from fields.annotation_fields import (
annotation_fields,
Expand Down
7 changes: 5 additions & 2 deletions api/controllers/console/app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@

from controllers.console import api
from controllers.console.app.wraps import get_app_model
from controllers.console.setup import setup_required
from controllers.console.wraps import account_initialization_required, cloud_edition_billing_resource_check
from controllers.console.wraps import (
account_initialization_required,
cloud_edition_billing_resource_check,
setup_required,
)
from core.ops.ops_trace_manager import OpsTraceManager
from fields.app_fields import (
app_detail_fields,
Expand Down
3 changes: 1 addition & 2 deletions api/controllers/console/app/audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@
UnsupportedAudioTypeError,
)
from controllers.console.app.wraps import get_app_model
from controllers.console.setup import setup_required
from controllers.console.wraps import account_initialization_required
from controllers.console.wraps import account_initialization_required, setup_required
from core.errors.error import ModelCurrentlyNotSupportError, ProviderTokenNotInitError, QuotaExceededError
from core.model_runtime.errors.invoke import InvokeError
from libs.login import login_required
Expand Down
3 changes: 1 addition & 2 deletions api/controllers/console/app/completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
ProviderQuotaExceededError,
)
from controllers.console.app.wraps import get_app_model
from controllers.console.setup import setup_required
from controllers.console.wraps import account_initialization_required
from controllers.console.wraps import account_initialization_required, setup_required
from controllers.web.error import InvokeRateLimitError as InvokeRateLimitHttpError
from core.app.apps.base_app_queue_manager import AppQueueManager
from core.app.entities.app_invoke_entities import InvokeFrom
Expand Down
3 changes: 1 addition & 2 deletions api/controllers/console/app/conversation.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@

from controllers.console import api
from controllers.console.app.wraps import get_app_model
from controllers.console.setup import setup_required
from controllers.console.wraps import account_initialization_required
from controllers.console.wraps import account_initialization_required, setup_required
from core.app.entities.app_invoke_entities import InvokeFrom
from extensions.ext_database import db
from fields.conversation_fields import (
Expand Down
3 changes: 1 addition & 2 deletions api/controllers/console/app/conversation_variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

from controllers.console import api
from controllers.console.app.wraps import get_app_model
from controllers.console.setup import setup_required
from controllers.console.wraps import account_initialization_required
from controllers.console.wraps import account_initialization_required, setup_required
from extensions.ext_database import db
from fields.conversation_variable_fields import paginated_conversation_variable_fields
from libs.login import login_required
Expand Down
3 changes: 1 addition & 2 deletions api/controllers/console/app/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
ProviderNotInitializeError,
ProviderQuotaExceededError,
)
from controllers.console.setup import setup_required
from controllers.console.wraps import account_initialization_required
from controllers.console.wraps import account_initialization_required, setup_required
from core.errors.error import ModelCurrentlyNotSupportError, ProviderTokenNotInitError, QuotaExceededError
from core.llm_generator.llm_generator import LLMGenerator
from core.model_runtime.errors.invoke import InvokeError
Expand Down
7 changes: 5 additions & 2 deletions api/controllers/console/app/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@
)
from controllers.console.app.wraps import get_app_model
from controllers.console.explore.error import AppSuggestedQuestionsAfterAnswerDisabledError
from controllers.console.setup import setup_required
from controllers.console.wraps import account_initialization_required, cloud_edition_billing_resource_check
from controllers.console.wraps import (
account_initialization_required,
cloud_edition_billing_resource_check,
setup_required,
)
from core.app.entities.app_invoke_entities import InvokeFrom
from core.errors.error import ModelCurrentlyNotSupportError, ProviderTokenNotInitError, QuotaExceededError
from core.model_runtime.errors.invoke import InvokeError
Expand Down
3 changes: 1 addition & 2 deletions api/controllers/console/app/model_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@

from controllers.console import api
from controllers.console.app.wraps import get_app_model
from controllers.console.setup import setup_required
from controllers.console.wraps import account_initialization_required
from controllers.console.wraps import account_initialization_required, setup_required
from core.agent.entities import AgentToolEntity
from core.tools.tool_manager import ToolManager
from core.tools.utils.configuration import ToolParameterConfigurationManager
Expand Down
3 changes: 1 addition & 2 deletions api/controllers/console/app/ops_trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

from controllers.console import api
from controllers.console.app.error import TracingConfigCheckError, TracingConfigIsExist, TracingConfigNotExist
from controllers.console.setup import setup_required
from controllers.console.wraps import account_initialization_required
from controllers.console.wraps import account_initialization_required, setup_required
from libs.login import login_required
from services.ops_service import OpsService

Expand Down
3 changes: 1 addition & 2 deletions api/controllers/console/app/site.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
from constants.languages import supported_language
from controllers.console import api
from controllers.console.app.wraps import get_app_model
from controllers.console.setup import setup_required
from controllers.console.wraps import account_initialization_required
from controllers.console.wraps import account_initialization_required, setup_required
from extensions.ext_database import db
from fields.app_fields import app_site_fields
from libs.login import login_required
Expand Down
3 changes: 1 addition & 2 deletions api/controllers/console/app/statistic.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@

from controllers.console import api
from controllers.console.app.wraps import get_app_model
from controllers.console.setup import setup_required
from controllers.console.wraps import account_initialization_required
from controllers.console.wraps import account_initialization_required, setup_required
from extensions.ext_database import db
from libs.helper import DatetimeString
from libs.login import login_required
Expand Down
3 changes: 1 addition & 2 deletions api/controllers/console/app/workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
from controllers.console import api
from controllers.console.app.error import ConversationCompletedError, DraftWorkflowNotExist, DraftWorkflowNotSync
from controllers.console.app.wraps import get_app_model
from controllers.console.setup import setup_required
from controllers.console.wraps import account_initialization_required
from controllers.console.wraps import account_initialization_required, setup_required
from core.app.apps.base_app_queue_manager import AppQueueManager
from core.app.entities.app_invoke_entities import InvokeFrom
from factories import variable_factory
Expand Down
3 changes: 1 addition & 2 deletions api/controllers/console/app/workflow_app_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@

from controllers.console import api
from controllers.console.app.wraps import get_app_model
from controllers.console.setup import setup_required
from controllers.console.wraps import account_initialization_required
from controllers.console.wraps import account_initialization_required, setup_required
from fields.workflow_app_log_fields import workflow_app_log_pagination_fields
from libs.login import login_required
from models import App
Expand Down
3 changes: 1 addition & 2 deletions api/controllers/console/app/workflow_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@

from controllers.console import api
from controllers.console.app.wraps import get_app_model
from controllers.console.setup import setup_required
from controllers.console.wraps import account_initialization_required
from controllers.console.wraps import account_initialization_required, setup_required
from fields.workflow_run_fields import (
advanced_chat_workflow_run_pagination_fields,
workflow_run_detail_fields,
Expand Down
3 changes: 1 addition & 2 deletions api/controllers/console/app/workflow_statistic.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@

from controllers.console import api
from controllers.console.app.wraps import get_app_model
from controllers.console.setup import setup_required
from controllers.console.wraps import account_initialization_required
from controllers.console.wraps import account_initialization_required, setup_required
from extensions.ext_database import db
from libs.helper import DatetimeString
from libs.login import login_required
Expand Down
3 changes: 1 addition & 2 deletions api/controllers/console/auth/data_source_bearer_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
from libs.login import login_required
from services.auth.api_key_auth_service import ApiKeyAuthService

from ..setup import setup_required
from ..wraps import account_initialization_required
from ..wraps import account_initialization_required, setup_required


class ApiKeyAuthDataSource(Resource):
Expand Down
3 changes: 1 addition & 2 deletions api/controllers/console/auth/data_source_oauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
from libs.login import login_required
from libs.oauth_data_source import NotionOAuth

from ..setup import setup_required
from ..wraps import account_initialization_required
from ..wraps import account_initialization_required, setup_required


def get_oauth_providers():
Expand Down
2 changes: 1 addition & 1 deletion api/controllers/console/auth/forgot_password.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
PasswordMismatchError,
)
from controllers.console.error import EmailSendIpLimitError, NotAllowedRegister
from controllers.console.setup import setup_required
from controllers.console.wraps import setup_required
from events.tenant_event import tenant_was_created
from extensions.ext_database import db
from libs.helper import email, extract_remote_ip
Expand Down
2 changes: 1 addition & 1 deletion api/controllers/console/auth/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
NotAllowedCreateWorkspace,
NotAllowedRegister,
)
from controllers.console.setup import setup_required
from controllers.console.wraps import setup_required
from events.tenant_event import tenant_was_created
from libs.helper import email, extract_remote_ip
from libs.password import valid_password
Expand Down
3 changes: 1 addition & 2 deletions api/controllers/console/billing/billing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
from flask_restful import Resource, reqparse

from controllers.console import api
from controllers.console.setup import setup_required
from controllers.console.wraps import account_initialization_required, only_edition_cloud
from controllers.console.wraps import account_initialization_required, only_edition_cloud, setup_required
from libs.login import login_required
from services.billing_service import BillingService

Expand Down
3 changes: 1 addition & 2 deletions api/controllers/console/datasets/data_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
from werkzeug.exceptions import NotFound

from controllers.console import api
from controllers.console.setup import setup_required
from controllers.console.wraps import account_initialization_required
from controllers.console.wraps import account_initialization_required, setup_required
from core.indexing_runner import IndexingRunner
from core.rag.extractor.entity.extract_setting import ExtractSetting
from core.rag.extractor.notion_extractor import NotionExtractor
Expand Down
3 changes: 1 addition & 2 deletions api/controllers/console/datasets/datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
from controllers.console.apikey import api_key_fields, api_key_list
from controllers.console.app.error import ProviderNotInitializeError
from controllers.console.datasets.error import DatasetInUseError, DatasetNameDuplicateError, IndexingEstimateError
from controllers.console.setup import setup_required
from controllers.console.wraps import account_initialization_required
from controllers.console.wraps import account_initialization_required, setup_required
from core.errors.error import LLMBadRequestError, ProviderTokenNotInitError
from core.indexing_runner import IndexingRunner
from core.model_runtime.entities.model_entities import ModelType
Expand Down
7 changes: 5 additions & 2 deletions api/controllers/console/datasets/datasets_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@
InvalidActionError,
InvalidMetadataError,
)
from controllers.console.setup import setup_required
from controllers.console.wraps import account_initialization_required, cloud_edition_billing_resource_check
from controllers.console.wraps import (
account_initialization_required,
cloud_edition_billing_resource_check,
setup_required,
)
from core.errors.error import (
LLMBadRequestError,
ModelCurrentlyNotSupportError,
Expand Down
2 changes: 1 addition & 1 deletion api/controllers/console/datasets/datasets_segments.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
from controllers.console import api
from controllers.console.app.error import ProviderNotInitializeError
from controllers.console.datasets.error import InvalidActionError, NoFileUploadedError, TooManyFilesError
from controllers.console.setup import setup_required
from controllers.console.wraps import (
account_initialization_required,
cloud_edition_billing_knowledge_limit_check,
cloud_edition_billing_resource_check,
setup_required,
)
from core.errors.error import LLMBadRequestError, ProviderTokenNotInitError
from core.model_manager import ModelManager
Expand Down
Loading