| import threading |
| import queue |
| import tiktoken |
|
|
| from langchain.chat_models import ChatOpenAI |
| from langchain.callbacks.manager import CallbackManager |
| from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler |
|
|
| from openai.error import InvalidRequestError |
|
|
| class ThreadedGenerator: |
| def __init__(self): |
| self.queue = queue.Queue() |
|
|
| def __iter__(self): |
| return self |
|
|
| def __next__(self): |
| item = self.queue.get() |
| if item is StopIteration: raise item |
| return item |
|
|
| def send(self, data): |
| self.queue.put(data) |
|
|
| def close(self): |
| self.queue.put(StopIteration) |
|
|
| class ChainStreamHandler(StreamingStdOutCallbackHandler): |
| def __init__(self, gen): |
| super().__init__() |
| self.gen = gen |
|
|
| def on_llm_new_token(self, token: str, **kwargs): |
| self.gen.send(token) |
|
|
| def run(g, prompts, retries = 0): |
| try: |
| chat = ChatOpenAI( |
| verbose=True, |
| streaming=True, |
| callback_manager=CallbackManager([ChainStreamHandler(g)]), |
| ) |
| chat(prompts) |
| except InvalidRequestError as e: |
| if retries >= 10: |
| raise e |
| else: |
| retries += 1 |
| del prompts[-1] |
| run(g, prompts, retries) |
|
|
| def llm_thread(g, prompts): |
| encoding = tiktoken.encoding_for_model("gpt-3.5-turbo") |
| messages = [] |
| tokens = 0 |
|
|
| for prompt in prompts: |
| tokens += len(encoding.encode(prompt.content)) |
| if tokens >= 4096: |
| break |
| |
| messages.append(prompt) |
|
|
| try: |
| run(g, messages) |
| finally: |
| g.close() |
|
|
|
|
| def chat(prompts): |
| g = ThreadedGenerator() |
| threading.Thread(target=llm_thread, args=(g, prompts)).start() |
| return g |