Skip to content

Commit

Permalink
refactor: rename time_frame to period
Browse files Browse the repository at this point in the history
  • Loading branch information
Colerar committed Oct 28, 2023
1 parent a846c13 commit 05da5a6
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 60 deletions.
30 changes: 13 additions & 17 deletions backend/funix/decorator/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,41 +259,37 @@ class LimitSource(Enum):

class Limiter:
call_history: dict
# How many calls client can send between each interval set by `time_frame`
# How many calls client can send between each interval set by `period`
max_calls: int
# Max call interval time, in seconds
time_frame: int
period: int
source: LimitSource

def __init__(
self,
max_calls: int = 10,
time_frame: int = 60,
period: int = 60,
source: LimitSource = LimitSource.SESSION,
):
if type(max_calls) is not int:
raise TypeError("type of `max_calls` is not int")
if type(time_frame) is not int:
raise TypeError("type of `time_frame` is not int")
if type(period) is not int:
raise TypeError("type of `period` is not int")
if type(source) is not LimitSource:
raise TypeError("type of `source` is not LimitSource")

self.source = source
self.max_calls = max_calls
self.time_frame = time_frame
self.period = period
self.call_history = {}

@staticmethod
def ip(max_calls: int, time_frame: int = 60):
return Limiter(
max_calls=max_calls, time_frame=time_frame, source=LimitSource.IP
)
def ip(max_calls: int, period: int = 60):
return Limiter(max_calls=max_calls, period=period, source=LimitSource.IP)

@staticmethod
def session(max_calls: int, time_frame: int = 60):
return Limiter(
max_calls=max_calls, time_frame=time_frame, source=LimitSource.SESSION
)
def session(max_calls: int, period: int = 60):
return Limiter(max_calls=max_calls, period=period, source=LimitSource.SESSION)

def rate_limit(self) -> Optional[Response]:
call_history = self.call_history
Expand All @@ -309,12 +305,12 @@ def rate_limit(self) -> Optional[Response]:
queue = call_history[source]
current_time = time.time()

while len(queue) > 0 and current_time - queue[0] > self.time_frame:
while len(queue) > 0 and current_time - queue[0] > self.period:
queue.popleft()

if len(queue) >= self.max_calls:
time_passed = current_time - queue[0]
time_to_wait = int(self.time_frame - time_passed)
time_to_wait = int(self.period - time_passed)
error_message = (
f"Rate limit exceeded. Please try again in {time_to_wait} seconds."
)
Expand Down Expand Up @@ -1454,7 +1450,7 @@ def verify_secret():
verify_secret_endpoint(verify_secret)
verify_secret_id(verify_secret)

limiters: Optional[list[Limiter]] = list() # was a none
limiters: Optional[list[Limiter]] = list() # was a none

if isinstance(rate_limit, Limiter):
limiters = list()
Expand Down
14 changes: 8 additions & 6 deletions examples/AI/DallE.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
import os
import os

import openai # pip install openai

openai.api_key = os.environ.get("OPENAI_KEY")

import IPython.display

import funix
import funix


@funix.funix( # Funix.io, the laziest way to build web apps in Python
title="OpenAI: Dall-E",
description="""Generate an image with DALL-E in [Funix](http://funix.io), the minimalist way to build apps in Python. An OpenAI key needs to be set. A rate limit is applied. """,
rate_limit=funix.decorator.Limiter.session(max_calls=1, time_frame=60*60*24),
rate_limit=funix.decorator.Limiter.session(max_calls=1, period=60 * 60 * 24),
show_source=True,
)
def dalle(Prompt: str = "a cat on a red jeep") -> IPython.display.Image:
response = openai.Image.create(prompt=Prompt, size="256x256")
return response["data"][0]["url"]


# **Note:**
# * An OpenAI key needs to be set in the environment variable OPENAI_KEY.
# **Note:**
# * An OpenAI key needs to be set in the environment variable OPENAI_KEY.
# * A rate limit of 1 call per day per browser session is set.

# Like us? Please star us on [GitHub](https://github.com/TexteaInc/funix)].
# Like us? Please star us on [GitHub](https://github.com/TexteaInc/funix)].
6 changes: 3 additions & 3 deletions examples/AI/chatGPT_advanced.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import openai

# openai.api_key = os.environ.get("OPENAI_KEY")
# Disable this app from being called in public hosted examples
# Disable this app from being called in public hosted examples

import funix

Expand All @@ -32,7 +32,7 @@ class PromptBox(str):
"conditional_visible": [
{"when": {"show_advanced_options": True}, "show": ["max_tokens", "model"]}
],
"rate_limit": funix.decorator.Limiter.session(max_calls=2, time_frame=60*60*24),
"rate_limit": funix.decorator.Limiter.session(max_calls=2, period=60 * 60 * 24),
}


Expand All @@ -51,4 +51,4 @@ def ChatGPT_advanced(
model=model,
max_tokens=max_tokens,
)
return completion["choices"][0]["message"]["content"]
return completion["choices"][0]["message"]["content"]
16 changes: 10 additions & 6 deletions examples/AI/chatGPT_lazy.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import os # Python's native
import openai # you cannot skip it
import os # Python's native
import openai # you cannot skip it

