From 3b087116c034aea4a22e3cb72653e227d5683ae6 Mon Sep 17 00:00:00 2001 From: shinalok Date: Thu, 23 Apr 2026 18:00:36 +0900 Subject: [PATCH] init project --- .bkit/audit/2026-04-23.jsonl | 18 +++++ .bkit/runtime/agent-state.json | 21 ++++++ .bkit/state/pdca-status.json | 34 +++++++++ .bkit/state/session-history.json | 10 +++ .idea/.gitignore | 10 +++ .idea/misc.xml | 6 ++ .idea/modules.xml | 8 +++ .idea/vcs.xml | 6 ++ CLAUDE.md | 27 ++++++++ chat.py | 77 +++++++++++++++++++++ docs/jetbrains-gateway-setup.md | 114 +++++++++++++++++++++++++++++++ requirements.txt | 1 + youlbot.iml | 9 +++ 13 files changed, 341 insertions(+) create mode 100644 .bkit/audit/2026-04-23.jsonl create mode 100644 .bkit/runtime/agent-state.json create mode 100644 .bkit/state/pdca-status.json create mode 100644 .bkit/state/session-history.json create mode 100644 .idea/.gitignore create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 CLAUDE.md create mode 100644 chat.py create mode 100644 docs/jetbrains-gateway-setup.md create mode 100644 requirements.txt create mode 100644 youlbot.iml diff --git a/.bkit/audit/2026-04-23.jsonl b/.bkit/audit/2026-04-23.jsonl new file mode 100644 index 0000000..37dc2db --- /dev/null +++ b/.bkit/audit/2026-04-23.jsonl @@ -0,0 +1,18 @@ +{"id":"34247001-e643-44e1-b961-a0f035191aeb","timestamp":"2026-04-23T07:10:11.884Z","sessionId":"","actor":"system","actorId":"unified-bash-post","action":"command_executed","category":"control","target":"find C:/workspace_python/youlbot -type f | head -80","targetType":"feature","details":{},"result":"success","reason":null,"destructiveOperation":false,"blastRadius":null,"bkitVersion":"2.1.7"} +{"id":"3fd3ea98-777d-488b-a422-68db5d344cc7","timestamp":"2026-04-23T07:10:35.921Z","sessionId":"","actor":"hook","actorId":"pre-write","action":"file_modified","category":"file","target":"C:\\workspace_python\\youlbot\\CLAUDE.md","targetType":"file","details":{},"result":"success","reason":null,"destructiveOperation":false,"blastRadius":null,"bkitVersion":"2.1.7"} +{"id":"e2da7865-24c1-4b6f-9988-d08ce233fdc6","timestamp":"2026-04-23T07:10:42.076Z","sessionId":"","actor":"system","actorId":"notification-handler","action":"phase_transition","category":"control","target":"permission_prompt","targetType":"feature","details":{"event":"notification","notificationType":"permission_prompt","title":"","message":"Claude needs your permission to use Write"},"result":"success","reason":null,"destructiveOperation":false,"blastRadius":null,"bkitVersion":"2.1.7"} +{"id":"fe81c041-0a2f-48a8-8bfd-e103f6e0c9e7","timestamp":"2026-04-23T07:11:49.340Z","sessionId":"","actor":"system","actorId":"unified-write-post","action":"file_modified","category":"file","target":"C:\\workspace_python\\youlbot\\CLAUDE.md","targetType":"file","details":{},"result":"success","reason":null,"destructiveOperation":false,"blastRadius":null,"bkitVersion":"2.1.7"} +{"id":"491dd54d-1165-4133-ba3d-f32205f54c5e","timestamp":"2026-04-23T07:16:32.546Z","sessionId":"","actor":"system","actorId":"unified-bash-post","action":"command_executed","category":"control","target":"ls -la \"C:/workspace_python/youlbot\" 2>/dev/null | head -20","targetType":"feature","details":{},"result":"success","reason":null,"destructiveOperation":false,"blastRadius":null,"bkitVersion":"2.1.7"} +{"id":"e434a175-dcac-43f2-8bd0-6084a142c4fa","timestamp":"2026-04-23T07:17:00.593Z","sessionId":"","actor":"hook","actorId":"pre-write","action":"file_modified","category":"file","target":"C:\\Users\\SAL\\.claude\\plans\\m4-tingly-pebble.md","targetType":"file","details":{},"result":"success","reason":null,"destructiveOperation":false,"blastRadius":null,"bkitVersion":"2.1.7"} +{"id":"b801c1c6-9ef0-4e59-a238-847b19a07c4b","timestamp":"2026-04-23T07:17:00.703Z","sessionId":"","actor":"system","actorId":"unified-write-post","action":"file_modified","category":"file","target":"C:\\Users\\SAL\\.claude\\plans\\m4-tingly-pebble.md","targetType":"file","details":{},"result":"success","reason":null,"destructiveOperation":false,"blastRadius":null,"bkitVersion":"2.1.7"} +{"id":"38d58fdb-a6fa-47cb-8011-96d3923e3c47","timestamp":"2026-04-23T07:17:25.704Z","sessionId":"","actor":"system","actorId":"notification-handler","action":"phase_transition","category":"control","target":"permission_prompt","targetType":"feature","details":{"event":"notification","notificationType":"permission_prompt","title":"","message":"Claude Code needs your approval for the plan"},"result":"success","reason":null,"destructiveOperation":false,"blastRadius":null,"bkitVersion":"2.1.7"} +{"id":"577d8ae4-a0f7-4793-87d5-1534f983c039","timestamp":"2026-04-23T07:19:51.600Z","sessionId":"","actor":"hook","actorId":"pre-write","action":"file_modified","category":"file","target":"C:\\workspace_python\\youlbot\\requirements.txt","targetType":"file","details":{},"result":"success","reason":null,"destructiveOperation":false,"blastRadius":null,"bkitVersion":"2.1.7"} +{"id":"eeeb27f5-8689-4af0-8c5c-238791453f1e","timestamp":"2026-04-23T07:19:51.718Z","sessionId":"","actor":"system","actorId":"unified-write-post","action":"file_modified","category":"file","target":"C:\\workspace_python\\youlbot\\requirements.txt","targetType":"file","details":{},"result":"success","reason":null,"destructiveOperation":false,"blastRadius":null,"bkitVersion":"2.1.7"} +{"id":"a0474f25-37e6-44ed-88c1-f8a49a7117b8","timestamp":"2026-04-23T07:20:07.341Z","sessionId":"","actor":"hook","actorId":"pre-write","action":"file_modified","category":"file","target":"C:\\workspace_python\\youlbot\\chat.py","targetType":"file","details":{},"result":"success","reason":null,"destructiveOperation":false,"blastRadius":null,"bkitVersion":"2.1.7"} +{"id":"63d6c73f-7473-4e0a-8e78-e5cf9babc050","timestamp":"2026-04-23T07:20:07.466Z","sessionId":"","actor":"system","actorId":"unified-write-post","action":"file_modified","category":"file","target":"C:\\workspace_python\\youlbot\\chat.py","targetType":"file","details":{},"result":"success","reason":null,"destructiveOperation":false,"blastRadius":null,"bkitVersion":"2.1.7"} +{"id":"41ce3a92-cf8d-4516-9bc3-1ea5325ef6e4","timestamp":"2026-04-23T07:21:19.294Z","sessionId":"","actor":"system","actorId":"notification-handler","action":"phase_transition","category":"control","target":"idle_prompt","targetType":"feature","details":{"event":"notification","notificationType":"idle_prompt","title":"","message":"Claude is waiting for your input"},"result":"success","reason":null,"destructiveOperation":false,"blastRadius":null,"bkitVersion":"2.1.7"} +{"id":"4cc20db5-e4f1-43ae-8872-27765ea000b2","timestamp":"2026-04-23T08:48:31.894Z","sessionId":"","actor":"system","actorId":"notification-handler","action":"phase_transition","category":"control","target":"idle_prompt","targetType":"feature","details":{"event":"notification","notificationType":"idle_prompt","title":"","message":"Claude is waiting for your input"},"result":"success","reason":null,"destructiveOperation":false,"blastRadius":null,"bkitVersion":"2.1.7"} +{"id":"d254be8a-117c-459a-8d55-92e8ed6c222d","timestamp":"2026-04-23T08:50:58.123Z","sessionId":"","actor":"hook","actorId":"pre-write","action":"file_modified","category":"file","target":"C:\\workspace_python\\youlbot\\docs\\jetbrains-gateway-setup.md","targetType":"file","details":{},"result":"success","reason":null,"destructiveOperation":false,"blastRadius":null,"bkitVersion":"2.1.7"} +{"id":"63b6c3c8-84a1-4426-887b-19c643278c25","timestamp":"2026-04-23T08:51:01.358Z","sessionId":"","actor":"system","actorId":"unified-write-post","action":"file_modified","category":"file","target":"C:\\workspace_python\\youlbot\\docs\\jetbrains-gateway-setup.md","targetType":"file","details":{},"result":"success","reason":null,"destructiveOperation":false,"blastRadius":null,"bkitVersion":"2.1.7"} +{"id":"7ac0cacc-20cd-4c35-883d-d87474ce6b45","timestamp":"2026-04-23T08:52:03.254Z","sessionId":"","actor":"system","actorId":"notification-handler","action":"phase_transition","category":"control","target":"idle_prompt","targetType":"feature","details":{"event":"notification","notificationType":"idle_prompt","title":"","message":"Claude is waiting for your input"},"result":"success","reason":null,"destructiveOperation":false,"blastRadius":null,"bkitVersion":"2.1.7"} +{"id":"0522fd93-2cea-4989-91ec-5d55140060b2","timestamp":"2026-04-23T08:56:06.983Z","sessionId":"","actor":"hook","actorId":"session-end-handler","action":"phase_transition","category":"control","target":"447cbd58-776c-45d1-bb67-4864a4449066","targetType":"feature","details":{"event":"session_end","reason":"prompt_input_exit"},"result":"success","reason":null,"destructiveOperation":false,"blastRadius":null,"bkitVersion":"2.1.7"} diff --git a/.bkit/runtime/agent-state.json b/.bkit/runtime/agent-state.json new file mode 100644 index 0000000..4b48ae7 --- /dev/null +++ b/.bkit/runtime/agent-state.json @@ -0,0 +1,21 @@ +{ + "version": "1.0", + "enabled": false, + "teamName": "", + "feature": "", + "pdcaPhase": "plan", + "orchestrationPattern": "leader", + "ctoAgent": "opus", + "startedAt": "2026-04-23T07:16:29.093Z", + "lastUpdated": "2026-04-23T07:20:19.184Z", + "teammates": [], + "progress": { + "totalTasks": 0, + "completedTasks": 0, + "inProgressTasks": 0, + "failedTasks": 0, + "pendingTasks": 0 + }, + "recentMessages": [], + "sessionId": "447cbd58-776c-45d1-bb67-4864a4449066" +} \ No newline at end of file diff --git a/.bkit/state/pdca-status.json b/.bkit/state/pdca-status.json new file mode 100644 index 0000000..cca58d8 --- /dev/null +++ b/.bkit/state/pdca-status.json @@ -0,0 +1,34 @@ +{ + "version": "3.0", + "lastUpdated": "2026-04-23T07:09:59.804Z", + "activeFeatures": [], + "primaryFeature": null, + "features": {}, + "pipeline": { + "currentPhase": 1, + "level": "Dynamic", + "phaseHistory": [] + }, + "session": { + "startedAt": "2026-04-23T07:09:59.583Z", + "onboardingCompleted": false, + "lastActivity": "2026-04-23T07:09:59.804Z" + }, + "history": [], + "stateMachine": { + "defaultWorkflow": "default", + "activeWorkflows": {}, + "totalTransitions": 0 + }, + "automation": { + "globalLevel": 2, + "trustScore": 40, + "pendingApprovals": 0, + "lastGateResult": null + }, + "team": { + "enabled": true, + "stateFile": ".bkit/runtime/agent-state.json", + "eventsFile": ".bkit/runtime/agent-events.jsonl" + } +} \ No newline at end of file diff --git a/.bkit/state/session-history.json b/.bkit/state/session-history.json new file mode 100644 index 0000000..6e0991f --- /dev/null +++ b/.bkit/state/session-history.json @@ -0,0 +1,10 @@ +[ + { + "sessionId": "447cbd58-776c-45d1-bb67-4864a4449066", + "reason": "prompt_input_exit", + "endedAt": "2026-04-23T08:56:06.977Z", + "feature": null, + "phase": null, + "progress": null + } +] \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..30cf57e --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..c73a9de --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..faaa059 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..7db0bfd --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,27 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +**youlbot** — Python 프로젝트 (초기 단계). IntelliJ IDEA로 관리되며, `py_ai`라는 이름의 Python 가상 환경을 사용한다. + +## Environment + +- **Python SDK**: `py_ai` (IntelliJ에 등록된 가상 환경) +- **IDE**: IntelliJ IDEA (`.idea/` 구성 포함) +- **PDCA 도구**: bkit (`.bkit/` 디렉터리, Dynamic 레벨) + +## Development Workflow + +이 프로젝트는 bkit PDCA 방법론을 사용한다. 새 기능 작업 전에 Plan/Design 문서를 먼저 확인하고, 구현 후에는 Gap 분석을 수행한다. + +``` +/pdca # PDCA 사이클 관리 (plan → design → do → check → act) +/btw # 작업 중 개선 제안 수집 +``` + +## Notes + +- 소스 코드가 아직 없는 프로젝트 초기 단계이므로, 첫 코드 작성 시 이 파일을 업데이트할 것 +- `py_ai` 가상 환경 경로는 로컬 IntelliJ 설정에 따라 다를 수 있음 diff --git a/chat.py b/chat.py new file mode 100644 index 0000000..0646bfb --- /dev/null +++ b/chat.py @@ -0,0 +1,77 @@ +from mlx_lm import load, stream_generate + +MODEL_ID = "mlx-community/Qwen2.5-7B-Instruct-4bit" +MAX_TOKENS = 1024 +MAX_HISTORY_TURNS = 10 # 최근 10턴만 유지해 메모리 절약 + +SYSTEM_PROMPT = """당신은 친절하고 따뜻한 한국어 상담 도우미입니다. +육아와 금융 두 분야를 전문으로 합니다. + +- 육아: 아이 발달, 이유식, 수면, 훈육, 교육 등 부모가 궁금해하는 모든 것을 도와드립니다. +- 금융: 저축, 투자, 보험, 대출, 세금 등 생활 금융 관련 질문에 답변드립니다. + +항상 쉽고 친근한 말투로 설명하고, 전문 용어는 풀어서 설명합니다. +의학적 진단이나 법적 판단이 필요한 경우에는 반드시 전문가 상담을 권유합니다.""" + + +def format_prompt(tokenizer, history: list[dict]) -> str: + return tokenizer.apply_chat_template( + history, + tokenize=False, + add_generation_prompt=True, + ) + + +def trim_history(history: list[dict], max_turns: int) -> list[dict]: + system_msgs = [m for m in history if m["role"] == "system"] + turn_msgs = [m for m in history if m["role"] != "system"] + if len(turn_msgs) > max_turns * 2: + turn_msgs = turn_msgs[-(max_turns * 2):] + return system_msgs + turn_msgs + + +def main(): + print(f"모델 로딩 중: {MODEL_ID}") + print("(첫 실행 시 HuggingFace에서 자동 다운로드됩니다. 약 4.5GB)\n") + + model, tokenizer = load(MODEL_ID) + + print("=" * 50) + print("육아 & 금융 상담 챗봇 시작!") + print("종료: '종료' / 'quit' / 'exit' 입력") + print("=" * 50 + "\n") + + history = [{"role": "system", "content": SYSTEM_PROMPT}] + + while True: + try: + user_input = input("나: ").strip() + except (EOFError, KeyboardInterrupt): + print("\n대화를 종료합니다.") + break + + if not user_input: + continue + + if user_input.lower() in ("종료", "quit", "exit"): + print("대화를 종료합니다.") + break + + history.append({"role": "user", "content": user_input}) + history = trim_history(history, MAX_HISTORY_TURNS) + + prompt = format_prompt(tokenizer, history) + + print("\n도우미: ", end="", flush=True) + response_text = "" + + for chunk in stream_generate(model, tokenizer, prompt=prompt, max_tokens=MAX_TOKENS): + print(chunk.text, end="", flush=True) + response_text += chunk.text + + print("\n") + history.append({"role": "assistant", "content": response_text}) + + +if __name__ == "__main__": + main() diff --git a/docs/jetbrains-gateway-setup.md b/docs/jetbrains-gateway-setup.md new file mode 100644 index 0000000..eef1289 --- /dev/null +++ b/docs/jetbrains-gateway-setup.md @@ -0,0 +1,114 @@ +# JetBrains Gateway 원격 개발 환경 설정 + +> Windows PC에서 편집 → Mac Mini M4에서 실행하는 환경 구축 가이드 + +``` +Windows PC Mac Mini M4 +┌─────────────────┐ ┌─────────────────────┐ +│ JetBrains │ SSH 연결 │ PyCharm 백엔드 │ +│ Gateway │ ─────────▶│ ~/youlbot/chat.py │ +│ (얇은 클라이언트) │ │ mlx-lm + M4 GPU │ +└─────────────────┘ └─────────────────────┘ + Windows에서 편집 Mac에서 실행 +``` + +--- + +## 1단계: Mac에서 SSH 활성화 + +Mac Mini에서 아래 경로로 이동해 **원격 로그인**을 켭니다. + +``` +시스템 설정 → 일반 → 공유 → 원격 로그인 ON +``` + +활성화 후 화면에 표시되는 `사용자명@IP주소`를 메모해 둡니다. + +--- + +## 2단계: 프로젝트를 Mac으로 전송 (Git) + +### Windows에서 (PowerShell) + +```bash +cd C:/workspace_python/youlbot +git add . +git commit -m "init: chat.py 초기 코드" +git remote add origin https://github.com/본인계정/youlbot.git +git push -u origin master +``` + +### Mac 터미널에서 + +```bash +cd ~ +git clone https://github.com/본인계정/youlbot.git +cd youlbot +python -m venv py_ai +source py_ai/bin/activate +pip install -r requirements.txt +``` + +--- + +## 3단계: JetBrains Gateway 설치 (Windows) + +아래 공식 사이트에서 다운로드 후 설치합니다. + +``` +https://www.jetbrains.com/remote-development/gateway/ +``` + +--- + +## 4단계: Gateway에서 Mac 연결 + +1. Gateway 실행 +2. **New Connection** → **SSH** 선택 +3. 아래 정보 입력 + +| 항목 | 값 | +|------|-----| +| Host | Mac의 IP 주소 | +| Username | Mac 사용자명 | +| Authentication | Password 또는 SSH Key | + +4. **Check Connection** 클릭해 연결 확인 +5. IDE 선택: **PyCharm** → 버전 선택 → **Download and Start IDE** + - Mac에 PyCharm 백엔드가 자동 설치됩니다 (최초 1회, 수분 소요) +6. 프로젝트 경로 입력: `~/youlbot` → 열기 + +--- + +## 5단계: Python 인터프리터 설정 + +PyCharm이 열리면 아래 경로에서 인터프리터를 연결합니다. + +``` +Settings → Project → Python Interpreter +→ Add Interpreter → Add Local Interpreter +→ ~/youlbot/py_ai 가상환경 선택 +``` + +--- + +## 6단계: 실행 확인 + +PyCharm 터미널에서 아래 명령어로 챗봇을 실행합니다. + +```bash +source py_ai/bin/activate +python chat.py +``` + +첫 실행 시 HuggingFace에서 모델(약 4.5GB)이 자동 다운로드됩니다. + +--- + +## 이후 개발 흐름 + +``` +1. Windows Gateway에서 코드 수정 +2. Mac PyCharm 터미널에서 python chat.py 실행 +3. 변경사항은 git push/pull로 동기화 +``` diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f8a69ec --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +mlx-lm>=0.19.0 diff --git a/youlbot.iml b/youlbot.iml new file mode 100644 index 0000000..18284f4 --- /dev/null +++ b/youlbot.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file