feat: Refactor langflow Components - Consolidate Imports, Remove Unused Components, and Update Astra Assistant Icons (#4460)

* fix lint

* fix lint

* [autofix.ci] apply automated fixes

* 📝 (message_to_data.py): refactor convert_message_to_data method to simplify code and improve readability
🔧 (conftest.py): update imports to organize them alphabetically for better code maintenance
🔧 (test_starter_projects.py): organize imports alphabetically for better code maintenance
🔧 (test_astra_component.py): organize imports alphabetically for better code maintenance
🔧 (test_parse_json_data.py): remove unnecessary whitespace for cleaner code
🔧 (test_chat_input.py): remove unnecessary whitespace for cleaner code
🔧 (test_text_input.py): remove unnecessary whitespace for cleaner code
🔧 (test_output_parser.py): remove unnecessary whitespace for cleaner code
🔧 (test_chat_output.py): remove unnecessary whitespace for cleaner code
🔧 (test_text_output.py): remove unnecessary whitespace for cleaner code
🔧 (test_prompt.py): remove unnecessary whitespace for cleaner code
🔧 (test_basic_prompting.py): remove unnecessary whitespace for cleaner code
🔧 (test_misc.py): remove unnecessary whitespace for cleaner code
🔧 (utils.py): remove unnecessary whitespace for cleaner code
🔧 (test_server_init.py): remove unnecessary whitespace for cleaner code
🔧 (test_endpoints.py): remove unnecessary whitespace for cleaner code
🔧 (test_component_toolkit.py): remove unnecessary whitespace for cleaner code
🔧 (test_agent_component.py): remove unnecessary whitespace for cleaner code
🔧 (test_agent_events.py): remove unnecessary whitespace for cleaner code
🔧 (test_tool_calling_agent.py): remove unnecessary whitespace for cleaner code
🔧 (test_structured_output_component.py): remove unnecessary whitespace for cleaner code
🔧 (test_chatollama_component.py): remove unnecessary whitespace for cleaner code

📝 (test_huggingface.py): Remove unnecessary import statement
📝 (test_create_data_component.py): Remove unnecessary import statement
📝 (test_update_data_component.py): Remove unnecessary import statement
📝 (test_componet_set_functionality.py): Remove unnecessary import statement
📝 (test_component.py): Remove unnecessary import statement
📝 (test_event_manager.py): Remove unnecessary import statement
📝 (test_edge_base.py): Remove unnecessary import statement
📝 (test_state_model.py): Remove unnecessary import statement
📝 (test_base.py): Remove unnecessary import statement
📝 (test_callback_graph.py): Remove unnecessary import statement
📝 (test_cycles.py): Remove unnecessary import statement
📝 (test_graph_state_model.py): Remove unnecessary import statement
📝 (test_runnable_vertices_manager.py): Remove unnecessary import statement
📝 (test_utils.py): Remove unnecessary import statement
📝 (test_graph.py): Remove unnecessary import statement
📝 (test_base_model_from_schema.py): Reorder import statements
📝 (test_memory_chatbot.py): Remove unnecessary import statement
📝 (test_vector_store_rag.py): Remove unnecessary import statement
📝 (test_inputs.py): Reorder import statements
📝 (test_io_schema.py): Remove unnecessary import statement
📝 (test_table_schema.py): Remove unnecessary import statement
📝 (test_schema_message.py): Remove unnecessary import statement
📝 (test_service.py): Reorder import statements
📝 (test_api_key.py): Remove unnecessary import statement
📝 (test_chat_endpoint.py): Remove unnecessary import statement
📝 (test_cli.py): Remove unnecessary import statement

📝 (test_custom_component.py): Add missing import statement in test_custom_component.py
📝 (test_custom_component_with_client.py): Add missing import statement in test_custom_component_with_client.py
📝 (test_data_class.py): Add missing import statement in test_data_class.py
📝 (test_data_components.py): Add missing import statement in test_data_components.py
📝 (test_database.py): Add missing import statement in test_database.py
📝 (test_endpoints.py): Add missing import statement in test_endpoints.py
📝 (test_files.py): Add missing import statement in test_files.py
📝 (test_frontend_nodes.py): Add missing import statement in test_frontend_nodes.py
📝 (test_initial_setup.py): Add missing import statement in test_initial_setup.py
📝 (test_kubernetes_secrets.py): Add missing import statement in test_kubernetes_secrets.py
📝 (test_logger.py): Add missing import statement in test_logger.py
📝 (test_login.py): Add missing import statement in test_login.py
📝 (test_messages.py): Add missing import statement in test_messages.py
📝 (test_messages_endpoints.py): Add missing import statement in test_messages_endpoints.py
📝 (test_schema.py): Add missing import statement in test_schema.py
📝 (test_telemetry.py): Add missing import statement in test_telemetry.py
📝 (test_template.py): Add missing import statement in test_template.py
📝 (test_user.py): Add missing import statement in test_user.py
📝 (test_validate_code.py): Add missing import statement in test_validate_code.py
📝 (test_connection_string_parser.py): Add missing import statement in test_connection_string_parser.py
📝 (test_format_directory_path.py): Add missing import statement in test_format_directory_path.py
📝 (test_rewrite_file_path.py): Add missing import statement in test_rewrite_file_path.py
📝 (test_truncate_long_strings.py): Add missing import statement in test_truncate_long_strings.py
📝 (test_truncate_long_strings_on_objects.py): Add missing import statement in test_truncate_long_strings_on_objects.py

* [autofix.ci] apply automated fixes

* formatting

* Update import paths for MemoryComponent and HuggingFaceEndpointsComponent

* fix tests

* ✨ (decisionFlow.spec.ts): update test selectors to match changes in the application's UI for better test accuracy and reliability

* [autofix.ci] apply automated fixes

* ♻️ (test_output_parser.py): refactor import statements to improve code readability and maintainability

* fix tests

* ✅ (Simple Agent.spec.ts): enable test for "Simple Agent" by removing the skip flag to ensure it runs properly

* [autofix.ci] apply automated fixes

* Remove optional type from 'num_news' field in YahooFinanceSchema

* Refactor JSON formatting for improved readability and maintainability across starter projects.

* adding icon to flows

* [autofix.ci] apply automated fixes

* ✅ (similarity.spec.ts): update test selectors for filtering and connection nodes to match changes in the frontend implementation

* [autofix.ci] apply automated fixes

* removing init uncessary

* ⬆️ (pyproject.toml): upgrade crewai dependency to version 0.76.9 to include the latest features and bug fixes

* ✅ (Simple Agent.spec.ts): update test assertion to check if the count of "print(" is greater than or equal to 1 for better test coverage.

* [autofix.ci] apply automated fixes

* proposed changes

* [autofix.ci] apply automated fixes

* add zep icon

* [autofix.ci] apply automated fixes

* 🔧 (model.py): remove unused import and method 'cast_vector_store' from LCVectorStoreComponent
🔧 (openai_tools.py): remove beta flag from OpenAIToolsAgentComponent
🔧 (tool_calling.py): remove beta flag from ToolCallingAgentComponent
🔧 (Vector Store RAG.json): remove 'cast_vector_store' method from starter projects
🔧 (styleUtils.ts): add missing icon 'WolframAlphaAPI' to nodeIconsLucide in styleUtils module

* add langwatch and mem0 icon

* change mem0 name to mem0ai

* ✨ (filterSidebar.spec.ts): update test to use first() method to select the first element with the specified test ID
♻️ (filterSidebar.spec.ts): remove unnecessary code related to checking the checkbox state in the test
🔧 (generalBugs-shard-2.spec.ts): update test to select the correct element with the test ID "dataWebhook" instead of "dataWebhook Input"

* ♻️ (test_vector_store_rag.py): remove redundant code setting "vector_store" value in both ingestion_graph and rag_graph functions to improve code readability and maintainability

* [autofix.ci] apply automated fixes

* updating json test

* [autofix.ci] apply automated fixes

* ⬆️ (pyproject.toml): downgrade crewai dependency version from 0.76.9 to 0.74.2 to resolve compatibility issues

* 🐛 (generalBugs-shard-5.spec.ts): fix typo in test case for component name
🐛 (generalBugs-shard-9.spec.ts): update endX calculation to move 600 pixels to the right instead of 300
🐛 (generalBugs-shard-9.spec.ts): fix typo in test case for component name and update test steps to click "fit_view" button twice

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
This commit is contained in:
Cristhian Zanforlin Lousa 2024-11-11 16:30:05 -03:00 • committed by GitHub
commit 29e484465c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
182 changed files with 7279 additions and 516 deletions

View file

@ -1,6 +1,6 @@
from abc import abstractmethod
from functools import wraps
from typing import TYPE_CHECKING, cast
from typing import TYPE_CHECKING
from loguru import logger
@ -64,11 +64,6 @@ class LCVectorStoreComponent(Component):
name="search_results",
method="search_documents",
),
Output(
display_name="Vector Store",
name="vector_store",
method="cast_vector_store",
),
]
def _validate_outputs(self) -> None:
@ -120,9 +115,6 @@ class LCVectorStoreComponent(Component):
self.status = data
return data
def cast_vector_store(self) -> VectorStore:
return cast(VectorStore, self.build_vector_store())
def build_base_retriever(self) -> Retriever: # type: ignore[type-var]
"""Builds the BaseRetriever object."""
if self._cached_vector_store is not None:

View file

@ -0,0 +1,19 @@
from .add_content_to_page import AddContentToPage
from .create_page import NotionPageCreator
from .list_database_properties import NotionDatabaseProperties
from .list_pages import NotionListPages
from .list_users import NotionUserList
from .page_content_viewer import NotionPageContent
from .search import NotionSearch
from .update_page_property import NotionPageUpdate
__all__ = [
"AddContentToPage",
"NotionPageCreator",
"NotionDatabaseProperties",
"NotionListPages",
"NotionUserList",
"NotionPageContent",
"NotionSearch",
"NotionPageUpdate",
]

View file

@ -1,42 +0,0 @@
from . import (
agents,
chains,
custom_component,
documentloaders,
embeddings,
helpers,
inputs,
link_extractors,
memories,
models,
outputs,
prompts,
prototypes,
retrievers,
textsplitters,
toolkits,
tools,
vectorstores,
)
__all__ = [
"agents",
"chains",
"documentloaders",
"embeddings",
"helpers",
"inputs",
"link_extractors",
"custom_component",
"memories",
"models",
"output_parsers",
"outputs",
"prompts",
"prototypes",
"retrievers",
"textsplitters",
"toolkits",
"tools",
"vectorstores",
]

View file

@ -1,29 +1,3 @@
from .crewai import CrewAIAgentComponent
from .csv import CSVAgentComponent
from .hierarchical_crew import HierarchicalCrewComponent
from .json import JsonAgentComponent
from .openai_tools import OpenAIToolsAgentComponent
from .openapi import OpenAPIAgentComponent
from .sequential_crew import SequentialCrewComponent
from .sequential_task import SequentialTaskAgentComponent
from .sql import SQLAgentComponent
from .tool_calling import ToolCallingAgentComponent
from .vector_store import VectorStoreAgentComponent
from .vector_store_router import VectorStoreRouterAgentComponent
from .xml import XMLAgentComponent
from .agent import AgentComponent
__all__ = [
"CSVAgentComponent",
"CrewAIAgentComponent",
"HierarchicalCrewComponent",
"JsonAgentComponent",
"OpenAIToolsAgentComponent",
"OpenAPIAgentComponent",
"SQLAgentComponent",
"SequentialCrewComponent",
"SequentialTaskAgentComponent",
"ToolCallingAgentComponent",
"VectorStoreAgentComponent",
"VectorStoreRouterAgentComponent",
"XMLAgentComponent",
]
__all__ = ["AgentComponent"]

