Compare commits

...
Author SHA1 Message Date
AkaraChen c5b07b999c build: add dependabot 2024-11-08 11:17:53 +08:00
Leo.WangandGitHub c9f785e00f Feat/tools/gitlab (#10407) 2024-11-08 09:53:03 +08:00
Bowen LiangandGitHub 0e8ab0588f fix: (#10437 followup) fix conditions with DEBUG config (#10438) 2024-11-08 09:42:53 +08:00
Bowen LiangandGitHub 0ebe198ff1 chore: use DEBUG in dify_config instead of parsing raw system environment variable in place (#10437) 2024-11-08 09:34:11 +08:00
-LAN-andGitHub 438ad8148b fix(http_request): send form data (#10431) 2024-11-08 09:33:40 +08:00
Bowen LiangandGitHub a60133bfb3 fix: config violations when running db migtration ci tests (#10428) 2024-11-08 09:33:12 +08:00
katsumaandGitHub 98b3e37144 fix: simplify Enter key handling and remove unused ref (#10413) 2024-11-07 21:21:50 +08:00
BenjaminandGitHub 6e23903c63 Conversation delete issue (#10423) 2024-11-07 21:13:23 +08:00
Bowen LiangandGitHub 574c4a264f chore(lint): Use logging.exception instead of logging.error (#10415) 2024-11-07 21:13:02 +08:00
ice yaoandGitHub dd5ffaf058 chore: use posixpath to wrapper filepath (#9976) 2024-11-07 19:31:49 +08:00
huangyafeiandGitHub 0b16270b88 fix typo: Retrieve Chunks API Docs (#10412) 2024-11-07 18:11:36 +08:00
f562a88249 feat(Tools): add lark tools (#10117)
Co-authored-by: 黎斌 <libin.23@bytedance.com>
2024-11-07 18:11:25 +08:00
非法操作andGitHub 59f8d116af chore: improve custom tool's display (#10410) 2024-11-07 18:10:41 +08:00
BenjaminandGitHub a5558f8fcc fix(conversation-service): return success response after conversation… (#10416) 2024-11-07 18:07:05 +08:00
-LAN-andGitHub 823ae03a08 fix(remote-files): fallback to get when remote server not support head method (#10370) 2024-11-07 14:35:58 +08:00
-LAN-andGitHub f8c958a409 refactor(iteration): introduce specific exceptions for iteration errors (#10366) 2024-11-07 14:02:55 +08:00
-LAN-andGitHub 25785d8c3f refactor(knowledge-retrieval): improve error handling with custom exceptions (#10385) 2024-11-07 14:02:46 +08:00
-LAN-andGitHub 35d3da9697 refactor(tool-node): introduce specific exceptions for tool node errors (#10357) 2024-11-07 14:02:38 +08:00
-LAN-andGitHub d3e9930235 refactor(question_classifier): improve error handling with custom exceptions (#10365) 2024-11-07 14:02:30 +08:00
1ccca7cc68 fixed: web api remote urls error (#10383)
Co-authored-by: hobo.l <hobo.l@binance.com>
2024-11-07 13:55:19 +08:00
powerfoolandGitHub 12a9e2972a Adjusted docker manifests and environment variables for OceanBase vector database (#10395) 2024-11-07 13:22:09 +08:00
omrandGitHub 444c1f170a fix typo: mMaximum -> Maximum (#10389) 2024-11-07 10:40:57 +08:00
非法操作andGitHub 3cb2fb8250 fix: remove duplicated category “recommended” (#10375) 2024-11-06 19:06:55 +08:00
MatsudaandGitHub 1e8457441d fix(model_runtime): remove vision from features for Claude 3.5 Haiku (#10360) 2024-11-06 17:42:18 +08:00
InfinitnetandGitHub 5a9448245b fix: remove unsupported vision in OpenRouter Haiku 3.5 (#10364) 2024-11-06 17:41:48 +08:00
Bowen LiangandGitHub eafe5a9d8f chore(ci): bring back poetry cache to speed up CI jobs (#10347) 2024-11-06 13:55:29 +08:00
Bowen LiangandGitHub d45d90e8ae chore: lazy import sagemaker (#10342) 2024-11-06 12:45:22 +08:00
comfutureandGitHub 42a9374e71 chore: update translation for 'account' from '계좌' to '계정' (#10350) 2024-11-06 12:44:44 +08:00
-LAN-andGitHub 82a775eca3 chore(ci): separate vector store tests into new workflow (#10354) 2024-11-06 12:43:55 +08:00
-LAN-andGitHub 1dae1a71fc fix(api): remove fixed source attribute from FileApi (#10353) 2024-11-06 12:29:58 +08:00
ac0fed6402 feat: support png, gif, webp (#7947)
Co-authored-by: xuanson9699 <84961581+xuanson9699@users.noreply.github.com>
2024-11-06 09:05:05 +08:00
Chenhe GuandGitHub fb656d480e Update README.md (#10332) 2024-11-06 08:57:49 +08:00
方程andGitHub 2b7341af57 Gitee AI tools (#10314) 2024-11-06 08:51:13 +08:00
Summer-GuandGitHub ce1f9d935d feat: The SSRF request timeout configuration item is added (#10292) 2024-11-06 08:50:57 +08:00
InfinitnetandGitHub bdadca1a65 feat: add support for anthropic/claude-3-5-haiku through OpenRouter (#10331) 2024-11-06 08:26:44 +08:00
BenjaminandGitHub d7b4d0756e feat(vannaai): add base_url configuration (#10294) 2024-11-05 20:58:49 +08:00
-LAN-andGitHub 1279e27825 docs: remove the TOC part (#10324) 2024-11-05 04:48:14 -08:00
非法操作andGitHub d92e3bd620 fix: special prompt not work for comfyUI tool (#10307) 2024-11-05 18:21:41 +08:00
-LAN-andGitHub 7f583ec1ac chore: update version to 0.11.0 across all relevant files (#10278) 2024-11-05 17:53:56 +08:00
NoviceandGitHub 7962101e5e fix: iteration none output error (#10295) 2024-11-05 16:31:49 +08:00
217 changed files with 5998 additions and 441 deletions
+10
View File
@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: npm
directory: /web
schedule:
interval: weekly
assignees:
- akarachen
labels:
- dependencies
+7 -26
View File
@@ -7,6 +7,7 @@ on:
paths:
- api/**
- docker/**
- .github/workflows/api-tests.yml
concurrency:
group: api-tests-${{ github.head_ref || github.run_id }}
@@ -27,16 +28,15 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Poetry
uses: abatilo/actions-poetry@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache-dependency-path: |
api/pyproject.toml
api/poetry.lock
- name: Install Poetry
uses: abatilo/actions-poetry@v3
cache: poetry
cache-dependency-path: api/poetry.lock
- name: Check Poetry lockfile
run: |
@@ -67,7 +67,7 @@ jobs:
run: sh .github/workflows/expose_service_ports.sh
- name: Set up Sandbox
uses: hoverkraft-tech/compose-action@v2.0.0
uses: hoverkraft-tech/compose-action@v2.0.2
with:
compose-file: |
docker/docker-compose.middleware.yaml
@@ -77,22 +77,3 @@ jobs:
- name: Run Workflow
run: poetry run -C api bash dev/pytest/pytest_workflow.sh
- name: Set up Vector Stores (Weaviate, Qdrant, PGVector, Milvus, PgVecto-RS, Chroma, MyScale, ElasticSearch, Couchbase)
uses: hoverkraft-tech/compose-action@v2.0.0
with:
compose-file: |
docker/docker-compose.yaml
services: |
weaviate
qdrant
couchbase-server
etcd
minio
milvus-standalone
pgvecto-rs
pgvector
chroma
elasticsearch
- name: Test Vector Stores
run: poetry run -C api bash dev/pytest/pytest_vdb.sh
+2 -1
View File
@@ -6,6 +6,7 @@ on:
- main
paths:
- api/migrations/**
- .github/workflows/db-migration-test.yml
concurrency:
group: db-migration-test-${{ github.ref }}
@@ -43,7 +44,7 @@ jobs:
cp middleware.env.example middleware.env
- name: Set up Middlewares
uses: hoverkraft-tech/compose-action@v2.0.0
uses: hoverkraft-tech/compose-action@v2.0.2
with:
compose-file: |
docker/docker-compose.middleware.yaml
+4 -4
View File
@@ -24,16 +24,16 @@ jobs:
with:
files: api/**
- name: Install Poetry
if: steps.changed-files.outputs.any_changed == 'true'
uses: abatilo/actions-poetry@v3
- name: Set up Python
uses: actions/setup-python@v5
if: steps.changed-files.outputs.any_changed == 'true'
with:
python-version: '3.10'
- name: Install Poetry
if: steps.changed-files.outputs.any_changed == 'true'
uses: abatilo/actions-poetry@v3
- name: Python dependencies
if: steps.changed-files.outputs.any_changed == 'true'
run: poetry install -C api --only lint
+75
View File
@@ -0,0 +1,75 @@
name: Run VDB Tests
on:
pull_request:
branches:
- main
paths:
- api/core/rag/datasource/**
- docker/**
- .github/workflows/vdb-tests.yml
concurrency:
group: vdb-tests-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
test:
name: VDB Tests
runs-on: ubuntu-latest
strategy:
matrix:
python-version:
- "3.10"
- "3.11"
- "3.12"
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Poetry
uses: abatilo/actions-poetry@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: poetry
cache-dependency-path: api/poetry.lock
- name: Check Poetry lockfile
run: |
poetry check -C api --lock
poetry show -C api
- name: Install dependencies
run: poetry install -C api --with dev
- name: Set up dotenvs
run: |
cp docker/.env.example docker/.env
cp docker/middleware.env.example docker/middleware.env
- name: Expose Service Ports
run: sh .github/workflows/expose_service_ports.sh
- name: Set up Vector Stores (Weaviate, Qdrant, PGVector, Milvus, PgVecto-RS, Chroma, MyScale, ElasticSearch, Couchbase)
uses: hoverkraft-tech/compose-action@v2.0.2
with:
compose-file: |
docker/docker-compose.yaml
services: |
weaviate
qdrant
couchbase-server
etcd
minio
milvus-standalone
pgvecto-rs
pgvector
chroma
elasticsearch
- name: Test Vector Stores
run: poetry run -C api bash dev/pytest/pytest_vdb.sh
+1
View File
@@ -175,6 +175,7 @@ docker/volumes/pgvector/data/*
docker/volumes/pgvecto_rs/data/*
docker/volumes/couchbase/*
docker/volumes/oceanbase/*
!docker/volumes/oceanbase/init.d
docker/nginx/conf.d/default.conf
docker/nginx/ssl/*
+17 -56
View File
@@ -46,45 +46,18 @@
</p>
## Table of Content
0. [Quick-Start🚀](https://github.com/langgenius/dify?tab=readme-ov-file#quick-start)
1. [Intro📖](https://github.com/langgenius/dify?tab=readme-ov-file#intro)
2. [How to use🔧](https://github.com/langgenius/dify?tab=readme-ov-file#using-dify)
3. [Stay Ahead🏃](https://github.com/langgenius/dify?tab=readme-ov-file#staying-ahead)
4. [Next Steps🏹](https://github.com/langgenius/dify?tab=readme-ov-file#next-steps)
5. [Contributing💪](https://github.com/langgenius/dify?tab=readme-ov-file#contributing)
6. [Community and Contact🏠](https://github.com/langgenius/dify?tab=readme-ov-file#community--contact)
7. [Star-History📈](https://github.com/langgenius/dify?tab=readme-ov-file#star-history)
8. [Security🔒](https://github.com/langgenius/dify?tab=readme-ov-file#security-disclosure)
9. [License🤝](https://github.com/langgenius/dify?tab=readme-ov-file#license)
> Make sure you read through this README before you start utilizing Dify😊
Dify is an open-source LLM app development platform. Its intuitive interface combines agentic AI workflow, RAG pipeline, agent capabilities, model management, observability features and more, letting you quickly go from prototype to production.
## Quick start
The quickest way to deploy Dify locally is to run our [docker-compose.yml](https://github.com/langgenius/dify/blob/main/docker/docker-compose.yaml). Follow the instructions to start in 5 minutes.
> Before installing Dify, make sure your machine meets the following minimum system requirements:
>
>- CPU >= 2 Core
>- RAM >= 4 GiB
>- Docker and Docker Compose Installed
</br>
Run the following command in your terminal to clone the whole repo.
```bash
git clone https://github.com/langgenius/dify.git
```
After cloning,run the following command one by one.
The easiest way to start the Dify server is through [docker compose](docker/docker-compose.yaml). Before running Dify with the following commands, make sure that [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/install/) are installed on your machine:
```bash
cd dify
cd docker
@@ -92,13 +65,14 @@ cp .env.example .env
docker compose up -d
```
After running, you can access the Dify dashboard in your browser at [http://localhost/install](http://localhost/install) and start the initialization process. You will be asked to setup an admin account.
For more info of quick setup, check [here](https://docs.dify.ai/getting-started/install-self-hosted/docker-compose)
After running, you can access the Dify dashboard in your browser at [http://localhost/install](http://localhost/install) and start the initialization process.
## Intro
Dify is an open-source LLM app development platform. Its intuitive interface combines AI workflow, RAG pipeline, agent capabilities, model management, observability features and more, letting you quickly go from prototype to production. Here's a list of the core features:
</br> </br>
#### Seeking help
Please refer to our [FAQ](https://docs.dify.ai/getting-started/install-self-hosted/faqs) if you encounter problems setting up Dify. Reach out to [the community and us](#community--contact) if you are still having issues.
> If you'd like to contribute to Dify or do additional development, refer to our [guide to deploying from source code](https://docs.dify.ai/getting-started/install-self-hosted/local-source-code)
## Key features
**1. Workflow**:
Build and test powerful AI workflows on a visual canvas, leveraging all the following features and beyond.
@@ -149,20 +123,8 @@ Star Dify on GitHub and be instantly notified of new releases.
![star-us](https://github.com/langgenius/dify/assets/13230914/b823edc1-6388-4e25-ad45-2f6b187adbb4)
## Next steps
Go to [quick-start](https://github.com/langgenius/dify?tab=readme-ov-file#quick-start) to setup your Dify or setup by source code.
#### If you......
If you forget your admin account, you can refer to this [guide](https://docs.dify.ai/getting-started/install-self-hosted/faqs#id-4.-how-to-reset-the-password-of-the-admin-account) to reset the password.
> Use docker compose up without "-d" to enable logs printing out in your terminal. This might be useful if you have encountered unknow problems when using Dify.
If you encountered system error and would like to acquire help in Github issues, make sure you always paste logs of the error in the request to accerate the conversation. Go to [Community & contact](https://github.com/langgenius/dify?tab=readme-ov-file#community--contact) for more information.
> Please read the [Dify Documentation](https://docs.dify.ai/) for detailed how-to-use guidance. Most of the potential problems are explained in the doc.
> If you'd like to contribute to Dify or make additional development, refer to our [guide to deploying from source code](https://docs.dify.ai/getting-started/install-self-hosted/local-source-code)
## Advanced Setup
If you need to customize the configuration, please refer to the comments in our [.env.example](docker/.env.example) file and update the corresponding values in your `.env` file. Additionally, you might need to make adjustments to the `docker-compose.yaml` file itself, such as changing image versions, port mappings, or volume mounts, based on your specific deployment environment and requirements. After making any changes, please re-run `docker-compose up -d`. You can find the full list of available environment variables [here](https://docs.dify.ai/getting-started/install-self-hosted/environments).
@@ -190,19 +152,18 @@ At the same time, please consider supporting Dify by sharing it on social media
> We are looking for contributors to help with translating Dify to languages other than Mandarin or English. If you are interested in helping, please see the [i18n README](https://github.com/langgenius/dify/blob/main/web/i18n/README.md) for more information, and leave us a comment in the `global-users` channel of our [Discord Community Server](https://discord.gg/8Tpq4AcN9c).
**Contributors**
<a href="https://github.com/langgenius/dify/graphs/contributors">
<img src="https://contrib.rocks/image?repo=langgenius/dify" />
</a>
## Community & contact
* [Github Discussion](https://github.com/langgenius/dify/discussions). Best for: sharing feedback and asking questions.
* [GitHub Issues](https://github.com/langgenius/dify/issues). Best for: bugs you encounter using Dify.AI, and feature proposals. See our [Contribution Guide](https://github.com/langgenius/dify/blob/main/CONTRIBUTING.md).
* [Discord](https://discord.gg/FngNHpbcY7). Best for: sharing your applications and hanging out with the community.
* [X(Twitter)](https://twitter.com/dify_ai). Best for: sharing your applications and hanging out with the community.
* Make sure a log, if possible, is attached to an error reported to maximize solution efficiency.
**Contributors**
<a href="https://github.com/langgenius/dify/graphs/contributors">
<img src="https://contrib.rocks/image?repo=langgenius/dify" />
</a>
## Star history
+7 -2
View File
@@ -121,7 +121,7 @@ WEB_API_CORS_ALLOW_ORIGINS=http://127.0.0.1:3000,*
CONSOLE_CORS_ALLOW_ORIGINS=http://127.0.0.1:3000,*
# Vector database configuration, support: weaviate, qdrant, milvus, myscale, relyt, pgvecto_rs, pgvector, pgvector, chroma, opensearch, tidb_vector, couchbase, vikingdb, upstash, lindorm
# Vector database configuration, support: weaviate, qdrant, milvus, myscale, relyt, pgvecto_rs, pgvector, pgvector, chroma, opensearch, tidb_vector, couchbase, vikingdb, upstash, lindorm, oceanbase
VECTOR_STORE=weaviate
# Weaviate configuration
@@ -273,7 +273,7 @@ LINDORM_PASSWORD=admin
OCEANBASE_VECTOR_HOST=127.0.0.1
OCEANBASE_VECTOR_PORT=2881
OCEANBASE_VECTOR_USER=root@test
OCEANBASE_VECTOR_PASSWORD=
OCEANBASE_VECTOR_PASSWORD=difyai123456
OCEANBASE_VECTOR_DATABASE=test
OCEANBASE_MEMORY_LIMIT=6G
@@ -320,9 +320,14 @@ ETL_TYPE=dify
UNSTRUCTURED_API_URL=
UNSTRUCTURED_API_KEY=
#ssrf
SSRF_PROXY_HTTP_URL=
SSRF_PROXY_HTTPS_URL=
SSRF_DEFAULT_MAX_RETRIES=3
SSRF_DEFAULT_TIME_OUT=5
SSRF_DEFAULT_CONNECT_TIME_OUT=5
SSRF_DEFAULT_READ_TIME_OUT=5
SSRF_DEFAULT_WRITE_TIME_OUT=5
BATCH_UPLOAD_LIMIT=10
KEYWORD_DATA_SOURCE_TYPE=database
+2 -2
View File
@@ -76,13 +76,13 @@
1. Install dependencies for both the backend and the test environment
```bash
poetry install --with dev
poetry install -C api --with dev
```
2. Run the tests locally with mocked system environment variables in `tool.pytest_env` section in `pyproject.toml`
```bash
cd ../
poetry run -C api bash dev/pytest/pytest_all_tests.sh
```
+1 -1
View File
@@ -2,7 +2,7 @@ import os
from configs import dify_config
if os.environ.get("DEBUG", "false").lower() != "true":
if not dify_config.DEBUG:
from gevent import monkey
monkey.patch_all()
+3 -1
View File
@@ -1,6 +1,8 @@
import os
if os.environ.get("DEBUG", "false").lower() != "true":
from configs import dify_config
if not dify_config.DEBUG:
from gevent import monkey
monkey.patch_all()
+31 -1
View File
@@ -109,7 +109,7 @@ class CodeExecutionSandboxConfig(BaseSettings):
)
CODE_MAX_PRECISION: PositiveInt = Field(
description="mMaximum number of decimal places for floating-point numbers in code execution",
description="Maximum number of decimal places for floating-point numbers in code execution",
default=20,
)
@@ -276,6 +276,16 @@ class HttpConfig(BaseSettings):
default=1 * 1024 * 1024,
)
SSRF_DEFAULT_MAX_RETRIES: PositiveInt = Field(
description="Maximum number of retries for network requests (SSRF)",
default=3,
)
SSRF_PROXY_ALL_URL: Optional[str] = Field(
description="Proxy URL for HTTP or HTTPS requests to prevent Server-Side Request Forgery (SSRF)",
default=None,
)
SSRF_PROXY_HTTP_URL: Optional[str] = Field(
description="Proxy URL for HTTP requests to prevent Server-Side Request Forgery (SSRF)",
default=None,
@@ -286,6 +296,26 @@ class HttpConfig(BaseSettings):
default=None,
)
SSRF_DEFAULT_TIME_OUT: PositiveFloat = Field(
description="The default timeout period used for network requests (SSRF)",
default=5,
)
SSRF_DEFAULT_CONNECT_TIME_OUT: PositiveFloat = Field(
description="The default connect timeout period used for network requests (SSRF)",
default=5,
)
SSRF_DEFAULT_READ_TIME_OUT: PositiveFloat = Field(
description="The default read timeout period used for network requests (SSRF)",
default=5,
)
SSRF_DEFAULT_WRITE_TIME_OUT: PositiveFloat = Field(
description="The default write timeout period used for network requests (SSRF)",
default=5,
)
RESPECT_XFORWARD_HEADERS_ENABLED: bool = Field(
description="Enable or disable the X-Forwarded-For Proxy Fix middleware from Werkzeug"
" to respect X-* headers to redirect clients",
+1 -1
View File
@@ -9,7 +9,7 @@ class PackagingInfo(BaseSettings):
CURRENT_VERSION: str = Field(
description="Dify version",
default="0.10.2",
default="0.11.0",
)
COMMIT_SHA: str = Field(
@@ -945,7 +945,7 @@ class DocumentRetryApi(DocumentResource):
raise DocumentAlreadyFinishedError()
retry_documents.append(document)
except Exception as e:
logging.error(f"Document {document_id} retry failed: {str(e)}")
logging.exception(f"Document {document_id} retry failed: {str(e)}")
continue
# retry document
DocumentService.retry_document(dataset_id, retry_documents)
+24
View File
@@ -62,3 +62,27 @@ class EmailSendIpLimitError(BaseHTTPException):
error_code = "email_send_ip_limit"
description = "Too many emails have been sent from this IP address recently. Please try again later."
code = 429
class FileTooLargeError(BaseHTTPException):
error_code = "file_too_large"
description = "File size exceeded. {message}"
code = 413
class UnsupportedFileTypeError(BaseHTTPException):
error_code = "unsupported_file_type"
description = "File type not allowed."
code = 415
class TooManyFilesError(BaseHTTPException):
error_code = "too_many_files"
description = "Only one file is allowed."
code = 400
class NoFileUploadedError(BaseHTTPException):
error_code = "no_file_uploaded"
description = "Please upload your file."
code = 400
@@ -15,7 +15,7 @@ from fields.file_fields import file_fields, upload_config_fields
from libs.login import login_required
from services.file_service import FileService
from .errors import (
from .error import (
FileTooLargeError,
NoFileUploadedError,
TooManyFilesError,
-25
View File
@@ -1,25 +0,0 @@
from libs.exception import BaseHTTPException
class FileTooLargeError(BaseHTTPException):
error_code = "file_too_large"
description = "File size exceeded. {message}"
code = 413
class UnsupportedFileTypeError(BaseHTTPException):
error_code = "unsupported_file_type"
description = "File type not allowed."
code = 415
class TooManyFilesError(BaseHTTPException):
error_code = "too_many_files"
description = "Only one file is allowed."
code = 400
class NoFileUploadedError(BaseHTTPException):
error_code = "no_file_uploaded"
description = "Please upload your file."
code = 400
+27 -17
View File
@@ -1,9 +1,11 @@
import urllib.parse
from typing import cast
import httpx
from flask_login import current_user
from flask_restful import Resource, marshal_with, reqparse
import services
from controllers.common import helpers
from core.file import helpers as file_helpers
from core.helper import ssrf_proxy
@@ -11,19 +13,25 @@ from fields.file_fields import file_fields_with_signed_url, remote_file_info_fie
from models.account import Account
from services.file_service import FileService
from .error import (
FileTooLargeError,
UnsupportedFileTypeError,
)
class RemoteFileInfoApi(Resource):
@marshal_with(remote_file_info_fields)
def get(self, url):
decoded_url = urllib.parse.unquote(url)
try:
response = ssrf_proxy.head(decoded_url)
return {
"file_type": response.headers.get("Content-Type", "application/octet-stream"),
"file_length": int(response.headers.get("Content-Length", 0)),
}
except Exception as e:
return {"error": str(e)}, 400
resp = ssrf_proxy.head(decoded_url)
if resp.status_code != httpx.codes.OK:
# failed back to get method
resp = ssrf_proxy.get(decoded_url, timeout=3)
resp.raise_for_status()
return {
"file_type": resp.headers.get("Content-Type", "application/octet-stream"),
"file_length": int(resp.headers.get("Content-Length", 0)),
}
class RemoteFileUploadApi(Resource):
@@ -35,17 +43,17 @@ class RemoteFileUploadApi(Resource):
url = args["url"]
response = ssrf_proxy.head(url)
response.raise_for_status()
resp = ssrf_proxy.head(url=url)
if resp.status_code != httpx.codes.OK:
resp = ssrf_proxy.get(url=url, timeout=3)
resp.raise_for_status()
file_info = helpers.guess_file_info_from_response(response)
file_info = helpers.guess_file_info_from_response(resp)
if not FileService.is_file_size_within_limit(extension=file_info.extension, file_size=file_info.size):
return {"error": "File size exceeded"}, 400
raise FileTooLargeError
response = ssrf_proxy.get(url)
response.raise_for_status()
content = response.content
content = resp.content if resp.request.method == "GET" else ssrf_proxy.get(url).content
try:
user = cast(Account, current_user)
@@ -56,8 +64,10 @@ class RemoteFileUploadApi(Resource):
user=user,
source_url=url,
)
except Exception as e:
return {"error": str(e)}, 400
except services.errors.file.FileTooLargeError as file_too_large_error:
raise FileTooLargeError(file_too_large_error.description)
except services.errors.file.UnsupportedFileTypeError:
raise UnsupportedFileTypeError()
return {
"id": upload_file.id,
@@ -7,7 +7,11 @@ from controllers.service_api import api
from controllers.service_api.app.error import NotChatAppError
from controllers.service_api.wraps import FetchUserArg, WhereisUserArg, validate_app_token
from core.app.entities.app_invoke_entities import InvokeFrom
from fields.conversation_fields import conversation_infinite_scroll_pagination_fields, simple_conversation_fields
from fields.conversation_fields import (
conversation_delete_fields,
conversation_infinite_scroll_pagination_fields,
simple_conversation_fields,
)
from libs.helper import uuid_value
from models.model import App, AppMode, EndUser
from services.conversation_service import ConversationService
@@ -49,7 +53,7 @@ class ConversationApi(Resource):
class ConversationDetailApi(Resource):
@validate_app_token(fetch_user_arg=FetchUserArg(fetch_from=WhereisUserArg.JSON))
@marshal_with(simple_conversation_fields)
@marshal_with(conversation_delete_fields)
def delete(self, app_model: App, end_user: EndUser, c_id):
app_mode = AppMode.value_of(app_model.mode)
if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}:
@@ -58,10 +62,9 @@ class ConversationDetailApi(Resource):
conversation_id = str(c_id)
try:
ConversationService.delete(app_model, conversation_id, end_user)
return ConversationService.delete(app_model, conversation_id, end_user)
except services.errors.conversation.ConversationNotExistsError:
raise NotFound("Conversation Not Exists.")
return {"result": "success"}, 200
class ConversationRenameApi(Resource):
-1
View File
@@ -41,7 +41,6 @@ class FileApi(Resource):
content=file.read(),
mimetype=file.mimetype,
user=end_user,
source="datasets",
)
except services.errors.file.FileTooLargeError as file_too_large_error:
raise FileTooLargeError(file_too_large_error.description)
+26 -19
View File
@@ -1,7 +1,9 @@
import urllib.parse
import httpx
from flask_restful import marshal_with, reqparse
import services
from controllers.common import helpers
from controllers.web.wraps import WebApiResource
from core.file import helpers as file_helpers
@@ -9,19 +11,22 @@ from core.helper import ssrf_proxy
from fields.file_fields import file_fields_with_signed_url, remote_file_info_fields
from services.file_service import FileService
from .error import FileTooLargeError, UnsupportedFileTypeError
class RemoteFileInfoApi(WebApiResource):
@marshal_with(remote_file_info_fields)
def get(self, url):
def get(self, app_model, end_user, url):
decoded_url = urllib.parse.unquote(url)
try:
response = ssrf_proxy.head(decoded_url)
return {
"file_type": response.headers.get("Content-Type", "application/octet-stream"),
"file_length": int(response.headers.get("Content-Length", -1)),
}
except Exception as e:
return {"error": str(e)}, 400
resp = ssrf_proxy.head(decoded_url)
if resp.status_code != httpx.codes.OK:
# failed back to get method
resp = ssrf_proxy.get(decoded_url, timeout=3)
resp.raise_for_status()
return {
"file_type": resp.headers.get("Content-Type", "application/octet-stream"),
"file_length": int(resp.headers.get("Content-Length", -1)),
}
class RemoteFileUploadApi(WebApiResource):
@@ -33,28 +38,30 @@ class RemoteFileUploadApi(WebApiResource):
url = args["url"]
response = ssrf_proxy.head(url)
response.raise_for_status()
resp = ssrf_proxy.head(url=url)
if resp.status_code != httpx.codes.OK:
resp = ssrf_proxy.get(url=url, timeout=3)
resp.raise_for_status()
file_info = helpers.guess_file_info_from_response(response)
file_info = helpers.guess_file_info_from_response(resp)
if not FileService.is_file_size_within_limit(extension=file_info.extension, file_size=file_info.size):
return {"error": "File size exceeded"}, 400
raise FileTooLargeError
response = ssrf_proxy.get(url)
response.raise_for_status()
content = response.content
content = resp.content if resp.request.method == "GET" else ssrf_proxy.get(url).content
try:
upload_file = FileService.upload_file(
filename=file_info.filename,
content=content,
mimetype=file_info.mimetype,
user=end_user, # Use end_user instead of current_user
user=end_user,
source_url=url,
)
except Exception as e:
return {"error": str(e)}, 400
except services.errors.file.FileTooLargeError as file_too_large_error:
raise FileTooLargeError(file_too_large_error.description)
except services.errors.file.UnsupportedFileTypeError:
raise UnsupportedFileTypeError
return {
"id": upload_file.id,
@@ -1,6 +1,5 @@
import contextvars
import logging
import os
import threading
import uuid
from collections.abc import Generator
@@ -10,6 +9,7 @@ from flask import Flask, current_app
from pydantic import ValidationError
import contexts
from configs import dify_config
from constants import UUID_NIL
from core.app.app_config.features.file_upload.manager import FileUploadConfigManager
from core.app.apps.advanced_chat.app_config_manager import AdvancedChatAppConfigManager
@@ -317,7 +317,7 @@ class AdvancedChatAppGenerator(MessageBasedAppGenerator):
logger.exception("Validation Error when generating")
queue_manager.publish_error(e, PublishFrom.APPLICATION_MANAGER)
except (ValueError, InvokeError) as e:
if os.environ.get("DEBUG", "false").lower() == "true":
if dify_config.DEBUG:
logger.exception("Error when generating")
queue_manager.publish_error(e, PublishFrom.APPLICATION_MANAGER)
except Exception as e:
@@ -242,7 +242,7 @@ class AdvancedChatAppGenerateTaskPipeline(BasedGenerateTaskPipeline, WorkflowCyc
start_listener_time = time.time()
yield MessageAudioStreamResponse(audio=audio_trunk.audio, task_id=task_id)
except Exception as e:
logger.error(e)
logger.exception(e)
break
if tts_publisher:
yield MessageAudioEndStreamResponse(audio="", task_id=task_id)
@@ -1,5 +1,4 @@
import logging
import os
import threading
import uuid
from collections.abc import Generator
@@ -8,6 +7,7 @@ from typing import Any, Literal, Union, overload
from flask import Flask, current_app
from pydantic import ValidationError
from configs import dify_config
from constants import UUID_NIL
from core.app.app_config.easy_ui_based_app.model_config.converter import ModelConfigConverter
from core.app.app_config.features.file_upload.manager import FileUploadConfigManager
@@ -230,7 +230,7 @@ class AgentChatAppGenerator(MessageBasedAppGenerator):
logger.exception("Validation Error when generating")
queue_manager.publish_error(e, PublishFrom.APPLICATION_MANAGER)
except (ValueError, InvokeError) as e:
if os.environ.get("DEBUG") and os.environ.get("DEBUG").lower() == "true":
if dify_config.DEBUG:
logger.exception("Error when generating")
queue_manager.publish_error(e, PublishFrom.APPLICATION_MANAGER)
except Exception as e:
+2 -2
View File
@@ -1,5 +1,4 @@
import logging
import os
import threading
import uuid
from collections.abc import Generator
@@ -8,6 +7,7 @@ from typing import Any, Literal, Union, overload
from flask import Flask, current_app
from pydantic import ValidationError
from configs import dify_config
from constants import UUID_NIL
from core.app.app_config.easy_ui_based_app.model_config.converter import ModelConfigConverter
from core.app.app_config.features.file_upload.manager import FileUploadConfigManager
@@ -227,7 +227,7 @@ class ChatAppGenerator(MessageBasedAppGenerator):
logger.exception("Validation Error when generating")
queue_manager.publish_error(e, PublishFrom.APPLICATION_MANAGER)
except (ValueError, InvokeError) as e:
if os.environ.get("DEBUG") and os.environ.get("DEBUG").lower() == "true":
if dify_config.DEBUG:
logger.exception("Error when generating")
queue_manager.publish_error(e, PublishFrom.APPLICATION_MANAGER)
except Exception as e:
@@ -1,5 +1,4 @@
import logging
import os
import threading
import uuid
from collections.abc import Generator
@@ -8,6 +7,7 @@ from typing import Any, Literal, Union, overload
from flask import Flask, current_app
from pydantic import ValidationError
from configs import dify_config
from core.app.app_config.easy_ui_based_app.model_config.converter import ModelConfigConverter
from core.app.app_config.features.file_upload.manager import FileUploadConfigManager
from core.app.apps.base_app_queue_manager import AppQueueManager, GenerateTaskStoppedError, PublishFrom
@@ -203,7 +203,7 @@ class CompletionAppGenerator(MessageBasedAppGenerator):
logger.exception("Validation Error when generating")
queue_manager.publish_error(e, PublishFrom.APPLICATION_MANAGER)
except (ValueError, InvokeError) as e:
if os.environ.get("DEBUG") and os.environ.get("DEBUG").lower() == "true":
if dify_config.DEBUG:
logger.exception("Error when generating")
queue_manager.publish_error(e, PublishFrom.APPLICATION_MANAGER)
except Exception as e:
+2 -2
View File
@@ -1,6 +1,5 @@
import contextvars
import logging
import os
import threading
import uuid
from collections.abc import Generator, Mapping, Sequence
@@ -10,6 +9,7 @@ from flask import Flask, current_app
from pydantic import ValidationError
import contexts
from configs import dify_config
from core.app.app_config.features.file_upload.manager import FileUploadConfigManager
from core.app.apps.base_app_generator import BaseAppGenerator
from core.app.apps.base_app_queue_manager import AppQueueManager, GenerateTaskStoppedError, PublishFrom
@@ -261,7 +261,7 @@ class WorkflowAppGenerator(BaseAppGenerator):
logger.exception("Validation Error when generating")
queue_manager.publish_error(e, PublishFrom.APPLICATION_MANAGER)
except (ValueError, InvokeError) as e:
if os.environ.get("DEBUG") and os.environ.get("DEBUG", "false").lower() == "true":
if dify_config.DEBUG:
logger.exception("Error when generating")
queue_manager.publish_error(e, PublishFrom.APPLICATION_MANAGER)
except Exception as e:
@@ -216,7 +216,7 @@ class WorkflowAppGenerateTaskPipeline(BasedGenerateTaskPipeline, WorkflowCycleMa
else:
yield MessageAudioStreamResponse(audio=audio_trunk.audio, task_id=task_id)
except Exception as e:
logger.error(e)
logger.exception(e)
break
if tts_publisher:
yield MessageAudioEndStreamResponse(audio="", task_id=task_id)
+16 -10
View File
@@ -3,22 +3,20 @@ Proxy requests to avoid SSRF
"""
import logging
import os
import time
import httpx
SSRF_PROXY_ALL_URL = os.getenv("SSRF_PROXY_ALL_URL", "")
SSRF_PROXY_HTTP_URL = os.getenv("SSRF_PROXY_HTTP_URL", "")
SSRF_PROXY_HTTPS_URL = os.getenv("SSRF_PROXY_HTTPS_URL", "")
SSRF_DEFAULT_MAX_RETRIES = int(os.getenv("SSRF_DEFAULT_MAX_RETRIES", "3"))
from configs import dify_config
SSRF_DEFAULT_MAX_RETRIES = dify_config.SSRF_DEFAULT_MAX_RETRIES
proxy_mounts = (
{
"http://": httpx.HTTPTransport(proxy=SSRF_PROXY_HTTP_URL),
"https://": httpx.HTTPTransport(proxy=SSRF_PROXY_HTTPS_URL),
"http://": httpx.HTTPTransport(proxy=dify_config.SSRF_PROXY_HTTP_URL),
"https://": httpx.HTTPTransport(proxy=dify_config.SSRF_PROXY_HTTPS_URL),
}
if SSRF_PROXY_HTTP_URL and SSRF_PROXY_HTTPS_URL
if dify_config.SSRF_PROXY_HTTP_URL and dify_config.SSRF_PROXY_HTTPS_URL
else None
)
@@ -32,11 +30,19 @@ def make_request(method, url, max_retries=SSRF_DEFAULT_MAX_RETRIES, **kwargs):
if "follow_redirects" not in kwargs:
kwargs["follow_redirects"] = allow_redirects
if "timeout" not in kwargs:
kwargs["timeout"] = httpx.Timeout(
timeout=dify_config.SSRF_DEFAULT_TIME_OUT,
connect=dify_config.SSRF_DEFAULT_CONNECT_TIME_OUT,
read=dify_config.SSRF_DEFAULT_READ_TIME_OUT,
write=dify_config.SSRF_DEFAULT_WRITE_TIME_OUT,
)
retries = 0
while retries <= max_retries:
try:
if SSRF_PROXY_ALL_URL:
with httpx.Client(proxy=SSRF_PROXY_ALL_URL) as client:
if dify_config.SSRF_PROXY_ALL_URL:
with httpx.Client(proxy=dify_config.SSRF_PROXY_ALL_URL) as client:
response = client.request(method=method, url=url, **kwargs)
elif proxy_mounts:
with httpx.Client(mounts=proxy_mounts) as client:
+2 -2
View File
@@ -1,8 +1,8 @@
import logging
import os
from collections.abc import Callable, Generator, Iterable, Sequence
from typing import IO, Any, Optional, Union, cast
from configs import dify_config
from core.entities.embedding_type import EmbeddingInputType
from core.entities.provider_configuration import ProviderConfiguration, ProviderModelBundle
from core.entities.provider_entities import ModelLoadBalancingConfiguration
@@ -473,7 +473,7 @@ class LBModelManager:
continue
if bool(os.environ.get("DEBUG", "False").lower() == "true"):
if dify_config.DEBUG:
logger.info(
f"Model LB\nid: {config.id}\nname:{config.name}\n"
f"tenant_id: {self._tenant_id}\nprovider: {self._provider}\n"
@@ -4,7 +4,6 @@ label:
model_type: llm
features:
- agent-thought
- vision
- tool-call
- stream-tool-call
model_properties:
@@ -47,9 +47,9 @@ class AzureRerankModel(RerankModel):
result = response.read()
return json.loads(result)
except urllib.error.HTTPError as error:
logger.error(f"The request failed with status code: {error.code}")
logger.error(error.info())
logger.error(error.read().decode("utf8", "ignore"))
logger.exception(f"The request failed with status code: {error.code}")
logger.exception(error.info())
logger.exception(error.read().decode("utf8", "ignore"))
raise
def _invoke(
@@ -4,7 +4,6 @@ label:
model_type: llm
features:
- agent-thought
- vision
- tool-call
- stream-tool-call
model_properties:
@@ -4,7 +4,6 @@ label:
model_type: llm
features:
- agent-thought
- vision
- tool-call
- stream-tool-call
model_properties:
@@ -0,0 +1,38 @@
model: anthropic/claude-3-5-haiku
label:
en_US: claude-3-5-haiku
model_type: llm
features:
- agent-thought
- tool-call
- stream-tool-call
model_properties:
mode: chat
context_size: 200000
parameter_rules:
- name: temperature
use_template: temperature
- name: top_p
use_template: top_p
- name: top_k
label:
zh_Hans: 取样数量
en_US: Top k
type: int
help:
zh_Hans: 仅从每个后续标记的前 K 个选项中采样。
en_US: Only sample from the top K options for each subsequent token.
required: false
- name: max_tokens
use_template: max_tokens
required: true
default: 8192
min: 1
max: 8192
- name: response_format
use_template: response_format
pricing:
input: "1"
output: "5"
unit: "0.000001"
currency: USD
@@ -4,10 +4,7 @@ import re
from collections.abc import Generator, Iterator
from typing import Any, Optional, Union, cast
# from openai.types.chat import ChatCompletion, ChatCompletionChunk
import boto3
from sagemaker import Predictor, serializers
from sagemaker.session import Session
from core.model_runtime.entities.llm_entities import LLMMode, LLMResult, LLMResultChunk, LLMResultChunkDelta
from core.model_runtime.entities.message_entities import (
@@ -212,6 +209,9 @@ class SageMakerLargeLanguageModel(LargeLanguageModel):
:param user: unique user id
:return: full response or stream response chunk generator result
"""
from sagemaker import Predictor, serializers
from sagemaker.session import Session
if not self.sagemaker_session:
access_key = credentials.get("aws_access_key_id")
secret_key = credentials.get("aws_secret_access_key")
+1 -1
View File
@@ -126,6 +126,6 @@ class OutputModeration(BaseModel):
result: ModerationOutputsResult = moderation_factory.moderation_for_outputs(moderation_buffer)
return result
except Exception as e:
logger.error("Moderation Output error: %s", e)
logger.exception("Moderation Output error: %s", e)
return None
+2 -2
View File
@@ -708,7 +708,7 @@ class TraceQueueManager:
trace_task.app_id = self.app_id
trace_manager_queue.put(trace_task)
except Exception as e:
logging.error(f"Error adding trace task: {e}")
logging.exception(f"Error adding trace task: {e}")
finally:
self.start_timer()
@@ -727,7 +727,7 @@ class TraceQueueManager:
if tasks:
self.send_to_celery(tasks)
except Exception as e:
logging.error(f"Error processing trace tasks: {e}")
logging.exception(f"Error processing trace tasks: {e}")
def start_timer(self):
global trace_manager_timer
@@ -242,7 +242,7 @@ class CouchbaseVector(BaseVector):
try:
self._cluster.query(query, named_parameters={"doc_ids": ids}).execute()
except Exception as e:
logger.error(e)
logger.exception(e)
def delete_by_document_id(self, document_id: str):
query = f"""
@@ -79,7 +79,7 @@ class LindormVectorStore(BaseVector):
existing_docs = self._client.mget(index=self._collection_name, body={"ids": batch_ids}, _source=False)
return {doc["_id"] for doc in existing_docs["docs"] if doc["found"]}
except Exception as e:
logger.error(f"Error fetching batch {batch_ids}: {e}")
logger.exception(f"Error fetching batch {batch_ids}: {e}")
return set()
@retry(stop=stop_after_attempt(3), wait=wait_fixed(60))
@@ -96,7 +96,7 @@ class LindormVectorStore(BaseVector):
)
return {doc["_id"] for doc in existing_docs["docs"] if doc["found"]}
except Exception as e:
logger.error(f"Error fetching batch {batch_ids}: {e}")
logger.exception(f"Error fetching batch {batch_ids}: {e}")
return set()
if ids is None:
@@ -177,7 +177,7 @@ class LindormVectorStore(BaseVector):
else:
logger.warning(f"Index '{self._collection_name}' does not exist. No deletion performed.")
except Exception as e:
logger.error(f"Error occurred while deleting the index: {e}")
logger.exception(f"Error occurred while deleting the index: {e}")
raise e
def text_exists(self, id: str) -> bool:
@@ -201,7 +201,7 @@ class LindormVectorStore(BaseVector):
try:
response = self._client.search(index=self._collection_name, body=query)
except Exception as e:
logger.error(f"Error executing search: {e}")
logger.exception(f"Error executing search: {e}")
raise
docs_and_scores = []
@@ -86,7 +86,7 @@ class MilvusVector(BaseVector):
ids = self._client.insert(collection_name=self._collection_name, data=batch_insert_list)
pks.extend(ids)
except MilvusException as e:
logger.error("Failed to insert batch starting at entity: %s/%s", i, total_count)
logger.exception("Failed to insert batch starting at entity: %s/%s", i, total_count)
raise e
return pks
@@ -142,7 +142,7 @@ class MyScaleVector(BaseVector):
for r in self._client.query(sql).named_results()
]
except Exception as e:
logging.error(f"\033[91m\033[1m{type(e)}\033[0m \033[95m{str(e)}\033[0m")
logging.exception(f"\033[91m\033[1m{type(e)}\033[0m \033[95m{str(e)}\033[0m")
return []
def delete(self) -> None:
@@ -129,7 +129,7 @@ class OpenSearchVector(BaseVector):
if status == 404:
logger.warning(f"Document not found for deletion: {doc_id}")
else:
logger.error(f"Error deleting document: {error}")
logger.exception(f"Error deleting document: {error}")
def delete(self) -> None:
self._client.indices.delete(index=self._collection_name.lower())
@@ -158,7 +158,7 @@ class OpenSearchVector(BaseVector):
try:
response = self._client.search(index=self._collection_name.lower(), body=query)
except Exception as e:
logger.error(f"Error executing search: {e}")
logger.exception(f"Error executing search: {e}")
raise
docs = []
+1 -1
View File
@@ -89,7 +89,7 @@ class CacheEmbedding(Embeddings):
db.session.rollback()
except Exception as ex:
db.session.rollback()
logger.error("Failed to embed documents: %s", ex)
logger.exception("Failed to embed documents: %s", ex)
raise ex
return text_embeddings
+4 -5
View File
@@ -28,7 +28,6 @@ logger = logging.getLogger(__name__)
class WordExtractor(BaseExtractor):
"""Load docx files.
Args:
file_path: Path to the file to load.
"""
@@ -51,9 +50,9 @@ class WordExtractor(BaseExtractor):
self.web_path = self.file_path
# TODO: use a better way to handle the file
self.temp_file = tempfile.NamedTemporaryFile() # noqa: SIM115
self.temp_file.write(r.content)
self.file_path = self.temp_file.name
with tempfile.NamedTemporaryFile(delete=False) as self.temp_file:
self.temp_file.write(r.content)
self.file_path = self.temp_file.name
elif not os.path.isfile(self.file_path):
raise ValueError(f"File path {self.file_path} is not a valid file or url")
@@ -230,7 +229,7 @@ class WordExtractor(BaseExtractor):
for i in url_pattern.findall(x.text):
hyperlinks_url = str(i)
except Exception as e:
logger.error(e)
logger.exception(e)
def parse_paragraph(paragraph):
paragraph_content = []
+7
View File
@@ -48,6 +48,13 @@
- feishu_task
- feishu_calendar
- feishu_spreadsheet
- lark_base
- lark_document
- lark_message_and_group
- lark_wiki
- lark_task
- lark_calendar
- lark_spreadsheet
- slack
- twilio
- wecom
@@ -8,6 +8,20 @@ from core.tools.provider.builtin.comfyui.tools.comfyui_client import ComfyUiClie
from core.tools.tool.builtin_tool import BuiltinTool
def sanitize_json_string(s):
escape_dict = {
"\n": "\\n",
"\r": "\\r",
"\t": "\\t",
"\b": "\\b",
"\f": "\\f",
}
for char, escaped in escape_dict.items():
s = s.replace(char, escaped)
return s
class ComfyUIWorkflowTool(BuiltinTool):
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage | list[ToolInvokeMessage]:
comfyui = ComfyUiClient(self.runtime.credentials["base_url"])
@@ -26,13 +40,17 @@ class ComfyUIWorkflowTool(BuiltinTool):
set_prompt_with_ksampler = True
if "{{positive_prompt}}" in workflow:
set_prompt_with_ksampler = False
workflow = workflow.replace("{{positive_prompt}}", positive_prompt)
workflow = workflow.replace("{{negative_prompt}}", negative_prompt)
workflow = workflow.replace("{{positive_prompt}}", positive_prompt.replace('"', "'"))
workflow = workflow.replace("{{negative_prompt}}", negative_prompt.replace('"', "'"))
try:
prompt = json.loads(workflow)
except:
return self.create_text_message("the Workflow JSON is not correct")
except json.JSONDecodeError:
cleaned_string = sanitize_json_string(workflow)
try:
prompt = json.loads(cleaned_string)
except:
return self.create_text_message("the Workflow JSON is not correct")
if set_prompt_with_ksampler:
try:
@@ -34,7 +34,7 @@ parameters:
Page size, default value: 20, maximum value: 100.
zh_Hans: 分页大小,默认值:20,最大值:100。
llm_description: 分页大小,默认值:20,最大值:100。
form: llm
form: form
- name: page_token
type: string
@@ -147,7 +147,7 @@ parameters:
Page size, default value: 20, maximum value: 500.
zh_Hans: 分页大小,默认值:20,最大值:500。
llm_description: 分页大小,默认值:20,最大值:500。
form: llm
form: form
- name: page_token
type: string
@@ -47,7 +47,7 @@ parameters:
en_US: The page size, i.e., the number of data entries returned in a single request. The default value is 50, and the value range is [50,1000].
zh_Hans: 分页大小,即单次请求所返回的数据条目数。默认值为 50,取值范围为 [50,1000]。
llm_description: 分页大小,即单次请求所返回的数据条目数。默认值为 50,取值范围为 [50,1000]。
form: llm
form: form
- name: page_token
type: string
@@ -85,7 +85,7 @@ parameters:
en_US: The page size, i.e., the number of data entries returned in a single request. The default value is 20, and the value range is [10,100].
zh_Hans: 分页大小,即单次请求所返回的数据条目数。默认值为 20,取值范围为 [10,100]。
llm_description: 分页大小,即单次请求所返回的数据条目数。默认值为 20,取值范围为 [10,100]。
form: llm
form: form
- name: page_token
type: string
@@ -59,7 +59,7 @@ parameters:
en_US: Paging size, the default and maximum value is 500.
zh_Hans: 分页大小, 默认值和最大值为 500。
llm_description: 分页大小, 表示一次请求最多返回多少条数据,默认值和最大值为 500。
form: llm
form: form
- name: page_token
type: string
@@ -81,7 +81,7 @@ parameters:
en_US: The page size, i.e., the number of data entries returned in a single request. The default value is 20, and the value range is [1,50].
zh_Hans: 分页大小,即单次请求所返回的数据条目数。默认值为 20,取值范围为 [1,50]。
llm_description: 分页大小,即单次请求所返回的数据条目数。默认值为 20,取值范围为 [1,50]。
form: llm
form: form
- name: page_token
type: string
@@ -57,7 +57,7 @@ parameters:
en_US: The page size, i.e., the number of data entries returned in a single request. The default value is 20, and the value range is [1,50].
zh_Hans: 分页大小,即单次请求所返回的数据条目数。默认值为 20,取值范围为 [1,50]。
llm_description: 分页大小,即单次请求所返回的数据条目数。默认值为 20,取值范围为 [1,50]。
form: llm
form: form
- name: page_token
type: string
@@ -56,7 +56,7 @@ parameters:
en_US: Number of columns to add, range (0-5000].
zh_Hans: 要增加的列数,范围(0-5000]。
llm_description: 要增加的列数,范围(0-5000]。
form: llm
form: form
- name: values
type: string
@@ -56,7 +56,7 @@ parameters:
en_US: Number of rows to add, range (0-5000].
zh_Hans: 要增加行数,范围(0-5000]。
llm_description: 要增加行数,范围(0-5000]。
form: llm
form: form
- name: values
type: string
@@ -82,7 +82,7 @@ parameters:
en_US: Starting column number, starting from 1.
zh_Hans: 起始列号,从 1 开始。
llm_description: 起始列号,从 1 开始。
form: llm
form: form
- name: num_cols
type: number
@@ -94,4 +94,4 @@ parameters:
en_US: Number of columns to read.
zh_Hans: 读取列数
llm_description: 读取列数
form: llm
form: form
@@ -82,7 +82,7 @@ parameters:
en_US: Starting row number, starting from 1.
zh_Hans: 起始行号,从 1 开始。
llm_description: 起始行号,从 1 开始。
form: llm
form: form
- name: num_rows
type: number
@@ -94,4 +94,4 @@ parameters:
en_US: Number of rows to read.
zh_Hans: 读取行数
llm_description: 读取行数
form: llm
form: form
@@ -82,7 +82,7 @@ parameters:
en_US: Starting row number, starting from 1.
zh_Hans: 起始行号,从 1 开始。
llm_description: 起始行号,从 1 开始。
form: llm
form: form
- name: num_rows
type: number
@@ -94,7 +94,7 @@ parameters:
en_US: Number of rows to read.
zh_Hans: 读取行数
llm_description: 读取行数
form: llm
form: form
- name: range
type: string
@@ -36,7 +36,7 @@ parameters:
en_US: The size of each page, with a maximum value of 50.
zh_Hans: 分页大小,最大值 50。
llm_description: 分页大小,最大值 50。
form: llm
form: form
- name: page_token
type: string
@@ -0,0 +1,3 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M25.132 24.3947C25.497 25.7527 25.8984 27.1413 26.3334 28.5834C26.7302 29.8992 25.5459 30.4167 25.0752 29.1758C24.571 27.8466 24.0885 26.523 23.6347 25.1729C21.065 26.4654 18.5025 27.5424 15.5961 28.7541C16.7581 33.0256 17.8309 36.5984 19.4952 39.9935C19.4953 39.9936 19.4953 39.9937 19.4954 39.9938C19.6631 39.9979 19.8313 40 20 40C31.0457 40 40 31.0457 40 20C40 16.0335 38.8453 12.3366 36.8537 9.22729C31.6585 9.69534 27.0513 10.4562 22.8185 11.406C22.8882 12.252 22.9677 13.0739 23.0555 13.855C23.3824 16.7604 23.9112 19.5281 24.6137 22.3836C27.0581 21.2848 29.084 20.3225 30.6816 19.522C32.2154 18.7535 33.6943 18.7062 31.2018 20.6594C29.0388 22.1602 27.0644 23.3566 25.132 24.3947ZM36.1559 8.20846C33.0001 3.89184 28.1561 0.887462 22.5955 0.166882C22.4257 2.86234 22.4785 6.26344 22.681 9.50447C26.7473 8.88859 31.1721 8.46032 36.1559 8.20846ZM19.9369 9.73661e-05C19.7594 2.92694 19.8384 6.65663 20.19 9.91293C17.3748 10.4109 14.7225 11.0064 12.1592 11.7038C12.0486 10.4257 11.9927 9.25764 11.9927 8.24178C11.9927 7.5054 11.3957 6.90844 10.6593 6.90844C9.92296 6.90844 9.32601 7.5054 9.32601 8.24178C9.32601 9.47868 9.42873 10.898 9.61402 12.438C8.33567 12.8278 7.07397 13.2443 5.81918 13.688C5.12493 13.9336 4.76118 14.6954 5.0067 15.3896C5.25223 16.0839 6.01406 16.4476 6.7083 16.2021C7.7931 15.8185 8.88482 15.4388 9.98927 15.0659C10.5222 18.3344 11.3344 21.9428 12.2703 25.4156C12.4336 26.0218 12.6062 26.6262 12.7863 27.2263C9.34168 28.4135 5.82612 29.3782 2.61128 29.8879C0.949407 26.9716 0 23.5967 0 20C0 8.97534 8.92023 0.0341108 19.9369 9.73661e-05ZM4.19152 32.2527C7.45069 36.4516 12.3458 39.3173 17.9204 39.8932C16.5916 37.455 14.9338 33.717 13.5405 29.5901C10.4404 30.7762 7.25883 31.6027 4.19152 32.2527ZM22.9735 23.1135C22.1479 20.41 21.4462 17.5441 20.9225 14.277C20.746 13.5841 20.5918 12.8035 20.4593 11.9636C17.6508 12.6606 14.9992 13.4372 12.4356 14.2598C12.8479 17.4766 13.5448 21.1334 14.5118 24.7218C14.662 25.2792 14.8081 25.8248 14.9514 26.3594L14.9516 26.3603L14.9524 26.3634L14.9526 26.3639L14.973 26.4401C16.1833 25.9872 17.3746 25.5123 18.53 25.0259C20.1235 24.3552 21.6051 23.7165 22.9735 23.1135Z" fill="#141519"/>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

@@ -0,0 +1,17 @@
import requests
from core.tools.errors import ToolProviderCredentialValidationError
from core.tools.provider.builtin_tool_provider import BuiltinToolProviderController
class GiteeAIProvider(BuiltinToolProviderController):
def _validate_credentials(self, credentials: dict) -> None:
url = "https://ai.gitee.com/api/base/account/me"
headers = {
"accept": "application/json",
"authorization": f"Bearer {credentials.get('api_key')}",
}
response = requests.get(url, headers=headers)
if response.status_code != 200:
raise ToolProviderCredentialValidationError("GiteeAI API key is invalid")
@@ -0,0 +1,22 @@
identity:
author: Gitee AI
name: gitee_ai
label:
en_US: Gitee AI
zh_Hans: Gitee AI
description:
en_US: 快速体验大模型,领先探索 AI 开源世界
zh_Hans: 快速体验大模型,领先探索 AI 开源世界
icon: icon.svg
tags:
- image
credentials_for_provider:
api_key:
type: secret-input
required: true
label:
en_US: API Key
placeholder:
zh_Hans: 在此输入您的 API Key
en_US: Enter your API Key
url: https://ai.gitee.com/dashboard/settings/tokens
@@ -0,0 +1,33 @@
from typing import Any, Union
import requests
from core.tools.entities.tool_entities import ToolInvokeMessage
from core.tools.tool.builtin_tool import BuiltinTool
class GiteeAITool(BuiltinTool):
def _invoke(
self, user_id: str, tool_parameters: dict[str, Any]
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
headers = {
"content-type": "application/json",
"authorization": f"Bearer {self.runtime.credentials['api_key']}",
}
payload = {
"inputs": tool_parameters.get("inputs"),
"width": tool_parameters.get("width", "720"),
"height": tool_parameters.get("height", "720"),
}
model = tool_parameters.get("model", "Kolors")
url = f"https://ai.gitee.com/api/serverless/{model}/text-to-image"
response = requests.post(url, json=payload, headers=headers)
if response.status_code != 200:
return self.create_text_message(f"Got Error Response:{response.text}")
# The returned image is base64 and needs to be mark as an image
result = [self.create_blob_message(blob=response.content, meta={"mime_type": "image/jpeg"})]
return result
@@ -0,0 +1,72 @@
identity:
name: text to image
author: gitee_ai
label:
en_US: text to image
icon: icon.svg
description:
human:
en_US: generate images using a variety of popular models
llm: This tool is used to generate image from text.
parameters:
- name: model
type: select
required: true
options:
- value: flux-1-schnell
label:
en_US: flux-1-schnell
- value: Kolors
label:
en_US: Kolors
- value: stable-diffusion-3-medium
label:
en_US: stable-diffusion-3-medium
- value: stable-diffusion-xl-base-1.0
label:
en_US: stable-diffusion-xl-base-1.0
- value: stable-diffusion-v1-4
label:
en_US: stable-diffusion-v1-4
default: Kolors
label:
en_US: Choose Image Model
zh_Hans: 选择生成图片的模型
form: form
- name: inputs
type: string
required: true
label:
en_US: Input Text
zh_Hans: 输入文本
human_description:
en_US: The text input used to generate the image.
zh_Hans: 用于生成图片的输入文本。
llm_description: This text input will be used to generate image.
form: llm
- name: width
type: number
required: true
default: 720
min: 1
max: 1024
label:
en_US: Image Width
zh_Hans: 图片宽度
human_description:
en_US: The width of the generated image.
zh_Hans: 生成图片的宽度。
form: form
- name: height
type: number
required: true
default: 720
min: 1
max: 1024
label:
en_US: Image Height
zh_Hans: 图片高度
human_description:
en_US: The height of the generated image.
zh_Hans: 生成图片的高度。
form: form
@@ -13,15 +13,15 @@ class GitlabCommitsTool(BuiltinTool):
def _invoke(
self, user_id: str, tool_parameters: dict[str, Any]
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
project = tool_parameters.get("project", "")
branch = tool_parameters.get("branch", "")
repository = tool_parameters.get("repository", "")
employee = tool_parameters.get("employee", "")
start_time = tool_parameters.get("start_time", "")
end_time = tool_parameters.get("end_time", "")
change_type = tool_parameters.get("change_type", "all")
if not project and not repository:
return self.create_text_message("Either project or repository is required")
if not repository:
return self.create_text_message("Either repository is required")
if not start_time:
start_time = (datetime.utcnow() - timedelta(days=1)).isoformat()
@@ -37,14 +37,9 @@ class GitlabCommitsTool(BuiltinTool):
site_url = "https://gitlab.com"
# Get commit content
if repository:
result = self.fetch_commits(
site_url, access_token, repository, employee, start_time, end_time, change_type, is_repository=True
)
else:
result = self.fetch_commits(
site_url, access_token, project, employee, start_time, end_time, change_type, is_repository=False
)
result = self.fetch_commits(
site_url, access_token, repository, branch, employee, start_time, end_time, change_type, is_repository=True
)
return [self.create_json_message(item) for item in result]
@@ -52,7 +47,8 @@ class GitlabCommitsTool(BuiltinTool):
self,
site_url: str,
access_token: str,
identifier: str,
repository: str,
branch: str,
employee: str,
start_time: str,
end_time: str,
@@ -64,27 +60,14 @@ class GitlabCommitsTool(BuiltinTool):
results = []
try:
if is_repository:
# URL encode the repository path
encoded_identifier = urllib.parse.quote(identifier, safe="")
commits_url = f"{domain}/api/v4/projects/{encoded_identifier}/repository/commits"
else:
# Get all projects
url = f"{domain}/api/v4/projects"
response = requests.get(url, headers=headers)
response.raise_for_status()
projects = response.json()
filtered_projects = [p for p in projects if identifier == "*" or p["name"] == identifier]
for project in filtered_projects:
project_id = project["id"]
project_name = project["name"]
print(f"Project: {project_name}")
commits_url = f"{domain}/api/v4/projects/{project_id}/repository/commits"
# URL encode the repository path
encoded_repository = urllib.parse.quote(repository, safe="")
commits_url = f"{domain}/api/v4/projects/{encoded_repository}/repository/commits"
# Fetch commits for the repository
params = {"since": start_time, "until": end_time}
if branch:
params["ref_name"] = branch
if employee:
params["author"] = employee
@@ -96,10 +79,7 @@ class GitlabCommitsTool(BuiltinTool):
commit_sha = commit["id"]
author_name = commit["author_name"]
if is_repository:
diff_url = f"{domain}/api/v4/projects/{encoded_identifier}/repository/commits/{commit_sha}/diff"
else:
diff_url = f"{domain}/api/v4/projects/{project_id}/repository/commits/{commit_sha}/diff"
diff_url = f"{domain}/api/v4/projects/{encoded_repository}/repository/commits/{commit_sha}/diff"
diff_response = requests.get(diff_url, headers=headers)
diff_response.raise_for_status()
@@ -120,7 +100,14 @@ class GitlabCommitsTool(BuiltinTool):
if line.startswith("+") and not line.startswith("+++")
]
)
results.append({"commit_sha": commit_sha, "author_name": author_name, "diff": final_code})
results.append(
{
"diff_url": diff_url,
"commit_sha": commit_sha,
"author_name": author_name,
"diff": final_code,
}
)
else:
if total_changes > 1:
final_code = "".join(
@@ -134,7 +121,12 @@ class GitlabCommitsTool(BuiltinTool):
)
final_code_escaped = json.dumps(final_code)[1:-1] # Escape the final code
results.append(
{"commit_sha": commit_sha, "author_name": author_name, "diff": final_code_escaped}
{
"diff_url": diff_url,
"commit_sha": commit_sha,
"author_name": author_name,
"diff": final_code_escaped,
}
)
except requests.RequestException as e:
print(f"Error fetching data from GitLab: {e}")
@@ -23,7 +23,7 @@ parameters:
form: llm
- name: repository
type: string
required: false
required: true
label:
en_US: repository
zh_Hans: 仓库路径
@@ -32,16 +32,16 @@ parameters:
zh_Hans: 仓库路径,以namespace/project_name的形式。
llm_description: Repository path for GitLab, like namespace/project_name.
form: llm
- name: project
- name: branch
type: string
required: false
label:
en_US: project
zh_Hans: 项目
en_US: branch
zh_Hans: 分支
human_description:
en_US: project
zh_Hans: 项目
llm_description: project for GitLab
en_US: branch
zh_Hans: 分支
llm_description: branch for GitLab
form: llm
- name: start_time
type: string
@@ -0,0 +1,78 @@
import urllib.parse
from typing import Any, Union
import requests
from core.tools.entities.tool_entities import ToolInvokeMessage
from core.tools.tool.builtin_tool import BuiltinTool
class GitlabMergeRequestsTool(BuiltinTool):
def _invoke(
self, user_id: str, tool_parameters: dict[str, Any]
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
repository = tool_parameters.get("repository", "")
branch = tool_parameters.get("branch", "")
start_time = tool_parameters.get("start_time", "")
end_time = tool_parameters.get("end_time", "")
state = tool_parameters.get("state", "opened") # Default to "opened"
if not repository:
return self.create_text_message("Repository is required")
access_token = self.runtime.credentials.get("access_tokens")
site_url = self.runtime.credentials.get("site_url")
if not access_token:
return self.create_text_message("Gitlab API Access Tokens is required.")
if not site_url:
site_url = "https://gitlab.com"
# Get merge requests
result = self.get_merge_requests(site_url, access_token, repository, branch, start_time, end_time, state)
return [self.create_json_message(item) for item in result]
def get_merge_requests(
self, site_url: str, access_token: str, repository: str, branch: str, start_time: str, end_time: str, state: str
) -> list[dict[str, Any]]:
domain = site_url
headers = {"PRIVATE-TOKEN": access_token}
results = []
try:
# URL encode the repository path
encoded_repository = urllib.parse.quote(repository, safe="")
merge_requests_url = f"{domain}/api/v4/projects/{encoded_repository}/merge_requests"
params = {"state": state}
# Add time filters if provided
if start_time:
params["created_after"] = start_time
if end_time:
params["created_before"] = end_time
response = requests.get(merge_requests_url, headers=headers, params=params)
response.raise_for_status()
merge_requests = response.json()
for mr in merge_requests:
# Filter by target branch
if branch and mr["target_branch"] != branch:
continue
results.append(
{
"id": mr["id"],
"title": mr["title"],
"author": mr["author"]["name"],
"web_url": mr["web_url"],
"target_branch": mr["target_branch"],
"created_at": mr["created_at"],
"state": mr["state"],
}
)
except requests.RequestException as e:
print(f"Error fetching merge requests from GitLab: {e}")
return results
@@ -0,0 +1,77 @@
identity:
name: gitlab_mergerequests
author: Leo.Wang
label:
en_US: GitLab Merge Requests
zh_Hans: GitLab 合并请求查询
description:
human:
en_US: A tool for query GitLab merge requests, Input should be a exists reposity or branch.
zh_Hans: 一个用于查询 GitLab 代码合并请求的工具,输入的内容应该是一个已存在的仓库名或者分支。
llm: A tool for query GitLab merge requests, Input should be a exists reposity or branch.
parameters:
- name: repository
type: string
required: false
label:
en_US: repository
zh_Hans: 仓库路径
human_description:
en_US: repository
zh_Hans: 仓库路径,以namespace/project_name的形式。
llm_description: Repository path for GitLab, like namespace/project_name.
form: llm
- name: branch
type: string
required: false
label:
en_US: branch
zh_Hans: 分支名
human_description:
en_US: branch
zh_Hans: 分支名
llm_description: branch for GitLab
form: llm
- name: start_time
type: string
required: false
label:
en_US: start_time
zh_Hans: 开始时间
human_description:
en_US: start_time
zh_Hans: 开始时间
llm_description: Start time for GitLab
form: llm
- name: end_time
type: string
required: false
label:
en_US: end_time
zh_Hans: 结束时间
human_description:
en_US: end_time
zh_Hans: 结束时间
llm_description: End time for GitLab
form: llm
- name: state
type: select
required: false
options:
- value: opened
label:
en_US: opened
zh_Hans: 打开
- value: closed
label:
en_US: closed
zh_Hans: 关闭
default: opened
label:
en_US: state
zh_Hans: 变更状态
human_description:
en_US: state
zh_Hans: 变更状态
llm_description: Merge request state type for GitLab
form: llm
@@ -0,0 +1,81 @@
import urllib.parse
from typing import Any, Union
import requests
from core.tools.entities.tool_entities import ToolInvokeMessage
from core.tools.tool.builtin_tool import BuiltinTool
class GitlabProjectsTool(BuiltinTool):
def _invoke(
self, user_id: str, tool_parameters: dict[str, Any]
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
project_name = tool_parameters.get("project_name", "")
page = tool_parameters.get("page", 1)
page_size = tool_parameters.get("page_size", 20)
access_token = self.runtime.credentials.get("access_tokens")
site_url = self.runtime.credentials.get("site_url")
if not access_token:
return self.create_text_message("Gitlab API Access Tokens is required.")
if not site_url:
site_url = "https://gitlab.com"
# Get project content
result = self.fetch_projects(site_url, access_token, project_name, page, page_size)
return [self.create_json_message(item) for item in result]
def fetch_projects(
self,
site_url: str,
access_token: str,
project_name: str,
page: str,
page_size: str,
) -> list[dict[str, Any]]:
domain = site_url
headers = {"PRIVATE-TOKEN": access_token}
results = []
try:
if project_name:
# URL encode the project name for the search query
encoded_project_name = urllib.parse.quote(project_name, safe="")
projects_url = (
f"{domain}/api/v4/projects?search={encoded_project_name}&page={page}&per_page={page_size}"
)
else:
projects_url = f"{domain}/api/v4/projects?page={page}&per_page={page_size}"
response = requests.get(projects_url, headers=headers)
response.raise_for_status()
projects = response.json()
for project in projects:
# Filter projects by exact name match if necessary
if project_name and project["name"].lower() == project_name.lower():
results.append(
{
"id": project["id"],
"name": project["name"],
"description": project.get("description", ""),
"web_url": project["web_url"],
}
)
elif not project_name:
# If no specific project name is provided, add all projects
results.append(
{
"id": project["id"],
"name": project["name"],
"description": project.get("description", ""),
"web_url": project["web_url"],
}
)
except requests.RequestException as e:
print(f"Error fetching data from GitLab: {e}")
return results
@@ -0,0 +1,45 @@
identity:
name: gitlab_projects
author: Leo.Wang
label:
en_US: GitLab Projects
zh_Hans: GitLab 项目列表查询
description:
human:
en_US: A tool for query GitLab projects, Input should be a project name.
zh_Hans: 一个用于查询 GitLab 项目列表的工具,输入的内容应该是一个项目名称。
llm: A tool for query GitLab projects, Input should be a project name.
parameters:
- name: project_name
type: string
required: false
label:
en_US: project_name
zh_Hans: 项目名称
human_description:
en_US: project_name
zh_Hans: 项目名称
llm_description: Project name for GitLab
form: llm
- name: page
type: string
required: false
label:
en_US: page
zh_Hans: 页码
human_description:
en_US: page
zh_Hans: 页码
llm_description: Page index for GitLab
form: llm
- name: page_size
type: string
required: false
label:
en_US: page_size
zh_Hans: 每页数量
human_description:
en_US: page_size
zh_Hans: 每页数量
llm_description: Page size for GitLab
form: llm
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

@@ -0,0 +1,7 @@
from core.tools.provider.builtin_tool_provider import BuiltinToolProviderController
from core.tools.utils.lark_api_utils import lark_auth
class LarkBaseProvider(BuiltinToolProviderController):
def _validate_credentials(self, credentials: dict) -> None:
lark_auth(credentials)
@@ -0,0 +1,36 @@
identity:
author: Doug Lea
name: lark_base
label:
en_US: Lark Base
zh_Hans: Lark 多维表格
description:
en_US: |
Lark base, requires the following permissions: bitable:app.
zh_Hans: |
Lark 多维表格,需要开通以下权限: bitable:app。
icon: icon.png
tags:
- social
- productivity
credentials_for_provider:
app_id:
type: text-input
required: true
label:
en_US: APP ID
placeholder:
en_US: Please input your Lark app id
zh_Hans: 请输入你的 Lark app id
help:
en_US: Get your app_id and app_secret from Lark
zh_Hans: 从 Lark 获取您的 app_id 和 app_secret
url: https://open.larksuite.com/app
app_secret:
type: secret-input
required: true
label:
en_US: APP Secret
placeholder:
en_US: Please input your app secret
zh_Hans: 请输入你的 Lark app secret
@@ -0,0 +1,21 @@
from typing import Any
from core.tools.entities.tool_entities import ToolInvokeMessage
from core.tools.tool.builtin_tool import BuiltinTool
from core.tools.utils.lark_api_utils import LarkRequest
class AddRecordsTool(BuiltinTool):
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
app_id = self.runtime.credentials.get("app_id")
app_secret = self.runtime.credentials.get("app_secret")
client = LarkRequest(app_id, app_secret)
app_token = tool_parameters.get("app_token")
table_id = tool_parameters.get("table_id")
table_name = tool_parameters.get("table_name")
records = tool_parameters.get("records")
user_id_type = tool_parameters.get("user_id_type", "open_id")
res = client.add_records(app_token, table_id, table_name, records, user_id_type)
return self.create_json_message(res)
@@ -0,0 +1,91 @@
identity:
name: add_records
author: Doug Lea
label:
en_US: Add Records
zh_Hans: 新增多条记录
description:
human:
en_US: Add Multiple Records to Multidimensional Table
zh_Hans: 在多维表格数据表中新增多条记录
llm: A tool for adding multiple records to a multidimensional table. (在多维表格数据表中新增多条记录)
parameters:
- name: app_token
type: string
required: true
label:
en_US: app_token
zh_Hans: app_token
human_description:
en_US: Unique identifier for the multidimensional table, supports inputting document URL.
zh_Hans: 多维表格的唯一标识符,支持输入文档 URL。
llm_description: 多维表格的唯一标识符,支持输入文档 URL。
form: llm
- name: table_id
type: string
required: false
label:
en_US: table_id
zh_Hans: table_id
human_description:
en_US: Unique identifier for the multidimensional table data, either table_id or table_name must be provided, cannot be empty simultaneously.
zh_Hans: 多维表格数据表的唯一标识符,table_id 和 table_name 至少需要提供一个,不能同时为空。
llm_description: 多维表格数据表的唯一标识符,table_id 和 table_name 至少需要提供一个,不能同时为空。
form: llm
- name: table_name
type: string
required: false
label:
en_US: table_name
zh_Hans: table_name
human_description:
en_US: Name of the multidimensional table data, either table_name or table_id must be provided, cannot be empty simultaneously.
zh_Hans: 多维表格数据表的名称,table_name 和 table_id 至少需要提供一个,不能同时为空。
llm_description: 多维表格数据表的名称,table_name 和 table_id 至少需要提供一个,不能同时为空。
form: llm
- name: records
type: string
required: true
label:
en_US: records
zh_Hans: 记录列表
human_description:
en_US: |
List of records to be added in this request. Example value: [{"multi-line-text":"text content","single_select":"option 1","date":1674206443000}]
For supported field types, refer to the integration guide (https://open.larkoffice.com/document/server-docs/docs/bitable-v1/notification). For data structures of different field types, refer to the data structure overview (https://open.larkoffice.com/document/server-docs/docs/bitable-v1/bitable-structure).
zh_Hans: |
本次请求将要新增的记录列表,示例值:[{"多行文本":"文本内容","单选":"选项 1","日期":1674206443000}]。
当前接口支持的字段类型请参考接入指南(https://open.larkoffice.com/document/server-docs/docs/bitable-v1/notification),不同类型字段的数据结构请参考数据结构概述(https://open.larkoffice.com/document/server-docs/docs/bitable-v1/bitable-structure)。
llm_description: |
本次请求将要新增的记录列表,示例值:[{"多行文本":"文本内容","单选":"选项 1","日期":1674206443000}]。
当前接口支持的字段类型请参考接入指南(https://open.larkoffice.com/document/server-docs/docs/bitable-v1/notification),不同类型字段的数据结构请参考数据结构概述(https://open.larkoffice.com/document/server-docs/docs/bitable-v1/bitable-structure)。
form: llm
- name: user_id_type
type: select
required: false
options:
- value: open_id
label:
en_US: open_id
zh_Hans: open_id
- value: union_id
label:
en_US: union_id
zh_Hans: union_id
- value: user_id
label:
en_US: user_id
zh_Hans: user_id
default: "open_id"
label:
en_US: user_id_type
zh_Hans: 用户 ID 类型
human_description:
en_US: User ID type, optional values are open_id, union_id, user_id, with a default value of open_id.
zh_Hans: 用户 ID 类型,可选值有 open_id、union_id、user_id,默认值为 open_id。
llm_description: 用户 ID 类型,可选值有 open_id、union_id、user_id,默认值为 open_id。
form: form
@@ -0,0 +1,18 @@
from typing import Any
from core.tools.entities.tool_entities import ToolInvokeMessage
from core.tools.tool.builtin_tool import BuiltinTool
from core.tools.utils.lark_api_utils import LarkRequest
class CreateBaseTool(BuiltinTool):
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
app_id = self.runtime.credentials.get("app_id")
app_secret = self.runtime.credentials.get("app_secret")
client = LarkRequest(app_id, app_secret)
name = tool_parameters.get("name")
folder_token = tool_parameters.get("folder_token")
res = client.create_base(name, folder_token)
return self.create_json_message(res)
@@ -0,0 +1,42 @@
identity:
name: create_base
author: Doug Lea
label:
en_US: Create Base
zh_Hans: 创建多维表格
description:
human:
en_US: Create Multidimensional Table in Specified Directory
zh_Hans: 在指定目录下创建多维表格
llm: A tool for creating a multidimensional table in a specified directory. (在指定目录下创建多维表格)
parameters:
- name: name
type: string
required: false
label:
en_US: name
zh_Hans: 多维表格 App 名字
human_description:
en_US: |
Name of the multidimensional table App. Example value: "A new multidimensional table".
zh_Hans: 多维表格 App 名字,示例值:"一篇新的多维表格"。
llm_description: 多维表格 App 名字,示例值:"一篇新的多维表格"。
form: llm
- name: folder_token
type: string
required: false
label:
en_US: folder_token
zh_Hans: 多维表格 App 归属文件夹
human_description:
en_US: |
Folder where the multidimensional table App belongs. Default is empty, meaning the table will be created in the root directory of the cloud space. Example values: Lf8uf6BoAlWkUfdGtpMjUV0PpZd or https://lark-japan.jp.larksuite.com/drive/folder/Lf8uf6BoAlWkUfdGtpMjUV0PpZd.
The folder_token must be an existing folder and supports inputting folder token or folder URL.
zh_Hans: |
多维表格 App 归属文件夹。默认为空,表示多维表格将被创建在云空间根目录。示例值: Lf8uf6BoAlWkUfdGtpMjUV0PpZd 或者 https://lark-japan.jp.larksuite.com/drive/folder/Lf8uf6BoAlWkUfdGtpMjUV0PpZd。
folder_token 必须是已存在的文件夹,支持输入文件夹 token 或者文件夹 URL。
llm_description: |
多维表格 App 归属文件夹。默认为空,表示多维表格将被创建在云空间根目录。示例值: Lf8uf6BoAlWkUfdGtpMjUV0PpZd 或者 https://lark-japan.jp.larksuite.com/drive/folder/Lf8uf6BoAlWkUfdGtpMjUV0PpZd。
folder_token 必须是已存在的文件夹,支持输入文件夹 token 或者文件夹 URL。
form: llm
@@ -0,0 +1,20 @@
from typing import Any
from core.tools.entities.tool_entities import ToolInvokeMessage
from core.tools.tool.builtin_tool import BuiltinTool
from core.tools.utils.lark_api_utils import LarkRequest
class CreateTableTool(BuiltinTool):
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
app_id = self.runtime.credentials.get("app_id")
app_secret = self.runtime.credentials.get("app_secret")
client = LarkRequest(app_id, app_secret)
app_token = tool_parameters.get("app_token")
table_name = tool_parameters.get("table_name")
default_view_name = tool_parameters.get("default_view_name")
fields = tool_parameters.get("fields")
res = client.create_table(app_token, table_name, default_view_name, fields)
return self.create_json_message(res)
@@ -0,0 +1,61 @@
identity:
name: create_table
author: Doug Lea
label:
en_US: Create Table
zh_Hans: 新增数据表
description:
human:
en_US: Add a Data Table to Multidimensional Table
zh_Hans: 在多维表格中新增一个数据表
llm: A tool for adding a data table to a multidimensional table. (在多维表格中新增一个数据表)
parameters:
- name: app_token
type: string
required: true
label:
en_US: app_token
zh_Hans: app_token
human_description:
en_US: Unique identifier for the multidimensional table, supports inputting document URL.
zh_Hans: 多维表格的唯一标识符,支持输入文档 URL。
llm_description: 多维表格的唯一标识符,支持输入文档 URL。
form: llm
- name: table_name
type: string
required: true
label:
en_US: Table Name
zh_Hans: 数据表名称
human_description:
en_US: |
The name of the data table, length range: 1 character to 100 characters.
zh_Hans: 数据表名称,长度范围:1 字符 ~ 100 字符。
llm_description: 数据表名称,长度范围:1 字符 ~ 100 字符。
form: llm
- name: default_view_name
type: string
required: false
label:
en_US: Default View Name
zh_Hans: 默认表格视图的名称
human_description:
en_US: The name of the default table view, defaults to "Table" if not filled.
zh_Hans: 默认表格视图的名称,不填则默认为"表格"。
llm_description: 默认表格视图的名称,不填则默认为"表格"。
form: llm
- name: fields
type: string
required: true
label:
en_US: Initial Fields
zh_Hans: 初始字段
human_description:
en_US: |
Initial fields of the data table, format: [ { "field_name": "Multi-line Text","type": 1 },{ "field_name": "Number","type": 2 },{ "field_name": "Single Select","type": 3 },{ "field_name": "Multiple Select","type": 4 },{ "field_name": "Date","type": 5 } ]. For field details, refer to: https://open.larkoffice.com/document/server-docs/docs/bitable-v1/app-table-field/guide
zh_Hans: 数据表的初始字段,格式为:[{"field_name":"多行文本","type":1},{"field_name":"数字","type":2},{"field_name":"单选","type":3},{"field_name":"多选","type":4},{"field_name":"日期","type":5}]。字段详情参考:https://open.larkoffice.com/document/server-docs/docs/bitable-v1/app-table-field/guide
llm_description: 数据表的初始字段,格式为:[{"field_name":"多行文本","type":1},{"field_name":"数字","type":2},{"field_name":"单选","type":3},{"field_name":"多选","type":4},{"field_name":"日期","type":5}]。字段详情参考:https://open.larkoffice.com/document/server-docs/docs/bitable-v1/app-table-field/guide
form: llm
@@ -0,0 +1,20 @@
from typing import Any
from core.tools.entities.tool_entities import ToolInvokeMessage
from core.tools.tool.builtin_tool import BuiltinTool
from core.tools.utils.lark_api_utils import LarkRequest
class DeleteRecordsTool(BuiltinTool):
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
app_id = self.runtime.credentials.get("app_id")
app_secret = self.runtime.credentials.get("app_secret")
client = LarkRequest(app_id, app_secret)
app_token = tool_parameters.get("app_token")
table_id = tool_parameters.get("table_id")
table_name = tool_parameters.get("table_name")
record_ids = tool_parameters.get("record_ids")
res = client.delete_records(app_token, table_id, table_name, record_ids)
return self.create_json_message(res)
@@ -0,0 +1,86 @@
identity:
name: delete_records
author: Doug Lea
label:
en_US: Delete Records
zh_Hans: 删除多条记录
description:
human:
en_US: Delete Multiple Records from Multidimensional Table
zh_Hans: 删除多维表格数据表中的多条记录
llm: A tool for deleting multiple records from a multidimensional table. (删除多维表格数据表中的多条记录)
parameters:
- name: app_token
type: string
required: true
label:
en_US: app_token
zh_Hans: app_token
human_description:
en_US: Unique identifier for the multidimensional table, supports inputting document URL.
zh_Hans: 多维表格的唯一标识符,支持输入文档 URL。
llm_description: 多维表格的唯一标识符,支持输入文档 URL。
form: llm
- name: table_id
type: string
required: false
label:
en_US: table_id
zh_Hans: table_id
human_description:
en_US: Unique identifier for the multidimensional table data, either table_id or table_name must be provided, cannot be empty simultaneously.
zh_Hans: 多维表格数据表的唯一标识符,table_id 和 table_name 至少需要提供一个,不能同时为空。
llm_description: 多维表格数据表的唯一标识符,table_id 和 table_name 至少需要提供一个,不能同时为空。
form: llm
- name: table_name
type: string
required: false
label:
en_US: table_name
zh_Hans: table_name
human_description:
en_US: Name of the multidimensional table data, either table_name or table_id must be provided, cannot be empty simultaneously.
zh_Hans: 多维表格数据表的名称,table_name 和 table_id 至少需要提供一个,不能同时为空。
llm_description: 多维表格数据表的名称,table_name 和 table_id 至少需要提供一个,不能同时为空。
form: llm
- name: record_ids
type: string
required: true
label:
en_US: Record IDs
zh_Hans: 记录 ID 列表
human_description:
en_US: |
List of IDs for the records to be deleted, example value: ["recwNXzPQv"].
zh_Hans: 删除的多条记录 ID 列表,示例值:["recwNXzPQv"]。
llm_description: 删除的多条记录 ID 列表,示例值:["recwNXzPQv"]。
form: llm
- name: user_id_type
type: select
required: false
options:
- value: open_id
label:
en_US: open_id
zh_Hans: open_id
- value: union_id
label:
en_US: union_id
zh_Hans: union_id
- value: user_id
label:
en_US: user_id
zh_Hans: user_id
default: "open_id"
label:
en_US: user_id_type
zh_Hans: 用户 ID 类型
human_description:
en_US: User ID type, optional values are open_id, union_id, user_id, with a default value of open_id.
zh_Hans: 用户 ID 类型,可选值有 open_id、union_id、user_id,默认值为 open_id。
llm_description: 用户 ID 类型,可选值有 open_id、union_id、user_id,默认值为 open_id。
form: form
@@ -0,0 +1,19 @@
from typing import Any
from core.tools.entities.tool_entities import ToolInvokeMessage
from core.tools.tool.builtin_tool import BuiltinTool
from core.tools.utils.lark_api_utils import LarkRequest
class DeleteTablesTool(BuiltinTool):
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
app_id = self.runtime.credentials.get("app_id")
app_secret = self.runtime.credentials.get("app_secret")
client = LarkRequest(app_id, app_secret)
app_token = tool_parameters.get("app_token")
table_ids = tool_parameters.get("table_ids")
table_names = tool_parameters.get("table_names")
res = client.delete_tables(app_token, table_ids, table_names)
return self.create_json_message(res)
@@ -0,0 +1,49 @@
identity:
name: delete_tables
author: Doug Lea
label:
en_US: Delete Tables
zh_Hans: 删除数据表
description:
human:
en_US: Batch Delete Data Tables from Multidimensional Table
zh_Hans: 批量删除多维表格中的数据表
llm: A tool for batch deleting data tables from a multidimensional table. (批量删除多维表格中的数据表)
parameters:
- name: app_token
type: string
required: true
label:
en_US: app_token
zh_Hans: app_token
human_description:
en_US: Unique identifier for the multidimensional table, supports inputting document URL.
zh_Hans: 多维表格的唯一标识符,支持输入文档 URL。
llm_description: 多维表格的唯一标识符,支持输入文档 URL。
form: llm
- name: table_ids
type: string
required: false
label:
en_US: Table IDs
zh_Hans: 数据表 ID
human_description:
en_US: |
IDs of the tables to be deleted. Each operation supports deleting up to 50 tables. Example: ["tbl1TkhyTWDkSoZ3"]. Ensure that either table_ids or table_names is not empty.
zh_Hans: 待删除的数据表的 ID,每次操作最多支持删除 50 个数据表。示例值:["tbl1TkhyTWDkSoZ3"]。请确保 table_ids 和 table_names 至少有一个不为空。
llm_description: 待删除的数据表的 ID,每次操作最多支持删除 50 个数据表。示例值:["tbl1TkhyTWDkSoZ3"]。请确保 table_ids 和 table_names 至少有一个不为空。
form: llm
- name: table_names
type: string
required: false
label:
en_US: Table Names
zh_Hans: 数据表名称
human_description:
en_US: |
Names of the tables to be deleted. Each operation supports deleting up to 50 tables. Example: ["Table1", "Table2"]. Ensure that either table_names or table_ids is not empty.
zh_Hans: 待删除的数据表的名称,每次操作最多支持删除 50 个数据表。示例值:["数据表1", "数据表2"]。请确保 table_names 和 table_ids 至少有一个不为空。
llm_description: 待删除的数据表的名称,每次操作最多支持删除 50 个数据表。示例值:["数据表1", "数据表2"]。请确保 table_names 和 table_ids 至少有一个不为空。
form: llm
@@ -0,0 +1,17 @@
from typing import Any
from core.tools.entities.tool_entities import ToolInvokeMessage
from core.tools.tool.builtin_tool import BuiltinTool
from core.tools.utils.lark_api_utils import LarkRequest
class GetBaseInfoTool(BuiltinTool):
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
app_id = self.runtime.credentials.get("app_id")
app_secret = self.runtime.credentials.get("app_secret")
client = LarkRequest(app_id, app_secret)
app_token = tool_parameters.get("app_token")
res = client.get_base_info(app_token)
return self.create_json_message(res)
@@ -0,0 +1,23 @@
identity:
name: get_base_info
author: Doug Lea
label:
en_US: Get Base Info
zh_Hans: 获取多维表格元数据
description:
human:
en_US: Get Metadata Information of Specified Multidimensional Table
zh_Hans: 获取指定多维表格的元数据信息
llm: A tool for getting metadata information of a specified multidimensional table. (获取指定多维表格的元数据信息)
parameters:
- name: app_token
type: string
required: true
label:
en_US: app_token
zh_Hans: app_token
human_description:
en_US: Unique identifier for the multidimensional table, supports inputting document URL.
zh_Hans: 多维表格的唯一标识符,支持输入文档 URL。
llm_description: 多维表格的唯一标识符,支持输入文档 URL。
form: llm
@@ -0,0 +1,19 @@
from typing import Any
from core.tools.entities.tool_entities import ToolInvokeMessage
from core.tools.tool.builtin_tool import BuiltinTool
from core.tools.utils.lark_api_utils import LarkRequest
class ListTablesTool(BuiltinTool):
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
app_id = self.runtime.credentials.get("app_id")
app_secret = self.runtime.credentials.get("app_secret")
client = LarkRequest(app_id, app_secret)
app_token = tool_parameters.get("app_token")
page_token = tool_parameters.get("page_token")
page_size = tool_parameters.get("page_size", 20)
res = client.list_tables(app_token, page_token, page_size)
return self.create_json_message(res)
@@ -0,0 +1,50 @@
identity:
name: list_tables
author: Doug Lea
label:
en_US: List Tables
zh_Hans: 列出数据表
description:
human:
en_US: Get All Data Tables under Multidimensional Table
zh_Hans: 获取多维表格下的所有数据表
llm: A tool for getting all data tables under a multidimensional table. (获取多维表格下的所有数据表)
parameters:
- name: app_token
type: string
required: true
label:
en_US: app_token
zh_Hans: app_token
human_description:
en_US: Unique identifier for the multidimensional table, supports inputting document URL.
zh_Hans: 多维表格的唯一标识符,支持输入文档 URL。
llm_description: 多维表格的唯一标识符,支持输入文档 URL。
form: llm
- name: page_size
type: number
required: false
default: 20
label:
en_US: page_size
zh_Hans: 分页大小
human_description:
en_US: |
Page size, default value: 20, maximum value: 100.
zh_Hans: 分页大小,默认值:20,最大值:100。
llm_description: 分页大小,默认值:20,最大值:100。
form: form
- name: page_token
type: string
required: false
label:
en_US: page_token
zh_Hans: 分页标记
human_description:
en_US: |
Page token, leave empty for the first request to start from the beginning; a new page_token will be returned if there are more items in the paginated query results, which can be used for the next traversal. Example value: "tblsRc9GRRXKqhvW".
zh_Hans: 分页标记,第一次请求不填,表示从头开始遍历;分页查询结果还有更多项时会同时返回新的 page_token,下次遍历可采用该 page_token 获取查询结果。示例值:"tblsRc9GRRXKqhvW"。
llm_description: 分页标记,第一次请求不填,表示从头开始遍历;分页查询结果还有更多项时会同时返回新的 page_token,下次遍历可采用该 page_token 获取查询结果。示例值:"tblsRc9GRRXKqhvW"。
form: llm
@@ -0,0 +1,21 @@
from typing import Any
from core.tools.entities.tool_entities import ToolInvokeMessage
from core.tools.tool.builtin_tool import BuiltinTool
from core.tools.utils.lark_api_utils import LarkRequest
class ReadRecordsTool(BuiltinTool):
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
app_id = self.runtime.credentials.get("app_id")
app_secret = self.runtime.credentials.get("app_secret")
client = LarkRequest(app_id, app_secret)
app_token = tool_parameters.get("app_token")
table_id = tool_parameters.get("table_id")
table_name = tool_parameters.get("table_name")
record_ids = tool_parameters.get("record_ids")
user_id_type = tool_parameters.get("user_id_type", "open_id")
res = client.read_records(app_token, table_id, table_name, record_ids, user_id_type)
return self.create_json_message(res)
@@ -0,0 +1,86 @@
identity:
name: read_records
author: Doug Lea
label:
en_US: Read Records
zh_Hans: 批量获取记录
description:
human:
en_US: Batch Retrieve Records from Multidimensional Table
zh_Hans: 批量获取多维表格数据表中的记录信息
llm: A tool for batch retrieving records from a multidimensional table, supporting up to 100 records per call. (批量获取多维表格数据表中的记录信息,单次调用最多支持查询 100 条记录)
parameters:
- name: app_token
type: string
required: true
label:
en_US: app_token
zh_Hans: app_token
human_description:
en_US: Unique identifier for the multidimensional table, supports inputting document URL.
zh_Hans: 多维表格的唯一标识符,支持输入文档 URL。
llm_description: 多维表格的唯一标识符,支持输入文档 URL。
form: llm
- name: table_id
type: string
required: false
label:
en_US: table_id
zh_Hans: table_id
human_description:
en_US: Unique identifier for the multidimensional table data, either table_id or table_name must be provided, cannot be empty simultaneously.
zh_Hans: 多维表格数据表的唯一标识符,table_id 和 table_name 至少需要提供一个,不能同时为空。
llm_description: 多维表格数据表的唯一标识符,table_id 和 table_name 至少需要提供一个,不能同时为空。
form: llm
- name: table_name
type: string
required: false
label:
en_US: table_name
zh_Hans: table_name
human_description:
en_US: Name of the multidimensional table data, either table_name or table_id must be provided, cannot be empty simultaneously.
zh_Hans: 多维表格数据表的名称,table_name 和 table_id 至少需要提供一个,不能同时为空。
llm_description: 多维表格数据表的名称,table_name 和 table_id 至少需要提供一个,不能同时为空。
form: llm
- name: record_ids
type: string
required: true
label:
en_US: record_ids
zh_Hans: 记录 ID 列表
human_description:
en_US: List of record IDs, which can be obtained by calling the "Query Records API".
zh_Hans: 记录 ID 列表,可以通过调用"查询记录接口"获取。
llm_description: 记录 ID 列表,可以通过调用"查询记录接口"获取。
form: llm
- name: user_id_type
type: select
required: false
options:
- value: open_id
label:
en_US: open_id
zh_Hans: open_id
- value: union_id
label:
en_US: union_id
zh_Hans: union_id
- value: user_id
label:
en_US: user_id
zh_Hans: user_id
default: "open_id"
label:
en_US: user_id_type
zh_Hans: 用户 ID 类型
human_description:
en_US: User ID type, optional values are open_id, union_id, user_id, with a default value of open_id.
zh_Hans: 用户 ID 类型,可选值有 open_id、union_id、user_id,默认值为 open_id。
llm_description: 用户 ID 类型,可选值有 open_id、union_id、user_id,默认值为 open_id。
form: form
@@ -0,0 +1,39 @@
from typing import Any
from core.tools.entities.tool_entities import ToolInvokeMessage
from core.tools.tool.builtin_tool import BuiltinTool
from core.tools.utils.lark_api_utils import LarkRequest
class SearchRecordsTool(BuiltinTool):
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
app_id = self.runtime.credentials.get("app_id")
app_secret = self.runtime.credentials.get("app_secret")
client = LarkRequest(app_id, app_secret)
app_token = tool_parameters.get("app_token")
table_id = tool_parameters.get("table_id")
table_name = tool_parameters.get("table_name")
view_id = tool_parameters.get("view_id")
field_names = tool_parameters.get("field_names")
sort = tool_parameters.get("sort")
filters = tool_parameters.get("filter")
page_token = tool_parameters.get("page_token")
automatic_fields = tool_parameters.get("automatic_fields", False)
user_id_type = tool_parameters.get("user_id_type", "open_id")
page_size = tool_parameters.get("page_size", 20)
res = client.search_record(
app_token,
table_id,
table_name,
view_id,
field_names,
sort,
filters,
page_token,
automatic_fields,
user_id_type,
page_size,
)
return self.create_json_message(res)
@@ -0,0 +1,163 @@
identity:
name: search_records
author: Doug Lea
label:
en_US: Search Records
zh_Hans: 查询记录
description:
human:
en_US: Query records in a multidimensional table, up to 500 rows per query.
zh_Hans: 查询多维表格数据表中的记录,单次最多查询 500 行记录。
llm: A tool for querying records in a multidimensional table, up to 500 rows per query. (查询多维表格数据表中的记录,单次最多查询 500 行记录)
parameters:
- name: app_token
type: string
required: true
label:
en_US: app_token
zh_Hans: app_token
human_description:
en_US: Unique identifier for the multidimensional table, supports inputting document URL.
zh_Hans: 多维表格的唯一标识符,支持输入文档 URL。
llm_description: 多维表格的唯一标识符,支持输入文档 URL。
form: llm
- name: table_id
type: string
required: false
label:
en_US: table_id
zh_Hans: table_id
human_description:
en_US: Unique identifier for the multidimensional table data, either table_id or table_name must be provided, cannot be empty simultaneously.
zh_Hans: 多维表格数据表的唯一标识符,table_id 和 table_name 至少需要提供一个,不能同时为空。
llm_description: 多维表格数据表的唯一标识符,table_id 和 table_name 至少需要提供一个,不能同时为空。
form: llm
- name: table_name
type: string
required: false
label:
en_US: table_name
zh_Hans: table_name
human_description:
en_US: Name of the multidimensional table data, either table_name or table_id must be provided, cannot be empty simultaneously.
zh_Hans: 多维表格数据表的名称,table_name 和 table_id 至少需要提供一个,不能同时为空。
llm_description: 多维表格数据表的名称,table_name 和 table_id 至少需要提供一个,不能同时为空。
form: llm
- name: view_id
type: string
required: false
label:
en_US: view_id
zh_Hans: 视图唯一标识
human_description:
en_US: |
Unique identifier for a view in a multidimensional table. It can be found in the URL's query parameter with the key 'view'. For example: https://lark-japan.jp.larksuite.com/base/XXX0bfYEraW5OWsbhcFjEqj6pxh?table=tbl5I6jqwz8wBRMv&view=vewW5zXVEU.
zh_Hans: 多维表格中视图的唯一标识,可在多维表格的 URL 地址栏中找到,query 参数中 key 为 view 的部分。例如:https://lark-japan.jp.larksuite.com/base/XXX0bfYEraW5OWsbhcFjEqj6pxh?table=tbl5I6jqwz8wBRMv&view=vewW5zXVEU。
llm_description: 多维表格中视图的唯一标识,可在多维表格的 URL 地址栏中找到,query 参数中 key 为 view 的部分。例如:https://lark-japan.jp.larksuite.com/base/XXX0bfYEraW5OWsbhcFjEqj6pxh?table=tbl5I6jqwz8wBRMv&view=vewW5zXVEU。
form: llm
- name: field_names
type: string
required: false
label:
en_US: field_names
zh_Hans: 字段名称
human_description:
en_US: |
Field names to specify which fields to include in the returned records. Example value: ["Field1", "Field2"].
zh_Hans: 字段名称,用于指定本次查询返回记录中包含的字段。示例值:["字段1","字段2"]。
llm_description: 字段名称,用于指定本次查询返回记录中包含的字段。示例值:["字段1","字段2"]。
form: llm
- name: sort
type: string
required: false
label:
en_US: sort
zh_Hans: 排序条件
human_description:
en_US: |
Sorting conditions, for example: [{"field_name":"Multiline Text","desc":true}].
zh_Hans: 排序条件,例如:[{"field_name":"多行文本","desc":true}]。
llm_description: 排序条件,例如:[{"field_name":"多行文本","desc":true}]。
form: llm
- name: filter
type: string
required: false
label:
en_US: filter
zh_Hans: 筛选条件
human_description:
en_US: Object containing filter information. For details on how to fill in the filter, refer to the record filter parameter guide (https://open.larkoffice.com/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-record/record-filter-guide).
zh_Hans: 包含条件筛选信息的对象。了解如何填写 filter,参考记录筛选参数填写指南(https://open.larkoffice.com/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-record/record-filter-guide)。
llm_description: 包含条件筛选信息的对象。了解如何填写 filter,参考记录筛选参数填写指南(https://open.larkoffice.com/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table-record/record-filter-guide)。
form: llm
- name: automatic_fields
type: boolean
required: false
label:
en_US: automatic_fields
zh_Hans: automatic_fields
human_description:
en_US: Whether to return automatically calculated fields. Default is false, meaning they are not returned.
zh_Hans: 是否返回自动计算的字段。默认为 false,表示不返回。
llm_description: 是否返回自动计算的字段。默认为 false,表示不返回。
form: form
- name: user_id_type
type: select
required: false
options:
- value: open_id
label:
en_US: open_id
zh_Hans: open_id
- value: union_id
label:
en_US: union_id
zh_Hans: union_id
- value: user_id
label:
en_US: user_id
zh_Hans: user_id
default: "open_id"
label:
en_US: user_id_type
zh_Hans: 用户 ID 类型
human_description:
en_US: User ID type, optional values are open_id, union_id, user_id, with a default value of open_id.
zh_Hans: 用户 ID 类型,可选值有 open_id、union_id、user_id,默认值为 open_id。
llm_description: 用户 ID 类型,可选值有 open_id、union_id、user_id,默认值为 open_id。
form: form
- name: page_size
type: number
required: false
default: 20
label:
en_US: page_size
zh_Hans: 分页大小
human_description:
en_US: |
Page size, default value: 20, maximum value: 500.
zh_Hans: 分页大小,默认值:20,最大值:500。
llm_description: 分页大小,默认值:20,最大值:500。
form: form
- name: page_token
type: string
required: false
label:
en_US: page_token
zh_Hans: 分页标记
human_description:
en_US: |
Page token, leave empty for the first request to start from the beginning; a new page_token will be returned if there are more items in the paginated query results, which can be used for the next traversal. Example value: "tblsRc9GRRXKqhvW".
zh_Hans: 分页标记,第一次请求不填,表示从头开始遍历;分页查询结果还有更多项时会同时返回新的 page_token,下次遍历可采用该 page_token 获取查询结果。示例值:"tblsRc9GRRXKqhvW"。
llm_description: 分页标记,第一次请求不填,表示从头开始遍历;分页查询结果还有更多项时会同时返回新的 page_token,下次遍历可采用该 page_token 获取查询结果。示例值:"tblsRc9GRRXKqhvW"。
form: llm
@@ -0,0 +1,21 @@
from typing import Any
from core.tools.entities.tool_entities import ToolInvokeMessage
from core.tools.tool.builtin_tool import BuiltinTool
from core.tools.utils.lark_api_utils import LarkRequest
class UpdateRecordsTool(BuiltinTool):
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
app_id = self.runtime.credentials.get("app_id")
app_secret = self.runtime.credentials.get("app_secret")
client = LarkRequest(app_id, app_secret)
app_token = tool_parameters.get("app_token")
table_id = tool_parameters.get("table_id")
table_name = tool_parameters.get("table_name")
records = tool_parameters.get("records")
user_id_type = tool_parameters.get("user_id_type", "open_id")
res = client.update_records(app_token, table_id, table_name, records, user_id_type)
return self.create_json_message(res)
@@ -0,0 +1,91 @@
identity:
name: update_records
author: Doug Lea
label:
en_US: Update Records
zh_Hans: 更新多条记录
description:
human:
en_US: Update Multiple Records in Multidimensional Table
zh_Hans: 更新多维表格数据表中的多条记录
llm: A tool for updating multiple records in a multidimensional table. (更新多维表格数据表中的多条记录)
parameters:
- name: app_token
type: string
required: true
label:
en_US: app_token
zh_Hans: app_token
human_description:
en_US: Unique identifier for the multidimensional table, supports inputting document URL.
zh_Hans: 多维表格的唯一标识符,支持输入文档 URL。
llm_description: 多维表格的唯一标识符,支持输入文档 URL。
form: llm
- name: table_id
type: string
required: false
label:
en_US: table_id
zh_Hans: table_id
human_description:
en_US: Unique identifier for the multidimensional table data, either table_id or table_name must be provided, cannot be empty simultaneously.
zh_Hans: 多维表格数据表的唯一标识符,table_id 和 table_name 至少需要提供一个,不能同时为空。
llm_description: 多维表格数据表的唯一标识符,table_id 和 table_name 至少需要提供一个,不能同时为空。
form: llm
- name: table_name
type: string
required: false
label:
en_US: table_name
zh_Hans: table_name
human_description:
en_US: Name of the multidimensional table data, either table_name or table_id must be provided, cannot be empty simultaneously.
zh_Hans: 多维表格数据表的名称,table_name 和 table_id 至少需要提供一个,不能同时为空。
llm_description: 多维表格数据表的名称,table_name 和 table_id 至少需要提供一个,不能同时为空。
form: llm
- name: records
type: string
required: true
label:
en_US: records
zh_Hans: 记录列表
human_description:
en_US: |
List of records to be updated in this request. Example value: [{"fields":{"multi-line-text":"text content","single_select":"option 1","date":1674206443000},"record_id":"recupK4f4RM5RX"}].
For supported field types, refer to the integration guide (https://open.larkoffice.com/document/server-docs/docs/bitable-v1/notification). For data structures of different field types, refer to the data structure overview (https://open.larkoffice.com/document/server-docs/docs/bitable-v1/bitable-structure).
zh_Hans: |
本次请求将要更新的记录列表,示例值:[{"fields":{"多行文本":"文本内容","单选":"选项 1","日期":1674206443000},"record_id":"recupK4f4RM5RX"}]。
当前接口支持的字段类型请参考接入指南(https://open.larkoffice.com/document/server-docs/docs/bitable-v1/notification),不同类型字段的数据结构请参考数据结构概述(https://open.larkoffice.com/document/server-docs/docs/bitable-v1/bitable-structure)。
llm_description: |
本次请求将要更新的记录列表,示例值:[{"fields":{"多行文本":"文本内容","单选":"选项 1","日期":1674206443000},"record_id":"recupK4f4RM5RX"}]。
当前接口支持的字段类型请参考接入指南(https://open.larkoffice.com/document/server-docs/docs/bitable-v1/notification),不同类型字段的数据结构请参考数据结构概述(https://open.larkoffice.com/document/server-docs/docs/bitable-v1/bitable-structure)。
form: llm
- name: user_id_type
type: select
required: false
options:
- value: open_id
label:
en_US: open_id
zh_Hans: open_id
- value: union_id
label:
en_US: union_id
zh_Hans: union_id
- value: user_id
label:
en_US: user_id
zh_Hans: user_id
default: "open_id"
label:
en_US: user_id_type
zh_Hans: 用户 ID 类型
human_description:
en_US: User ID type, optional values are open_id, union_id, user_id, with a default value of open_id.
zh_Hans: 用户 ID 类型,可选值有 open_id、union_id、user_id,默认值为 open_id。
llm_description: 用户 ID 类型,可选值有 open_id、union_id、user_id,默认值为 open_id。
form: form
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

@@ -0,0 +1,7 @@
from core.tools.provider.builtin_tool_provider import BuiltinToolProviderController
from core.tools.utils.lark_api_utils import lark_auth
class LarkCalendarProvider(BuiltinToolProviderController):
def _validate_credentials(self, credentials: dict) -> None:
lark_auth(credentials)
@@ -0,0 +1,36 @@
identity:
author: Doug Lea
name: lark_calendar
label:
en_US: Lark Calendar
zh_Hans: Lark 日历
description:
en_US: |
Lark calendar, requires the following permissions: calendar:calendar:read、calendar:calendar、contact:user.id:readonly.
zh_Hans: |
Lark 日历,需要开通以下权限: calendar:calendar:read、calendar:calendar、contact:user.id:readonly。
icon: icon.png
tags:
- social
- productivity
credentials_for_provider:
app_id:
type: text-input
required: true
label:
en_US: APP ID
placeholder:
en_US: Please input your Lark app id
zh_Hans: 请输入你的 Lark app id
help:
en_US: Get your app_id and app_secret from Lark
zh_Hans: 从 Lark 获取您的 app_id 和 app_secret
url: https://open.larksuite.com/app
app_secret:
type: secret-input
required: true
label:
en_US: APP Secret
placeholder:
en_US: Please input your app secret
zh_Hans: 请输入你的 Lark app secret
@@ -0,0 +1,20 @@
from typing import Any
from core.tools.entities.tool_entities import ToolInvokeMessage
from core.tools.tool.builtin_tool import BuiltinTool
from core.tools.utils.lark_api_utils import LarkRequest
class AddEventAttendeesTool(BuiltinTool):
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
app_id = self.runtime.credentials.get("app_id")
app_secret = self.runtime.credentials.get("app_secret")
client = LarkRequest(app_id, app_secret)
event_id = tool_parameters.get("event_id")
attendee_phone_or_email = tool_parameters.get("attendee_phone_or_email")
need_notification = tool_parameters.get("need_notification", True)
res = client.add_event_attendees(event_id, attendee_phone_or_email, need_notification)
return self.create_json_message(res)
@@ -0,0 +1,54 @@
identity:
name: add_event_attendees
author: Doug Lea
label:
en_US: Add Event Attendees
zh_Hans: 添加日程参会人
description:
human:
en_US: Add Event Attendees
zh_Hans: 添加日程参会人
llm: A tool for adding attendees to events in Lark. (在 Lark 中添加日程参会人)
parameters:
- name: event_id
type: string
required: true
label:
en_US: Event ID
zh_Hans: 日程 ID
human_description:
en_US: |
The ID of the event, which will be returned when the event is created. For example: fb2a6406-26d6-4c8d-a487-6f0246c94d2f_0.
zh_Hans: |
创建日程时会返回日程 ID。例如: fb2a6406-26d6-4c8d-a487-6f0246c94d2f_0。
llm_description: |
日程 ID,创建日程时会返回日程 ID。例如: fb2a6406-26d6-4c8d-a487-6f0246c94d2f_0。
form: llm
- name: need_notification
type: boolean
required: false
default: true
label:
en_US: Need Notification
zh_Hans: 是否需要通知
human_description:
en_US: |
Whether to send a Bot notification to attendees. true: send, false: do not send.
zh_Hans: |
是否给参与人发送 Bot 通知,true: 发送,false: 不发送。
llm_description: |
是否给参与人发送 Bot 通知,true: 发送,false: 不发送。
form: form
- name: attendee_phone_or_email
type: string
required: true
label:
en_US: Attendee Phone or Email
zh_Hans: 参会人电话或邮箱
human_description:
en_US: The list of attendee emails or phone numbers, separated by commas.
zh_Hans: 日程参会人邮箱或者手机号列表,使用逗号分隔。
llm_description: 日程参会人邮箱或者手机号列表,使用逗号分隔。
form: llm
@@ -0,0 +1,26 @@
from typing import Any
from core.tools.entities.tool_entities import ToolInvokeMessage
from core.tools.tool.builtin_tool import BuiltinTool
from core.tools.utils.lark_api_utils import LarkRequest
class CreateEventTool(BuiltinTool):
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
app_id = self.runtime.credentials.get("app_id")
app_secret = self.runtime.credentials.get("app_secret")
client = LarkRequest(app_id, app_secret)
summary = tool_parameters.get("summary")
description = tool_parameters.get("description")
start_time = tool_parameters.get("start_time")
end_time = tool_parameters.get("end_time")
attendee_ability = tool_parameters.get("attendee_ability")
need_notification = tool_parameters.get("need_notification", True)
auto_record = tool_parameters.get("auto_record", False)
res = client.create_event(
summary, description, start_time, end_time, attendee_ability, need_notification, auto_record
)
return self.create_json_message(res)

Some files were not shown because too many files have changed in this diff Show More