from typing import Any, Dict

from langchain.base_language import BaseLanguageModel
from langchain.prompts import (
    ChatPromptTemplate,
    HumanMessagePromptTemplate,
    MessagesPlaceholder,
    SystemMessagePromptTemplate,
)
from langchain.chains import ConversationChain

from real_agents.adapters.executors.base import BaseExecutor
from real_agents.adapters.memory import ConversationBufferMemory

class ChatExecutor(BaseExecutor):
    """Chat Executor."""

    _DEFAULT_TEMPLATE = "The following is a friendly conversation between a human and an AI. \
        The AI is talkative and provides lots of specific details from its context. \
        If the AI does not know the answer to a question, it truthfully says it does not know."


from real_agents.adapters.executors.base import BaseExecutor
from real_agents.adapters.executors.chat_executor import ChatExecutor
from real_agents.adapters.executors.question_suggestion.question_suggestion_executor import (
    QuestionSuggestionExecutor,
    QuestionSuggestionChainChatMemory,
    QuestionSuggestionChainBase,
)


from __future__ import annotations

from langchain.base_language import BaseLanguageModel
from langchain.chains.llm import LLMChain

from real_agents.adapters.executors.question_suggestion.base import QuestionSuggestionChainBase
from real_agents.adapters.executors.question_suggestion.prompts import QUESTION_SUGGESTION_PROMPT_CHAT_MEMORY

class QuestionSuggestionChainChatMemory(QuestionSuggestionChainBase):
    @classmethod
    def from_prompt(cls, llm: BaseLanguageModel) -> QuestionSuggestionChainChatMemory:
        """Load from user profile prompt."""
        llm_chain = LLMChain(llm=llm, prompt=QUESTION_SUGGESTION_PROMPT_CHAT_MEMORY)
        return cls(llm_chain=llm_chain)


from __future__ import annotations

from typing import Dict, List, Optional
from pydantic import BaseModel, Extra

from langchain.base_language import BaseLanguageModel
from langchain.callbacks.manager import CallbackManagerForChainRun
from langchain.chains.base import Chain
from langchain.chains.llm import LLMChain

from real_agents.adapters.executors.question_suggestion.prompts import QUESTION_SUGGESTION_PROMPT_BASE

class QuestionSuggestionChainBase(Chain, BaseModel):
    """Question Suggestion by Language Models."""

    llm_chain: LLMChain
    output_key: str = "questions"

    class Config:
        """Configuration for this pydantic object."""


from __future__ import annotations

from langchain.base_language import BaseLanguageModel
from langchain.chains.llm import LLMChain

from real_agents.adapters.executors.question_suggestion.base import QuestionSuggestionChainBase
from real_agents.adapters.executors.question_suggestion.prompts import QUESTION_SUGGESTION_PROMPT_USER_PROFILE

class QuestionSuggestionChainUserProfile(QuestionSuggestionChainBase):
    @classmethod
    def from_prompt(cls, llm: BaseLanguageModel) -> QuestionSuggestionChainUserProfile:
        """Load from user profile prompt."""
        llm_chain = LLMChain(llm=llm, prompt=QUESTION_SUGGESTION_PROMPT_USER_PROFILE)
        return cls(llm_chain=llm_chain)


from langchain import PromptTemplate

template_base = (
    "{input_string}\nPlease provide {num_questions} natural language questions related to the above contents, "
    "but very different from each other. These questions should be diverse, challenging, "
    "and targeted towards different perspectives. "
    "You should ask these questions like you would ask a human, "
    "but strictly follow the style of your role-playing character.\n"
    "Do not explicitly mention the provided contents; "
    "instead use natural language descriptions for them. "
    "The final result should be a numbered list.".strip() + "\n"
)

QUESTION_SUGGESTION_PROMPT_BASE = PromptTemplate(
    input_variables=["input_string", "num_questions"], template=template_base
)

