""" Parse raw recipe data (corbt/all-recipes parquet files) and join Directions into the labeled CSV (All_Recipe_Web_Scraping_Dataset_Labeled.csv). Each row in the raw parquet has a single 'input' column with the format: Ingredients: - ingredient 1 - ... Directions: - step 1 - ... Output: All_Recipe_Web_Scraping_Dataset_With_Directions.csv """ import glob import os import re import pandas as pd RAW_DATA_DIR = os.path.join(os.path.dirname(__file__), "raw_data") HF_BLOB_DIR = os.path.expanduser( "~/.cache/huggingface/hub/datasets--corbt--all-recipes/blobs" ) CSV_PATH = os.path.join(os.path.dirname(__file__), "All_Recipe_Web_Scraping_Dataset_Labeled.csv") OUTPUT_PATH = os.path.join(os.path.dirname(__file__), "All_Recipe_Web_Scraping_Dataset_With_Directions.csv") def load_raw_data() -> pd.DataFrame: """Load all parquet shards; fall back to HF cache if symlinks are broken.""" files = sorted(glob.glob(os.path.join(RAW_DATA_DIR, "*.parquet"))) if not files: raise FileNotFoundError(f"No parquet files found in {RAW_DATA_DIR}") try: dfs = [pd.read_parquet(f) for f in files] print(f"Loaded {len(files)} parquet shard(s) from {RAW_DATA_DIR}") except (FileNotFoundError, OSError): # Symlinks point to a relative blob path that doesn't exist locally; # fall back to the HuggingFace cache. print(f"Symlinks broken — falling back to HF cache at {HF_BLOB_DIR}") blobs = [ os.path.join(HF_BLOB_DIR, f) for f in os.listdir(HF_BLOB_DIR) if len(f) == 64 # sha256 hex blobs only (not JSON metadata files) ] if not blobs: raise FileNotFoundError(f"No blob files found in {HF_BLOB_DIR}") dfs = [pd.read_parquet(b) for b in blobs] print(f"Loaded {len(blobs)} blob(s) from HF cache") return pd.concat(dfs, ignore_index=True) def parse_input(text: str) -> pd.Series: """Extract recipe name, ingredients text, and directions from a raw input string.""" name_match = re.match(r"^(.+?)\n", text) name = name_match.group(1).strip() if name_match else "" directions_match = re.search(r"Directions:\n(.*?)$", text, re.DOTALL) directions = directions_match.group(1).strip() if directions_match else "" return pd.Series({"raw_name": name, "directions": directions}) def main(): # --- Load raw data --- raw_df = load_raw_data() print(f"Total raw rows: {len(raw_df):,}") # --- Parse each input string --- print("Parsing input strings...") parsed = raw_df["input"].apply(parse_input) raw_df = pd.concat([raw_df, parsed], axis=1) # Normalize name for joining raw_df["_key"] = raw_df["raw_name"].str.lower().str.strip() # Deduplicate: keep first occurrence per normalized key raw_df = raw_df.drop_duplicates(subset="_key") print(f"Unique recipe names in raw data: {len(raw_df):,}") # --- Load labeled CSV --- csv_df = pd.read_csv(CSV_PATH) print(f"Labeled CSV rows: {len(csv_df):,}") # --- Join on normalized recipe name --- csv_df["_key"] = csv_df["Name"].str.lower().str.strip() merged = csv_df.merge( raw_df[["_key", "directions"]], on="_key", how="left", ).drop(columns="_key") matched = merged["directions"].notna().sum() print(f"Matched {matched:,} / {len(merged):,} rows with directions") # --- Save output --- merged.to_csv(OUTPUT_PATH, index=False) print(f"Saved to {OUTPUT_PATH}") # Quick preview print("\nSample output:") print(merged[["Name", "directions"]].head(3).to_string(max_colwidth=80)) if __name__ == "__main__": main()