Merge branch 'feat/r2' into deploy/rag-dev

This commit is contained in:
jyong 2025-06-18 11:06:37 +08:00
commit fa9f0ebfb1
13 changed files with 53 additions and 66 deletions

View File

@ -163,7 +163,7 @@ def exchange_token_for_existing_web_user(app_code: str, enterprise_user_decoded:
) )
db.session.add(end_user) db.session.add(end_user)
db.session.commit() db.session.commit()
exp_dt = datetime.now(UTC) + timedelta(hours=dify_config.ACCESS_TOKEN_EXPIRE_MINUTES * 24) exp_dt = datetime.now(UTC) + timedelta(minutes=dify_config.ACCESS_TOKEN_EXPIRE_MINUTES)
exp = int(exp_dt.timestamp()) exp = int(exp_dt.timestamp())
payload = { payload = {
"iss": site.id, "iss": site.id,

View File

@ -32,6 +32,7 @@ from core.repositories.sqlalchemy_workflow_execution_repository import SQLAlchem
from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository
from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository
from extensions.ext_database import db from extensions.ext_database import db
from libs.flask_utils import preserve_flask_contexts
from models import Account, EndUser, Workflow, WorkflowNodeExecutionTriggeredFrom from models import Account, EndUser, Workflow, WorkflowNodeExecutionTriggeredFrom
from models.dataset import Document, DocumentPipelineExecutionLog, Pipeline from models.dataset import Document, DocumentPipelineExecutionLog, Pipeline
from models.enums import WorkflowRunTriggeredFrom from models.enums import WorkflowRunTriggeredFrom
@ -209,25 +210,22 @@ class PipelineGenerator(BaseAppGenerator):
# run in child thread # run in child thread
context = contextvars.copy_context() context = contextvars.copy_context()
@copy_current_request_context worker_thread = threading.Thread(
def worker_with_context(): target=self._generate,
# Run the worker within the copied context kwargs={
return context.run( "flask_app": current_app._get_current_object(), # type: ignore
self._generate, "context": context,
flask_app=current_app._get_current_object(), # type: ignore "pipeline": pipeline,
context=context, "workflow_id": workflow.id,
pipeline=pipeline, "user": user,
workflow_id=workflow.id, "application_generate_entity": application_generate_entity,
user=user, "invoke_from": invoke_from,
application_generate_entity=application_generate_entity, "workflow_execution_repository": workflow_execution_repository,
invoke_from=invoke_from, "workflow_node_execution_repository": workflow_node_execution_repository,
workflow_execution_repository=workflow_execution_repository, "streaming": streaming,
workflow_node_execution_repository=workflow_node_execution_repository, "workflow_thread_pool_id": workflow_thread_pool_id,
streaming=streaming, },
workflow_thread_pool_id=workflow_thread_pool_id, )
)
worker_thread = threading.Thread(target=worker_with_context)
worker_thread.start() worker_thread.start()
# return batch, dataset, documents # return batch, dataset, documents
@ -282,23 +280,7 @@ class PipelineGenerator(BaseAppGenerator):
:param streaming: is stream :param streaming: is stream
:param workflow_thread_pool_id: workflow thread pool id :param workflow_thread_pool_id: workflow thread pool id
""" """
print("jin ru la 1") with preserve_flask_contexts(flask_app, context_vars=context):
for var, val in context.items():
var.set(val)
# FIXME(-LAN-): Save current user before entering new app context
from flask import g
saved_user = None
if has_request_context() and hasattr(g, "_login_user"):
saved_user = g._login_user
with flask_app.app_context():
# Restore user in new app context
print("jin ru la 2")
if saved_user is not None:
from flask import g
g._login_user = saved_user
# init queue manager # init queue manager
workflow = db.session.query(Workflow).filter(Workflow.id == workflow_id).first() workflow = db.session.query(Workflow).filter(Workflow.id == workflow_id).first()
if not workflow: if not workflow:
@ -311,20 +293,17 @@ class PipelineGenerator(BaseAppGenerator):
) )
context = contextvars.copy_context() context = contextvars.copy_context()
@copy_current_request_context
def worker_with_context():
# Run the worker within the copied context
return context.run(
self._generate_worker,
flask_app=current_app._get_current_object(), # type: ignore
context=context,
queue_manager=queue_manager,
application_generate_entity=application_generate_entity,
workflow_thread_pool_id=workflow_thread_pool_id,
)
# new thread # new thread
worker_thread = threading.Thread(target=worker_with_context) worker_thread = threading.Thread(
target=self._generate_worker,
kwargs={
"flask_app": current_app._get_current_object(), # type: ignore
"context": context,
"queue_manager": queue_manager,
"application_generate_entity": application_generate_entity,
"workflow_thread_pool_id": workflow_thread_pool_id,
},
)
worker_thread.start() worker_thread.start()
@ -521,20 +500,9 @@ class PipelineGenerator(BaseAppGenerator):
:param workflow_thread_pool_id: workflow thread pool id :param workflow_thread_pool_id: workflow thread pool id
:return: :return:
""" """
print("jin ru la 3")
for var, val in context.items():
var.set(val)
from flask import g
saved_user = None with preserve_flask_contexts(flask_app, context_vars=context):
if has_request_context() and hasattr(g, "_login_user"):
saved_user = g._login_user
with flask_app.app_context():
try: try:
if saved_user is not None:
from flask import g
g._login_user = saved_user
# workflow app # workflow app
runner = PipelineRunner( runner = PipelineRunner(
application_generate_entity=application_generate_entity, application_generate_entity=application_generate_entity,

View File

@ -41,6 +41,12 @@ class WeaviateVector(BaseVector):
weaviate.connect.connection.has_grpc = False weaviate.connect.connection.has_grpc = False
# Fix to minimize the performance impact of the deprecation check in weaviate-client 3.24.0,
# by changing the connection timeout to pypi.org from 1 second to 0.001 seconds.
# TODO: This can be removed once weaviate-client is updated to 3.26.7 or higher,
# which does not contain the deprecation check.
weaviate.connect.connection.PYPI_TIMEOUT = 0.001
try: try:
client = weaviate.Client( client = weaviate.Client(
url=config.endpoint, auth_client_secret=auth_config, timeout_config=(5, 60), startup_period=None url=config.endpoint, auth_client_secret=auth_config, timeout_config=(5, 60), startup_period=None

View File

@ -214,7 +214,7 @@ class AgentNode(ToolNode):
) )
if tool_runtime.entity.description: if tool_runtime.entity.description:
tool_runtime.entity.description.llm = ( tool_runtime.entity.description.llm = (
extra.get("descrption", "") or tool_runtime.entity.description.llm extra.get("description", "") or tool_runtime.entity.description.llm
) )
for tool_runtime_params in tool_runtime.entity.parameters: for tool_runtime_params in tool_runtime.entity.parameters:
tool_runtime_params.form = ( tool_runtime_params.form = (

View File

@ -31,10 +31,13 @@ const TestApi: FC<Props> = ({
const language = getLanguage(locale) const language = getLanguage(locale)
const [credentialsModalShow, setCredentialsModalShow] = useState(false) const [credentialsModalShow, setCredentialsModalShow] = useState(false)
const [tempCredential, setTempCredential] = React.useState<Credential>(customCollection.credentials) const [tempCredential, setTempCredential] = React.useState<Credential>(customCollection.credentials)
const [testing, setTesting] = useState(false)
const [result, setResult] = useState<string>('') const [result, setResult] = useState<string>('')
const { operation_id: toolName, parameters } = tool const { operation_id: toolName, parameters } = tool
const [parametersValue, setParametersValue] = useState<Record<string, string>>({}) const [parametersValue, setParametersValue] = useState<Record<string, string>>({})
const handleTest = async () => { const handleTest = async () => {
if (testing) return
setTesting(true)
// clone test schema // clone test schema
const credentials = JSON.parse(JSON.stringify(tempCredential)) as Credential const credentials = JSON.parse(JSON.stringify(tempCredential)) as Credential
if (credentials.auth_type === AuthType.none) { if (credentials.auth_type === AuthType.none) {
@ -52,6 +55,7 @@ const TestApi: FC<Props> = ({
} }
const res = await testAPIAvailable(data) as any const res = await testAPIAvailable(data) as any
setResult(res.error || res.result) setResult(res.error || res.result)
setTesting(false)
} }
return ( return (
@ -107,7 +111,7 @@ const TestApi: FC<Props> = ({
</div> </div>
</div> </div>
<Button variant='primary' className=' mt-4 h-10 w-full' onClick={handleTest}>{t('tools.test.title')}</Button> <Button variant='primary' className=' mt-4 h-10 w-full' loading={testing} disabled={testing} onClick={handleTest}>{t('tools.test.title')}</Button>
<div className='mt-6'> <div className='mt-6'>
<div className='flex items-center space-x-3'> <div className='flex items-center space-x-3'>
<div className='system-xs-semibold text-text-tertiary'>{t('tools.test.testResult')}</div> <div className='system-xs-semibold text-text-tertiary'>{t('tools.test.testResult')}</div>

View File

@ -118,6 +118,7 @@ export const AgentStrategy = memo((props: AgentStrategyProps) => {
title={<> title={<>
{renderI18nObject(def.label)} {def.required && <span className='text-red-500'>*</span>} {renderI18nObject(def.label)} {def.required && <span className='text-red-500'>*</span>}
</>} </>}
key={def.variable}
tooltip={def.tooltip && renderI18nObject(def.tooltip)} tooltip={def.tooltip && renderI18nObject(def.tooltip)}
inline inline
> >

View File

@ -140,6 +140,7 @@ const CodeEditor: FC<Props> = ({
language={languageMap[language] || 'javascript'} language={languageMap[language] || 'javascript'}
theme={isMounted ? theme : 'default-theme'} // sometimes not load the default theme theme={isMounted ? theme : 'default-theme'} // sometimes not load the default theme
value={outPutValue} value={outPutValue}
loading={<span className='text-text-primary'>Loading...</span>}
onChange={handleEditorChange} onChange={handleEditorChange}
// https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IEditorOptions.html // https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IEditorOptions.html
options={{ options={{

View File

@ -54,9 +54,9 @@ const AgentNode: FC<NodeProps<AgentNodeType>> = (props) => {
const field = param.name const field = param.name
const value = inputs.agent_parameters?.[field]?.value const value = inputs.agent_parameters?.[field]?.value
if (value) { if (value) {
(value as unknown as any[]).forEach((item) => { (value as unknown as any[]).forEach((item, idx) => {
tools.push({ tools.push({
id: `${param.name}-${i}`, id: `${param.name}-${idx}`,
providerName: item.provider_name, providerName: item.provider_name,
}) })
}) })

View File

@ -207,6 +207,7 @@ const translation = {
modelNotSupportedTip: 'El modelo actual no admite esta función y se degrada automáticamente a inyección de comandos.', modelNotSupportedTip: 'El modelo actual no admite esta función y se degrada automáticamente a inyección de comandos.',
structuredTip: 'Las Salidas Estructuradas son una función que garantiza que el modelo siempre generará respuestas que se ajusten a su esquema JSON proporcionado.', structuredTip: 'Las Salidas Estructuradas son una función que garantiza que el modelo siempre generará respuestas que se ajusten a su esquema JSON proporcionado.',
modelNotSupported: 'Modelo no soportado', modelNotSupported: 'Modelo no soportado',
structured: 'sistemático',
}, },
accessItemsDescription: { accessItemsDescription: {
anyone: 'Cualquiera puede acceder a la aplicación web.', anyone: 'Cualquiera puede acceder a la aplicación web.',

View File

@ -202,6 +202,7 @@ const translation = {
builtInDescription: 'Los metadatos integrados se extraen y generan automáticamente. Deben estar habilitados antes de su uso y no se pueden editar.', builtInDescription: 'Los metadatos integrados se extraen y generan automáticamente. Deben estar habilitados antes de su uso y no se pueden editar.',
name: 'Nombre', name: 'Nombre',
description: 'Puedes gestionar todos los metadatos en este conocimiento aquí. Las modificaciones se sincronizarán en todos los documentos.', description: 'Puedes gestionar todos los metadatos en este conocimiento aquí. Las modificaciones se sincronizarán en todos los documentos.',
disabled: 'desactivar',
}, },
documentMetadata: { documentMetadata: {
technicalParameters: 'Parámetros técnicos', technicalParameters: 'Parámetros técnicos',

View File

@ -188,6 +188,7 @@ const translation = {
nodeResize: '노드 크기 조정됨', nodeResize: '노드 크기 조정됨',
nodeDragStop: '노드가 이동했습니다.', nodeDragStop: '노드가 이동했습니다.',
edgeDelete: '노드가 연결이 끊어졌습니다.', edgeDelete: '노드가 연결이 끊어졌습니다.',
nodeTitleChange: '노드 제목이 변경됨',
}, },
errorMsg: { errorMsg: {
fieldRequired: '{{field}}가 필요합니다', fieldRequired: '{{field}}가 필요합니다',

View File

@ -188,6 +188,7 @@ const translation = {
nodeDescriptionChange: 'Descrierea nodului a fost modificată', nodeDescriptionChange: 'Descrierea nodului a fost modificată',
edgeDelete: 'Nod deconectat', edgeDelete: 'Nod deconectat',
nodeAdd: 'Nod adăugat', nodeAdd: 'Nod adăugat',
nodeDragStop: 'Nod mutat',
}, },
errorMsg: { errorMsg: {
fieldRequired: '{{field}} este obligatoriu', fieldRequired: '{{field}} este obligatoriu',

View File

@ -112,6 +112,7 @@ const translation = {
pointerMode: 'Način s kazalcem', pointerMode: 'Način s kazalcem',
autoSaved: 'Samodejno shranjeno', autoSaved: 'Samodejno shranjeno',
configure: 'Konfiguriraj', configure: 'Konfiguriraj',
inRunMode: 'V načinu izvajanja',
}, },
env: { env: {
modal: { modal: {
@ -185,6 +186,7 @@ const translation = {
clearHistory: 'Počisti zgodovino', clearHistory: 'Počisti zgodovino',
hintText: 'Vaša dejanja urejanja so sledena v zgodovini sprememb, ki se hrani na vaši napravi za čas trajanja te seje. Ta zgodovina bo izbrisana, ko zapustite urejevalnik.', hintText: 'Vaša dejanja urejanja so sledena v zgodovini sprememb, ki se hrani na vaši napravi za čas trajanja te seje. Ta zgodovina bo izbrisana, ko zapustite urejevalnik.',
placeholder: 'Še niste spremenili ničesar.', placeholder: 'Še niste spremenili ničesar.',
stepForward_one: '{{count}} korak naprej',
}, },
errorMsg: { errorMsg: {
fields: { fields: {
@ -836,6 +838,7 @@ const translation = {
upload_file_id: 'Naložite ID datoteke', upload_file_id: 'Naložite ID datoteke',
title: 'datoteke, ki jih je ustvaril agent', title: 'datoteke, ki jih je ustvaril agent',
url: 'URL slike', url: 'URL slike',
transfer_method: 'Metoda prenosa. Vrednost je remote_url ali local_file.',
}, },
json: 'agent generiran json', json: 'agent generiran json',
text: 'vsebina, ki jo je ustvaril agent', text: 'vsebina, ki jo je ustvaril agent',