File size: 5,195 Bytes
69381c2
 
 
 
 
86346c3
69381c2
 
0daa9f6
69381c2
 
 
 
e10ade5
72ccb9c
 
 
11e087c
fe3da63
 
 
69381c2
 
 
d54c8f8
69381c2
439e701
0daa9f6
e020321
69381c2
0daa9f6
 
69381c2
0daa9f6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69381c2
 
0daa9f6
 
 
 
 
69381c2
0daa9f6
 
 
 
 
 
69381c2
0daa9f6
69381c2
0daa9f6
 
 
 
69381c2
ed4a13f
 
 
 
 
69381c2
 
 
 
 
 
 
 
 
 
 
 
 
d54c8f8
69381c2
 
 
 
 
 
 
 
a8813ea
 
69381c2
 
 
 
 
86346c3
 
 
 
 
 
 
 
 
 
 
 
733b482
 
 
 
e020321
733b482
44cc3dd
65f492b
 
733b482
 
 
 
a8813ea
 
733b482
 
 
b4f99ee
 
 
733b482
 
69381c2
 
 
 
6a636b6
69381c2
 
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

import os
import json
import numpy as np
import faiss
from flask import Flask, request, jsonify, send_file
from transformers import LlamaTokenizer, LlamaModel
import torch
from tqdm import tqdm

# Load tokenizer and model (global for both embedding generation and API)
model_name = "openlm-research/open_llama_3b_v2"
tokenizer = LlamaTokenizer.from_pretrained(model_name)
model = LlamaModel.from_pretrained(model_name)
# Set the pad_token to eos_token
tokenizer.pad_token = tokenizer.eos_token

# model.eval()
device = "cuda" if torch.cuda.is_available() else "cpu"

model = model.to(device)

app = Flask(__name__)

file_path = "products.json"
# Function to generate embeddings
def generate_embeddings(batch_size=64, max_length=512):
    # Load product data
    with open(file_path, "r") as f:
        products = json.load(f)

    # Initialize storage for embeddings
    embeddings = []
    product_ids = []

    # Process products in batches
    num_batches = len(products) // batch_size + (len(products) % batch_size > 0)
    for i in tqdm(range(num_batches), desc="Generating embeddings"):
        batch = products[i * batch_size : (i + 1) * batch_size]
        descriptions = [product["description"] for product in batch]
        ids = [product["id"] for product in batch]
        
        # Tokenize and move inputs to the device
        inputs = tokenizer(
            descriptions, return_tensors="pt", padding=True, truncation=True, max_length=max_length
        ).to(device)
        
        # Generate embeddings
        with torch.no_grad():
            outputs = model(**inputs, output_hidden_states=True)
        batch_embeddings = outputs.hidden_states[-1].mean(dim=1).cpu().numpy()
        
        # Append results
        embeddings.extend(batch_embeddings)
        product_ids.extend(ids)

    # Convert embeddings to NumPy array
    embeddings = np.array(embeddings)
    product_ids = np.array(product_ids)

    # Save embeddings to FAISS index
    dimension = embeddings.shape[1]  # Embedding size
    index = faiss.IndexFlatL2(dimension)
    index.add(embeddings)
    faiss.write_index(index, "product_index.faiss")
    np.save("product_ids.npy", product_ids)

    print(f"Embeddings for {len(product_ids)} products generated successfully!")
    return f"Embeddings for {len(product_ids)} products generated successfully!"

@app.route("/", methods=["GET"])
def home():
    return "Flask app is running!"


# API Endpoint to Trigger Embedding Generation
@app.route("/generate_embeddings", methods=["POST"])
def trigger_embedding_generation():
    print("creating embeddings")
    generate_embeddings()
    return jsonify({"message": "Embeddings generated successfully!"})

# API Endpoint to Get Similar Products
@app.route("/similar", methods=["POST"])
def get_similar_products():
    print("finding right product")
    index = faiss.read_index("product_index.faiss")
    product_ids = np.load("product_ids.npy")
    with open(file_path, "r") as f:
        products = {p["id"]: p for p in json.load(f)}

    data = request.json
    product_id = data.get("product_id")
    product_index = np.where(product_ids == product_id)[0]
    if len(product_index) == 0:
        return jsonify({"error": "Product ID not found"}), 404

    query_embedding = index.reconstruct(int(product_index[0]))

    distances, indices = index.search(np.expand_dims(query_embedding, axis=0), k=5)
    similar_ids = product_ids[indices[0]].tolist()
    similar_products = [products[pid] for pid in similar_ids if pid != product_id]
    return jsonify({"similar_products": similar_products})

@app.route("/download/<filename>", methods=["GET"])
def download_file(filename):
    try:
        # Validate allowed files
        if filename not in ["product_index.faiss", "product_ids.npy"]:
            return {"error": "File not found or not allowed"}, 404
        
        # Serve the file for download
        return send_file(filename, as_attachment=True)
    except Exception as e:
        return {"error": str(e)}, 500

def get_similar_produdcts_direct(product_id):
    print("finding right product")
    index = faiss.read_index("product_index.faiss")
    product_ids = np.load("product_ids.npy")
    with open(file_path, "r") as f:
        products = {p["id"]: p for p in json.load(f)}
    # print(products[:6])
    print(len(products))
    print(product_id)
    product_index = np.where(product_ids == product_id)[0]
    if len(product_index) == 0:
        return jsonify({"error": "Product ID not found"}), 404

    query_embedding = index.reconstruct(int(product_index[0]))

    distances, indices = index.search(np.expand_dims(query_embedding, axis=0), k=5)
    similar_ids = product_ids[indices[0]].tolist()
    similar_products = [products[pid] for pid in similar_ids if pid != product_id]
    print("Ran fine")
    print(similar_products)
    # return jsonify({"similar_products": similar_products})


if __name__ == "__main__":
    # Check if embeddings already exist; if not, generate them
    if not os.path.exists("product_index.faiss") or not os.path.exists("product_ids.npy"):
        generate_embeddings()
    # get_similar_produdcts_direct(2)
    app.run(host="0.0.0.0", port=7860)