From e2b084514deca114a72c28c2214afd42180ce510 Mon Sep 17 00:00:00 2001 From: Bently Date: Thu, 17 Oct 2024 12:09:12 +0100 Subject: [PATCH 01/13] add jina fact checker block --- autogpt_platform/backend/.env.example | 3 + .../backend/backend/blocks/search.py | 62 ++++++++++++++++++- .../backend/backend/util/settings.py | 2 + 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/autogpt_platform/backend/.env.example b/autogpt_platform/backend/.env.example index 0cb4d7abd723..eb5680b6252a 100644 --- a/autogpt_platform/backend/.env.example +++ b/autogpt_platform/backend/.env.example @@ -95,6 +95,9 @@ REPLICATE_API_KEY= # Ideogram IDEOGRAM_API_KEY= +# Jina +JINA_API_KEY= + # Logging Configuration LOG_LEVEL=INFO ENABLE_CLOUD_LOGGING=false diff --git a/autogpt_platform/backend/backend/blocks/search.py b/autogpt_platform/backend/backend/blocks/search.py index ecd63e2ee658..5128f7947703 100644 --- a/autogpt_platform/backend/backend/blocks/search.py +++ b/autogpt_platform/backend/backend/blocks/search.py @@ -1,4 +1,4 @@ -from typing import Any +from typing import Any, Dict from urllib.parse import quote import requests @@ -9,8 +9,8 @@ class GetRequest: @classmethod - def get_request(cls, url: str, json=False) -> Any: - response = requests.get(url) + def get_request(cls, url: str, json=False, headers: Dict[str, str] = None) -> Any: + response = requests.get(url, headers=headers) response.raise_for_status() return response.json() if json else response.text @@ -163,3 +163,59 @@ def run(self, input_data: Input, **kwargs) -> BlockOutput: yield "condition", weather_data["weather"][0]["description"] else: raise RuntimeError(f"Expected keys not found in response: {weather_data}") + + +class FactCheckerBlock(Block, GetRequest): + class Input(BlockSchema): + statement: str + api_key: BlockSecret = SecretField(key="jina_api_key") + + class Output(BlockSchema): + factuality: float + result: bool + reason: str + error: str + + def __init__(self): + super().__init__( + id="a1b2c3d4-5e6f-7g8h-9i0j-k1l2m3n4o5p6", + description="This block checks the factuality of a given statement using Jina AI's Grounding API.", + categories={BlockCategory.SEARCH}, + input_schema=FactCheckerBlock.Input, + output_schema=FactCheckerBlock.Output, + test_input={"statement": "Jina AI was founded in 2020 in Berlin."}, + test_output=[ + ("factuality", 0.95), + ("result", True), + ("reason", "The statement is supported by multiple sources."), + ], + test_mock={ + "get_request": lambda url, json, headers: { + "data": { + "factuality": 0.95, + "result": True, + "reason": "The statement is supported by multiple sources.", + } + } + }, + ) + + def run(self, input_data: Input, **kwargs) -> BlockOutput: + api_key = input_data.api_key.get_secret_value() + encoded_statement = quote(input_data.statement) + url = f"https://g.jina.ai/{encoded_statement}" + + headers = { + "Accept": "application/json", + "Authorization": f"Bearer {api_key}" + } + + response = self.get_request(url, json=True, headers=headers) + + if "data" in response: + data = response["data"] + yield "factuality", data["factuality"] + yield "result", data["result"] + yield "reason", data["reason"] + else: + raise RuntimeError(f"Expected 'data' key not found in response: {response}") diff --git a/autogpt_platform/backend/backend/util/settings.py b/autogpt_platform/backend/backend/util/settings.py index 6e552fadb83d..2a9c8c5dd5b8 100644 --- a/autogpt_platform/backend/backend/util/settings.py +++ b/autogpt_platform/backend/backend/util/settings.py @@ -256,6 +256,8 @@ class Secrets(UpdateTrackingModel["Secrets"], BaseSettings): unreal_speech_api_key: str = Field(default="", description="Unreal Speech API Key") ideogram_api_key: str = Field(default="", description="Ideogram API Key") + jina_api_key: str = Field(default="", description="Jina API Key") + # Add more secret fields as needed model_config = SettingsConfigDict( From c3720bf57e9c59b3da2fe9e1186feb68f9380476 Mon Sep 17 00:00:00 2001 From: Bently Date: Fri, 18 Oct 2024 16:39:00 +0100 Subject: [PATCH 02/13] add api key input for all jina related blocks --- .../backend/backend/blocks/search.py | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/autogpt_platform/backend/backend/blocks/search.py b/autogpt_platform/backend/backend/blocks/search.py index 5128f7947703..b7801db2f88d 100644 --- a/autogpt_platform/backend/backend/blocks/search.py +++ b/autogpt_platform/backend/backend/blocks/search.py @@ -47,6 +47,7 @@ def run(self, input_data: Input, **kwargs) -> BlockOutput: class SearchTheWebBlock(Block, GetRequest): class Input(BlockSchema): query: str # The search query + api_key: BlockSecret = SecretField(key="jina_api_key") class Output(BlockSchema): results: str # The search results including content from top 5 URLs @@ -59,9 +60,9 @@ def __init__(self): categories={BlockCategory.SEARCH}, input_schema=SearchTheWebBlock.Input, output_schema=SearchTheWebBlock.Output, - test_input={"query": "Artificial Intelligence"}, + test_input={"query": "Artificial Intelligence", "api_key": "YOUR_API_KEY"}, test_output=("results", "search content"), - test_mock={"get_request": lambda url, json: "search content"}, + test_mock={"get_request": lambda url, json, headers: "search content"}, ) def run(self, input_data: Input, **kwargs) -> BlockOutput: @@ -71,8 +72,13 @@ def run(self, input_data: Input, **kwargs) -> BlockOutput: # Prepend the Jina Search URL to the encoded query jina_search_url = f"https://s.jina.ai/{encoded_query}" + # Prepare headers with API key + headers = { + "Authorization": f"Bearer {input_data.api_key.get_secret_value()}" + } + # Make the request to Jina Search - response = self.get_request(jina_search_url, json=False) + response = self.get_request(jina_search_url, json=False, headers=headers) # Output the search results yield "results", response @@ -81,6 +87,7 @@ def run(self, input_data: Input, **kwargs) -> BlockOutput: class ExtractWebsiteContentBlock(Block, GetRequest): class Input(BlockSchema): url: str # The URL to scrape + api_key: BlockSecret = SecretField(key="jina_api_key") raw_content: bool = SchemaField( default=False, title="Raw Content", @@ -99,9 +106,9 @@ def __init__(self): categories={BlockCategory.SEARCH}, input_schema=ExtractWebsiteContentBlock.Input, output_schema=ExtractWebsiteContentBlock.Output, - test_input={"url": "https://en.wikipedia.org/wiki/Artificial_intelligence"}, + test_input={"url": "https://en.wikipedia.org/wiki/Artificial_intelligence", "api_key": "YOUR_API_KEY"}, test_output=("content", "scraped content"), - test_mock={"get_request": lambda url, json: "scraped content"}, + test_mock={"get_request": lambda url, json, headers: "scraped content"}, ) def run(self, input_data: Input, **kwargs) -> BlockOutput: @@ -110,7 +117,12 @@ def run(self, input_data: Input, **kwargs) -> BlockOutput: else: url = f"https://r.jina.ai/{input_data.url}" - content = self.get_request(url, json=False) + # Prepare headers with API key + headers = { + "Authorization": f"Bearer {input_data.api_key.get_secret_value()}" + } + + content = self.get_request(url, json=False, headers=headers) yield "content", content From 5d0f01b46b031007281b92ef7b0d0c580dabb1ec Mon Sep 17 00:00:00 2001 From: Bently Date: Fri, 18 Oct 2024 16:48:57 +0100 Subject: [PATCH 03/13] Revert "add api key input for all jina related blocks" This reverts commit c3720bf57e9c59b3da2fe9e1186feb68f9380476. --- .../backend/backend/blocks/search.py | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/autogpt_platform/backend/backend/blocks/search.py b/autogpt_platform/backend/backend/blocks/search.py index b7801db2f88d..5128f7947703 100644 --- a/autogpt_platform/backend/backend/blocks/search.py +++ b/autogpt_platform/backend/backend/blocks/search.py @@ -47,7 +47,6 @@ def run(self, input_data: Input, **kwargs) -> BlockOutput: class SearchTheWebBlock(Block, GetRequest): class Input(BlockSchema): query: str # The search query - api_key: BlockSecret = SecretField(key="jina_api_key") class Output(BlockSchema): results: str # The search results including content from top 5 URLs @@ -60,9 +59,9 @@ def __init__(self): categories={BlockCategory.SEARCH}, input_schema=SearchTheWebBlock.Input, output_schema=SearchTheWebBlock.Output, - test_input={"query": "Artificial Intelligence", "api_key": "YOUR_API_KEY"}, + test_input={"query": "Artificial Intelligence"}, test_output=("results", "search content"), - test_mock={"get_request": lambda url, json, headers: "search content"}, + test_mock={"get_request": lambda url, json: "search content"}, ) def run(self, input_data: Input, **kwargs) -> BlockOutput: @@ -72,13 +71,8 @@ def run(self, input_data: Input, **kwargs) -> BlockOutput: # Prepend the Jina Search URL to the encoded query jina_search_url = f"https://s.jina.ai/{encoded_query}" - # Prepare headers with API key - headers = { - "Authorization": f"Bearer {input_data.api_key.get_secret_value()}" - } - # Make the request to Jina Search - response = self.get_request(jina_search_url, json=False, headers=headers) + response = self.get_request(jina_search_url, json=False) # Output the search results yield "results", response @@ -87,7 +81,6 @@ def run(self, input_data: Input, **kwargs) -> BlockOutput: class ExtractWebsiteContentBlock(Block, GetRequest): class Input(BlockSchema): url: str # The URL to scrape - api_key: BlockSecret = SecretField(key="jina_api_key") raw_content: bool = SchemaField( default=False, title="Raw Content", @@ -106,9 +99,9 @@ def __init__(self): categories={BlockCategory.SEARCH}, input_schema=ExtractWebsiteContentBlock.Input, output_schema=ExtractWebsiteContentBlock.Output, - test_input={"url": "https://en.wikipedia.org/wiki/Artificial_intelligence", "api_key": "YOUR_API_KEY"}, + test_input={"url": "https://en.wikipedia.org/wiki/Artificial_intelligence"}, test_output=("content", "scraped content"), - test_mock={"get_request": lambda url, json, headers: "scraped content"}, + test_mock={"get_request": lambda url, json: "scraped content"}, ) def run(self, input_data: Input, **kwargs) -> BlockOutput: @@ -117,12 +110,7 @@ def run(self, input_data: Input, **kwargs) -> BlockOutput: else: url = f"https://r.jina.ai/{input_data.url}" - # Prepare headers with API key - headers = { - "Authorization": f"Bearer {input_data.api_key.get_secret_value()}" - } - - content = self.get_request(url, json=False, headers=headers) + content = self.get_request(url, json=False) yield "content", content From f1ea47f2c9ffa491ad755c9607f1de6347e9e457 Mon Sep 17 00:00:00 2001 From: Bently Date: Wed, 23 Oct 2024 14:07:34 +0100 Subject: [PATCH 04/13] update to add descriptions for input and outputs --- autogpt_platform/backend/backend/blocks/search.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/autogpt_platform/backend/backend/blocks/search.py b/autogpt_platform/backend/backend/blocks/search.py index 5128f7947703..a497987c37d1 100644 --- a/autogpt_platform/backend/backend/blocks/search.py +++ b/autogpt_platform/backend/backend/blocks/search.py @@ -167,14 +167,14 @@ def run(self, input_data: Input, **kwargs) -> BlockOutput: class FactCheckerBlock(Block, GetRequest): class Input(BlockSchema): - statement: str + statement: str = SchemaField(description="The statement to check for factuality") api_key: BlockSecret = SecretField(key="jina_api_key") class Output(BlockSchema): - factuality: float - result: bool - reason: str - error: str + factuality: float = SchemaField(description="The factuality score of the statement") + result: bool = SchemaField(description="The result of the factuality check") + reason: str = SchemaField(description="The reason for the factuality result") + error: str = SchemaField(description="Error message if the check fails") def __init__(self): super().__init__( From 62b17b825968eedef38cb214ae62146e846cd29b Mon Sep 17 00:00:00 2001 From: Bently Date: Wed, 23 Oct 2024 14:52:00 +0100 Subject: [PATCH 05/13] use new credentials system for api key --- autogpt_platform/backend/backend/blocks/search.py | 15 ++++++++++----- .../components/integrations/credentials-input.tsx | 3 ++- .../integrations/credentials-provider.tsx | 3 ++- .../frontend/src/lib/autogpt-server-api/types.ts | 2 +- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/autogpt_platform/backend/backend/blocks/search.py b/autogpt_platform/backend/backend/blocks/search.py index a497987c37d1..25f527b1b02d 100644 --- a/autogpt_platform/backend/backend/blocks/search.py +++ b/autogpt_platform/backend/backend/blocks/search.py @@ -4,7 +4,9 @@ import requests from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema -from backend.data.model import BlockSecret, SchemaField, SecretField +from backend.data.model import BlockSecret, SchemaField, SecretField, CredentialsField, CredentialsMetaInput +from typing import Literal +from autogpt_libs.supabase_integration_credentials_store import APIKeyCredentials class GetRequest: @@ -168,7 +170,11 @@ def run(self, input_data: Input, **kwargs) -> BlockOutput: class FactCheckerBlock(Block, GetRequest): class Input(BlockSchema): statement: str = SchemaField(description="The statement to check for factuality") - api_key: BlockSecret = SecretField(key="jina_api_key") + credentials: CredentialsMetaInput[Literal['jina'], Literal['api_key']] = CredentialsField( + provider="jina", + supported_credential_types={"api_key"}, + description="The Jina AI API key for getting around the API rate limit.", + ) class Output(BlockSchema): factuality: float = SchemaField(description="The factuality score of the statement") @@ -200,14 +206,13 @@ def __init__(self): }, ) - def run(self, input_data: Input, **kwargs) -> BlockOutput: - api_key = input_data.api_key.get_secret_value() + def run(self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs) -> BlockOutput: encoded_statement = quote(input_data.statement) url = f"https://g.jina.ai/{encoded_statement}" headers = { "Accept": "application/json", - "Authorization": f"Bearer {api_key}" + "Authorization": credentials.bearer() } response = self.get_request(url, json=True, headers=headers) diff --git a/autogpt_platform/frontend/src/components/integrations/credentials-input.tsx b/autogpt_platform/frontend/src/components/integrations/credentials-input.tsx index 811e37d809bd..0189086b40d0 100644 --- a/autogpt_platform/frontend/src/components/integrations/credentials-input.tsx +++ b/autogpt_platform/frontend/src/components/integrations/credentials-input.tsx @@ -7,7 +7,7 @@ import useCredentials from "@/hooks/useCredentials"; import { zodResolver } from "@hookform/resolvers/zod"; import AutoGPTServerAPI from "@/lib/autogpt-server-api"; import { NotionLogoIcon } from "@radix-ui/react-icons"; -import { FaGithub, FaGoogle } from "react-icons/fa"; +import { FaGithub, FaGoogle, FaKey } from "react-icons/fa"; import { FC, useMemo, useState } from "react"; import { CredentialsMetaInput } from "@/lib/autogpt-server-api/types"; import { IconKey, IconKeyPlus, IconUserPlus } from "@/components/ui/icons"; @@ -41,6 +41,7 @@ export const providerIcons: Record> = { github: FaGithub, google: FaGoogle, notion: NotionLogoIcon, + jina: FaKey, // Use a generic icon for now as there is no specific icon for Jina AI }; // --8<-- [end:ProviderIconsEmbed] diff --git a/autogpt_platform/frontend/src/components/integrations/credentials-provider.tsx b/autogpt_platform/frontend/src/components/integrations/credentials-provider.tsx index ffb62d793e9b..c3d7ab749766 100644 --- a/autogpt_platform/frontend/src/components/integrations/credentials-provider.tsx +++ b/autogpt_platform/frontend/src/components/integrations/credentials-provider.tsx @@ -12,7 +12,7 @@ import { } from "react"; // --8<-- [start:CredentialsProviderNames] -const CREDENTIALS_PROVIDER_NAMES = ["github", "google", "notion"] as const; +const CREDENTIALS_PROVIDER_NAMES = ["github", "google", "notion", "jina"] as const; export type CredentialsProviderName = (typeof CREDENTIALS_PROVIDER_NAMES)[number]; @@ -21,6 +21,7 @@ const providerDisplayNames: Record = { github: "GitHub", google: "Google", notion: "Notion", + jina: "Jina AI", }; // --8<-- [end:CredentialsProviderNames] diff --git a/autogpt_platform/frontend/src/lib/autogpt-server-api/types.ts b/autogpt_platform/frontend/src/lib/autogpt-server-api/types.ts index 97a6bf4e5046..535fd8ffec45 100644 --- a/autogpt_platform/frontend/src/lib/autogpt-server-api/types.ts +++ b/autogpt_platform/frontend/src/lib/autogpt-server-api/types.ts @@ -96,7 +96,7 @@ export type CredentialsType = "api_key" | "oauth2"; // --8<-- [start:BlockIOCredentialsSubSchema] export type BlockIOCredentialsSubSchema = BlockIOSubSchemaMeta & { - credentials_provider: "github" | "google" | "notion"; + credentials_provider: "github" | "google" | "notion" | "jina"; credentials_scopes?: string[]; credentials_types: Array; }; From a8dabe5ebb6a319ee9cba098d9ce22f8a554bb99 Mon Sep 17 00:00:00 2001 From: Bently Date: Wed, 23 Oct 2024 14:58:29 +0100 Subject: [PATCH 06/13] prettier + format --- .../backend/backend/blocks/search.py | 46 +++++++++++-------- .../integrations/credentials-provider.tsx | 7 ++- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/autogpt_platform/backend/backend/blocks/search.py b/autogpt_platform/backend/backend/blocks/search.py index 25f527b1b02d..b27f2a62e4bc 100644 --- a/autogpt_platform/backend/backend/blocks/search.py +++ b/autogpt_platform/backend/backend/blocks/search.py @@ -1,12 +1,17 @@ -from typing import Any, Dict +from typing import Any, Dict, Literal from urllib.parse import quote import requests +from autogpt_libs.supabase_integration_credentials_store import APIKeyCredentials from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema -from backend.data.model import BlockSecret, SchemaField, SecretField, CredentialsField, CredentialsMetaInput -from typing import Literal -from autogpt_libs.supabase_integration_credentials_store import APIKeyCredentials +from backend.data.model import ( + BlockSecret, + CredentialsField, + CredentialsMetaInput, + SchemaField, + SecretField, +) class GetRequest: @@ -169,15 +174,21 @@ def run(self, input_data: Input, **kwargs) -> BlockOutput: class FactCheckerBlock(Block, GetRequest): class Input(BlockSchema): - statement: str = SchemaField(description="The statement to check for factuality") - credentials: CredentialsMetaInput[Literal['jina'], Literal['api_key']] = CredentialsField( - provider="jina", - supported_credential_types={"api_key"}, - description="The Jina AI API key for getting around the API rate limit.", + statement: str = SchemaField( + description="The statement to check for factuality" + ) + credentials: CredentialsMetaInput[Literal["jina"], Literal["api_key"]] = ( + CredentialsField( + provider="jina", + supported_credential_types={"api_key"}, + description="The Jina AI API key for getting around the API rate limit.", + ) ) class Output(BlockSchema): - factuality: float = SchemaField(description="The factuality score of the statement") + factuality: float = SchemaField( + description="The factuality score of the statement" + ) result: bool = SchemaField(description="The result of the factuality check") reason: str = SchemaField(description="The reason for the factuality result") error: str = SchemaField(description="Error message if the check fails") @@ -206,17 +217,16 @@ def __init__(self): }, ) - def run(self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs) -> BlockOutput: + def run( + self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs + ) -> BlockOutput: encoded_statement = quote(input_data.statement) url = f"https://g.jina.ai/{encoded_statement}" - - headers = { - "Accept": "application/json", - "Authorization": credentials.bearer() - } - + + headers = {"Accept": "application/json", "Authorization": credentials.bearer()} + response = self.get_request(url, json=True, headers=headers) - + if "data" in response: data = response["data"] yield "factuality", data["factuality"] diff --git a/autogpt_platform/frontend/src/components/integrations/credentials-provider.tsx b/autogpt_platform/frontend/src/components/integrations/credentials-provider.tsx index c3d7ab749766..c2a0ee28934a 100644 --- a/autogpt_platform/frontend/src/components/integrations/credentials-provider.tsx +++ b/autogpt_platform/frontend/src/components/integrations/credentials-provider.tsx @@ -12,7 +12,12 @@ import { } from "react"; // --8<-- [start:CredentialsProviderNames] -const CREDENTIALS_PROVIDER_NAMES = ["github", "google", "notion", "jina"] as const; +const CREDENTIALS_PROVIDER_NAMES = [ + "github", + "google", + "notion", + "jina", +] as const; export type CredentialsProviderName = (typeof CREDENTIALS_PROVIDER_NAMES)[number]; From aa836a9943d7b4dafe1fcb32c79a9c8bf594d533 Mon Sep 17 00:00:00 2001 From: Bently Date: Wed, 23 Oct 2024 15:16:47 +0100 Subject: [PATCH 07/13] fix for linter --- autogpt_platform/backend/backend/blocks/search.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/autogpt_platform/backend/backend/blocks/search.py b/autogpt_platform/backend/backend/blocks/search.py index b27f2a62e4bc..ce4a48869820 100644 --- a/autogpt_platform/backend/backend/blocks/search.py +++ b/autogpt_platform/backend/backend/blocks/search.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, Literal +from typing import Any, Dict, Literal, Optional from urllib.parse import quote import requests @@ -16,7 +16,10 @@ class GetRequest: @classmethod - def get_request(cls, url: str, json=False, headers: Dict[str, str] = None) -> Any: + def get_request( + cls, url: str, json=False, headers: Optional[Dict[str, str]] = None + ) -> Any: + headers = headers or {} response = requests.get(url, headers=headers) response.raise_for_status() return response.json() if json else response.text From 2e6ba8f03e6a802c9a27610f83616f341972a449 Mon Sep 17 00:00:00 2001 From: Bently Date: Wed, 23 Oct 2024 16:44:52 +0100 Subject: [PATCH 08/13] update for tests --- .../backend/backend/blocks/search.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/autogpt_platform/backend/backend/blocks/search.py b/autogpt_platform/backend/backend/blocks/search.py index ce4a48869820..3c93b139d693 100644 --- a/autogpt_platform/backend/backend/blocks/search.py +++ b/autogpt_platform/backend/backend/blocks/search.py @@ -203,7 +203,15 @@ def __init__(self): categories={BlockCategory.SEARCH}, input_schema=FactCheckerBlock.Input, output_schema=FactCheckerBlock.Output, - test_input={"statement": "Jina AI was founded in 2020 in Berlin."}, + test_input={ + "statement": "Jina AI was founded in 2020 in Berlin.", + "credentials": { + "id": "test-credentials-id", + "provider": "jina", + "type": "api_key", + "title": "Mock Jina API key", + }, + }, test_output=[ ("factuality", 0.95), ("result", True), @@ -218,6 +226,13 @@ def __init__(self): } } }, + test_credentials=APIKeyCredentials( + id="test-credentials-id", + provider="jina", + api_key="mock-api-key", + title="Mock Jina API key", + expires_at=None, + ), ) def run( From 4968a0187c12c229a8cee7745341533ff1355332 Mon Sep 17 00:00:00 2001 From: Bentlybro Date: Tue, 26 Nov 2024 11:10:27 +0000 Subject: [PATCH 09/13] Move fact checker to jina folder + update to new auth --- autogpt_platform/backend/.env.example | 2 - .../backend/blocks/jina/fact_checker.py | 58 ++++++++++++++ .../backend/backend/blocks/search.py | 78 ------------------- .../backend/backend/util/settings.py | 2 - 4 files changed, 58 insertions(+), 82 deletions(-) create mode 100644 autogpt_platform/backend/backend/blocks/jina/fact_checker.py diff --git a/autogpt_platform/backend/.env.example b/autogpt_platform/backend/.env.example index a79301a4e79b..db8d95a1d6d5 100644 --- a/autogpt_platform/backend/.env.example +++ b/autogpt_platform/backend/.env.example @@ -106,8 +106,6 @@ REPLICATE_API_KEY= # Ideogram IDEOGRAM_API_KEY= -# Jina -JINA_API_KEY= # Logging Configuration LOG_LEVEL=INFO diff --git a/autogpt_platform/backend/backend/blocks/jina/fact_checker.py b/autogpt_platform/backend/backend/blocks/jina/fact_checker.py new file mode 100644 index 000000000000..65086c669811 --- /dev/null +++ b/autogpt_platform/backend/backend/blocks/jina/fact_checker.py @@ -0,0 +1,58 @@ +import requests +from urllib.parse import quote + +from backend.blocks.jina._auth import ( + JinaCredentials, + JinaCredentialsField, + JinaCredentialsInput, +) +from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema +from backend.data.model import SchemaField + + +class FactCheckerBlock(Block): + class Input(BlockSchema): + statement: str = SchemaField( + description="The statement to check for factuality" + ) + credentials: JinaCredentialsInput = JinaCredentialsField() + + class Output(BlockSchema): + factuality: float = SchemaField( + description="The factuality score of the statement" + ) + result: bool = SchemaField(description="The result of the factuality check") + reason: str = SchemaField(description="The reason for the factuality result") + error: str = SchemaField(description="Error message if the check fails") + + def __init__(self): + super().__init__( + id="a1b2c3d4-5e6f-7g8h-9i0j-k1l2m3n4o5p6", + description="This block checks the factuality of a given statement using Jina AI's Grounding API.", + categories={BlockCategory.SEARCH}, + input_schema=FactCheckerBlock.Input, + output_schema=FactCheckerBlock.Output, + ) + + def run( + self, input_data: Input, *, credentials: JinaCredentials, **kwargs + ) -> BlockOutput: + encoded_statement = quote(input_data.statement) + url = f"https://g.jina.ai/{encoded_statement}" + + headers = { + "Accept": "application/json", + "Authorization": f"Bearer {credentials.api_key.get_secret_value()}", + } + + response = requests.get(url, headers=headers) + response.raise_for_status() + data = response.json() + + if "data" in data: + data = data["data"] + yield "factuality", data["factuality"] + yield "result", data["result"] + yield "reason", data["reason"] + else: + raise RuntimeError(f"Expected 'data' key not found in response: {data}") diff --git a/autogpt_platform/backend/backend/blocks/search.py b/autogpt_platform/backend/backend/blocks/search.py index 14ff2dc4d413..16f7e0b32f27 100644 --- a/autogpt_platform/backend/backend/blocks/search.py +++ b/autogpt_platform/backend/backend/blocks/search.py @@ -164,81 +164,3 @@ def run( else: raise RuntimeError(f"Expected keys not found in response: {weather_data}") - -class FactCheckerBlock(Block, GetRequest): - class Input(BlockSchema): - statement: str = SchemaField( - description="The statement to check for factuality" - ) - credentials: CredentialsMetaInput[Literal["jina"], Literal["api_key"]] = ( - CredentialsField( - provider="jina", - supported_credential_types={"api_key"}, - description="The Jina AI API key for getting around the API rate limit.", - ) - ) - - class Output(BlockSchema): - factuality: float = SchemaField( - description="The factuality score of the statement" - ) - result: bool = SchemaField(description="The result of the factuality check") - reason: str = SchemaField(description="The reason for the factuality result") - error: str = SchemaField(description="Error message if the check fails") - - def __init__(self): - super().__init__( - id="a1b2c3d4-5e6f-7g8h-9i0j-k1l2m3n4o5p6", - description="This block checks the factuality of a given statement using Jina AI's Grounding API.", - categories={BlockCategory.SEARCH}, - input_schema=FactCheckerBlock.Input, - output_schema=FactCheckerBlock.Output, - test_input={ - "statement": "Jina AI was founded in 2020 in Berlin.", - "credentials": { - "id": "test-credentials-id", - "provider": "jina", - "type": "api_key", - "title": "Mock Jina API key", - }, - }, - test_output=[ - ("factuality", 0.95), - ("result", True), - ("reason", "The statement is supported by multiple sources."), - ], - test_mock={ - "get_request": lambda url, json, headers: { - "data": { - "factuality": 0.95, - "result": True, - "reason": "The statement is supported by multiple sources.", - } - } - }, - test_credentials=APIKeyCredentials( - id="test-credentials-id", - provider="jina", - api_key="mock-api-key", - title="Mock Jina API key", - expires_at=None, - ), - ) - - def run( - self, input_data: Input, *, credentials: APIKeyCredentials, **kwargs - ) -> BlockOutput: - encoded_statement = quote(input_data.statement) - url = f"https://g.jina.ai/{encoded_statement}" - - headers = {"Accept": "application/json", "Authorization": credentials.bearer()} - - response = self.get_request(url, json=True, headers=headers) - - if "data" in response: - data = response["data"] - yield "factuality", data["factuality"] - yield "result", data["result"] - yield "reason", data["reason"] - else: - raise RuntimeError(f"Expected 'data' key not found in response: {response}") diff --git a/autogpt_platform/backend/backend/util/settings.py b/autogpt_platform/backend/backend/util/settings.py index 22d4b8cd241c..34ca9336d45d 100644 --- a/autogpt_platform/backend/backend/util/settings.py +++ b/autogpt_platform/backend/backend/util/settings.py @@ -290,8 +290,6 @@ class Secrets(UpdateTrackingModel["Secrets"], BaseSettings): jina_api_key: str = Field(default="", description="Jina API Key") unreal_speech_api_key: str = Field(default="", description="Unreal Speech API Key") - jina_api_key: str = Field(default="", description="Jina API Key") - # Add more secret fields as needed model_config = SettingsConfigDict( From 3198b94f03d2c5e33acad3b1df3e3b6173bf68af Mon Sep 17 00:00:00 2001 From: Bentlybro Date: Tue, 26 Nov 2024 11:11:02 +0000 Subject: [PATCH 10/13] Update search.py --- autogpt_platform/backend/backend/blocks/search.py | 1 - 1 file changed, 1 deletion(-) diff --git a/autogpt_platform/backend/backend/blocks/search.py b/autogpt_platform/backend/backend/blocks/search.py index 16f7e0b32f27..dffe8b97c872 100644 --- a/autogpt_platform/backend/backend/blocks/search.py +++ b/autogpt_platform/backend/backend/blocks/search.py @@ -163,4 +163,3 @@ def run( yield "condition", weather_data["weather"][0]["description"] else: raise RuntimeError(f"Expected keys not found in response: {weather_data}") - From cb0506a2506722f5937c813ed9a41c1aa2fc195b Mon Sep 17 00:00:00 2001 From: Bentlybro Date: Tue, 26 Nov 2024 11:11:18 +0000 Subject: [PATCH 11/13] Update .env.example --- autogpt_platform/backend/.env.example | 1 - 1 file changed, 1 deletion(-) diff --git a/autogpt_platform/backend/.env.example b/autogpt_platform/backend/.env.example index db8d95a1d6d5..0dd10e838501 100644 --- a/autogpt_platform/backend/.env.example +++ b/autogpt_platform/backend/.env.example @@ -106,7 +106,6 @@ REPLICATE_API_KEY= # Ideogram IDEOGRAM_API_KEY= - # Logging Configuration LOG_LEVEL=INFO ENABLE_CLOUD_LOGGING=false From d12e3fd9b33d4d66593d21495dee8c7a359a79c7 Mon Sep 17 00:00:00 2001 From: Bentlybro Date: Tue, 26 Nov 2024 11:22:46 +0000 Subject: [PATCH 12/13] format --- autogpt_platform/backend/backend/blocks/jina/fact_checker.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/autogpt_platform/backend/backend/blocks/jina/fact_checker.py b/autogpt_platform/backend/backend/blocks/jina/fact_checker.py index 65086c669811..b64f183fc300 100644 --- a/autogpt_platform/backend/backend/blocks/jina/fact_checker.py +++ b/autogpt_platform/backend/backend/blocks/jina/fact_checker.py @@ -1,6 +1,7 @@ -import requests from urllib.parse import quote +import requests + from backend.blocks.jina._auth import ( JinaCredentials, JinaCredentialsField, From 6d30a6aab68398d90a8b295c3faf08cdf9ba0bcb Mon Sep 17 00:00:00 2001 From: Bentlybro Date: Wed, 27 Nov 2024 10:31:52 +0000 Subject: [PATCH 13/13] new UUID --- autogpt_platform/backend/backend/blocks/jina/fact_checker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autogpt_platform/backend/backend/blocks/jina/fact_checker.py b/autogpt_platform/backend/backend/blocks/jina/fact_checker.py index b64f183fc300..c9b8c08d1db8 100644 --- a/autogpt_platform/backend/backend/blocks/jina/fact_checker.py +++ b/autogpt_platform/backend/backend/blocks/jina/fact_checker.py @@ -28,7 +28,7 @@ class Output(BlockSchema): def __init__(self): super().__init__( - id="a1b2c3d4-5e6f-7g8h-9i0j-k1l2m3n4o5p6", + id="d38b6c5e-9968-4271-8423-6cfe60d6e7e6", description="This block checks the factuality of a given statement using Jina AI's Grounding API.", categories={BlockCategory.SEARCH}, input_schema=FactCheckerBlock.Input,