-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathmain.py
More file actions
171 lines (136 loc) · 6.61 KB
/
Copy pathmain.py
File metadata and controls
171 lines (136 loc) · 6.61 KB
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
# -*- coding: utf-8 -*-
import json
import os
import yaml
from llama_index.core import SimpleDirectoryReader, VectorStoreIndex, StorageContext, load_index_from_storage
from core.message import Msg
from core.embedding import LiteLLMEmbedding
from init_agents import init_retriever, init_profiler, init_summarizer
from tagging import run_tagging
from util.data_loader import load_synthpai, check_valid
from util.data_clean import deduplicate
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--target_user", "-u", type=str, help="The target user to infer PIIs.")
parser.add_argument("--llm_model", "-m", type=str, default="gemini-2.5-flash", help="The LLM model to use.")
args = parser.parse_args()
target_user = args.target_user
llm_model = args.llm_model
# check whether the target user has ground truth
target_attributes = check_valid(target_user)
if target_attributes == []:
exit()
# Load config from YAML
config_path = f"./config/{llm_model}.yaml"
with open(config_path, "r") as f:
config = yaml.safe_load(f)
model_name = config["model"]
embedding_model = config.get("embedding_model", "openai/text-embedding-3-small")
api_key = config.get("api_key", None)
embedding_api_key = config.get("embedding_api_key", api_key)
# Run tagging step before building RAG index
run_tagging(target_user=target_user, model_name=model_name, api_key=api_key)
# Set up embedding model via LiteLLM
embed_model = LiteLLMEmbedding(model_name=embedding_model, api_key=embedding_api_key)
# Set up RAG knowledge base using direct LlamaIndex API
vdb_path = f"./dataset/vdb/{target_user}"
data_dir = f"./dataset/tag/{target_user}"
if os.path.exists(vdb_path):
# Load existing index from disk
storage_context = StorageContext.from_defaults(persist_dir=vdb_path)
knowledge = load_index_from_storage(storage_context, embed_model=embed_model)
else:
# Build new index
documents = SimpleDirectoryReader(input_dir=data_dir, required_exts=[".txt"]).load_data()
knowledge = VectorStoreIndex.from_documents(documents, embed_model=embed_model)
knowledge.storage_context.persist(persist_dir=vdb_path)
# Load reddit history
user_history = load_synthpai(target_user)
visited_history = []
count_token = True if llm_model == "gpt-4" else False
retriever = init_retriever(user_history, knowledge, visited_history, count_token, model_name=model_name, api_key=api_key)
profiler = init_profiler(target_attributes, count_token, model_name=model_name, api_key=api_key)
summarizer = init_summarizer(target_attributes, count_token, model_name=model_name, api_key=api_key)
x = Msg(name="user", role="user", content="Please begin inferring\n")
# Build
key_piis = [] # we explicitly store the highly confident PIIs in case of forget
cur_piis = [] # this serves as the compression of memory
while True:
instruct_msg = profiler.think(x, reset=True)
while instruct_msg.parsed["action"] == "retrieval" or instruct_msg.parsed["action"] == "search":
# send the message to the retriever
instruct_msg = Msg(name="profiler", role="assistant", content=instruct_msg.parsed["instruction"])
data_msg = retriever(instruct_msg)
# send the response to the profiler
instruct_msg = profiler.think(data_msg)
if instruct_msg.parsed["action"] == "finish":
if len(visited_history) == len(user_history):
# force to reason agine with all user history
res_msg = profiler.naive_infer(target_attributes, user_history)
new_piis = res_msg.parsed["results"]
key_piis.extend(new_piis)
# final check with inferred and once-inferred PIIs
final_msg = Msg(name="profiler", role="assistant", content=key_piis)
# update the inferred PIIs
final_piis = summarizer.check(final_msg).parsed["results"]
final_piis = deduplicate(final_piis)
break
else:
x = Msg(
name="user",
role="user",
content=f"You already infer: {x}. However, there is still more user's comment history, you should retrieval more for reasoning. Keep going!\n",
)
continue
elif instruct_msg.parsed["action"] == "reason":
########### start reasoning ###########
instruct_msg = Msg(name="profiler", role="assistant", content=instruct_msg.parsed["instruction"])
res_msg = profiler.reason(instruct_msg)
########### get the inferred PIIs ###########
new_piis = res_msg.parsed["results"]
####### store highly confident PIIs in case of forget #######
for attr_dict in new_piis:
# Check if attr_dict is actually a dictionary
try:
if attr_dict["type"] in target_attributes:
# if the attribute is the target attribute, store it
print(f"Stored target attribute: {attr_dict}")
key_piis.append(attr_dict)
except:
print(f"Error: {attr_dict} is not a dictionary")
# combine all cur_piis
cur_piis.extend(new_piis)
########### check the inferred PIIs ###########
# send the response to the summarizer for checking
res_msg = Msg(name="profiler", role="assistant", content=cur_piis)
# update the inferred PIIs
cur_piis = summarizer.check(res_msg).parsed["results"]
# perpare for the next iteration
x = Msg(name="Summarizer", role="assistant", content=cur_piis)
else:
action = instruct_msg.parsed["action"]
print(f"Warning: unrecognized action '{action}', treating as 'retrieval'")
x = Msg(
name="user",
role="user",
content=f"Invalid action '{action}'. Please choose from: retrieval, search, reason, or finish.\n",
)
print(f"Inferred PIIs: {json.dumps(final_piis, indent=2)}")
print("The summary of the inferred PIIs:")
res_msg = Msg(name="user", role="user", content=final_piis)
description = summarizer.summary(res_msg)
print(description.parsed["summary"])
# save the inferred PIIs
os.makedirs(f"./dataset/{llm_model}/pii/", exist_ok=True)
os.makedirs(f"./dataset/{llm_model}/summary/", exist_ok=True)
with open(f"./dataset/{llm_model}/pii/{target_user}.json", "w") as f:
json.dump(final_piis, f, indent=2)
with open(f"./dataset/{llm_model}/summary/{target_user}.txt", "w") as f:
if description.parsed["summary"] is None:
f.write("No summary available")
else:
f.write(description.parsed["summary"])
if len(final_piis) != len(target_attributes):
print("The inferred PIIs are not complete!")
with open(f"./incomplete_{llm_model}.txt", "w+") as f:
f.write(target_user)