-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpyproject.toml
More file actions
138 lines (124 loc) · 4.68 KB
/
Copy pathpyproject.toml
File metadata and controls
138 lines (124 loc) · 4.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
[project]
name = "devs-ai"
version = "0.1.0"
description = "채용 데이터 수집 · 임베딩 · LLM 어시스턴트"
requires-python = ">=3.13"
dependencies = [
# --- web ---
"fastapi>=0.115",
"uvicorn[standard]>=0.32",
"sse-starlette>=2.1",
"pydantic>=2.9",
"pydantic-settings>=2.6",
# --- db (postgres + pgvector) ---
"sqlmodel>=0.0.24",
"sqlalchemy[asyncio]>=2.0",
"psycopg[binary,pool]>=3.2",
"pgvector>=0.3.6",
"alembic>=1.14",
# --- auth ---
"pyjwt[crypto]>=2.9",
# --- llm / graph ---
"anthropic>=0.40",
"langgraph>=0.2.50",
"langgraph-checkpoint-postgres>=2.0",
# --- worker ---
"arq>=0.26",
# --- crawler ---
"httpx>=0.27",
"beautifulsoup4>=4.12",
"lxml>=5.3",
"tenacity>=9.0",
"pyyaml>=6.0",
"ollama>=0.6.2",
]
[dependency-groups]
dev = [
"pytest>=8.3",
"pytest-asyncio>=0.24",
"respx>=0.21",
"ruff>=0.8",
"import-linter>=2.1",
]
# scripts/embed_local/ 전용. torch 를 끌고 와 수 GB 라 기본에서 뺐다.
# uv sync --group local
# uv run python -m scripts.embed_local.run
# ★ 호스트 전용이다. 워커 이미지에는 넣지 않는다 — 맥의 Docker 는 GPU(MPS)를
# 통과시키지 않아 컨테이너 안에서는 CPU 로 떨어진다.
# 실측: 호스트 MPS fp16 90.7 청크/초 vs 컨테이너 CPU 3.4 청크/초
local = [
"sentence-transformers>=3.0",
# torch 는 sentence-transformers 가 어차피 끌고 오지만, 여기 직접 적어야
# 아래 [tool.uv.sources] 의 CPU 전용 인덱스 지정이 먹는다.
# uv 의 source 재정의는 직접 의존성에만 적용되고 전이 의존성은 건너뛴다.
"torch>=2.0",
]
# ── torch 를 linux 에서는 CPU 전용으로 받는다 ────────────────────────────────
# 기본 PyPI 의 linux 용 torch 는 CUDA 런타임을 끌고 와 이미지가 3.5GB 커진다
# (nvidia/ 2.9GB · triton/ 652MB — 워커는 GPU 를 못 쓰므로 전부 죽은 무게).
# macOS 는 marker 로 제외한다. 기본 PyPI 의 torch 가 MPS 를 지원한다.
[[tool.uv.index]]
name = "pytorch-cpu"
url = "https://download.pytorch.org/whl/cpu"
explicit = true
[tool.uv.sources]
torch = [{ index = "pytorch-cpu", marker = "sys_platform != 'darwin'" }]
[tool.uv]
package = false
[tool.ruff]
line-length = 100
target-version = "py313"
[tool.ruff.lint]
# 진짜 오류만 본다. import 정렬(I) · 줄바꿈 · 코드 스타일 계열은 켜지 않는다.
# E9 구문 오류 · 파일 입출력 오류
# F 미정의 이름(F821) · 미사용 import(F401) 같은 실제 버그
# 명시하지 않으면 기본값 E4,E7,E9,F 가 켜져 스타일 지적이 섞인다.
select = ["E9", "F"]
ignore = ["I001"]
[tool.pytest.ini_options]
asyncio_mode = "auto"
# ─────────────────────────────────────────────────────────────────────────────
# 의존 규칙 R1~R4 강제 (lint-imports)
# CI: `lint-imports` 를 ruff 와 함께 실행
# ─────────────────────────────────────────────────────────────────────────────
[tool.importlinter]
root_package = "app"
# R1 — market 은 아무 도메인도 import 하지 않는다
[[tool.importlinter.contracts]]
name = "R1: market is independent"
type = "forbidden"
source_modules = ["app.domains.market"]
forbidden_modules = ["app.domains.crawler", "app.domains.chat", "app.llm"]
# R2 — crawler 는 chat 을 모른다
[[tool.importlinter.contracts]]
name = "R2: crawler does not touch chat"
type = "forbidden"
source_modules = ["app.domains.crawler"]
forbidden_modules = ["app.domains.chat"]
# R3 — chat 은 market.queries(읽기)만. models/repository 직접 참조 금지
[[tool.importlinter.contracts]]
name = "R3: chat reads market through queries only"
type = "forbidden"
source_modules = ["app.domains.chat"]
forbidden_modules = [
"app.domains.market.models",
"app.domains.market.repository",
"app.domains.crawler",
]
# R4 — port 는 어댑터를 모른다
[[tool.importlinter.contracts]]
name = "R4: port knows no adapter"
type = "forbidden"
source_modules = ["app.llm.port"]
forbidden_modules = [
"app.llm.chat_adapter",
"app.llm.embed_adapter",
"app.llm.gemini_embed_adapter",
"app.llm.fake",
]
# core 는 도메인을 모른다
[[tool.importlinter.contracts]]
name = "core is the bottom layer"
type = "forbidden"
source_modules = ["app.core"]
forbidden_modules = ["app.domains", "app.llm"]