Переглянути джерело

Merge branch 'main' into feat/rag-2

tags/2.0.0-beta.1
twwu 2 місяці тому
джерело
коміт
85fd97e090
100 змінених файлів з 247 додано та 1246 видалено
  1. 1
    1
      .devcontainer/post_create_command.sh
  2. 0
    68
      README.md
  3. 0
    68
      README_AR.md
  4. 0
    68
      README_BN.md
  5. 0
    68
      README_CN.md
  6. 0
    68
      README_DE.md
  7. 0
    68
      README_ES.md
  8. 0
    68
      README_FR.md
  9. 0
    68
      README_JA.md
  10. 0
    68
      README_KL.md
  11. 0
    68
      README_KR.md
  12. 0
    68
      README_PT.md
  13. 0
    68
      README_SI.md
  14. 0
    68
      README_TR.md
  15. 0
    68
      README_TW.md
  16. 0
    68
      README_VI.md
  17. 12
    4
      api/README.md
  18. 5
    3
      api/app_factory.py
  19. 20
    1
      api/controllers/common/fields.py
  20. 0
    1
      api/controllers/console/__init__.py
  21. 1
    1
      api/controllers/console/admin.py
  22. 5
    5
      api/controllers/console/apikey.py
  23. 1
    1
      api/controllers/console/app/advanced_prompt_template.py
  24. 1
    1
      api/controllers/console/app/agent.py
  25. 1
    1
      api/controllers/console/app/annotation.py
  26. 1
    1
      api/controllers/console/app/app.py
  27. 1
    1
      api/controllers/console/app/app_import.py
  28. 1
    1
      api/controllers/console/app/audio.py
  29. 1
    1
      api/controllers/console/app/completion.py
  30. 14
    24
      api/controllers/console/app/conversation.py
  31. 1
    1
      api/controllers/console/app/conversation_variables.py
  32. 1
    1
      api/controllers/console/app/generator.py
  33. 1
    1
      api/controllers/console/app/mcp_server.py
  34. 2
    2
      api/controllers/console/app/message.py
  35. 1
    1
      api/controllers/console/app/model_config.py
  36. 1
    1
      api/controllers/console/app/ops_trace.py
  37. 1
    1
      api/controllers/console/app/site.py
  38. 1
    1
      api/controllers/console/app/statistic.py
  39. 1
    1
      api/controllers/console/app/workflow.py
  40. 2
    2
      api/controllers/console/app/workflow_app_log.py
  41. 1
    1
      api/controllers/console/app/workflow_draft_variable.py
  42. 2
    2
      api/controllers/console/app/workflow_run.py
  43. 1
    1
      api/controllers/console/app/workflow_statistic.py
  44. 1
    1
      api/controllers/console/auth/activate.py
  45. 1
    1
      api/controllers/console/auth/data_source_bearer_auth.py
  46. 1
    1
      api/controllers/console/auth/data_source_oauth.py
  47. 1
    1
      api/controllers/console/auth/forgot_password.py
  48. 2
    2
      api/controllers/console/auth/login.py
  49. 1
    1
      api/controllers/console/auth/oauth.py
  50. 1
    1
      api/controllers/console/billing/billing.py
  51. 1
    1
      api/controllers/console/billing/compliance.py
  52. 1
    1
      api/controllers/console/datasets/data_source.py
  53. 4
    4
      api/controllers/console/datasets/datasets.py
  54. 1
    1
      api/controllers/console/datasets/datasets_document.py
  55. 13
    3
      api/controllers/console/datasets/datasets_segments.py
  56. 1
    1
      api/controllers/console/datasets/external.py
  57. 1
    1
      api/controllers/console/datasets/hit_testing.py
  58. 1
    1
      api/controllers/console/datasets/hit_testing_base.py
  59. 1
    1
      api/controllers/console/datasets/metadata.py
  60. 0
    62
      api/controllers/console/datasets/upload_file.py
  61. 1
    1
      api/controllers/console/datasets/website.py
  62. 1
    1
      api/controllers/console/explore/audio.py
  63. 1
    1
      api/controllers/console/explore/completion.py
  64. 2
    2
      api/controllers/console/explore/conversation.py
  65. 1
    1
      api/controllers/console/explore/installed_app.py
  66. 2
    2
      api/controllers/console/explore/message.py
  67. 1
    1
      api/controllers/console/explore/parameter.py
  68. 1
    1
      api/controllers/console/explore/recommended_app.py
  69. 2
    2
      api/controllers/console/explore/saved_message.py
  70. 1
    1
      api/controllers/console/explore/workflow.py
  71. 1
    1
      api/controllers/console/explore/wraps.py
  72. 1
    1
      api/controllers/console/extension.py
  73. 1
    1
      api/controllers/console/feature.py
  74. 1
    1
      api/controllers/console/files.py
  75. 1
    1
      api/controllers/console/init_validate.py
  76. 1
    1
      api/controllers/console/ping.py
  77. 1
    1
      api/controllers/console/remote_files.py
  78. 1
    1
      api/controllers/console/setup.py
  79. 3
    3
      api/controllers/console/tag/tags.py
  80. 1
    1
      api/controllers/console/version.py
  81. 1
    1
      api/controllers/console/workspace/account.py
  82. 1
    1
      api/controllers/console/workspace/agent_providers.py
  83. 1
    1
      api/controllers/console/workspace/endpoint.py
  84. 1
    1
      api/controllers/console/workspace/load_balancing_config.py
  85. 1
    1
      api/controllers/console/workspace/members.py
  86. 1
    1
      api/controllers/console/workspace/model_providers.py
  87. 1
    1
      api/controllers/console/workspace/models.py
  88. 1
    1
      api/controllers/console/workspace/plugin.py
  89. 1
    1
      api/controllers/console/workspace/tool_providers.py
  90. 1
    1
      api/controllers/console/workspace/workspace.py
  91. 13
    2
      api/controllers/files/__init__.py
  92. 5
    7
      api/controllers/files/image_preview.py
  93. 4
    6
      api/controllers/files/tool_files.py
  94. 60
    24
      api/controllers/files/upload.py
  95. 1
    1
      api/controllers/inner_api/mail.py
  96. 1
    1
      api/controllers/inner_api/plugin/plugin.py
  97. 1
    1
      api/controllers/inner_api/plugin/wraps.py
  98. 1
    1
      api/controllers/inner_api/workspace/workspace.py
  99. 13
    1
      api/controllers/mcp/__init__.py
  100. 0
    0
      api/controllers/mcp/mcp.py

+ 1
- 1
.devcontainer/post_create_command.sh Переглянути файл

@@ -1,6 +1,6 @@
#!/bin/bash

npm add -g pnpm@10.13.1
npm add -g pnpm@10.15.0
cd web && pnpm install
pipx install uv


+ 0
- 68
README.md Переглянути файл

@@ -107,74 +107,6 @@ Monitor and analyze application logs and performance over time. You could contin
**7. Backend-as-a-Service**:
All of Dify's offerings come with corresponding APIs, so you could effortlessly integrate Dify into your own business logic.

## Feature Comparison

<table style="width: 100%;">
<tr>
<th align="center">Feature</th>
<th align="center">Dify.AI</th>
<th align="center">LangChain</th>
<th align="center">Flowise</th>
<th align="center">OpenAI Assistants API</th>
</tr>
<tr>
<td align="center">Programming Approach</td>
<td align="center">API + App-oriented</td>
<td align="center">Python Code</td>
<td align="center">App-oriented</td>
<td align="center">API-oriented</td>
</tr>
<tr>
<td align="center">Supported LLMs</td>
<td align="center">Rich Variety</td>
<td align="center">Rich Variety</td>
<td align="center">Rich Variety</td>
<td align="center">OpenAI-only</td>
</tr>
<tr>
<td align="center">RAG Engine</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">Agent</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">Workflow</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Observability</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Enterprise Feature (SSO/Access control)</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Local Deployment</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
</table>

## Using Dify

- **Cloud </br>**

+ 0
- 68
README_AR.md Переглянути файл

@@ -68,74 +68,6 @@

**7.الواجهة الخلفية (Backend) كخدمة**: تأتي جميع عروض Dify مع APIs مطابقة، حتى يمكنك دمج Dify بسهولة في منطق أعمالك الخاص.

## مقارنة الميزات

