Skip to content

Commit 7eadbd0

Browse files
author
Preetam Joshi
committed
A few small changes for error handling in the client and the example application.
Getting the Aimon API key from the streamlit app
1 parent 773bd30 commit 7eadbd0

File tree

2 files changed

+61
-47
lines changed

2 files changed

+61
-47
lines changed

src/aimon_rely_client/simple_client.py

Lines changed: 53 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,68 @@
1-
from typing import List, Dict
2-
3-
import requests
4-
51
from functools import wraps
6-
def retry(ExceptionToCheck, tries=5, delay=3, backoff=2, logger=None):
7-
"""Retry calling the decorated function using an exponential backoff.
8-
9-
http://www.saltycrane.com/blog/2009/11/trying-out-retry-decorator-python/
10-
original from: http://wiki.python.org/moin/PythonDecoratorLibrary#Retry
2+
import logging
3+
from typing import Callable, Type, Union, Tuple, Optional, List, Dict
4+
import random
5+
import time
6+
import requests
117

12-
:param ExceptionToCheck: the exception to check. may be a tuple of
13-
exceptions to check
14-
:type ExceptionToCheck: Exception or tuple
15-
:param tries: number of times to try (not retry) before giving up
16-
:type tries: int
17-
:param delay: initial delay between retries in seconds
18-
:type delay: int
19-
:param backoff: backoff multiplier e.g. value of 2 will double the delay
20-
each retry
21-
:type backoff: int
22-
:param logger: logger to use. If None, print
23-
:type logger: logging.Logger instance
8+
def retry(
9+
exception_to_check: Union[Type[BaseException], Tuple[Type[BaseException], ...]],
10+
tries: int = 5,
11+
delay: int = 3,
12+
backoff: int = 2,
13+
logger: Optional[logging.Logger] = None,
14+
log_level: int = logging.WARNING,
15+
re_raise: bool = True,
16+
jitter: float = 0.1
17+
) -> Callable:
2418
"""
25-
def deco_retry(f):
19+
Retry calling the decorated function using an exponential backoff.
2620
27-
@wraps(f)
21+
:param exception_to_check: Exception or a tuple of exceptions to check.
22+
:param tries: Number of times to try (not retry) before giving up.
23+
:param delay: Initial delay between retries in seconds.
24+
:param backoff: Backoff multiplier e.g., a value of 2 will double the delay each retry.
25+
:param logger: Logger to use. If None, print.
26+
:param log_level: Logging level.
27+
:param re_raise: Whether to re-raise the exception after the last retry.
28+
:param jitter: The maximum jitter to apply to the delay as a fraction of the delay.
29+
"""
30+
def deco_retry(func: Callable) -> Callable:
31+
@wraps(func)
2832
def f_retry(*args, **kwargs):
29-
mtries, mdelay = tries, delay
30-
while mtries > 1:
33+
remaining_tries, current_delay = tries, delay
34+
while remaining_tries > 1:
3135
try:
32-
return f(*args, **kwargs)
33-
except ExceptionToCheck as e:
34-
msg = "%s, Retrying in %d seconds..." % (str(e), mdelay)
36+
return func(*args, **kwargs)
37+
except exception_to_check as e:
38+
msg = f"{e}, Retrying in {current_delay} seconds..."
3539
if logger:
36-
#logger.exception(msg) # would print stack trace
37-
logger.warning(msg)
40+
logger.log(log_level, msg)
3841
else:
3942
print(msg)
40-
time.sleep(mdelay)
41-
mtries -= 1
42-
mdelay *= backoff
43-
return f(*args, **kwargs)
43+
time.sleep(current_delay * (1 + jitter * (2 * random.random() - 1)))
44+
remaining_tries -= 1
45+
current_delay *= backoff
4446

45-
return f_retry # true decorator
47+
try:
48+
return func(*args, **kwargs)
49+
except exception_to_check as e:
50+
msg = f"Failed after {tries} tries. {e}"
51+
if logger:
52+
logger.log(log_level, msg)
53+
else:
54+
print(msg)
55+
if re_raise:
56+
raise
4657

58+
return f_retry
4759
return deco_retry
4860

49-
import time
50-
import requests
51-
5261
class RetryableError(Exception):
5362
pass
5463

64+
class InvalidAPIKeyError(Exception):
65+
pass
5566

5667
class SimpleAimonRelyClient(object):
5768
"""
@@ -63,6 +74,8 @@ def __init__(self, api_key: str):
6374
"""
6475
:param api_key: the Aimon Rely API key. If you don't have one, request one by sending an email to info@aimon.ai
6576
"""
77+
if len(api_key) == 0 or "YOUR API KEY" in api_key:
78+
raise InvalidAPIKeyError("Enter a valid Aimon API key. Request it at info@aimon.ai or on Discord.")
6679
self.api_key = api_key
6780

