mirror of
https://github.com/langgenius/dify.git
synced 2026-01-10 08:14:14 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bfcd227e8 | ||
|
|
7f891939f1 | ||
|
|
69a5ce1e31 |
BIN
api/core/tools/provider/builtin/tavily/_assets/icon.png
Normal file
BIN
api/core/tools/provider/builtin/tavily/_assets/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
22
api/core/tools/provider/builtin/tavily/tavily.py
Normal file
22
api/core/tools/provider/builtin/tavily/tavily.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from typing import Any
|
||||
|
||||
from core.tools.errors import ToolProviderCredentialValidationError
|
||||
from core.tools.provider.builtin.tavily.tools.tavily_search import TavilySearchTool
|
||||
from core.tools.provider.builtin_tool_provider import BuiltinToolProviderController
|
||||
|
||||
|
||||
class TavilyProvider(BuiltinToolProviderController):
|
||||
def _validate_credentials(self, credentials: dict[str, Any]) -> None:
|
||||
try:
|
||||
TavilySearchTool().fork_tool_runtime(
|
||||
meta={
|
||||
"credentials": credentials,
|
||||
}
|
||||
).invoke(
|
||||
user_id='',
|
||||
tool_parameters={
|
||||
"query": "Sachin Tendulkar",
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
29
api/core/tools/provider/builtin/tavily/tavily.yaml
Normal file
29
api/core/tools/provider/builtin/tavily/tavily.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
identity:
|
||||
author: Yash Parmar
|
||||
name: tavily
|
||||
label:
|
||||
en_US: Tavily
|
||||
zh_Hans: Tavily
|
||||
pt_BR: Tavily
|
||||
description:
|
||||
en_US: Tavily
|
||||
zh_Hans: Tavily
|
||||
pt_BR: Tavily
|
||||
icon: icon.png
|
||||
credentials_for_provider:
|
||||
tavily_api_key:
|
||||
type: secret-input
|
||||
required: true
|
||||
label:
|
||||
en_US: Tavily API key
|
||||
zh_Hans: Tavily API key
|
||||
pt_BR: Tavily API key
|
||||
placeholder:
|
||||
en_US: Please input your Tavily API key
|
||||
zh_Hans: 请输入你的 Tavily API key
|
||||
pt_BR: Please input your Tavily API key
|
||||
help:
|
||||
en_US: Get your Tavily API key from Tavily
|
||||
zh_Hans: 从 TavilyApi 获取您的 Tavily API key
|
||||
pt_BR: Get your Tavily API key from Tavily
|
||||
url: https://docs.tavily.com/docs/tavily-api/introduction
|
||||
161
api/core/tools/provider/builtin/tavily/tools/tavily_search.py
Normal file
161
api/core/tools/provider/builtin/tavily/tools/tavily_search.py
Normal file
@@ -0,0 +1,161 @@
|
||||
from typing import Any, Optional
|
||||
|
||||
import requests
|
||||
|
||||
from core.tools.entities.tool_entities import ToolInvokeMessage
|
||||
from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
TAVILY_API_URL = "https://api.tavily.com"
|
||||
|
||||
|
||||
class TavilySearch:
|
||||
"""
|
||||
A class for performing search operations using the Tavily Search API.
|
||||
|
||||
Args:
|
||||
api_key (str): The API key for accessing the Tavily Search API.
|
||||
|
||||
Methods:
|
||||
raw_results: Retrieves raw search results from the Tavily Search API.
|
||||
results: Retrieves cleaned search results from the Tavily Search API.
|
||||
clean_results: Cleans the raw search results.
|
||||
"""
|
||||
|
||||
def __init__(self, api_key: str) -> None:
|
||||
self.api_key = api_key
|
||||
|
||||
def raw_results(
|
||||
self,
|
||||
query: str,
|
||||
max_results: Optional[int] = 3,
|
||||
search_depth: Optional[str] = "advanced",
|
||||
include_domains: Optional[list[str]] = [],
|
||||
exclude_domains: Optional[list[str]] = [],
|
||||
include_answer: Optional[bool] = False,
|
||||
include_raw_content: Optional[bool] = False,
|
||||
include_images: Optional[bool] = False,
|
||||
) -> dict:
|
||||
"""
|
||||
Retrieves raw search results from the Tavily Search API.
|
||||
|
||||
Args:
|
||||
query (str): The search query.
|
||||
max_results (int, optional): The maximum number of results to retrieve. Defaults to 3.
|
||||
search_depth (str, optional): The search depth. Defaults to "advanced".
|
||||
include_domains (List[str], optional): The domains to include in the search. Defaults to [].
|
||||
exclude_domains (List[str], optional): The domains to exclude from the search. Defaults to [].
|
||||
include_answer (bool, optional): Whether to include answer in the search results. Defaults to False.
|
||||
include_raw_content (bool, optional): Whether to include raw content in the search results. Defaults to False.
|
||||
include_images (bool, optional): Whether to include images in the search results. Defaults to False.
|
||||
|
||||
Returns:
|
||||
dict: The raw search results.
|
||||
|
||||
"""
|
||||
params = {
|
||||
"api_key": self.api_key,
|
||||
"query": query,
|
||||
"max_results": max_results,
|
||||
"search_depth": search_depth,
|
||||
"include_domains": include_domains,
|
||||
"exclude_domains": exclude_domains,
|
||||
"include_answer": include_answer,
|
||||
"include_raw_content": include_raw_content,
|
||||
"include_images": include_images,
|
||||
}
|
||||
response = requests.post(f"{TAVILY_API_URL}/search", json=params)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
def results(
|
||||
self,
|
||||
query: str,
|
||||
max_results: Optional[int] = 3,
|
||||
search_depth: Optional[str] = "advanced",
|
||||
include_domains: Optional[list[str]] = [],
|
||||
exclude_domains: Optional[list[str]] = [],
|
||||
include_answer: Optional[bool] = False,
|
||||
include_raw_content: Optional[bool] = False,
|
||||
include_images: Optional[bool] = False,
|
||||
) -> list[dict]:
|
||||
"""
|
||||
Retrieves cleaned search results from the Tavily Search API.
|
||||
|
||||
Args:
|
||||
query (str): The search query.
|
||||
max_results (int, optional): The maximum number of results to retrieve. Defaults to 3.
|
||||
search_depth (str, optional): The search depth. Defaults to "advanced".
|
||||
include_domains (List[str], optional): The domains to include in the search. Defaults to [].
|
||||
exclude_domains (List[str], optional): The domains to exclude from the search. Defaults to [].
|
||||
include_answer (bool, optional): Whether to include answer in the search results. Defaults to False.
|
||||
include_raw_content (bool, optional): Whether to include raw content in the search results. Defaults to False.
|
||||
include_images (bool, optional): Whether to include images in the search results. Defaults to False.
|
||||
|
||||
Returns:
|
||||
list: The cleaned search results.
|
||||
|
||||
"""
|
||||
raw_search_results = self.raw_results(
|
||||
query,
|
||||
max_results=max_results,
|
||||
search_depth=search_depth,
|
||||
include_domains=include_domains,
|
||||
exclude_domains=exclude_domains,
|
||||
include_answer=include_answer,
|
||||
include_raw_content=include_raw_content,
|
||||
include_images=include_images,
|
||||
)
|
||||
return self.clean_results(raw_search_results["results"])
|
||||
|
||||
def clean_results(self, results: list[dict]) -> list[dict]:
|
||||
"""
|
||||
Cleans the raw search results.
|
||||
|
||||
Args:
|
||||
results (list): The raw search results.
|
||||
|
||||
Returns:
|
||||
list: The cleaned search results.
|
||||
|
||||
"""
|
||||
clean_results = []
|
||||
for result in results:
|
||||
clean_results.append(
|
||||
{
|
||||
"url": result["url"],
|
||||
"content": result["content"],
|
||||
}
|
||||
)
|
||||
# return clean results as a string
|
||||
return "\n".join([f"{res['url']}\n{res['content']}" for res in clean_results])
|
||||
|
||||
|
||||
class TavilySearchTool(BuiltinTool):
|
||||
"""
|
||||
A tool for searching Tavily using a given query.
|
||||
"""
|
||||
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> ToolInvokeMessage | list[ToolInvokeMessage]:
|
||||
"""
|
||||
Invokes the Tavily search tool with the given user ID and tool parameters.
|
||||
|
||||
Args:
|
||||
user_id (str): The ID of the user invoking the tool.
|
||||
tool_parameters (Dict[str, Any]): The parameters for the Tavily search tool.
|
||||
|
||||
Returns:
|
||||
ToolInvokeMessage | list[ToolInvokeMessage]: The result of the Tavily search tool invocation.
|
||||
"""
|
||||
query = tool_parameters.get("query", "")
|
||||
api_key = self.runtime.credentials["tavily_api_key"]
|
||||
if not query:
|
||||
return self.create_text_message("Please input query")
|
||||
tavily_search = TavilySearch(api_key)
|
||||
results = tavily_search.results(query)
|
||||
print(results)
|
||||
if not results:
|
||||
return self.create_text_message(f"No results found for '{query}' in Tavily")
|
||||
else:
|
||||
return self.create_text_message(text=results)
|
||||
@@ -0,0 +1,27 @@
|
||||
identity:
|
||||
name: tavily_search
|
||||
author: Yash Parmar
|
||||
label:
|
||||
en_US: TavilySearch
|
||||
zh_Hans: TavilySearch
|
||||
pt_BR: TavilySearch
|
||||
description:
|
||||
human:
|
||||
en_US: A tool for search engine built specifically for AI agents (LLMs), delivering real-time, accurate, and factual results at speed.
|
||||
zh_Hans: 专为人工智能代理 (LLM) 构建的搜索引擎工具,可快速提供实时、准确和真实的结果。
|
||||
pt_BR: A tool for search engine built specifically for AI agents (LLMs), delivering real-time, accurate, and factual results at speed.
|
||||
llm: A tool for search engine built specifically for AI agents (LLMs), delivering real-time, accurate, and factual results at speed.
|
||||
parameters:
|
||||
- name: query
|
||||
type: string
|
||||
required: true
|
||||
label:
|
||||
en_US: Query string
|
||||
zh_Hans: 查询语句
|
||||
pt_BR: Query string
|
||||
human_description:
|
||||
en_US: used for searching
|
||||
zh_Hans: 用于搜索网页内容
|
||||
pt_BR: used for searching
|
||||
llm_description: key words for searching
|
||||
form: llm
|
||||
@@ -82,7 +82,7 @@ services:
|
||||
S3_SECRET_KEY: 'sk-difyai'
|
||||
S3_REGION: 'us-east-1'
|
||||
# The type of vector store to use. Supported values are `weaviate`, `qdrant`, `milvus`.
|
||||
VECTOR_STORE: weaviate
|
||||
VECTOR_STORE: qdrant
|
||||
# The Weaviate endpoint URL. Only available when VECTOR_STORE is `weaviate`.
|
||||
WEAVIATE_ENDPOINT: http://weaviate:8080
|
||||
# The Weaviate API key.
|
||||
@@ -168,7 +168,7 @@ services:
|
||||
STORAGE_TYPE: local
|
||||
STORAGE_LOCAL_PATH: storage
|
||||
# The type of vector store to use. Supported values are `weaviate`, `qdrant`, `milvus`.
|
||||
VECTOR_STORE: weaviate
|
||||
VECTOR_STORE: qdrant
|
||||
# The Weaviate endpoint URL. Only available when VECTOR_STORE is `weaviate`.
|
||||
WEAVIATE_ENDPOINT: http://weaviate:8080
|
||||
# The Weaviate API key.
|
||||
@@ -263,25 +263,25 @@ services:
|
||||
# - "6379:6379"
|
||||
|
||||
# The Weaviate vector store.
|
||||
weaviate:
|
||||
image: semitechnologies/weaviate:1.19.0
|
||||
restart: always
|
||||
volumes:
|
||||
# Mount the Weaviate data directory to the container.
|
||||
- ./volumes/weaviate:/var/lib/weaviate
|
||||
environment:
|
||||
# The Weaviate configurations
|
||||
# You can refer to the [Weaviate](https://weaviate.io/developers/weaviate/config-refs/env-vars) documentation for more information.
|
||||
QUERY_DEFAULTS_LIMIT: 25
|
||||
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'false'
|
||||
PERSISTENCE_DATA_PATH: '/var/lib/weaviate'
|
||||
DEFAULT_VECTORIZER_MODULE: 'none'
|
||||
CLUSTER_HOSTNAME: 'node1'
|
||||
AUTHENTICATION_APIKEY_ENABLED: 'true'
|
||||
AUTHENTICATION_APIKEY_ALLOWED_KEYS: 'WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih'
|
||||
AUTHENTICATION_APIKEY_USERS: 'hello@dify.ai'
|
||||
AUTHORIZATION_ADMINLIST_ENABLED: 'true'
|
||||
AUTHORIZATION_ADMINLIST_USERS: 'hello@dify.ai'
|
||||
# weaviate:
|
||||
# image: semitechnologies/weaviate:1.19.0
|
||||
# restart: always
|
||||
# volumes:
|
||||
# # Mount the Weaviate data directory to the container.
|
||||
# - ./volumes/weaviate:/var/lib/weaviate
|
||||
# environment:
|
||||
# # The Weaviate configurations
|
||||
# # You can refer to the [Weaviate](https://weaviate.io/developers/weaviate/config-refs/env-vars) documentation for more information.
|
||||
# QUERY_DEFAULTS_LIMIT: 25
|
||||
# AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'false'
|
||||
# PERSISTENCE_DATA_PATH: '/var/lib/weaviate'
|
||||
# DEFAULT_VECTORIZER_MODULE: 'none'
|
||||
# CLUSTER_HOSTNAME: 'node1'
|
||||
# AUTHENTICATION_APIKEY_ENABLED: 'true'
|
||||
# AUTHENTICATION_APIKEY_ALLOWED_KEYS: 'WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih'
|
||||
# AUTHENTICATION_APIKEY_USERS: 'hello@dify.ai'
|
||||
# AUTHORIZATION_ADMINLIST_ENABLED: 'true'
|
||||
# AUTHORIZATION_ADMINLIST_USERS: 'hello@dify.ai'
|
||||
# uncomment to expose weaviate port to host
|
||||
# ports:
|
||||
# - "8080:8080"
|
||||
@@ -290,13 +290,13 @@ services:
|
||||
# uncomment to use qdrant as vector store.
|
||||
# (if uncommented, you need to comment out the weaviate service above,
|
||||
# and set VECTOR_STORE to qdrant in the api & worker service.)
|
||||
# qdrant:
|
||||
# image: langgenius/qdrant:v1.7.3
|
||||
# restart: always
|
||||
# volumes:
|
||||
# - ./volumes/qdrant:/qdrant/storage
|
||||
# environment:
|
||||
# QDRANT__API_KEY: 'difyai123456'
|
||||
qdrant:
|
||||
image: langgenius/qdrant:v1.7.3
|
||||
restart: always
|
||||
volumes:
|
||||
- ./volumes/qdrant:/qdrant/storage
|
||||
environment:
|
||||
QDRANT__API_KEY: 'difyai123456'
|
||||
# # uncomment to expose qdrant port to host
|
||||
# # ports:
|
||||
# # - "6333:6333"
|
||||
|
||||
@@ -61,13 +61,14 @@ const AudioBtn = ({
|
||||
const audioUrl = URL.createObjectURL(blob)
|
||||
const audio = new Audio(audioUrl)
|
||||
audioRef.current = audio
|
||||
audio.play().then(() => {
|
||||
setIsPlaying(true)
|
||||
}).catch(() => {
|
||||
audio.play().then(() => {}).catch(() => {
|
||||
setIsPlaying(false)
|
||||
URL.revokeObjectURL(audioUrl)
|
||||
})
|
||||
audio.onended = () => setHasEnded(true)
|
||||
audio.onended = () => {
|
||||
setHasEnded(true)
|
||||
setIsPlaying(false)
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
setIsPlaying(false)
|
||||
@@ -75,24 +76,34 @@ const AudioBtn = ({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const togglePlayPause = () => {
|
||||
if (audioRef.current) {
|
||||
if (isPlaying) {
|
||||
setPause(true)
|
||||
audioRef.current.pause()
|
||||
}
|
||||
else if (!hasEnded) {
|
||||
setPause(false)
|
||||
audioRef.current.play()
|
||||
if (!hasEnded) {
|
||||
setPause(false)
|
||||
audioRef.current.play()
|
||||
}
|
||||
if (!isPause) {
|
||||
setPause(true)
|
||||
audioRef.current.pause()
|
||||
}
|
||||
}
|
||||
else if (!isPlaying) {
|
||||
playAudio().then()
|
||||
if (isPause) {
|
||||
setPause(false)
|
||||
audioRef.current.play()
|
||||
}
|
||||
else {
|
||||
setHasEnded(false)
|
||||
playAudio().then()
|
||||
}
|
||||
}
|
||||
setIsPlaying(prevIsPlaying => !prevIsPlaying)
|
||||
}
|
||||
else {
|
||||
playAudio().then()
|
||||
setIsPlaying(true)
|
||||
if (!isPlaying)
|
||||
playAudio().then()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +118,7 @@ const AudioBtn = ({
|
||||
className={`box-border p-0.5 flex items-center justify-center cursor-pointer ${isAudition || 'rounded-md bg-white'}`}
|
||||
style={{ boxShadow: !isAudition ? '0px 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06)' : '' }}
|
||||
onClick={togglePlayPause}>
|
||||
<div className={`w-6 h-6 rounded-md ${!isAudition ? 'hover:bg-gray-200' : 'hover:bg-gray-50'} ${!isPause ? ((isPlaying && !hasEnded) ? s.playIcon : s.stopIcon) : s.pauseIcon}`}></div>
|
||||
<div className={`w-6 h-6 rounded-md ${!isAudition ? 'hover:bg-gray-200' : 'hover:bg-gray-50'} ${(isPlaying && !hasEnded) ? s.pauseIcon : s.playIcon}`}></div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
@@ -8,9 +8,3 @@
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.stopIcon {
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url(~@/app/components/develop/secret-key/assets/stop.svg);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_129_107)">
|
||||
<path d="M7.99991 14.6666C11.6819 14.6666 14.6666 11.6819 14.6666 7.99998C14.6666 4.31808 11.6819 1.33331 7.99998 1.33331C4.31808 1.33331 1.33331 4.31808 1.33331 7.99998C1.33331 11.6819 4.31808 14.6666 7.99998 14.6666Z" stroke="#155EEF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6.66665 5.33331L10.6666 7.99998L6.66665 10.6666V5.33331Z" stroke="#155EEF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M7.99998 14.6666C11.6819 14.6666 14.6666 11.6819 14.6666 7.99998C14.6666 4.31808 11.6819 1.33331 7.99998 1.33331C4.31808 1.33331 1.33331 4.31808 1.33331 7.99998C1.33331 11.6819 4.31808 14.6666 7.99998 14.6666Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6.66665 5.33331L10.6666 7.99998L6.66665 10.6666V5.33331Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_129_107">
|
||||
|
||||
|
Before Width: | Height: | Size: 703 B After Width: | Height: | Size: 703 B |
@@ -1,11 +0,0 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_129_107)">
|
||||
<path d="M7.99998 14.6666C11.6819 14.6666 14.6666 11.6819 14.6666 7.99998C14.6666 4.31808 11.6819 1.33331 7.99998 1.33331C4.31808 1.33331 1.33331 4.31808 1.33331 7.99998C1.33331 11.6819 4.31808 14.6666 7.99998 14.6666Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6.66665 5.33331L10.6666 7.99998L6.66665 10.6666V5.33331Z" stroke="#667085" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_129_107">
|
||||
<rect width="16" height="16" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 703 B |
Reference in New Issue
Block a user