학습·시험

AICE Pro 실전연습 스튜디오

AICE Pro 시험 준비생이 정형·자연어·이미지 실전 문제를 노트북 셀로 풀고 바로 자동 채점·실수 진단을 받는 연습 스튜디오입니다.

분야학습·시험플랫폼Web + 로컬 Python 엔진기술Python 표준 라이브러리 (ThreadingHTTPServer, ast, re) · Vanilla JS · HTML/CSS · Jupyter (.ipynb) · GitHub Pages (docs/)
문제 패널과 노트북 셀: 단계별 코드를 실행하고 제출 파일을 채점합니다.
문제 패널과 노트북 셀: 단계별 코드를 실행하고 제출 파일을 채점합니다.

왜 만들었나

실습 시험을 연습하려면 Jupyter 설치, 데이터 준비, 제출 파일 채점을 직접 해야 해서 정작 공부할 시간이 줄어듭니다. 문제 선택부터 코드 실행, 채점, 실수 피드백까지 한 화면에서 처리합니다.

주요 기능

  • Tabular 2·NLP 2·Image 2 총 6문제, 학습 모드와 타이머가 있는 시험 모드
  • 브라우저 안 멀티셀 노트북 (상태가 이어지는 Python 커널)
  • 제출 CSV 형식 검사와 지표 채점(Macro F1·RMSE·R²)
  • 노트북 코드 정적 분석으로 데이터 누수·to_csv(index=False) 누락 등 진단
  • 공식 라이브러리 API 즉시 검색, 오프라인 ZIP·단일 HTML 배포

숫자로 보면

실전 문제 6개(3개 유형 × 2), 문제마다 풀이 체크리스트 10단계
공식 API 즉시 검색 문서 9개 · 허용 공식 도메인 6개
pytest 테스트 6개

어떻게 동작하나

  1. 로컬 엔진 탐지

    페이지가 열리면 127.0.0.1:8765와 8000의 /api/catalog를 0.9초 제한으로 찔러 보고, 응답이 없으면 정적 번들 모드로 전환합니다.

    docs/app.js
  2. 정적 폴백

    handleStaticFallbackApi()가 catalog_bundle.js의 문제·문서 데이터로 API 응답을 흉내 내고, 셀 실행·채점 요청에는 로컬 엔진 설치 안내를 띄웁니다.

    docs/app.js
  3. 데이터셋 생성

    문제마다 시드 기반 난수로 train/test CSV와 PNG 이미지를 만들고, 정답은 workspace/.ground_truth에 따로 저장합니다.

    aice_pro/dataset_generator.py
  4. 셀 실행

    StatefulNotebookSession이 셀 코드를 ast로 파싱해 실행하고, 마지막 줄이 식이면 eval해 결과를 HTML 표로 돌려주며 네임스페이스를 셀 사이에 유지합니다.

    aice_pro/kernel.py
  5. 코드 진단

    diagnose_notebook_code()가 주석을 뺀 코드에 정규식을 돌려 test/val에 fit 호출, test.dropna(), stratify 누락 같은 실수 패턴을 찾습니다.

    aice_pro/evaluator.py
  6. 제출 채점

    evaluate_submission()이 submission.csv의 형식을 검사한 뒤 숨겨 둔 정답과 비교해 문제별 지표를 계산합니다.

    aice_pro/evaluator.py

핵심 코드

aice_pro/kernel.pyGitHub에서 보기 ↗
with _EXEC_LOCK:
    prev_cwd = Path.cwd()
    try:
        os.chdir(self.problem_dir)
        with contextlib.redirect_stdout(stdout_buf), contextlib.redirect_stderr(stderr_buf):
            tree = ast.parse(raw_code, filename=f"<cell_{cell_index + 1}>", mode="exec")
            if tree.body and isinstance(tree.body[-1], ast.Expr):
                last_expr = ast.Expression(tree.body.pop().value)
                if tree.body:
                    exec(compile(tree, filename=f"<cell_{cell_index + 1}>", mode="exec"), self.namespace)
                val = eval(compile(last_expr, filename=f"<cell_{cell_index + 1}>", mode="eval"), self.namespace)
                fmt = _format_value_for_jupyter(val)
                result_html = fmt["html"]
                result_text = fmt["text"]
            else:
                exec(compile(tree, filename=f"<cell_{cell_index + 1}>", mode="exec"), self.namespace)

셀 코드를 AST로 나눠 앞부분은 exec, 마지막 식은 eval해서 Jupyter처럼 결과 값을 화면에 보여 주는 부분입니다.

어려웠던 점

Jupyter 없이도 셀 사이 상태가 이어지고 마지막 식의 값이 출력되게 하려고, 셀마다 ast.parse로 마지막 Expr 노드를 떼어 eval하고 나머지는 같은 namespace에서 exec합니다. 작업 폴더 변경과 stdout 가로채기는 전역 상태라 잠금(_EXEC_LOCK) 안에서만 처리합니다.