<table style="width: 100%;">
<tr>
<th align="center">الميزة</th>
<th align="center">Dify.AI</th>
<th align="center">LangChain</th>
<th align="center">Flowise</th>
<th align="center">OpenAI Assistants API</th>
</tr>
<tr>
<td align="center">نهج البرمجة</td>
<td align="center">موجّه لـ تطبيق + واجهة برمجة تطبيق (API)</td>
<td align="center">برمجة Python</td>
<td align="center">موجه لتطبيق</td>
<td align="center">واجهة برمجة تطبيق (API)</td>
</tr>
<tr>
<td align="center">LLMs المدعومة</td>
<td align="center">تنوع غني</td>
<td align="center">تنوع غني</td>
<td align="center">تنوع غني</td>
<td align="center">فقط OpenAI</td>
</tr>
<tr>
<td align="center">محرك RAG</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">الوكيل</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">سير العمل</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">الملاحظة</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">ميزات الشركات (SSO / مراقبة الوصول)</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">نشر محلي</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
</table>

## استخدام Dify

- **سحابة </br>**

+ 0
- 68
README_BN.md Переглянути файл

@@ -106,74 +106,6 @@ LLM ফাংশন কলিং বা ReAct উপর ভিত্তি ক
**7. ব্যাকএন্ড-অ্যাজ-এ-সার্ভিস**:
ডিফাই-এর সমস্ত অফার সংশ্লিষ্ট API-সহ আছে, যাতে আপনি অনায়াসে ডিফাইকে আপনার নিজস্ব বিজনেস লজিকে ইন্টেগ্রেট করতে পারেন।

## বৈশিষ্ট্য তুলনা

<table style="width: 100%;">
<tr>
<th align="center">বৈশিষ্ট্য</th>
<th align="center">Dify.AI</th>
<th align="center">LangChain</th>
<th align="center">Flowise</th>
<th align="center">OpenAI Assistants API</th>
</tr>
<tr>
<td align="center">প্রোগ্রামিং পদ্ধতি</td>
<td align="center">API + App-oriented</td>
<td align="center">Python Code</td>
<td align="center">App-oriented</td>
<td align="center">API-oriented</td>
</tr>
<tr>
<td align="center">সাপোর্টেড LLMs</td>
<td align="center">Rich Variety</td>
<td align="center">Rich Variety</td>
<td align="center">Rich Variety</td>
<td align="center">OpenAI-only</td>
</tr>
<tr>
<td align="center">RAG ইঞ্জিন</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">এজেন্ট</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">ওয়ার্কফ্লো</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">অবজার্ভেবল</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">এন্টারপ্রাইজ ফিচার (SSO/Access control)</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">লোকাল ডেপ্লয়মেন্ট</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
</table>

## ডিফাই-এর ব্যবহার

- **ক্লাউড </br>**

+ 0
- 68
README_CN.md Переглянути файл

@@ -80,74 +80,6 @@ Dify 是一个开源的 LLM 应用开发平台。其直观的界面结合了 AI
**7. 后端即服务**:
所有 Dify 的功能都带有相应的 API,因此您可以轻松地将 Dify 集成到自己的业务逻辑中。

## 功能比较

<table style="width: 100%;">
<tr>
<th align="center">功能</th>
<th align="center">Dify.AI</th>
<th align="center">LangChain</th>
<th align="center">Flowise</th>
<th align="center">OpenAI Assistant API</th>
</tr>
<tr>
<td align="center">编程方法</td>
<td align="center">API + 应用程序导向</td>
<td align="center">Python 代码</td>
<td align="center">应用程序导向</td>
<td align="center">API 导向</td>
</tr>
<tr>
<td align="center">支持的 LLMs</td>
<td align="center">丰富多样</td>
<td align="center">丰富多样</td>
<td align="center">丰富多样</td>
<td align="center">仅限 OpenAI</td>
</tr>
<tr>
<td align="center">RAG 引擎</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">Agent</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">工作流</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">可观测性</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">企业功能(SSO/访问控制)</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">本地部署</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
</table>

## 使用 Dify

- **云 </br>**

+ 0
- 68
README_DE.md Переглянути файл

@@ -106,74 +106,6 @@ Sie können Agenten basierend auf LLM Function Calling oder ReAct definieren und
**7. Backend-as-a-Service**:
Alle Dify-Angebote kommen mit entsprechenden APIs, sodass Sie Dify mühelos in Ihre eigene Geschäftslogik integrieren können.

## Vergleich der Merkmale

<table style="width: 100%;">
<tr>
<th align="center">Feature</th>
<th align="center">Dify.AI</th>
<th align="center">LangChain</th>
<th align="center">Flowise</th>
<th align="center">OpenAI Assistants API</th>
</tr>
<tr>
<td align="center">Programming Approach</td>
<td align="center">API + App-oriented</td>
<td align="center">Python Code</td>
<td align="center">App-oriented</td>
<td align="center">API-oriented</td>
</tr>
<tr>
<td align="center">Supported LLMs</td>
<td align="center">Rich Variety</td>
<td align="center">Rich Variety</td>
<td align="center">Rich Variety</td>
<td align="center">OpenAI-only</td>
</tr>
<tr>
<td align="center">RAG Engine</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">Agent</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">Workflow</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Observability</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Enterprise Feature (SSO/Access control)</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Local Deployment</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
</table>

## Dify verwenden

- **Cloud </br>**

+ 0
- 68
README_ES.md Переглянути файл

@@ -79,74 +79,6 @@ Supervisa y analiza registros de aplicaciones y rendimiento a lo largo del tiemp
**7. Backend como servicio**:
Todas las ofertas de Dify vienen con APIs correspondientes, por lo que podrías integrar Dify sin esfuerzo en tu propia lógica empresarial.

## Comparación de características

<table style="width: 100%;">
<tr>
<th align="center">Característica</th>
<th align="center">Dify.AI</th>
<th align="center">LangChain</th>
<th align="center">Flowise</th>
<th align="center">API de Asistentes de OpenAI</th>
</tr>
<tr>
<td align="center">Enfoque de programación</td>
<td align="center">API + orientado a la aplicación</td>
<td align="center">Código Python</td>
<td align="center">Orientado a la aplicación</td>
<td align="center">Orientado a la API</td>
</tr>
<tr>
<td align="center">LLMs admitidos</td>
<td align="center">Gran variedad</td>
<td align="center">Gran variedad</td>
<td align="center">Gran variedad</td>
<td align="center">Solo OpenAI</td>
</tr>
<tr>
<td align="center">Motor RAG</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">Agente</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">Flujo de trabajo</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Observabilidad</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Característica empresarial (SSO/Control de acceso)</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Implementación local</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
</table>

## Usando Dify

- **Nube </br>**

+ 0
- 68
README_FR.md Переглянути файл

@@ -79,74 +79,6 @@ Surveillez et analysez les journaux d'application et les performances au fil du
**7. Backend-as-a-Service** :
Toutes les offres de Dify sont accompagnées d'API correspondantes, vous permettant d'intégrer facilement Dify dans votre propre logique métier.

## Comparaison des fonctionnalités

<table style="width: 100%;">
<tr>
<th align="center">Fonctionnalité</th>
<th align="center">Dify.AI</th>
<th align="center">LangChain</th>
<th align="center">Flowise</th>
<th align="center">OpenAI Assistants API</th>
</tr>
<tr>
<td align="center">Approche de programmation</td>
<td align="center">API + Application</td>
<td align="center">Code Python</td>
<td align="center">Application</td>
<td align="center">API</td>
</tr>
<tr>
<td align="center">LLMs pris en charge</td>
<td align="center">Grande variété</td>
<td align="center">Grande variété</td>
<td align="center">Grande variété</td>
<td align="center">Uniquement OpenAI</td>
</tr>
<tr>
<td align="center">Moteur RAG</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">Agent</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">Flux de travail</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Observabilité</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Fonctionnalité d'entreprise (SSO/Contrôle d'accès)</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Déploiement local</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
</table>

## Utiliser Dify

- **Cloud </br>**

+ 0
- 68
README_JA.md Переглянути файл

@@ -80,74 +80,6 @@ LLM Function CallingやReActに基づくエージェントの定義が可能で
**7. Backend-as-a-Service**:
すべての機能はAPIを提供されており、Difyを自分のビジネスロジックに簡単に統合できます。

## 機能比較

<table style="width: 100%;">
<tr>
<th align="center">機能</th>
<th align="center">Dify.AI</th>
<th align="center">LangChain</th>
<th align="center">Flowise</th>
<th align="center">OpenAI Assistants API</th>
</tr>
<tr>
<td align="center">プログラミングアプローチ</td>
<td align="center">API + アプリ指向</td>
<td align="center">Pythonコード</td>
<td align="center">アプリ指向</td>
<td align="center">API指向</td>
</tr>
<tr>
<td align="center">サポートされているLLM</td>
<td align="center">バラエティ豊か</td>
<td align="center">バラエティ豊か</td>
<td align="center">バラエティ豊か</td>
<td align="center">OpenAIのみ</td>
</tr>
<tr>
<td align="center">RAGエンジン</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">エージェント</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">ワークフロー</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">観測性</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">エンタープライズ機能(SSO/アクセス制御)</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">ローカル展開</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
</table>