6881
@retry(RetryableError)
@@ -83,6 +96,8 @@ def detect(self, data_to_send: List[Dict[str, str]]):
8396
response = requests.post(self.URL, json=data_to_send, headers=headers, timeout=30)
8497
if response.status_code in [503, 504]:
8598
raise RetryableError("Status code: {} received".format(response.status_code))
99+
if response.status_code == 401:
100+
raise InvalidAPIKeyError("Use a valid Aimon API key. Request it at info@aimon.ai or on Discord.")
86101
if response.status_code != 200:
87102
raise Exception(f"Error, bad response: {response}")
88103
if len(response.json()) == 0 or 'error' in response.json() or 'error' in response.json()[0]:

src/examples/langchain_summarization_app.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,24 @@
99
from langchain.llms.openai import OpenAI
1010
from langchain.chains.summarize import load_summarize_chain
1111

12-
from aimon_rely_client.simple_client import SimpleAimonRelyClient
13-
14-
API_KEY = "YOUR API KEY HERE"
12+
from aimon_rely_client.simple_client import SimpleAimonRelyClient, InvalidAPIKeyError
1513

1614
# Streamlit app
1715
st.title('LangChain Text Summarizer')
1816

1917
# Get OpenAI API key and source text input
2018
openai_api_key = st.text_input("OpenAI API Key", type="password")
19+
aimon_api_key = st.text_input("Aimon API Key", type="password")
2120
source_text = st.text_area("Source Text", height=200)
2221

23-
aimon_rely_client = SimpleAimonRelyClient(API_KEY)
24-
2522
# Check if the 'Summarize' button is clicked
2623
if st.button("Summarize"):
2724
# Validate inputs
28-
if not openai_api_key.strip() or not source_text.strip():
25+
if not openai_api_key.strip() or not aimon_api_key.strip() or not source_text.strip():
2926
st.write(f"Please complete the missing fields.")
3027
else:
3128
try:
29+
aimon_rely_client = SimpleAimonRelyClient(aimon_api_key)
3230
# Split the source text
3331
text_splitter = CharacterTextSplitter()
3432
texts = text_splitter.split_text(source_text)
@@ -45,20 +43,21 @@
4543
st.header('Summary')
4644
st.write(summary)
4745

48-
# Call Aimon Rely and render response
46+
# Call Aimon Rely to detect hallucinations
4947
ar_response = aimon_rely_client.detect([
5048
{
5149
"context": source_text,
5250
"generated_text": summary
5351
}
5452
])
55-
5653
# You could perform any action based on this reponse here
5754
# ....
5855

5956
# Display the Aimon Rely response
6057
st.header('Aimon Rely - Hallucination Detector Response')
6158
st.json(ar_response)
62-
59+
except InvalidAPIKeyError as ivk:
60+
st.header(":red[ERROR: Add a valid Aimon API key.]")
61+
st.write("Request it at info@aimon.ai or on Discord.")
6362
except Exception as e:
6463
st.write(f"An error occurred: {e}")

0 commit comments

Comments
 (0)