Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ wheels/
.venv
.DS_Store
.env*

claude.md
.claude/
314 changes: 314 additions & 0 deletions build_combined.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,314 @@
"""
Merge notebooks 01-05 into one combined notebook.
Output: colab_package/sarcasm_classification.ipynb
"""
import json
from pathlib import Path

ROOT = Path(".")
NB_DIR = ROOT / "notebooks"
OUT_DIR = ROOT / "colab_package"
OUT_DIR.mkdir(exist_ok=True)

# ── Load all notebooks ────────────────────────────────────────────────────────
def load_nb(name):
path = NB_DIR / name
nb = json.loads(path.read_bytes().decode("utf-8"))
cells = []
for c in nb["cells"]:
src = c["source"]
if isinstance(src, list):
src = "".join(src)
cells.append({"type": c["cell_type"], "src": src})
return cells

nb01 = load_nb("01_data_preparation.ipynb")
nb02 = load_nb("02_tfidf_lr_baseline.ipynb")
nb03 = load_nb("03_naive_bayes_baseline.ipynb")
nb04 = load_nb("04_bert_classification.ipynb")
nb05 = load_nb("05_error_analysis.ipynb")


# ── Single combined setup cell ────────────────────────────────────────────────
# Merges all imports + file detection + all output-dir definitions

SETUP_SRC = "\n".join([
"# ============================================================",
"# SETUP — imports, file upload, paths",
"# ============================================================",
"from __future__ import annotations",
"import json, hashlib, random, os, warnings, shutil",
"from dataclasses import dataclass",
"from pathlib import Path",
"from collections import Counter",
"from urllib.parse import urlparse",
"from typing import Optional",
"",
"import numpy as np",
"import pandas as pd",
"import matplotlib.pyplot as plt",
"import matplotlib.gridspec as gridspec",
"import seaborn as sns",
"",
"from sklearn.pipeline import Pipeline",
"from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer",
"from sklearn.linear_model import LogisticRegression",
"from sklearn.naive_bayes import MultinomialNB, ComplementNB",
"from sklearn.model_selection import GridSearchCV, GroupKFold",
"from sklearn.metrics import (",
" accuracy_score, precision_score, recall_score,",
" f1_score, classification_report, confusion_matrix,",
")",
"",
"warnings.filterwarnings('ignore')",
"",
"SEED = 42",
"random.seed(SEED)",
"np.random.seed(SEED)",
"",
"# ── Locate or upload the JSONL data file ─────────────────────────────────",
'FILENAME = "sarcasm_pairs_step35_clean.jsonl"',
"",
"def _locate_file(filename):",
" candidates = []",
" for root in [Path.cwd()] + list(Path.cwd().parents):",
" for sub in [",
' Path("data") / "processed" / filename,',
' Path("data") / filename,',
" Path(filename),",
" ]:",
" candidates.append(root / sub)",
" for p in [",
' Path("/content") / filename,',
' Path("/mnt/data") / filename,',
" ]:",
" candidates.append(p)",
" _c = Path('/content')",
" for p in (_c.rglob(filename) if _c.exists() else []):",
" candidates.append(p)",
" for p in candidates:",
" if p.is_file():",
" return p",
" return None",
"",
"print(f'cwd: {Path.cwd()}')",
"print(f'files in cwd: {[p.name for p in Path.cwd().iterdir()][:10]}')",
"",
"DATA_FILE = _locate_file(FILENAME)",
"if DATA_FILE is None:",
" try:",
" from google.colab import files as _cf",
' print(f"Upload {FILENAME!r}:")',
" _up = _cf.upload()",
" if not _up:",
' raise RuntimeError("No file uploaded.")',
" _name = list(_up.keys())[0]",
' DATA_FILE = Path("/content") / FILENAME',
" if Path(_name) != DATA_FILE:",
" shutil.move(_name, str(DATA_FILE))",
' print(f"Saved to {DATA_FILE}")',
" except ImportError:",
" raise FileNotFoundError(",
' f"Cannot find {FILENAME!r}. Place it in the same folder as this notebook."',
" )",
"",
"# ── Project root + all output directories ────────────────────────────────",
"def _find_root(data_file):",
' for parent in [data_file.parent] + list(data_file.parents):',
' if any((parent / m).exists() for m in ["outputs","notebooks","data"]):',
" return parent",
" return data_file.parent",
"",
"ROOT = _find_root(DATA_FILE)",
"",
"OUT_DATASETS = ROOT / 'outputs' / 'datasets'",
"OUT_SPLITS = ROOT / 'outputs' / 'splits'",
"OUT_TFIDF = ROOT / 'outputs' / 'classical' / 'tfidf_lr'",
"OUT_NB = ROOT / 'outputs' / 'classical' / 'naive_bayes'",
"BERT_OUT = ROOT / 'outputs' / 'bert'",
"REPORTS_DIR = ROOT / 'outputs' / 'reports'",
"SPLITS = OUT_SPLITS",
"",
"for d in [OUT_DATASETS, OUT_SPLITS, OUT_TFIDF, OUT_NB, BERT_OUT, REPORTS_DIR]:",
" d.mkdir(parents=True, exist_ok=True)",
"",
'print(f"Data : {DATA_FILE}")',
'print(f"Root : {ROOT}")',
'print(f"Output : {ROOT / \'outputs\'}")',
]) + "\n"
Comment on lines +35 to +138

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

