Spaces:
Running
Running
| import os | |
| import pandas as pd | |
| import numpy as np | |
| import re | |
| import json | |
| import urllib.request | |
| import zipfile | |
| import tarfile | |
| import io | |
| import logging | |
| import traceback | |
| from tqdm import tqdm | |
| # Configure logging | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| def download_sarcasm_dataset(): | |
| """ | |
| Download and prepare a sarcasm detection dataset. | |
| Returns a pandas DataFrame with text and sentiment columns. | |
| """ | |
| sarcasm_dir = os.path.join(os.getcwd(), 'datasets', 'sarcasm') | |
| os.makedirs(sarcasm_dir, exist_ok=True) | |
| sarcasm_data = [] | |
| try: | |
| # News Headlines Dataset for Sarcasm Detection | |
| headlines_file = os.path.join(sarcasm_dir, 'Sarcasm_Headlines_Dataset.json') | |
| if not os.path.exists(headlines_file): | |
| logger.info("Downloading News Headlines Sarcasm Dataset...") | |
| headlines_url = 'https://raw.githubusercontent.com/rishabhmisra/News-Headlines-Dataset-For-Sarcasm-Detection/master/Sarcasm_Headlines_Dataset.json' | |
| urllib.request.urlretrieve(headlines_url, headlines_file) | |
| # Load and process the dataset | |
| logger.info("Processing News Headlines Sarcasm Dataset...") | |
| with open(headlines_file, 'r', encoding='utf-8') as f: | |
| for line in tqdm(f, desc="Processing Headlines"): | |
| try: | |
| article = json.loads(line) | |
| is_sarcastic = article.get('is_sarcastic', 0) | |
| headline = article.get('headline', '') | |
| # Skip very short headlines | |
| if len(headline.split()) < 4: | |
| continue | |
| # Map sarcastic (1) to negative (0) and non-sarcastic (0) to positive (1) | |
| # This is because sarcasm usually implies negative sentiment | |
| sentiment = 0 if is_sarcastic else 1 | |
| # Only add clear examples - verify sarcasm with keyword checks | |
| if is_sarcastic: | |
| sarcasm_indicators = any(kw in headline.lower() for kw in | |
| ['perfect', 'best', 'greatest', 'finally', 'exactly', 'amazing', 'brilliant']) | |
| if sarcasm_indicators: | |
| sarcasm_data.append({ | |
| 'text': headline, | |
| 'sentiment': sentiment, | |
| 'source': 'sarcasm_headlines' | |
| }) | |
| else: | |
| # Add a smaller subset of non-sarcastic headlines | |
| if np.random.random() < 0.2: # Only keep 20% of non-sarcastic examples | |
| sarcasm_data.append({ | |
| 'text': headline, | |
| 'sentiment': sentiment, | |
| 'source': 'sarcasm_headlines' | |
| }) | |
| except: | |
| continue | |
| # Try to get the Reddit sarcasm dataset if available | |
| reddit_file = os.path.join(sarcasm_dir, 'train-balanced-sarcasm.csv') | |
| if os.path.exists(reddit_file): | |
| logger.info("Processing Reddit Sarcasm Dataset...") | |
| try: | |
| # This dataset is large, so read only a sample | |
| reddit_df = pd.read_csv(reddit_file, nrows=10000) | |
| for _, row in tqdm(reddit_df.iterrows(), total=len(reddit_df), desc="Processing Reddit"): | |
| try: | |
| comment = row.get('comment', '') | |
| is_sarcastic = row.get('label', 0) | |
| # Skip very short or long comments | |
| if len(comment.split()) < 5 or len(comment.split()) > 30: | |
| continue | |
| # Map sarcastic (1) to negative (0) and non-sarcastic (0) to positive (1) | |
| sentiment = 0 if is_sarcastic else 1 | |
| # Only add clear examples with good indicators | |
| if is_sarcastic: | |
| sarcasm_indicators = any(kw in comment.lower() for kw in | |
| ['perfect', 'best', 'greatest', 'finally', 'exactly', 'amazing', 'brilliant', | |
| 'love', 'absolutely', 'totally', 'clearly', 'obviously', 'enjoy', 'surely']) | |
| if sarcasm_indicators: | |
| sarcasm_data.append({ | |
| 'text': comment, | |
| 'sentiment': sentiment, | |
| 'source': 'reddit_sarcasm' | |
| }) | |
| else: | |
| # Add a smaller subset of non-sarcastic comments | |
| if np.random.random() < 0.2: # Only keep 20% of non-sarcastic examples | |
| sarcasm_data.append({ | |
| 'text': comment, | |
| 'sentiment': sentiment, | |
| 'source': 'reddit_sarcasm' | |
| }) | |
| except: | |
| continue | |
| except Exception as e: | |
| logger.warning(f"Error processing Reddit sarcasm data: {e}") | |
| # Add manually curated examples with known patterns | |
| logger.info("Adding manually curated sarcasm examples...") | |
| manual_examples = [ | |
| # Sarcastic examples (negative sentiment) | |
| {"text": "If you enjoy falling asleep during movies, this one's perfect for you!", "sentiment": 0}, | |
| {"text": "The best part of this movie was when the credits rolled.", "sentiment": 0}, | |
| {"text": "I'd rather watch paint dry than sit through this again.", "sentiment": 0}, | |
| {"text": "Exactly what the world needed, another superhero movie.", "sentiment": 0}, | |
| {"text": "Oh great, another remake. Hollywood is so original these days.", "sentiment": 0}, | |
| {"text": "Wow, what an original plot twist! I totally didn't see that coming... said no one ever.", "sentiment": 0}, | |
| {"text": "Just what I always wanted, two hours of my life I'll never get back.", "sentiment": 0}, | |
| {"text": "If you're looking for a cure for insomnia, this movie is perfect!", "sentiment": 0}, | |
| {"text": "The director really outdid himself. I've never been so bored.", "sentiment": 0}, | |
| {"text": "Amazing! I've finally found a movie worse than my ex's personality.", "sentiment": 0}, | |
| # Non-sarcastic examples (positive sentiment) | |
| {"text": "This film was genuinely engaging from start to finish.", "sentiment": 1}, | |
| {"text": "I thoroughly enjoyed the creative storyline and character development.", "sentiment": 1}, | |
| {"text": "The director's vision really came through in this unique movie.", "sentiment": 1}, | |
| {"text": "This is definitely worth watching for the stunning visuals alone.", "sentiment": 1}, | |
| {"text": "A refreshing take on the genre that kept me interested throughout.", "sentiment": 1} | |
| ] | |
| for example in manual_examples: | |
| example['source'] = 'manual_curated' | |
| sarcasm_data.append(example) | |
| logger.info(f"Collected {len(sarcasm_data)} sarcasm examples") | |
| return pd.DataFrame(sarcasm_data) | |
| except Exception as e: | |
| logger.error(f"Error downloading sarcasm dataset: {e}") | |
| logger.error(traceback.format_exc()) | |
| return pd.DataFrame(columns=['text', 'sentiment', 'source']) | |
| def download_idiom_dataset(): | |
| """ | |
| Create a dataset of idioms and expressions with their associated sentiments. | |
| Returns a pandas DataFrame with text and sentiment columns. | |
| """ | |
| idiom_dir = os.path.join(os.getcwd(), 'datasets', 'idioms') | |
| os.makedirs(idiom_dir, exist_ok=True) | |
| idiom_data = [] | |
| try: | |
| # Create a synthetic dataset of sentences containing idioms | |
| logger.info("Creating idiom dataset...") | |
| # Dictionary of negative idioms with example sentences | |
| negative_idioms = { | |
| "waste of time": [ | |
| "The movie was a complete waste of time.", | |
| "Going to that conference was a waste of time and money.", | |
| "Reading this book is a waste of time if you're looking for new insights." | |
| ], | |
| "leave a lot to be desired": [ | |
| "The film's special effects leave a lot to be desired.", | |
| "Their customer service leaves a lot to be desired.", | |
| "The restaurant's cleanliness leaves a lot to be desired." | |
| ], | |
| "miss the mark": [ | |
| "The remake completely misses the mark compared to the original.", | |
| "This adaptation missed the mark by changing key elements of the story.", | |
| "Their attempt at humor missed the mark and fell flat." | |
| ], | |
| "train wreck": [ | |
| "The whole event was a train wreck from start to finish.", | |
| "I couldn't look away from the train wreck that was their performance.", | |
| "The interview turned into a complete train wreck." | |
| ], | |
| "not worth it": [ | |
| "The expensive ticket price was not worth it for such a mediocre show.", | |
| "The long wait was not worth it for the quality of food we received.", | |
| "The extra features are not worth the subscription cost." | |
| ] | |
| } | |
| # Dictionary of positive idioms with example sentences | |
| positive_idioms = { | |
| "breath of fresh air": [ | |
| "After so many sequels, this original story is a breath of fresh air.", | |
| "Her unique approach to the problem was a breath of fresh air.", | |
| "The new management style is a breath of fresh air for the company." | |
| ], | |
| "worth every penny": [ | |
| "The concert tickets were expensive but worth every penny.", | |
| "This camera is worth every penny if you're serious about photography.", | |
| "The guided tour was worth every penny for the insider knowledge we gained." | |
| ], | |
| "edge of my seat": [ | |
| "The thriller had me on the edge of my seat the entire time.", | |
| "I was on the edge of my seat during the championship game.", | |
| "The final chapters had me on the edge of my seat until the very end." | |
| ], | |
| "blown away": [ | |
| "I was completely blown away by the twist ending.", | |
| "We were blown away by the quality of their presentation.", | |
| "Everyone was blown away by her vocal performance." | |
| ], | |
| "exceeded expectations": [ | |
| "The new restaurant exceeded all my expectations.", | |
| "The sequel actually exceeded my expectations.", | |
| "Their service exceeded our expectations in every way." | |
| ] | |
| } | |
| # Add negative idiom examples | |
| for idiom, sentences in negative_idioms.items(): | |
| for sentence in sentences: | |
| idiom_data.append({ | |
| 'text': sentence, | |
| 'sentiment': 0, # Negative | |
| 'source': 'idiom_synthetic', | |
| 'idiom': idiom | |
| }) | |
| # Add variations with different contexts | |
| contexts = [ | |
| f"I think {sentence.lower()}", | |
| f"In my opinion, {sentence.lower()}", | |
| f"I felt that {sentence.lower()}", | |
| f"Many people agree that {sentence.lower()}", | |
| f"It's clear that {sentence.lower()}" | |
| ] | |
| for context in contexts: | |
| if np.random.random() < 0.5: # Only add some variations | |
| idiom_data.append({ | |
| 'text': context, | |
| 'sentiment': 0, # Negative | |
| 'source': 'idiom_synthetic_variation', | |
| 'idiom': idiom | |
| }) | |
| # Add positive idiom examples | |
| for idiom, sentences in positive_idioms.items(): | |
| for sentence in sentences: | |
| idiom_data.append({ | |
| 'text': sentence, | |
| 'sentiment': 1, # Positive | |
| 'source': 'idiom_synthetic', | |
| 'idiom': idiom | |
| }) | |
| # Add variations with different contexts | |
| contexts = [ | |
| f"I think {sentence.lower()}", | |
| f"In my opinion, {sentence.lower()}", | |
| f"I felt that {sentence.lower()}", | |
| f"Many people agree that {sentence.lower()}", | |
| f"It's clear that {sentence.lower()}" | |
| ] | |
| for context in contexts: | |
| if np.random.random() < 0.5: # Only add some variations | |
| idiom_data.append({ | |
| 'text': context, | |
| 'sentiment': 1, # Positive | |
| 'source': 'idiom_synthetic_variation', | |
| 'idiom': idiom | |
| }) | |
| # Add examples for special case "laughed more than I should" | |
| humor_expressions = [ | |
| "I laughed more than I should have at this movie.", | |
| "The comedy made me laugh more than I should admit.", | |
| "I laughed more than I should at those cheesy jokes.", | |
| "The scene was so ridiculous that I laughed more than I should have.", | |
| "It's a guilty pleasure that made me laugh more than I should.", | |
| "The dialogue was so bad that I laughed more than I should.", | |
| "Their attempt at being serious made me laugh more than I should." | |
| ] | |
| for expression in humor_expressions: | |
| idiom_data.append({ | |
| 'text': expression, | |
| 'sentiment': 1, # Positive | |
| 'source': 'humor_expression', | |
| 'idiom': 'laugh_more_than_should' | |
| }) | |
| logger.info(f"Created {len(idiom_data)} idiom examples") | |
| return pd.DataFrame(idiom_data) | |
| except Exception as e: | |
| logger.error(f"Error creating idiom dataset: {e}") | |
| logger.error(traceback.format_exc()) | |
| return pd.DataFrame(columns=['text', 'sentiment', 'source', 'idiom']) | |
| def download_contrast_dataset(): | |
| """ | |
| Create a dataset focusing on contrast markers like "but", "however", "despite". | |
| Returns a pandas DataFrame with text and sentiment columns. | |
| """ | |
| contrast_dir = os.path.join(os.getcwd(), 'datasets', 'contrast') | |
| os.makedirs(contrast_dir, exist_ok=True) | |
| contrast_data = [] | |
| try: | |
| # Create synthetic examples with contrast markers | |
| logger.info("Creating contrast marker dataset...") | |
| # Templates for contrast examples | |
| # Format: (before_text, contrast_marker, after_text, final_sentiment) | |
| contrast_templates = [ | |
| # Positive despite negative | |
| ("The movie had poor special effects", "but", "the story was compelling and emotional", 1), | |
| ("The restaurant was crowded", "but", "the food was absolutely delicious", 1), | |
| ("The service was slow", "but", "the quality was worth the wait", 1), | |
| ("The hotel room was small", "but", "the view was breathtaking", 1), | |
| ("The concert venue was uncomfortable", "but", "the performance was incredible", 1), | |
| # Negative despite positive | |
| ("The visuals were stunning", "but", "the plot made no sense at all", 0), | |
| ("The actors did their best", "but", "the script was terrible", 0), | |
| ("The location was beautiful", "but", "the experience was ruined by poor service", 0), | |
| ("The idea was innovative", "but", "the execution was disappointingly bad", 0), | |
| ("The ingredients were high quality", "but", "the dish was bland and overcooked", 0), | |
| # Despite + negative, positive | |
| ("Despite the rainy weather", "despite", "we had an amazing time at the park", 1), | |
| ("Despite the bad reviews", "despite", "I really enjoyed the play", 1), | |
| ("Despite the high price", "despite", "the product exceeded my expectations", 1), | |
| ("Despite the long line", "despite", "the attraction was worth the wait", 1), | |
| ("Despite the technical difficulties", "despite", "the presentation was informative", 1), | |
| # Despite + positive, negative | |
| ("Despite the beautiful setting", "despite", "the event was boring and poorly organized", 0), | |
| ("Despite the talented cast", "despite", "the movie was a huge disappointment", 0), | |
| ("Despite the excellent location", "despite", "the hotel was dirty and uncomfortable", 0), | |
| ("Despite the promising concept", "despite", "the execution was a complete failure", 0), | |
| ("Despite the friendly staff", "despite", "the service was unacceptably slow", 0), | |
| # However + contrast | |
| ("The graphics were impressive", "however", "the gameplay was repetitive and dull", 0), | |
| ("The first half was entertaining", "however", "it fell apart in the second half", 0), | |
| ("The meal started well", "however", "the main course was undercooked", 0), | |
| ("The characters were likeable", "however", "the plot had too many holes to enjoy", 0), | |
| ("The hotel looked great online", "however", "the reality was completely different", 0), | |
| # Nevertheless + contrast | |
| ("The journey was challenging", "nevertheless", "the destination was worth every hardship", 1), | |
| ("The exam was difficult", "nevertheless", "I managed to pass with a good grade", 1), | |
| ("The recipe was complicated", "nevertheless", "the results were delicious", 1), | |
| ("The training was exhausting", "nevertheless", "I feel much stronger now", 1), | |
| ("The project had many setbacks", "nevertheless", "we delivered it successfully on time", 1), | |
| # Yet + contrast | |
| ("The film received poor reviews", "yet", "I found it thoroughly entertaining", 1), | |
| ("It was a simple design", "yet", "incredibly effective for its purpose", 1), | |
| ("The solution seemed obvious", "yet", "no one had thought of it before", 1), | |
| ("They had limited resources", "yet", "created something remarkable", 1), | |
| ("The book was published decades ago", "yet", "the message is still relevant today", 1), | |
| # Although + contrast | |
| ("Although the course was challenging", "although", "I learned a tremendous amount", 1), | |
| ("Although the hike was strenuous", "although", "the view from the top was magnificent", 1), | |
| ("Although the medicine tasted terrible", "although", "it cured my illness quickly", 1), | |
| ("Although the museum was crowded", "although", "seeing the famous paintings was worth it", 1), | |
| ("Although the instructions were confusing", "although", "I managed to assemble it correctly", 1), | |
| # Even though + contrast | |
| ("Even though the critics loved it", "even though", "I found the movie pretentious and boring", 0), | |
| ("Even though it won awards", "even though", "the novel was tedious to read", 0), | |
| ("Even though it was expensive", "even though", "the quality was disappointingly low", 0), | |
| ("Even though the trailer looked exciting", "even though", "the actual film was dull", 0), | |
| ("Even though we had reservations", "even though", "we still had to wait an hour", 0) | |
| ] | |
| # Generate examples from templates | |
| for before, marker, after, sentiment in contrast_templates: | |
| # Add the basic example | |
| full_text = f"{before} {marker} {after}" | |
| contrast_data.append({ | |
| 'text': full_text, | |
| 'sentiment': sentiment, | |
| 'source': 'contrast_template', | |
| 'contrast_marker': marker | |
| }) | |
| # Add variations with different intensifiers | |
| intensifiers = ["", "very ", "extremely ", "somewhat ", "quite ", "incredibly ", "rather "] | |
| if sentiment == 1: # Positive sentiment | |
| positive_adjectives = ["good", "great", "excellent", "amazing", "wonderful", "fantastic", "enjoyable", "delightful"] | |
| for intensifier in intensifiers: | |
| for adj in positive_adjectives: | |
| if np.random.random() < 0.3: # Only generate some combinations | |
| # Create variation where we strengthen the positive part | |
| if "was" in after: | |
| enhanced_after = after.replace("was", f"was {intensifier}{adj} and") | |
| full_text = f"{before} {marker} {enhanced_after}" | |
| contrast_data.append({ | |
| 'text': full_text, | |
| 'sentiment': sentiment, | |
| 'source': 'contrast_variation', | |
| 'contrast_marker': marker | |
| }) | |
| elif sentiment == 0: # Negative sentiment | |
| negative_adjectives = ["bad", "terrible", "awful", "horrible", "disappointing", "poor", "dreadful", "mediocre"] | |
| for intensifier in intensifiers: | |
| for adj in negative_adjectives: | |
| if np.random.random() < 0.3: # Only generate some combinations | |
| # Create variation where we strengthen the negative part | |
| if "was" in after: | |
| enhanced_after = after.replace("was", f"was {intensifier}{adj} and") | |
| full_text = f"{before} {marker} {enhanced_after}" | |
| contrast_data.append({ | |
| 'text': full_text, | |
| 'sentiment': sentiment, | |
| 'source': 'contrast_variation', | |
| 'contrast_marker': marker | |
| }) | |
| # Add special examples for "The restaurant was crowded, but the food was absolutely delicious" | |
| restaurant_examples = [ | |
| "The restaurant was crowded, but the food was absolutely delicious and worth the wait.", | |
| "Despite the noisy atmosphere, the restaurant served amazing dishes.", | |
| "The service was slow, however the flavors were incredible and memorable.", | |
| "The restaurant was small and cramped, yet the cuisine was exceptional.", | |
| "Although we had to wait for a table, the restaurant's signature dish was spectacular.", | |
| "The restaurant was busy and loud, but their chef's special was mouthwatering.", | |
| "The dining room was packed with people, but each dish was prepared to perfection.", | |
| "Getting a reservation was difficult, however their famous dessert alone justified the effort.", | |
| "The restaurant had a long line, but their award-winning menu lived up to the hype.", | |
| "The place was too crowded for comfort, nevertheless the food quality was outstanding." | |
| ] | |
| for example in restaurant_examples: | |
| contrast_data.append({ | |
| 'text': example, | |
| 'sentiment': 1, # Positive | |
| 'source': 'restaurant_contrast', | |
| 'contrast_marker': 'mixed' | |
| }) | |
| logger.info(f"Created {len(contrast_data)} contrast examples") | |
| return pd.DataFrame(contrast_data) | |
| except Exception as e: | |
| logger.error(f"Error creating contrast dataset: {e}") | |
| logger.error(traceback.format_exc()) | |
| return pd.DataFrame(columns=['text', 'sentiment', 'source', 'contrast_marker']) | |
| def combine_datasets(): | |
| """ | |
| Combine all specialized datasets for training. | |
| """ | |
| try: | |
| # Create a datasets directory | |
| dataset_dir = os.path.join(os.getcwd(), 'datasets') | |
| os.makedirs(dataset_dir, exist_ok=True) | |
| # Get all specialized datasets | |
| logger.info("Downloading and creating specialized datasets...") | |
| sarcasm_df = download_sarcasm_dataset() | |
| idiom_df = download_idiom_dataset() | |
| contrast_df = download_contrast_dataset() | |
| # Combine all datasets | |
| all_data = pd.concat([sarcasm_df, idiom_df, contrast_df], ignore_index=True) | |
| # Save the combined dataset | |
| combined_file = os.path.join(dataset_dir, 'augmented_sentiment_dataset.csv') | |
| all_data.to_csv(combined_file, index=False) | |
| logger.info(f"Combined dataset created with {len(all_data)} examples") | |
| logger.info(f"Saved to {combined_file}") | |
| return combined_file | |
| except Exception as e: | |
| logger.error(f"Error combining datasets: {e}") | |
| logger.error(traceback.format_exc()) | |
| return None | |
| if __name__ == "__main__": | |
| combine_datasets() |