Spaces:
Runtime error
Runtime error
File size: 15,905 Bytes
f8ac491 9bade29 f8ac491 7ab07f3 9bade29 b81234c 7ab07f3 f8ac491 b81234c f8ac491 7ab07f3 f8ac491 9bade29 f8ac491 7ab07f3 f8ac491 7ab07f3 f8ac491 9bade29 7ab07f3 9bade29 7ab07f3 688baf5 7ab07f3 f8ac491 7ab07f3 f8ac491 7ab07f3 f8ac491 688baf5 7ab07f3 f8ac491 7ab07f3 f8ac491 7ab07f3 f8ac491 7ab07f3 f8ac491 7ab07f3 f8ac491 7ab07f3 f8ac491 9bade29 f8ac491 7ab07f3 9bade29 f8ac491 9bade29 f8ac491 9bade29 f8ac491 9bade29 f8ac491 9bade29 7ab07f3 9bade29 f8ac491 1398b01 f8ac491 7ab07f3 f8ac491 9bade29 f8ac491 9bade29 f8ac491 7ab07f3 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
import pandas as pd
import numpy as np
from openai import OpenAI
from sentence_transformers import util, SentenceTransformer
import torch
import time
from time import perf_counter as timer
from datetime import datetime
import textwrap
import json
import gradio as gr
print("Launching")
client = OpenAI()
# Load the enhanced JSON file with summaries
def load_enhanced_json(file_path):
with open(file_path, 'r') as file:
return json.load(file)
enhanced_json_file = "./output/SWCompleteRevisedPDF_enhanced_output.json"
enhanced_data = load_enhanced_json(enhanced_json_file)
# Extract document summary and page summaries
document_summary = enhanced_data.get('document_summary', 'No document summary available.')
page_summaries = {int(page): data['summary'] for page, data in enhanced_data.get('pages', {}).items()}
# Import saved file and view
embeddings_df_save_path = "./output/SWCompleteRevisedPDF_output_embeddings.csv"
print("Loading embeddings.csv")
text_chunks_and_embedding_df_load = pd.read_csv(embeddings_df_save_path)
print("Embedding file loaded")
# Convert the stringified embeddings back to numpy arrays
text_chunks_and_embedding_df_load['embedding'] = text_chunks_and_embedding_df_load['embedding_str'].apply(lambda x: np.array(json.loads(x)))
# Convert texts and embedding df to list of dicts
pages_and_chunks = text_chunks_and_embedding_df_load.to_dict(orient="records")
# Debug: Print the first few rows and column names
print("DataFrame columns:", text_chunks_and_embedding_df_load.columns)
print("\nFirst few rows of the DataFrame:")
print(text_chunks_and_embedding_df_load.head())
# Debug: Print the first item in pages_and_chunks
# print("\nFirst item in pages_and_chunks:")
# print(pages_and_chunks[0])
embedding_model_path = "BAAI/bge-m3"
print("Loading embedding model")
embedding_model = SentenceTransformer(model_name_or_path=embedding_model_path,
device='cpu') # choose the device to load the model to
# Convert embeddings to torch tensor and send to device (note: NumPy arrays are float64, torch tensors are float32 by default)
embeddings = torch.tensor(np.array(text_chunks_and_embedding_df_load["embedding"].tolist()), dtype=torch.float32).to('cpu')
# Define helper function to print wrapped text
def print_wrapped(text, wrap_length=80):
wrapped_text = textwrap.fill(text, wrap_length)
print(wrapped_text)
def hybrid_estimate_tokens(text: str)-> float:
# Part 1: Estimate based on spaces and punctuation
estimated_words = text.count(' ') + 1 # Counting words by spaces
punctuation_count = sum(1 for char in text if char in ',.!?;:') # Counting punctuation as potential separate tokens
estimate1 = estimated_words + punctuation_count
# Part 2: Estimate based on total characters divided by average token length
average_token_length = 4
total_characters = len(text)
estimate2 = (total_characters // average_token_length) + punctuation_count
# Average the two estimates
estimated_tokens = (estimate1 + estimate2) / 2
return estimated_tokens
def retrieve_relevant_resources(query: str,
embeddings: torch.tensor,
model: SentenceTransformer=embedding_model,
n_resources_to_return: int=4,
print_time: bool=True):
"""
Embeds a query with model and returns top k scores and indices from embeddings.
"""
# Embed the query
query_embedding = model.encode(query,
convert_to_tensor=True)
# Get dot product scores on embeddings
start_time = timer()
dot_scores = util.dot_score(query_embedding, embeddings)[0]
end_time = timer()
if print_time:
print(f"[INFO] Time taken to get scores on {len(embeddings)} embeddings: {end_time-start_time:.5f} seconds.")
scores, indices = torch.topk(input=dot_scores,
k=n_resources_to_return)
return scores, indices
def print_top_results_and_scores(query: str,
embeddings: torch.tensor,
pages_and_chunks: list[dict]=pages_and_chunks,
n_resources_to_return: int=5):
"""
Takes a query, retrieves most relevant resources and prints them out in descending order.
Note: Requires pages_and_chunks to be formatted in a specific way (see above for reference).
"""
scores, indices = retrieve_relevant_resources(query=query,
embeddings=embeddings,
n_resources_to_return=n_resources_to_return)
print(f"Query: {query}\n")
print("Results:")
print(f"Number of results: {len(indices)}")
print(f"Indices: {indices}")
print(f"Total number of chunks: {len(pages_and_chunks)}")
for i, (score, index) in enumerate(zip(scores, indices)):
print(f"\nResult {i+1}:")
print(f"Score: {score:.4f}")
print(f"Index: {index}")
if index < 0 or index >= len(pages_and_chunks):
print(f"Error: Index {index} is out of range!")
continue
chunk = pages_and_chunks[index]
print(f"Token Count: {chunk['chunk_token_count']}")
print("Available keys:", list(chunk.keys()))
print("sentence_chunk content:", repr(chunk.get("sentence_chunk", "NOT FOUND")))
chunk_text = chunk.get("sentence_chunk", "Chunk not found")
print_wrapped(chunk_text[:200] + "..." if len(chunk_text) > 200 else chunk_text)
print(f"File of Origin: {chunk['file_path']}")
return scores, indices
def prompt_formatter(query: str, context_items: list[dict]) -> str:
# Include document summary
formatted_context = f"Document Summary: {document_summary}\n\n"
# Add context items with their page summaries
for item in context_items:
page_number = item.get('page', 'Unknown')
page_summary = page_summaries.get(page_number, 'No page summary available.')
formatted_context += f"Summary: {page_summary}\n"
formatted_context += f"Content: {item['sentence_chunk']}\n\n"
base_prompt = """Use the following context to answer the user query:
{context}
User query: {query}
Answer:"""
print(f"Prompt: {base_prompt.format(context=formatted_context, query=query)}")
return base_prompt.format(context=formatted_context, query=query)
system_prompt = """You are a friendly and technical answering system, answering questions with accurate, grounded, descriptive, clear, and specific responses. ALWAYS provide a page number citation. Provide a story example. Avoid extraneous details and focus on direct answers. Use the examples provided as a guide for style and brevity. When responding:
1. Identify the key point of the query.
2. Provide a straightforward answer, omitting the thought process.
3. Avoid additional advice or extended explanations.
4. Answer in an informative manner, aiding the user's understanding without overwhelming them or quoting the source.
5. DO NOT SUMMARIZE YOURSELF. DO NOT REPEAT YOURSELF.
6. End with page citations, a line break and "What else can I help with?"
Example:
Query: Explain how the player should think about balance and lethality in this game. Explain how the game master should think about balance and lethality?
Answer: In "Swords & Wizardry: WhiteBox," players and the game master should consider balance and lethality from different perspectives. For players, understanding that this game encourages creativity and flexibility is key. The rules are intentionally streamlined, allowing for a potentially high-risk environment where player decisions significantly impact outcomes. The players should think carefully about their actions and strategy, knowing that the game can be lethal, especially without reliance on intricate rules for safety. Page 33 discusses the possibility of characters dying when their hit points reach zero, although alternative, less harsh rules regarding unconsciousness and recovery are mentioned.
For the game master (referred to as the Referee), balancing the game involves providing fair yet challenging scenarios. The role of the Referee isn't to defeat players but to present interesting and dangerous challenges that enhance the story collaboratively. Page 39 outlines how the Referee and players work together to craft a narrative, with the emphasis on creating engaging and potentially perilous experiences without making it a zero-sum competition. Referees can choose how lethal the game will be, considering their group's preferred play style, including implementing house rules to soften deaths or adjust game balance accordingly.
Pages: 33, 39
Use the context provided to answer the user's query concisely. """
with gr.Blocks() as RulesLawyer:
message_state = gr.State()
chatbot_state = gr.State([])
chatbot = gr.Chatbot()
msg = gr.Textbox()
clear = gr.ClearButton([msg, chatbot])
def store_message(message):
return message
def respond(message, chat_history):
print(datetime.now())
print(f"User Input : {message}")
print(f"Chat History: {chat_history}")
print(f"""Token Estimate: {hybrid_estimate_tokens(f"{message} {chat_history}")}""")
# Get relevant resources
scores, indices = print_top_results_and_scores(query=message,
embeddings=embeddings)
# Create a list of context items
context_items = [pages_and_chunks[i] for i in indices]
# Format prompt with context items
prompt = prompt_formatter(query=f"Chat History : {chat_history} + {message}",
context_items=context_items)
bot_message = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "user",
"content": f"{system_prompt} {prompt}"
}
],
temperature=1,
max_tokens=1000,
top_p=1,
frequency_penalty=0,
presence_penalty=0
)
chat_history.append((message, bot_message.choices[0].message.content))
print(f"Response : {bot_message.choices[0].message.content}")
time.sleep(2)
return "", chat_history
msg.change(store_message, inputs = [msg], outputs = [message_state])
chatbot.change(store_message, [chatbot], [chatbot_state])
msg.submit(respond, [message_state, chatbot_state], [msg, chatbot])ary = page_summaries.get(page_number, 'No page summary available.')
formatted_context += f"Summary: {page_summary}\n"
formatted_context += f"Content: {item['sentence_chunk']}\n\n"
base_prompt = """Use the following context to answer the user query:
{context}
User query: {query}
Answer:"""
print(f"Prompt: {base_prompt.format(context=formatted_context, query=query)}")
return base_prompt.format(context=formatted_context, query=query)
system_prompt = """You are a friendly and technical answering system, answering questions with accurate, grounded, descriptive, clear, and specific responses. ALWAYS provide a page number citation. Provide a story example. Avoid extraneous details and focus on direct answers. Use the examples provided as a guide for style and brevity. When responding:
1. Identify the key point of the query.
2. Provide a straightforward answer, omitting the thought process.
3. Avoid additional advice or extended explanations.
4. Answer in an informative manner, aiding the user's understanding without overwhelming them or quoting the source.
5. DO NOT SUMMARIZE YOURSELF. DO NOT REPEAT YOURSELF.
6. End with page citations, a line break and "What else can I help with?"
Example:
Query: Explain how the player should think about balance and lethality in this game. Explain how the game master should think about balance and lethality?
Answer: In "Swords & Wizardry: WhiteBox," players and the game master should consider balance and lethality from different perspectives. For players, understanding that this game encourages creativity and flexibility is key. The rules are intentionally streamlined, allowing for a potentially high-risk environment where player decisions significantly impact outcomes. The players should think carefully about their actions and strategy, knowing that the game can be lethal, especially without reliance on intricate rules for safety. Page 33 discusses the possibility of characters dying when their hit points reach zero, although alternative, less harsh rules regarding unconsciousness and recovery are mentioned.
For the game master (referred to as the Referee), balancing the game involves providing fair yet challenging scenarios. The role of the Referee isn't to defeat players but to present interesting and dangerous challenges that enhance the story collaboratively. Page 39 outlines how the Referee and players work together to craft a narrative, with the emphasis on creating engaging and potentially perilous experiences without making it a zero-sum competition. Referees can choose how lethal the game will be, considering their group's preferred play style, including implementing house rules to soften deaths or adjust game balance accordingly.
Pages: 33, 39
Use the context provided to answer the user's query concisely. """
with gr.Blocks() as RulesLawyer:
message_state = gr.State()
chatbot_state = gr.State([])
chatbot = gr.Chatbot()
msg = gr.Textbox()
clear = gr.ClearButton([msg, chatbot])
def store_message(message):
return message
def respond(message, chat_history):
print(datetime.now())
print(f"User Input : {message}")
print(f"Chat History: {chat_history}")
print(f"""Token Estimate: {hybrid_estimate_tokens(f"{message} {chat_history}")}""")
# Get relevant resources
scores, indices = print_top_results_and_scores(query=message,
embeddings=embeddings)
# Create a list of context items
context_items = [pages_and_chunks[i] for i in indices]
# Format prompt with context items
prompt = prompt_formatter(query=f"Chat History : {chat_history} + {message}",
context_items=context_items)
bot_message = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "user",
"content": f"{system_prompt} {prompt}"
}
],
temperature=1,
max_tokens=1000,
top_p=1,
frequency_penalty=0,
presence_penalty=0
)
chat_history.append((message, bot_message.choices[0].message.content))
print(f"Response : {bot_message.choices[0].message.content}")
time.sleep(2)
return "", chat_history
msg.change(store_message, inputs = [msg], outputs = [message_state])
chatbot.change(store_message, [chatbot], [chatbot_state])
msg.submit(respond, [message_state, chatbot_state], [msg, chatbot])
if __name__ == "__main__":
RulesLawyer.launch()
|