| | import os |
| | import requests |
| | from datetime import datetime |
| |
|
| | import gradio as gr |
| | from gradio import components |
| |
|
| | import openai |
| | from langchain_openai import ChatOpenAI |
| | from langchain.chains.summarize import load_summarize_chain |
| | from langchain.docstore.document import Document |
| |
|
| | def comment_datetime(comment_json): |
| | dt = datetime.fromisoformat(comment_json["created_at"][:-1]) |
| | return comment_json["user"]["login"] + " commented on " + dt.strftime("%b %d, %Y") + ":" |
| |
|
| | str_format = """ |
| | {author}\n |
| | {comment} |
| | """.strip() |
| |
|
| | def get_comments(url): |
| | response = requests.get(url, headers=None) |
| | json_content = response.json() |
| | comments = "<|endoftext|>".join([str_format.format(author=comment_datetime(x).strip(), comment=x["body"].strip()) for x in json_content]) |
| |
|
| | return comments |
| |
|
| |
|
| | template = """ |
| | ### ISSUE #{issue_num}\n |
| | ### TITLE: {title}\n |
| | ### URL: {html_url}\n |
| | ### LABELS: {labels}\n |
| | ### BODY:\n |
| | {body}\n |
| | ### COMMENTS:\n |
| | {comments}\n |
| | """.strip() |
| |
|
| | def get_full_context(row): |
| | labels = row["labels"].split("<|endoftext|>") |
| | comments = row["comments"].replace("<|endoftext|>", "\n\n") |
| | context = template.format( |
| | issue_num=row["issue_num"], |
| | url=row["url"], |
| | comments_url=row["comments_url"], |
| | html_url=row["html_url"], |
| | title=row["title"], |
| | labels=labels, |
| | body=row["body"], |
| | comments=comments |
| | ) |
| |
|
| | return context |
| |
|
| |
|
| | def get_issue_info(url): |
| | url_items = url.split("/") |
| | url_api = "https://api.github.com/repos/{}/{}/issues/{}".format(url_items[-4], url_items[-3], url_items[-1]) |
| | headers = {"Authorization": f"token {os.getenv('GITHUB_TOKEN')}"} |
| | response = requests.get(url_api, headers=None) |
| | issue = response.json() |
| | issue_short = {k: v for k, v in issue.items() if k in ["id", "url", "comments_url", "html_url", "title", "body"]} |
| | issue_short["labels"] = "<|endoftext|>".join([x["name"] for x in issue["labels"]]) |
| | issue_short["issue_num"] = issue["number"] |
| | issue_short["comment_count"] = issue["comments"] |
| |
|
| | |
| | issue_short["comments"] = get_comments(issue_short["comments_url"]) |
| |
|
| | |
| | context = get_full_context(issue_short) |
| | |
| | return context |
| | |
| |
|
| | def init_chain(openai_api_key): |
| | llm = ChatOpenAI( |
| | model_name="gpt-4o", |
| | temperature=0.0, |
| | openai_api_key=openai_api_key |
| | ) |
| | |
| | chain = load_summarize_chain(llm, chain_type="stuff") |
| |
|
| | return chain |
| |
|
| |
|
| | def get_summary(text, chain): |
| | doc = Document(page_content=text) |
| | summary = chain.invoke([doc])["output_text"].strip() |
| |
|
| | return summary |
| |
|
| |
|
| | template_output = """ |
| | ## SUMMARY ๐ |
| | ### {summary} |
| | *** |
| | ## Source ๐พ |
| | {context} |
| | """.strip() |
| |
|
| | def run_all(openai_api_key, url): |
| | try: |
| | context = get_issue_info(url) |
| | except (IndexError, KeyError) as error: |
| | return "## Invalid Github Issue URL.\n ## See examples below for reference." |
| | |
| | try: |
| | chain = init_chain(openai_api_key) |
| | summary = get_summary(context, chain) |
| | print(summary) |
| | return template_output.format(summary=summary, context=context) |
| | except (ValueError, openai.AuthenticationError) as error: |
| | return "## Invalid OpenAI API key provided." |
| | |
| | html = """ |
| | <h1 style='text-align: center;'>GitHub Issue Summarizer</h1> |
| | <img src="https://octodex.github.com/images/Professortocat_v2.png" width=100 height=100 style="display: block; margin: 0 auto;"> |
| | """.strip() |
| |
|
| | examples = [ |
| | [None, "https://github.com/rust-lang/rust/issues/97362"], |
| | [None, "https://github.com/rust-lang/rust/issues/83788"], |
| | [None, "https://github.com/langchain-ai/langchain/issues/9733"], |
| | [None, "https://github.com/huggingface/transformers/issues/25720"] |
| | ] |
| |
|
| | with gr.Blocks() as demo: |
| | with gr.Row(): |
| | gr.HTML(html) |
| |
|
| | with gr.Row(): |
| | with gr.Column(): |
| | with gr.Row(): |
| | textbox_api_key = components.Textbox(placeholder="sk-...", label="OpenAI API Key", value=None, type="password") |
| | with gr.Row(): |
| | textbox = gr.Textbox(label="Type a GitHub Issue URL:", placeholder="https://github.com/rust-lang/rust/issues/97362", lines=1) |
| | with gr.Row(): |
| | summarize = gr.Button("Summarize", variant="primary") |
| | clear_button = gr.ClearButton() |
| | with gr.Row(): |
| | gr.Examples(examples=examples, inputs=[textbox_api_key, textbox]) |
| | with gr.Column(scale=1, min_width=1000): |
| | summary = gr.Markdown(value="Summary") |
| | summarize.click(run_all, [textbox_api_key, textbox], outputs=summary) |
| | clear_button.click(fn=lambda: [None, None, "Summary"], outputs=[textbox_api_key, textbox, summary]) |
| |
|
| | demo.launch() |