Bläddra i källkod

Add New Tool: StackExchange (#3034)

Co-authored-by: crazywoola <427733928@qq.com>
Richards Tu 1 år sedan
förälder
incheckning
17af0de7b6

+ 1 - 0
api/core/tools/provider/builtin/stackexchange/_assets/icon.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120"><style>.st0{fill:#376db6}.st1{fill:#4ca2da}.st2{fill:#91d8f4}.st3{fill:#1e5397}</style><path class="st0" d="M22.4 57.5h74.8v15.4H22.4z"/><path class="st1" d="M22.4 37.6h74.8V53H22.4z"/><path class="st2" d="M85.5 17H34.4c-6.6 0-12 5.5-12 12.3v4h74.8v-4C97.2 22.5 92 17 85.5 17z"/><path class="st3" d="M22.4 77.3v4c0 6.8 5.4 12.3 12 12.3h32v16.3l15.8-16.3h3.5c6.6 0 12-5.5 12-12.3v-4H22.4z"/></svg>

+ 25 - 0
api/core/tools/provider/builtin/stackexchange/stackexchange.py

@@ -0,0 +1,25 @@
+from core.tools.errors import ToolProviderCredentialValidationError
+from core.tools.provider.builtin.stackexchange.tools.searchStackExQuestions import SearchStackExQuestionsTool
+from core.tools.provider.builtin_tool_provider import BuiltinToolProviderController
+
+
+class StackExchangeProvider(BuiltinToolProviderController):
+    def _validate_credentials(self, credentials: dict) -> None:
+        try:
+            SearchStackExQuestionsTool().fork_tool_runtime(
+                meta={
+                    "credentials": credentials,
+                }
+            ).invoke(
+                user_id='',
+                tool_parameters={
+                    "intitle": "Test",
+                    "sort": "relevance",  
+                    "order": "desc",
+                    "site": "stackoverflow",
+                    "accepted": True,
+                    "pagesize": 1
+                },
+            )
+        except Exception as e:
+            raise ToolProviderCredentialValidationError(str(e))

+ 10 - 0
api/core/tools/provider/builtin/stackexchange/stackexchange.yaml

@@ -0,0 +1,10 @@
+identity:
+  author: Richards Tu
+  name: stackexchange
+  label:
+    en_US: Stack Exchange
+    zh_Hans: Stack Exchange
+  description:
+    en_US: Access questions and answers from the Stack Exchange and its sub-sites.
+    zh_Hans: 从Stack Exchange和其子论坛获取问题和答案。
+  icon: icon.svg

+ 37 - 0
api/core/tools/provider/builtin/stackexchange/tools/fetchAnsByStackExQuesID.py

@@ -0,0 +1,37 @@
+from typing import Any, Union
+
+import requests
+from pydantic import BaseModel, Field
+
+from core.tools.entities.tool_entities import ToolInvokeMessage
+from core.tools.tool.builtin_tool import BuiltinTool
+
+
+class FetchAnsByStackExQuesIDInput(BaseModel):
+    id: int = Field(..., description="The question ID")
+    site: str = Field(..., description="The Stack Exchange site")
+    order: str = Field(..., description="asc or desc")
+    sort: str = Field(..., description="activity, votes, creation")
+    pagesize: int = Field(..., description="Number of answers per page")
+    page: int = Field(..., description="Page number")
+
+
+class FetchAnsByStackExQuesIDTool(BuiltinTool):
+    def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
+        input = FetchAnsByStackExQuesIDInput(**tool_parameters)
+
+        params = {
+            "site": input.site,
+            "filter": "!nNPvSNdWme",
+            "order": input.order,
+            "sort": input.sort,
+            "pagesize": input.pagesize,
+            "page": input.page
+        }
+
+        response = requests.get(f"https://api.stackexchange.com/2.3/questions/{input.id}/answers", params=params)
+
+        if response.status_code == 200:
+            return self.create_text_message(self.summary(user_id=user_id, content=response.text))
+        else:
+            return self.create_text_message(f"API request failed with status code {response.status_code}")

+ 189 - 0
api/core/tools/provider/builtin/stackexchange/tools/fetchAnsByStackExQuesID.yaml

@@ -0,0 +1,189 @@
+identity:
+  name: fetchAnsByStackExQuesID
+  author: Richards Tu
+  label:
+    en_US: Fetch Stack Exchange Answers
+    zh_Hans: 获取 Stack Exchange 答案
+description:
+  human:
+    en_US: A tool for retrieving answers for a specific Stack Exchange question ID. Specify the question ID, Stack Exchange site, sorting order, number of results per page, and page number. Must be used with the searchStackExQuesID tool.
+    zh_Hans: 用于检索特定Stack Exchange问题ID的答案的工具。指定问题ID、Stack Exchange站点、排序顺序、每页结果数和页码。 必须与searchStackExQuesID工具一起使用。
+  llm: A tool for retrieving answers for a specific Stack Exchange question ID based on the provided parameters.
+parameters:
+  - name: id
+    type: string
+    required: true
+    label:
+      en_US: Question ID
+      zh_Hans: 问题ID
+    human_description:
+      en_US: The ID of the Stack Exchange question to fetch answers for.
+      zh_Hans: 要获取答案的Stack Exchange问题的ID。
+    llm_description: The ID of the Stack Exchange question.
+    form: llm
+  - name: site
+    type: string
+    required: true
+    label:
+      en_US: Stack Exchange site
+      zh_Hans: Stack Exchange站点
+    human_description:
+      en_US: The Stack Exchange site the question is from, e.g. stackoverflow, unix, etc.
+      zh_Hans: 问题所在的Stack Exchange站点,例如stackoverflow、unix等。
+    llm_description: The Stack Exchange site identifier.
+    options:
+      - value: stackoverflow
+        label:
+          en_US: stackoverflow
+      - value: serverfault
+        label:
+          en_US: serverfault
+      - value: superuser
+        label:
+          en_US: superuser
+      - value: askubuntu
+        label:
+          en_US: askubuntu
+      - value: unix
+        label:
+          en_US: unix
+      - value: cs
+        label:
+          en_US: cs
+      - value: softwareengineering
+        label:
+          en_US: softwareengineering
+      - value: codegolf
+        label:
+          en_US: codegolf
+      - value: codereview
+        label:
+          en_US: codereview
+      - value: cstheory
+        label:
+          en_US: cstheory
+      - value: security
+        label:
+          en_US: security
+      - value: cryptography
+        label:
+          en_US: cryptography
+      - value: reverseengineering
+        label:
+          en_US: reverseengineering
+      - value: datascience
+        label:
+          en_US: datascience
+      - value: devops
+        label:
+          en_US: devops
+      - value: ux
+        label:
+          en_US: ux
+      - value: dba
+        label:
+          en_US: dba
+      - value: gis
+        label:
+          en_US: gis
+      - value: webmasters
+        label:
+          en_US: webmasters
+      - value: arduino
+        label:
+          en_US: arduino
+      - value: raspberrypi
+        label:
+          en_US: raspberrypi
+      - value: networkengineering
+        label:
+          en_US: networkengineering
+      - value: iot
+        label:
+          en_US: iot
+      - value: tor
+        label:
+          en_US: tor
+      - value: sqa
+        label:
+          en_US: sqa
+      - value: mathoverflow
+        label:
+          en_US: mathoverflow
+      - value: math
+        label:
+          en_US: math
+      - value: mathematica
+        label:
+          en_US: mathematica
+      - value: dsp
+        label:
+          en_US: dsp
+      - value: gamedev
+        label:
+          en_US: gamedev
+      - value: robotics
+        label:
+          en_US: robotics
+      - value: genai
+        label:
+          en_US: genai
+      - value: computergraphics
+        label:
+          en_US: computergraphics
+    form: form
+  - name: filter
+    type: string
+    required: true
+    label:
+      en_US: Filter
+      zh_Hans: 过滤器
+    human_description:
+      en_US: This is required in order to actually get the body of the answer.
+      zh_Hans: 为了实际获取答案的正文,这是必需的。
+    llm_description: Required in order to actually get the body of the answer. Must be \"!nNPvSNdWme\".
+    form: llm
+  - name: order
+    type: string
+    required: true
+    label:
+      en_US: Sort direction
+      zh_Hans: 排序方向
+    human_description:
+      en_US: The direction to sort the answers - ascending or descending.
+      zh_Hans: 答案的排序方向 - 升序或降序。
+    llm_description: asc for ascending, desc for descending.
+    form: llm
+  - name: sort
+    type: string
+    required: true
+    label:
+      en_US: Sort order
+      zh_Hans: 排序
+    human_description:
+      en_US: The sort order for the answers - activity, votes, or creation date.
+      zh_Hans: 答案的排序顺序 - 活动、投票或创建日期。
+    llm_description: activity, votes, or creation.
+    form: llm
+  - name: pagesize
+    type: number
+    required: true
+    label:
+      en_US: Results per page
+      zh_Hans: 每页结果数
+    human_description:
+      en_US: The number of answers to return per page.
+      zh_Hans: 每页返回的答案数。
+    llm_description: The number of answers per page.
+    form: llm
+  - name: page
+    type: number
+    required: true
+    label:
+      en_US: Page number
+      zh_Hans: 页码
+    human_description:
+      en_US: The page number of answers to retrieve.
+      zh_Hans: 要检索的答案的页码。
+    llm_description: The page number to retrieve.
+    form: llm

+ 43 - 0
api/core/tools/provider/builtin/stackexchange/tools/searchStackExQuestions.py

@@ -0,0 +1,43 @@
+from typing import Any, Union
+
+import requests
+from pydantic import BaseModel, Field
+
+from core.tools.entities.tool_entities import ToolInvokeMessage
+from core.tools.tool.builtin_tool import BuiltinTool
+
+
+class SearchStackExQuestionsInput(BaseModel):
+    intitle: str = Field(..., description="The search query.")
+    sort: str = Field(..., description="The sort order - relevance, activity, votes, creation.")  
+    order: str = Field(..., description="asc or desc")
+    site: str = Field(..., description="The Stack Exchange site.")
+    tagged: str = Field(None, description="Semicolon-separated tags to include.")
+    nottagged: str = Field(None, description="Semicolon-separated tags to exclude.")
+    accepted: bool = Field(..., description="true for only accepted answers, false otherwise") 
+    pagesize: int = Field(..., description="Number of results per page")
+
+
+class SearchStackExQuestionsTool(BuiltinTool):
+    def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
+        input = SearchStackExQuestionsInput(**tool_parameters)
+
+        params = {
+            "intitle": input.intitle,
+            "sort": input.sort,
+            "order": input.order,  
+            "site": input.site,
+            "accepted": input.accepted,
+            "pagesize": input.pagesize
+        }
+        if input.tagged:
+            params["tagged"] = input.tagged
+        if input.nottagged:
+            params["nottagged"] = input.nottagged
+
+        response = requests.get("https://api.stackexchange.com/2.3/search", params=params)
+
+        if response.status_code == 200:
+            return self.create_text_message(self.summary(user_id=user_id, content=response.text))
+        else:
+            return self.create_text_message(f"API request failed with status code {response.status_code}")

+ 200 - 0
api/core/tools/provider/builtin/stackexchange/tools/searchStackExQuestions.yaml

@@ -0,0 +1,200 @@
+identity:
+  name: searchStackExQuestions
+  author: Richards Tu
+  label:
+    en_US: Search Stack Exchange Questions
+    zh_Hans: 搜索Stack Exchange问题
+description:
+  human:
+    en_US: A tool for searching questions on a Stack Exchange site. Specify the search query, sorting order, tags to include or exclude, whether to search only for questions with accepted answers, the Stack Exchange site, and number of results per page.
+    zh_Hans: 在Stack Exchange站点上搜索问题的工具。指定搜索查询、排序顺序、要包含或排除的标签、是否仅搜索有已接受答案的问题、Stack Exchange站点以及每页结果数。
+  llm: A tool for searching questions on a Stack Exchange site based on the provided parameters.
+parameters:
+  - name: intitle
+    type: string
+    required: true
+    label:
+      en_US: Search query
+      zh_Hans: 搜索查询
+    human_description:
+      en_US: The search query to use for finding questions.
+      zh_Hans: 用于查找问题的搜索查询。
+    llm_description: The search query to use.
+    form: llm
+  - name: sort
+    type: string
+    required: true
+    label:
+      en_US: Sort order
+      zh_Hans: 排序
+    human_description:
+      en_US: The sort order for the search results - relevance, activity, votes, or creation date.
+      zh_Hans: 搜索结果的排序顺序 - 相关性、活动、投票或创建日期。
+    llm_description: The sort order - relevance, activity, votes, or creation.
+    form: llm
+  - name: order
+    type: string
+    required: true
+    label:
+      en_US: Sort direction
+      zh_Hans: 排序方向
+    human_description:
+      en_US: The direction to sort - ascending or descending.
+      zh_Hans: 排序方向 - 升序或降序。
+    llm_description: asc for ascending, desc for descending.
+    form: llm
+  - name: site
+    type: string
+    required: true
+    label:
+      en_US: Stack Exchange site
+      zh_Hans: Stack Exchange 站点
+    human_description:
+      en_US: The Stack Exchange site to search, e.g. stackoverflow, unix, etc.
+      zh_Hans: 要搜索的Stack Exchange站点,例如stackoverflow、unix等。
+    llm_description: The Stack Exchange site identifier.
+    options:
+      - value: stackoverflow
+        label:
+          en_US: stackoverflow
+      - value: serverfault
+        label:
+          en_US: serverfault
+      - value: superuser
+        label:
+          en_US: superuser
+      - value: askubuntu
+        label:
+          en_US: askubuntu
+      - value: unix
+        label:
+          en_US: unix
+      - value: cs
+        label:
+          en_US: cs
+      - value: softwareengineering
+        label:
+          en_US: softwareengineering
+      - value: codegolf
+        label:
+          en_US: codegolf
+      - value: codereview
+        label:
+          en_US: codereview
+      - value: cstheory
+        label:
+          en_US: cstheory
+      - value: security
+        label:
+          en_US: security
+      - value: cryptography
+        label:
+          en_US: cryptography
+      - value: reverseengineering
+        label:
+          en_US: reverseengineering
+      - value: datascience
+        label:
+          en_US: datascience
+      - value: devops
+        label:
+          en_US: devops
+      - value: ux
+        label:
+          en_US: ux
+      - value: dba
+        label:
+          en_US: dba
+      - value: gis
+        label:
+          en_US: gis
+      - value: webmasters
+        label:
+          en_US: webmasters
+      - value: arduino
+        label:
+          en_US: arduino
+      - value: raspberrypi
+        label:
+          en_US: raspberrypi
+      - value: networkengineering
+        label:
+          en_US: networkengineering
+      - value: iot
+        label:
+          en_US: iot
+      - value: tor
+        label:
+          en_US: tor
+      - value: sqa
+        label:
+          en_US: sqa
+      - value: mathoverflow
+        label:
+          en_US: mathoverflow
+      - value: math
+        label:
+          en_US: math
+      - value: mathematica
+        label:
+          en_US: mathematica
+      - value: dsp
+        label:
+          en_US: dsp
+      - value: gamedev
+        label:
+          en_US: gamedev
+      - value: robotics
+        label:
+          en_US: robotics
+      - value: genai
+        label:
+          en_US: genai
+      - value: computergraphics
+        label:
+          en_US: computergraphics
+    form: form
+  - name: tagged
+    type: string
+    required: false
+    label:
+      en_US: Include tags
+      zh_Hans: 包含标签
+    human_description:
+      en_US: A semicolon-separated list of tags that questions must have.
+      zh_Hans: 问题必须具有的标签的分号分隔列表。
+    llm_description: Semicolon-separated tags to include. Leave blank if not needed.
+    form: llm
+  - name: nottagged
+    type: string
+    required: false
+    label:
+      en_US: Exclude tags
+      zh_Hans: 排除标签
+    human_description:
+      en_US: A semicolon-separated list of tags to exclude from the search.
+      zh_Hans: 从搜索中排除的标签的分号分隔列表。
+    llm_description: Semicolon-separated tags to exclude. Leave blank if not needed.
+    form: llm
+  - name: accepted
+    type: boolean
+    required: true
+    label:
+      en_US: Has accepted answer
+      zh_Hans: 有已接受的答案
+    human_description:
+      en_US: Whether to limit to only questions that have an accepted answer.
+      zh_Hans: 是否限制为只有已接受答案的问题。
+    llm_description: true to limit to only questions with accepted answers, false otherwise.
+    form: llm
+  - name: pagesize
+    type: number
+    required: true
+    label:
+      en_US: Results per page
+      zh_Hans: 每页结果数
+    human_description:
+      en_US: The number of results to return per page.
+      zh_Hans: 每页返回的结果数。
+    llm_description: The number of results per page.
+    form: llm