View file

@ -2,9 +2,9 @@ from langchain_core.tools import StructuredTool
from langflow.base.agents.agent import LCToolsAgentComponent
from langflow.base.models.model_input_constants import ALL_PROVIDER_FIELDS, MODEL_PROVIDERS_DICT
from langflow.components.agents.tool_calling import ToolCallingAgentComponent
from langflow.components.helpers import CurrentDateComponent
from langflow.components.helpers.memory import MemoryComponent
from langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent
from langflow.components.memories.memory import MemoryComponent
from langflow.io import BoolInput, DropdownInput, MultilineInput, Output
from langflow.schema.dotdict import dotdict
from langflow.schema.message import Message

View file

@ -1,32 +0,0 @@
from langchain.agents import AgentExecutor, create_vectorstore_agent
from langchain.agents.agent_toolkits.vectorstore.toolkit import VectorStoreToolkit
from langflow.base.agents.agent import LCAgentComponent
from langflow.inputs import HandleInput
class VectorStoreAgentComponent(LCAgentComponent):
display_name = "VectorStoreAgent"
description = "Construct an agent from a Vector Store."
name = "VectorStoreAgent"
legacy: bool = True
inputs = [
*LCAgentComponent._base_inputs,
HandleInput(
name="llm",
display_name="Language Model",
input_types=["LanguageModel"],
required=True,
),
HandleInput(
name="vectorstore",
display_name="Vector Store",
input_types=["VectorStoreInfo"],
required=True,
),
]
def build_agent(self) -> AgentExecutor:
toolkit = VectorStoreToolkit(vectorstore_info=self.vectorstore, llm=self.llm)
return create_vectorstore_agent(llm=self.llm, toolkit=toolkit, **self.get_agent_kwargs())

