add parallel request and bug fix

This commit is contained in:
hediehloo 2025-11-30 14:35:25 +00:00
parent 9a446bca16
commit e18d569096
5 changed files with 155 additions and 42 deletions

2
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,2 @@
{
}

View File

@ -77,17 +77,17 @@ class Configuration:
character = "".join([f"- {selected_persona[i]}\n" for i in range(len(selected_persona))]) character = "".join([f"- {selected_persona[i]}\n" for i in range(len(selected_persona))])
example1 = "{'passage': 'چیپست اسنپدراگون نام خانواده\\u200cای از SoCها یا «سیستم بر روی یک تراشه» است که توسط شرکت تراشه\\u200cساز آمریکایی کوالکام Qualcomm ساخته می شود. هدف از ساخت این تراشه\\u200cها استفاده از آنها در گوشی\\u200cهای همراه هوشمند و تبلت\\u200cهاست. هر تراشه\\u200cی اسنپ\\u200cدراگون شامل واحدهای پردازنده\\u200cی مرکزی، پردازنده\\u200cی گرافیکی Adreno، کنترلر دوربین، سیستم ناوبری جهانی GPS، مودم داخلی برای اتصال به شبکه\\u200cهای 5G و اتصال Wi-Fi است. در واقع در این تراشه\\u200cها تمام ابزارهای لازم برای توانمندسازی یک دستگاه هوشمند یکجا جمع شده است. البته تمام پردازنده های اسنپدراگون توانایی\\u200cهای برابری ندارد.', 'Character': 'A widely acclaimed microprocessor scientist passionate about creating next generation mobile chipsets', 'Question_Type': 'keywords', 'Difficulty': 'university'}" example1 = "{'passage': 'چیپست اسنپدراگون نام خانواده\\u200cای از SoCها یا «سیستم بر روی یک تراشه» است که توسط شرکت تراشه\\u200cساز آمریکایی کوالکام Qualcomm ساخته می شود. هدف از ساخت این تراشه\\u200cها استفاده از آنها در گوشی\\u200cهای همراه هوشمند و تبلت\\u200cهاست. هر تراشه\\u200cی اسنپ\\u200cدراگون شامل واحدهای پردازنده\\u200cی مرکزی، پردازنده\\u200cی گرافیکی Adreno، کنترلر دوربین، سیستم ناوبری جهانی GPS، مودم داخلی برای اتصال به شبکه\\u200cهای 5G و اتصال Wi-Fi است. در واقع در این تراشه\\u200cها تمام ابزارهای لازم برای توانمندسازی یک دستگاه هوشمند یکجا جمع شده است. البته تمام پردازنده های اسنپدراگون توانایی\\u200cهای برابری ندارد.', 'Character': 'A widely acclaimed microprocessor scientist passionate about creating next generation mobile chipsets', 'Question_Type': 'keywords', 'Difficulty': 'university'}"
example2 = '{\'passage\': \'امام علی(ع) پس از خلیفه سوم، به اصرار مسلمانان خلافت و حکومت را پذیرفت. او در دوران حکومتش اهمیت ویژه\\u200cای برای عدالت قائل بود و در برابر روش خلفا که بیت\\u200cالمال را بر اساس سوابق افراد تقسیم می\\u200cکردند، ایستاد. وی دستور داد که عرب و عجم و هر مسلمانی از هر تیره و تبار که باشد، در سهم بیت\\u200cالمال یکسان\\u200cاند و تمام زمین\\u200cهایی که عثمان به افراد مختلف واگذار کرده بود، به بیت\\u200cالمال بازگرداند. در دوره کوتاه حکومت امام علی(ع) سه جنگ سنگین داخلی جمل، صفین و نهروان درگرفت.\', \'Character\': "a devout Shi\'a Muslim scholar who has spent years studying Islamic scriptures and the life of Imam Ali.", \'Question_Type\': \'keywords\', \'Difficulty\': \'university\'}' example2 = str(
{
"passage": "مدل‌های معادلات ساختاری مبتنی بر بیزی (Bayesian SEM) در دهه‌های اخیر به‌عنوان جایگزینی برای روش‌های کلاسیک بیشینه‌سازی درست‌نمایی مطرح شده‌اند. در این رویکرد، به‌جای برآورد نقطه‌ای پارامترها، توزیع پسین آن‌ها بر اساس پیشین‌های انتخاب‌شده محاسبه می‌شود. یکی از چالش‌های بنیادی در Bayesian SEM، تعیین پیشین‌های ضعیفاً آگاهانه برای ماتریس کوواریانس خطاهاست؛ زیرا انتخاب نامناسب پیشین می‌تواند همگرایی زنجیره‌های MCMC را مختل کرده و منجر به posterior shape distortion شود. افزون بر این، ارزیابی مدل در این چارچوب دیگر محدود به شاخص‌های کلاسیک برازش نیست، بلکه معیارهایی مانند WAIC، LOO-CV و Bayes Factor نقش تعیین‌کننده‌ای دارند. با وجود مزایای متعدد، همچون امکان مدل‌سازی ساختارهای سلسله‌مراتبی پیچیده و داده‌های گمشده، همچنان بحث‌های مهمی درباره حساسیت مدل به specification priors و پایداری استنباط در نمونه‌های کوچک باقی مانده است.",
"Character": "a rigorous quantitative methodologist specializing in Bayesian hierarchical modeling and structural equation theory",
"Question_Type": "acquire_knowledge",
"Difficulty": "phd"
})
example3 = "{'passage': 'همه موجودات زنده بر اساس ویژگی های بسیار اساسی و مشترک طبقه بندی می شوند. سپس موجودات درون هر گروه به گروههای کوچکتر تقسیم می شوند. این گروه های کوچکتر بر اساس شباهت های دقیق تر در هر گروه بزرگتر هستند. این سیستم گروه بندی ، مطالعه گروه های خاصی از موجودات را برای دانشمندان آسان می کند. ویژگی هایی مانند ظاهر ، تولید مثل ، تحرک و عملکرد تنها چند روش برای گروه بندی موجودات زنده است. این گروه های تخصصی را طبقه بندی موجودات زنده می نامند. طبقه بندی موجودات زنده شامل ۷ سطح است: فرمانروا، شاخه، رده، راسته، خانواده، جنس و گونه', 'Character': 'a classification biologists who is slightly impatient with imprecise information.', 'Question_Type': 'acquire_knowledge', 'Difficulty': 'high_school'}" example3 = "{'passage': 'همه موجودات زنده بر اساس ویژگی های بسیار اساسی و مشترک طبقه بندی می شوند. سپس موجودات درون هر گروه به گروههای کوچکتر تقسیم می شوند. این گروه های کوچکتر بر اساس شباهت های دقیق تر در هر گروه بزرگتر هستند. این سیستم گروه بندی ، مطالعه گروه های خاصی از موجودات را برای دانشمندان آسان می کند. ویژگی هایی مانند ظاهر ، تولید مثل ، تحرک و عملکرد تنها چند روش برای گروه بندی موجودات زنده است. این گروه های تخصصی را طبقه بندی موجودات زنده می نامند. طبقه بندی موجودات زنده شامل ۷ سطح است: فرمانروا، شاخه، رده، راسته، خانواده، جنس و گونه', 'Character': 'a classification biologists who is slightly impatient with imprecise information.', 'Question_Type': 'acquire_knowledge', 'Difficulty': 'high_school'}"
config_prompt = f"""Given a **Passage** and **Character**, select the appropriate option from config_prompt = f"""Given a **Passage** and **Character**, select the appropriate option from three fields: Character, Question_Type, Difficulty, and return the output in JSON format.
three fields: Character, Question_Type, Difficulty, and return the output First, select the Character who are likely to be interested in the Passage from the candidates. Then select the Question_Type that the Character might ask about the Passage; Finally, choose the Difficulty of the possible question based on the Passage, the Character, and the Question_Type.
in JSON format.
First, select the Character who are likely to be interested in the Passage
from the candidates. Then select the Question_Type that the Character
might ask about the Passage; Finally, choose the Difficulty of the
possible question based on the Passage, the Character, and the
Question_Type.
Character: Given by input **Character** Character: Given by input **Character**
Question_Type: Question_Type:
- keywords: ... - keywords: ...
@ -104,9 +104,7 @@ Example1: {example1}
Example2: {example2} Example2: {example2}
Example3: {example3} Example3: {example3}
Now, generate the **output** based on the **Passage** and **Character** from Now, generate the **output** based on the **Passage** and **Character** from user, the **Passage** will be in {language} language and the **Character** will be in English.
user, the **Passage** will be in {language} language and the **Character**
will be in English.
Ensure to generate only the JSON output with content in English. Ensure to generate only the JSON output with content in English.
@ -162,7 +160,7 @@ Ensure to generate only the JSON output with content in English.
# for key in data: # for key in data:
# example[key] = data[key] # example[key] = data[key]
config["length"] = random.choice([10, 20, 40, 80]) config["length"] = random.choice([10, 20, 40, 80, 150])
return config return config

