monoai.cli
MonoAI Command Line Interface
This module provides a command-line interface for MonoAI.
Available Commands: serve Start the API server with configurable options to serve the app defined in main.py.
Examples:
# Start server with default settings
monoai serve
# Start server on custom host and port
monoai serve --host 127.0.0.1 --port 8080
# Start server with auto-reload enabled
monoai serve --reload
# Start server with multiple workers
monoai serve --workers 4
1#!/usr/bin/env python3 2""" 3MonoAI Command Line Interface 4 5This module provides a command-line interface for MonoAI. 6 7Available Commands: 8 serve Start the API server with configurable options to serve the app defined in main.py. 9 10Examples: 11 12 # Start server with default settings 13 monoai serve 14 15 # Start server on custom host and port 16 monoai serve --host 127.0.0.1 --port 8080 17 18 # Start server with auto-reload enabled 19 monoai serve --reload 20 21 # Start server with multiple workers 22 monoai serve --workers 4 23 24""" 25import typer 26from typing import Optional 27import sys 28import os 29 30# Add project root directory to path 31_project_root = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) 32sys.path.insert(0, _project_root) 33 34_cli_app = typer.Typer( 35 help="MonoAI CLI - Command line interface for MonoAI API server", 36 no_args_is_help=True, 37 add_completion=False 38) 39 40@_cli_app.command() 41def serve( 42 host: str = typer.Option( 43 "0.0.0.0", 44 "--host", "-h", 45 help="Host address to bind the server to" 46 ), 47 port: int = typer.Option( 48 8000, 49 "--port", "-p", 50 help="Port number to bind the server to" 51 ), 52 reload: bool = typer.Option( 53 False, 54 "--reload", "-r", 55 help="Enable auto-reload when code changes are detected" 56 ), 57 workers: Optional[int] = typer.Option( 58 None, 59 "--workers", "-w", 60 help="Number of worker processes to use (None for single process)" 61 ), 62 log_level: str = typer.Option( 63 "info", 64 "--log-level", "-l", 65 help="Log level (debug, info, warning, error, critical)" 66 ), 67): 68 """ 69 Start the MonoAI API server. 70 71 This command starts the API server with all configured endpoints 72 for models, agents, authentication, and rate limiting. 73 74 The server will be available at http://{host}:{port} 75 76 """ 77 print(f"🚀 Starting MonoAI server on {host}:{port}") 78 print(f"📊 Log level: {log_level}") 79 if reload: 80 print("🔄 Auto-reload enabled") 81 if workers: 82 print(f"👥 Workers: {workers}") 83 else: 84 print("👤 Single process mode") 85 86 try: 87 from main import app as main_app 88 main_app.serve(host=host, port=port, reload=reload, workers=workers, log_level=log_level) 89 except ImportError as e: 90 print(f"❌ Error importing main app: {e}") 91 print("💡 Make sure main.py exists in the project root") 92 raise typer.Exit(1) 93 except Exception as e: 94 print(f"❌ Error starting server: {e}") 95 raise typer.Exit(1) 96 97 98@_cli_app.command() 99def create(): 100 """ 101 Create a new MonoAI project with configuration files. 102 103 This command creates the necessary files for a new MonoAI project: 104 - ai.yaml: Main configuration file 105 - providers.keys: API keys for AI providers 106 - observability.keys: API keys for observability platforms (optional) 107 - main.py: Basic application file 108 109 The command will prompt for configuration details interactively. 110 """ 111 print("🚀 Creating new MonoAI project...") 112 print("=" * 50) 113 114 # Check if files already exist 115 existing_files = [] 116 if os.path.exists("ai.yaml"): 117 existing_files.append("ai.yaml") 118 if os.path.exists("providers.keys"): 119 existing_files.append("providers.keys") 120 if os.path.exists("observability.keys"): 121 existing_files.append("observability.keys") 122 if os.path.exists("main.py"): 123 existing_files.append("main.py") 124 125 if existing_files: 126 print(f"⚠️ Warning: The following files already exist: {', '.join(existing_files)}") 127 overwrite = input("Do you want to overwrite them? (y/N): ").lower().strip() 128 if overwrite != 'y': 129 print("❌ Project creation cancelled.") 130 return 131 132 # Collect configuration 133 config = {} 134 135 print("\n📝 Configuration Setup") 136 print("-" * 30) 137 138 # Base model configuration 139 print("\n🤖 Base Model Configuration") 140 provider = input("AI Provider (openai, anthropic, google, etc.): ").strip() 141 if provider: 142 model_name = input(f"Model name (e.g., gpt-4o-mini for OpenAI): ").strip() 143 api_key = input(f"API Key for {provider} [required]: ").strip() 144 145 if api_key: 146 config['base_model'] = { 147 'provider': provider, 148 'model': model_name or 'gpt-4o-mini' 149 } 150 # Write API key to providers.keys 151 with open("providers.keys", "w") as f: 152 f.write(f"{provider.upper()}={api_key}\n") 153 print(f"✅ API key saved to providers.keys") 154 else: 155 print("⚠️ No API key provided, base_model will not be configured") 156 157 # Prompts path 158 prompts_path = input("\n📁 Prompts directory path, default: prompts]: ").strip() 159 if prompts_path: 160 config['prompts_path'] = prompts_path 161 else: 162 config['prompts_path'] = "prompts" 163 164 # Supported files 165 print("\n📄 Supported Files Configuration") 166 text_files = input("Text file extensions (comma-separated, e.g., txt,py,md): ").strip() 167 image_files = input("Image file extensions (comma-separated, e.g., png,jpg,jpeg): ").strip() 168 169 if text_files or image_files: 170 config['supported_files'] = {} 171 if text_files: 172 config['supported_files']['text'] = [ext.strip() for ext in text_files.split(',')] 173 if image_files: 174 config['supported_files']['image'] = [ext.strip() for ext in image_files.split(',')] 175 176 # Default prompts 177 print("\n💬 Default Prompts Configuration") 178 179 # Get default prompts from Conf class 180 from monoai.conf.conf import Conf 181 default_prompts = Conf._DEFAULT_CONFIG['default_prompt'] 182 183 rag_prompt = input(f"RAG prompt template (default: {default_prompts['rag']}): ").strip() 184 summary_prompt = input(f"Summary prompt template (default: {default_prompts['summary']}): ").strip() 185 file_prompt = input(f"File upload prompt template (default: {default_prompts['file']}): ").strip() 186 187 # Always include default_prompt section, using defaults if user didn't provide custom values 188 config['default_prompt'] = {} 189 config['default_prompt']['rag'] = rag_prompt if rag_prompt else default_prompts['rag'] 190 config['default_prompt']['summary'] = summary_prompt if summary_prompt else default_prompts['summary'] 191 config['default_prompt']['file'] = file_prompt if file_prompt else default_prompts['file'] 192 193 # Observability 194 print("\n📊 Observability Configuration") 195 obs_platforms = input("Observability platforms (comma-separated, e.g., logfire,langfuse): ").strip() 196 197 if obs_platforms: 198 platforms = [p.strip() for p in obs_platforms.split(',')] 199 config['observability'] = platforms 200 201 # Ask for API keys for observability platforms 202 obs_keys = {} 203 for platform in platforms: 204 if platform.lower() == 'langfuse': 205 # Langfuse requires both PUBLIC_KEY and SECRET_KEY 206 public_key = input(f"LANGFUSE_PUBLIC_KEY for {platform}: ").strip() 207 secret_key = input(f"LANGFUSE_SECRET_KEY for {platform}: ").strip() 208 209 if public_key or secret_key: 210 obs_keys['LANGFUSE_PUBLIC_KEY'] = public_key 211 obs_keys['LANGFUSE_SECRET_KEY'] = secret_key 212 else: 213 # Other platforms use single API key 214 key = input(f"API Key for {platform}: ").strip() 215 if key: 216 obs_keys[platform.upper()] = key 217 218 if obs_keys: 219 with open("observability.keys", "w") as f: 220 for key_name, key_value in obs_keys.items(): 221 f.write(f"{key_name}={key_value}\n") 222 print(f"✅ Observability keys saved to observability.keys") 223 224 # Create ai.yaml 225 import yaml 226 with open("ai.yaml", "w") as f: 227 yaml.dump(config, f, default_flow_style=False, sort_keys=False) 228 print("✅ ai.yaml created") 229 230 # Create providers.keys if it doesn't exist 231 if not os.path.exists("providers.keys"): 232 with open("providers.keys", "w") as f: 233 f.write("# Add your API keys here\n") 234 f.write("# Format: PROVIDER_NAME=your_api_key\n") 235 print("✅ providers.keys created (empty)") 236 237 # Create prompts directory and hello.prompt file 238 prompts_dir = config.get('prompts_path', 'prompts') 239 os.makedirs(prompts_dir, exist_ok=True) 240 241 hello_prompt_content = '''<prompt response_type="text"> 242Hello MonoAI! Please introduce yourself and tell me what you can do. 243</prompt>''' 244 245 hello_prompt_path = os.path.join(prompts_dir, "hello.prompt") 246 with open(hello_prompt_path, "w") as f: 247 f.write(hello_prompt_content) 248 print(f"✅ {hello_prompt_path} created") 249 250 main_py_content = '''from monoai.models import Model 251from monoai.prompts import Prompt 252# Initialize model 253''' 254 255 if provider == "": 256 main_py_content += '''# Remember to set your provider key in the providers.keys file 257provider = "" # set your provider (es. openai, anthropic, google, etc.) 258model = "" # set your model (es. gpt-4o-mini, claude-3, gemini-1.5-flash, etc.) 259model = Model(provider=provider, model=model) 260''' 261 else: 262 main_py_content += f'''model = Model(provider="{provider}", model="{model_name or 'gpt-4o-mini'}") 263''' 264 265 main_py_content += '''# Load and use the hello prompt 266prompt = Prompt(prompt_id="hello") 267response = model.ask(prompt) 268print(f"Response: {response['response']}") 269''' 270 271 with open("main.py", "w") as f: 272 f.write(main_py_content) 273 print("✅ main.py created") 274 275 print("\n🎉 Project created successfully!") 276 277 278@_cli_app.command() 279def info(): 280 """ 281 Show detailed information about the MonoAI installation. 282 283 Displays comprehensive information about the MonoAI installation, 284 including available models, agents, and configuration. 285 """ 286 print("📋 MonoAI Information") 287 print("=" * 50) 288 289 # Version info 290 try: 291 import monoai 292 print(f"Version: {getattr(monoai, '__version__', 'unknown')}") 293 except ImportError: 294 print("Version: unknown (not installed)") 295 296 # Python info 297 print(f"Python: {sys.version}") 298 print(f"Platform: {sys.platform}") 299 300 # Project info 301 print(f"Project root: {_project_root}") 302 print(f"CLI file: {__file__}") 303 304 # Check main.py 305 main_py_path = os.path.join(_project_root, "main.py") 306 if os.path.exists(main_py_path): 307 print(f"✅ main.py found: {main_py_path}") 308 else: 309 print(f"❌ main.py not found: {main_py_path}") 310 311 # Check for configuration files 312 config_files = ["requirements.txt", "pyproject.toml", "setup.py"] 313 print("\n📁 Configuration files:") 314 for config_file in config_files: 315 config_path = os.path.join(_project_root, config_file) 316 if os.path.exists(config_path): 317 print(f" ✅ {config_file}") 318 else: 319 print(f" ❌ {config_file}") 320 321 print("\n🔗 Available commands:") 322 print(" create - Create a new MonoAI project") 323 print(" serve - Start the API server") 324 print(" info - Show detailed information") 325 326# Export cli_app as alias for _cli_app for external imports 327cli_app = _cli_app 328 329if __name__ == "__main__": 330 _cli_app()
41@_cli_app.command() 42def serve( 43 host: str = typer.Option( 44 "0.0.0.0", 45 "--host", "-h", 46 help="Host address to bind the server to" 47 ), 48 port: int = typer.Option( 49 8000, 50 "--port", "-p", 51 help="Port number to bind the server to" 52 ), 53 reload: bool = typer.Option( 54 False, 55 "--reload", "-r", 56 help="Enable auto-reload when code changes are detected" 57 ), 58 workers: Optional[int] = typer.Option( 59 None, 60 "--workers", "-w", 61 help="Number of worker processes to use (None for single process)" 62 ), 63 log_level: str = typer.Option( 64 "info", 65 "--log-level", "-l", 66 help="Log level (debug, info, warning, error, critical)" 67 ), 68): 69 """ 70 Start the MonoAI API server. 71 72 This command starts the API server with all configured endpoints 73 for models, agents, authentication, and rate limiting. 74 75 The server will be available at http://{host}:{port} 76 77 """ 78 print(f"🚀 Starting MonoAI server on {host}:{port}") 79 print(f"📊 Log level: {log_level}") 80 if reload: 81 print("🔄 Auto-reload enabled") 82 if workers: 83 print(f"👥 Workers: {workers}") 84 else: 85 print("👤 Single process mode") 86 87 try: 88 from main import app as main_app 89 main_app.serve(host=host, port=port, reload=reload, workers=workers, log_level=log_level) 90 except ImportError as e: 91 print(f"❌ Error importing main app: {e}") 92 print("💡 Make sure main.py exists in the project root") 93 raise typer.Exit(1) 94 except Exception as e: 95 print(f"❌ Error starting server: {e}") 96 raise typer.Exit(1)
Start the MonoAI API server.
This command starts the API server with all configured endpoints for models, agents, authentication, and rate limiting.
The server will be available at http://{host}:{port}
99@_cli_app.command() 100def create(): 101 """ 102 Create a new MonoAI project with configuration files. 103 104 This command creates the necessary files for a new MonoAI project: 105 - ai.yaml: Main configuration file 106 - providers.keys: API keys for AI providers 107 - observability.keys: API keys for observability platforms (optional) 108 - main.py: Basic application file 109 110 The command will prompt for configuration details interactively. 111 """ 112 print("🚀 Creating new MonoAI project...") 113 print("=" * 50) 114 115 # Check if files already exist 116 existing_files = [] 117 if os.path.exists("ai.yaml"): 118 existing_files.append("ai.yaml") 119 if os.path.exists("providers.keys"): 120 existing_files.append("providers.keys") 121 if os.path.exists("observability.keys"): 122 existing_files.append("observability.keys") 123 if os.path.exists("main.py"): 124 existing_files.append("main.py") 125 126 if existing_files: 127 print(f"⚠️ Warning: The following files already exist: {', '.join(existing_files)}") 128 overwrite = input("Do you want to overwrite them? (y/N): ").lower().strip() 129 if overwrite != 'y': 130 print("❌ Project creation cancelled.") 131 return 132 133 # Collect configuration 134 config = {} 135 136 print("\n📝 Configuration Setup") 137 print("-" * 30) 138 139 # Base model configuration 140 print("\n🤖 Base Model Configuration") 141 provider = input("AI Provider (openai, anthropic, google, etc.): ").strip() 142 if provider: 143 model_name = input(f"Model name (e.g., gpt-4o-mini for OpenAI): ").strip() 144 api_key = input(f"API Key for {provider} [required]: ").strip() 145 146 if api_key: 147 config['base_model'] = { 148 'provider': provider, 149 'model': model_name or 'gpt-4o-mini' 150 } 151 # Write API key to providers.keys 152 with open("providers.keys", "w") as f: 153 f.write(f"{provider.upper()}={api_key}\n") 154 print(f"✅ API key saved to providers.keys") 155 else: 156 print("⚠️ No API key provided, base_model will not be configured") 157 158 # Prompts path 159 prompts_path = input("\n📁 Prompts directory path, default: prompts]: ").strip() 160 if prompts_path: 161 config['prompts_path'] = prompts_path 162 else: 163 config['prompts_path'] = "prompts" 164 165 # Supported files 166 print("\n📄 Supported Files Configuration") 167 text_files = input("Text file extensions (comma-separated, e.g., txt,py,md): ").strip() 168 image_files = input("Image file extensions (comma-separated, e.g., png,jpg,jpeg): ").strip() 169 170 if text_files or image_files: 171 config['supported_files'] = {} 172 if text_files: 173 config['supported_files']['text'] = [ext.strip() for ext in text_files.split(',')] 174 if image_files: 175 config['supported_files']['image'] = [ext.strip() for ext in image_files.split(',')] 176 177 # Default prompts 178 print("\n💬 Default Prompts Configuration") 179 180 # Get default prompts from Conf class 181 from monoai.conf.conf import Conf 182 default_prompts = Conf._DEFAULT_CONFIG['default_prompt'] 183 184 rag_prompt = input(f"RAG prompt template (default: {default_prompts['rag']}): ").strip() 185 summary_prompt = input(f"Summary prompt template (default: {default_prompts['summary']}): ").strip() 186 file_prompt = input(f"File upload prompt template (default: {default_prompts['file']}): ").strip() 187 188 # Always include default_prompt section, using defaults if user didn't provide custom values 189 config['default_prompt'] = {} 190 config['default_prompt']['rag'] = rag_prompt if rag_prompt else default_prompts['rag'] 191 config['default_prompt']['summary'] = summary_prompt if summary_prompt else default_prompts['summary'] 192 config['default_prompt']['file'] = file_prompt if file_prompt else default_prompts['file'] 193 194 # Observability 195 print("\n📊 Observability Configuration") 196 obs_platforms = input("Observability platforms (comma-separated, e.g., logfire,langfuse): ").strip() 197 198 if obs_platforms: 199 platforms = [p.strip() for p in obs_platforms.split(',')] 200 config['observability'] = platforms 201 202 # Ask for API keys for observability platforms 203 obs_keys = {} 204 for platform in platforms: 205 if platform.lower() == 'langfuse': 206 # Langfuse requires both PUBLIC_KEY and SECRET_KEY 207 public_key = input(f"LANGFUSE_PUBLIC_KEY for {platform}: ").strip() 208 secret_key = input(f"LANGFUSE_SECRET_KEY for {platform}: ").strip() 209 210 if public_key or secret_key: 211 obs_keys['LANGFUSE_PUBLIC_KEY'] = public_key 212 obs_keys['LANGFUSE_SECRET_KEY'] = secret_key 213 else: 214 # Other platforms use single API key 215 key = input(f"API Key for {platform}: ").strip() 216 if key: 217 obs_keys[platform.upper()] = key 218 219 if obs_keys: 220 with open("observability.keys", "w") as f: 221 for key_name, key_value in obs_keys.items(): 222 f.write(f"{key_name}={key_value}\n") 223 print(f"✅ Observability keys saved to observability.keys") 224 225 # Create ai.yaml 226 import yaml 227 with open("ai.yaml", "w") as f: 228 yaml.dump(config, f, default_flow_style=False, sort_keys=False) 229 print("✅ ai.yaml created") 230 231 # Create providers.keys if it doesn't exist 232 if not os.path.exists("providers.keys"): 233 with open("providers.keys", "w") as f: 234 f.write("# Add your API keys here\n") 235 f.write("# Format: PROVIDER_NAME=your_api_key\n") 236 print("✅ providers.keys created (empty)") 237 238 # Create prompts directory and hello.prompt file 239 prompts_dir = config.get('prompts_path', 'prompts') 240 os.makedirs(prompts_dir, exist_ok=True) 241 242 hello_prompt_content = '''<prompt response_type="text"> 243Hello MonoAI! Please introduce yourself and tell me what you can do. 244</prompt>''' 245 246 hello_prompt_path = os.path.join(prompts_dir, "hello.prompt") 247 with open(hello_prompt_path, "w") as f: 248 f.write(hello_prompt_content) 249 print(f"✅ {hello_prompt_path} created") 250 251 main_py_content = '''from monoai.models import Model 252from monoai.prompts import Prompt 253# Initialize model 254''' 255 256 if provider == "": 257 main_py_content += '''# Remember to set your provider key in the providers.keys file 258provider = "" # set your provider (es. openai, anthropic, google, etc.) 259model = "" # set your model (es. gpt-4o-mini, claude-3, gemini-1.5-flash, etc.) 260model = Model(provider=provider, model=model) 261''' 262 else: 263 main_py_content += f'''model = Model(provider="{provider}", model="{model_name or 'gpt-4o-mini'}") 264''' 265 266 main_py_content += '''# Load and use the hello prompt 267prompt = Prompt(prompt_id="hello") 268response = model.ask(prompt) 269print(f"Response: {response['response']}") 270''' 271 272 with open("main.py", "w") as f: 273 f.write(main_py_content) 274 print("✅ main.py created") 275 276 print("\n🎉 Project created successfully!")
Create a new MonoAI project with configuration files.
This command creates the necessary files for a new MonoAI project:
- ai.yaml: Main configuration file
- providers.keys: API keys for AI providers
- observability.keys: API keys for observability platforms (optional)
- main.py: Basic application file
The command will prompt for configuration details interactively.
279@_cli_app.command() 280def info(): 281 """ 282 Show detailed information about the MonoAI installation. 283 284 Displays comprehensive information about the MonoAI installation, 285 including available models, agents, and configuration. 286 """ 287 print("📋 MonoAI Information") 288 print("=" * 50) 289 290 # Version info 291 try: 292 import monoai 293 print(f"Version: {getattr(monoai, '__version__', 'unknown')}") 294 except ImportError: 295 print("Version: unknown (not installed)") 296 297 # Python info 298 print(f"Python: {sys.version}") 299 print(f"Platform: {sys.platform}") 300 301 # Project info 302 print(f"Project root: {_project_root}") 303 print(f"CLI file: {__file__}") 304 305 # Check main.py 306 main_py_path = os.path.join(_project_root, "main.py") 307 if os.path.exists(main_py_path): 308 print(f"✅ main.py found: {main_py_path}") 309 else: 310 print(f"❌ main.py not found: {main_py_path}") 311 312 # Check for configuration files 313 config_files = ["requirements.txt", "pyproject.toml", "setup.py"] 314 print("\n📁 Configuration files:") 315 for config_file in config_files: 316 config_path = os.path.join(_project_root, config_file) 317 if os.path.exists(config_path): 318 print(f" ✅ {config_file}") 319 else: 320 print(f" ❌ {config_file}") 321 322 print("\n🔗 Available commands:") 323 print(" create - Create a new MonoAI project") 324 print(" serve - Start the API server") 325 print(" info - Show detailed information")
Show detailed information about the MonoAI installation.
Displays comprehensive information about the MonoAI installation, including available models, agents, and configuration.