View file

@ -0,0 +1,13 @@
from .assemblyai_get_subtitles import AssemblyAIGetSubtitles
from .assemblyai_lemur import AssemblyAILeMUR
from .assemblyai_list_transcripts import AssemblyAIListTranscripts
from .assemblyai_poll_transcript import AssemblyAITranscriptionJobPoller
from .assemblyai_start_transcript import AssemblyAITranscriptionJobCreator
__all__ = [
"AssemblyAIGetSubtitles",
"AssemblyAILeMUR",
"AssemblyAIListTranscripts",
"AssemblyAITranscriptionJobPoller",
"AssemblyAITranscriptionJobCreator",
]

View file

@ -18,7 +18,7 @@ from langflow.template import Output
class AstraAssistantManager(ComponentWithCache):
display_name = "Astra Assistant Manager"
description = "Manages Assistant Interactions"
icon = "bot"
icon = "AstraDB"
inputs = [
StrInput(

View file

@ -8,7 +8,7 @@ from langflow.template import Output
class AssistantsCreateAssistant(ComponentWithCache):
icon = "bot"
icon = "AstraDB"
display_name = "Create Assistant"
description = "Creates an Assistant and returns it's id"

View file

@ -8,7 +8,7 @@ from langflow.template import Output
class AssistantsCreateThread(ComponentWithCache):
display_name = "Create Assistant Thread"
description = "Creates a thread and returns the thread id"
icon = "AstraDB"
inputs = [
MultilineInput(
name="env_set",

View file

@ -11,7 +11,7 @@ from langflow.template import Output
class Dotenv(Component):
display_name = "Dotenv"
description = "Load .env file into env vars"
icon = "AstraDB"
inputs = [
MultilineSecretInput(
name="dotenv_file_content",

View file

@ -8,7 +8,7 @@ from langflow.template import Output
class AssistantsGetAssistantName(ComponentWithCache):
display_name = "Get Assistant name"
description = "Assistant by id"
icon = "AstraDB"
inputs = [
StrInput(
name="assistant_id",

View file

@ -9,7 +9,7 @@ from langflow.template import Output
class GetEnvVar(Component):
display_name = "Get env var"
description = "Get env var"
icon = "code"
icon = "AstraDB"
inputs = [
StrInput(

View file

@ -7,7 +7,7 @@ from langflow.template.field.base import Output
class AssistantsListAssistants(ComponentWithCache):
display_name = "List Assistants"
description = "Returns a list of assistant id's"
icon = "AstraDB"
outputs = [
Output(display_name="Assistants", name="assistants", method="process_inputs"),
]

View file

@ -13,6 +13,7 @@ from langflow.template import Output
class AssistantsRun(ComponentWithCache):
display_name = "Run Assistant"
description = "Executes an Assistant Run against a thread"
icon = "AstraDB"
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)

View file

@ -1,13 +0,0 @@
from .conversation import ConversationChainComponent
from .llm_checker import LLMCheckerChainComponent
from .llm_math import LLMMathChainComponent
from .retrieval_qa import RetrievalQAComponent
from .sql_generator import SQLGeneratorComponent
__all__ = [
"ConversationChainComponent",
"LLMCheckerChainComponent",
"LLMMathChainComponent",
"RetrievalQAComponent",
"SQLGeneratorComponent",
]

View file

@ -0,0 +1,3 @@
from .cohere_rerank import CohereRerankComponent
__all__ = ["CohereRerankComponent"]

View file

@ -0,0 +1,90 @@
from typing import cast
from langchain.retrievers import ContextualCompressionRetriever
from langchain_cohere import CohereRerank
from langflow.base.vectorstores.model import (
LCVectorStoreComponent,
check_cached_vector_store,
)
from langflow.field_typing import Retriever, VectorStore
from langflow.io import (
DropdownInput,
HandleInput,
IntInput,
MessageTextInput,
MultilineInput,
SecretStrInput,
)
from langflow.schema import Data
from langflow.template.field.base import Output
class CohereRerankComponent(LCVectorStoreComponent):
display_name = "Cohere Rerank"
description = "Rerank documents using the Cohere API and a retriever."
name = "CohereRerank"
icon = "Cohere"
legacy: bool = True
inputs = [
MultilineInput(
name="search_query",
display_name="Search Query",
),
DropdownInput(
name="model",
display_name="Model",
options=[
"rerank-english-v3.0",
"rerank-multilingual-v3.0",
"rerank-english-v2.0",
"rerank-multilingual-v2.0",
],
value="rerank-english-v3.0",
),
SecretStrInput(name="api_key", display_name="API Key"),
IntInput(name="top_n", display_name="Top N", value=3),
MessageTextInput(
name="user_agent",
display_name="User Agent",
value="langflow",
advanced=True,
),
HandleInput(name="retriever", display_name="Retriever", input_types=["Retriever"]),
]
outputs = [
Output(
display_name="Retriever",
name="base_retriever",
method="build_base_retriever",
),
Output(
display_name="Search Results",
name="search_results",
method="search_documents",
),
]
def build_base_retriever(self) -> Retriever: # type: ignore[type-var]
cohere_reranker = CohereRerank(
cohere_api_key=self.api_key,
model=self.model,
top_n=self.top_n,
user_agent=self.user_agent,
)
retriever = ContextualCompressionRetriever(base_compressor=cohere_reranker, base_retriever=self.retriever)
return cast(Retriever, retriever)
async def search_documents(self) -> list[Data]: # type: ignore[override]
retriever = self.build_base_retriever()
documents = await retriever.ainvoke(self.search_query, config={"callbacks": self.get_langchain_callbacks()})
data = self.to_data(documents)
self.status = data
return data
@check_cached_vector_store
def build_vector_store(self) -> VectorStore:
msg = "Cohere Rerank does not support vector stores."
raise NotImplementedError(msg)

View file

@ -0,0 +1,3 @@
from .composio_api import ComposioAPIComponent
__all__ = ["ComposioAPIComponent"]

View file

@ -0,0 +1,173 @@
from collections.abc import Sequence
from typing import Any
from composio_langchain import Action, App, ComposioToolSet
from langchain_core.tools import Tool
from loguru import logger
from typing_extensions import override
from langflow.base.langchain_utilities.model import LCToolComponent
from langflow.inputs import DropdownInput, MessageTextInput, MultiselectInput, SecretStrInput, StrInput
class ComposioAPIComponent(LCToolComponent):
display_name: str = "Composio Tools"
description: str = "Use Composio toolset to run actions with your agent"
name = "ComposioAPI"
icon = "Composio"
documentation: str = "https://docs.composio.dev"
inputs = [
MessageTextInput(name="entity_id", display_name="Entity ID", value="default", advanced=True),
SecretStrInput(
name="api_key",
display_name="Composio API Key",
required=True,
refresh_button=True,
info="Refer to https://docs.composio.dev/introduction/foundations/howtos/get_api_key",
),
DropdownInput(
name="app_names",
display_name="App Name",
options=list(App.__annotations__),
value="",
info="The app name to use. Please refresh after selecting app name",
refresh_button=True,
),
MultiselectInput(
name="action_names",
display_name="Actions to use",
required=False,
options=[],
value=[],
info="The actions to pass to agent to execute",
),
StrInput(
name="auth_status_config",
display_name="Auth status",
value="",
refresh_button=True,
info="Open link or enter api key. Then refresh button",
),
]
def _check_for_authorization(self, app: str) -> str:
"""Checks if the app is authorized.
Args:
app (str): The app name to check authorization for.
Returns:
str: The authorization status.
"""
toolset = self._build_wrapper()
entity = toolset.client.get_entity(id=self.entity_id)
try:
entity.get_connection(app=app)
except Exception: # noqa: BLE001
logger.opt(exception=True).debug("Authorization error")
return self._handle_authorization_failure(toolset, entity, app)
return f"{app} CONNECTED"
def _handle_authorization_failure(self, toolset: ComposioToolSet, entity: Any, app: str) -> str:
"""Handles the authorization failure by attempting to process API key auth or initiate default connection.
Args:
toolset (ComposioToolSet): The toolset instance.
entity (Any): The entity instance.
app (str): The app name.
Returns:
str: The result of the authorization failure message.
"""
try:
auth_schemes = toolset.client.apps.get(app).auth_schemes
if auth_schemes[0].auth_mode == "API_KEY":
return self._process_api_key_auth(entity, app)
return self._initiate_default_connection(entity, app)
except Exception: # noqa: BLE001
logger.exception("Authorization error")
return "Error"
def _process_api_key_auth(self, entity: Any, app: str) -> str:
"""Processes the API key authentication.
Args:
entity (Any): The entity instance.
app (str): The app name.
Returns:
str: The status of the API key authentication.
"""
auth_status_config = self.auth_status_config
is_url = "http" in auth_status_config or "https" in auth_status_config
is_different_app = "CONNECTED" in auth_status_config and app not in auth_status_config
is_default_api_key_message = "API Key" in auth_status_config
if is_different_app or is_url or is_default_api_key_message:
return "Enter API Key"
if not is_default_api_key_message:
entity.initiate_connection(
app_name=app,
auth_mode="API_KEY",
auth_config={"api_key": self.auth_status_config},
use_composio_auth=False,
force_new_integration=True,
)
return f"{app} CONNECTED"
return "Enter API Key"
def _initiate_default_connection(self, entity: Any, app: str) -> str:
connection = entity.initiate_connection(app_name=app, use_composio_auth=True, force_new_integration=True)
return connection.redirectUrl
def _get_connected_app_names_for_entity(self) -> list[str]:
toolset = self._build_wrapper()
connections = toolset.client.get_entity(id=self.entity_id).get_connections()
return list({connection.appUniqueId for connection in connections})
def _update_app_names_with_connected_status(self, build_config: dict) -> dict:
connected_app_names = self._get_connected_app_names_for_entity()
app_names = [
f"{app_name}_CONNECTED" for app_name in App.__annotations__ if app_name.lower() in connected_app_names
]
non_connected_app_names = [
app_name for app_name in App.__annotations__ if app_name.lower() not in connected_app_names
]
build_config["app_names"]["options"] = app_names + non_connected_app_names
build_config["app_names"]["value"] = app_names[0] if app_names else ""
return build_config
def _get_normalized_app_name(self) -> str:
return self.app_names.replace("_CONNECTED", "").replace("_connected", "")
@override
def update_build_config(self, build_config: dict, field_value: Any, field_name: str | None = None) -> dict:
if field_name == "api_key":
if hasattr(self, "api_key") and self.api_key != "":
build_config = self._update_app_names_with_connected_status(build_config)
return build_config
if field_name in {"app_names", "auth_status_config"}:
if hasattr(self, "api_key") and self.api_key != "":
build_config["auth_status_config"]["value"] = self._check_for_authorization(
self._get_normalized_app_name()
)
all_action_names = list(Action.__annotations__)
app_action_names = [
action_name
for action_name in all_action_names
if action_name.lower().startswith(self._get_normalized_app_name().lower() + "_")
]
build_config["action_names"]["options"] = app_action_names
build_config["action_names"]["value"] = [app_action_names[0]] if app_action_names else [""]
return build_config
def build_tool(self) -> Sequence[Tool]:
composio_toolset = self._build_wrapper()
return composio_toolset.get_tools(actions=self.action_names)
def _build_wrapper(self) -> ComposioToolSet:
return ComposioToolSet(api_key=self.api_key)

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