From 642c8836c26cac780e79f7a6097f65ef76d6e2c8 Mon Sep 17 00:00:00 2001 From: Preetam Joshi Date: Fri, 26 Jul 2024 23:29:49 -0700 Subject: [PATCH] [Higher Level API] Added decorators for better dev UX and a Chatbot application (#19) Adding the Aimon Rely README, images, the postman collection, a simple client and examples. A few small changes for error handling in the client and the example application. Getting the Aimon API key from the streamlit app updating README Updating langchain example gif Updating API endpoint Adding V2 API with support for conciseness, completeness and toxicity checks (#1) * Adding V2 API with support for conciseness, completeness and toxicity checks. * Removing prints and updating config for the example application. * Updating README --------- Co-authored-by: Preetam Joshi Updating postman collection Fixed the simple aimon client's handling of batch requests. Updated postman collection. Added support for a user_query parameter in the input data dictionary. Updating readme Fixed bug in the example app Uploading client code Adding more convenience APIs Fixing bug in create_dataset Added Github actions config to publish to PyPI. Cleaned up dependencies and updated documentation. Fixing langchain example Fixing doc links Formatting changes Changes for aimon-rely * Adding instruction adherence and hallucination v0.2 to the client Updating git ignore Adding more to gitignore Removing .idea files * Fixing doc string * Updating documentation * Updating Client to use V3 API * Fixing test * Updating tests * Updating documentation in the client * Adding .streamlit dir to .gitignore * initial version of decorators for syntactic sugar * A few more changes * updating analyze and detect decorators * Adding new notebooks * Fixing bug in analyze decorator --------- Co-authored-by: Preetam Joshi --- .gitignore | 2 + aimon/__init__.py | 5 +- aimon/decorators/__init__.py | 0 aimon/decorators/analyze.py | 123 +++++++++ aimon/decorators/common.py | 15 ++ aimon/decorators/detect.py | 107 ++++++++ examples/aimon_chatbot_demo.py | 154 +++++++++++ ...rators_langchain_summarization_0_5_0.ipynb | 247 ++++++++++++++++++ .../aimon_sdk_langchain_summarization.ipynb | 2 +- ...on_sdk_langchain_summarization_0_5_0.ipynb | 2 +- examples/requirements_chatbot.txt | 4 + 11 files changed, 658 insertions(+), 3 deletions(-) create mode 100644 aimon/decorators/__init__.py create mode 100644 aimon/decorators/analyze.py create mode 100644 aimon/decorators/common.py create mode 100644 aimon/decorators/detect.py create mode 100644 examples/aimon_chatbot_demo.py create mode 100644 examples/notebooks/aimon_decorators_langchain_summarization_0_5_0.ipynb create mode 100644 examples/requirements_chatbot.txt diff --git a/.gitignore b/.gitignore index 3e8eab4..e75867b 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ lib64 # Installer logs pip-log.txt + +.streamlit/* diff --git a/aimon/__init__.py b/aimon/__init__.py index e4b0248..605560f 100644 --- a/aimon/__init__.py +++ b/aimon/__init__.py @@ -62,7 +62,7 @@ "DEFAULT_MAX_RETRIES", "DEFAULT_CONNECTION_LIMITS", "DefaultHttpxClient", - "DefaultAsyncHttpxClient", + "DefaultAsyncHttpxClient" ] _setup_logging() @@ -79,3 +79,6 @@ except (TypeError, AttributeError): # Some of our exported symbols are builtins which we can't set attributes for. pass + +from .decorators.detect import DetectWithContextQuery, DetectWithContextQueryInstructions, DetectWithQueryFuncReturningContext, DetectWithQueryInstructionsFuncReturningContext +from .decorators.analyze import Analyze, Application, Model diff --git a/aimon/decorators/__init__.py b/aimon/decorators/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/aimon/decorators/analyze.py b/aimon/decorators/analyze.py new file mode 100644 index 0000000..c0667ee --- /dev/null +++ b/aimon/decorators/analyze.py @@ -0,0 +1,123 @@ +from functools import wraps +from .common import AimonClientSingleton + + +class Application: + def __init__(self, name, stage="evaluation", type="text", metadata={}): + self.name = name + self.stage = stage + self.type = type + self.metadata = metadata + + +class Model: + def __init__(self, name, model_type, metadata={}): + self.name = name + self.model_type = model_type + self.metadata = metadata + + +class Analyze(object): + DEFAULT_CONFIG = {'hallucination': {'detector_name': 'default'}} + + def __init__(self, application, model, api_key=None, evaluation_name=None, dataset_collection_name=None, eval_tags=None, instructions=None, config=None): + self.client = AimonClientSingleton.get_instance(api_key) + self.application = application + self.model = model + self.evaluation_name = evaluation_name + self.dataset_collection_name = dataset_collection_name + self.eval_tags = eval_tags + self.instructions = instructions + self.config = config if config else self.DEFAULT_CONFIG + self.initialize() + + def initialize(self): + # Create or retrieve the model + self._am_model = self.client.models.create( + name=self.model.name, + type=self.model.model_type, + description="This model is named {} and is of type {}".format(self.model.name, self.model.model_type), + metadata=self.model.metadata + ) + + # Create or retrieve the application + self._am_app = self.client.applications.create( + name=self.application.name, + model_name=self._am_model.name, + stage=self.application.stage, + type=self.application.type, + metadata=self.application.metadata + ) + + if self.evaluation_name is not None: + + if self.dataset_collection_name is None: + raise ValueError("Dataset collection name must be provided for running an evaluation.") + + # Create or retrieve the dataset collection + self._am_dataset_collection = self.client.datasets.collection.retrieve(name=self.dataset_collection_name) + + # Create or retrieve the evaluation + self._eval = self.client.evaluations.create( + name=self.evaluation_name, + application_id=self._am_app.id, + model_id=self._am_model.id, + dataset_collection_id=self._am_dataset_collection.id + ) + + def _run_eval(self, func, args, kwargs): + # Create an evaluation run + eval_run = self.client.evaluations.run.create( + evaluation_id=self._eval.id, + metrics_config=self.config, + ) + # Get all records from the datasets + dataset_collection_records = [] + for dataset_id in self._am_dataset_collection.dataset_ids: + dataset_records = self.client.datasets.records.list(sha=dataset_id) + dataset_collection_records.extend(dataset_records) + results = [] + for record in dataset_collection_records: + result = func(record['context_docs'], record['user_query'], *args, **kwargs) + payload = { + "application_id": self._am_app.id, + "version": self._am_app.version, + "prompt": record['prompt'] or "", + "user_query": record['user_query'] or "", + "context_docs": [d for d in record['context_docs']], + "output": result, + "evaluation_id": self._eval.id, + "evaluation_run_id": eval_run.id, + } + results.append((result, self.client.analyze.create(body=[payload]))) + return results + + def _run_production_analysis(self, func, context, sys_prompt, user_query, args, kwargs): + result = func(context, sys_prompt, user_query, *args, **kwargs) + if result is None: + raise ValueError("Result must be returned by the decorated function") + payload = { + "application_id": self._am_app.id, + "version": self._am_app.version, + "prompt": sys_prompt or "", + "user_query": user_query or "", + "context_docs": context or [], + "output": result + } + aimon_response = self.client.analyze.create(body=[payload]) + return aimon_response, result + + def __call__(self, func): + @wraps(func) + def wrapper(context=None, sys_prompt=None, user_query=None, *args, **kwargs): + + if self.evaluation_name is not None: + return self._run_eval(func, args, kwargs) + else: + # Production mode, run the provided args through the user function + return self._run_production_analysis(func, context, sys_prompt, user_query, args, kwargs) + + return wrapper + + +analyze = Analyze diff --git a/aimon/decorators/common.py b/aimon/decorators/common.py new file mode 100644 index 0000000..d48524b --- /dev/null +++ b/aimon/decorators/common.py @@ -0,0 +1,15 @@ +import os +from aimon import Client + + +# A singleton class that instantiates the Aimon client once +# and provides a method to get the client instance +class AimonClientSingleton: + _instance = None + + @staticmethod + def get_instance(api_key=None): + if AimonClientSingleton._instance is None: + api_key = os.getenv('AIMON_API_KEY') if not api_key else api_key + AimonClientSingleton._instance = Client(auth_header="Bearer {}".format(api_key)) + return AimonClientSingleton._instance diff --git a/aimon/decorators/detect.py b/aimon/decorators/detect.py new file mode 100644 index 0000000..6c670ed --- /dev/null +++ b/aimon/decorators/detect.py @@ -0,0 +1,107 @@ +from functools import wraps + +from .common import AimonClientSingleton + + +class DetectWithQueryFuncReturningContext(object): + DEFAULT_CONFIG = {'hallucination': {'detector_name': 'default'}} + + def __init__(self, api_key=None, config=None): + self.client = AimonClientSingleton.get_instance(api_key) + self.config = config if config else self.DEFAULT_CONFIG + + def __call__(self, func): + @wraps(func) + def wrapper(user_query, *args, **kwargs): + result, context = func(user_query, *args, **kwargs) + + if result is None or context is None: + raise ValueError("Result and context must be returned by the decorated function") + + data_to_send = [{ + "user_query": user_query, + "context": context, + "generated_text": result, + "config": self.config + }] + + aimon_response = self.client.inference.detect(body=data_to_send)[0] + return result, context, aimon_response + + return wrapper + + +class DetectWithQueryInstructionsFuncReturningContext(DetectWithQueryFuncReturningContext): + def __call__(self, func): + @wraps(func) + def wrapper(user_query, instructions, *args, **kwargs): + result, context = func(user_query, instructions, *args, **kwargs) + + if result is None or context is None: + raise ValueError("Result and context must be returned by the decorated function") + + data_to_send = [{ + "user_query": user_query, + "context": context, + "generated_text": result, + "instructions": instructions, + "config": self.config + }] + + aimon_response = self.client.inference.detect(body=data_to_send)[0] + return result, context, aimon_response + + return wrapper + + +# Another class but does not include instructions in the wrapper call +class DetectWithContextQuery(object): + DEFAULT_CONFIG = {'hallucination': {'detector_name': 'default'}} + + def __init__(self, api_key=None, config=None): + self.client = AimonClientSingleton.get_instance(api_key) + self.config = config if config else self.DEFAULT_CONFIG + + def __call__(self, func): + @wraps(func) + def wrapper(context, user_query, *args, **kwargs): + result = func(context, user_query, *args, **kwargs) + + if result is None: + raise ValueError("Result must be returned by the decorated function") + + data_to_send = [{ + "context": context, + "user_query": user_query, + "generated_text": result, + "config": self.config + }] + + aimon_response = self.client.inference.detect(body=data_to_send)[0] + return result, aimon_response + + return wrapper + + +class DetectWithContextQueryInstructions(DetectWithContextQuery): + def __call__(self, func): + @wraps(func) + def wrapper(context, user_query, instructions, *args, **kwargs): + result = func(context, user_query, instructions, *args, **kwargs) + + if result is None: + raise ValueError("Result must be returned by the decorated function") + + data_to_send = [{ + "context": context, + "user_query": user_query, + "generated_text": result, + "instructions": instructions, + "config": self.config + }] + + aimon_response = self.client.inference.detect(body=data_to_send)[0] + return result, aimon_response + + return wrapper + diff --git a/examples/aimon_chatbot_demo.py b/examples/aimon_chatbot_demo.py new file mode 100644 index 0000000..c87e45d --- /dev/null +++ b/examples/aimon_chatbot_demo.py @@ -0,0 +1,154 @@ +import streamlit as st +import openai +from llama_index.llms.openai import OpenAI +from llama_index.core import VectorStoreIndex, Settings +from llama_index.core.memory import ChatMemoryBuffer +from llama_index.core import StorageContext, load_index_from_storage +from llama_index.readers.web import SimpleWebPageReader +from aimon import DetectWithQueryInstructionsFuncReturningContext +from aimon import AuthenticationError +import logging +import os + +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s') +st.set_page_config(page_title="AIMon Chatbot Demo", page_icon="🦙", layout="centered", initial_sidebar_state="auto", + menu_items=None) + +aimon_config = {'hallucination': {'detector_name': 'default'}, 'instruction_adherence': {'detector_name': 'default'}} +detect = DetectWithQueryInstructionsFuncReturningContext(st.secrets.aimon_api_key, aimon_config) + + +@st.cache_resource(show_spinner=False) +def load_data(): + index_file_dir = "./data/PG" + index_file_persisted = index_file_dir + "/persisted" + logging.info("Creating OpenAI LLM...") + Settings.llm = OpenAI( + model="gpt-4o-mini", + temperature=0.2, + system_prompt="""You are an expert on + answering questions on Essays and your + job is to answer questions related to this domain. Your answers should be based on + facts – do not hallucinate features.""", + ) + logging.info("Finished creating OpenAI LLM...") + Settings.chunk_size = 256 + Settings.chunk_overlap = 50 + if os.path.exists(index_file_persisted): + logging.info("Loading index from disk...") + # Rebuild storage context + storage_context = StorageContext.from_defaults(persist_dir=index_file_persisted) + # Load index + rindex = load_index_from_storage(storage_context) + return rindex + logging.info("Creating index from documents...") + docs = SimpleWebPageReader(html_to_text=True).load_data(["http://paulgraham.com/worked.html"]) + + rindex = VectorStoreIndex.from_documents(docs) + # Save the newly created index to disk + rindex.storage_context.persist(persist_dir=index_file_persisted) + logging.info("Finished creating index and saving to disk...") + return rindex + + +def get_source_docs(chat_response): + contexts = [] + relevance_scores = [] + if hasattr(chat_response, 'source_nodes'): + for node in chat_response.source_nodes: + if hasattr(node, 'node') and hasattr(node.node, 'text') and hasattr(node, + 'score') and node.score is not None: + contexts.append(node.node.text) + relevance_scores.append(node.score) + elif hasattr(node, 'text') and hasattr(node, 'score') and node.score is not None: + contexts.append(node.text) + relevance_scores.append(node.score) + else: + logging.info("Node does not have required attributes.") + else: + logging.info("No source_nodes attribute found in the chat response.") + return contexts, relevance_scores + + +def split_into_paragraphs(text): + import re + # Normalize newlines + text = text.replace('\r\n', '\n').replace('\r', '\n') + # Replace single newlines within paragraphs with a space + text = re.sub(r'(? 0: + st.json(am_res_json) + st.json({"context": context}, expanded=False) + message.update({'aimon_response': am_res_json, 'context': {"text": context}}) + # Add response to message history + st.session_state.messages.append(message) + + +try: + execute() +except AuthenticationError as e: + st.error("Authentication error. Please check your AIMon API key.") diff --git a/examples/notebooks/aimon_decorators_langchain_summarization_0_5_0.ipynb b/examples/notebooks/aimon_decorators_langchain_summarization_0_5_0.ipynb new file mode 100644 index 0000000..0028728 --- /dev/null +++ b/examples/notebooks/aimon_decorators_langchain_summarization_0_5_0.ipynb @@ -0,0 +1,247 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "6e6a72d8-c7ab-4393-ad0d-9edc06159be8", + "metadata": {}, + "outputs": [], + "source": [ + "from aimon import Analyze, Application, Model" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "244a9542-8b05-440f-996d-4ef6919f6c08", + "metadata": {}, + "outputs": [], + "source": [ + "openai_api_key = \"OPEN AI API KEY\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "790a85fa-3026-4ea9-94e4-8bbb22cdb6b8", + "metadata": {}, + "outputs": [], + "source": [ + "analyze_eval = Analyze(\n", + " Application(\"app_jun18_2024\"),\n", + " Model(\"my_gpt4_model_fine_tuned\", \"GPT-4\"), \n", + " api_key=\"AIMON API KEY\",\n", + " evaluation_name=\"simple_eval\",\n", + " dataset_collection_name=\"my_first_dataset_collection241\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "d5c3e5f0-7611-4e44-ba32-b721fba56218", + "metadata": {}, + "outputs": [], + "source": [ + "analyze_prod = Analyze(\n", + " Application(\"llm_marketing_summarization_app\"), \n", + " Model(\"my_gpt4_model_v2\", \"GPT-4\"), \n", + " api_key=\"AIMON API KEY\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "797a4ade-8083-4f67-a762-430f205c83b5", + "metadata": {}, + "source": [ + "### Evaluation\n", + "\n", + "We will run an evaluation the example below that uses Langchain to summarize documents using OpenAI." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "af98abfc-c04d-4cc7-ba3c-62f550de0c99", + "metadata": {}, + "outputs": [], + "source": [ + "# Lanchain app example\n", + "from langchain.text_splitter import CharacterTextSplitter\n", + "from langchain.docstore.document import Document\n", + "from langchain.llms.openai import OpenAI\n", + "from langchain.chains.summarize import load_summarize_chain\n", + "\n", + "@analyze_eval\n", + "def run_application_eval_mode(source_text=None, prompt=None, user_query=None, eval_run=None):\n", + " # Split the source text\n", + " text_splitter = CharacterTextSplitter()\n", + " texts = text_splitter.split_text(source_text)\n", + " \n", + " # Create Document objects for the texts\n", + " docs = [Document(page_content=t) for t in texts[:3]]\n", + " \n", + " # Initialize the OpenAI module, load and run the summarize chain\n", + " llm = OpenAI(temperature=0, openai_api_key=openai_api_key)\n", + " chain = load_summarize_chain(llm, chain_type=\"map_reduce\")\n", + " return chain.run(docs)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "bcdddfa8-43c7-446a-9337-3ad0f16a015e", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/preetamjoshi/projects/aimon/pj_aimon_rely/examples/chbt/lib/python3.9/site-packages/langchain_core/_api/deprecation.py:139: LangChainDeprecationWarning: The class `OpenAI` was deprecated in LangChain 0.0.10 and will be removed in 0.3.0. An updated version of the class exists in the langchain-openai package and should be used instead. To use it run `pip install -U langchain-openai` and import as `from langchain_openai import OpenAI`.\n", + " warn_deprecated(\n", + "/Users/preetamjoshi/projects/aimon/pj_aimon_rely/examples/chbt/lib/python3.9/site-packages/langchain_core/_api/deprecation.py:139: LangChainDeprecationWarning: The method `Chain.run` was deprecated in langchain 0.1.0 and will be removed in 0.3.0. Use invoke instead.\n", + " warn_deprecated(\n" + ] + }, + { + "data": { + "text/plain": [ + "[(' Acme recently launched version 2.1 of their Python library, which has deep integrations with the Python ecosystem and has been proven to be beneficial for developers. This new version includes features like async support and improved error handling.',\n", + " AnalyzeCreateResponse(message='Data successfully sent to AIMon.')),\n", + " ('\\n\\nTo configure the Acme python client, environment variables must be set up and dependencies must be installed. Detailed instructions for both basic and advanced setups can be found in the official documentation.',\n", + " AnalyzeCreateResponse(message='Data successfully sent to AIMon.')),\n", + " (' The Acme python client is compatible with Python 3.6+ and multiple databases, including MySQL, PostgreSQL, and MongoDB. It is also suitable for cross-language projects with Node.js.',\n", + " AnalyzeCreateResponse(message='Data successfully sent to AIMon.')),\n", + " (' The Acme python client may have installation, package conflicts, and connectivity issues. Troubleshooting involves checking the Python environment, dependencies, and log files, with specific error resolutions available in the online help section.',\n", + " AnalyzeCreateResponse(message='Data successfully sent to AIMon.')),\n", + " (' Acme recently launched version 2.1 of their Python library, which has deep integrations with the Python ecosystem and has been proven to be beneficial for developers. This new version includes features like async support and improved error handling.',\n", + " AnalyzeCreateResponse(message='Data successfully sent to AIMon.')),\n", + " ('\\n\\nTo configure the Acme python client, environment variables must be set up and dependencies must be installed. Detailed instructions for both basic and advanced setups can be found in the official documentation.',\n", + " AnalyzeCreateResponse(message='Data successfully sent to AIMon.')),\n", + " (' The Acme python client is compatible with Python 3.6+ and multiple databases, including MySQL, PostgreSQL, and MongoDB. It is also suitable for cross-language projects with Node.js.',\n", + " AnalyzeCreateResponse(message='Data successfully sent to AIMon.')),\n", + " (' The Acme python client may have installation, package conflicts, and connectivity issues. Troubleshooting involves checking the Python environment, dependencies, and log files, with specific error resolutions available in the online help section.',\n", + " AnalyzeCreateResponse(message='Data successfully sent to AIMon.'))]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "run_application_eval_mode()" + ] + }, + { + "cell_type": "markdown", + "id": "8f4ac734-ff30-4000-a410-65228e35fca8", + "metadata": {}, + "source": [ + "### Production\n", + "\n", + "We will monitor the example below that uses Langchain to summarize documents using OpenAI." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "44438e7f-5652-46b5-9244-cbf2977d9d48", + "metadata": {}, + "outputs": [], + "source": [ + "# Lanchain app example\n", + "from langchain.text_splitter import CharacterTextSplitter\n", + "from langchain.docstore.document import Document\n", + "from langchain.llms.openai import OpenAI\n", + "from langchain.chains.summarize import load_summarize_chain\n", + "\n", + "@analyze_prod\n", + "def run_application(source_text, prompt=None, user_query=None, eval_run=None):\n", + " # Split the source text\n", + " text_splitter = CharacterTextSplitter()\n", + " texts = text_splitter.split_text(source_text)\n", + " \n", + " # Create Document objects for the texts\n", + " docs = [Document(page_content=t) for t in texts[:3]]\n", + " \n", + " # Initialize the OpenAI module, load and run the summarize chain\n", + " llm = OpenAI(temperature=0, openai_api_key=openai_api_key)\n", + " chain = load_summarize_chain(llm, chain_type=\"map_reduce\")\n", + " return chain.run(docs)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "bb81a8ad-e10a-43f5-9682-844d9ab2ccb4", + "metadata": {}, + "outputs": [], + "source": [ + "source_text = \"\"\"\n", + "Large Language Models (LLMs) have become integral to automating and enhancing various business processes. \n", + "However, a significant challenge these models face is the concept of \\\"hallucinations\\\" - outputs that, \n", + "although fluent and confident, are factually incorrect or nonsensical. For enterprises relying on AI \n", + "for decision-making, content creation, or customer service, these hallucinations can undermine credibility, \n", + "spread misinformation, and disrupt operations. Recently, AirCanada lost a court case due to hallucinations \n", + "in its chatbot [7]. Also, the 2024 Edelman Trust Barometer reported a drop in trust in AI companies from \n", + "61% to 53% compared to 90% 8 years ago [8]. Recognizing the urgency of the issue, we have developed a \n", + "state-of-the-art system designed for both offline and online detection of hallucinations, ensuring higher \n", + "reliability and trustworthiness in LLM outputs.\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "1e0dc9d7-e0b0-4a05-8967-0e06179486a3", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(AnalyzeCreateResponse(message='Data successfully sent to AIMon.'),\n", + " '\\n\\nLLMs are commonly used in businesses, but they can produce incorrect or nonsensical outputs, leading to a decrease in trust in AI. To solve this problem, a new system has been created to detect and prevent these \"hallucinations,\" making LLM outputs more reliable and trustworthy.')" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "run_application(source_text, \"Langhchain based summarization of documents\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5515eafd-8644-4792-a69e-23625a026c6c", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/notebooks/aimon_sdk_langchain_summarization.ipynb b/examples/notebooks/aimon_sdk_langchain_summarization.ipynb index c57824a..393efd8 100644 --- a/examples/notebooks/aimon_sdk_langchain_summarization.ipynb +++ b/examples/notebooks/aimon_sdk_langchain_summarization.ipynb @@ -396,7 +396,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.9.0" } }, "nbformat": 4, diff --git a/examples/notebooks/aimon_sdk_langchain_summarization_0_5_0.ipynb b/examples/notebooks/aimon_sdk_langchain_summarization_0_5_0.ipynb index 657387f..9a8d975 100644 --- a/examples/notebooks/aimon_sdk_langchain_summarization_0_5_0.ipynb +++ b/examples/notebooks/aimon_sdk_langchain_summarization_0_5_0.ipynb @@ -503,7 +503,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.4" + "version": "3.9.0" } }, "nbformat": 4, diff --git a/examples/requirements_chatbot.txt b/examples/requirements_chatbot.txt new file mode 100644 index 0000000..d4bc1c3 --- /dev/null +++ b/examples/requirements_chatbot.txt @@ -0,0 +1,4 @@ +llama-index +llama-index-readers-web +streamlit +