template_user_profile = (
    "{input_string}\n--------------------\n"
    "{user_description}\n"
    "From now on, you should speak in a style that fully conforms to the given role. \n"


from typing import Any, Dict

from langchain.base_language import BaseLanguageModel
from langchain.schema import AIMessage, HumanMessage

from real_agents.adapters.memory import ConversationReActBufferMemory
from real_agents.adapters.executors.question_suggestion.chat_memory import QuestionSuggestionChainChatMemory
from real_agents.adapters.executors.question_suggestion.base import QuestionSuggestionChainBase
from real_agents.adapters.executors.question_suggestion.user_profile import QuestionSuggestionChainUserProfile

class QuestionSuggestionExecutor:
    def run(
        self,
        user_intent: str,
        llm: BaseLanguageModel,
        num_questions: int = 3,
        mode: str = "",
        user_profile: str = "",
        chat_memory: ConversationReActBufferMemory = ConversationReActBufferMemory(),
    ) -> Dict[str, Any]:


"""Chain that takes in an input and produces an action and action input."""
from __future__ import annotations

import json
import logging
import time
from abc import abstractmethod
from pathlib import Path
from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union
import yaml
from pydantic import BaseModel, root_validator

from langchain.agents.agent_types import AgentType
from langchain.agents.tools import InvalidTool
from langchain.base_language import BaseLanguageModel
from langchain.callbacks.base import BaseCallbackManager
from langchain.callbacks.manager import (
    AsyncCallbackManagerForToolRun,
    CallbackManagerForChainRun,
    CallbackManagerForToolRun,
    Callbacks,


from __future__ import annotations

from typing import Optional, Union
from pydantic import Extra

from langchain.schema import (
    AgentAction,
    AgentFinish,
)
from real_agents.adapters.agent_helpers.agent import AgentOutputParser
from real_agents.adapters.schema import AgentTransition

class ConversationOutputParser(AgentOutputParser):
    class Config:
        """Configuration for this pydantic object."""

        extra = Extra.allow
        arbitrary_types_allowed = True

    def get_format_instructions(self, app_name="copilot") -> str:


"""Interface for agents."""
from real_agents.adapters.agent_helpers.agent import (
    Agent,
    AgentExecutor,
    AgentOutputParser,
    BaseSingleActionAgent,
)
from real_agents.adapters.agent_helpers.tools import Tool, tool

__all__ = [
    "AgentExecutor",
    "Agent",
    "Tool",
    "tool",
    "AgentOutputParser",
    "BaseSingleActionAgent",
]


"""Interface for tools."""
from inspect import signature
from typing import Any, Awaitable, Callable, Dict, Optional, Type, Union
from pydantic import BaseModel, validate_arguments

from langchain.tools.base import BaseTool

from real_agents.adapters.data_model import DataModel
from real_agents.adapters.callbacks.manager import (
    CallbackManager,
    Callbacks,
)

class Tool(BaseTool):
    """Tool that takes in function or coroutine directly."""

    description: str = ""
    func: Callable[..., str]
    """The function to run when the tool is called."""
    coroutine: Optional[Callable[..., Awaitable[str]]] = None


# flake8: noqa
import datetime

PREFIX = (
    """You are XLang Plugins Agent, a friendly and intuitive assistant developed by the XLang Team to guide you through every aspects of your work and your daily life. XLang Agent is always at your fingertips through our interactive chat system.

You can aware of what plugins you have, and use the plugins properly in right order to finish what user wants.

Today is
""".strip() + " "
    + datetime.datetime.now().strftime("%Y-%m-%d")
    + """, and you should adapt the input to fit into the date, for example, seasonal information, or today's date as coordinate, etc.

To make your response informative, always speak includes the following information in MARKDOWN format when responding a message, that is:
1. Natural language explanation, that make explain the API output in a human readable way;
2. Organized information such as bullet points or MARKDOWN tables, followed by the links to the items (that in the API output), news etc. if API output contains the information;
3. The links should in MARKDOWN format and have value in it. If reference information is provided in the API output, like links to the items, news etc. Your explanation MUST provide the links on each items and links can be clicked on when API output contains the information. The links better attach on some natural language explanation through MARKDOWN syntax, for example, - [Renewable Energy - Center for Climate and Energy Solutions](https://www.c2es.org/content/renewable-energy/);
4. If there are image we would like to display, please use MARKDOWN syntax to display it, for example, ![image](https://www.c2es.org/content/renewable-energy/);
5. Try to speak more and show all the information you got in a organized way, that will make you a better assistant, especially when you are giving the final answer.

PLUGINS


"""An agent designed to hold a conversation in addition to using tools. (Specially designed for plugins model)"""
from __future__ import annotations

from typing import Any, List, Optional, Sequence, Tuple, Union
from pydantic import Extra, Field
from typing_extensions import override

from langchain.agents.agent import AgentOutputParser
from langchain.agents.utils import validate_tools_single_input
from langchain.base_language import BaseLanguageModel
from langchain.chains import LLMChain
from langchain.schema import (
    AgentAction,
    AgentFinish,
    AIMessage,
    BaseMessage,
    BaseOutputParser,
    HumanMessage
)
from langchain.callbacks.manager import (
    Callbacks


from real_agents.plugins_agent.plugin import ConversationalPluginChatAgent
from real_agents.plugins_agent.api_calling.base import APICallingChain
from real_agents.plugins_agent.executors.plugin_executor import PluginExecutor


"""The .py file to control the plugin we use in the chatbot"""
import os
from enum import Enum

CURRENT_PATH = os.path.dirname(os.path.abspath(__file__))

class PluginName(str, Enum):
    """
    Enum class for plugin names
    each name is a plugin name 🔌 , each value is the folder name 📁 of the plugin
    """
    KLARNA = "klarna"
    ZAPIER = "zapier"
    COURSERA = "Coursera"
    JOBSEARCH = "jobsearch"
    SHOW_ME = "show_me"
    SPEAK = "speak"
    CREATE_QR_CODE = "create_qr_code"
    MAPS = "maps"
    ASKYOURPDF = "askyourpdf"


from langchain.tools.base import BaseTool
from langchain.tools.ifttt import IFTTTWebhook
from langchain.tools.openapi.utils.api_models import APIOperation
from langchain.tools.openapi.utils.openapi_utils import OpenAPISpec
from langchain.tools.plugin import AIPluginTool

from real_agents.plugins_agent.plugins.plugin_names import PluginName

__all__ = [
    "BaseTool",
    "IFTTTWebhook",
    "AIPluginTool",
    "OpenAPISpec",
    "APIOperation",
    "PluginName",
]


"""Utils for plugins (loading and more to add)"""
import importlib
import json
import os
import sys
from collections import defaultdict
from typing import Any
import yaml
from tqdm import tqdm

from real_agents.adapters.data_model import APIYamlModel, SpecModel
from real_agents.plugins_agent.plugins.plugin_names import PluginName

CURRENT_PATH = os.path.dirname(os.path.abspath(__file__))

AI_PLUGIN_FILE = "ai-plugin.json"
PLUGIN_SPEC_FILE = "openapi.yaml"
PATH_FOLDER = "paths"

def _load_module(name: str, file_path: str) -> Any:


"""Implementation of Tool Selector that automate the selection of tools for the question (or sub-question)."""
import os
import pickle

import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
from tqdm import tqdm
from typing import Any

from real_agents.adapters.data_model import SpecModel
from langchain.embeddings.huggingface import HuggingFaceInstructEmbeddings

DEFAULT_TOOL_INSTRUCTION = "Represent the tool description for retrieval:"
DEFAULT_QUERY_INSTRUCTION = "Represent the question for retrieving tools that can be used to solve the question:"
PLUGIN_SPEC_FILE = "openapi.yaml"
CURRENT_PATH = os.path.dirname(os.path.abspath(__file__))
EMBEDDING_CACHE_PATH = os.path.join(CURRENT_PATH, "..", "..", "..", "backend", "static", "tool_embeddings")
if not os.path.exists(EMBEDDING_CACHE_PATH):
    os.makedirs(EMBEDDING_CACHE_PATH)


"""Search for products by keyword, price range, and size."""
from typing import Any, Dict

import requests

url = "https://www.klarna.com/us/shopping/public/openai/v0/products"

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    headers = {"Accept": "application/json"}
    response = requests.get(url, headers=headers, params=input_json)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}

# input_json = {
#     "q": "nike shoes",
#     "size": 10,
#     "min_price": 50,


path_dict = {
    "products": "/public/openai/v0/products",
}


"""Search Coursera API for courses matching a query."""
from typing import Any, Dict

import requests

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    response = requests.post("https://www.coursera.org/api/rest/v1/search", json=input_json)
    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}


path_dict = {"search": "/api/rest/v1/search"}


"""NBA stats API path."""
from typing import Any, Dict

import requests

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    response = requests.post("https://nba-gpt-prod.onrender.com/basketball_stats", json=input_json)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}


path_dict = {
    "basketball_stats": "/basketball_stats"
}


"""Download PDF from AskYourPDF API."""
from typing import Any, Dict
import requests

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    response = requests.post("https://plugin.askyourpdf.com/api/download_pdf", params=input_json)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}


path_dict = {
    "download_pdf": "/api/download_pdf",
    "perform_query": "/query"
}


"""Perform query to AskYourPDF API."""
from typing import Any, Dict
import requests

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    response = requests.post("https://plugin.askyourpdf.com/query", json=input_json)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}


"""LLM API for Wolfram Alpha"""
import requests

def call_api(input_json, api_key):
    input_json["appid"] = api_key
    response = requests.get("https://www.wolframalpha.com/api/v1/llm-api", params=input_json)

    if response.status_code == 200:
        return response.content.decode("utf-8")
    else:
        return {"status_code": response.status_code, "text": response.text}


"""Cloud plugin for Wolfram Alpha API"""
import requests

def call_api(input_json, api_key):
    input_json["appid"] = api_key
    response = requests.get("https://www.wolframalpha.com/api/v1/cloud-plugin", params=input_json)

    if response.status_code == 200:
        return response.content.decode("utf-8")
    else:
        return {"status_code": response.status_code, "text": response.text}


path_dict = {
    "cloud_plugin": "/api/v1/cloud-plugin",
    "llm_api": "/api/v1/llm-api"
}


"""Render diagram path for Show Me plugin."""
from typing import Any, Dict
import requests

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    response = requests.get("https://showme.redstarplugin.com/render/", params=input_json)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}


path_dict = {
    "diagram_guidelines": "/diagram-guidelines",
    "render_diagram": "/render",
    "show_carousel": "/show-carousel"
}


"""Show Carousel path for Show Me plugin."""
from typing import Any, Dict
import requests

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    response = requests.get("https://showme.redstarplugin.com/show-carousel", params=input_json)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}


"""Guidelines for diagramming"""
from typing import Any, Dict
import requests

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    response = requests.get("https://showme.redstarplugin.com/diagram-guidelines", params=input_json)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}


"""Radars API path."""
from typing import Any, Dict
import requests

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    location = input_json['location']
    response = requests.get(f"https://openai-plugin.xweather.com/radar/{location}", params=input_json)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}


"""Weather summary path for XWeather plugin."""
from typing import Any, Dict
import requests

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    url = "https://openai-plugin.xweather.com/weather/summary/{}".format(input_json['location'])
    response = requests.get(url)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}


path_dict = {
    "get_radar": "/radar/{location}",
    "weather_forecast": "/weather/forecast/{location}",
    "weather_summary": "/weather/summary/{location}"
}


"""Weather Forecast API Path."""
from typing import Dict, Any
import requests

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    location = input_json["location"]
    url = f"https://openai-plugin.xweather.com/weather/forecast/{location}"
    response = requests.get(url)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}


"""Search news from Biztoc API."""
from typing import Any, Dict

import requests

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    response = requests.get("https://ai.biztoc.com/ai/news", params=input_json)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}


path_dict = {
    "search_news": "/ai/news",
}


path_dict = {
    "scraper": "/scrape"
}


"""Scrape data from a website using the Scraper API."""
import requests
from typing import Any, Dict

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    response = requests.post("https://scraper.gafo.tech/scrape", json=input_json)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}


"""Jobsearch API jobs path."""
from typing import Any, Dict
import requests

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    url = "https://jobsearch.vencio.de/jobs"
    headers = {
        "Content-Type": "application/json"
    }
    response = requests.get(url, headers=headers, params=input_json)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}


"""Maps plugin for generating maps from latlng coordinates."""
from typing import Any, Dict

import requests

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    query_param = input_json["latlng"]
    response = requests.get(f"https://maps.smoothplugins.com/?latlng={query_param}")

    if response.status_code == 200:
        return {"result": response.content.decode()}
    else:
        return {"status_code": response.status_code, "text": response.text}


"""Explains a foreign phrase in the context of a full query."""
from typing import Any, Dict

import requests

url = "https://api.speak.com/v1/public/openai/explain-phrase"

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    headers = {"Content-Type": "application/json"}
    response = requests.post(url, json=input_json, headers=headers)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}

# input_json = {
#         "foreign_phrase": "no mames",
#         "learning_language": "Spanish",
#         "native_language": "English",


path_dict = {
    "translate": "/v1/public/openai/translate",
    "explain_task": "/v1/public/openai/explain-task",
    "explain_phrase": "/v1/public/openai/explain-phrase",
}


"""Translate a phrase from one language to another."""
from typing import Any, Dict

import requests

url = "https://api.speak.com/v1/public/openai/translate"

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    headers = {"Content-Type": "application/json"}
    response = requests.post(url, json=input_json, headers=headers)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}

# input_json = {
#     "phrase_to_translate": "Hello, how are you?",
#     "learning_language": "Spanish",
#     "native_language": "English",


"""Explain the task to the user."""
from typing import Any, Dict

import requests

url = "https://api.speak.com/v1/public/openai/explain-task"

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    headers = {"Content-Type": "application/json"}
    response = requests.post(url, json=input_json, headers=headers)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}

# input_json = {
#         "task_description": "ask for directions,
#         "learning_language": "French",
#         "native_language": "English",


path_dict = {
    "get_classes": "/classes",
    "search_teachers": "/teachers"
}


"""Search for teachers on Outschool."""
from typing import Any, Dict
import requests

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    response = requests.get("https://chatgpt-plugin.outschool.com/api/teachers", params=input_json)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}


"""Get classes from Outschool API."""
from typing import Any, Dict
import requests

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    response = requests.get("https://chatgpt-plugin.outschool.com/api/classes", params=input_json)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}


path_dict = {
    "dream_interpreter": "/getDream/{DreamText}",
    "data": "/api/data",
}


"""Data path for DreamInterpreter plugin."""""
from typing import Any, Dict

import requests

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    response = requests.post("https://dreamplugin.bgnetmobile.com/api/data", json=input_json)

    if response.status_code == 200:
        return response.content
    else:
        return {"status_code": response.status_code, "text": response.text}


"""Dream Interpreter plugin."""
from typing import Any, Dict
import requests

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    dream_text = input_json["DreamText"]
    response = requests.get(f"https://dreamplugin.bgnetmobile.com/getDream/{dream_text}")
    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}


"""The Zapier plugin personnel openapi.yaml handling, since it is special case, we need to handle it separately"""
import os
import requests

FILE_PATH = os.path.dirname(os.path.abspath(__file__))

# You need to manage your actions first in https://nla.zapier.com/providers/

# Reload the openapi
def reload_openapi(api_key, openapi_json):
    # Original data
    headers = {"X-API-Key": api_key, }
    # Call read the openapi
    url = "https://nla.zapier.com/api/v1/exposed/"

    data = None
    while True:
        try:
            response = requests.get(url, headers=headers)
            data = response.json()


"""Exposed paths for the Zapier plugin."""
from typing import Any, Dict

import requests

def call_api(input_json: Dict[str, Any], api_key) -> Dict[str, Any]:
    headers = {
        "X-API-Key": api_key,
    }
    url = "https://nla.zapier.com/api/v1/exposed/"
    response = requests.get(url, headers=headers)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}


"""Configuration Link Path."""
from typing import Any, Dict

import requests

def call_api(input_json: Dict[str, Any], api_key) -> Dict[str, Any]:
    headers = {
        "X-API-Key": api_key,
    }
    url = "https://nla.zapier.com/api/v1/configuration-link/"
    response = requests.get(url, headers=headers)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}


"""Preview a Zapier Zap."""
from typing import Any, Dict

import requests

def call_api(input_json: Dict[str, Any], api_key) -> Dict[str, Any]:
    headers = {
        "X-API-Key": api_key,
        "Content-Type": "application/json"
    }
    url = "https://nla.zapier.com/api/v1/preview-a-zap/"
    response = requests.post(url, headers=headers)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}


"""Execution log path for Zapier plugin."""
from typing import Any, Dict

import requests

def call_api(input_json: Dict[str, Any], api_key) -> Dict[str, Any]:
    headers = {
        "X-API-Key": api_key,
    }
    url = "https://nla.zapier.com/api/v1/" + input_json['execution-log']
    response = requests.get(url, headers=headers)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}


"""Search Actions"""
from typing import Any, Dict

import requests

def call_api(input_json: Dict[str, Any], api_key) -> Dict[str, Any]:
    headers = {
        "X-API-Key": api_key,
    }
    url = "https://nla.zapier.com/api/v1/search/actions/"
    response = requests.get(url, headers=headers, params=input_json)

    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}


path_dict = {
    "search_actions": "/api/v1/search/actions/",
    "preview_a_zap": "/api/v1/preview-a-zap/",
    "configuration_link": "/api/v1/configuration-link/",
    "exposed": "/api/v1/exposed/",
    "execution_log": "/api/v1/execution-log/{execution_log_id}/",
}


path_dict = {"create_qr": "/create-qr-code"}


"""Create QR Code API."""
from typing import Any, Dict

import requests

def call_api(input_json: Dict[str, Any]) -> Dict[str, Any]:
    url = "https://create-qr-code.modelxy.com/create-qr-code"
    response = requests.get(url, params=input_json)
    if response.status_code == 200:
        return response.json()
    else:
        return {"status_code": response.status_code, "text": response.text}


"""Executor that manage the plugins calling"""
from __future__ import annotations

from typing import Any, Callable, Dict, Union
from pydantic import BaseModel, Extra

from langchain.base_language import BaseLanguageModel

from real_agents.adapters.data_model import SpecModel
from real_agents.plugins_agent import APICallingChain
from real_agents.plugins_agent.plugins.utils import load_plugin_elements_by_name
from real_agents.adapters.data_model.utils import indent_multiline_string

class PluginExecutor(BaseModel):
    """Executor to call plugins that handle the spec showing, endpoint calling and output modeling."""
    name: str
    description: str
    spec_model: SpecModel
    meta_info: Dict[str, Any]
    endpoint2caller: Dict[str, Callable]


"""Implement API calling."""

from __future__ import annotations

import re
import traceback
from typing import Any, Callable, Dict, List, Optional
import backoff
import json5
from fuzzywuzzy import process
from pydantic import BaseModel, Extra

from langchain.base_language import BaseLanguageModel
from langchain.callbacks.manager import CallbackManagerForChainRun
from langchain.chains import LLMChain
from langchain.chains.base import Chain
from langchain.prompts.base import BasePromptTemplate
from langchain.prompts.chat import (
    ChatPromptTemplate,
    HumanMessagePromptTemplate,
    SystemMessagePromptTemplate,


SYSTEM_PROMPT = (
    """You are acting like plugin system that understand user's needs and call APIs precisely for them.""".strip()
    + "\n"
)

USER_PROMPT = (
    """
Here are the endpoints specs:
```
{specs_str}
```
Here is the input string:
```
{input_str}
```
Select the right endpoint called that can process the input string.
You need to wrap the input str into a json object, so that it could be fed into the function you selected.
During wrapping, you should:
1. modify the value of each key so that it satisfies the requirements in function specs.For example, if the type of the value should be a number, then you should modify it into a number;
2. ignore the information that is not useful or not applicable to the function you selected.
You fill values into some slots in the input_json, and then call the API. If the API returns a valid output, then you succeed. Otherwise, you fail.


"""Customize exceptions for API calling."""

class ParsingError(BaseException):
    """Error occur when parsing."""

    def __init__(self, message: str):
        self.message = message
        super().__init__(f"Error occur when parsing: {message}")

class APICallingError(BaseException):
    """Error occur when calling API."""
    def __init__(self, message: str):
        self.message = message
        super().__init__(f"Error occur when calling API: {message}")