## Difyの使用方法

- **クラウド </br>**

+ 0
- 68
README_KL.md Переглянути файл

@@ -79,74 +79,6 @@ Monitor and analyze application logs and performance over time. You could contin
**7. Backend-as-a-Service**:
All of Dify's offerings come with corresponding APIs, so you could effortlessly integrate Dify into your own business logic.

## Feature Comparison

<table style="width: 100%;">
<tr>
<th align="center">Feature</th>
<th align="center">Dify.AI</th>
<th align="center">LangChain</th>
<th align="center">Flowise</th>
<th align="center">OpenAI Assistants API</th>
</tr>
<tr>
<td align="center">Programming Approach</td>
<td align="center">API + App-oriented</td>
<td align="center">Python Code</td>
<td align="center">App-oriented</td>
<td align="center">API-oriented</td>
</tr>
<tr>
<td align="center">Supported LLMs</td>
<td align="center">Rich Variety</td>
<td align="center">Rich Variety</td>
<td align="center">Rich Variety</td>
<td align="center">OpenAI-only</td>
</tr>
<tr>
<td align="center">RAG Engine</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">Agent</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">Workflow</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Observability</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Enterprise Feature (SSO/Access control)</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Local Deployment</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
</table>

## Using Dify

- **Cloud </br>**

+ 0
- 68
README_KR.md Переглянути файл

@@ -73,74 +73,6 @@ LLM 함수 호출 또는 ReAct를 기반으로 에이전트를 정의하고 에
**7. Backend-as-a-Service**:
Dify의 모든 제품에는 해당 API가 함께 제공되므로 Dify를 자신의 비즈니스 로직에 쉽게 통합할 수 있습니다.

## 기능 비교

<table style="width: 100%;">
<tr>
<th align="center">기능</th>
<th align="center">Dify.AI</th>
<th align="center">LangChain</th>
<th align="center">Flowise</th>
<th align="center">OpenAI Assistants API</th>
</tr>
<tr>
<td align="center">프로그래밍 접근 방식</td>
<td align="center">API + 앱 중심</td>
<td align="center">Python 코드</td>
<td align="center">앱 중심</td>
<td align="center">API 중심</td>
</tr>
<tr>
<td align="center">지원되는 LLMs</td>
<td align="center">다양한 종류</td>
<td align="center">다양한 종류</td>
<td align="center">다양한 종류</td>
<td align="center">OpenAI 전용</td>
</tr>
<tr>
<td align="center">RAG 엔진</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">에이전트</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">워크플로우</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">가시성</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">기업용 기능 (SSO/접근 제어)</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">로컬 배포</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
</table>

## Dify 사용하기

- **클라우드 </br>**

+ 0
- 68
README_PT.md Переглянути файл

@@ -79,74 +79,6 @@ Monitore e analise os registros e o desempenho do aplicativo ao longo do tempo.
**7. Backend como Serviço**:
Todas os recursos do Dify vêm com APIs correspondentes, permitindo que você integre o Dify sem esforço na lógica de negócios da sua empresa.

## Comparação de recursos

<table style="width: 100%;">
<tr>
<th align="center">Recurso</th>
<th align="center">Dify.AI</th>
<th align="center">LangChain</th>
<th align="center">Flowise</th>
<th align="center">OpenAI Assistants API</th>
</tr>
<tr>
<td align="center">Abordagem de Programação</td>
<td align="center">Orientada a API + Aplicativo</td>
<td align="center">Código Python</td>
<td align="center">Orientada a Aplicativo</td>
<td align="center">Orientada a API</td>
</tr>
<tr>
<td align="center">LLMs Suportados</td>
<td align="center">Variedade Rica</td>
<td align="center">Variedade Rica</td>
<td align="center">Variedade Rica</td>
<td align="center">Apenas OpenAI</td>
</tr>
<tr>
<td align="center">RAG Engine</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">Agente</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">Workflow</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Observabilidade</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Recursos Empresariais (SSO/Controle de Acesso)</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Implantação Local</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
</table>

## Usando o Dify

- **Nuvem </br>**

+ 0
- 68
README_SI.md Переглянути файл

@@ -103,74 +103,6 @@ Spremljajte in analizirajte dnevnike aplikacij in učinkovitost skozi čas. Pozi
**7. Backend-as-a-Service**:
AVse ponudbe Difyja so opremljene z ustreznimi API-ji, tako da lahko Dify brez težav integrirate v svojo poslovno logiko.

## Primerjava Funkcij

<table style="width: 100%;">
<tr>
<th align="center">Funkcija</th>
<th align="center">Dify.AI</th>
<th align="center">LangChain</th>
<th align="center">Flowise</th>
<th align="center">OpenAI Assistants API</th>
</tr>
<tr>
<td align="center">Programski pristop</td>
<td align="center">API + usmerjeno v aplikacije</td>
<td align="center">Python koda</td>
<td align="center">Usmerjeno v aplikacije</td>
<td align="center">Usmerjeno v API</td>
</tr>
<tr>
<td align="center">Podprti LLM-ji</td>
<td align="center">Bogata izbira</td>
<td align="center">Bogata izbira</td>
<td align="center">Bogata izbira</td>
<td align="center">Samo OpenAI</td>
</tr>
<tr>
<td align="center">RAG pogon</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">Agent</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">Potek dela</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Spremljanje</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Funkcija za podjetja (SSO/nadzor dostopa)</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Lokalna namestitev</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
</table>

## Uporaba Dify

- **Cloud </br>**

+ 0
- 68
README_TR.md Переглянути файл

@@ -74,74 +74,6 @@ Uygulama loglarını ve performans metriklerini zaman içinde izleme ve analiz e
**7. Hizmet Olarak Backend**:
Dify'ın tüm özellikleri ilgili API'lerle birlikte gelir, böylece Dify'ı kendi iş mantığınıza kolayca entegre edebilirsiniz.

## Özellik karşılaştırması

<table style="width: 100%;">
<tr>
<th align="center">Özellik</th>
<th align="center">Dify.AI</th>
<th align="center">LangChain</th>
<th align="center">Flowise</th>
<th align="center">OpenAI Assistants API</th>
</tr>
<tr>
<td align="center">Programlama Yaklaşımı</td>
<td align="center">API + Uygulama odaklı</td>
<td align="center">Python Kodu</td>
<td align="center">Uygulama odaklı</td>
<td align="center">API odaklı</td>
</tr>
<tr>
<td align="center">Desteklenen LLM'ler</td>
<td align="center">Zengin Çeşitlilik</td>
<td align="center">Zengin Çeşitlilik</td>
<td align="center">Zengin Çeşitlilik</td>
<td align="center">Yalnızca OpenAI</td>
</tr>
<tr>
<td align="center">RAG Motoru</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">Ajan</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">İş Akışı</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Gözlemlenebilirlik</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Kurumsal Özellikler (SSO/Erişim kontrolü)</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Yerel Dağıtım</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
</table>

## Dify'ı Kullanma

- **Cloud </br>**

+ 0
- 68
README_TW.md Переглянути файл

@@ -106,74 +106,6 @@ docker compose up -d
**7. 後端即服務**:
Dify 的所有功能都提供相應的 API,因此您可以輕鬆地將 Dify 整合到您自己的業務邏輯中。

## 功能比較

<table style="width: 100%;">
<tr>
<th align="center">功能</th>
<th align="center">Dify.AI</th>
<th align="center">LangChain</th>
<th align="center">Flowise</th>
<th align="center">OpenAI Assistants API</th>
</tr>
<tr>
<td align="center">程式設計方法</td>
<td align="center">API + 應用導向</td>
<td align="center">Python 代碼</td>
<td align="center">應用導向</td>
<td align="center">API 導向</td>
</tr>
<tr>
<td align="center">支援的 LLM 模型</td>
<td align="center">豐富多樣</td>
<td align="center">豐富多樣</td>
<td align="center">豐富多樣</td>
<td align="center">僅限 OpenAI</td>
</tr>
<tr>
<td align="center">RAG 引擎</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">代理功能</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">工作流程</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">可觀察性</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">企業級功能 (SSO/存取控制)</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">本地部署</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
</table>

## 使用 Dify

- **雲端服務 </br>**

+ 0
- 68
README_VI.md Переглянути файл

@@ -74,74 +74,6 @@ Giám sát và phân tích nhật ký và hiệu suất ứng dụng theo thời
**7. Backend-as-a-Service**:
Tất cả các dịch vụ của Dify đều đi kèm với các API tương ứng, vì vậy bạn có thể dễ dàng tích hợp Dify vào logic kinh doanh của riêng mình.

## So sánh tính năng