53
src/parallel_requester.py Normal file
View File

@ -0,0 +1,53 @@
import threading
from typing import Callable, Any
from tqdm import tqdm
class ParallelRequester:
def __init__(self):
self.lock = threading.Lock()
def get_a_data(self):
with self.lock:
if self.data_idx < len(self.data):
data = self.data[self.data_idx]
data_idx = self.data_idx
self.data_idx += 1
else:
data = None
data_idx = None
return data, data_idx
def thread_function(self, exec_function: Callable[[Any], Any]):
while True:
data, data_idx = self.get_a_data()
if data == None:
return
self.all_res[data_idx] = exec_function(data)
self.pbar.update(1)
def run(self, data, exec_function, num_threads):
self.data_idx = 0
self.all_res = {}
self.data = data
self.pbar = tqdm(total=len(data), desc="Processing", unit="item")
allthreads = []
for thread_idx in range(num_threads):
allthreads += [threading.Thread(target=self.thread_function, args=(exec_function,))]
for thread_idx in range(num_threads):
allthreads[thread_idx].start()
for thread_idx in range(num_threads):
allthreads[thread_idx].join()
all_res = [self.all_res[i] for i in range(len(self.all_res))]
del self.all_res
del self.data
return all_res

View File

@ -1,18 +1,12 @@
import json import json
import os import os
import requests
import tqdm
import faiss
import numpy
import importlib import importlib
from openai import OpenAI
from dotenv import load_dotenv
import re import re
import random import random
import tqdm
import pandas as pd import pandas as pd
def import_lib(path, file_name, package_name): def import_lib(path, file_name, package_name):
file_path = path + "/" + file_name + ".py" file_path = path + "/" + file_name + ".py"
spec = importlib.util.spec_from_file_location(file_name, file_path) spec = importlib.util.spec_from_file_location(file_name, file_path)
@ -23,7 +17,7 @@ def import_lib(path, file_name, package_name):
Configuration = import_lib(os.path.dirname(__file__) , "configuration", "Configuration") Configuration = import_lib(os.path.dirname(__file__) , "configuration", "Configuration")
QueryGenerator = import_lib(os.path.dirname(__file__) , "query_generator", "QueryGenerator") QueryGenerator = import_lib(os.path.dirname(__file__) , "query_generator", "QueryGenerator")
ParallelRequester = import_lib(os.path.dirname(__file__) , "parallel_requester", "ParallelRequester")
class Pipline: class Pipline:
def __init__(self): def __init__(self):
@ -32,6 +26,7 @@ class Pipline:
self.configuration.init_persona() self.configuration.init_persona()
self.query_generator = QueryGenerator() self.query_generator = QueryGenerator()
def load_data(self): def load_data(self):
df = pd.read_csv(self.file_path + "/../data/persian_blog/blogs.csv") df = pd.read_csv(self.file_path + "/../data/persian_blog/blogs.csv")
rows = df.values.tolist() rows = df.values.tolist()
@ -64,28 +59,87 @@ class Pipline:
json.dump(data, f, ensure_ascii=False, indent=2) json.dump(data, f, ensure_ascii=False, indent=2)
def get_a_data(self):
with self.lock:
if self.data_idx < len(self.data):
data = self.data[self.data_idx]
data_idx = self.data_idx
else:
data = None
data_idx = None
self.data_idx += 1
return data, data_idx
def exec_function(self, passage):
config = self.configuration.run(passage)
generated_data = self.query_generator.run(passage, config)
one_data = config.copy()
one_data["document"] = passage
one_data["query"] = generated_data["query"]
return one_data
def make_a_passage(self, selected_lenth, sentences, start_idx):
one_passage = ""
for i in range(start_idx, len(sentences)):
if len(one_passage) + len(sentences[i]) > selected_lenth and len(one_passage) > 0:
return one_passage, i
one_passage += sentences[i]
return one_passage, len(sentences)
def chunk_data(self, passage):
max_length = 3000
min_length = 30
if len(passage) < max_length:
return [passage]
sentences = passage.split(".")
all_passages = []
start_idx = 0
stop_idx = 0
while True:
selected_lenth = random.choice([50, 100, 200, 300, 500, 800, 1300, 2000, 3000])
start_idx = stop_idx
one_passage, stop_idx = self.make_a_passage(selected_lenth, sentences, start_idx)
if len(one_passage) > min_length:
all_passages += [one_passage]
if stop_idx == len(sentences):
break
return all_passages
def pre_process(self, data):
chunk_data = []
for i in tqdm.trange(len(data)):
chunk_data += self.chunk_data(data[i])
random.shuffle(chunk_data)
return chunk_data
def run(self): def run(self):
data = self.load_data() data = self.load_data()
chunk_data = self.pre_process(data)
num_data = 10 num_data = 20
num_threads = 5
dataset = [] parallel_requester = ParallelRequester()
for i in range(num_data): dataset = parallel_requester.run(chunk_data[0:num_data], self.exec_function, num_threads)
config = self.configuration.run(data[i])
generated_data = self.query_generator.run(data[i], config)
one_data = config.copy()
one_data["document"] = data[i]
one_data["query"] = generated_data
dataset += [one_data]
self.save_dataset(dataset) self.save_dataset(dataset)
def main(): def main():
random.seed(42)
pipline = Pipline() pipline = Pipline()
pipline.run() pipline.run()

