Spaces:
Running
Running
# app_hybrid_llm.py | |
import os | |
import re | |
import numpy as np | |
import faiss | |
import gradio as gr | |
import openai | |
from openai import OpenAI | |
from langchain.text_splitter import CharacterTextSplitter | |
from sentence_transformers import SentenceTransformer | |
DARTMOUTH_CHAT_API_KEY = os.getenv('DARTMOUTH_CHAT_API_KEY') | |
if DARTMOUTH_CHAT_API_KEY is None: | |
raise ValueError("DARTMOUTH_CHAT_API_KEY not set.") | |
MODEL = "openai.gpt-4o-2024-08-06" | |
client = OpenAI( | |
base_url="https://chat.dartmouth.edu/api", # Replace with your endpoint URL | |
api_key=DARTMOUTH_CHAT_API_KEY, # Replace with your API key, if required | |
) | |
# --- Load and Prepare Data --- | |
with open("gen_agents.txt", "r", encoding="utf-8") as f: | |
full_text = f.read() | |
text_splitter = CharacterTextSplitter(separator="\n\n", chunk_size=512, chunk_overlap=20) | |
docs = text_splitter.create_documents([full_text]) | |
passages = [doc.page_content for doc in docs] | |
embedder = SentenceTransformer('all-MiniLM-L6-v2') | |
passage_embeddings = embedder.encode(passages, convert_to_tensor=False, show_progress_bar=True) | |
passage_embeddings = np.array(passage_embeddings).astype("float32") | |
d = passage_embeddings.shape[1] | |
index = faiss.IndexFlatL2(d) | |
index.add(passage_embeddings) | |
# --- Provided Functions --- | |
def retrieve_passages(query, embedder, index, passages, top_k=3): | |
query_embedding = embedder.encode([query], convert_to_tensor=False) | |
query_embedding = np.array(query_embedding).astype('float32') | |
distances, indices = index.search(query_embedding, top_k) | |
retrieved = [passages[i] for i in indices[0]] | |
return retrieved | |
def process_llm_output_with_references(text, passages): | |
""" | |
Replace tokens like <<PASSAGE_1>> in the LLM output with HTML block quotes. | |
""" | |
def replacement(match): | |
num = int(match.group(1)) | |
if 0 <= num < len(passages): | |
passage_text = passages[num - 1] | |
return (f"<blockquote style='background: #ffffff; color: #000000; padding: 10px; " | |
f"border-left: 5px solid #ccc; margin: 10px 0; font-size: 14px;'>{passage_text}</blockquote>") | |
return match.group(0) | |
return re.sub(r"<<PASSAGE_(\d+)>>", replacement, text) | |
def generate_answer_with_references(query, retrieved_text): | |
""" | |
Generate an answer using GPT-4 with reference tokens. | |
""" | |
context_str = "\n".join([f"<<PASSAGE_{i}>>: \"{passage}\"" for i, passage in enumerate(retrieved_text)]) | |
messages = [ | |
{"role": "system", "content": "You are a knowledgeable technical assistant."}, | |
{"role": "user", "content": ( | |
f"Using the following textbook passages as reference:\n{context_str}\n\n" | |
"In your answer, include passage block quotes as references. " | |
"Refer to the passages using tokens such as <<PASSAGE_0>>, <<PASSAGE_1>>, etc. " | |
"They should appear after complete thoughts on a new line.\n\n" | |
f"Answer the question: {query}" | |
)} | |
] | |
response = client.chat.completions.create( | |
model=MODEL, | |
messages=messages, | |
) | |
answer = response.choices[0].message.content.strip() | |
return answer | |
# --- Gradio App Function --- | |
def get_hybrid_output(query): | |
retrieved = retrieve_passages(query, embedder, index, passages, top_k=3) | |
hybrid_raw = generate_answer_with_references(query, retrieved) | |
hybrid_processed = process_llm_output_with_references(hybrid_raw, retrieved) | |
return f"<div style='white-space: pre-wrap;'>{hybrid_processed}</div>" | |
def clear_output(): | |
return "" | |
# --- Custom CSS --- | |
custom_css = """ | |
body { | |
background-color: #343541 !important; | |
color: #ECECEC !important; | |
margin: 0; | |
padding: 0; | |
font-family: 'Inter', sans-serif; | |
} | |
#container { | |
max-width: 900px; | |
margin: 0 auto; | |
padding: 20px; | |
} | |
label { | |
color: #ECECEC; | |
font-weight: 600; | |
} | |
textarea, input { | |
background-color: #40414F; | |
color: #ECECEC; | |
border: 1px solid #565869; | |
} | |
button { | |
background-color: #565869; | |
color: #ECECEC; | |
border: none; | |
font-weight: 600; | |
transition: background-color 0.2s ease; | |
} | |
button:hover { | |
background-color: #6e7283; | |
} | |
.output-box { | |
border: 1px solid #565869; | |
border-radius: 4px; | |
padding: 10px; | |
margin-top: 8px; | |
background-color: #40414F; | |
} | |
""" | |
# --- Build Gradio Interface --- | |
with gr.Blocks(css=custom_css) as demo: | |
with gr.Column(elem_id="container"): | |
gr.Markdown("## Anonymous Chatbot\n### Loaded Article: Generative Agents - Interactive Simulacra of Human Behavior (Park et al. 2023)\n [https://arxiv.org/pdf/2304.03442](https://arxiv.org/pdf/2304.03442)") | |
gr.Markdown("Enter any questions about the article above in the prompt!") | |
query_input = gr.Textbox(label="Query", placeholder="Enter your query here...", lines=1) | |
with gr.Column(): | |
submit_button = gr.Button("Submit") | |
clear_button = gr.Button("Clear") | |
output_box = gr.HTML(label="Output", elem_classes="output-box") | |
submit_button.click(fn=get_hybrid_output, inputs=query_input, outputs=output_box) | |
clear_button.click(fn=clear_output, inputs=[], outputs=output_box) | |
demo.launch() | |