Team Ai
Apppublic

Decoder2704/python-chatbot-jay

sourceHugging Faceupdated 7mo agoView on Hugging Face
0likes
build_final_dataset.py201 linesDownload Raw Back to scripts
1#!/usr/bin/env python32"""3Build final_chatbot_data.csv from Questions.csv and AnswersV2.csv.4 5Parity with Chatbot-V5.ipynb: same reads, renames, filter, merge, drops, renames,6and BeautifulSoup HTML stripping (no TF-IDF / UI).7 8Default inputs: Questions.csv from repo pybot_data/, AnswersV2.csv from backend/data/.9Default output: backend/data/final_chatbot_data.csv10 11Paths resolve from this script file location (not the process working directory).12"""13 14from __future__ import annotations15 16import argparse17import logging18import sys19from pathlib import Path20 21import pandas as pd22from bs4 import BeautifulSoup23 24_BACKEND_DIR = Path(__file__).resolve().parent.parent25if str(_BACKEND_DIR) not in sys.path:26    sys.path.insert(0, str(_BACKEND_DIR))27 28from app.paths import DATA_DIR, PYBOT_DATA_DIR, ensure_data_and_artifacts_dirs29 30DEFAULT_QUESTIONS_PATH = PYBOT_DATA_DIR / "Questions.csv"31DEFAULT_ANSWERS_V2_PATH = DATA_DIR / "AnswersV2.csv"32DEFAULT_OUTPUT_PATH = DATA_DIR / "final_chatbot_data.csv"33 34CSV_ENCODING = "latin-1"35 36DROP_AFTER_MERGE = [37    "OwnerUserId_x",38    "CreationDate_x",39    "Score_x",40    "OwnerUserId_y",41    "CreationDate_y",42]43 44logging.basicConfig(45    level=logging.INFO,46    format="%(levelname)s: %(message)s",47)48logger = logging.getLogger(__name__)49 50 51def read_questions(path: Path) -> pd.DataFrame:52    logger.info("Loading Questions from %s", path)53    df = pd.read_csv(path, encoding=CSV_ENCODING)54    logger.info("Questions: %s rows, %s columns", f"{len(df):,}", len(df.columns))55    return df56 57 58def read_answers_v2(path: Path) -> pd.DataFrame:59    logger.info("Loading AnswersV2 from %s", path)60    df = pd.read_csv(path, encoding=CSV_ENCODING)61    logger.info("AnswersV2: %s rows, %s columns", f"{len(df):,}", len(df.columns))62    return df63 64 65def rename_answer_keys(an: pd.DataFrame) -> pd.DataFrame:66    """Notebook cell 4: ParentId -> QId."""67    out = an.rename(columns={"ParentId": "QId"})68    return out69 70 71def rename_ids(q: pd.DataFrame, an: pd.DataFrame) -> tuple[pd.DataFrame, pd.DataFrame]:72    """Notebook cell 5: Questions Id -> QId; Answers Id -> AId."""73    q = q.rename(columns={"Id": "QId"})74    an = an.rename(columns={"Id": "AId"})75    return q, an76 77 78def filter_answers_score_gt_five(an: pd.DataFrame) -> pd.DataFrame:79    """Notebook cell 6: an = an[an['Score']>5]."""80    before = len(an)81    out = an[an["Score"] > 5]82    logger.info("Filtered answers with Score > 5: %s -> %s rows", f"{before:,}", f"{len(out):,}")83    return out84 85 86def merge_on_qid(q: pd.DataFrame, an: pd.DataFrame) -> pd.DataFrame:87    """Notebook cell 8: df = q.merge(an, on='QId')."""88    df = q.merge(an, on="QId")89    logger.info("Merged on QId: %s rows", f"{len(df):,}")90    return df91 92 93def drop_columns(df: pd.DataFrame) -> pd.DataFrame:94    """Notebook cell 9."""95    missing = [c for c in DROP_AFTER_MERGE if c not in df.columns]96    if missing:97        raise ValueError(f"Expected merge columns missing before drop: {missing}")98    return df.drop(columns=DROP_AFTER_MERGE)99 100 101def rename_body_columns(df: pd.DataFrame) -> pd.DataFrame:102    """Notebook cell 10."""103    return df.rename(104        columns={"Body_x": "Question", "Body_y": "Answer", "Score_y": "Score"}105    )106 107 108def strip_html_question_answer(df: pd.DataFrame) -> pd.DataFrame:109    """Notebook cell 12 (same order: Answer, then Question)."""110    out = df.copy()111    out["Answer"] = out["Answer"].apply(lambda x: BeautifulSoup(x).get_text())112    out["Question"] = out["Question"].apply(lambda x: BeautifulSoup(x).get_text())113    return out114 115 116def save_final(df: pd.DataFrame, path: Path) -> None:117    path.parent.mkdir(parents=True, exist_ok=True)118    df.to_csv(path, index=False)119    logger.info("Wrote %s rows to %s", f"{len(df):,}", path)120 121 122def build_final_dataset(q: pd.DataFrame, an: pd.DataFrame) -> pd.DataFrame:123    """Full notebook data pipeline (cells 4–12)."""124    an = rename_answer_keys(an)125    q, an = rename_ids(q, an)126    an = filter_answers_score_gt_five(an)127    df = merge_on_qid(q, an)128    df = drop_columns(df)129    df = rename_body_columns(df)130    df = strip_html_question_answer(df)131    return df132 133 134def parse_args() -> argparse.Namespace:135    p = argparse.ArgumentParser(136        description="Build final_chatbot_data.csv (Chatbot-V5.ipynb data flow).",137    )138    p.add_argument(139        "--questions",140        type=Path,141        default=DEFAULT_QUESTIONS_PATH,142        help=f"Path to Questions.csv (default: {DEFAULT_QUESTIONS_PATH})",143    )144    p.add_argument(145        "--answers-v2",146        type=Path,147        default=DEFAULT_ANSWERS_V2_PATH,148        help=f"Path to AnswersV2.csv (default: {DEFAULT_ANSWERS_V2_PATH})",149    )150    p.add_argument(151        "--output",152        type=Path,153        default=DEFAULT_OUTPUT_PATH,154        help=f"Output CSV path (default: {DEFAULT_OUTPUT_PATH})",155    )156    return p.parse_args()157 158 159def main() -> int:160    ensure_data_and_artifacts_dirs()161    args = parse_args()162    questions_path = args.questions.resolve()163    answers_path = args.answers_v2.resolve()164    output_path = args.output.resolve()165 166    if not questions_path.is_file():167        print(f"ERROR: Questions.csv not found: {questions_path}", file=sys.stderr)168        return 1169    if not answers_path.is_file():170        print(f"ERROR: AnswersV2.csv not found: {answers_path}", file=sys.stderr)171        return 1172 173    try:174        q = read_questions(questions_path)175        an = read_answers_v2(answers_path)176        df = build_final_dataset(q, an)177        save_final(df, output_path)178    except UnicodeDecodeError as exc:179        print(f"ERROR: CSV decode failed (expected {CSV_ENCODING!r}): {exc}", file=sys.stderr)180        return 1181    except OSError as exc:182        print(f"ERROR: file read/write failed: {exc}", file=sys.stderr)183        return 1184    except ValueError as exc:185        print(f"ERROR: {exc}", file=sys.stderr)186        return 1187    except Exception as exc:188        logger.exception("Build failed: %s", exc)189        return 1190 191    print(f"input (Questions):  {questions_path}")192    print(f"input (AnswersV2):  {answers_path}")193    print(f"output:              {output_path}")194    print(f"rows:                {len(df):,}")195    print(f"columns:             {list(df.columns)}")196    return 0197 198 199if __name__ == "__main__":200    raise SystemExit(main())201