View File

@ -27,17 +27,23 @@ class QueryGenerator:
self.openai_responder = OpenAIResponder(client=client, model=os.environ["OPENAI_MODEL"], price_per_1m_input_tokens=0, price_per_1m_output_tokens=0) self.openai_responder = OpenAIResponder(client=client, model=os.environ["OPENAI_MODEL"], price_per_1m_input_tokens=0, price_per_1m_output_tokens=0)
def get_prompt(self, passage, character, corpus_language, queries_language, difficulty, length, language, question_type): def get_prompt(self, passage, character, corpus_language, queries_language, difficulty, length, language, question_type):
example = {
example = "{'passage': 'چیپست اسنپدراگون نام خانواده\\u200cای از SoCها یا «سیستم بر روی یک تراشه» است که توسط شرکت تراشه\\u200cساز آمریکایی کوالکام Qualcomm ساخته می شود. هدف از ساخت این تراشه\\u200cها استفاده از آنها در گوشی\\u200cهای همراه هوشمند و تبلت\\u200cهاست. هر تراشه\\u200cی اسنپ\\u200cدراگون شامل واحدهای پردازنده\\u200cی مرکزی، پردازنده\\u200cی گرافیکی Adreno، کنترلر دوربین، سیستم ناوبری جهانی GPS، مودم داخلی برای اتصال به شبکه\\u200cهای 5G و اتصال Wi-Fi است. در واقع در این تراشه\\u200cها تمام ابزارهای لازم برای توانمندسازی یک دستگاه هوشمند یکجا جمع شده است. البته تمام پردازنده های اسنپدراگون توانایی\\u200cهای برابری ندارد.', 'Character': 'A widely acclaimed microprocessor scientist passionate about creating next generation mobile chipsets', 'Question_Type': 'keywords', 'Difficulty': 'university'}" "input" : {
example2 = '{\'passage\': \'امام علی(ع) پس از خلیفه سوم، به اصرار مسلمانان خلافت و حکومت را پذیرفت. او در دوران حکومتش اهمیت ویژه\\u200cای برای عدالت قائل بود و در برابر روش خلفا که بیت\\u200cالمال را بر اساس سوابق افراد تقسیم می\\u200cکردند، ایستاد. وی دستور داد که عرب و عجم و هر مسلمانی از هر تیره و تبار که باشد، در سهم بیت\\u200cالمال یکسان\\u200cاند و تمام زمین\\u200cهایی که عثمان به افراد مختلف واگذار کرده بود، به بیت\\u200cالمال بازگرداند. در دوره کوتاه حکومت امام علی(ع) سه جنگ سنگین داخلی جمل، صفین و نهروان درگرفت.\', \'Character\': "a devout Shi\'a Muslim scholar who has spent years studying Islamic scriptures and the life of Imam Ali.", \'Question_Type\': \'keywords\', \'Difficulty\': \'university\'}' "passage": "مدل‌های معادلات ساختاری مبتنی بر بیزی (Bayesian SEM) در دهه‌های اخیر به‌عنوان جایگزینی برای روش‌های کلاسیک بیشینه‌سازی درست‌نمایی مطرح شده‌اند. در این رویکرد، به‌جای برآورد نقطه‌ای پارامترها، توزیع پسین آن‌ها بر اساس پیشین‌های انتخاب‌شده محاسبه می‌شود. یکی از چالش‌های بنیادی در Bayesian SEM، تعیین پیشین‌های ضعیفاً آگاهانه برای ماتریس کوواریانس خطاهاست؛ زیرا انتخاب نامناسب پیشین می‌تواند همگرایی زنجیره‌های MCMC را مختل کرده و منجر به posterior shape distortion شود. افزون بر این، ارزیابی مدل در این چارچوب دیگر محدود به شاخص‌های کلاسیک برازش نیست، بلکه معیارهایی مانند WAIC، LOO-CV و Bayes Factor نقش تعیین‌کننده‌ای دارند. با وجود مزایای متعدد، همچون امکان مدل‌سازی ساختارهای سلسله‌مراتبی پیچیده و داده‌های گمشده، همچنان بحث‌های مهمی درباره حساسیت مدل به specification priors و پایداری استنباط در نمونه‌های کوچک باقی مانده است.",
example3 = "{'passage': 'همه موجودات زنده بر اساس ویژگی های بسیار اساسی و مشترک طبقه بندی می شوند. سپس موجودات درون هر گروه به گروههای کوچکتر تقسیم می شوند. این گروه های کوچکتر بر اساس شباهت های دقیق تر در هر گروه بزرگتر هستند. این سیستم گروه بندی ، مطالعه گروه های خاصی از موجودات را برای دانشمندان آسان می کند. ویژگی هایی مانند ظاهر ، تولید مثل ، تحرک و عملکرد تنها چند روش برای گروه بندی موجودات زنده است. این گروه های تخصصی را طبقه بندی موجودات زنده می نامند. طبقه بندی موجودات زنده شامل ۷ سطح است: فرمانروا، شاخه، رده، راسته، خانواده، جنس و گونه', 'Character': 'a classification biologists who is slightly impatient with imprecise information.', 'Question_Type': 'acquire_knowledge', 'Difficulty': 'high_school'}" "Character": "a rigorous quantitative methodologist specializing in Bayesian hierarchical modeling and structural equation theory",
"Question_Type": "acquire_knowledge",
"Difficulty": "phd"
},
"output": {
"query": "در مدل‌های معادلات ساختاری مبتنی بر رویکرد بیزی، چرا انتخاب پیشین‌های ضعیفاً آگاهانه برای ماتریس کوواریانس خطاها اهمیت دارد و چه پیامدی در صورت انتخاب نامناسب آن رخ می‌دهد؟"
}
}
prompt = f"""Given a **Character**, **Passage**, and **Requirement**, generate a query from the **Character**'s perspective that satisfies the **Requirement** and can be used to retrieve the **Passage**. Please return the result in JSON format. prompt = f"""Given a **Character**, **Passage**, and **Requirement**, generate a query from the **Character**'s perspective that satisfies the **Requirement** and can be used to retrieve the **Passage**. Please return the result in JSON format.
The query must NOT mention, reference, or imply the existence Passage. Instead, generate a natural, self-contained query whose answer can be found within the **Passage**.
Here is an example: Here is an example:
<example> {example}
Now, generate the **output** based on the **Character**, **Passage** and **Requirement** from user, the **Passage** will be in {corpus_language} language, the **Character** and **Requirement** will be in English. Now, generate the **output** based on the **Character**, **Passage** and **Requirement** from user, the **Passage** will be in {corpus_language} language, the **Character** and **Requirement** will be in English.