fd build_combined.py

Repository: SeeYangZhi/Project-LLMao

Length of output: 85


🏁 Script executed:

wc -l build_combined.py

Repository: SeeYangZhi/Project-LLMao

Length of output: 89


🏁 Script executed:

cat -n build_combined.py

Repository: SeeYangZhi/Project-LLMao

Length of output: 13265


🏁 Script executed:

fd "04_bert_classification.ipynb"

Repository: SeeYangZhi/Project-LLMao

Length of output: 106


🏁 Script executed:

cat notebooks/04_bert_classification.ipynb | python3 << 'EOF'
import json
import sys

nb = json.load(sys.stdin)
for i, cell in enumerate(nb["cells"]):
    src = cell["source"]
    if isinstance(src, list):
        src = "".join(src)
    
    # Look for torch, transformers, DEVICE, Dataset, DataLoader
    keywords = ["torch", "transformers", "DEVICE", "Dataset", "DataLoader"]
    has_keyword = any(kw in src for kw in keywords)
    
    if has_keyword or (i < 5):  # Show first 5 cells + any with keywords
        cell_type = cell["cell_type"]
        print(f"\n=== Cell {i} ({cell_type}) ===")
        if cell_type == "code":
            # Show first 50 lines
            lines = src.split("\n")[:50]
            for j, line in enumerate(lines, 1):
                print(f"{j:3d}: {line}")
            if len(src.split("\n")) > 50:
                print("     ...")
        else:
            print(src[:200])
EOF

Repository: SeeYangZhi/Project-LLMao

Length of output: 788


🏁 Script executed:

python3 << 'EOF'
import json
from pathlib import Path

nb_path = Path("notebooks/04_bert_classification.ipynb")
with open(nb_path, 'r') as f:
    nb = json.load(f)

for i, cell in enumerate(nb["cells"]):
    src = cell["source"]
    if isinstance(src, list):
        src = "".join(src)
    
    # Look for torch, transformers, DEVICE, Dataset, DataLoader
    keywords = ["torch", "transformers", "DEVICE", "Dataset", "DataLoader"]
    has_keyword = any(kw in src for kw in keywords)
    
    if has_keyword or (i < 5):  # Show first 5 cells + any with keywords
        cell_type = cell["cell_type"]
        print(f"\n=== Cell {i} ({cell_type}) ===")
        if cell_type == "code":
            # Show first 80 lines
            lines = src.split("\n")[:80]
            for j, line in enumerate(lines, 1):
                print(f"{j:3d}: {line}")
            if len(src.split("\n")) > 80:
                print("     ...")
        else:
            print(src[:300])
EOF

Repository: SeeYangZhi/Project-LLMao

Length of output: 11941


Add missing torch, transformers, and tqdm imports plus DEVICE initialization to SETUP_SRC.

The combined notebook skips notebook 04's setup cell (filtered by is_setup_cell), but SETUP_SRC does not define torch, transformers imports, Dataset, DataLoader, or DEVICE. Part 4 will fail at runtime (e.g., NameError: name 'DEVICE' is not defined, NameError: name 'Dataset' is not defined).

