-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathingest.py
More file actions
148 lines (118 loc) · 5.4 KB
/
Copy pathingest.py
File metadata and controls
148 lines (118 loc) · 5.4 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
import os
import yaml
from groq import Groq
import pymupdf4llm
from pinecone import Pinecone
from sentence_transformers import SentenceTransformer
from langchain_text_splitters import RecursiveCharacterTextSplitter
def main(config, path_to_doc):
# INITIALIZE ALL CLIENTS
pc = Pinecone(api_key=config["PC_API_KEY"])
index = pc.Index(config["pinecone_index_name"])
embed_model = SentenceTransformer(config["embedding_model_name"])
groq_client = Groq(api_key=config["GROQ_API_KEY"])
# Define the files and their labels
docs = [
{"path": f"{path_to_doc}/shopify_q1.pdf", "quarter": "Q1"},
{"path": f"{path_to_doc}/shopify_q2.pdf", "quarter": "Q2"},
{"path": f"{path_to_doc}/shopify_q3.pdf", "quarter": "Q3"},
{"path": f"{path_to_doc}/shopify_annual.pdf", "quarter": "Full Year"},
]
# Define the Chunker
# We use a slightly larger chunk size for Markdown to keep tables intact
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=100,
separators=["\n\n", "\n", " ", ""]
)
def process_and_upload(doc_info):
file_path = doc_info["path"]
quarter = doc_info["quarter"]
print(f"--- Processing {file_path} ({quarter}) ---")
# Convert PDF to Markdown
md_text = pymupdf4llm.to_markdown(file_path)
# Split Markdown into Chunks
chunks = text_splitter.split_text(md_text)
print(f"Created {len(chunks)} chunks.")
# Prepare for Pinecone
vectors_to_upsert = []
for i, chunk in enumerate(chunks):
embedding = embed_model.encode(chunk).tolist()
vectors_to_upsert.append({
"id": f"shopify_2023_{quarter}_{i}",
"values": embedding,
"metadata": {
"text": chunk,
"quarter": quarter,
"year": 2023,
"company": "Shopify"
}
})
# ====================================================================
# Delete any exixting namespace "shopify-2023"
index.delete(delete_all=True, namespace="shopify-2023")
# Upsert to namespace "shopify-2023"
index.upsert(vectors=vectors_to_upsert, namespace="shopify-2023")
print(f"\n Successfully uploaded {quarter} to Pinecone!")
def compare_quarters(query, q_a="Q1", q_b="Full Year"):
query_vec = embed_model.encode(query).tolist()
# Targeted Search for Quarter A
res_a = index.query(
vector=query_vec,
top_k=3,
namespace="shopify-2023",
filter={"quarter": {"$eq": q_a}}, # THE KEY: Metadata filtering
include_metadata=True
)
# Targeted Search for Quarter B
res_b = index.query(
vector=query_vec,
top_k=3,
namespace="shopify-2023",
filter={"quarter": {"$eq": q_b}}, # THE KEY: Metadata filtering
include_metadata=True
)
# Combine Context
context_a = "\n".join([m['metadata']['text'] for m in res_a['matches']])
context_b = "\n".join([m['metadata']['text'] for m in res_b['matches']])
# Construct the Analysis Prompt
prompt = f"""
You are a Senior Financial Analyst. Analyze the performance of Shopify
by comparing {q_a} data with {q_b} data based ONLY on the context below.
--- CONTEXT FOR {q_a} ---
{context_a}
--- CONTEXT FOR {q_b} ---
{context_b}
TASK:
Identify the key differences in financial metrics, management tone,
or strategic priorities between these two periods.
Use a bulleted list for the comparison.
"""
response = groq_client.chat.completions.create(
model=config["groq_model_name"],
messages=[{"role": "user", "content": prompt}],
temperature=0.1
)
return response.choices[0].message.content
# ======================================================================================
# Run the pipeline
# Upload the PDF to pinecone
for doc in docs:
if os.path.exists(doc["path"]):
process_and_upload(doc)
else:
print(f"\nFile not found: {doc['path']}")
print(f"\n--- Describe index:\n{index.describe_index_stats()}")
#
# Run a query
analysis_query = "What were the main revenue drivers and how did they change?"
print(f"\nANALYZING: {analysis_query}\n")
ans = compare_quarters(analysis_query)
print(f"\n---\n{ans}")
# =======================================================================================
if __name__ == "__main__":
path_to_config = os.path.join(os.getcwd(), "config.yaml")
path_to_doc = os.path.join(os.getcwd(), "shopify_data")
with open(path_to_config, 'r') as file:
config = yaml.safe_load(file)
main(config, path_to_doc)