diff --git a/adhoc/adhoc.py b/adhoc/adhoc.py index 0e675ee..afc38fd 100644 --- a/adhoc/adhoc.py +++ b/adhoc/adhoc.py @@ -6,6 +6,7 @@ from .commands.commit import commit_command from .commands.generate import generate_command from .commands.config import config_command # New import +from .commands.startapi import run_server_command def main(): parser = argparse.ArgumentParser( @@ -40,6 +41,17 @@ def main(): parser_config.add_argument('-u', '--username', type=str, help='Set the author username') parser_config.set_defaults(func=config_command) + #? Start API command + parser_startapi = subparsers.add_parser('startapi', help='Start the FastAPI server') + + # Add arguments for host, reloads, worker and port + parser_startapi.add_argument('-p', '--port', type=int, default=8000, help='Port number to run the server on') + parser_startapi.add_argument('-H', '--host', type=str, default='0.0.0.0', help='Host address to bind to') + parser_startapi.add_argument('-r', '--reload', action='store_true', help='Enable auto-reload') + parser_startapi.add_argument('-w', '--workers', type=int, default=1, help='Number of worker processes') + + parser_startapi.set_defaults(func=run_server_command) + # Parse arguments args = parser.parse_args() diff --git a/adhoc/api/Endpoints.txt b/adhoc/api/Endpoints.txt new file mode 100644 index 0000000..bc9bc39 --- /dev/null +++ b/adhoc/api/Endpoints.txt @@ -0,0 +1,3 @@ +[ + .../'generate-documentation', {author_name: args[string], output_format: args[string]} +] \ No newline at end of file diff --git a/adhoc/api/api.py b/adhoc/api/api.py new file mode 100644 index 0000000..aa63d75 --- /dev/null +++ b/adhoc/api/api.py @@ -0,0 +1,116 @@ +from fastapi import FastAPI, HTTPException +from pydantic import BaseModel +from enum import Enum +from typing import Optional +from starlette import status + +# Import the original documentation generation function +from adhoc.db.database import get_explanations, get_codebase_summary +from adhoc.utils.latex_utils import render_latex_document +from adhoc.utils.markdown_utils import render_markdown_document +from adhoc.utils.word_utils import render_word_document +from adhoc.utils.config_utils import load_config + +# Initialize FastAPI app +app = FastAPI( + title="ADHOC Documentation Generator API", + description="API for generating documentation from codebase", + version=1.0) + +# Define allowed output formats +class OutputFormat(str, Enum): + LATEX = "latex" + MARKDOWN = "markdown" + WORD = "word" + +# Request model +class DocumentationRequest(BaseModel): + output_format: OutputFormat + author_name: Optional[str] = "Default Author" + +# Response model +class DocumentationResponse(BaseModel): + content: str + format: OutputFormat + message: str + +@app.post( + "/generate-documentation", + response_model=DocumentationResponse, + status_code=status.HTTP_201_CREATED +) +async def generate_documentation(request: DocumentationRequest): + try: + # Get the required data from database + explanations = get_explanations() + codebase_summary = get_codebase_summary() + + content = None # Initialize content variable + + # Generate the actual documentation based on format + if request.output_format == OutputFormat.LATEX: + content = render_latex_document( + explanations, + codebase_summary, + request.author_name + ) + elif request.output_format == OutputFormat.MARKDOWN: + content = render_markdown_document( + explanations, + codebase_summary, + request.author_name + ) + elif request.output_format == OutputFormat.WORD: + # For Word, we need to handle it differently since it creates a file + output_filename = "documentation.docx" + render_word_document( + explanations, + codebase_summary, + output_filename, + request.author_name + ) + # Read the generated Word file + with open(output_filename, 'rb') as f: + content = f.read() + import os + os.remove(output_filename) # Clean up the file + + if content is None: + raise ValueError("No content was generated") + + return DocumentationResponse( + content=content, + format=request.output_format, + message=f"Documentation generated successfully in {request.output_format} format" + ) + + except ValueError as e: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=str(e) + ) + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"Failed to generate documentation: {str(e)}" + ) + +# Health check endpoint +@app.get( + "/health", + status_code=status.HTTP_200_OK, + responses={ + 200: { + "description": "API is healthy", + "content": { + "application/json": { + "example": { + "status": "healthy" + } + } + } + } + } +) +async def health_check(): + return {"status": "healthy"} \ No newline at end of file diff --git a/adhoc/commands/generate.py b/adhoc/commands/generate.py index 5d0af54..3ddd08b 100644 --- a/adhoc/commands/generate.py +++ b/adhoc/commands/generate.py @@ -5,12 +5,14 @@ from ..utils.config_utils import load_config # Import the config loader from ..db.database import get_codebase_summary + def generate_command(args): config = load_config() OUTPUT_FORMAT = config.get('OUTPUT_FORMAT', 'latex') AUTHOR_NAME = config.get('AUTHOR_NAME', 'Default Author') explanations = get_explanations() codebase_summary = get_codebase_summary() + FOLDER_PATH = "output/" # Pass AUTHOR_NAME to rendering functions if needed @@ -18,18 +20,20 @@ def generate_command(args): if OUTPUT_FORMAT == 'latex': latex_content = render_latex_document(explanations, codebase_summary, AUTHOR_NAME) output_filename = 'documentation.tex' - with open(output_filename, 'w') as f: + file_path = FOLDER_PATH + output_filename + with open(file_path, 'w') as f: f.write(latex_content) - print(f"LaTeX documentation generated: {output_filename}") + print(f"LaTeX documentation generated: {file_path}") elif OUTPUT_FORMAT == 'markdown': markdown_content = render_markdown_document(explanations, codebase_summary, AUTHOR_NAME) output_filename = 'documentation.md' - with open(output_filename, 'w') as f: + file_path = FOLDER_PATH + output_filename + with open(file_path, 'w') as f: f.write(markdown_content) print(f"Markdown documentation generated: {output_filename}") elif OUTPUT_FORMAT == 'word': output_filename = "documentation.docx" - render_word_document(explanations, codebase_summary,output_filename, AUTHOR_NAME) + render_word_document(explanations, codebase_summary, file_path, AUTHOR_NAME) print(f"Word documentation generated: {output_filename}") else: diff --git a/adhoc/commands/startapi.py b/adhoc/commands/startapi.py new file mode 100644 index 0000000..077e6d0 --- /dev/null +++ b/adhoc/commands/startapi.py @@ -0,0 +1,98 @@ +import os +import argparse +import subprocess +import sys +from typing import Optional +import uvicorn +from pathlib import Path + +def find_fastapi_app() -> Optional[str]: + """ + Finds the api.py FastAPI application file in the current directory. + Looks for common patterns like main.py, app.py, or api.py. + + Returns: + str: The module path to the FastAPI app, or None if not found + """ + common_names = ['main.py', 'app.py', 'api.py'] + + # First, look in current directory + for name in common_names: + if os.path.exists(name): + module_name = name.replace('.py', '') + return f"{module_name}:app" + + # Then look in app directory + if os.path.exists('app'): + for name in common_names: + if os.path.exists(os.path.join('app', name)): + module_name = name.replace('.py', '') + return f"app.{module_name}:app" + + return None + +def run_server_command(args): + API_PATH = './adhoc/api/api.py' + """ + Command handler for running the FastAPI server + + Args: + args: Parsed command line arguments containing: + - port: Port number to run the server on + - host: Host address to bind to + - reload: Whether to enable auto-reload + - workers: Number of worker processes + """ + + # If no app specified, try to find it + app_path = API_PATH + if not app_path: + app_path = find_fastapi_app() + if not app_path: + print("Error: Could not find FastAPI application. Please specify with --app") + return 1 + + try: + # Check if we're in a virtual environment + in_venv = sys.prefix != sys.base_prefix + if in_venv: + print("Warning: Running in a virtual environment.") + print("Consider running without a virtual environment for better performance.") + + # Check if required packages are installed + try: + import fastapi + import uvicorn + except ImportError: + print("Error: Required packages not found. Please install fastapi and uvicorn:") + print("pip install fastapi uvicorn") + return 1 + + # Print startup message + print(f"\nStarting FastAPI server:") + print(f"→ Application: {app_path}") + print(f"→ Host: {args.host}") + print(f"→ Port: {args.port}") + print(f"→ Reload: {'enabled' if args.reload else 'disabled'}") + print(f"→ Workers: {args.workers}") + print("\nAPI documentation will be available at:") + print(f"→ Swagger UI: http://{args.host}:{args.port}/docs") + print(f"→ ReDoc: http://{args.host}:{args.port}/redoc") + print("\n Api will be available at: http://{args.host}:{args.post}/ \n ") + print("\nPress Ctrl+C to stop the server\n") + + # Run the server + uvicorn.run( + app_path, + host=args.host, + port=args.port, + reload=args.reload, + workers=args.workers, + log_level="info" + ) + + except Exception as e: + print(f"Error running server: {str(e)}") + return 1 + + return 0 diff --git a/adhoc_python.egg-info/requires.txt b/adhoc_python.egg-info/requires.txt index 9b55dd9..3ef0c2d 100644 --- a/adhoc_python.egg-info/requires.txt +++ b/adhoc_python.egg-info/requires.txt @@ -3,3 +3,4 @@ requests>=2.32.3 watchdog>=5.0.3 python-docx>=1.1.2 ollama +fastapi[standard] \ No newline at end of file diff --git a/documentation.tex b/documentation.tex new file mode 100644 index 0000000..a5d3f38 --- /dev/null +++ b/documentation.tex @@ -0,0 +1,56 @@ +\documentclass{article} +\usepackage{hyperref} % For hyperlinks +\usepackage{listings} % For code listings +\usepackage{upquote} % For correct display of quotes in verbatim +\usepackage{geometry} % For better page layout +\usepackage{fancyhdr} % For headers and footers +\usepackage{titlesec} % For customizing section titles +\usepackage{color} % For colored text +\usepackage{xcolor} % Extended colors +\usepackage{graphicx} % For including images +\usepackage{longtable}% For tables that span multiple pages +\usepackage{tocloft} % For table of contents customization +\usepackage{setspace} % For line spacing + +% Page layout settings +\geometry{ + a4paper, + left=25mm, + right=25mm, + top=25mm, + bottom=25mm, +} + +% Header and footer settings +\pagestyle{fancy} +\fancyhf{} +\lhead{\textbf{Zhreyas}} +\rhead{\textbf{\today}} +\cfoot{\thepage} + +% Section title formatting +\titleformat{\section}{ + \normalfont\Large\bfseries +}{\thesection}{1em}{} + +% Set line spacing +\setstretch{1.2} + +\title{\textbf{Documentation for Codebase Changes}} +\author{Generated by Adhoc \\ Author: Default Author} +\date{\today} + +\begin{document} + +\maketitle + +\section*{Codebase Summary} +No codebase summary available. + +\newpage + +\section*{Change Explanations} + + + +\end{document} \ No newline at end of file diff --git a/include b/include deleted file mode 100644 index e69de29..0000000 diff --git a/requirements.txt b/requirements.txt index 479a588..17caa25 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ requests==2.32.3 watchdog==5.0.3 python-docx==1.1.2 ollama +fastapi[standard] \ No newline at end of file diff --git a/setup.py b/setup.py index fb6509a..1e47513 100644 --- a/setup.py +++ b/setup.py @@ -19,6 +19,7 @@ 'watchdog>=5.0.3', # Updated to a compatible version 'python-docx>=1.1.2', 'ollama' + 'fastapi[standard]', # For API # Removed 'argparse' as it's part of the standard library for Python >=3.2 ], author='Shreyas S',