데이터를 넣으면 어디가 문제인지 진단하고, 생성형 AI 에게 처방을 받아, 실제로 고쳐서 돌려주는 로컬 웹 도구입니다.
데이터 사이언스를 모르는 사람도 쓸 수 있게 만들었습니다. 모든 화면이 한국어이고, 전문 용어가 나올 때마다 바로 풀어서 설명합니다.
입력 데이터 ─→ [ 이미징 → 데이터 진단 ] ─→ [ 개선 처방 → 품질 개선 ] ─→ 개선 데이터
(촬영) (진단서) (AI) (실행) (CSV 내려받기)
다루는 데이터는 네 가지입니다.
| 입력 | 결과물 | |
|---|---|---|
| 수치형 | CSV | 정리된 CSV |
| 글자형(텍스트) | CSV | 정리된 CSV + 뽑아낸 특징 컬럼 |
| 이미지 | 내 컴퓨터의 폴더 | 정리된 이미지 폴더 + 목록 CSV (zip) |
| 영상 | 내 컴퓨터의 폴더 | 뽑아낸 프레임 + 목록 CSV (zip) |
이미지·영상도 파일 하나를 표의 한 줄로 바꿔서 다룹니다. 그래서 진단·처방·개선이 표 데이터와 똑같은 방식으로 흘러갑니다.
pip install -r requirements.txt
python -m app.fetch_samples # 샘플 데이터 내려받기 (한 번만)
python run.py # http://127.0.0.1:8000 이 자동으로 열립니다따로 설정할 것이 없습니다. 팀 공용 키가 .env.shared 로 저장소에 함께 들어 있어서,
clone 하고 바로 실행하면 AI 처방이 동작합니다.
개인 키를 쓰고 싶으면 같은 폴더에 .env 를 만드세요. 그쪽이 항상 우선합니다.
OPEN_AI_API=sk-...
OPENAI_MODEL=gpt-5.4-mini # 선택. 없으면 gpt-5.4-mini 를 씁니다
키를 어디서 가져왔는지는 화면 왼쪽 아래에 표시됩니다. 키가 아예 없어도 도구는 돌아갑니다. 이때는 AI 처방 대신 규칙 기반 처방이 적용됩니다.
저장소를 공개로 바꾸지 마세요.
.env.shared에 실제 키가 들어 있습니다. 공개 저장소에 키가 올라가면 GitHub 이 이를 찾아내 OpenAI 에 알리고, 키가 자동으로 폐기되어 팀 전체가 쓰지 못하게 됩니다. 공개해야 한다면 먼저.env.shared를 지우고.gitignore에 추가한 뒤, 키를 새로 발급받으세요.
| 단계 | 화면에 보이는 것 | 뒤에서 하는 일 |
|---|---|---|
| 0. 목적 적기 | "이 데이터로 무엇을 하려고 하시나요?" | 적어 둔 목적이 AI 처방의 기준이 됩니다 |
| 1. 데이터 넣기 | 샘플 또는 내 CSV·폴더 | CSV 는 인코딩·구분자를 자동으로 맞추고, 폴더는 파일마다 특징을 잽니다 |
| 2. 촬영 & 진단 | 건강 점수, 빈칸 지도, 진단서, 컬럼별 그래프 | imaging.py 가 통계를 뽑고 diagnose.py 의 렌즈 26개가 문제를 찾습니다 |
| 3. AI 처방 | 문제마다 "이렇게 하자 + 왜 + 잃는 것" | 진단서를 OpenAI 에 보내 처방을 받습니다 |
| 4. 고치기 | 전/후 비교, 처리 기록, 남은 문제 | enhance.py 가 처방을 정해진 순서대로 실행합니다 |
| 5. 결과 받기 | CSV + JSON 리포트 내려받기 | 원본은 건드리지 않고 사본을 만듭니다 |
처방은 하나하나 끄고 켤 수 있고, 다른 처리 방법으로 바꿀 수도 있습니다. AI 가 정한 대로 무조건 실행되지 않습니다.
같은 문제라도 무엇을 하려는지에 따라 답이 달라야 합니다. 화면 맨 위에 목적을 적어 두면 AI 가 그 기준으로 판단하고, 무엇을 우선했는지 한 줄로 설명합니다.
| 적어 둔 목적 | 달라지는 점 |
|---|---|
| 모델 학습 | 빈칸을 채우고 잡음을 지우고 특징을 뽑는 쪽으로 적극적으로 |
| 보고서·대시보드 | 표준화·로그변환처럼 숫자를 알아볼 수 없게 만드는 처리는 피함 |
| 외부 공유·납품 | 개인정보 가리기를 최우선. 행 삭제는 보수적으로 |
| 일단 살펴보기 | 원본을 최대한 보존. 기록만 남기기 를 적극적으로 |
통계만 봐서는 01012345678 이 전화번호인지 주문번호인지 알 수 없습니다.
그래서 컬럼 이름을 근거로 삼고, 필요하면 직접 설명을 달 수 있습니다.
- 이름에
주민·전화·이메일·주소·계좌같은 말이 있으면 개인정보로 보고 가릴 것을 권합니다. - 이름이
타깃·label·y면 맞혀야 할 정답으로 보고 값을 바꾸지 않습니다. - 진단 화면의 컬럼 메모에 직접 적은 설명은 통계보다 우선합니다.
(
cd_flg에 "해지 여부, 1=해지" 라고 적어 두는 식)
개인정보로 판정된 컬럼은 가명으로 바꾸기(같은 사람은 같은 코드가 되어 연결은 유지), 뒷자리만 남기기, 값 전체 가리기, 컬럼 삭제 중에서 고를 수 있습니다.
둘 다 공개 데이터를 원본 그대로 씁니다. 일부러 깨끗한 것을 고르지 않았습니다. 실제로 지저분해야 도구가 제대로 동작하는지 확인할 수 있기 때문입니다.
| 자동차 연비 (수치형) | 문자 스팸 (글자형) | |
|---|---|---|
| 출처 | UCI Auto MPG (seaborn 배포판) | UCI SMS Spam Collection (Kaggle 배포판) |
| 크기 | 398행 × 9컬럼 | 5,572행 × 5컬럼 |
| 실제 문제 | 마력 결측 6개, 이상치, 컬럼 간 단위 642배 차이 | 빈 열 3개, 중복 403행, URL·전화번호·HTML 혼입, 라벨 87:13 불균형 |
| 처리 결과 | 81.9점(B) → 91.0점(A) | 21.3점(E) → 94.0점(A) |
이미지와 영상도 공개 데이터를 그대로 씁니다.
| 예제 이미지 22장 | 공개 영상 클립 5편 | |
|---|---|---|
| 출처 | scikit-image 내장 예제 이미지 | Blender 재단 공개 영화 (CC) |
| 실제 문제 | 흑백·컬러 반반, 크기 102~1411px, PNG/JPG 혼재, 같은 고양이 사진 중복 | 360p·720p·1080p 혼재, 24·30·60fps 혼재 |
| 처리 결과 | 중복 제거 → 전부 3채널 컬러 → 긴 변 512px 통일 | 1초 간격 프레임 50장 추출 |
모두 python -m app.fetch_samples 로 내려받거나 다시 만들 수 있습니다.
저장소에는 넣지 않습니다.
python -m app.selftest # 규칙 기반만 (빠르고 무료)
python -m app.selftest --with-ai # 실제 OpenAI 호출 포함샘플 두 개로 전체 흐름을 돌리고 다음을 확인합니다. 하나라도 어긋나면 종료 코드 1 을 냅니다.
- 진단이 문제를 찾아내는가, 컬럼 종류를 제대로 알아보는가
- 문제 1건당 처방 1건이 빠짐없이 붙는가
- AI 가 허용되지 않은 처리를 고르지 않는가
- 빈칸·중복이 늘지 않는가, 건강 점수가 떨어지지 않는가
- 행이 절반 이상 살아남는가, 결과 CSV 를 다시 읽을 수 있는가
- 원본 데이터가 그대로 보존되는가
- 고친 문제가 재진단에서 다시 걸리지 않는가
이 도구는 AI 에게 코드를 짜게 하지 않습니다. AI 는 미리 등록된 처리 동작 34개 중에서 고르기만 합니다.
actions.py에 등록된 동작만 실행됩니다. 목록에 없는 것은 데이터에 손대지 못합니다.- AI 가 고른 동작이 그 문제에 허용된 후보 목록에 없으면 버리고 규칙 기본값을 씁니다. 이런 일이 생기면 화면에 표시됩니다.
- API 호출이 실패하거나 키가 없으면 규칙 기반으로 넘어갑니다. 조용히 멈추지 않습니다.
- 원본
DataFrame은 절대 수정하지 않습니다. 항상 사본에 작업합니다. - 모든 처리는 처리 기록에 남고, 건너뛴 처방까지 기록됩니다.
데이터 파일은 이 컴퓨터를 벗어나지 않습니다. AI 처방을 받을 때 OpenAI 로 보내는 것은
컬럼 이름, 통계 수치, 그리고 문제를 보여주는 예시 값 3개 이하입니다
(prescribe.py 의 _finding_brief, _dataset_brief 참고).
민감한 데이터라면 .env.shared 의 키 줄을 지우고 규칙 기반으로만 쓰시면 됩니다.
.env.shared 의 키는 LabQ 계정으로 과금됩니다. 이 저장소에 접근할 수 있는
사람이라면 누구나 쓸 수 있으므로, 아래를 지켜 주세요.
- 저장소를 조직 밖으로 공개하지 않습니다.
- 키를 저장소 밖(메신저·문서·다른 프로젝트)으로 복사하지 않습니다.
- 대량 처리를 돌리기 전에는 한 번 알려 주세요. 큰 파일을 여러 번 돌리면 호출 비용이 빠르게 늘어납니다.
- 키가 샜다고 판단되면 OpenAI 대시보드에서 폐기하고 새로 발급한 뒤
.env.shared만 고쳐서 커밋하면 팀 전체에 반영됩니다.
preprocessing_tool/
├── run.py 실행기 (uvicorn 서버를 띄우고 브라우저를 엽니다)
├── .env.shared 팀 공용 키 (저장소에 포함. private 저장소 전제)
├── .env 개인 키 (선택. 만들면 공용 키를 덮어씁니다)
├── app/
│ ├── config.py 설정과 키 로딩
│ ├── schema.py Finding / Prescription / ActionLog 자료 구조
│ ├── imaging.py 01. 이미징 - 데이터를 숫자로 촬영
│ ├── diagnose.py 01. 진단 - 렌즈 26개로 문제 판정
│ ├── prescribe.py 02. 처방 - OpenAI 에 물어보기 + 검증 + 대체
│ ├── actions.py 실행 가능한 처리 동작 34개 (여기 없으면 실행 불가)
│ ├── enhance.py 02. 개선 - 처방 실행 + 전후 비교 + 건강 점수
│ ├── pipeline.py 전체 흐름 엮기, 작업 세션 보관
│ ├── main.py FastAPI 서버
│ ├── media.py 이미지/영상 이미징 - 파일을 표 한 줄로
│ ├── media_lenses.py 이미지/영상 전용 진단 렌즈
│ ├── media_actions.py 이미지/영상 파일을 실제로 손보는 동작
│ ├── samples.py 샘플 데이터 정의
│ ├── fetch_samples.py 샘플 내려받기
│ └── selftest.py 검증 스크립트
├── web/ 화면 (라이브러리 없는 순수 HTML/CSS/JS)
│ ├── index.html 왼쪽 사이드바 + 본문 구조
│ ├── styles.css PROP 디자인 토큰 (무채색)
│ ├── charts.js SVG 차트 직접 그리기 (CDN 의존성 없음)
│ ├── app.js 화면 동작
│ └── labq-symbol.svg 랩큐 심볼
├── data/samples/ 샘플 CSV
└── outputs/ 저장한 결과물
인터넷이 끊겨 있어도 화면은 그대로 뜹니다. 외부 CDN 을 쓰지 않습니다.
랩큐 PROP(prop-ai.kr) 의 디자인 언어를 그대로 따릅니다.
| 값 | |
|---|---|
| 색 | 무채색만. #0f0f0f 먹색 / #6c6c6c / #9a9a9a / #e7e7e5 선 / #fafafa 면 |
| 글꼴 | 본문 Inter 14px, 숫자와 코드는 전부 IBM Plex Mono |
| 모서리 | 8~9px, 그림자 없음, 1px 실선 |
| 버튼 | 꽉 찬 먹색 하나(.btn.solid), 나머지는 외곽선 |
| 구조 | 왼쪽 고정 사이드바(235px) + 오른쪽 본문. 사이드바가 진행 단계 표시를 겸합니다 |
PROP 은 마감이 하루 남은 공고(D-1)에도 빨간색을 쓰지 않습니다. 그 절제를 따라
심각도도 색이 아니라 글자와 진하기로 나타냅니다. 색을 넣고 싶으면
styles.css 의 --sev-critical 등 네 줄만 바꾸면 화면 전체에 반영됩니다.
차트도 같은 원칙입니다. 크기는 옅은 회색에서 먹색으로 이어지는 진하기 단계로 나타내므로 색맹 여부와 무관하게 읽히고, 계열이 둘일 때는 범례와 막대 옆 숫자를 반드시 함께 적어 색만으로 구분하게 만들지 않습니다.
정확한 Inter / IBM Plex Mono 를 쓰려면 index.html 의 Google Fonts 한 줄을
주석 해제하세요. 없으면 시스템 글꼴로 대체되고 동작은 같습니다.
diagnose.py 에 함수 하나를 더하면 됩니다.
@lens("my_check", "내가 만든 검사")
def _my_lens(img, col):
if col["role"] != "numeric" or col["unique"] > 3:
return []
return [make(
"my_check", "내가 만든 검사", col["name"],
"warning", # critical / serious / warning / info
"한 줄 요약",
"쉬운 말로 자세한 설명",
"왜 신경 써야 하는지",
{"unique": col["unique"]}, # 근거 수치
["drop_column", "keep"], # 허용할 처리 (actions.py 에 있어야 함)
"keep", # 규칙 기반 기본값
)]새 렌즈는 schema.py 의 LENS_ORDER 에도 넣어 주세요.
넣지 않으면 진단서 맨 뒤로 밀리고, selftest 가 알려 줍니다.
처리 동작을 새로 만들려면 actions.py 에서 @register(...) 를 쓰면 됩니다.
(DataFrame, 컬럼명, 파라미터) 를 받아 (새 DataFrame, 사람이 읽는 메시지, 바뀐 칸 수) 를 돌려주면 됩니다.
enhance.py 의 STAGE 가 실행 순서를 정합니다. 순서가 틀리면 결과가 달라집니다.
1) 컬럼 삭제 버릴 열을 먼저 치운다 (고쳐 놓고 버리면 헛일)
2) 형식 교정 숫자로 바꾸기, 깨진 글자 되살리기 (이후 판단의 기준)
3) 내용 정리 링크·전화번호 가리기, 늘어진 글자 줄이기
4) 행 삭제 다듬은 뒤에 해야 중복이 제대로 잡힌다
5) 빈칸 채우기 행을 정리한 뒤의 중앙값이라야 맞다
6) 값 변형 로그·표준화는 맨 마지막
7) 파생 컬럼 정리가 끝난 데이터에서 특징을 뽑는다
- 세션은 메모리에만 보관합니다. 서버를 다시 켜면 작업 내역이 사라집니다 (최대 12개까지 유지).
- 표 데이터는 CSV 만 읽습니다. 엑셀(.xlsx) 파일은 CSV 로 저장한 뒤 올려 주세요.
- 이미지/영상은 내 컴퓨터의 폴더 경로를 입력받습니다. 파일을 업로드하지 않으므로
수 GB짜리 데이터셋도 복사 없이 바로 진단합니다. 원본 폴더는 절대 건드리지 않고,
outputs/아래 새 폴더에 사본을 만들어 손봅니다. - 한 번에 읽는 미디어 파일은 4,000개까지입니다. 그보다 많으면 앞의 4,000개만 봅니다.
- 영상은 진단과 프레임 추출까지만 합니다. 다시 인코딩하지 않습니다. 해상도·프레임률을 맞추려면 프레임을 뽑은 뒤 이미지 쪽 처리를 쓰시면 됩니다.
- 영상을 읽으려면
imageio-ffmpeg이 필요합니다 (requirements 에 들어 있습니다). 없으면 영상 탭에서 설치 안내를 보여주고, 나머지 기능은 그대로 동작합니다. - 이상치는 IQR 방식만 씁니다. 값의 절반 이상이 같은 컬럼(예: 대부분이 0 인 개수 컬럼)에서는 이 방식이 의미가 없어, 아예 판정하지 않고 넘어갑니다.
- 텍스트 검사는 영어·한국어 기준으로 만들었습니다. 다른 언어에서는 '자주 나오는 단어'의 불용어 제거가 제대로 안 될 수 있습니다.
- 표 전체 표준화는 일부러 하지 않습니다. 단위 차이는 알려만 드립니다. 전처리가 아니라 모델에 넣기 직전에 할 일이고, 지금 하면 내려받은 CSV 를 사람이 읽을 수 없게 됩니다.