Piyush1225's picture
push
5df8a73
#!/usr/bin/env python
"""
System Setup and Initialization
Combines user directory initialization and port configuration management.
"""
import json
from pathlib import Path
import yaml
from deeptutor.logging import get_logger
from deeptutor.services.config import get_env_store
from deeptutor.services.path_service import get_path_service
# Initialize logger for setup operations
_setup_logger = None
DEFAULT_INTERFACE_SETTINGS = {
"theme": "light",
"language": "en",
"sidebar_description": "✨ Data Intelligence Lab @ HKU",
"sidebar_nav_order": {
"start": ["/", "/history", "/knowledge", "/notebook"],
"learnResearch": ["/question", "/solver", "/guide", "/research", "/co_writer"],
},
}
DEFAULT_MAIN_SETTINGS = {
"system": {
"language": "en",
},
"logging": {
"level": "WARNING",
"save_to_file": True,
"console_output": True,
},
"personalization": {
"auto_update": True,
"max_react_rounds": 6,
"agents": {
"reflection": True,
"summary": True,
"weakness": True,
},
},
"tools": {
"run_code": {
"allowed_roots": ["./data/user"],
},
"web_search": {
"enabled": True,
},
},
"capabilities": {
"question": {
"rag_query_count": 3,
"max_parallel_questions": 1,
"idea_loop": {"max_rounds": 3, "ideas_per_round": 5},
"generation": {"max_retries": 2},
},
"solve": {
"max_react_iterations": 10,
"max_plan_steps": 10,
"max_replans": 2,
"observation_max_tokens": 2000,
"enable_citations": True,
"save_intermediate_results": True,
"detailed_answer": True,
},
"research": {
"researching": {
"note_agent_mode": "auto",
"tool_timeout": 60,
"tool_max_retries": 2,
"paper_search_years_limit": 3,
},
"rag": {},
},
},
}
DEFAULT_AGENTS_SETTINGS = {
"capabilities": {
"solve": {"temperature": 0.3, "max_tokens": 8192},
"research": {"temperature": 0.5, "max_tokens": 12000},
"question": {"temperature": 0.7, "max_tokens": 4096},
"guide": {"temperature": 0.5, "max_tokens": 16192},
"co_writer": {"temperature": 0.7, "max_tokens": 4096},
},
"tools": {
"brainstorm": {"temperature": 0.8, "max_tokens": 2048},
},
"services": {
"personalization": {"temperature": 0.5, "max_tokens": 8192},
},
"plugins": {
"vision_solver": {"temperature": 0.3, "max_tokens": 12000},
"math_animator": {"temperature": 0.4, "max_tokens": 12000},
},
}
def _get_setup_logger():
"""Get logger for setup operations"""
global _setup_logger
if _setup_logger is None:
_setup_logger = get_logger("Setup")
return _setup_logger
# ============================================================================
# User Directory Initialization
# ============================================================================
def init_user_directories(project_root: Path | None = None) -> None:
"""
Initialize essential user data files if they don't exist.
This function uses lazy initialization - directories are created on-demand
when files are saved, rather than pre-creating all directories at startup.
Only essential configuration files (like settings/interface.json) are
created at startup if they don't exist.
Directory structure (created on-demand by each module):
data/user/
β”œβ”€β”€ chat_history.db
β”œβ”€β”€ logs/
β”œβ”€β”€ settings/
β”‚ β”œβ”€β”€ interface.json
β”‚ β”œβ”€β”€ main.yaml
β”‚ └── agents.yaml
└── workspace/
β”œβ”€β”€ notebook/
β”œβ”€β”€ memory/
β”œβ”€β”€ co-writer/
β”œβ”€β”€ guide/
└── chat/
β”œβ”€β”€ chat/
β”œβ”€β”€ deep_solve/
β”œβ”€β”€ deep_question/
β”œβ”€β”€ deep_research/
β”œβ”€β”€ math_animator/
└── _detached_code_execution/
Args:
project_root: Project root directory (ignored, kept for API compatibility)
"""
# Use PathService for all paths
path_service = get_path_service()
path_service.ensure_all_directories()
# Only initialize essential configuration files
# Directories will be created on-demand when files are saved
_ensure_essential_settings(path_service)
def _ensure_essential_settings(path_service) -> None:
"""
Ensure essential settings files exist.
This is the minimal initialization needed at startup.
All other directories are created on-demand when files are saved.
"""
interface_file = path_service.get_settings_file("interface")
_write_json_if_missing(interface_file, DEFAULT_INTERFACE_SETTINGS)
main_file = path_service.get_runtime_config_file("main")
_write_yaml_if_missing(main_file, DEFAULT_MAIN_SETTINGS)
agents_file = path_service.get_runtime_config_file("agents")
_write_yaml_if_missing(agents_file, DEFAULT_AGENTS_SETTINGS)
def _write_json_if_missing(file_path: Path, payload: dict) -> None:
"""Write JSON defaults once; never overwrite user-managed files."""
if file_path.exists():
return
try:
file_path.parent.mkdir(parents=True, exist_ok=True)
with open(file_path, "w", encoding="utf-8") as f:
json.dump(payload, f, indent=2, ensure_ascii=False)
_get_setup_logger().info(f"Created default settings: {file_path}")
except Exception as e:
_get_setup_logger().warning(f"Failed to create default JSON file {file_path}: {e}")
def _write_yaml_if_missing(file_path: Path, payload: dict) -> None:
"""Write YAML defaults once; never overwrite user-managed files."""
if file_path.exists():
return
try:
file_path.parent.mkdir(parents=True, exist_ok=True)
with open(file_path, "w", encoding="utf-8") as f:
yaml.safe_dump(payload, f, sort_keys=False, allow_unicode=True)
_get_setup_logger().info(f"Created default settings: {file_path}")
except Exception as e:
_get_setup_logger().warning(f"Failed to create default YAML file {file_path}: {e}")
# ============================================================================
# Port Configuration Management
# ============================================================================
# Ports are configured via environment variables in .env file:
# BACKEND_PORT=8001 (default: 8001)
# FRONTEND_PORT=3782 (default: 3782)
# ============================================================================
def get_backend_port(project_root: Path | None = None) -> int:
"""
Get backend port from environment variable.
Configure in .env file: BACKEND_PORT=8001
Returns:
Backend port number (default: 8001)
"""
env_port = get_env_store().get("BACKEND_PORT", "8001")
try:
return int(env_port)
except ValueError:
logger = _get_setup_logger()
logger.warning(f"Invalid BACKEND_PORT: {env_port}, using default 8001")
return 8001
def get_frontend_port(project_root: Path | None = None) -> int:
"""
Get frontend port from environment variable.
Configure in .env file: FRONTEND_PORT=3782
Returns:
Frontend port number (default: 3782)
"""
env_port = get_env_store().get("FRONTEND_PORT", "3782")
try:
return int(env_port)
except ValueError:
logger = _get_setup_logger()
logger.warning(f"Invalid FRONTEND_PORT: {env_port}, using default 3782")
return 3782
def get_ports(project_root: Path | None = None) -> tuple[int, int]:
"""
Get both backend and frontend ports from configuration.
Args:
project_root: Project root directory (if None, will try to detect)
Returns:
Tuple of (backend_port, frontend_port)
Raises:
SystemExit: If ports are not configured
"""
backend_port = get_backend_port(project_root)
frontend_port = get_frontend_port(project_root)
return (backend_port, frontend_port)
__all__ = [
# User directory initialization
"init_user_directories",
# Port configuration (from .env)
"get_backend_port",
"get_frontend_port",
"get_ports",
]