diff --git a/zulip/integrations/litelllm/README.md b/zulip/integrations/litelllm/README.md new file mode 100644 index 000000000..81fd645a2 --- /dev/null +++ b/zulip/integrations/litelllm/README.md @@ -0,0 +1,33 @@ +# Summarize topic + +Generate a short summary of the last 100 messages in the provided topic URL. + + +### API Keys + +For testing you need access token from https://huggingface.co/settings/tokens (or set the correct env variable with the access token if using a different model) + +In `~/.zuliprc` add a section named `LITELLM_API_KEYS` and set the api key for the model you are trying to use. +For example: +``` +[LITELLM_API_KEYS] +HUGGINGFACE_API_KEY=YOUR_API_KEY +``` + +### Setup + +```bash +$ pip install -r zulip/integrations/litelllm/requirements.txt +``` + +Just run `zulip/integrations/litelllm/summarize-topic` to generate sample summary. + +```bash +$ zulip/integrations/litelllm/summarize-topic --help +usage: summarize-topic [-h] [--url URL] [--model MODEL] + +options: + -h, --help show this help message and exit + --url URL The URL to fetch content from + --model MODEL The model name to use for summarization +``` diff --git a/zulip/integrations/litelllm/requirements.txt b/zulip/integrations/litelllm/requirements.txt new file mode 100644 index 000000000..f4d085270 --- /dev/null +++ b/zulip/integrations/litelllm/requirements.txt @@ -0,0 +1,2 @@ +zulip +litellm diff --git a/zulip/integrations/litelllm/summarize-topic b/zulip/integrations/litelllm/summarize-topic new file mode 100755 index 000000000..5d536cbd0 --- /dev/null +++ b/zulip/integrations/litelllm/summarize-topic @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 + +import argparse +import os +import sys +import urllib.parse +from configparser import ConfigParser + +from litellm import completion # type: ignore[import-not-found] + +import zulip + +config_file = zulip.get_default_config_filename() +if not config_file: + print("Could not find the Zulip configuration file. Please read the provided README.") + sys.exit() + +client = zulip.Client(config_file=config_file) + +config = ConfigParser() +# Make config parser case sensitive otherwise API keys will be lowercased +# which is not supported by litellm. +# https://docs.python.org/3/library/configparser.html#configparser.ConfigParser.optionxform +config.optionxform = str # type: ignore[assignment, method-assign] + +with open(config_file) as f: + config.read_file(f, config_file) + +# Set all the keys in `LITELLM_API_KEYS` as environment variables. +for key in config["LITELLM_API_KEYS"]: + print("Setting key:", key) + os.environ[key] = config["LITELLM_API_KEYS"][key] + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument( + "--url", + type=str, + help="The URL to fetch content from", + default="https://chat.zulip.org/#narrow/stream/101-design/topic/more.20user.20indicators", + ) + parser.add_argument( + "--model", + type=str, + help="The model name to use for summarization", + default="huggingface/meta-llama/Meta-Llama-3-8B-Instruct", + ) + args = parser.parse_args() + + url = args.url + model = args.model + + base_url, narrow_hash = url.split("#") + narrow_hash_terms = narrow_hash.split("/") + channel = narrow_hash_terms[2].split("-")[1] + topic = narrow_hash_terms[4] + channel = urllib.parse.unquote(channel.replace(".", "%")) + topic = urllib.parse.unquote(topic.replace(".", "%")) + + narrow = [ + {"operator": "channel", "operand": channel}, + {"operator": "topic", "operand": topic}, + ] + + request = { + "anchor": "newest", + "num_before": 100, + "num_after": 0, + "narrow": narrow, + "apply_markdown": False, + } + result = client.get_messages(request) + messages = result["messages"] + + formatted_messages = [ + {"content": f"{message['sender_full_name']}: {message['content']}", "role": "user"} + for message in messages + ] + + # Provide a instruction if using an `Instruct` model. + # There is a 100 token output limit by hugging face. + if "Instruct" in model: + formatted_messages.append( + {"content": "Summarize the above content within 90 words.", "role": "user"} + ) + + # Send formatted messages to the LLM model for summarization + response = completion( + model=model, + messages=formatted_messages, + ) + + print("Server response:\n", response) + print("\n\nGenerated summary for URL:", url) + print("Summary:") + print(response["choices"][0]["message"]["content"])