ltcai 0.1.26 → 0.1.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -294,7 +294,7 @@ Or: `./start_ai.sh` (auto-restart + caffeinate)
294
294
  | VS Code Marketplace | [marketplace.visualstudio.com](https://marketplace.visualstudio.com/items?itemName=parktaesoo.ltcai) |
295
295
  | Open VSX | [open-vsx.org](https://open-vsx.org/extension/parktaesoo/ltcai) |
296
296
 
297
- Current version: **0.1.26** — [Changelog](docs/CHANGELOG.md)
297
+ Current version: **0.1.27** — [Changelog](docs/CHANGELOG.md)
298
298
 
299
299
  ---
300
300
 
package/docs/CHANGELOG.md CHANGED
@@ -1,5 +1,43 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.28] - 2026-05-24
4
+
5
+ ### 버그 수정: 추천 모델 ID 오류
6
+
7
+ - **`google/gemma-4-E4B` → `mlx-community/gemma-4-e4b-it-4bit` 수정**
8
+ - 기존 ID는 HuggingFace의 BF16 풀프리시전 원본 모델 (~16GB) 로, MLX 포맷이 아니어서 `mlx_vlm.load()` 로 로드 불가능
9
+ - 올바른 MLX 4-bit 양자화 버전(`mlx-community/gemma-4-e4b-it-4bit`, 5.2GB, 43K downloads)으로 교체
10
+ - 크기 표시도 `"Next-Gen"` → `"5.2GB"` 로 실제 값으로 수정
11
+
12
+ ### Release
13
+ - 배포 버전을 `0.1.28`로 상향
14
+ - 대상 채널: `npm` · `PyPI` · `VS Code Marketplace` · `Open VSX`
15
+
16
+ ---
17
+
18
+ ## [0.1.27] - 2026-05-24
19
+
20
+ ### 로그인 페이지 UI 개선
21
+
22
+ **Language 버튼**
23
+ - 언어 표시 버튼 라벨을 `한국어 / English` 가변 텍스트에서 `Language` 고정 텍스트로 변경
24
+ - 버튼 위치를 화면 고정(fixed) → 로그인 카드 우측 상단(absolute) 으로 이동, 화면 크기 무관하게 카드 안에 항상 위치
25
+ - 버튼 크기 약 2/3 축소 (font 13px→11px, padding 6/14px→4/9px)
26
+ - footer 하단 언어 전환 버튼 제거 (도움말·개인정보처리방침 링크만 유지)
27
+
28
+ **로그인 카드 레이아웃**
29
+ - 카드 전체 크기 약 4/5 축소 — 너비 `min(720px)→min(460px)`, 폰트·버튼 높이·여백 비례 감소
30
+ - 타이틀 폰트 `38–54px → 28–40px`, 부제목 `24–34px → 17–24px`
31
+ - 카드 수직 위치: 타이틀바(58px)를 제외한 나머지 화면의 정중앙 배치 (`flex-direction: column` + `justify-content: center`, `padding-top: 58px`)
32
+ - 카드가 타이틀바와 겹치는 현상 구조적 수정 (기존 `align-items: center` 로 카드가 위로 올라가는 문제 해결)
33
+ - 로그인 카드와 개인정보처리방침 사이 여백 확보 (bottom padding 증가)
34
+
35
+ ### Release
36
+ - 배포 버전을 `0.1.27`로 상향
37
+ - 대상 채널: `npm` · `PyPI` · `VS Code Marketplace` · `Open VSX`
38
+
39
+ ---
40
+
3
41
  ## [0.1.26] - 2026-05-24
4
42
 
5
43
  ### MCP 관리 대폭 확장 — 3-탭 UI
@@ -119,3 +119,38 @@ GET /auth/sso/callback?code=... → 토큰 교환 → 세션 생성
119
119
  Claude Desktop / Cursor의 MCP 설정에 `http://localhost:4825/mcp` 추가 시 직접 도구 사용 가능.
120
120
 
121
121
  자세한 내용: [mcp-tools.md](mcp-tools.md)
122
+
123
+ ---
124
+
125
+ ## PPT 명세와의 정렬 (2026-05 추가)
126
+
127
+ `lattice_ai_full_spec.pptx` (UI 명세서) 에 맞춰 세 가지 보강 모듈이 추가됐다.
128
+ 어떤 슬라이드가 어떤 파일에 매핑되는지 한눈에:
129
+
130
+ | PPT 슬라이드 | 의미 | 구현 파일 |
131
+ |--------------|------|-----------|
132
+ | 14 (세 가지 약속) | Cross-platform · Auto-setup · Graph 원칙 | (전체 아키텍처) |
133
+ | 15·19 (크로스플랫폼·디자인 토큰) | 공유 토큰 = 단일 진실 근원 | [`static/css/tokens.css`](../static/css/tokens.css) |
134
+ | 16·17 (자동 환경 매트릭스·5단계) | OS·HW 감지 → 모델 추천 → 설치 → 검증 → 프리셋 | [`auto_setup.py`](../auto_setup.py) |
135
+ | 20·21·22 (KG 노드·엣지·데이터 모델) | 10 NodeType / 12 EdgeType + embedding + confidence | [`kg_schema.py`](../kg_schema.py), [`docs/kg-schema.md`](kg-schema.md) |
136
+ | 24 (통합 아키텍처) | 6 레이어 (UI / Logic / AI Core / KG / Storage / Auto-Setup) | 이 문서 + 위 파일들 |
137
+
138
+ ### 신규 모듈 빠른 참조
139
+
140
+ ```bash
141
+ # 자동 환경 세팅 5단계
142
+ python3 auto_setup.py probe # ① 시스템 감지
143
+ python3 auto_setup.py recommend # ② 모델 추천
144
+ python3 auto_setup.py plan # ③ 설치 계획 (실행 안 함)
145
+ python3 auto_setup.py plan --apply # ③ 실제 설치 (위험)
146
+ python3 auto_setup.py verify # ④ 검증
147
+ python3 auto_setup.py preset # ⑤ 프리셋
148
+ python3 auto_setup.py all # 전체 흐름
149
+
150
+ # KG v2 스키마
151
+ python3 kg_schema.py init ~/.ltcai/kg_v2.db
152
+ python3 kg_schema.py migrate ~/.ltcai/knowledge_graph.db # legacy → v2
153
+ python3 kg_schema.py stats ~/.ltcai/knowledge_graph.db
154
+ ```
155
+
156
+ 전체 명세 ↔ 구현 매핑은 [`spec-vs-impl.md`](spec-vs-impl.md) 참고.
@@ -0,0 +1,210 @@
1
+ # Knowledge Graph — v2 스키마
2
+
3
+ 명세 출처: `lattice_ai_full_spec.pptx` 슬라이드 20·21·22
4
+ 구현: `kg_schema.py`
5
+
6
+ ---
7
+
8
+ ## 한 줄 요약
9
+
10
+ > **점(노드)은 워크스페이스의 모든 *명사*. 선(엣지)은 모든 *동사*.**
11
+ > 모든 노드는 임베딩 벡터를 가지고, 모든 엣지는 (방향 · 타입 · 가중치 · 신뢰도 · 근거)를 가진다.
12
+
13
+ ---
14
+
15
+ ## 점 (Node)
16
+
17
+ ```
18
+ Node {
19
+ id string // ULID, 영속, 전역 유일 ("node:01HX…")
20
+ type NodeType // 아래 10가지 중 하나
21
+ label string // 사람이 읽는 짧은 이름 (≤240자)
22
+ attrs object // 타입별 구조화 메타데이터
23
+ embedding float[1024]? // 의미 벡터 (옵셔널, 권장)
24
+ owner_id string? // 소유 사용자
25
+ visibility Visibility // private | internal | shared | public
26
+ created_at ISO8601 UTC
27
+ updated_at ISO8601 UTC
28
+ }
29
+ ```
30
+
31
+ ### 노드 타입 카탈로그
32
+
33
+ | 타입 | 의미 | 대표 `attrs` |
34
+ |------|------|--------------|
35
+ | `CONVERSATION` | 대화 세션 전체 | `started_at`, `model_id`, `mode` |
36
+ | `MESSAGE` | 단일 발화 | `role`, `tokens`, `parent_id` |
37
+ | `FILE` | 업로드/연결된 파일 | `mime`, `sizeBytes`, `pageCount`, `lang` |
38
+ | `CHUNK` | 파일의 분할 청크 | `parent_file`, `offset`, `length` |
39
+ | `CODE_SYMBOL` | 함수·클래스·모듈 | `path`, `lang`, `signature` |
40
+ | `CONCEPT` | 추출된 개념 / 태그 | `aliases[]`, `extractor` |
41
+ | `PERSON` | 사용자·협업자 | `email`, `role` |
42
+ | `MODEL` | 로컬/원격 LLM | `provider`, `runtime`, `quantization` |
43
+ | `TOOL` | MCP 서버·외부 도구 | `scope`, `version`, `capabilities[]` |
44
+ | `PROJECT` | 주제별 작업 공간 | `description`, `members[]` |
45
+
46
+ ---
47
+
48
+ ## 선 (Edge)
49
+
50
+ ```
51
+ Edge {
52
+ id string // ULID ("edge:01HX…")
53
+ source string // 출발 노드 id
54
+ target string // 도착 노드 id (방향 있음)
55
+ type EdgeType // 아래 12가지 중 하나
56
+ weight float [0..1] // 관계의 ‘강도’
57
+ confidence float [0..1] // 추출/추론의 ‘신뢰도’
58
+ evidence string[] // 근거 (메시지/청크 ID 리스트)
59
+ created_by string // extractor:llm-gemma-3-12b | rule:regex | user
60
+ created_at ISO8601 UTC
61
+ }
62
+ ```
63
+
64
+ ### 엣지 타입 카탈로그
65
+
66
+ | 타입 | 허용 source → target | 의미 |
67
+ |------|---------------------|------|
68
+ | `CONTAINS` | `FILE → CHUNK` | 파일이 청크를 포함 |
69
+ | `MENTIONS` | `MESSAGE`·`FILE`·`CHUNK` → `CONCEPT`·`PERSON`·`MODEL`·`TOOL` | 언급/등장 |
70
+ | `REFERENCES` | `FILE`·`MESSAGE`·`CHUNK` → 동일 | 명시적 참조/링크 |
71
+ | `REPLIES_TO` | `MESSAGE → MESSAGE` | 답글 |
72
+ | `AUTHORED_BY` | `FILE`·`MESSAGE`·`CONVERSATION` → `PERSON` | 작성자 |
73
+ | `USES` | `PROJECT`·`CONVERSATION` → `TOOL`·`MODEL` | 도구/모델 사용 |
74
+ | `DERIVED_FROM` | `CHUNK`·`FILE` → 동일 | 요약·재가공 출처 |
75
+ | `SIMILAR_TO` | ANY ↔ ANY | 코사인 유사도 기반 (자기 자신 허용) |
76
+ | `DEPENDS_ON` | `CODE_SYMBOL → CODE_SYMBOL` | 코드 의존 관계 |
77
+ | `TAGGED_AS` | ANY → `CONCEPT` | 태깅 |
78
+ | `VERSION_OF` | `FILE → FILE` | 버전 히스토리 |
79
+ | `GRANTS_ACCESS` | `PERSON → FILE`·`CONVERSATION`·`PROJECT` | 접근 권한 부여 |
80
+
81
+ **엔드포인트 룰은 코드에서 강제된다** (`validate_endpoints` in `kg_schema.py`).
82
+ 잘못된 페어(예: `FILE → FILE` 에 `REPLIES_TO`)는 `upsert_edge` 가 거부한다.
83
+
84
+ ---
85
+
86
+ ## 예시 (PPT 슬라이드 22 와 동일)
87
+
88
+ ```json
89
+ {
90
+ "node": {
91
+ "id": "node:01HX7K…",
92
+ "type": "FILE",
93
+ "label": "LatticeAI_기획서.pdf",
94
+ "embedding": [0.014, -0.231, "…", 0.082],
95
+ "attrs": { "mime":"application/pdf",
96
+ "pageCount":24, "lang":"ko" },
97
+ "owner_id": "user_seoljun",
98
+ "visibility": "private",
99
+ "created_at": "2026-05-20T05:30:00Z"
100
+ },
101
+ "edge": {
102
+ "id": "edge:01HX7M…",
103
+ "source": "node:01HX7K…", // FILE
104
+ "target": "node:01HX5A…", // CONCEPT 'MCP'
105
+ "type": "MENTIONS",
106
+ "weight": 0.82,
107
+ "confidence": 0.91,
108
+ "evidence": ["chunk:01HX7K…#p3", "chunk:01HX7K…#p11"],
109
+ "created_by": "extractor:llm-gemma-3-12b"
110
+ }
111
+ }
112
+ ```
113
+
114
+ ---
115
+
116
+ ## 마이그레이션 (legacy → v2)
117
+
118
+ 기존 `knowledge_graph.py` 가 만든 `nodes` / `edges` 테이블은 자유 문자열 타입을
119
+ 사용해 왔다. `kg_schema.py` 는 매핑 표를 가지고 있어 정식 enum 으로 변환한다.
120
+
121
+ | legacy 타입 (한글 동사) | → v2 `EdgeType` |
122
+ |------------------------|------------------|
123
+ | `언급함`, `설명함`, `관련됨` | `MENTIONS` |
124
+ | `포함함` | `CONTAINS` |
125
+ | `해결함`, `연결함`, `발생함` | `REFERENCES` |
126
+ | `의존함` | `DEPENDS_ON` |
127
+ | `비교함` | `SIMILAR_TO` |
128
+ | `사용함`, `지원함` | `USES` |
129
+ | `확장함` | `DERIVED_FROM` |
130
+ | `생성함` | `AUTHORED_BY` |
131
+ | `대체함` | `VERSION_OF` |
132
+
133
+ | legacy 타입 (노드, 자유 문자열) | → v2 `NodeType` |
134
+ |-------------------------------|------------------|
135
+ | `Code` | `CODE_SYMBOL` |
136
+ | `Concept`, `Feature`, `Error`, `Tag` | `CONCEPT` |
137
+ | `Person`, `User` | `PERSON` |
138
+ | `File`, `Document`, `Page`, `Sheet`, `Slide` | `FILE` / `CHUNK` |
139
+ | `Message`, `AIResponse` | `MESSAGE` |
140
+ | `Model` | `MODEL` |
141
+ | `Tool`, `MCP` | `TOOL` |
142
+ | `Project`, `Workspace` | `PROJECT` |
143
+
144
+ ### 실행
145
+
146
+ ```bash
147
+ # 1) 현재 DB 의 어떤 row 가 어떻게 변환될지만 보기
148
+ python3 kg_schema.py migrate ~/.ltcai/knowledge_graph.db --dry-run
149
+
150
+ # 2) 실제 마이그레이션 (v2 테이블에 복사. 기존 테이블은 보존)
151
+ python3 kg_schema.py migrate ~/.ltcai/knowledge_graph.db
152
+
153
+ # 3) 결과 확인
154
+ python3 kg_schema.py stats ~/.ltcai/knowledge_graph.db
155
+ ```
156
+
157
+ 마이그레이션은 **기존 `nodes` / `edges` 를 건드리지 않는다.** 신규 `nodes_v2` / `edges_v2`
158
+ 테이블에 복사할 뿐이다. 새 코드가 안정화되면 다음 메이저 릴리스에서 legacy 테이블을
159
+ DROP 한다.
160
+
161
+ ---
162
+
163
+ ## 임베딩
164
+
165
+ - 차원: 환경 변수 `LATTICEAI_EMBED_DIM` (기본 `1024`)
166
+ - 저장: SQLite `BLOB` 컬럼, `struct.pack('<{n}f', …)` 직렬화
167
+ - 검색: `KGStoreV2.search_similar(vec, top_k=8)` — sqlite-vec 가 없는 환경에서도
168
+ 순수 Python 코사인으로 동작. sqlite-vec 가 설치되면 인덱스 자동 활용 (추후).
169
+
170
+ 임베딩 모델은 LLM 라우터(`llm_router.py`) 가 결정한다 — 기본 `sentence-transformers/all-MiniLM-L12-v2`
171
+ (384-d, dim 변경시 `LATTICEAI_EMBED_DIM` 도 함께 설정).
172
+
173
+ ---
174
+
175
+ ## 사용 (Python)
176
+
177
+ ```python
178
+ from kg_schema import KGStoreV2, Node, Edge, NodeType, EdgeType, Visibility
179
+
180
+ store = KGStoreV2("/Users/me/.ltcai/kg_v2.db")
181
+ store.init_schema()
182
+
183
+ # 노드 만들기
184
+ file_node = Node(
185
+ type=NodeType.FILE,
186
+ label="LatticeAI_기획서.pdf",
187
+ attrs={"mime": "application/pdf", "pageCount": 24, "lang": "ko"},
188
+ owner_id="user_seoljun",
189
+ visibility=Visibility.PRIVATE,
190
+ )
191
+ store.upsert_node(file_node)
192
+
193
+ # 관계 만들기
194
+ store.upsert_edge(Edge(
195
+ source=file_node.id,
196
+ target=concept_node.id,
197
+ type=EdgeType.MENTIONS,
198
+ weight=0.82, confidence=0.91,
199
+ evidence=["chunk:01HX7K…#p3"],
200
+ created_by="extractor:llm-gemma-3-12b",
201
+ ))
202
+
203
+ # 이웃 탐색
204
+ for edge, other in store.neighbors(file_node.id, edge_type=EdgeType.MENTIONS):
205
+ print(f"-[{edge.type.value}]-> {other.label}")
206
+
207
+ # 의미 검색
208
+ for node, score in store.search_similar(query_embedding, top_k=8):
209
+ print(f"{score:+.3f} {node.type.value:>12} {node.label}")
210
+ ```
@@ -0,0 +1,132 @@
1
+ # Lattice AI — 명세(PPT) vs 구현(repo) 매핑
2
+
3
+ `lattice_ai_full_spec.pptx` 의 사양과 현재 리포지토리 구현 사이의 정렬 상태를 한 장으로 정리한다.
4
+ 각 항목은 **목표(PPT) → 현재(repo) → 갭 → 보강 위치** 순으로 본다.
5
+
6
+ ---
7
+
8
+ ## 0. 세 가지 약속
9
+
10
+ | 약속 | 목표 (PPT) | 현재 (repo) | 갭 |
11
+ |------|-----------|-------------|----|
12
+ | Cross-Platform Parity | Win·macOS·Linux·iOS·Android, 같은 디자인 토큰·컴포넌트 | Web(static) + VSCode ext + Telegram (브라우저 어디서나) | 네이티브 데스크탑/모바일 셸 없음 (PWA 부분 지원) |
13
+ | Zero-Config Auto Setup | PROBE → RECOMMEND → INSTALL → VERIFY → PRESET, 90초 내 | `LTCAI doctor` (의존성만 체크 = PROBE의 일부) | GPU/RAM 프로빙, 추천, 설치, 벤치마크, 프리셋 미구현 |
14
+ | Everything is a Graph | 10 노드 타입 / 12 엣지 타입 / 임베딩 / 신뢰도+증거 | nodes·edges·chunks 테이블 + 한글 동사 엣지(EDGE_VERB) | 명시 enum·embedding·confidence/evidence·owner 결손 |
15
+
16
+ ---
17
+
18
+ ## 1. 크로스플랫폼
19
+
20
+ PPT 명세는 "한 코드·다섯 화면" — Shared Core(Design Tokens, UI Components, Business Logic, AI/Graph Core) 위에서 Tauri(데스크탑) / Capacitor·RN(모바일) 렌더러가 같은 결과를 낸다.
21
+
22
+ **현재 구현**
23
+ - `static/chat.html`, `static/graph.html`, `static/admin.html`, `static/account.html` 4개 HTML — 각자 자체 CSS 변수 보유
24
+ - `vscode-extension/` — TypeScript VSCode 통합
25
+ - `static/manifest.json` + `static/sw.js` — PWA 부분 지원 (iOS/Android 홈 화면 추가는 됨)
26
+ - `telegram_bot.py` — Telegram 미러
27
+
28
+ **갭**
29
+ - 데스크탑 네이티브 셸 (Tauri) 미구현
30
+ - 모바일 네이티브 (Capacitor / RN) 미구현
31
+ - 4개 HTML이 각자 다른 색 토큰 사용 → 같은 화면이 같게 안 보임
32
+ - 다국어(i18n) 시스템화 안 됨 (HTML에 한글 하드코딩)
33
+
34
+ **보강 결과물**
35
+ - `static/css/tokens.css` (이번 PR에서 추가) — 4개 HTML이 공유할 단일 진실 토큰
36
+ - 로드맵: `apps/desktop/` (Tauri 셸) · `apps/mobile/` (Capacitor 셸) 차후 단계
37
+
38
+ ---
39
+
40
+ ## 2. 자동 환경 세팅
41
+
42
+ PPT 명세 5단계:
43
+
44
+ | 단계 | 의미 | 현재 |
45
+ |------|------|------|
46
+ | ① PROBE | OS · CPU · GPU · RAM · 디스크 · 권한 감지 | `LTCAI doctor` 가 의존성만 체크 |
47
+ | ② RECOMMEND | 사양 점수 → 최적 모델 자동 선택 | 없음 |
48
+ | ③ INSTALL | OS별 패키지 매니저로 런타임 설치 | 없음 |
49
+ | ④ VERIFY | 토큰/초 측정, 첫 응답 지연 검증 | 없음 |
50
+ | ⑤ PRESET | 기본/고급 모드 분기 + 단축키/MCP/테마 | 없음 |
51
+
52
+ **보강 결과물**
53
+ - `auto_setup.py` (이번 PR) — 위 5단계를 단일 모듈로 구현
54
+ - `LTCAI setup` 서브커맨드 추가 (`ltcai_cli.py` 마이너 패치 또는 별도 진입점)
55
+
56
+ ---
57
+
58
+ ## 3. 지식 그래프
59
+
60
+ PPT 명세 (점 = 노드, 선 = 엣지):
61
+
62
+ ```
63
+ NODE { id, type∈10종, label, embedding[1024], attrs, createdAt, updatedAt,
64
+ ownerId, visibility }
65
+ EDGE { id, source, target, type∈12종, weight, confidence, evidence[],
66
+ createdBy, createdAt }
67
+ ```
68
+
69
+ **현재 구현 (`knowledge_graph.py`)**
70
+ ```
71
+ nodes ( id, type, title, summary, metadata_json, raw_json, created_at, updated_at )
72
+ edges ( id, from_node, to_node, type, weight, metadata_json, created_at,
73
+ UNIQUE(from_node, to_node, type) )
74
+ chunks ( id, source_node, text, metadata_json, created_at )
75
+ ```
76
+
77
+ **갭**
78
+ - 노드 타입이 enum이 아닌 자유 문자열 (`Code`, `Person`, `Concept`, `Feature`, `Error`, `Message`, `AIResponse` 산발)
79
+ - `embedding` 컬럼 부재 → semantic similarity 검색 불가, `SIMILAR_TO` 엣지 추론 불가
80
+ - 엣지 타입이 한글 동사 14종 (`언급함`, `포함함` …) — PPT 영문 SCREAMING_CASE 12종과 불일치
81
+ - `confidence` / `evidence` 가 metadata_json 안에 비공식적으로 섞임
82
+ - `ownerId` / `visibility` 부재 → multi-tenant 권한 정책 불가
83
+ - `createdBy` (추출기 출처) 부재 → 디버깅·재추출 안 됨
84
+
85
+ **보강 결과물**
86
+ - `kg_schema.py` (이번 PR) — `NodeType`, `EdgeType` Enum + Pydantic 모델 + 마이그레이션 가이드
87
+ - `docs/kg-schema.md` — JSON 예시, 매핑 표
88
+ - 기존 코드와의 호환: 신규 모델은 기존 SQLite 와 공존 (별도 v2 테이블), 점진 마이그레이션
89
+
90
+ ---
91
+
92
+ ## 4. 디자인 일관성
93
+
94
+ | 파일 | 현재 --bg | 현재 --accent |
95
+ |------|-----------|---------------|
96
+ | `chat.html` | `#182332` 다크 블루그린 | `#22d3a0` 민트 |
97
+ | `graph.html` | `#282a36` 다크 그레이 | `#a77cff` 라일락 |
98
+ | `admin.html` | `#282a36` | `#a77cff` |
99
+ | `account.html`| `#282a36` + `#f7f3ff` 혼재 | `#a77cff` |
100
+ | `lattice-reference.css` | (라이트, PPT) | `#6f42e8` Lattice 보라 |
101
+ | **PPT 명세** | `#FFFFFF` 또는 `#0B0B16` | `#6E4AE6` Lattice 보라 |
102
+
103
+ **보강 결과물**
104
+ - `static/css/tokens.css` — 단일 토큰 (PPT 명세 그대로)
105
+ - 4개 HTML 의 `:root {}` 블록을 `@import` 한 줄로 대체 가능하도록 토큰 명 호환
106
+
107
+ ---
108
+
109
+ ## 5. SSO·다국어
110
+
111
+ PPT 화면 1, 13 (login, security) 에 한국어 / Microsoft Entra ID / Okta SSO 가 있음.
112
+
113
+ **현재**
114
+ - `server.py` 의 `/auth/sso` 엔드포인트 존재 (architecture.md 언급) — Entra/Okta 둘 다 명시되어 있는지 확인 필요
115
+ - 다국어 — HTML 하드코딩 (`lang="ko"`)
116
+
117
+ **갭 / 다음 단계**
118
+ - i18n 사전 (`static/i18n/{ko,en,ja}.json`) 추출 → PPT 명세 그대로 토큰화
119
+
120
+ ---
121
+
122
+ ## 6. 보강 우선순위 요약
123
+
124
+ | 순위 | 파일 | 무엇 |
125
+ |------|------|------|
126
+ | 1 | `docs/kg-schema.md`, `kg_schema.py` | KG 스키마 정식화 (10 노드 · 12 엣지 · embedding · confidence) |
127
+ | 2 | `static/css/tokens.css` | 디자인 토큰 통합 (PPT 색팔레트) |
128
+ | 3 | `auto_setup.py` | OS 프로빙 + 모델 추천 + 설치 어댑터 |
129
+ | 4 | `docs/architecture.md` 보강 | 위 변경 반영 |
130
+ | 5 | (차후) `apps/desktop`, `apps/mobile` 스캐폴딩 | Tauri/Capacitor |
131
+
132
+ 각 항목은 이번 PR 에 함께 들어간다 (1~3은 코드, 4는 문서, 5는 청사진만).
@@ -18,6 +18,11 @@ from datetime import datetime
18
18
  from pathlib import Path
19
19
  from typing import Any, Dict, List, Optional
20
20
 
21
+ try:
22
+ from kg_schema import KGStoreV2
23
+ except Exception: # pragma: no cover - v2 schema is optional at import time
24
+ KGStoreV2 = None # type: ignore[assignment]
25
+
21
26
 
22
27
  GRAPH_SCHEMA_VERSION = 1
23
28
 
@@ -438,6 +443,16 @@ class KnowledgeGraphStore:
438
443
  "INSERT OR REPLACE INTO graph_meta(key, value) VALUES (?, ?)",
439
444
  ("schema_version", str(GRAPH_SCHEMA_VERSION)),
440
445
  )