<table style="width: 100%;">
<tr>
<th align="center">Tính năng</th>
<th align="center">Dify.AI</th>
<th align="center">LangChain</th>
<th align="center">Flowise</th>
<th align="center">OpenAI Assistants API</th>
</tr>
<tr>
<td align="center">Phương pháp lập trình</td>
<td align="center">Hướng API + Ứng dụng</td>
<td align="center">Mã Python</td>
<td align="center">Hướng ứng dụng</td>
<td align="center">Hướng API</td>
</tr>
<tr>
<td align="center">LLMs được hỗ trợ</td>
<td align="center">Đa dạng phong phú</td>
<td align="center">Đa dạng phong phú</td>
<td align="center">Đa dạng phong phú</td>
<td align="center">Chỉ OpenAI</td>
</tr>
<tr>
<td align="center">RAG Engine</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">Agent</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
</tr>
<tr>
<td align="center">Quy trình làm việc</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Khả năng quan sát</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Tính năng doanh nghiệp (SSO/Kiểm soát truy cập)</td>
<td align="center">✅</td>
<td align="center">❌</td>
<td align="center">❌</td>
<td align="center">❌</td>
</tr>
<tr>
<td align="center">Triển khai cục bộ</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">❌</td>
</tr>
</table>

## Sử dụng Dify

- **Cloud </br>**

+ 12
- 4
api/README.md Переглянути файл

@@ -80,7 +80,7 @@
1. If you need to handle and debug the async tasks (e.g. dataset importing and documents indexing), please start the worker service.

```bash
uv run celery -A app.celery worker -P gevent -c 1 --loglevel INFO -Q dataset,generation,mail,ops_trace,app_deletion,plugin,workflow_storage
uv run celery -A app.celery worker -P gevent -c 1 --loglevel INFO -Q dataset,generation,mail,ops_trace,app_deletion,plugin,workflow_storage,conversation
```

Addition, if you want to debug the celery scheduled tasks, you can use the following command in another terminal:
@@ -97,8 +97,16 @@ uv run celery -A app.celery beat
uv sync --dev
```

1. Run the tests locally with mocked system environment variables in `tool.pytest_env` section in `pyproject.toml`
1. Run the tests locally with mocked system environment variables in `tool.pytest_env` section in `pyproject.toml`, more can check [Claude.md](../CLAUDE.md)

```bash
uv run -P api bash dev/pytest/pytest_all_tests.sh
```cli
uv run --project api pytest # Run all tests
uv run --project api pytest tests/unit_tests/ # Unit tests only
uv run --project api pytest tests/integration_tests/ # Integration tests

# Code quality
./dev/reformat # Run all formatters and linters
uv run --project api ruff check --fix ./ # Fix linting issues
uv run --project api ruff format ./ # Format code
uv run --project api mypy . # Type checking
```

+ 5
- 3
api/app_factory.py Переглянути файл

@@ -5,6 +5,8 @@ from configs import dify_config
from contexts.wrapper import RecyclableContextVar
from dify_app import DifyApp

logger = logging.getLogger(__name__)


# ----------------------------
# Application Factory Function
@@ -32,7 +34,7 @@ def create_app() -> DifyApp:
initialize_extensions(app)
end_time = time.perf_counter()
if dify_config.DEBUG:
logging.info("Finished create_app (%s ms)", round((end_time - start_time) * 1000, 2))
logger.info("Finished create_app (%s ms)", round((end_time - start_time) * 1000, 2))
return app


@@ -93,14 +95,14 @@ def initialize_extensions(app: DifyApp):
is_enabled = ext.is_enabled() if hasattr(ext, "is_enabled") else True
if not is_enabled:
if dify_config.DEBUG:
logging.info("Skipped %s", short_name)
logger.info("Skipped %s", short_name)
continue

start_time = time.perf_counter()
ext.init_app(app)
end_time = time.perf_counter()
if dify_config.DEBUG:
logging.info("Loaded %s (%s ms)", short_name, round((end_time - start_time) * 1000, 2))
logger.info("Loaded %s (%s ms)", short_name, round((end_time - start_time) * 1000, 2))


def create_migrations_app():

+ 20
- 1
api/controllers/common/fields.py Переглянути файл

@@ -1,4 +1,4 @@
from flask_restful import fields
from flask_restx import Api, Namespace, fields

from libs.helper import AppIconUrlField

@@ -10,6 +10,12 @@ parameters__system_parameters = {
"workflow_file_upload_limit": fields.Integer,
}


def build_system_parameters_model(api_or_ns: Api | Namespace):
"""Build the system parameters model for the API or Namespace."""
return api_or_ns.model("SystemParameters", parameters__system_parameters)


