|
|
import os
|
|
|
os.environ["TOKENIZERS_PARALLELISM"] = "false"
|
|
|
import datetime
|
|
|
import functools
|
|
|
import traceback
|
|
|
from typing import List, Optional, Any, Dict, Tuple
|
|
|
import csv
|
|
|
import pandas as pd
|
|
|
import tempfile
|
|
|
import shutil
|
|
|
import glob
|
|
|
|
|
|
import torch
|
|
|
import transformers
|
|
|
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
|
|
|
from langchain_community.llms import HuggingFacePipeline
|
|
|
|
|
|
|
|
|
from langchain_community.document_loaders import OnlinePDFLoader
|
|
|
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
|
|
from langchain_community.vectorstores import FAISS
|
|
|
from langchain.embeddings import HuggingFaceEmbeddings
|
|
|
from langchain_community.retrievers import BM25Retriever
|
|
|
from langchain.embeddings.base import Embeddings
|
|
|
from langchain.retrievers import EnsembleRetriever
|
|
|
from langchain.prompts import ChatPromptTemplate
|
|
|
from langchain.schema import StrOutputParser, Document
|
|
|
from langchain_core.runnables import RunnableParallel, RunnableLambda
|
|
|
from transformers.quantizers.auto import AutoQuantizationConfig
|
|
|
import gradio as gr
|
|
|
from pydantic import PrivateAttr
|
|
|
import pydantic
|
|
|
|
|
|
from langchain.llms.base import LLM
|
|
|
from typing import Any, Optional, List
|
|
|
import typing
|
|
|
import time
|
|
|
import re
|
|
|
import requests
|
|
|
from langchain.schema import Document
|
|
|
from langchain_community.document_loaders import PyMuPDFLoader
|
|
|
import tempfile
|
|
|
import mimetypes
|
|
|
import gc
|
|
|
|
|
|
|
|
|
def generate_parameter_values(min_val, max_val, num_values):
|
|
|
"""Generate evenly spaced values between min and max"""
|
|
|
if num_values == 1:
|
|
|
return [min_val]
|
|
|
step = (max_val - min_val) / (num_values - 1)
|
|
|
return [min_val + (step * i) for i in range(num_values)]
|
|
|
|
|
|
def process_batch_query(query, model_choice, max_tokens, param_configs, slider_values, job_id, use_history=True):
|
|
|
"""Process a batch of queries with different parameter combinations"""
|
|
|
results = []
|
|
|
|
|
|
|
|
|
temp_values = [slider_values['temperature']] if param_configs['temperature'] == "Constant" else generate_parameter_values(0.1, 1.0, int(param_configs['temperature'].split()[2]))
|
|
|
top_p_values = [slider_values['top_p']] if param_configs['top_p'] == "Constant" else generate_parameter_values(0.1, 0.99, int(param_configs['top_p'].split()[2]))
|
|
|
top_k_values = [slider_values['top_k']] if param_configs['top_k'] == "Constant" else generate_parameter_values(1, 100, int(param_configs['top_k'].split()[2]))
|
|
|
bm25_values = [slider_values['bm25']] if param_configs['bm25'] == "Constant" else generate_parameter_values(0.0, 1.0, int(param_configs['bm25'].split()[2]))
|
|
|
|
|
|
total_combinations = len(temp_values) * len(top_p_values) * len(top_k_values) * len(bm25_values)
|
|
|
current = 0
|
|
|
|
|
|
for temp in temp_values:
|
|
|
for top_p in top_p_values:
|
|
|
for top_k in top_k_values:
|
|
|
for bm25 in bm25_values:
|
|
|
current += 1
|
|
|
try:
|
|
|
|
|
|
rag_chain.temperature = temp
|
|
|
rag_chain.top_p = top_p
|
|
|
rag_chain.top_k = top_k
|
|
|
rag_chain.bm25_weight = bm25
|
|
|
rag_chain.faiss_weight = 1.0 - bm25
|
|
|
|
|
|
|
|
|
rag_chain.ensemble_retriever = EnsembleRetriever(
|
|
|
retrievers=[rag_chain.bm25_retriever, rag_chain.faiss_retriever],
|
|
|
weights=[rag_chain.bm25_weight, rag_chain.faiss_weight]
|
|
|
)
|
|
|
|
|
|
|
|
|
response = rag_chain.elevated_rag_chain.invoke({"question": query})
|
|
|
|
|
|
|
|
|
if use_history:
|
|
|
trimmed_response = response[:1000] + ("..." if len(response) > 1000 else "")
|
|
|
rag_chain.conversation_history.append({"query": query, "response": trimmed_response})
|
|
|
|
|
|
|
|
|
result = {
|
|
|
"Parameters": f"Temp: {temp:.2f}, Top-p: {top_p:.2f}, Top-k: {top_k}, BM25: {bm25:.2f}",
|
|
|
"Response": response,
|
|
|
"Progress": f"Query {current}/{total_combinations}"
|
|
|
}
|
|
|
results.append(result)
|
|
|
|
|
|
except Exception as e:
|
|
|
results.append({
|
|
|
"Parameters": f"Temp: {temp:.2f}, Top-p: {top_p:.2f}, Top-k: {top_k}, BM25: {bm25:.2f}",
|
|
|
"Response": f"Error: {str(e)}",
|
|
|
"Progress": f"Query {current}/{total_combinations}"
|
|
|
})
|
|
|
|
|
|
|
|
|
formatted_results, csv_path = format_batch_result_files(
|
|
|
results, job_id,
|
|
|
embedding_model=getattr(rag_chain, 'embedding_model', 'unknown'),
|
|
|
llm_model=model_choice,
|
|
|
param_variations=param_configs
|
|
|
)
|
|
|
|
|
|
return (
|
|
|
formatted_results,
|
|
|
csv_path,
|
|
|
f"Job ID: {job_id}",
|
|
|
f"Input tokens: {count_tokens(query)}",
|
|
|
f"Output tokens: {sum(count_tokens(r['Response']) for r in results)}"
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def create_csv_from_batch_results(results: List[Dict], job_id: str,
|
|
|
embedding_model: str = None, llm_model: str = None,
|
|
|
param_variations: Dict = None) -> str:
|
|
|
"""Create a CSV file from batch query results and return the file path"""
|
|
|
|
|
|
|
|
|
|
|
|
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
|
|
|
|
|
|
|
def get_short_name(full_name, prefix_length=2):
|
|
|
"""Extract short name from full model name"""
|
|
|
if not full_name:
|
|
|
return "unknown"
|
|
|
|
|
|
clean_name = full_name.split(" ", 1)[-1] if " " in full_name else full_name
|
|
|
|
|
|
if len(clean_name) > 8:
|
|
|
return clean_name[:4] + clean_name[-4:]
|
|
|
return clean_name
|
|
|
|
|
|
def get_param_variation_name(param_configs):
|
|
|
"""Get the parameter that was varied"""
|
|
|
if not param_configs:
|
|
|
return "const"
|
|
|
|
|
|
varied_params = []
|
|
|
for param, config in param_configs.items():
|
|
|
if config != "Constant":
|
|
|
|
|
|
if "values" in config:
|
|
|
num_values = config.split()[2] if len(config.split()) > 2 else "X"
|
|
|
varied_params.append(f"{param}_{num_values}")
|
|
|
|
|
|
if not varied_params:
|
|
|
return "const"
|
|
|
return "_".join(varied_params)
|
|
|
|
|
|
|
|
|
embedding_short = get_short_name(embedding_model) if embedding_model else "emb"
|
|
|
llm_short = get_short_name(llm_model) if llm_model else "llm"
|
|
|
param_short = get_param_variation_name(param_variations) if param_variations else "const"
|
|
|
|
|
|
|
|
|
csv_filename = f"batch_{embedding_short}_{llm_short}_{param_short}_{timestamp}.csv"
|
|
|
csv_path = os.path.abspath(csv_filename)
|
|
|
|
|
|
|
|
|
data = []
|
|
|
start_time = time.time()
|
|
|
for result in results:
|
|
|
params = result["Parameters"]
|
|
|
response = result["Response"]
|
|
|
progress = result["Progress"]
|
|
|
|
|
|
|
|
|
current_time = time.time()
|
|
|
elapsed_time = current_time - start_time
|
|
|
|
|
|
|
|
|
temp = float(re.search(r"Temp: ([\d.]+)", params).group(1))
|
|
|
top_p = float(re.search(r"Top-p: ([\d.]+)", params).group(1))
|
|
|
top_k = int(re.search(r"Top-k: (\d+)", params).group(1))
|
|
|
bm25 = float(re.search(r"BM25: ([\d.]+)", params).group(1))
|
|
|
|
|
|
|
|
|
model_info = re.search(r"Model: (.*?)\n", response)
|
|
|
model = model_info.group(1) if model_info else "Unknown"
|
|
|
|
|
|
|
|
|
answer_match = re.search(r"Model Parameters:.*?\n\n(.*?)\n\n---", response, re.DOTALL)
|
|
|
main_answer = answer_match.group(1).strip() if answer_match else response
|
|
|
|
|
|
|
|
|
input_tokens = re.search(r"Input tokens: (\d+)", response)
|
|
|
output_tokens = re.search(r"Output tokens: (\d+)", response)
|
|
|
|
|
|
|
|
|
conv_history = re.search(r"Conversation History: (\d+) conversation", response)
|
|
|
|
|
|
data.append({
|
|
|
"Temperature": temp,
|
|
|
"Top-p": top_p,
|
|
|
"Top-k": top_k,
|
|
|
"BM25 Weight": bm25,
|
|
|
"Model": model,
|
|
|
"Main Answer": main_answer,
|
|
|
"Input Tokens": input_tokens.group(1) if input_tokens else "N/A",
|
|
|
"Output Tokens": output_tokens.group(1) if output_tokens else "N/A",
|
|
|
"Conversation History": conv_history.group(1) if conv_history else "0",
|
|
|
"Progress": progress,
|
|
|
"Elapsed Time (s)": f"{elapsed_time:.2f}"
|
|
|
})
|
|
|
|
|
|
|
|
|
df = pd.DataFrame(data)
|
|
|
df.to_csv(csv_path, index=False)
|
|
|
|
|
|
return csv_path
|
|
|
|
|
|
def format_batch_result_files(results: List[Dict], job_id: str,
|
|
|
embedding_model: str = None, llm_model: str = None,
|
|
|
param_variations: Dict = None) -> Tuple[str, str]:
|
|
|
"""Format batch results with links to CSV files"""
|
|
|
|
|
|
csv_path = create_csv_from_batch_results(results, job_id, embedding_model, llm_model, param_variations)
|
|
|
|
|
|
|
|
|
formatted_results = "### Batch Query Results\n\n"
|
|
|
|
|
|
|
|
|
for result in results:
|
|
|
formatted_results += f"#### {result['Parameters']}\n"
|
|
|
formatted_results += f"**Progress:** {result['Progress']}\n\n"
|
|
|
formatted_results += f"{result['Response']}\n\n"
|
|
|
formatted_results += "---\n\n"
|
|
|
|
|
|
return formatted_results, csv_path
|
|
|
|
|
|
|