mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-08-14 12:45:59 +08:00
chore: cleanup and rearrange unclassified configs into feature config groups (#7586)
This commit is contained in:
parent
e3d7c7c6f9
commit
3ace01cfb3
@ -1,4 +1,3 @@
|
|||||||
from pydantic import Field, computed_field
|
|
||||||
from pydantic_settings import SettingsConfigDict
|
from pydantic_settings import SettingsConfigDict
|
||||||
|
|
||||||
from configs.deploy import DeploymentConfig
|
from configs.deploy import DeploymentConfig
|
||||||
@ -24,8 +23,6 @@ class DifyConfig(
|
|||||||
# **Before using, please contact business@dify.ai by email to inquire about licensing matters.**
|
# **Before using, please contact business@dify.ai by email to inquire about licensing matters.**
|
||||||
EnterpriseFeatureConfig,
|
EnterpriseFeatureConfig,
|
||||||
):
|
):
|
||||||
DEBUG: bool = Field(default=False, description='whether to enable debug mode.')
|
|
||||||
|
|
||||||
model_config = SettingsConfigDict(
|
model_config = SettingsConfigDict(
|
||||||
# read from dotenv format config file
|
# read from dotenv format config file
|
||||||
env_file='.env',
|
env_file='.env',
|
||||||
@ -35,33 +32,7 @@ class DifyConfig(
|
|||||||
extra='ignore',
|
extra='ignore',
|
||||||
)
|
)
|
||||||
|
|
||||||
CODE_MAX_NUMBER: int = 9223372036854775807
|
# Before adding any config,
|
||||||
CODE_MIN_NUMBER: int = -9223372036854775808
|
# please consider to arrange it in the proper config group of existed or added
|
||||||
CODE_MAX_DEPTH: int = 5
|
# for better readability and maintainability.
|
||||||
CODE_MAX_PRECISION: int = 20
|
# Thanks for your concentration and consideration.
|
||||||
CODE_MAX_STRING_LENGTH: int = 80000
|
|
||||||
CODE_MAX_STRING_ARRAY_LENGTH: int = 30
|
|
||||||
CODE_MAX_OBJECT_ARRAY_LENGTH: int = 30
|
|
||||||
CODE_MAX_NUMBER_ARRAY_LENGTH: int = 1000
|
|
||||||
|
|
||||||
HTTP_REQUEST_MAX_CONNECT_TIMEOUT: int = 300
|
|
||||||
HTTP_REQUEST_MAX_READ_TIMEOUT: int = 600
|
|
||||||
HTTP_REQUEST_MAX_WRITE_TIMEOUT: int = 600
|
|
||||||
HTTP_REQUEST_NODE_MAX_BINARY_SIZE: int = 1024 * 1024 * 10
|
|
||||||
|
|
||||||
@computed_field
|
|
||||||
def HTTP_REQUEST_NODE_READABLE_MAX_BINARY_SIZE(self) -> str:
|
|
||||||
return f'{self.HTTP_REQUEST_NODE_MAX_BINARY_SIZE / 1024 / 1024:.2f}MB'
|
|
||||||
|
|
||||||
HTTP_REQUEST_NODE_MAX_TEXT_SIZE: int = 1024 * 1024
|
|
||||||
|
|
||||||
@computed_field
|
|
||||||
def HTTP_REQUEST_NODE_READABLE_MAX_TEXT_SIZE(self) -> str:
|
|
||||||
return f'{self.HTTP_REQUEST_NODE_MAX_TEXT_SIZE / 1024 / 1024:.2f}MB'
|
|
||||||
|
|
||||||
SSRF_PROXY_HTTP_URL: str | None = None
|
|
||||||
SSRF_PROXY_HTTPS_URL: str | None = None
|
|
||||||
|
|
||||||
MODERATION_BUFFER_SIZE: int = Field(default=300, description='The buffer size for moderation.')
|
|
||||||
|
|
||||||
MAX_VARIABLE_SIZE: int = Field(default=5 * 1024, description='The maximum size of a variable. default is 5KB.')
|
|
||||||
|
@ -11,6 +11,11 @@ class DeploymentConfig(BaseSettings):
|
|||||||
default='langgenius/dify',
|
default='langgenius/dify',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
DEBUG: bool = Field(
|
||||||
|
description='whether to enable debug mode.',
|
||||||
|
default=False,
|
||||||
|
)
|
||||||
|
|
||||||
TESTING: bool = Field(
|
TESTING: bool = Field(
|
||||||
description='',
|
description='',
|
||||||
default=False,
|
default=False,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from pydantic import AliasChoices, Field, NonNegativeInt, PositiveInt, computed_field
|
from pydantic import AliasChoices, Field, NegativeInt, NonNegativeInt, PositiveInt, computed_field
|
||||||
from pydantic_settings import BaseSettings
|
from pydantic_settings import BaseSettings
|
||||||
|
|
||||||
from configs.feature.hosted_service import HostedServiceConfig
|
from configs.feature.hosted_service import HostedServiceConfig
|
||||||
@ -52,6 +52,46 @@ class CodeExecutionSandboxConfig(BaseSettings):
|
|||||||
default='dify-sandbox',
|
default='dify-sandbox',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
CODE_MAX_NUMBER: PositiveInt = Field(
|
||||||
|
description='max depth for code execution',
|
||||||
|
default=9223372036854775807,
|
||||||
|
)
|
||||||
|
|
||||||
|
CODE_MIN_NUMBER: NegativeInt = Field(
|
||||||
|
description='',
|
||||||
|
default=-9223372036854775807,
|
||||||
|
)
|
||||||
|
|
||||||
|
CODE_MAX_DEPTH: PositiveInt = Field(
|
||||||
|
description='max depth for code execution',
|
||||||
|
default=5,
|
||||||
|
)
|
||||||
|
|
||||||
|
CODE_MAX_PRECISION: PositiveInt = Field(
|
||||||
|
description='max precision digits for float type in code execution',
|
||||||
|
default=20,
|
||||||
|
)
|
||||||
|
|
||||||
|
CODE_MAX_STRING_LENGTH: PositiveInt = Field(
|
||||||
|
description='max string length for code execution',
|
||||||
|
default=80000,
|
||||||
|
)
|
||||||
|
|
||||||
|
CODE_MAX_STRING_ARRAY_LENGTH: PositiveInt = Field(
|
||||||
|
description='',
|
||||||
|
default=30,
|
||||||
|
)
|
||||||
|
|
||||||
|
CODE_MAX_OBJECT_ARRAY_LENGTH: PositiveInt = Field(
|
||||||
|
description='',
|
||||||
|
default=30,
|
||||||
|
)
|
||||||
|
|
||||||
|
CODE_MAX_NUMBER_ARRAY_LENGTH: PositiveInt = Field(
|
||||||
|
description='',
|
||||||
|
default=1000,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class EndpointConfig(BaseSettings):
|
class EndpointConfig(BaseSettings):
|
||||||
"""
|
"""
|
||||||
@ -157,6 +197,41 @@ class HttpConfig(BaseSettings):
|
|||||||
def WEB_API_CORS_ALLOW_ORIGINS(self) -> list[str]:
|
def WEB_API_CORS_ALLOW_ORIGINS(self) -> list[str]:
|
||||||
return self.inner_WEB_API_CORS_ALLOW_ORIGINS.split(',')
|
return self.inner_WEB_API_CORS_ALLOW_ORIGINS.split(',')
|
||||||
|
|
||||||
|
HTTP_REQUEST_MAX_CONNECT_TIMEOUT: NonNegativeInt = Field(
|
||||||
|
description='',
|
||||||
|
default=300,
|
||||||
|
)
|
||||||
|
|
||||||
|
HTTP_REQUEST_MAX_READ_TIMEOUT: NonNegativeInt = Field(
|
||||||
|
description='',
|
||||||
|
default=600,
|
||||||
|
)
|
||||||
|
|
||||||
|
HTTP_REQUEST_MAX_WRITE_TIMEOUT: NonNegativeInt = Field(
|
||||||
|
description='',
|
||||||
|
default=600,
|
||||||
|
)
|
||||||
|
|
||||||
|
HTTP_REQUEST_NODE_MAX_BINARY_SIZE: PositiveInt = Field(
|
||||||
|
description='',
|
||||||
|
default=10 * 1024 * 1024,
|
||||||
|
)
|
||||||
|
|
||||||
|
HTTP_REQUEST_NODE_MAX_TEXT_SIZE: PositiveInt = Field(
|
||||||
|
description='',
|
||||||
|
default=1 * 1024 * 1024,
|
||||||
|
)
|
||||||
|
|
||||||
|
SSRF_PROXY_HTTP_URL: Optional[str] = Field(
|
||||||
|
description='HTTP URL for SSRF proxy',
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
SSRF_PROXY_HTTPS_URL: Optional[str] = Field(
|
||||||
|
description='HTTPS URL for SSRF proxy',
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class InnerAPIConfig(BaseSettings):
|
class InnerAPIConfig(BaseSettings):
|
||||||
"""
|
"""
|
||||||
@ -255,6 +330,11 @@ class WorkflowConfig(BaseSettings):
|
|||||||
default=5,
|
default=5,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
MAX_VARIABLE_SIZE: PositiveInt = Field(
|
||||||
|
description='The maximum size in bytes of a variable. default to 5KB.',
|
||||||
|
default=5 * 1024,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class OAuthConfig(BaseSettings):
|
class OAuthConfig(BaseSettings):
|
||||||
"""
|
"""
|
||||||
@ -291,8 +371,7 @@ class ModerationConfig(BaseSettings):
|
|||||||
Moderation in app configs.
|
Moderation in app configs.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# todo: to be clarified in usage and unit
|
MODERATION_BUFFER_SIZE: PositiveInt = Field(
|
||||||
OUTPUT_MODERATION_BUFFER_SIZE: PositiveInt = Field(
|
|
||||||
description='buffer size for moderation',
|
description='buffer size for moderation',
|
||||||
default=300,
|
default=300,
|
||||||
)
|
)
|
||||||
@ -444,7 +523,6 @@ class CeleryBeatConfig(BaseSettings):
|
|||||||
|
|
||||||
|
|
||||||
class PositionConfig(BaseSettings):
|
class PositionConfig(BaseSettings):
|
||||||
|
|
||||||
POSITION_PROVIDER_PINS: str = Field(
|
POSITION_PROVIDER_PINS: str = Field(
|
||||||
description='The heads of model providers',
|
description='The heads of model providers',
|
||||||
default='',
|
default='',
|
||||||
|
@ -11,15 +11,6 @@ from core.workflow.nodes.base_node import BaseNode
|
|||||||
from core.workflow.nodes.code.entities import CodeNodeData
|
from core.workflow.nodes.code.entities import CodeNodeData
|
||||||
from models.workflow import WorkflowNodeExecutionStatus
|
from models.workflow import WorkflowNodeExecutionStatus
|
||||||
|
|
||||||
MAX_NUMBER = dify_config.CODE_MAX_NUMBER
|
|
||||||
MIN_NUMBER = dify_config.CODE_MIN_NUMBER
|
|
||||||
MAX_PRECISION = dify_config.CODE_MAX_PRECISION
|
|
||||||
MAX_DEPTH = dify_config.CODE_MAX_DEPTH
|
|
||||||
MAX_STRING_LENGTH = dify_config.CODE_MAX_STRING_LENGTH
|
|
||||||
MAX_STRING_ARRAY_LENGTH = dify_config.CODE_MAX_STRING_ARRAY_LENGTH
|
|
||||||
MAX_OBJECT_ARRAY_LENGTH = dify_config.CODE_MAX_OBJECT_ARRAY_LENGTH
|
|
||||||
MAX_NUMBER_ARRAY_LENGTH = dify_config.CODE_MAX_NUMBER_ARRAY_LENGTH
|
|
||||||
|
|
||||||
|
|
||||||
class CodeNode(BaseNode):
|
class CodeNode(BaseNode):
|
||||||
_node_data_cls = CodeNodeData
|
_node_data_cls = CodeNodeData
|
||||||
@ -97,8 +88,9 @@ class CodeNode(BaseNode):
|
|||||||
else:
|
else:
|
||||||
raise ValueError(f"Output variable `{variable}` must be a string")
|
raise ValueError(f"Output variable `{variable}` must be a string")
|
||||||
|
|
||||||
if len(value) > MAX_STRING_LENGTH:
|
if len(value) > dify_config.CODE_MAX_STRING_ARRAY_LENGTH:
|
||||||
raise ValueError(f'The length of output variable `{variable}` must be less than {MAX_STRING_LENGTH} characters')
|
raise ValueError(f'The length of output variable `{variable}` must be'
|
||||||
|
f' less than {dify_config.CODE_MAX_STRING_ARRAY_LENGTH} characters')
|
||||||
|
|
||||||
return value.replace('\x00', '')
|
return value.replace('\x00', '')
|
||||||
|
|
||||||
@ -115,13 +107,15 @@ class CodeNode(BaseNode):
|
|||||||
else:
|
else:
|
||||||
raise ValueError(f"Output variable `{variable}` must be a number")
|
raise ValueError(f"Output variable `{variable}` must be a number")
|
||||||
|
|
||||||
if value > MAX_NUMBER or value < MIN_NUMBER:
|
if value > dify_config.CODE_MAX_NUMBER or value < dify_config.CODE_MIN_NUMBER:
|
||||||
raise ValueError(f'Output variable `{variable}` is out of range, it must be between {MIN_NUMBER} and {MAX_NUMBER}.')
|
raise ValueError(f'Output variable `{variable}` is out of range,'
|
||||||
|
f' it must be between {dify_config.CODE_MIN_NUMBER} and {dify_config.CODE_MAX_NUMBER}.')
|
||||||
|
|
||||||
if isinstance(value, float):
|
if isinstance(value, float):
|
||||||
# raise error if precision is too high
|
# raise error if precision is too high
|
||||||
if len(str(value).split('.')[1]) > MAX_PRECISION:
|
if len(str(value).split('.')[1]) > dify_config.CODE_MAX_PRECISION:
|
||||||
raise ValueError(f'Output variable `{variable}` has too high precision, it must be less than {MAX_PRECISION} digits.')
|
raise ValueError(f'Output variable `{variable}` has too high precision,'
|
||||||
|
f' it must be less than {dify_config.CODE_MAX_PRECISION} digits.')
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@ -134,8 +128,8 @@ class CodeNode(BaseNode):
|
|||||||
:param output_schema: output schema
|
:param output_schema: output schema
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
if depth > MAX_DEPTH:
|
if depth > dify_config.CODE_MAX_DEPTH:
|
||||||
raise ValueError("Depth limit reached, object too deep.")
|
raise ValueError(f"Depth limit ${dify_config.CODE_MAX_DEPTH} reached, object too deep.")
|
||||||
|
|
||||||
transformed_result = {}
|
transformed_result = {}
|
||||||
if output_schema is None:
|
if output_schema is None:
|
||||||
@ -235,9 +229,10 @@ class CodeNode(BaseNode):
|
|||||||
f'Output {prefix}{dot}{output_name} is not an array, got {type(result.get(output_name))} instead.'
|
f'Output {prefix}{dot}{output_name} is not an array, got {type(result.get(output_name))} instead.'
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if len(result[output_name]) > MAX_NUMBER_ARRAY_LENGTH:
|
if len(result[output_name]) > dify_config.CODE_MAX_NUMBER_ARRAY_LENGTH:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f'The length of output variable `{prefix}{dot}{output_name}` must be less than {MAX_NUMBER_ARRAY_LENGTH} elements.'
|
f'The length of output variable `{prefix}{dot}{output_name}` must be'
|
||||||
|
f' less than {dify_config.CODE_MAX_NUMBER_ARRAY_LENGTH} elements.'
|
||||||
)
|
)
|
||||||
|
|
||||||
transformed_result[output_name] = [
|
transformed_result[output_name] = [
|
||||||
@ -257,9 +252,10 @@ class CodeNode(BaseNode):
|
|||||||
f'Output {prefix}{dot}{output_name} is not an array, got {type(result.get(output_name))} instead.'
|
f'Output {prefix}{dot}{output_name} is not an array, got {type(result.get(output_name))} instead.'
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if len(result[output_name]) > MAX_STRING_ARRAY_LENGTH:
|
if len(result[output_name]) > dify_config.CODE_MAX_STRING_ARRAY_LENGTH:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f'The length of output variable `{prefix}{dot}{output_name}` must be less than {MAX_STRING_ARRAY_LENGTH} elements.'
|
f'The length of output variable `{prefix}{dot}{output_name}` must be'
|
||||||
|
f' less than {dify_config.CODE_MAX_STRING_ARRAY_LENGTH} elements.'
|
||||||
)
|
)
|
||||||
|
|
||||||
transformed_result[output_name] = [
|
transformed_result[output_name] = [
|
||||||
@ -279,9 +275,10 @@ class CodeNode(BaseNode):
|
|||||||
f'Output {prefix}{dot}{output_name} is not an array, got {type(result.get(output_name))} instead.'
|
f'Output {prefix}{dot}{output_name} is not an array, got {type(result.get(output_name))} instead.'
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if len(result[output_name]) > MAX_OBJECT_ARRAY_LENGTH:
|
if len(result[output_name]) > dify_config.CODE_MAX_OBJECT_ARRAY_LENGTH:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f'The length of output variable `{prefix}{dot}{output_name}` must be less than {MAX_OBJECT_ARRAY_LENGTH} elements.'
|
f'The length of output variable `{prefix}{dot}{output_name}` must be'
|
||||||
|
f' less than {dify_config.CODE_MAX_OBJECT_ARRAY_LENGTH} elements.'
|
||||||
)
|
)
|
||||||
|
|
||||||
for i, value in enumerate(result[output_name]):
|
for i, value in enumerate(result[output_name]):
|
||||||
|
@ -18,11 +18,6 @@ from core.workflow.nodes.http_request.entities import (
|
|||||||
)
|
)
|
||||||
from core.workflow.utils.variable_template_parser import VariableTemplateParser
|
from core.workflow.utils.variable_template_parser import VariableTemplateParser
|
||||||
|
|
||||||
MAX_BINARY_SIZE = dify_config.HTTP_REQUEST_NODE_MAX_BINARY_SIZE
|
|
||||||
READABLE_MAX_BINARY_SIZE = dify_config.HTTP_REQUEST_NODE_READABLE_MAX_BINARY_SIZE
|
|
||||||
MAX_TEXT_SIZE = dify_config.HTTP_REQUEST_NODE_MAX_TEXT_SIZE
|
|
||||||
READABLE_MAX_TEXT_SIZE = dify_config.HTTP_REQUEST_NODE_READABLE_MAX_TEXT_SIZE
|
|
||||||
|
|
||||||
|
|
||||||
class HttpExecutorResponse:
|
class HttpExecutorResponse:
|
||||||
headers: dict[str, str]
|
headers: dict[str, str]
|
||||||
@ -237,16 +232,14 @@ class HttpExecutor:
|
|||||||
else:
|
else:
|
||||||
raise ValueError(f'Invalid response type {type(response)}')
|
raise ValueError(f'Invalid response type {type(response)}')
|
||||||
|
|
||||||
if executor_response.is_file:
|
threshold_size = dify_config.HTTP_REQUEST_NODE_MAX_BINARY_SIZE if executor_response.is_file \
|
||||||
if executor_response.size > MAX_BINARY_SIZE:
|
else dify_config.HTTP_REQUEST_NODE_MAX_TEXT_SIZE
|
||||||
raise ValueError(
|
if executor_response.size > threshold_size:
|
||||||
f'File size is too large, max size is {READABLE_MAX_BINARY_SIZE}, but current size is {executor_response.readable_size}.'
|
raise ValueError(
|
||||||
)
|
f'{"File" if executor_response.is_file else "Text"} size is too large,'
|
||||||
else:
|
f' max size is {threshold_size / 1024 / 1024:.2f} MB,'
|
||||||
if executor_response.size > MAX_TEXT_SIZE:
|
f' but current size is {executor_response.readable_size}.'
|
||||||
raise ValueError(
|
)
|
||||||
f'Text size is too large, max size is {READABLE_MAX_TEXT_SIZE}, but current size is {executor_response.readable_size}.'
|
|
||||||
)
|
|
||||||
|
|
||||||
return executor_response
|
return executor_response
|
||||||
|
|
||||||
|
9
api/poetry.lock
generated
9
api/poetry.lock
generated
@ -6372,13 +6372,13 @@ semver = ["semver (>=3.0.2)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pydantic-settings"
|
name = "pydantic-settings"
|
||||||
version = "2.3.4"
|
version = "2.4.0"
|
||||||
description = "Settings management using Pydantic"
|
description = "Settings management using Pydantic"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "pydantic_settings-2.3.4-py3-none-any.whl", hash = "sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a"},
|
{file = "pydantic_settings-2.4.0-py3-none-any.whl", hash = "sha256:bb6849dc067f1687574c12a639e231f3a6feeed0a12d710c1382045c5db1c315"},
|
||||||
{file = "pydantic_settings-2.3.4.tar.gz", hash = "sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7"},
|
{file = "pydantic_settings-2.4.0.tar.gz", hash = "sha256:ed81c3a0f46392b4d7c0a565c05884e6e54b3456e6f0fe4d8814981172dc9a88"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -6386,6 +6386,7 @@ pydantic = ">=2.7.0"
|
|||||||
python-dotenv = ">=0.21.0"
|
python-dotenv = ">=0.21.0"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
|
azure-key-vault = ["azure-identity (>=1.16.0)", "azure-keyvault-secrets (>=4.8.0)"]
|
||||||
toml = ["tomli (>=2.0.1)"]
|
toml = ["tomli (>=2.0.1)"]
|
||||||
yaml = ["pyyaml (>=6.0.1)"]
|
yaml = ["pyyaml (>=6.0.1)"]
|
||||||
|
|
||||||
@ -9633,4 +9634,4 @@ cffi = ["cffi (>=1.11)"]
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = ">=3.10,<3.13"
|
python-versions = ">=3.10,<3.13"
|
||||||
content-hash = "69c20af8ecacced3cca092662223a1511acaf65cb2616a5a1e38b498223463e0"
|
content-hash = "d7336115709114c2a4ff09b392f717e9c3547ae82b6a111d0c885c7a44269f02"
|
||||||
|
@ -162,7 +162,7 @@ pandas = { version = "~2.2.2", extras = ["performance", "excel"] }
|
|||||||
psycopg2-binary = "~2.9.6"
|
psycopg2-binary = "~2.9.6"
|
||||||
pycryptodome = "3.19.1"
|
pycryptodome = "3.19.1"
|
||||||
pydantic = "~2.8.2"
|
pydantic = "~2.8.2"
|
||||||
pydantic-settings = "~2.3.4"
|
pydantic-settings = "~2.4.0"
|
||||||
pydantic_extra_types = "~2.9.0"
|
pydantic_extra_types = "~2.9.0"
|
||||||
pyjwt = "~2.8.0"
|
pyjwt = "~2.8.0"
|
||||||
pypdfium2 = "~4.17.0"
|
pypdfium2 = "~4.17.0"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user