parameters_fields = {
"opening_statement": fields.String,
"suggested_questions": fields.Raw,
@@ -25,6 +31,14 @@ parameters_fields = {
"system_parameters": fields.Nested(parameters__system_parameters),
}


def build_parameters_model(api_or_ns: Api | Namespace):
"""Build the parameters model for the API or Namespace."""
copied_fields = parameters_fields.copy()
copied_fields["system_parameters"] = fields.Nested(build_system_parameters_model(api_or_ns))
return api_or_ns.model("Parameters", copied_fields)


site_fields = {
"title": fields.String,
"chat_color_theme": fields.String,
@@ -41,3 +55,8 @@ site_fields = {
"show_workflow_steps": fields.Boolean,
"use_icon_as_answer_icon": fields.Boolean,
}


def build_site_model(api_or_ns: Api | Namespace):
"""Build the site model for the API or Namespace."""
return api_or_ns.model("Site", site_fields)

+ 0
- 1
api/controllers/console/__init__.py Переглянути файл

@@ -84,7 +84,6 @@ from .datasets import (
external,
hit_testing,
metadata,
upload_file,
website,
)
from .datasets.rag_pipeline import (

+ 1
- 1
api/controllers/console/admin.py Переглянути файл

@@ -1,7 +1,7 @@
from functools import wraps

from flask import request
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from sqlalchemy import select
from sqlalchemy.orm import Session
from werkzeug.exceptions import NotFound, Unauthorized

+ 5
- 5
api/controllers/console/apikey.py Переглянути файл

@@ -1,8 +1,8 @@
from typing import Any, Optional

import flask_restful
import flask_restx
from flask_login import current_user
from flask_restful import Resource, fields, marshal_with
from flask_restx import Resource, fields, marshal_with
from sqlalchemy import select
from sqlalchemy.orm import Session
from werkzeug.exceptions import Forbidden
@@ -40,7 +40,7 @@ def _get_resource(resource_id, tenant_id, resource_model):
).scalar_one_or_none()

if resource is None:
flask_restful.abort(404, message=f"{resource_model.__name__} not found.")
flask_restx.abort(404, message=f"{resource_model.__name__} not found.")

return resource

@@ -81,7 +81,7 @@ class BaseApiKeyListResource(Resource):
)

if current_key_count >= self.max_keys:
flask_restful.abort(
flask_restx.abort(
400,
message=f"Cannot create more than {self.max_keys} API keys for this resource type.",
code="max_keys_exceeded",
@@ -126,7 +126,7 @@ class BaseApiKeyResource(Resource):
)

if key is None:
flask_restful.abort(404, message="API key not found")
flask_restx.abort(404, message="API key not found")

db.session.query(ApiToken).where(ApiToken.id == api_key_id).delete()
db.session.commit()

+ 1
- 1
api/controllers/console/app/advanced_prompt_template.py Переглянути файл

@@ -1,4 +1,4 @@
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse

from controllers.console import api
from controllers.console.wraps import account_initialization_required, setup_required

+ 1
- 1
api/controllers/console/app/agent.py Переглянути файл

@@ -1,4 +1,4 @@
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse

from controllers.console import api
from controllers.console.app.wraps import get_app_model

+ 1
- 1
api/controllers/console/app/annotation.py Переглянути файл

@@ -2,7 +2,7 @@ from typing import Literal

from flask import request
from flask_login import current_user
from flask_restful import Resource, marshal, marshal_with, reqparse
from flask_restx import Resource, marshal, marshal_with, reqparse
from werkzeug.exceptions import Forbidden

from controllers.common.errors import NoFileUploadedError, TooManyFilesError

+ 1
- 1
api/controllers/console/app/app.py Переглянути файл

@@ -2,7 +2,7 @@ import uuid
from typing import cast

from flask_login import current_user
from flask_restful import Resource, inputs, marshal, marshal_with, reqparse
from flask_restx import Resource, inputs, marshal, marshal_with, reqparse
from sqlalchemy import select
from sqlalchemy.orm import Session
from werkzeug.exceptions import BadRequest, Forbidden, abort

+ 1
- 1
api/controllers/console/app/app_import.py Переглянути файл

@@ -1,7 +1,7 @@
from typing import cast

from flask_login import current_user
from flask_restful import Resource, marshal_with, reqparse
from flask_restx import Resource, marshal_with, reqparse
from sqlalchemy.orm import Session
from werkzeug.exceptions import Forbidden


+ 1
- 1
api/controllers/console/app/audio.py Переглянути файл

@@ -1,7 +1,7 @@
import logging

from flask import request
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from werkzeug.exceptions import InternalServerError

import services

+ 1
- 1
api/controllers/console/app/completion.py Переглянути файл

@@ -2,7 +2,7 @@ import logging

import flask_login
from flask import request
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from werkzeug.exceptions import InternalServerError, NotFound

import services

+ 14
- 24
api/controllers/console/app/conversation.py Переглянути файл

@@ -2,8 +2,8 @@ from datetime import datetime

import pytz # pip install pytz
from flask_login import current_user
from flask_restful import Resource, marshal_with, reqparse
from flask_restful.inputs import int_range
from flask_restx import Resource, marshal_with, reqparse
from flask_restx.inputs import int_range
from sqlalchemy import func, or_
from sqlalchemy.orm import joinedload
from werkzeug.exceptions import Forbidden, NotFound
@@ -24,6 +24,8 @@ from libs.helper import DatetimeString
from libs.login import login_required
from models import Conversation, EndUser, Message, MessageAnnotation
from models.model import AppMode
from services.conversation_service import ConversationService
from services.errors.conversation import ConversationNotExistsError


class CompletionConversationApi(Resource):
@@ -46,7 +48,9 @@ class CompletionConversationApi(Resource):
parser.add_argument("limit", type=int_range(1, 100), default=20, location="args")
args = parser.parse_args()

query = db.select(Conversation).where(Conversation.app_id == app_model.id, Conversation.mode == "completion")
query = db.select(Conversation).where(
Conversation.app_id == app_model.id, Conversation.mode == "completion", Conversation.is_deleted.is_(False)
)

if args["keyword"]:
query = query.join(Message, Message.conversation_id == Conversation.id).where(
@@ -119,18 +123,11 @@ class CompletionConversationDetailApi(Resource):
raise Forbidden()
conversation_id = str(conversation_id)

conversation = (
db.session.query(Conversation)
.where(Conversation.id == conversation_id, Conversation.app_id == app_model.id)
.first()
)

if not conversation:
try:
ConversationService.delete(app_model, conversation_id, current_user)
except ConversationNotExistsError:
raise NotFound("Conversation Not Exists.")

conversation.is_deleted = True
db.session.commit()

return {"result": "success"}, 204


@@ -171,7 +168,7 @@ class ChatConversationApi(Resource):
.subquery()
)

query = db.select(Conversation).where(Conversation.app_id == app_model.id)
query = db.select(Conversation).where(Conversation.app_id == app_model.id, Conversation.is_deleted.is_(False))

if args["keyword"]:
keyword_filter = f"%{args['keyword']}%"
@@ -284,18 +281,11 @@ class ChatConversationDetailApi(Resource):
raise Forbidden()
conversation_id = str(conversation_id)

conversation = (
db.session.query(Conversation)
.where(Conversation.id == conversation_id, Conversation.app_id == app_model.id)
.first()
)

if not conversation:
try:
ConversationService.delete(app_model, conversation_id, current_user)
except ConversationNotExistsError:
raise NotFound("Conversation Not Exists.")

conversation.is_deleted = True
db.session.commit()

return {"result": "success"}, 204



+ 1
- 1
api/controllers/console/app/conversation_variables.py Переглянути файл

@@ -1,4 +1,4 @@
from flask_restful import Resource, marshal_with, reqparse
from flask_restx import Resource, marshal_with, reqparse
from sqlalchemy import select
from sqlalchemy.orm import Session


+ 1
- 1
api/controllers/console/app/generator.py Переглянути файл

@@ -1,7 +1,7 @@
from collections.abc import Sequence

from flask_login import current_user
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse

from controllers.console import api
from controllers.console.app.error import (

+ 1
- 1
api/controllers/console/app/mcp_server.py Переглянути файл

@@ -2,7 +2,7 @@ import json
from enum import StrEnum

from flask_login import current_user
from flask_restful import Resource, marshal_with, reqparse
from flask_restx import Resource, marshal_with, reqparse
from werkzeug.exceptions import NotFound

from controllers.console import api

+ 2
- 2
api/controllers/console/app/message.py Переглянути файл

@@ -1,8 +1,8 @@
import logging

from flask_login import current_user
from flask_restful import Resource, fields, marshal_with, reqparse
from flask_restful.inputs import int_range
from flask_restx import Resource, fields, marshal_with, reqparse
from flask_restx.inputs import int_range
from werkzeug.exceptions import Forbidden, InternalServerError, NotFound

from controllers.console import api

+ 1
- 1
api/controllers/console/app/model_config.py Переглянути файл

@@ -3,7 +3,7 @@ from typing import cast

from flask import request
from flask_login import current_user
from flask_restful import Resource
from flask_restx import Resource

from controllers.console import api
from controllers.console.app.wraps import get_app_model

+ 1
- 1
api/controllers/console/app/ops_trace.py Переглянути файл

@@ -1,4 +1,4 @@
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from werkzeug.exceptions import BadRequest

from controllers.console import api

+ 1
- 1
api/controllers/console/app/site.py Переглянути файл

@@ -1,5 +1,5 @@
from flask_login import current_user
from flask_restful import Resource, marshal_with, reqparse
from flask_restx import Resource, marshal_with, reqparse
from werkzeug.exceptions import Forbidden, NotFound

from constants.languages import supported_language

+ 1
- 1
api/controllers/console/app/statistic.py Переглянути файл

@@ -5,7 +5,7 @@ import pytz
import sqlalchemy as sa
from flask import jsonify
from flask_login import current_user
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse

from controllers.console import api
from controllers.console.app.wraps import get_app_model

+ 1
- 1
api/controllers/console/app/workflow.py Переглянути файл

@@ -4,7 +4,7 @@ from collections.abc import Sequence
from typing import cast

from flask import abort, request
from flask_restful import Resource, inputs, marshal_with, reqparse
from flask_restx import Resource, inputs, marshal_with, reqparse
from sqlalchemy.orm import Session
from werkzeug.exceptions import Forbidden, InternalServerError, NotFound


+ 2
- 2
api/controllers/console/app/workflow_app_log.py Переглянути файл

@@ -1,6 +1,6 @@
from dateutil.parser import isoparse
from flask_restful import Resource, marshal_with, reqparse
from flask_restful.inputs import int_range
from flask_restx import Resource, marshal_with, reqparse
from flask_restx.inputs import int_range
from sqlalchemy.orm import Session

from controllers.console import api

+ 1
- 1
api/controllers/console/app/workflow_draft_variable.py Переглянути файл

@@ -2,7 +2,7 @@ import logging
from typing import Any, NoReturn

from flask import Response
from flask_restful import Resource, fields, inputs, marshal, marshal_with, reqparse
from flask_restx import Resource, fields, inputs, marshal, marshal_with, reqparse
from sqlalchemy.orm import Session
from werkzeug.exceptions import Forbidden


+ 2
- 2
api/controllers/console/app/workflow_run.py Переглянути файл

@@ -1,8 +1,8 @@
from typing import cast

from flask_login import current_user
from flask_restful import Resource, marshal_with, reqparse
from flask_restful.inputs import int_range
from flask_restx import Resource, marshal_with, reqparse
from flask_restx.inputs import int_range

from controllers.console import api
from controllers.console.app.wraps import get_app_model

+ 1
- 1
api/controllers/console/app/workflow_statistic.py Переглянути файл

@@ -5,7 +5,7 @@ import pytz
import sqlalchemy as sa
from flask import jsonify
from flask_login import current_user
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse

from controllers.console import api
from controllers.console.app.wraps import get_app_model

+ 1
- 1
api/controllers/console/auth/activate.py Переглянути файл

@@ -1,5 +1,5 @@
from flask import request
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse

from constants.languages import supported_language
from controllers.console import api

+ 1
- 1
api/controllers/console/auth/data_source_bearer_auth.py Переглянути файл

@@ -1,5 +1,5 @@
from flask_login import current_user
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from werkzeug.exceptions import Forbidden

from controllers.console import api

+ 1
- 1
api/controllers/console/auth/data_source_oauth.py Переглянути файл

@@ -3,7 +3,7 @@ import logging
import requests
from flask import current_app, redirect, request
from flask_login import current_user
from flask_restful import Resource
from flask_restx import Resource
from werkzeug.exceptions import Forbidden

from configs import dify_config

+ 1
- 1
api/controllers/console/auth/forgot_password.py Переглянути файл

@@ -2,7 +2,7 @@ import base64
import secrets

from flask import request
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from sqlalchemy import select
from sqlalchemy.orm import Session


+ 2
- 2
api/controllers/console/auth/login.py Переглянути файл

@@ -2,7 +2,7 @@ from typing import cast

import flask_login
from flask import request
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse

import services
from configs import dify_config
@@ -221,7 +221,7 @@ class EmailCodeLoginApi(Resource):
email=user_email, name=user_email, interface_language=languages[0]
)
except WorkSpaceNotAllowedCreateError:
return NotAllowedCreateWorkspace()
raise NotAllowedCreateWorkspace()
except AccountRegisterError as are:
raise AccountInFreezeError()
except WorkspacesLimitExceededError:

+ 1
- 1
api/controllers/console/auth/oauth.py Переглянути файл

@@ -3,7 +3,7 @@ from typing import Optional

import requests
from flask import current_app, redirect, request
from flask_restful import Resource
from flask_restx import Resource
from sqlalchemy import select
from sqlalchemy.orm import Session
from werkzeug.exceptions import Unauthorized

+ 1
- 1
api/controllers/console/billing/billing.py Переглянути файл

@@ -1,5 +1,5 @@
from flask_login import current_user
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse

from controllers.console import api
from controllers.console.wraps import account_initialization_required, only_edition_cloud, setup_required

+ 1
- 1
api/controllers/console/billing/compliance.py Переглянути файл

@@ -1,6 +1,6 @@
from flask import request
from flask_login import current_user
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse

from libs.helper import extract_remote_ip
from libs.login import login_required

+ 1
- 1
api/controllers/console/datasets/data_source.py Переглянути файл

@@ -4,7 +4,7 @@ from typing import cast

from flask import request
from flask_login import current_user
from flask_restful import Resource, marshal_with, reqparse
from flask_restx import Resource, marshal_with, reqparse
from sqlalchemy import select
from sqlalchemy.orm import Session
from werkzeug.exceptions import NotFound

+ 4
- 4
api/controllers/console/datasets/datasets.py Переглянути файл

@@ -1,7 +1,7 @@
import flask_restful
import flask_restx
from flask import request
from flask_login import current_user
from flask_restful import Resource, marshal, marshal_with, reqparse
from flask_restx import Resource, marshal, marshal_with, reqparse
from werkzeug.exceptions import Forbidden, NotFound

import services
@@ -600,7 +600,7 @@ class DatasetApiKeyApi(Resource):
)

if current_key_count >= self.max_keys:
flask_restful.abort(
flask_restx.abort(
400,
message=f"Cannot create more than {self.max_keys} API keys for this resource type.",
code="max_keys_exceeded",
@@ -640,7 +640,7 @@ class DatasetApiDeleteApi(Resource):
)

if key is None:
flask_restful.abort(404, message="API key not found")
flask_restx.abort(404, message="API key not found")

db.session.query(ApiToken).where(ApiToken.id == api_key_id).delete()
db.session.commit()

+ 1
- 1
api/controllers/console/datasets/datasets_document.py Переглянути файл

@@ -5,7 +5,7 @@ from typing import Literal, cast

from flask import request
from flask_login import current_user
from flask_restful import Resource, marshal, marshal_with, reqparse
from flask_restx import Resource, marshal, marshal_with, reqparse
from sqlalchemy import asc, desc, select
from werkzeug.exceptions import Forbidden, NotFound


+ 13
- 3
api/controllers/console/datasets/datasets_segments.py Переглянути файл

@@ -2,7 +2,7 @@ import uuid

from flask import request
from flask_login import current_user
from flask_restful import Resource, marshal, reqparse
from flask_restx import Resource, marshal, reqparse
from sqlalchemy import select
from werkzeug.exceptions import Forbidden, NotFound

@@ -584,7 +584,12 @@ class ChildChunkUpdateApi(Resource):
child_chunk_id = str(child_chunk_id)
child_chunk = (
db.session.query(ChildChunk)
.where(ChildChunk.id == str(child_chunk_id), ChildChunk.tenant_id == current_user.current_tenant_id)
.where(
ChildChunk.id == str(child_chunk_id),
ChildChunk.tenant_id == current_user.current_tenant_id,
ChildChunk.segment_id == segment.id,
ChildChunk.document_id == document_id,
)
.first()
)
if not child_chunk:
@@ -633,7 +638,12 @@ class ChildChunkUpdateApi(Resource):
child_chunk_id = str(child_chunk_id)
child_chunk = (
db.session.query(ChildChunk)
.where(ChildChunk.id == str(child_chunk_id), ChildChunk.tenant_id == current_user.current_tenant_id)
.where(
ChildChunk.id == str(child_chunk_id),
ChildChunk.tenant_id == current_user.current_tenant_id,
ChildChunk.segment_id == segment.id,
ChildChunk.document_id == document_id,
)
.first()
)
if not child_chunk:

+ 1
- 1
api/controllers/console/datasets/external.py Переглянути файл

@@ -1,6 +1,6 @@
from flask import request
from flask_login import current_user
from flask_restful import Resource, marshal, reqparse
from flask_restx import Resource, marshal, reqparse
from werkzeug.exceptions import Forbidden, InternalServerError, NotFound

import services

+ 1
- 1
api/controllers/console/datasets/hit_testing.py Переглянути файл

@@ -1,4 +1,4 @@
from flask_restful import Resource
from flask_restx import Resource

from controllers.console import api
from controllers.console.datasets.hit_testing_base import DatasetsHitTestingBase

+ 1
- 1
api/controllers/console/datasets/hit_testing_base.py Переглянути файл

@@ -1,7 +1,7 @@
import logging

from flask_login import current_user
from flask_restful import marshal, reqparse
from flask_restx import marshal, reqparse
from werkzeug.exceptions import Forbidden, InternalServerError, NotFound

import services.dataset_service

+ 1
- 1
api/controllers/console/datasets/metadata.py Переглянути файл

@@ -1,7 +1,7 @@
from typing import Literal

from flask_login import current_user
from flask_restful import Resource, marshal_with, reqparse
from flask_restx import Resource, marshal_with, reqparse
from werkzeug.exceptions import NotFound

from controllers.console import api

+ 0
- 62
api/controllers/console/datasets/upload_file.py Переглянути файл

@@ -1,62 +0,0 @@
from flask_login import current_user
from flask_restful import Resource
from werkzeug.exceptions import NotFound

from controllers.console import api
from controllers.console.wraps import (
account_initialization_required,
setup_required,
)
from core.file import helpers as file_helpers
from extensions.ext_database import db
from models.dataset import Dataset
from models.model import UploadFile
from services.dataset_service import DocumentService


class UploadFileApi(Resource):
@setup_required
@account_initialization_required
def get(self, dataset_id, document_id):
"""Get upload file."""
# check dataset
dataset_id = str(dataset_id)
dataset = (
db.session.query(Dataset)
.filter(Dataset.tenant_id == current_user.current_tenant_id, Dataset.id == dataset_id)
.first()
)
if not dataset:
raise NotFound("Dataset not found.")
# check document
document_id = str(document_id)
document = DocumentService.get_document(dataset.id, document_id)
if not document:
raise NotFound("Document not found.")
# check upload file
if document.data_source_type != "upload_file":
raise ValueError(f"Document data source type ({document.data_source_type}) is not upload_file.")
data_source_info = document.data_source_info_dict
if data_source_info and "upload_file_id" in data_source_info:
file_id = data_source_info["upload_file_id"]
upload_file = db.session.query(UploadFile).where(UploadFile.id == file_id).first()
if not upload_file:
raise NotFound("UploadFile not found.")
else:
raise ValueError("Upload file id not found in document data source info.")

url = file_helpers.get_signed_file_url(upload_file_id=upload_file.id)
return {
"id": upload_file.id,
"name": upload_file.name,
"size": upload_file.size,
"extension": upload_file.extension,
"url": url,
"download_url": f"{url}&as_attachment=true",
"mime_type": upload_file.mime_type,
"created_by": upload_file.created_by,
"created_at": upload_file.created_at.timestamp(),
}, 200


api.add_resource(UploadFileApi, "/datasets/<uuid:dataset_id>/documents/<uuid:document_id>/upload-file")

+ 1
- 1
api/controllers/console/datasets/website.py Переглянути файл

@@ -1,4 +1,4 @@
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse

from controllers.console import api
from controllers.console.datasets.error import WebsiteCrawlError

+ 1
- 1
api/controllers/console/explore/audio.py Переглянути файл

@@ -65,7 +65,7 @@ class ChatAudioApi(InstalledAppResource):

class ChatTextApi(InstalledAppResource):
def post(self, installed_app):
from flask_restful import reqparse
from flask_restx import reqparse

app_model = installed_app.app
try:

+ 1
- 1
api/controllers/console/explore/completion.py Переглянути файл

@@ -1,7 +1,7 @@
import logging

from flask_login import current_user
from flask_restful import reqparse
from flask_restx import reqparse
from werkzeug.exceptions import InternalServerError, NotFound

import services

+ 2
- 2
api/controllers/console/explore/conversation.py Переглянути файл

@@ -1,6 +1,6 @@
from flask_login import current_user
from flask_restful import marshal_with, reqparse
from flask_restful.inputs import int_range
from flask_restx import marshal_with, reqparse
from flask_restx.inputs import int_range
from sqlalchemy.orm import Session
from werkzeug.exceptions import NotFound


+ 1
- 1
api/controllers/console/explore/installed_app.py Переглянути файл

@@ -3,7 +3,7 @@ from typing import Any

from flask import request
from flask_login import current_user
from flask_restful import Resource, inputs, marshal_with, reqparse
from flask_restx import Resource, inputs, marshal_with, reqparse
from sqlalchemy import and_
from werkzeug.exceptions import BadRequest, Forbidden, NotFound


+ 2
- 2
api/controllers/console/explore/message.py Переглянути файл

@@ -1,8 +1,8 @@
import logging

from flask_login import current_user
from flask_restful import marshal_with, reqparse
from flask_restful.inputs import int_range
from flask_restx import marshal_with, reqparse
from flask_restx.inputs import int_range
from werkzeug.exceptions import InternalServerError, NotFound

from controllers.console.app.error import (

+ 1
- 1
api/controllers/console/explore/parameter.py Переглянути файл

@@ -1,4 +1,4 @@
from flask_restful import marshal_with
from flask_restx import marshal_with

from controllers.common import fields
from controllers.console import api

+ 1
- 1
api/controllers/console/explore/recommended_app.py Переглянути файл

@@ -1,5 +1,5 @@
from flask_login import current_user
from flask_restful import Resource, fields, marshal_with, reqparse
from flask_restx import Resource, fields, marshal_with, reqparse

from constants.languages import languages
from controllers.console import api

+ 2
- 2
api/controllers/console/explore/saved_message.py Переглянути файл

@@ -1,6 +1,6 @@
from flask_login import current_user
from flask_restful import fields, marshal_with, reqparse
from flask_restful.inputs import int_range
from flask_restx import fields, marshal_with, reqparse
from flask_restx.inputs import int_range
from werkzeug.exceptions import NotFound

from controllers.console import api

+ 1
- 1
api/controllers/console/explore/workflow.py Переглянути файл

@@ -1,6 +1,6 @@
import logging

from flask_restful import reqparse
from flask_restx import reqparse
from werkzeug.exceptions import InternalServerError

from controllers.console.app.error import (

+ 1
- 1
api/controllers/console/explore/wraps.py Переглянути файл

@@ -1,7 +1,7 @@
from functools import wraps

from flask_login import current_user
from flask_restful import Resource
from flask_restx import Resource
from werkzeug.exceptions import NotFound

from controllers.console.explore.error import AppAccessDeniedError

+ 1
- 1
api/controllers/console/extension.py Переглянути файл

@@ -1,5 +1,5 @@
from flask_login import current_user
from flask_restful import Resource, marshal_with, reqparse
from flask_restx import Resource, marshal_with, reqparse

from constants import HIDDEN_VALUE
from controllers.console import api

+ 1
- 1
api/controllers/console/feature.py Переглянути файл

@@ -1,5 +1,5 @@
from flask_login import current_user
from flask_restful import Resource
from flask_restx import Resource

from libs.login import login_required
from services.feature_service import FeatureService

+ 1
- 1
api/controllers/console/files.py Переглянути файл

@@ -2,7 +2,7 @@ from typing import Literal

from flask import request
from flask_login import current_user
from flask_restful import Resource, marshal_with
from flask_restx import Resource, marshal_with
from werkzeug.exceptions import Forbidden

import services

+ 1
- 1
api/controllers/console/init_validate.py Переглянути файл

@@ -1,7 +1,7 @@
import os

from flask import session
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from sqlalchemy import select
from sqlalchemy.orm import Session


+ 1
- 1
api/controllers/console/ping.py Переглянути файл

@@ -1,4 +1,4 @@
from flask_restful import Resource
from flask_restx import Resource

from controllers.console import api


+ 1
- 1
api/controllers/console/remote_files.py Переглянути файл

@@ -3,7 +3,7 @@ from typing import cast

import httpx
from flask_login import current_user
from flask_restful import Resource, marshal_with, reqparse
from flask_restx import Resource, marshal_with, reqparse

import services
from controllers.common import helpers

+ 1
- 1
api/controllers/console/setup.py Переглянути файл

@@ -1,5 +1,5 @@
from flask import request
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse

from configs import dify_config
from libs.helper import StrLen, email, extract_remote_ip

+ 3
- 3
api/controllers/console/tag/tags.py Переглянути файл

@@ -1,11 +1,11 @@
from flask import request
from flask_login import current_user
from flask_restful import Resource, marshal_with, reqparse
from flask_restx import Resource, marshal_with, reqparse
from werkzeug.exceptions import Forbidden

from controllers.console import api
from controllers.console.wraps import account_initialization_required, setup_required
from fields.tag_fields import tag_fields
from fields.tag_fields import dataset_tag_fields
from libs.login import login_required
from models.model import Tag
from services.tag_service import TagService
@@ -21,7 +21,7 @@ class TagListApi(Resource):
@setup_required
@login_required
@account_initialization_required
@marshal_with(tag_fields)
@marshal_with(dataset_tag_fields)
def get(self):
tag_type = request.args.get("type", type=str, default="")
keyword = request.args.get("keyword", default=None, type=str)

+ 1
- 1
api/controllers/console/version.py Переглянути файл

@@ -2,7 +2,7 @@ import json
import logging

import requests
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from packaging import version

from configs import dify_config

+ 1
- 1
api/controllers/console/workspace/account.py Переглянути файл

@@ -3,7 +3,7 @@ from datetime import datetime
import pytz
from flask import request
from flask_login import current_user
from flask_restful import Resource, fields, marshal_with, reqparse
from flask_restx import Resource, fields, marshal_with, reqparse
from sqlalchemy import select
from sqlalchemy.orm import Session


+ 1
- 1
api/controllers/console/workspace/agent_providers.py Переглянути файл

@@ -1,5 +1,5 @@
from flask_login import current_user
from flask_restful import Resource
from flask_restx import Resource

from controllers.console import api
from controllers.console.wraps import account_initialization_required, setup_required

+ 1
- 1
api/controllers/console/workspace/endpoint.py Переглянути файл

@@ -1,5 +1,5 @@
from flask_login import current_user
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from werkzeug.exceptions import Forbidden

from controllers.console import api

+ 1
- 1
api/controllers/console/workspace/load_balancing_config.py Переглянути файл

@@ -1,4 +1,4 @@
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from werkzeug.exceptions import Forbidden

from controllers.console import api

+ 1
- 1
api/controllers/console/workspace/members.py Переглянути файл

@@ -2,7 +2,7 @@ from urllib import parse

from flask import request
from flask_login import current_user
from flask_restful import Resource, abort, marshal_with, reqparse
from flask_restx import Resource, abort, marshal_with, reqparse

import services
from configs import dify_config

+ 1
- 1
api/controllers/console/workspace/model_providers.py Переглянути файл

@@ -2,7 +2,7 @@ import io

from flask import send_file
from flask_login import current_user
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from werkzeug.exceptions import Forbidden

from controllers.console import api

+ 1
- 1
api/controllers/console/workspace/models.py Переглянути файл

@@ -1,7 +1,7 @@
import logging

from flask_login import current_user
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from werkzeug.exceptions import Forbidden

from controllers.console import api

+ 1
- 1
api/controllers/console/workspace/plugin.py Переглянути файл

@@ -2,7 +2,7 @@ import io

from flask import request, send_file
from flask_login import current_user
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from werkzeug.exceptions import Forbidden

from configs import dify_config

+ 1
- 1
api/controllers/console/workspace/tool_providers.py Переглянути файл

@@ -3,7 +3,7 @@ from urllib.parse import urlparse

from flask import make_response, redirect, request, send_file
from flask_login import current_user
from flask_restful import (
from flask_restx import (
Resource,
reqparse,
)

+ 1
- 1
api/controllers/console/workspace/workspace.py Переглянути файл

@@ -2,7 +2,7 @@ import logging

from flask import request
from flask_login import current_user
from flask_restful import Resource, fields, inputs, marshal, marshal_with, reqparse
from flask_restx import Resource, fields, inputs, marshal, marshal_with, reqparse
from sqlalchemy import select
from werkzeug.exceptions import Unauthorized


+ 13
- 2
api/controllers/files/__init__.py Переглянути файл

@@ -1,9 +1,20 @@
from flask import Blueprint
from flask_restx import Namespace

from libs.external_api import ExternalApi

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

api = ExternalApi(
bp,
version="1.0",
title="Files API",
description="API for file operations including upload and preview",
doc="/docs", # Enable Swagger UI at /files/docs
)

files_ns = Namespace("files", description="File operations", path="/")

from . import image_preview, tool_files, upload

api.add_namespace(files_ns)

+ 5
- 7
api/controllers/files/image_preview.py Переглянути файл

@@ -1,16 +1,17 @@
from urllib.parse import quote

from flask import Response, request
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from werkzeug.exceptions import NotFound

import services
from controllers.common.errors import UnsupportedFileTypeError
from controllers.files import api
from controllers.files import files_ns
from services.account_service import TenantService
from services.file_service import FileService


@files_ns.route("/<uuid:file_id>/image-preview")
class ImagePreviewApi(Resource):
"""
Deprecated
@@ -39,6 +40,7 @@ class ImagePreviewApi(Resource):
return Response(generator, mimetype=mimetype)


@files_ns.route("/<uuid:file_id>/file-preview")
class FilePreviewApi(Resource):
def get(self, file_id):
file_id = str(file_id)
@@ -94,6 +96,7 @@ class FilePreviewApi(Resource):
return response


@files_ns.route("/workspaces/<uuid:workspace_id>/webapp-logo")
class WorkspaceWebappLogoApi(Resource):
def get(self, workspace_id):
workspace_id = str(workspace_id)
@@ -112,8 +115,3 @@ class WorkspaceWebappLogoApi(Resource):
raise UnsupportedFileTypeError()

return Response(generator, mimetype=mimetype)


api.add_resource(ImagePreviewApi, "/files/<uuid:file_id>/image-preview")
api.add_resource(FilePreviewApi, "/files/<uuid:file_id>/file-preview")
api.add_resource(WorkspaceWebappLogoApi, "/files/workspaces/<uuid:workspace_id>/webapp-logo")

+ 4
- 6
api/controllers/files/tool_files.py Переглянути файл

@@ -1,17 +1,18 @@
from urllib.parse import quote

from flask import Response
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from werkzeug.exceptions import Forbidden, NotFound

from controllers.common.errors import UnsupportedFileTypeError
from controllers.files import api
from controllers.files import files_ns
from core.tools.signature import verify_tool_file_signature
from core.tools.tool_file_manager import ToolFileManager
from models import db as global_db


class ToolFilePreviewApi(Resource):
@files_ns.route("/tools/<uuid:file_id>.<string:extension>")
class ToolFileApi(Resource):
def get(self, file_id, extension):
file_id = str(file_id)

@@ -52,6 +53,3 @@ class ToolFilePreviewApi(Resource):
response.headers["Content-Disposition"] = f"attachment; filename*=UTF-8''{encoded_filename}"

return response


api.add_resource(ToolFilePreviewApi, "/files/tools/<uuid:file_id>.<string:extension>")

+ 60
- 24
api/controllers/files/upload.py Переглянути файл

@@ -1,7 +1,9 @@
from mimetypes import guess_extension
from typing import Optional

from flask import request
from flask_restful import Resource, marshal_with
from flask_restx import Resource, reqparse
from flask_restx.api import HTTPStatus
from werkzeug.datastructures import FileStorage
from werkzeug.exceptions import Forbidden

import services
@@ -10,39 +12,76 @@ from controllers.common.errors import (
UnsupportedFileTypeError,
)
from controllers.console.wraps import setup_required
from controllers.files import api
from controllers.files import files_ns
from controllers.inner_api.plugin.wraps import get_user
from core.file.helpers import verify_plugin_file_signature
from core.tools.tool_file_manager import ToolFileManager
from fields.file_fields import file_fields
from fields.file_fields import build_file_model

# Define parser for both documentation and validation
upload_parser = reqparse.RequestParser()
upload_parser.add_argument("file", location="files", type=FileStorage, required=True, help="File to upload")
upload_parser.add_argument(
"timestamp", type=str, required=True, location="args", help="Unix timestamp for signature verification"
)
upload_parser.add_argument(
"nonce", type=str, required=True, location="args", help="Random string for signature verification"
)
upload_parser.add_argument(
"sign", type=str, required=True, location="args", help="HMAC signature for request validation"
)
upload_parser.add_argument("tenant_id", type=str, required=True, location="args", help="Tenant identifier")
upload_parser.add_argument("user_id", type=str, required=False, location="args", help="User identifier")


@files_ns.route("/upload/for-plugin")
class PluginUploadFileApi(Resource):
@setup_required
@marshal_with(file_fields)
@files_ns.expect(upload_parser)
@files_ns.doc("upload_plugin_file")
@files_ns.doc(description="Upload a file for plugin usage with signature verification")
@files_ns.doc(
responses={
201: "File uploaded successfully",
400: "Invalid request parameters",
403: "Forbidden - Invalid signature or missing parameters",
413: "File too large",
415: "Unsupported file type",
}
)
@files_ns.marshal_with(build_file_model(files_ns), code=HTTPStatus.CREATED)
def post(self):
# get file from request
file = request.files["file"]

timestamp = request.args.get("timestamp")
nonce = request.args.get("nonce")
sign = request.args.get("sign")
tenant_id = request.args.get("tenant_id")
if not tenant_id:
raise Forbidden("Invalid request.")

user_id = request.args.get("user_id")
"""Upload a file for plugin usage.

Accepts a file upload with signature verification for security.
The file must be accompanied by valid timestamp, nonce, and signature parameters.

Returns:
dict: File metadata including ID, URLs, and properties
int: HTTP status code (201 for success)

Raises:
Forbidden: Invalid signature or missing required parameters
FileTooLargeError: File exceeds size limit
UnsupportedFileTypeError: File type not supported
"""
# Parse and validate all arguments
args = upload_parser.parse_args()

file: FileStorage = args["file"]
timestamp: str = args["timestamp"]
nonce: str = args["nonce"]
sign: str = args["sign"]
tenant_id: str = args["tenant_id"]
user_id: Optional[str] = args.get("user_id")
user = get_user(tenant_id, user_id)

filename = file.filename
mimetype = file.mimetype
filename: Optional[str] = file.filename
mimetype: Optional[str] = file.mimetype

if not filename or not mimetype:
raise Forbidden("Invalid request.")

if not timestamp or not nonce or not sign:
raise Forbidden("Invalid request.")

if not verify_plugin_file_signature(
filename=filename,
mimetype=mimetype,
@@ -88,6 +127,3 @@ class PluginUploadFileApi(Resource):
raise FileTooLargeError(file_too_large_error.description)
except services.errors.file.UnsupportedFileTypeError:
raise UnsupportedFileTypeError()


api.add_resource(PluginUploadFileApi, "/files/upload/for-plugin")

+ 1
- 1
api/controllers/inner_api/mail.py Переглянути файл

@@ -1,4 +1,4 @@
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse

from controllers.console.wraps import setup_required
from controllers.inner_api import api

+ 1
- 1
api/controllers/inner_api/plugin/plugin.py Переглянути файл

@@ -1,4 +1,4 @@
from flask_restful import Resource
from flask_restx import Resource

from controllers.console.wraps import setup_required
from controllers.inner_api import api

+ 1
- 1
api/controllers/inner_api/plugin/wraps.py Переглянути файл

@@ -4,7 +4,7 @@ from typing import Optional

from flask import current_app, request
from flask_login import user_logged_in
from flask_restful import reqparse
from flask_restx import reqparse
from pydantic import BaseModel
from sqlalchemy.orm import Session


+ 1
- 1
api/controllers/inner_api/workspace/workspace.py Переглянути файл

@@ -1,6 +1,6 @@
import json

from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse

from controllers.console.wraps import setup_required
from controllers.inner_api import api

+ 13
- 1
api/controllers/mcp/__init__.py Переглянути файл

@@ -1,8 +1,20 @@
from flask import Blueprint
from flask_restx import Namespace

from libs.external_api import ExternalApi

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

api = ExternalApi(
bp,
version="1.0",
title="MCP API",
description="API for Model Context Protocol operations",
doc="/docs", # Enable Swagger UI at /mcp/docs
)

mcp_ns = Namespace("mcp", description="MCP operations", path="/")

from . import mcp

api.add_namespace(mcp_ns)

+ 0
- 0
api/controllers/mcp/mcp.py Переглянути файл


Деякі файли не було показано, через те що забагато файлів було змінено

Завантаження…
Відмінити
Зберегти