Suggested fix
 SETUP_SRC = "\n".join([
     "import seaborn as sns",
+    "import torch",
+    "from torch import nn",
+    "from torch.utils.data import Dataset, DataLoader",
+    "from transformers import (",
+    "    AutoTokenizer,",
+    "    AutoModelForSequenceClassification,",
+    "    get_linear_schedule_with_warmup,",
+    ")",
+    "from tqdm.auto import tqdm",
     "",
     "warnings.filterwarnings('ignore')",
     "",
     "SEED = 42",
     "random.seed(SEED)",
     "np.random.seed(SEED)",
+    "torch.manual_seed(SEED)",
+    "if torch.cuda.is_available():",
+    "    torch.cuda.manual_seed_all(SEED)",
+    "    torch.backends.cudnn.deterministic = True",
+    "DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')",
+    "print(f'Device: {DEVICE}')",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@build_combined.py` around lines 35 - 138, SETUP_SRC is missing imports and
DEVICE/Dataset/DataLoader definitions needed by notebook part 04; update
SETUP_SRC to import torch, transformers (e.g., from transformers import
AutoTokenizer, AutoModel, etc. as used elsewhere), and tqdm (or tqdm.auto), and
import Dataset and DataLoader from torch.utils.data, then add DEVICE =
torch.device("cuda" if torch.cuda.is_available() else "cpu") (and set
torch.manual_seed(SEED) after SEED) so code referencing DEVICE, Dataset,
DataLoader, torch, or transformers resolves at runtime; modify the block that
defines imports and SEED in SETUP_SRC accordingly, keeping symbol names exactly
as used (SETUP_SRC, SEED, DEVICE, Dataset, DataLoader, torch, transformers,
tqdm).


# Validate setup cell
try:
compile(SETUP_SRC, "<setup>", "exec")
print("Setup cell: OK")
except SyntaxError as e:
lines = SETUP_SRC.split("\n")
print(f"SyntaxError line {e.lineno}: {lines[e.lineno-1]!r} — {e}")
raise


# ── Helper: make a code cell ──────────────────────────────────────────────────
def code_cell(src):
return {
"cell_type": "code",
"execution_count": None,
"metadata": {},
"outputs": [],
"source": src,
}

def md_cell(src):
return {
"cell_type": "markdown",
"metadata": {},
"source": src,
}


# ── Determine which cells are "setup" cells to skip ──────────────────────────
# A setup cell is: first code cell in each notebook that defines ROOT/_find_
def is_setup_cell(src):
triggers = [
"_find_project_root",
"_find_data_file",
"_locate_file",
"Colab / environment setup",
"import json, hashlib, random",
"SEED = 42\nrandom.seed",
]
return any(t in src for t in triggers)


# ── Collect content cells from each notebook (skip setup cells) ───────────────
def content_cells(cells):
"""Return cells that are not setup cells."""
out = []
for c in cells:
if c["type"] == "code" and is_setup_cell(c["src"]):
continue
# Patch nb02's OUT_DIR references to use OUT_TFIDF
src = c["src"].replace(
'ROOT / "outputs" / "classical" / "tfidf_lr"',
"OUT_TFIDF"
).replace(
"OUT_DIR", "OUT_TFIDF"
) if c["type"] == "code" else c["src"]

out.append({"type": c["type"], "src": src})
return out

def content_cells_nb(cells, out_dir_var, out_dir_val):
"""Return cells, replacing OUT_DIR with the right variable."""
result = []
for c in cells:
if c["type"] == "code" and is_setup_cell(c["src"]):
continue
src = c["src"]
if c["type"] == "code":
src = src.replace("OUT_DIR", out_dir_var)
result.append({"type": c["type"], "src": src})
return result


# ── Build combined cell list ──────────────────────────────────────────────────
all_cells = []

# Title
all_cells.append(md_cell(
"# Sarcasm Classification — Complete Pipeline\n\n"
"**Sections**:\n"
"1. Setup & Data Preparation\n"
"2. TF-IDF + Logistic Regression Baseline\n"
"3. Naive Bayes Baseline\n"
"4. BERT / DistilBERT Classification\n"
"5. Error Analysis & Model Comparison\n\n"
"**Run all cells in order (Runtime → Run all).**"
))

# Setup cell
all_cells.append(code_cell(SETUP_SRC))

# ── Section 1: Data Preparation ───────────────────────────────────────────────
all_cells.append(md_cell("---\n# Part 1 — Data Preparation"))
for c in content_cells(nb01):
if c["type"] == "markdown":
all_cells.append(md_cell(c["src"]))
else:
all_cells.append(code_cell(c["src"]))

# ── Section 2: TF-IDF + LR ───────────────────────────────────────────────────
all_cells.append(md_cell("---\n# Part 2 — TF-IDF + Logistic Regression Baseline"))
for c in content_cells_nb(nb02, "OUT_TFIDF", "OUT_TFIDF"):
if c["type"] == "markdown":
all_cells.append(md_cell(c["src"]))
else:
all_cells.append(code_cell(c["src"]))

# ── Section 3: Naive Bayes ────────────────────────────────────────────────────
all_cells.append(md_cell("---\n# Part 3 — Naive Bayes Baseline"))
for c in content_cells_nb(nb03, "OUT_NB", "OUT_NB"):
if c["type"] == "markdown":
all_cells.append(md_cell(c["src"]))
else:
all_cells.append(code_cell(c["src"]))

# ── Section 4: BERT ───────────────────────────────────────────────────────────
all_cells.append(md_cell("---\n# Part 4 — BERT / DistilBERT Classification"))
for c in content_cells_nb(nb04, "BERT_OUT", "BERT_OUT"):
if c["type"] == "markdown":
all_cells.append(md_cell(c["src"]))
else:
all_cells.append(code_cell(c["src"]))

# ── Section 5: Error Analysis ─────────────────────────────────────────────────
all_cells.append(md_cell("---\n# Part 5 — Error Analysis & Model Comparison"))
for c in content_cells_nb(nb05, "REPORTS_DIR", "REPORTS_DIR"):
if c["type"] == "markdown":
all_cells.append(md_cell(c["src"]))
else:
# Also patch CLASSICAL and BERT_OUT references (already correct var names)
all_cells.append(code_cell(c["src"]))

# ── Compile-check all code cells ──────────────────────────────────────────────
errors = []
for i, c in enumerate(all_cells):
if c["cell_type"] == "code":
src = c["source"]
try:
compile(src, f"cell{i}", "exec")
except SyntaxError as e:
errors.append((i, e.lineno, str(e), src.split("\n")[e.lineno-1] if e.lineno else ""))

if errors:
print(f"\n{len(errors)} syntax error(s):")
for i, ln, msg, line in errors:
print(f" Cell {i:3d} line {ln}: {line!r}")
print(f" {msg}")
else:
print(f"All {len(all_cells)} cells: syntax OK")

Comment on lines +282 to +289

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fail the build when syntax errors are detected.

Currently the script prints syntax errors but still writes the combined notebook, which can ship broken artifacts.

Suggested fix
 if errors:
     print(f"\n{len(errors)} syntax error(s):")
     for i, ln, msg, line in errors:
         print(f"  Cell {i:3d} line {ln}: {line!r}")
         print(f"           {msg}")
+    raise RuntimeError("Aborting: combined notebook contains syntax errors.")
 else:
     print(f"All {len(all_cells)} cells: syntax OK")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if errors:
print(f"\n{len(errors)} syntax error(s):")
for i, ln, msg, line in errors:
print(f" Cell {i:3d} line {ln}: {line!r}")
print(f" {msg}")
else:
print(f"All {len(all_cells)} cells: syntax OK")
if errors:
print(f"\n{len(errors)} syntax error(s):")
for i, ln, msg, line in errors:
print(f" Cell {i:3d} line {ln}: {line!r}")
print(f" {msg}")
raise RuntimeError("Aborting: combined notebook contains syntax errors.")
else:
print(f"All {len(all_cells)} cells: syntax OK")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@build_combined.py` around lines 282 - 289, When syntax errors are found (the
errors list is non-empty) stop the build instead of continuing: after printing
the error summary (the block that iterates over errors) call sys.exit(1) or
raise SystemExit so the script exits non‑zero and prevents subsequent writing of
the combined notebook; alternatively move the code that writes the combined
notebook so it only executes in the else branch where you currently print
"syntax OK". Refer to the errors variable and the all_cells check in
build_combined.py and ensure the combined-notebook write logic (the function or
code that serializes/writes the notebook) only runs when no syntax errors are
present.

# ── Write combined notebook ───────────────────────────────────────────────────
combined = {
"nbformat": 4,
"nbformat_minor": 4,
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3",
},
"language_info": {"name": "python", "version": "3.11.0"},
"colab": {"provenance": []},
},
"cells": all_cells,
}

out_nb = OUT_DIR / "sarcasm_classification.ipynb"
out_nb.write_bytes(json.dumps(combined, indent=1).encode("utf-8"))
print(f"\nSaved: {out_nb}")
print(f"Total cells: {len(all_cells)}")
print(f"\ncolab_package/ contents:")
for p in sorted(OUT_DIR.iterdir()):
print(f" {p.name}")
print(f"\nAlso copy into colab_package/:")
print(f" sarcasm_pairs_step35_clean.jsonl (from data/processed/)")
Loading