openai.api_key = os.environ.get("OPENAI_KEY")

import funix
@funix.funix(rate_limit=funix.decorator.Limiter.session(max_calls=2, time_frame=60*60*24))

# If in lazy model, the two lines above should be commented out.

@funix.funix(
rate_limit=funix.decorator.Limiter.session(max_calls=2, period=60 * 60 * 24)
)

# If in lazy model, the two lines above should be commented out.
# Lazy model means run this command
# $ funix -l chatGPT_lazy.py


def ChatGPT(prompt: str) -> str:
completion = openai.ChatCompletion.create(
messages=[{"role": "user", "content": prompt}],
model="gpt-3.5-turbo"
messages=[{"role": "user", "content": prompt}], model="gpt-3.5-turbo"
)
return completion["choices"][0]["message"]["content"]
26 changes: 13 additions & 13 deletions examples/AI/chatGPT_muilti_turn.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import os
import openai
import openai

openai.api_key = os.environ.get("OPENAI_KEY")

import IPython

messages = [] # list of dicts, dict keys: role, content, system
messages = [] # list of dicts, dict keys: role, content, system


def print_messages_html(messages):
printout = ""
Expand All @@ -16,22 +18,20 @@ def print_messages_html(messages):
printout += f'<div style="position: relative; left: {left}; width: 70%"><b>{name}</b>: {message["content"]}</div>'
return printout

import funix

import funix


@funix.funix(
description="""Multi-turn chat with ChatGPT in [Funix](http://funix.io), the minimalist way to build apps in Python. An OpenAI key needs to be set. A rate limit is applied. """,
rate_limit=funix.decorator.Limiter.session(max_calls=3, time_frame=60*60*24),
direction="column-reverse") # input is below log
def ChatGPT_multi_turn(current_message: str) -> IPython.display.HTML:
rate_limit=funix.decorator.Limiter.session(max_calls=3, period=60 * 60 * 24),
direction="column-reverse",
) # input is below log
def ChatGPT_multi_turn(current_message: str) -> IPython.display.HTML:
current_message = current_message.strip()
messages.append({"role": "user", "content": current_message})
completion = openai.ChatCompletion.create(
messages=messages,
model='gpt-3.5-turbo'
)
completion = openai.ChatCompletion.create(messages=messages, model="gpt-3.5-turbo")
chatgpt_response = completion["choices"][0]["message"]["content"]
messages.append({"role": "assistant", "content": chatgpt_response})

return print_messages_html(messages)



32 changes: 17 additions & 15 deletions examples/AI/huggingface.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,42 @@
# Building a one-turn chatbot from any causal language model hosted on HuggingFace using free Inference API

# Copyleft 2023 Forrest Sheng Bao http://forrestbao.github.io
# The purpose of this code is to demonstrate the use of Funix to turn a simple API call function to a web app.
# Copyleft 2023 Forrest Sheng Bao http://forrestbao.github.io
# The purpose of this code is to demonstrate the use of Funix to turn a simple API call function to a web app.

# To turn this code into a web app, run the following command in the terminal:
# funix huggingface.py -l # the -l flag is very important. It tells Funix to load the function as a web app.

import os, json, typing # Python's native
import requests # pip install requests
import os, json, typing # Python's native
import requests # pip install requests
import ipywidgets

# API_TOKEN = os.getenv("HF_TOKEN") # "Please set your API token as an environment variable named HF_TOKEN. You can get your token from https://huggingface.co/settings/token"

import funix


@funix.funix(
description="""Talk to LLMs hosted at HuggingFace. A HuggingFace token needs to be set in the environment variable HF_TOKEN.""",
# rate_limit=funix.decorator.Limiter.session(max_calls=20, time_frame=60*60*24),
# rate_limit=funix.decorator.Limiter.session(max_calls=20, period=60*60*24),
)
def huggingface(
model_name: typing.Literal[
"gpt2",
"bigcode/starcoder",
"google/flan-t5-base"] = "gpt2",
prompt: str = "Who is Einstein?",
API_TOKEN: ipywidgets.Password = None
) -> str:

payload = {"inputs": prompt, "max_tokens":200} # not all models use this query and output formats. Hence, we limit the models above.
"gpt2", "bigcode/starcoder", "google/flan-t5-base"
] = "gpt2",
prompt: str = "Who is Einstein?",
API_TOKEN: ipywidgets.Password = None,
) -> str:
payload = {
"inputs": prompt,
"max_tokens": 200,
} # not all models use this query and output formats. Hence, we limit the models above.

API_URL = f"https://api-inference.huggingface.co/models/{model_name}"
headers = {"Authorization": f"Bearer {API_TOKEN.value}"}

response = requests.post(API_URL, headers=headers, json=payload)

if "error" in response.json():
if "error" in response.json():
return response.json()["error"]
else:
return response.json()[0]["generated_text"]
return response.json()[0]["generated_text"]

0 comments on commit 05da5a6

Please sign in to comment.