realtimex-deeptutor 0.5.0.post2__py3-none-any.whl → 0.5.0.post3__py3-none-any.whl

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.
@@ -0,0 +1,460 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ DeepTutor Installation Checker
4
+
5
+ Verifies that all required dependencies are correctly installed.
6
+ Run this script to diagnose installation issues.
7
+ """
8
+
9
+ import importlib.metadata
10
+ import os
11
+ from pathlib import Path
12
+ import shutil
13
+ import subprocess
14
+ import sys
15
+
16
+ # Set Windows console UTF-8 encoding
17
+ if sys.platform == "win32":
18
+ import io
19
+
20
+ sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
21
+ sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8")
22
+
23
+
24
+ # Color codes for terminal output
25
+ class Colors:
26
+ RED = "\033[0;31m"
27
+ GREEN = "\033[0;32m"
28
+ YELLOW = "\033[1;33m"
29
+ BLUE = "\033[0;34m"
30
+ CYAN = "\033[0;36m"
31
+ NC = "\033[0m" # No Color
32
+
33
+ @classmethod
34
+ def disable(cls):
35
+ """Disable colors for non-TTY output"""
36
+ cls.RED = cls.GREEN = cls.YELLOW = cls.BLUE = cls.CYAN = cls.NC = ""
37
+
38
+
39
+ # Disable colors if not a TTY
40
+ if not sys.stdout.isatty():
41
+ Colors.disable()
42
+
43
+
44
+ def print_header(message: str):
45
+ """Print section header"""
46
+ print(f"\n{'=' * 60}")
47
+ print(f"📋 {message}")
48
+ print("=" * 60)
49
+
50
+
51
+ def print_success(message: str):
52
+ """Print success message"""
53
+ print(f"{Colors.GREEN}✅ {message}{Colors.NC}")
54
+
55
+
56
+ def print_error(message: str):
57
+ """Print error message"""
58
+ print(f"{Colors.RED}❌ {message}{Colors.NC}")
59
+
60
+
61
+ def print_warning(message: str):
62
+ """Print warning message"""
63
+ print(f"{Colors.YELLOW}⚠️ {message}{Colors.NC}")
64
+
65
+
66
+ def print_info(message: str):
67
+ """Print info message"""
68
+ print(f"{Colors.CYAN}ℹ️ {message}{Colors.NC}")
69
+
70
+
71
+ def get_package_version(package_name: str) -> str | None:
72
+ """Get installed package version"""
73
+ try:
74
+ return importlib.metadata.version(package_name)
75
+ except importlib.metadata.PackageNotFoundError:
76
+ return None
77
+
78
+
79
+ def check_python_environment() -> bool:
80
+ """Check Python environment"""
81
+ print_header("Python Environment")
82
+
83
+ all_ok = True
84
+
85
+ # Python version
86
+ py_version = sys.version_info
87
+ print_info(f"Python version: {py_version.major}.{py_version.minor}.{py_version.micro}")
88
+
89
+ if py_version >= (3, 10):
90
+ print_success(f"Python {py_version.major}.{py_version.minor} meets requirement (>=3.10)")
91
+ else:
92
+ print_error(f"Python {py_version.major}.{py_version.minor} is below requirement (>=3.10)")
93
+ all_ok = False
94
+
95
+ # Python executable
96
+ print_info(f"Python executable: {sys.executable}")
97
+
98
+ # Virtual environment
99
+ in_venv = hasattr(sys, "real_prefix") or (
100
+ hasattr(sys, "base_prefix") and sys.base_prefix != sys.prefix
101
+ )
102
+ conda_env = os.environ.get("CONDA_DEFAULT_ENV")
103
+
104
+ if conda_env:
105
+ print_success(f"Conda environment: {conda_env}")
106
+ elif in_venv:
107
+ print_success(f"Virtual environment: {sys.prefix}")
108
+ else:
109
+ print_warning("No isolated environment detected (recommended: use conda or venv)")
110
+
111
+ return all_ok
112
+
113
+
114
+ def check_backend_packages() -> tuple[bool, int, int]:
115
+ """Check backend Python packages"""
116
+ print_header("Backend Dependencies")
117
+
118
+ # Required packages: (pip_name, import_name, min_version, is_optional)
119
+ packages = [
120
+ # Core
121
+ ("python-dotenv", "dotenv", "1.0.0", False),
122
+ ("PyYAML", "yaml", "6.0", False),
123
+ ("tiktoken", "tiktoken", "0.5.0", False),
124
+ ("jinja2", "jinja2", "3.1.0", False),
125
+ # HTTP & API
126
+ ("requests", "requests", "2.32.0", False),
127
+ ("openai", "openai", "1.30.0", False),
128
+ ("anthropic", "anthropic", "0.30.0", False),
129
+ ("aiohttp", "aiohttp", "3.9.0", False),
130
+ ("httpx", "httpx", "0.27.0", False),
131
+ # Async
132
+ ("nest-asyncio", "nest_asyncio", "1.5.8", False),
133
+ ("tenacity", "tenacity", "8.0.0", False),
134
+ # Web framework
135
+ ("fastapi", "fastapi", "0.100.0", False),
136
+ ("uvicorn", "uvicorn", "0.24.0", False),
137
+ ("websockets", "websockets", "12.0", False),
138
+ ("pydantic", "pydantic", "2.0.0", False),
139
+ # RAG
140
+ ("lightrag-hku", "lightrag", "1.0.0", False),
141
+ ("raganything", "raganything", "0.1.0", False),
142
+ ("llama-index", "llama_index", "0.14.0", False),
143
+ # Document parsing
144
+ ("docling", "docling", "2.31.0", True), # Optional
145
+ ("PyMuPDF", "fitz", "1.26.0", False),
146
+ # Academic
147
+ ("arxiv", "arxiv", "2.0.0", False),
148
+ # Optional API clients
149
+ ("perplexityai", "perplexity", "0.1.0", True),
150
+ ("dashscope", "dashscope", "1.14.0", True),
151
+ ]
152
+
153
+ installed = 0
154
+ missing = 0
155
+ all_ok = True
156
+
157
+ for pip_name, import_name, min_version, is_optional in packages:
158
+ try:
159
+ __import__(import_name)
160
+ version = get_package_version(pip_name)
161
+ version_str = f" (v{version})" if version else ""
162
+ print_success(f" ✓ {pip_name}{version_str}")
163
+ installed += 1
164
+ except ImportError:
165
+ if is_optional:
166
+ print_warning(f" ⚠ {pip_name} not installed (optional)")
167
+ else:
168
+ print_error(f" ✗ {pip_name} not installed")
169
+ all_ok = False
170
+ missing += 1
171
+
172
+ return all_ok, installed, missing
173
+
174
+
175
+ def check_frontend_packages(project_root: Path) -> tuple[bool, int, int]:
176
+ """Check frontend Node.js packages"""
177
+ print_header("Frontend Dependencies")
178
+
179
+ web_dir = project_root / "web"
180
+ node_modules = web_dir / "node_modules"
181
+ package_json = web_dir / "package.json"
182
+
183
+ installed = 0
184
+ missing = 0
185
+ all_ok = True
186
+
187
+ # Check npm
188
+ npm_path = shutil.which("npm")
189
+ if npm_path:
190
+ try:
191
+ result = subprocess.run(
192
+ ["npm", "--version"],
193
+ capture_output=True,
194
+ text=True,
195
+ timeout=10,
196
+ )
197
+ npm_version = result.stdout.strip()
198
+ print_success(f"npm available (v{npm_version})")
199
+ except Exception:
200
+ print_warning("npm found but version check failed")
201
+ else:
202
+ print_error("npm not found - Node.js is required for frontend")
203
+ all_ok = False
204
+
205
+ # Check node
206
+ node_path = shutil.which("node")
207
+ if node_path:
208
+ try:
209
+ result = subprocess.run(
210
+ ["node", "--version"],
211
+ capture_output=True,
212
+ text=True,
213
+ timeout=10,
214
+ )
215
+ node_version = result.stdout.strip()
216
+ print_success(f"Node.js available ({node_version})")
217
+ except Exception:
218
+ print_warning("Node.js found but version check failed")
219
+ else:
220
+ print_error("Node.js not found")
221
+ all_ok = False
222
+
223
+ # Check package.json exists
224
+ if not package_json.exists():
225
+ print_error(f"package.json not found: {package_json}")
226
+ return False, 0, 0
227
+
228
+ # Check node_modules
229
+ if not node_modules.exists():
230
+ print_error("node_modules directory does not exist")
231
+ print_info("Run 'npm install' in web/ directory to install dependencies")
232
+ return False, 0, 0
233
+
234
+ # Check key packages
235
+ key_packages = [
236
+ "next",
237
+ "react",
238
+ "react-dom",
239
+ "typescript",
240
+ "tailwindcss",
241
+ "@radix-ui/react-dialog",
242
+ "lucide-react",
243
+ ]
244
+
245
+ print_info("Checking key frontend packages...")
246
+
247
+ for pkg in key_packages:
248
+ pkg_dir = node_modules / pkg
249
+ if pkg_dir.exists():
250
+ # Try to get version from package.json
251
+ pkg_json = pkg_dir / "package.json"
252
+ version = ""
253
+ if pkg_json.exists():
254
+ try:
255
+ import json
256
+
257
+ with open(pkg_json) as f:
258
+ data = json.load(f)
259
+ version = f" (v{data.get('version', '?')})"
260
+ except Exception:
261
+ pass
262
+ print_success(f" ✓ {pkg}{version}")
263
+ installed += 1
264
+ else:
265
+ print_error(f" ✗ {pkg} not installed")
266
+ missing += 1
267
+ all_ok = False
268
+
269
+ return all_ok, installed, missing
270
+
271
+
272
+ def check_system_tools() -> bool:
273
+ """Check system tools and utilities"""
274
+ print_header("System Tools")
275
+
276
+ all_ok = True
277
+
278
+ # Git
279
+ git_path = shutil.which("git")
280
+ if git_path:
281
+ try:
282
+ result = subprocess.run(
283
+ ["git", "--version"],
284
+ capture_output=True,
285
+ text=True,
286
+ timeout=10,
287
+ )
288
+ git_version = result.stdout.strip()
289
+ print_success(f"{git_version}")
290
+ except Exception:
291
+ print_warning("git found but version check failed")
292
+ else:
293
+ print_warning("git not found (optional but recommended)")
294
+
295
+ # uv (fast Python package manager)
296
+ uv_path = shutil.which("uv")
297
+ if uv_path:
298
+ try:
299
+ result = subprocess.run(
300
+ ["uv", "--version"],
301
+ capture_output=True,
302
+ text=True,
303
+ timeout=10,
304
+ )
305
+ uv_version = result.stdout.strip()
306
+ print_success(f"uv available ({uv_version})")
307
+ except Exception:
308
+ print_warning("uv found but version check failed")
309
+ else:
310
+ print_info("uv not found (optional, for faster package installation)")
311
+
312
+ return all_ok
313
+
314
+
315
+ def check_env_file(project_root: Path) -> bool:
316
+ """Check .env file configuration"""
317
+ print_header("Environment Configuration")
318
+
319
+ env_file = project_root / ".env"
320
+ env_example = project_root / ".env.example"
321
+
322
+ if env_file.exists():
323
+ print_success(".env file exists")
324
+
325
+ # Check for required keys (without revealing values)
326
+ required_keys = [
327
+ "OPENAI_API_KEY",
328
+ ]
329
+ optional_keys = [
330
+ "ANTHROPIC_API_KEY",
331
+ "PERPLEXITY_API_KEY",
332
+ "DASHSCOPE_API_KEY",
333
+ ]
334
+
335
+ try:
336
+ with open(env_file) as f:
337
+ content = f.read()
338
+ lines = content.split("\n")
339
+ env_vars = {}
340
+ for line in lines:
341
+ line = line.strip()
342
+ if line and not line.startswith("#") and "=" in line:
343
+ key = line.split("=")[0].strip()
344
+ value = line.split("=", 1)[1].strip() if "=" in line else ""
345
+ env_vars[key] = value
346
+
347
+ for key in required_keys:
348
+ if key in env_vars and env_vars[key]:
349
+ print_success(f" ✓ {key} is set")
350
+ else:
351
+ print_warning(f" ⚠ {key} is not set (required for most features)")
352
+
353
+ for key in optional_keys:
354
+ if key in env_vars and env_vars[key]:
355
+ print_success(f" ✓ {key} is set")
356
+ else:
357
+ print_info(f" ○ {key} is not set (optional)")
358
+
359
+ except Exception as e:
360
+ print_warning(f"Could not read .env file: {e}")
361
+
362
+ return True
363
+ else:
364
+ print_warning(".env file not found")
365
+ if env_example.exists():
366
+ print_info("Copy .env.example to .env and configure your API keys")
367
+ else:
368
+ print_info("Create a .env file with your API keys (e.g., OPENAI_API_KEY)")
369
+ return False
370
+
371
+
372
+ def main():
373
+ """Main function"""
374
+ print("\n" + "=" * 60)
375
+ print("🔍 DeepTutor Installation Checker")
376
+ print("=" * 60)
377
+ print("Checking all dependencies and configurations...")
378
+
379
+ # Get project root
380
+ script_dir = Path(__file__).parent
381
+ project_root = script_dir.parent
382
+
383
+ print_info(f"Project root: {project_root}")
384
+
385
+ # Track overall status
386
+ all_checks_passed = True
387
+ summary = []
388
+
389
+ # 1. Python environment
390
+ if check_python_environment():
391
+ summary.append(("Python Environment", "✅ OK"))
392
+ else:
393
+ summary.append(("Python Environment", "❌ Issues found"))
394
+ all_checks_passed = False
395
+
396
+ # 2. Backend packages
397
+ backend_ok, backend_installed, backend_missing = check_backend_packages()
398
+ if backend_ok:
399
+ summary.append(("Backend Dependencies", f"✅ OK ({backend_installed} packages)"))
400
+ else:
401
+ summary.append(
402
+ ("Backend Dependencies", f"❌ {backend_missing} missing, {backend_installed} installed")
403
+ )
404
+ all_checks_passed = False
405
+
406
+ # 3. Frontend packages
407
+ frontend_ok, frontend_installed, frontend_missing = check_frontend_packages(project_root)
408
+ if frontend_ok:
409
+ summary.append(("Frontend Dependencies", f"✅ OK ({frontend_installed} packages)"))
410
+ else:
411
+ summary.append(
412
+ (
413
+ "Frontend Dependencies",
414
+ f"❌ {frontend_missing} missing, {frontend_installed} installed",
415
+ )
416
+ )
417
+ all_checks_passed = False
418
+
419
+ # 4. System tools
420
+ check_system_tools()
421
+ summary.append(("System Tools", "✅ Checked"))
422
+
423
+ # 5. Environment configuration
424
+ if check_env_file(project_root):
425
+ summary.append(("Environment Config", "✅ .env exists"))
426
+ else:
427
+ summary.append(("Environment Config", "⚠️ .env missing"))
428
+
429
+ # Print summary
430
+ print_header("Summary")
431
+
432
+ for item, status in summary:
433
+ print(f" {item}: {status}")
434
+
435
+ print("")
436
+ if all_checks_passed:
437
+ print_success("All required dependencies are installed!")
438
+ print_info("You can start DeepTutor with: python scripts/start_web.py")
439
+ else:
440
+ print_error("Some dependencies are missing!")
441
+ print_info("Run: python scripts/install_all.py")
442
+ print_info("Or manually install missing packages")
443
+
444
+ print("=" * 60 + "\n")
445
+
446
+ return 0 if all_checks_passed else 1
447
+
448
+
449
+ if __name__ == "__main__":
450
+ try:
451
+ sys.exit(main())
452
+ except KeyboardInterrupt:
453
+ print("\n\n⚠️ Check interrupted by user")
454
+ sys.exit(1)
455
+ except Exception as e:
456
+ print_error(f"\n❌ Unexpected error: {e}")
457
+ import traceback
458
+
459
+ traceback.print_exc()
460
+ sys.exit(1)