Coverage for src/semware/cli.py: 0%
75 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-09 02:15 -0700
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-09 02:15 -0700
1#!/usr/bin/env python3
2"""Command-line interface for SemWare."""
4import argparse
5import sys
6import uvicorn
7from pathlib import Path
9from .config import get_settings
10from .utils.logging import setup_logging
11from loguru import logger
14def create_parser() -> argparse.ArgumentParser:
15 """Create command-line argument parser."""
16 parser = argparse.ArgumentParser(
17 prog="semware",
18 description="SemWare - Semantic Search API Server",
19 formatter_class=argparse.RawDescriptionHelpFormatter,
20 epilog="""
21Examples:
22 semware Start server with default settings
23 semware --host 127.0.0.1 Start on localhost only
24 semware --port 8080 Start on port 8080
25 semware --workers 4 Start with 4 worker processes
26 semware --debug Start in debug mode
27 semware --reload Start with auto-reload (development)
29Environment variables:
30 API_KEY API key for authentication (required)
31 DEBUG Enable debug mode (true/false)
32 DB_PATH Database storage path
33 HOST Server host address
34 PORT Server port
35 LOG_LEVEL Logging level (DEBUG/INFO/WARNING/ERROR)
37For more information, visit: https://github.com/your-org/semware
38 """,
39 )
41 parser.add_argument(
42 "--host",
43 type=str,
44 default=None,
45 help="Host to bind the server to (default: from config/env)",
46 )
48 parser.add_argument(
49 "--port",
50 type=int,
51 default=None,
52 help="Port to bind the server to (default: from config/env)",
53 )
55 parser.add_argument(
56 "--workers",
57 type=int,
58 default=None,
59 help="Number of worker processes (default: from config/env)",
60 )
62 parser.add_argument(
63 "--debug",
64 action="store_true",
65 help="Enable debug mode with API documentation",
66 )
68 parser.add_argument(
69 "--reload",
70 action="store_true",
71 help="Enable auto-reload for development (implies --workers 1)",
72 )
74 parser.add_argument(
75 "--log-level",
76 choices=["DEBUG", "INFO", "WARNING", "ERROR"],
77 default=None,
78 help="Set logging level (default: from config/env)",
79 )
81 parser.add_argument(
82 "--version",
83 action="version",
84 version=f"SemWare 0.1.0",
85 )
87 return parser
90def validate_environment() -> bool:
91 """Validate that required environment is set up."""
92 try:
93 settings = get_settings()
95 # Check if API key is set (not the default)
96 if not settings.api_key or settings.api_key == "your-secret-api-key":
97 logger.error("❌ API_KEY not configured!")
98 logger.info("💡 Set your API key in .env file or environment variable:")
99 logger.info(" export API_KEY=your-secret-api-key")
100 logger.info(" Or create .env file from .env.example")
101 return False
103 # Check if database directory exists and is writable
104 db_path = Path(settings.db_path)
105 try:
106 db_path.mkdir(parents=True, exist_ok=True)
107 except PermissionError:
108 logger.error(f"❌ Cannot create database directory: {db_path}")
109 logger.info("💡 Check directory permissions or set DB_PATH to writable location")
110 return False
112 logger.info(f"✅ Database directory: {db_path.absolute()}")
113 return True
115 except Exception as e:
116 logger.error(f"❌ Configuration error: {e}")
117 return False
120def main() -> None:
121 """Main CLI entry point."""
122 parser = create_parser()
123 args = parser.parse_args()
125 # Load settings first
126 try:
127 settings = get_settings()
128 except Exception as e:
129 print(f"❌ Failed to load configuration: {e}", file=sys.stderr)
130 sys.exit(1)
132 # Override settings with CLI arguments
133 host = args.host or settings.host
134 port = args.port or settings.port
135 workers = args.workers or settings.workers
136 debug = args.debug or settings.debug
137 log_level = args.log_level or settings.log_level
139 # Setup logging
140 setup_logging(level=log_level)
142 # Show startup banner
143 print("🚀 SemWare - Semantic Search API Server")
144 print("=" * 50)
146 # Validate environment
147 if not validate_environment():
148 sys.exit(1)
150 # Show configuration
151 logger.info(f"📡 Starting server on http://{host}:{port}")
152 logger.info(f"🔧 Debug mode: {'ON' if debug else 'OFF'}")
153 logger.info(f"👥 Workers: {workers}")
154 logger.info(f"📝 Log level: {log_level}")
156 if debug:
157 logger.info("📚 API Documentation:")
158 logger.info(f" • Swagger UI: http://{host}:{port}/docs")
159 logger.info(f" • ReDoc: http://{host}:{port}/redoc")
161 # Handle reload mode
162 if args.reload:
163 if workers > 1:
164 logger.warning("⚠️ Auto-reload mode forces workers=1")
165 workers = 1
167 try:
168 # Start the server
169 uvicorn.run(
170 "semware.main:app",
171 host=host,
172 port=port,
173 workers=workers,
174 reload=args.reload,
175 log_level=log_level.lower(),
176 access_log=debug,
177 loop="auto",
178 )
179 except KeyboardInterrupt:
180 logger.info("👋 Server stopped by user")
181 except Exception as e:
182 logger.error(f"❌ Failed to start server: {e}")
183 sys.exit(1)
186if __name__ == "__main__":
187 main()