{"id":48549542,"url":"https://github.com/machbase/neo-pkg-bbox","last_synced_at":"2026-05-14T01:04:26.192Z","repository":{"id":340475069,"uuid":"1139652179","full_name":"machbase/neo-pkg-bbox","owner":"machbase","description":null,"archived":false,"fork":false,"pushed_at":"2026-04-16T08:39:36.000Z","size":336696,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-16T09:12:51.775Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/machbase.png","metadata":{"files":{"readme":"README-project.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-22T08:34:48.000Z","updated_at":"2026-04-10T08:16:19.000Z","dependencies_parsed_at":null,"dependency_job_id":"74c91fa7-d4f5-4d5f-9c14-cdefb128285e","html_url":"https://github.com/machbase/neo-pkg-bbox","commit_stats":null,"previous_names":["machbase/neo-blackbox","machbase/neo-pkg-blackbox","machbase/neo-pkg-bbox"],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/machbase/neo-pkg-bbox","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/machbase%2Fneo-pkg-bbox","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/machbase%2Fneo-pkg-bbox/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/machbase%2Fneo-pkg-bbox/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/machbase%2Fneo-pkg-bbox/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/machbase","download_url":"https://codeload.github.com/machbase/neo-pkg-bbox/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/machbase%2Fneo-pkg-bbox/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32162614,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-22T17:06:48.269Z","status":"online","status_checked_at":"2026-04-23T02:00:06.710Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-08T08:00:34.007Z","updated_at":"2026-04-23T02:05:12.057Z","avatar_url":"https://github.com/machbase.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# neo-blackbox\n\nCCTV 영상 녹화, AI 객체 감지, 이벤트 규칙 평가를 하나로 묶은 백엔드 서버입니다.\nMachbase(시계열 DB)에 영상 청크와 감지 데이터를 저장하고, REST API로 조회할 수 있습니다.\n\n## 주요 기능\n\n- **카메라 관리** - RTSP/WebRTC 카메라 등록, 활성화/비활성화, 상태 조회\n- **영상 녹화** - FFmpeg를 이용한 RTSP 스트림 녹화 및 청크 단위 DB 저장\n- **미디어 서버** - MediaMTX를 통한 RTSP 스트림 관리\n- **AI 감지** - blackbox-ai-manager와 연동하여 객체 감지 결과 수집\n- **이벤트 규칙** - DSL 기반 규칙 평가 (예: `person \u003e 5 AND car \u003e= 2`)\n- **센서 데이터** - 센서 데이터 저장 및 조회\n- **웹 UI** - API 테스트용 웹 페이지 내장\n\n## 프로젝트 구조\n\n```\nneo-blackbox/\n├── cmd/\n│   └── neo-blackbox/\n│       └── main.go              # 진입점\n├── magefile.go                  # 빌드/배포 스크립트 (mage 타겟 정의)\n├── mage.go                      # mage 부트스트랩 (go run mage.go 진입점)\n├── web/\n│   └── index.html               # API 테스트 웹 UI\n├── tools/                       # 외부 바이너리 (플랫폼별 서브디렉토리)\n│   ├── linux-amd64/             #   ffmpeg, ffprobe, mediamtx, mediamtx.yml\n│   ├── linux-arm64/             #   blackbox-ai-manager, blackbox-ai-core\n│   ├── darwin-amd64/            #   libonnxruntime.so, config.json 등\n│   ├── darwin-arm64/\n│   └── windows-amd64/\n└── internal/\n    ├── ai/                      # AI manager 프로세스 관리\n    ├── config/                  # 설정 로드 (config.yaml 포함)\n    ├── db/                      # Machbase DB 연동\n    ├── dsl/                     # 이벤트 규칙 DSL 파서\n    ├── ffmpeg/                  # FFmpeg 프로세스 관리\n    ├── logger/                  # 로그 설정\n    ├── mediamtx/                # MediaMTX 프로세스/클라이언트 관리\n    ├── server/                  # HTTP API 핸들러\n    └── watcher/                 # 파일 감시 및 DB 저장\n```\n\n## 시작하기\n\n### 필요 사항\n\n- Go 1.25+\n- [Machbase](https://machbase.com) (시계열 DB)\n- [Mage](https://magefile.org) (빌드 도구, 별도 설치 불필요)\n\n### 설정\n\n`internal/config/config.yaml`을 환경에 맞게 수정합니다.\n\n```yaml\nserver:\n  addr: 0.0.0.0:8000\n  camera_dir: \"../bin/cameras\"   # 카메라 설정 파일 저장 경로\n  mvs_dir: \"../ai/mvs\"           # MVS 파일 저장 경로\n  data_dir: \"../bin/data\"        # 영상 데이터 저장 경로\n\nmachbase:\n  scheme: \"http\"\n  host: 127.0.0.1\n  port: 5654\n  timeout_seconds: 30\n  api_token: \"\"                  # Machbase API 토큰 (필요 시)\n\nmediamtx:\n  binary: \"../tools/mediamtx\"          # 비어있으면 외부 서버 사용\n  config_file: \"../tools/mediamtx.yml\" # 비어있으면 바이너리 옆에서 자동 탐색\n  host: 127.0.0.1\n  port: 9997                           # MediaMTX HTTP API 포트\n\nffmpeg:\n  binary: \"../tools/ffmpeg\"\n  defaults:\n    probe_binary: \"../tools/ffprobe\"\n    probe_args:\n      - flag: v\n        value: \"error\"\n      - flag: select_streams\n        value: \"v:0\"\n      - flag: show_entries\n        value: \"packet=pts_time,duration_time\"\n      - flag: of\n        value: \"csv=p=0\"\n\nai:\n  binary: \"../ai/blackbox-ai-manager\"  # 비어있으면 AI 비활성화\n  config_file: \"../ai/config.json\"\n\nlog:\n  dir: \"../logs\"                 # 앱 로그 + ffmpeg 로그 디렉토리\n  level: \"info\"                  # debug, info, warn, error\n  format: \"json\"                 # json, text\n  output: \"both\"                 # stdout, file, both\n  file:\n    filename: \"blackbox.log\"\n    max_size: 100                # MB\n    max_backups: 10\n    max_age: 30                  # days\n    compress: true\n```\n\n\u003e **경로 참고**: 모든 상대경로는 **config 파일이 위치한 디렉토리(`config/`) 기준**입니다.\n\u003e 예: `../bin/cameras` → `bin/cameras/`, `../ai/mvs` → `ai/mvs/`, `../tools/mediamtx` → `tools/mediamtx`\n\u003e 개발 시에는 `internal/config/config.yaml`을 직접 수정하거나, 절대경로로 설정하세요.\n\n### 빌드 및 실행\n\n```bash\n# 빌드 (tmp/neo-blackbox 생성)\ngo run mage.go build\n\n# 실행 (internal/config/config.yaml 사용)\ngo run mage.go run\n\n# 개발 모드 (go run)\ngo run mage.go dev\n\n# 커스텀 config로 실행\ngo run mage.go runWithConfig path/to/config.yaml\ngo run mage.go devWithConfig path/to/config.yaml\n\n# 테스트\ngo run mage.go test\n\n# 코드 품질 검사 (fmt + vet + test)\ngo run mage.go check\n\n# 사용 가능한 타겟 목록\ngo run mage.go -l\n```\n\n### 배포\n\n패키징 시 타겟 플랫폼을 `os-arch` 형식으로 지정합니다.\n\n```bash\n# 패키징 (dist/ 폴더에 아카이브 생성)\ngo run mage.go package linux-amd64\ngo run mage.go package linux-arm64\ngo run mage.go package windows-amd64   # .zip 생성\n\n# 기본 서버에 배포 (패키징 + scp)\ngo run mage.go dp linux-amd64\n\n# G4U 서버에 배포\ngo run mage.go dpG4u linux-amd64\n```\n\n배포 서버 정보는 `.env` 파일로 설정합니다:\n\n```env\nDEPLOY_USER=eleven\nDEPLOY_HOST=192.168.0.87\nDEPLOY_PATH=/blackbox/be/pkg\n```\n\n## 패키지 구조\n\n`go run mage.go package` 실행 후 생성되는 구조:\n\n```\nneo-blackbox-linux-amd64/\n├── bin/\n│   ├── neo-blackbox             # 백엔드 바이너리\n│   └── web/\n│       └── index.html           # 웹 UI (바이너리 실행 위치 기준 탐색)\n├── config/\n│   └── config.yaml              # 설정 파일 (환경에 맞게 수정 필요)\n├── tools/                       # 미디어 도구\n│   ├── ffmpeg\n│   ├── ffprobe\n│   ├── mediamtx\n│   └── mediamtx.yml\n├── ai/                          # AI 엔진\n│   ├── blackbox-ai-manager\n│   ├── blackbox-ai-core\n│   ├── config.json\n│   ├── libonnxruntime.so        # ONNX Runtime 공유 라이브러리\n│   ├── models/\n│   │   └── *.onnx               # AI 모델 파일\n│   └── mvs/                     # MVS 작업 디렉토리 (런타임 생성)\n├── logs/                        # 로그 파일 디렉토리 (런타임 생성)\n└── README.txt\n```\n\n압축 해제 후 실행:\n\n```bash\ntar -xzf neo-blackbox-linux-amd64.tar.gz\ncd neo-blackbox-linux-amd64\n\n# config/config.yaml 수정 후 실행\n./bin/neo-blackbox -config config/config.yaml\n\n# 웹 UI 포함 실행\n./bin/neo-blackbox -config config/config.yaml -web\n\n# 환경변수로 오버라이드 (config.yaml 값 무시)\nBB_ADDR=0.0.0.0:9000 ./bin/neo-blackbox -config config/config.yaml\nBB_MACHBASE_HOST=10.0.0.5 BB_MACHBASE_PORT=5655 ./bin/neo-blackbox -config config/config.yaml\n```\n\n\u003e **주의**: `config.yaml`의 상대경로는 **config 파일 위치(`config/`) 기준**입니다.\n\u003e 패키지 루트(`neo-blackbox-linux-amd64/`)에서 실행하면 경로가 올바르게 해석됩니다.\n\n## DB 테이블 구조\n\n카메라 생성 시 3개의 TAG 테이블이 자동 생성됩니다. 여러 카메라가 같은 테이블을 공유할 수 있습니다.\n\n### `{table}` — 영상 청크 테이블\n\n```sql\nCREATE TAG TABLE IF NOT EXISTS {table} (\n    name VARCHAR(128) PRIMARY KEY,\n    time DATETIME BASETIME,\n    value DOUBLE SUMMARIZED,\n    chunk_path VARCHAR(128)\n) WITH ROLLUP TAG_PARTITION_COUNT=1, TAG_DATA_PART_SIZE=4194304\n```\n\n| 컬럼 | 설명 |\n|------|------|\n| `name` | 카메라 ID (태그 키) |\n| `time` | 청크 시작 시각 |\n| `value` | 청크 길이 (초) |\n| `chunk_path` | 청크 파일 경로 |\n\n### `{table}_event` — 이벤트 룰 평가 결과 테이블\n\n```sql\nCREATE TAG TABLE IF NOT EXISTS {table}_event (\n    name VARCHAR(128) PRIMARY KEY,\n    time DATETIME BASETIME,\n    value DOUBLE,\n    expression_text VARCHAR(200),\n    used_counts_snapshot JSON\n) METADATA (\n    camera_id VARCHAR(64),\n    rule_id VARCHAR(64),\n    rule_name VARCHAR(128)\n) TAG_PARTITION_COUNT=1, TAG_DATA_PART_SIZE=4194304\n```\n\n| 컬럼 | 설명 |\n|------|------|\n| `name` | 이벤트 이름 (태그 키) |\n| `time` | 이벤트 발생 시각 |\n| `value` | 이벤트 값 (1=TRIGGER, 0=RESOLVE 등) |\n| `expression_text` | 평가된 DSL 표현식 |\n| `used_counts_snapshot` | 평가 시점의 객체 카운트 JSON |\n| `camera_id` | 카메라 ID (메타데이터) |\n| `rule_id` | 룰 ID (메타데이터) |\n| `rule_name` | 룰 이름 (메타데이터) |\n\n### `{table}_log` — AI 감지 로그 테이블\n\n```sql\nCREATE TAG TABLE IF NOT EXISTS {table}_log (\n    name VARCHAR(128) PRIMARY KEY,\n    time DATETIME BASETIME,\n    value DOUBLE,\n    model_id INTEGER\n) METADATA (\n    camera_id VARCHAR(64),\n    ident VARCHAR(64)\n) TAG_PARTITION_COUNT=1, TAG_DATA_PART_SIZE=4194304\n```\n\n| 컬럼 | 설명 |\n|------|------|\n| `name` | `{cameraID}.{ident}` 형식 (예: `camera1.person`) |\n| `time` | 감지 시각 |\n| `value` | 감지 수량 |\n| `model_id` | 사용된 AI 모델 ID |\n| `camera_id` | 카메라 ID (메타데이터) |\n| `ident` | 감지 객체 종류 (메타데이터) |\n\n---\n\n## REST API\n\n모든 응답은 아래 공통 포맷을 사용합니다:\n\n```json\n{\n  \"success\": true,\n  \"reason\": \"\",\n  \"elapse\": \"1.23ms\",\n  \"data\": { ... }\n}\n```\n\n---\n\n### 공통\n\n| Method | Path | 설명 |\n|--------|------|------|\n| GET | `/api/ping` | 헬스체크 |\n| GET | `/api/config` | 앱 설정 조회 |\n| POST | `/api/config` | 앱 설정 수정 (server.addr, ai 항목은 읽기 전용) |\n\n---\n\n### 카메라 관리\n\n| Method | Path | 설명 |\n|--------|------|------|\n| GET | `/api/cameras` | 카메라 목록 조회 |\n| POST | `/api/camera` | 카메라 생성 |\n| GET | `/api/camera/:id` | 카메라 상세 조회 |\n| POST | `/api/camera/:id` | 카메라 수정 |\n| DELETE | `/api/camera/:id` | 카메라 삭제 |\n| POST | `/api/camera/:id/enable` | 카메라 활성화 (ffmpeg 시작) |\n| POST | `/api/camera/:id/disable` | 카메라 비활성화 (ffmpeg 중지) |\n| GET | `/api/camera/:id/status` | 카메라 상태 조회 |\n| GET | `/api/cameras/health` | 전체 카메라 상태 조회 |\n| POST | `/api/camera/:id/test` | RTSP 접속 테스트 |\n\n**POST /api/camera 요청:**\n```json\n{\n  \"table\": \"cam01\",\n  \"name\": \"cam01\",\n  \"desc\": \"주차장 카메라\",\n  \"rtsp_url\": \"rtsp://user:pass@192.168.1.100/stream1\",\n  \"rtsp_path\": \"\",           // 비어있으면 cam-{16자리 hex} 자동 생성\n  \"model_id\": 0,\n  \"detect_objects\": [\"person\", \"car\"],\n  \"save_objects\": false,\n  \"ffmpeg_options\": [],\n  \"server_url\": \"\"           // WebRTC 외부 IP (WSL 등 환경)\n}\n```\n\n**POST /api/camera 응답 data:**\n```json\n{ \"camera_id\": \"cam01\" }\n```\n\n---\n\n### 영상 조회\n\n| Method | Path | 설명 |\n|--------|------|------|\n| GET | `/api/get_time_range` | 카메라의 녹화 시간 범위 조회 |\n| GET | `/api/get_chunk_info` | 특정 시각의 청크 정보 조회 |\n| GET | `/api/v_get_chunk` | 청크 바이너리 데이터 반환 (`application/octet-stream`) |\n| GET | `/api/get_camera_rollup_info` | 분 단위 롤업 데이터 조회 |\n| GET | `/api/data_gaps` | 녹화 누락 구간 조회 |\n\n**GET /api/get_time_range 파라미터:**\n```\n?tagname={camera_id}\n```\n**응답 data:**\n```json\n{\n  \"camera\": \"cam01\",\n  \"start\": \"2024-01-01T00:00:00Z\",\n  \"end\": \"2024-01-01T01:00:00Z\",\n  \"chunk_duration_seconds\": 5.0,\n  \"fps\": 30\n}\n```\n\n**GET /api/get_chunk_info 파라미터:**\n```\n?tagname={camera_id}\u0026time={RFC3339 또는 nanoseconds}\n```\n**응답 data:**\n```json\n{\n  \"camera\": \"cam01\",\n  \"time\": \"2024-01-01T00:00:05Z\",\n  \"length\": 5.123\n}\n```\n\n**GET /api/v_get_chunk 파라미터:**\n```\n?tagname={camera_id}\u0026time={RFC3339 또는 nanoseconds 또는 \"0\"(초기화 세그먼트)}\n```\n\n**GET /api/get_camera_rollup_info 파라미터:**\n```\n?tagname={camera_id}\u0026minutes={분}\u0026start_time={ns}\u0026end_time={ns}\n```\n**응답 data:**\n```json\n{\n  \"camera\": \"cam01\",\n  \"minutes\": 1,\n  \"start_time_ns\": 1700000000000000000,\n  \"end_time_ns\":   1700003600000000000,\n  \"start\": \"2024-01-01T00:00:00Z\",\n  \"end\":   \"2024-01-01T01:00:00Z\",\n  \"rows\": [\n    { \"time\": \"2024-01-01T00:00:00Z\", \"sum_length\": 60.0 }\n  ]\n}\n```\n\n**GET /api/data_gaps 파라미터:**\n```\n?camera_id={id}\u0026start_time={RFC3339}\u0026end_time={RFC3339}\u0026interval={초, 기본 5}\n```\n**응답 data:**\n```json\n{\n  \"camera_id\": \"cam01\",\n  \"start_time\": \"2024-01-01T00:00:00Z\",\n  \"end_time\": \"2024-01-01T01:00:00Z\",\n  \"interval\": 5,\n  \"total_gaps\": 3,\n  \"missing_times\": [\"2024-01-01T00:05:00Z\", ...]\n}\n```\n\n---\n\n### 이벤트 룰\n\n| Method | Path | 설명 |\n|--------|------|------|\n| GET | `/api/event_rule/:camera_id` | 카메라의 이벤트 룰 목록 조회 |\n| POST | `/api/event_rule` | 이벤트 룰 추가 |\n| POST | `/api/event_rule/:camera_id/:rule_id` | 이벤트 룰 수정 |\n| DELETE | `/api/event_rule/:camera_id/:rule_id` | 이벤트 룰 삭제 |\n\n**POST /api/event_rule 요청:**\n```json\n{\n  \"camera_id\": \"cam01\",\n  \"rule\": {\n    \"rule_id\": \"rule_001\",\n    \"name\": \"사람 5명 초과\",\n    \"expression_text\": \"person \u003e 5 AND car \u003e= 2\",\n    \"record_mode\": \"EDGE_ONLY\",   // \"ALL_MATCHES\" 또는 \"EDGE_ONLY\"\n    \"enabled\": true\n  }\n}\n```\n\n---\n\n### 카메라 이벤트 조회\n\n| Method | Path | 설명 |\n|--------|------|------|\n| GET | `/api/camera_events` | 이벤트 조회 (시간 범위, 페이지네이션) |\n| GET | `/api/camera_events/count` | 마지막 조회 이후 신규 이벤트 수 |\n\n**GET /api/camera_events 파라미터:**\n```\n?start_time={ns}\u0026end_time={ns}\n  \u0026camera_id={id}        // 선택 (없으면 전체)\n  \u0026event_name={name}     // 선택\n  \u0026event_type={type}     // 선택: MATCH, TRIGGER, RESOLVE, ERROR\n  \u0026size={100}\u0026page={1}   // 페이지네이션\n```\n**응답 data:**\n```json\n{\n  \"events\": [\n    {\n      \"name\": \"rule_001\",\n      \"time\": \"2024-01-01T00:00:05Z\",\n      \"value\": 1,\n      \"value_label\": \"TRIGGER\",\n      \"expression_text\": \"person \u003e 5\",\n      \"used_counts_snapshot\": \"{\\\"person\\\":6}\",\n      \"camera_id\": \"cam01\",\n      \"rule_id\": \"rule_001\",\n      \"rule_name\": \"사람 5명 초과\"\n    }\n  ],\n  \"total_count\": 42,\n  \"total_pages\": 1\n}\n```\n\n---\n\n### AI / 감지 객체\n\n| Method | Path | 설명 |\n|--------|------|------|\n| GET | `/api/models` | AI 모델 목록 조회 (yolov8n~x) |\n| GET | `/api/detect_objects` | 감지 가능한 객체 목록 조회 |\n| GET | `/api/camera/:id/detect_objects` | 카메라별 감지 객체 조회 |\n| POST | `/api/camera/:id/detect_objects` | 카메라별 감지 객체 수정 |\n| POST | `/api/ai/result` | AI 감지 결과 수신 (ai-manager → blackbox) |\n\n---\n\n### MVS\n\n| Method | Path | 설명 |\n|--------|------|------|\n| POST | `/api/mvs/camera` | MVS 카메라 설정 생성 |\n\n---\n\n### 센서 데이터\n\n| Method | Path | 설명 |\n|--------|------|------|\n| GET | `/api/sensors` | 카메라별 센서 목록 조회 |\n| GET | `/api/sensor_data` | 센서 데이터 조회 |\n\n**GET /api/sensor_data 파라미터:**\n```\n?sensors={id1,id2,...}\u0026start={RFC3339}\u0026end={RFC3339}\n```\n\n---\n\n### 기타\n\n| Method | Path | 설명 |\n|--------|------|------|\n| GET | `/api/tables` | Machbase TAG 테이블 목록 조회 |\n| POST | `/api/table` | TAG 테이블 생성 |\n| POST | `/api/cameras/ping` | IP 주소 ping 테스트 |\n| GET | `/api/media/heartbeat` | MediaMTX 상태 확인 |\n| POST | `/db/tql` | Machbase TQL 쿼리 프록시 |\n\n**POST /api/cameras/ping 요청:**\n```json\n{ \"ip\": \"192.168.1.100\", \"timeout\": 3 }\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmachbase%2Fneo-pkg-bbox","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmachbase%2Fneo-pkg-bbox","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmachbase%2Fneo-pkg-bbox/lists"}