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()
def serve( host: str = <typer.models.OptionInfo object>, port: int = <typer.models.OptionInfo object>, reload: bool = <typer.models.OptionInfo object>, workers: Optional[int] = <typer.models.OptionInfo object>, log_level: str = <typer.models.OptionInfo object>):
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}

def create():
 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.

def info():
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.

cli_app = <typer.main.Typer object>