File size: 7,354 Bytes
353ae3d
 
c7c97ec
36b4c49
382cd22
c7c97ec
 
90fde42
353ae3d
 
c7c97ec
1d93c5b
c7c97ec
 
 
6204642
353ae3d
2085d11
c7c97ec
382cd22
c7c97ec
 
382cd22
c7c97ec
36b4c49
 
 
 
353ae3d
c7c97ec
36b4c49
 
 
 
 
ccc7e0f
382cd22
c7c97ec
 
b296a5f
c7c97ec
 
382cd22
c7c97ec
36b4c49
 
c7c97ec
36b4c49
 
c7c97ec
b296a5f
 
6204642
b296a5f
6204642
b296a5f
1d93c5b
b296a5f
 
 
 
 
 
6204642
b296a5f
1d93c5b
6204642
1d93c5b
6204642
b296a5f
36b4c49
 
c7c97ec
b296a5f
1d93c5b
b296a5f
 
 
 
 
 
 
6204642
 
 
 
b296a5f
 
382cd22
b296a5f
 
 
 
 
6204642
b296a5f
382cd22
 
 
 
b296a5f
382cd22
b296a5f
c7c97ec
 
2cda063
c7c97ec
 
1d93c5b
6204642
1d93c5b
6204642
1d93c5b
 
 
6204642
2cda063
 
 
 
 
 
 
21901b7
2cda063
 
c7c97ec
 
1d93c5b
c7c97ec
2cda063
c7c97ec
2cda063
c7c97ec
 
 
36b4c49
2cda063
c7c97ec
 
 
353ae3d
c7c97ec
353ae3d
c7c97ec
2cda063
 
 
 
 
 
21901b7
 
 
 
2cda063
c7c97ec
 
 
2cda063
353ae3d
2cda063
 
 
353ae3d
 
 
cd33177
2cda063
353ae3d
 
 
 
 
 
cd33177
 
 
353ae3d
 
 
2cda063
353ae3d
2cda063
 
 
 
 
c7c97ec
353ae3d
2cda063
353ae3d
2cda063
 
 
 
 
 
 
 
 
353ae3d
2cda063
c7c97ec
 
353ae3d
c7c97ec
2cda063
1d93c5b
36b4c49
353ae3d
90fde42
353ae3d
2cda063
b296a5f
2cda063
b296a5f
 
 
 
2cda063
b296a5f
2cda063
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
import pandas as pd
import numpy as np
import warnings
import os
from typing import List, Dict, Any

warnings.filterwarnings('ignore')

print("Importing libraries...")

from langchain_community.vectorstores import FAISS
from langchain_huggingface import HuggingFaceEmbeddings, HuggingFaceEndpoint
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough

print("βœ“ All imports successful!")

# ============================================================================
# LOAD PRE-BUILT VECTOR STORE
# ============================================================================

print("\nLoading pre-built FAISS vector store...")

embeddings = HuggingFaceEmbeddings(
    model_name="BAAI/bge-large-en-v1.5",
    model_kwargs={'device': 'cpu'},
    encode_kwargs={'normalize_embeddings': True}
)

vectorstore = FAISS.load_local(
    "faiss_index", 
    embeddings,
    allow_dangerous_deserialization=True
)

print("βœ“ Vector store loaded!")

# ============================================================================
# LOAD YOUR DATA WITH SENTIMENT
# ============================================================================

print("\nLoading data files...")

medical_df = pd.read_csv('medical_info.csv')
print(f"βœ“ Loaded {len(medical_df):,} medical Q&As")

ingredient_df = pd.read_csv('ingredient_list_final.csv')
print(f"βœ“ Loaded {len(ingredient_df):,} ingredients")

# Load YOUR sentiment analysis from CSV
print("Loading YOUR sentiment analysis from CSV...")
try:
    sentiment_df = pd.read_csv('sentiment_analysis.csv')
    print(f"βœ“ Loaded YOUR sentiment for {len(sentiment_df):,} products!")
    print(f"   Columns: {list(sentiment_df.columns)}")
    has_sentiment = True
except FileNotFoundError:
    print("⚠️  sentiment_analysis.csv not found!")
    print("   Run CONVERT_PICKLE_COLAB.py in Colab to create it")
    print("   Continuing without sentiment...")
    sentiment_df = None
    has_sentiment = False
except Exception as e:
    print(f"⚠️  Error loading sentiment CSV: {e}")
    print("   Continuing without sentiment...")
    sentiment_df = None
    has_sentiment = False

# Load products
products = pd.read_csv('product_info.csv', low_memory=False)
skincare = products[products['primary_category'] == 'Skincare'].copy()

# Merge with YOUR sentiment analysis
if has_sentiment and sentiment_df is not None:
    print("Merging sentiment data...")
    
    # Make sure product_id types match
    skincare['product_id'] = skincare['product_id'].astype(str)
    sentiment_df['product_id'] = sentiment_df['product_id'].astype(str)
    
    # Merge
    skincare = skincare.merge(
        sentiment_df[['product_id', 'avg_rating', 'total_reviews', 
                     'predicted_sentiment', 'positive_rating_pct']],
        on='product_id', 
        how='left',
        suffixes=('', '_sentiment')
    )
    
    # Count how many products got sentiment
    with_sentiment = skincare['predicted_sentiment'].notna().sum()
    print(f"βœ“ Merged sentiment for {with_sentiment:,} products!")
    
else:
    # No sentiment data
    skincare['avg_rating'] = 0
    skincare['total_reviews'] = 0
    skincare['predicted_sentiment'] = 'unknown'
    skincare['positive_rating_pct'] = 0
    print("⚠️  Products have no sentiment data")

print(f"βœ“ Loaded {len(skincare):,} total products")

# ============================================================================
# LOAD LLM - Using a working free model
# ============================================================================

print("\nConnecting to HuggingFace Inference API...")

hf_token = os.environ.get('HUGGINGFACEHUB_API_TOKEN')

if not hf_token:
    print("❌ ERROR: HUGGINGFACEHUB_API_TOKEN not found!")
    raise ValueError("Missing API token")

# Use Mistral with the correct configuration
from langchain_huggingface import ChatHuggingFace

llm = ChatHuggingFace(
    llm=HuggingFaceEndpoint(
        repo_id="mistralai/Mistral-7B-Instruct-v0.2",
        temperature=0.3,
        max_new_tokens=1500,
        huggingfacehub_api_token=hf_token,
    )
)

print("βœ“ Connected to Inference API!")


# ============================================================================
# SKINCARE AGENT - Updated to work with ChatHuggingFace
# ============================================================================

class SkincareAgent:
    """Skincare consultant agent"""

    def __init__(self, vectorstore, llm):
        self.vectorstore = vectorstore
        self.llm = llm
        self.retriever = vectorstore.as_retriever(search_kwargs={"k": 8})
        self.conversation_history = []
        self.last_results = []

        # Updated prompt for chat format
        from langchain_core.prompts import ChatPromptTemplate
        
        self.prompt_template = ChatPromptTemplate.from_messages([
            ("system", """You are a professional skincare consultant with expertise in dermatology, 
            cosmetic chemistry, and product recommendations. Provide helpful, accurate, and 
            personalized responses. When listing recommendations:
            - Give 3-5 specific products with brief explanations
            - Complete all numbered points
            - Be thorough but concise"""),
            ("human", """Based on this information:

{context}

Answer this question: {question}

Provide specific product recommendations when relevant, explain ingredients, and consider any 
budget mentioned. Highlight customer sentiment when available.""")
        ])

    def chat(self, query: str, show_details: bool = False) -> str:
        """Main chat function"""
        docs = self.retriever.invoke(query)

        self.last_results = [
            {
                'type': doc.metadata.get('type'),
                'name': doc.metadata.get('name', ''),
                'brand': doc.metadata.get('brand', ''),
                'price': doc.metadata.get('price', 0),
                'sentiment': doc.metadata.get('sentiment', 'neutral'),
                'rating': doc.metadata.get('rating', 0),
                'positive_pct': doc.metadata.get('positive_pct', 0),
            }
            for doc in docs[:10]
        ]

        context = "\n\n".join([doc.page_content for doc in docs[:8]])

        # Use invoke instead of the old chain syntax
        messages = self.prompt_template.format_messages(
            context=context,
            question=query
        )
        
        response = self.llm.invoke(messages)
        
        # Extract content from response
        if hasattr(response, 'content'):
            text = response.content
        else:
            text = str(response)

        return text.strip()

    def get_last_results(self):
        return self.last_results

    def clear_history(self):
        self.conversation_history = []
        self.last_results = []


# Create agent
print("\nCreating agent...")
agent = SkincareAgent(vectorstore, llm)
print("βœ“ Agent ready!")

print("\n" + "=" * 70)
print("SKINCARE AGENT READY!")
print("=" * 70)
if has_sentiment:
    print("βœ… WITH YOUR SENTIMENT ANALYSIS!")
    print(f"βœ… {with_sentiment:,} products have ratings & sentiment")
else:
    print("⚠️ Running without sentiment")
print("βœ… Inference API (fast & free)")
print("=" * 70)