Update app.py
Browse files
app.py
CHANGED
|
@@ -22,7 +22,6 @@ import seaborn as sns
|
|
| 22 |
from collections import Counter
|
| 23 |
import pickle
|
| 24 |
from transformers import ResNetForImageClassification
|
| 25 |
-
from datasets import load_dataset, Dataset # Hugging Face datasets library
|
| 26 |
|
| 27 |
# Set up logging
|
| 28 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
@@ -35,35 +34,13 @@ os.chdir(WORKING_DIR)
|
|
| 35 |
# Verify the current directory
|
| 36 |
logging.info(f"Current working directory: {os.getcwd()}")
|
| 37 |
|
| 38 |
-
#
|
| 39 |
-
|
| 40 |
|
| 41 |
-
#
|
| 42 |
-
|
| 43 |
-
""
|
| 44 |
-
|
| 45 |
-
dataset = Dataset.from_dict(data)
|
| 46 |
-
dataset.push_to_hub(dataset_name)
|
| 47 |
-
logging.info(f"Data saved to Hugging Face Hub: {dataset_name}")
|
| 48 |
-
except Exception as e:
|
| 49 |
-
logging.error(f"Error saving data to Hugging Face Hub: {e}")
|
| 50 |
-
|
| 51 |
-
# Function to load data from Hugging Face Hub
|
| 52 |
-
def load_from_hub(dataset_name):
|
| 53 |
-
"""Load data from Hugging Face Hub."""
|
| 54 |
-
try:
|
| 55 |
-
dataset = load_dataset(dataset_name)
|
| 56 |
-
logging.info(f"Data loaded from Hugging Face Hub: {dataset_name}")
|
| 57 |
-
return dataset["train"].to_dict() # Convert to dictionary
|
| 58 |
-
except Exception as e:
|
| 59 |
-
logging.error(f"Error loading data from Hugging Face Hub: {e}")
|
| 60 |
-
return None
|
| 61 |
-
|
| 62 |
-
# Load cache from Hugging Face Hub
|
| 63 |
-
CACHE_KEY = "image_text_cache"
|
| 64 |
-
cache = load_from_hub(DATASET_NAME)
|
| 65 |
-
if cache and CACHE_KEY in cache:
|
| 66 |
-
cache = cache[CACHE_KEY]
|
| 67 |
else:
|
| 68 |
cache = {}
|
| 69 |
|
|
@@ -118,22 +95,6 @@ except FileNotFoundError:
|
|
| 118 |
logging.error("solved.json not found. Please ensure the file exists.")
|
| 119 |
exit()
|
| 120 |
|
| 121 |
-
# Load competitor data from JSON
|
| 122 |
-
logging.info("Loading competitor data from JSON...")
|
| 123 |
-
try:
|
| 124 |
-
with open('competitors_data.json', 'r') as f:
|
| 125 |
-
competitor_data = json.load(f)
|
| 126 |
-
# Combine all competitors' data into a single DataFrame
|
| 127 |
-
competitor_dfs = []
|
| 128 |
-
for competitor, posts in competitor_data.items():
|
| 129 |
-
df = pd.json_normalize(posts)
|
| 130 |
-
df['competitor'] = competitor # Add competitor name for tracking
|
| 131 |
-
competitor_dfs.append(df)
|
| 132 |
-
competitor_df = pd.concat(competitor_dfs, ignore_index=True)
|
| 133 |
-
except FileNotFoundError:
|
| 134 |
-
logging.error("competitors_data.json not found. Please ensure the file exists.")
|
| 135 |
-
exit()
|
| 136 |
-
|
| 137 |
# Ensure required columns exist in your company's data
|
| 138 |
required_columns = ['likes', 'comments', 'shares', 'posting_time', 'caption', 'hashtags']
|
| 139 |
missing_columns = [col for col in required_columns if col not in your_df.columns]
|
|
@@ -149,23 +110,6 @@ if missing_columns:
|
|
| 149 |
your_df[col] = [[] for _ in range(len(your_df))] # Fill with default value (list of empty lists)
|
| 150 |
logging.info("Default values added for missing columns.")
|
| 151 |
|
| 152 |
-
# Ensure required columns exist in competitor data
|
| 153 |
-
required_columns = ['caption', 'hashtags', 'likes', 'comments', 'date', 'image_url']
|
| 154 |
-
missing_columns = [col for col in required_columns if col not in competitor_df.columns]
|
| 155 |
-
|
| 156 |
-
if missing_columns:
|
| 157 |
-
logging.warning(f"Missing required columns in competitor data: {missing_columns}")
|
| 158 |
-
for col in missing_columns:
|
| 159 |
-
if col == 'caption':
|
| 160 |
-
competitor_df[col] = '' # Fill with default value (empty string)
|
| 161 |
-
elif col == 'hashtags':
|
| 162 |
-
competitor_df[col] = [[] for _ in range(len(competitor_df))] # Fill with default value (list of empty lists)
|
| 163 |
-
elif col == 'image_url':
|
| 164 |
-
competitor_df[col] = '' # Fill with default value (empty string)
|
| 165 |
-
else:
|
| 166 |
-
competitor_df[col] = 0 # Fill with default value (integer)
|
| 167 |
-
logging.info("Default values added for missing columns.")
|
| 168 |
-
|
| 169 |
# Process your company's data
|
| 170 |
logging.info("Processing your company's data...")
|
| 171 |
your_df['posting_time'] = pd.to_datetime(your_df['posting_time'], format='%Y-%m-%d %H:%M:%S', errors='coerce')
|
|
@@ -176,33 +120,20 @@ your_df['hashtag_count'] = your_df['hashtags'].apply(len)
|
|
| 176 |
your_df['caption_sentiment'] = your_df['caption'].apply(lambda x: TextBlob(x).sentiment.polarity)
|
| 177 |
your_df['sentiment'] = your_df['caption_sentiment']
|
| 178 |
|
| 179 |
-
#
|
| 180 |
-
|
| 181 |
-
competitor_df['posting_time'] = pd.to_datetime(competitor_df['date'], format='%Y-%m-%d %H:%M:%S', errors='coerce')
|
| 182 |
-
competitor_df = competitor_df[competitor_df['posting_time'].notna()]
|
| 183 |
-
competitor_df['engagement_rate'] = competitor_df['likes'] + competitor_df['comments']
|
| 184 |
-
competitor_df['caption_length'] = competitor_df['caption'].apply(len)
|
| 185 |
-
competitor_df['hashtag_count'] = competitor_df['hashtags'].apply(len)
|
| 186 |
-
competitor_df['caption_sentiment'] = competitor_df['caption'].apply(lambda x: TextBlob(x).sentiment.polarity)
|
| 187 |
-
competitor_df['sentiment'] = competitor_df['caption_sentiment']
|
| 188 |
-
|
| 189 |
-
# Combine your company's data and competitor data for model training
|
| 190 |
-
logging.info("Combining your company's data and competitor data for model training...")
|
| 191 |
-
combined_df = pd.concat([your_df, competitor_df], ignore_index=True)
|
| 192 |
-
|
| 193 |
-
# Handle missing or invalid image URLs
|
| 194 |
-
combined_df['image_url'] = combined_df['image_url'].fillna('')
|
| 195 |
|
| 196 |
# Process only new images (those not in the cache)
|
| 197 |
logging.info("Extracting text from new images...")
|
| 198 |
-
new_images =
|
| 199 |
new_images = process_new_images(new_images)
|
| 200 |
|
| 201 |
-
# Update the
|
| 202 |
-
|
| 203 |
|
| 204 |
-
# Save the
|
| 205 |
-
|
|
|
|
| 206 |
|
| 207 |
logging.info("Incremental processing complete!")
|
| 208 |
|
|
@@ -245,7 +176,7 @@ def analyze_image(image_url):
|
|
| 245 |
return None
|
| 246 |
|
| 247 |
logging.info("Analyzing image content...")
|
| 248 |
-
|
| 249 |
|
| 250 |
# Define scoring criteria for posts
|
| 251 |
def rate_post(row):
|
|
@@ -264,11 +195,11 @@ def rate_post(row):
|
|
| 264 |
return score
|
| 265 |
|
| 266 |
logging.info("Rating posts...")
|
| 267 |
-
|
| 268 |
|
| 269 |
# Log the results
|
| 270 |
logging.info("Post Ratings:")
|
| 271 |
-
print(
|
| 272 |
|
| 273 |
# Train models using all features
|
| 274 |
logging.info("Training models using all features...")
|
|
@@ -280,11 +211,11 @@ features = [
|
|
| 280 |
|
| 281 |
# Viral Potential Prediction
|
| 282 |
logging.info("Training viral potential prediction model...")
|
| 283 |
-
|
| 284 |
-
|
| 285 |
|
| 286 |
-
X =
|
| 287 |
-
y =
|
| 288 |
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
|
| 289 |
|
| 290 |
viral_model = RandomForestClassifier(random_state=42)
|
|
@@ -295,8 +226,8 @@ logging.info(f"Viral Potential Model Accuracy: {accuracy:.4f}")
|
|
| 295 |
|
| 296 |
# Engagement Rate Prediction
|
| 297 |
logging.info("Training engagement rate prediction model...")
|
| 298 |
-
X =
|
| 299 |
-
y =
|
| 300 |
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
|
| 301 |
|
| 302 |
engagement_model = XGBRegressor(random_state=42)
|
|
@@ -307,11 +238,11 @@ logging.info(f"Engagement Rate Prediction Model - MAE: {mae:.4f}")
|
|
| 307 |
|
| 308 |
# Promotion Strategy
|
| 309 |
logging.info("Training promotion prediction model...")
|
| 310 |
-
promotion_threshold =
|
| 311 |
-
|
| 312 |
|
| 313 |
-
X =
|
| 314 |
-
y =
|
| 315 |
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
|
| 316 |
|
| 317 |
promotion_model = LogisticRegression(random_state=42)
|
|
|
|
| 22 |
from collections import Counter
|
| 23 |
import pickle
|
| 24 |
from transformers import ResNetForImageClassification
|
|
|
|
| 25 |
|
| 26 |
# Set up logging
|
| 27 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
|
|
| 34 |
# Verify the current directory
|
| 35 |
logging.info(f"Current working directory: {os.getcwd()}")
|
| 36 |
|
| 37 |
+
# Cache file to store extracted text
|
| 38 |
+
CACHE_FILE = os.path.join(WORKING_DIR, "image_text_cache.pkl")
|
| 39 |
|
| 40 |
+
# Load cache if it exists
|
| 41 |
+
if os.path.exists(CACHE_FILE):
|
| 42 |
+
with open(CACHE_FILE, "rb") as f:
|
| 43 |
+
cache = pickle.load(f)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
else:
|
| 45 |
cache = {}
|
| 46 |
|
|
|
|
| 95 |
logging.error("solved.json not found. Please ensure the file exists.")
|
| 96 |
exit()
|
| 97 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
# Ensure required columns exist in your company's data
|
| 99 |
required_columns = ['likes', 'comments', 'shares', 'posting_time', 'caption', 'hashtags']
|
| 100 |
missing_columns = [col for col in required_columns if col not in your_df.columns]
|
|
|
|
| 110 |
your_df[col] = [[] for _ in range(len(your_df))] # Fill with default value (list of empty lists)
|
| 111 |
logging.info("Default values added for missing columns.")
|
| 112 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 113 |
# Process your company's data
|
| 114 |
logging.info("Processing your company's data...")
|
| 115 |
your_df['posting_time'] = pd.to_datetime(your_df['posting_time'], format='%Y-%m-%d %H:%M:%S', errors='coerce')
|
|
|
|
| 120 |
your_df['caption_sentiment'] = your_df['caption'].apply(lambda x: TextBlob(x).sentiment.polarity)
|
| 121 |
your_df['sentiment'] = your_df['caption_sentiment']
|
| 122 |
|
| 123 |
+
# Handle missing or invalid image URLs in your company's data
|
| 124 |
+
your_df['image_url'] = your_df['image_url'].fillna('')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 125 |
|
| 126 |
# Process only new images (those not in the cache)
|
| 127 |
logging.info("Extracting text from new images...")
|
| 128 |
+
new_images = your_df[~your_df['image_url'].isin(cache.keys())]
|
| 129 |
new_images = process_new_images(new_images)
|
| 130 |
|
| 131 |
+
# Update the DataFrame with extracted text
|
| 132 |
+
your_df.update(new_images)
|
| 133 |
|
| 134 |
+
# Save the cache
|
| 135 |
+
with open(CACHE_FILE, "wb") as f:
|
| 136 |
+
pickle.dump(cache, f)
|
| 137 |
|
| 138 |
logging.info("Incremental processing complete!")
|
| 139 |
|
|
|
|
| 176 |
return None
|
| 177 |
|
| 178 |
logging.info("Analyzing image content...")
|
| 179 |
+
your_df['image_analysis'] = your_df['image_url'].apply(analyze_image)
|
| 180 |
|
| 181 |
# Define scoring criteria for posts
|
| 182 |
def rate_post(row):
|
|
|
|
| 195 |
return score
|
| 196 |
|
| 197 |
logging.info("Rating posts...")
|
| 198 |
+
your_df['post_score'] = your_df.apply(rate_post, axis=1)
|
| 199 |
|
| 200 |
# Log the results
|
| 201 |
logging.info("Post Ratings:")
|
| 202 |
+
print(your_df[['post_id', 'post_score']].head())
|
| 203 |
|
| 204 |
# Train models using all features
|
| 205 |
logging.info("Training models using all features...")
|
|
|
|
| 211 |
|
| 212 |
# Viral Potential Prediction
|
| 213 |
logging.info("Training viral potential prediction model...")
|
| 214 |
+
viral_threshold = your_df['engagement_rate'].quantile(0.9)
|
| 215 |
+
your_df['viral'] = your_df['engagement_rate'].apply(lambda x: 1 if x >= viral_threshold else 0)
|
| 216 |
|
| 217 |
+
X = your_df[features]
|
| 218 |
+
y = your_df['viral']
|
| 219 |
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
|
| 220 |
|
| 221 |
viral_model = RandomForestClassifier(random_state=42)
|
|
|
|
| 226 |
|
| 227 |
# Engagement Rate Prediction
|
| 228 |
logging.info("Training engagement rate prediction model...")
|
| 229 |
+
X = your_df[features]
|
| 230 |
+
y = your_df['engagement_rate']
|
| 231 |
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
|
| 232 |
|
| 233 |
engagement_model = XGBRegressor(random_state=42)
|
|
|
|
| 238 |
|
| 239 |
# Promotion Strategy
|
| 240 |
logging.info("Training promotion prediction model...")
|
| 241 |
+
promotion_threshold = your_df['engagement_rate'].quantile(0.8)
|
| 242 |
+
your_df['promote'] = your_df['engagement_rate'].apply(lambda x: 1 if x >= promotion_threshold else 0)
|
| 243 |
|
| 244 |
+
X = your_df[features]
|
| 245 |
+
y = your_df['promote']
|
| 246 |
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
|
| 247 |
|
| 248 |
promotion_model = LogisticRegression(random_state=42)
|