446
+ self._init_v2_schema()
447
+
448
+ def _init_v2_schema(self) -> None:
449
+ """Initialize the PPT-aligned v2 tables alongside the legacy graph tables."""
450
+ if KGStoreV2 is None:
451
+ return
452
+ try:
453
+ KGStoreV2(self.db_path).init_schema()
454
+ except Exception as e:
455
+ logging.warning("knowledge_graph: v2 schema init skipped: %s", e)
441
456
 
442
457
  def _upsert_node(
443
458
  self,
@@ -1275,4 +1290,17 @@ class KnowledgeGraphStore:
1275
1290
  row["type"]: row["count"]
1276
1291
  for row in conn.execute("SELECT type, COUNT(*) AS count FROM edges GROUP BY type")
1277
1292
  }
1278
- return {"db_path": str(self.db_path), "nodes": node_counts, "edges": edge_counts}
1293
+ v2 = None
1294
+ if KGStoreV2 is not None:
1295
+ try:
1296
+ v2 = KGStoreV2(self.db_path).stats()
1297
+ except Exception as e:
1298
+ v2 = {"available": False, "error": str(e)}
1299
+ return {
1300
+ "db_path": str(self.db_path),
1301
+ "schema_version": GRAPH_SCHEMA_VERSION,
1302
+ "v2_schema_available": KGStoreV2 is not None,
1303
+ "nodes": node_counts,
1304
+ "edges": edge_counts,
1305
+ "v2": v2,
1306
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ltcai",
3
- "version": "0.1.26",
3
+ "version": "0.1.28",
4
4
  "description": "Lattice AI local MLX/cloud LLM workspace server",
5
5
  "homepage": "https://github.com/TaeSooPark-PTS/LatticeAI#readme",
6
6
  "repository": {
@@ -56,6 +56,8 @@
56
56
  "static/graph.html",
57
57
  "static/manifest.json",
58
58
  "static/sw.js",
59
+ "static/lattice-reference.css",
60
+ "static/css/",
59
61
  "static/icons/",
60
62
  "docs/",
61
63
  "requirements.txt",
package/server.py CHANGED
@@ -48,6 +48,13 @@ from llm_router import AsyncOpenAI, LLMRouter, OPENAI_COMPATIBLE_PROVIDERS, HF_M
48
48
  from knowledge_graph import KnowledgeGraphStore
49
49
  from p_reinforce import BRAIN_DIR, PReinforceGardener
50
50
  from setup import get_recommendations, install_stream, open_url, scan_environment
51
+ from auto_setup import (
52
+ plan as auto_setup_plan,
53
+ preset as auto_setup_preset,
54
+ probe as auto_setup_probe,
55
+ recommend as auto_setup_recommend,
56
+ verify as auto_setup_verify,
57
+ )
51
58
  from telegram_bot import broadcast_web_chat
52
59
  from tools import (
53
60
  AGENT_ROOT,
@@ -3993,7 +4000,7 @@ async def list_models():
3993
4000
  {"id": "mlx-community/Llama-3.1-8B-Instruct-4bit", "name": "Llama 3.1 8B", "tag": "general", "size": "4.7GB"},
3994
4001
 
3995
4002
  # Gemma Series
3996
- {"id": "google/gemma-4-E4B", "name": "Gemma 4 E4B (Latest)", "tag": "next-gen", "size": "Next-Gen"},
4003
+ {"id": "mlx-community/gemma-4-e4b-it-4bit", "name": "Gemma 4 E4B (4-bit)", "tag": "next-gen", "size": "5.2GB"},
3997
4004
  {"id": "mlx-community/gemma-2-9b-it-4bit", "name": "Gemma 2 9B", "tag": "balanced","size": "5.4GB"},
3998
4005
  {"id": "mlx-community/gemma-2-2b-it-4bit", "name": "Gemma 2 2B", "tag": "ultra-light", "size": "1.6GB"},
3999
4006
 
@@ -4334,6 +4341,17 @@ async def knowledge_graph_stats(request: Request):
4334
4341
  require_user(request)
4335
4342
  return KNOWLEDGE_GRAPH.stats()
4336
4343
 
4344
+ @app.get("/knowledge-graph/schema")
4345
+ async def knowledge_graph_schema(request: Request):
4346
+ _require_graph()
4347
+ require_user(request)
4348
+ stats = KNOWLEDGE_GRAPH.stats()
4349
+ return {
4350
+ "legacy_schema_version": stats.get("schema_version"),
4351
+ "v2_schema_available": stats.get("v2_schema_available"),
4352
+ "v2": stats.get("v2"),
4353
+ }
4354
+
4337
4355
 
4338
4356
  @app.get("/knowledge-graph/graph")
4339
4357
  async def knowledge_graph_data(request: Request, limit: int = 300):
@@ -6772,13 +6790,37 @@ async def garden_tree(request: Request):
6772
6790
  class SetupInstallRequest(BaseModel):
6773
6791
  items: List[Dict]
6774
6792
 
6793
+ def setup_auto_state() -> Dict[str, object]:
6794
+ """Return the PPT-aligned zero-config setup state used by setup UI/API."""
6795
+ profile = auto_setup_probe()
6796
+ recommendation = auto_setup_recommend(profile)
6797
+ install_plan = auto_setup_plan(profile, recommendation)
6798
+ return {
6799
+ "probe": profile.to_json(),
6800
+ "recommend": recommendation.to_json(),
6801
+ "plan": install_plan.to_json(),
6802
+ "verify": auto_setup_verify(profile, recommendation),
6803
+ "preset": auto_setup_preset(profile, recommendation),
6804
+ }
6805
+
6775
6806
  @app.get("/setup/scan")
6776
6807
  async def setup_scan(request: Request):
6777
6808
  """환경 감지 및 맞춤 추천 반환."""
6778
6809
  require_user(request)
6779
6810
  env = scan_environment()
6780
6811
  recs = get_recommendations(env)
6781
- return {"environment": env, "recommendations": recs}
6812
+ zero_config = setup_auto_state()
6813
+ env["zero_config"] = zero_config
6814
+ recs.setdefault("summary", {})["zero_config"] = zero_config["recommend"]
6815
+ recs["install_plan"] = zero_config["plan"]
6816
+ recs["preset"] = zero_config["preset"]
6817
+ return {"environment": env, "recommendations": recs, "zero_config": zero_config}
6818
+
6819
+ @app.get("/setup/auto")
6820
+ async def setup_auto(request: Request):
6821
+ """PPT-aligned zero-config setup pipeline: probe → recommend → plan → verify → preset."""
6822
+ require_user(request)
6823
+ return setup_auto_state()
6782
6824
 
6783
6825
  @app.post("/setup/install")
6784
6826
  async def setup_install(req: SetupInstallRequest, request: Request):