Skip to content

LCEL with LLamaCPP #125

Description

@ahuang11
"""
Demonstrates how to use the `ChatInterface` to create a chatbot using
[LangChain Expression Language](https://python.langchain.com/docs/expression_language/) (LCEL)
with streaming and memory.
"""

from operator import itemgetter

import panel as pn
from transformers import AutoTokenizer
from huggingface_hub import hf_hub_download
from langchain.memory import ConversationTokenBufferMemory
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_core.runnables import RunnableLambda, RunnablePassthrough
from langchain_community.llms.llamacpp import LlamaCpp

pn.extension()

TOKENIZER_REPO_ID = "HuggingFaceH4/zephyr-7b-beta"
REPO_ID = "TheBloke/zephyr-7B-beta-GGUF"
FILENAME = "zephyr-7b-beta.Q5_K_M.gguf"
SYSTEM_PROMPT = "Be a helpful chatbot."
PROMPT_TEMPLATE = """
<|system|>
{system_prompt}</s>
{chat_history}
<|user|>
{user_input}</s>
<|assistant|>
""".strip()
ROLE_MAPPING = {
    "system": "system",
    "human": "user",
    "ai": "assistant",
}


def load_llm(repo_id: str = REPO_ID, filename: str = FILENAME, **kwargs):
    model_path = hf_hub_download(repo_id=repo_id, filename=filename)
    llm = LlamaCpp(model_path=model_path, **kwargs)
    return llm


def callback(contents: str, user: str, instance: pn.chat.ChatInterface):
    message = ""
    inputs = {"user_input": contents}
    for token in chain.stream(inputs):
        message += token
        yield message
    memory.save_context(inputs, {"output": message})


def apply_chat_template_to_history(history):
    conversation = [
        {"role": ROLE_MAPPING[message.type], "content": message.content}
        for message in history["chat_history"]
    ]
    tokenizer = AutoTokenizer.from_pretrained(TOKENIZER_REPO_ID)
    chat_history = tokenizer.apply_chat_template(conversation, tokenize=False)
    return chat_history


model_path = hf_hub_download(repo_id=REPO_ID, filename=FILENAME)
llm = LlamaCpp(
    model_path=model_path,
    streaming=True,
    n_gpu_layers=1,
    temperature=0.75,
    max_tokens=1024,
    n_ctx=8192,
    top_p=1,
)
memory = ConversationTokenBufferMemory(
    return_messages=True,
    llm=llm,
    memory_key="chat_history",
    max_token_limit=8192 - 1024,
)
prompt = PromptTemplate.from_template(
    PROMPT_TEMPLATE, partial_variables={"system_prompt": SYSTEM_PROMPT}
)

output_parser = StrOutputParser()
chain = (
    RunnablePassthrough.assign(
        chat_history=RunnableLambda(memory.load_memory_variables)
        | itemgetter("chat_history")
    )
    | RunnablePassthrough.assign(chat_history=apply_chat_template_to_history)
    | prompt
    | llm
    | output_parser
)

chat_interface = pn.chat.ChatInterface(
    pn.chat.ChatMessage(
        "Offer a topic and Mistral will try to be funny!", user="System"
    ),
    callback=callback,
    callback_user="Mistral",
    callback_exception="verbose",
)
chat_interface.servable()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions