From 349eed72fa9dffc75fef6aaa0b7194416fe5a071 Mon Sep 17 00:00:00 2001 From: vikramxD Date: Mon, 23 Dec 2024 14:20:00 +0000 Subject: [PATCH] Enhance LTX and Mochi video generation APIs with detailed documentation and combined routing - Updated ltx_serve.py and serve.py to improve API structure and documentation. - Added comprehensive docstrings for key classes and methods, enhancing clarity on functionality and usage. - Implemented a combined API router to handle requests for both LTX and Mochi models, allowing clients to specify the model via a single endpoint. - Improved Prometheus metrics logging for better performance monitoring. - Updated logging configuration to support combined API metrics. These changes aim to streamline the API usage, improve maintainability, and enhance user understanding of the video generation services. --- api/__pycache__/ltx_serve.cpython-310.pyc | Bin 0 -> 12725 bytes api/__pycache__/mochi_serve.cpython-310.pyc | Bin 0 -> 8242 bytes api/logs/combined_api.log | 1 + api/ltx_serve.py | 119 ++++++++- api/serve.py | 227 ++++++++---------- .../__pycache__/aws_settings.cpython-310.pyc | Bin 566 -> 555 bytes .../__pycache__/ltx_settings.cpython-310.pyc | Bin 0 -> 10959 bytes .../mochi_settings.cpython-310.pyc | Bin 3345 -> 3212 bytes .../__pycache__/ltx_inference.cpython-310.pyc | Bin 0 -> 10705 bytes .../mochi_diffusers.cpython-310.pyc | Bin 5638 -> 8181 bytes .../mp4_to_s3_json.cpython-310.pyc | Bin 974 -> 963 bytes .../__pycache__/s3_manager.cpython-310.pyc | Bin 2608 -> 2597 bytes 12 files changed, 213 insertions(+), 134 deletions(-) create mode 100644 api/__pycache__/ltx_serve.cpython-310.pyc create mode 100644 api/__pycache__/mochi_serve.cpython-310.pyc create mode 100644 api/logs/combined_api.log create mode 100644 configs/__pycache__/ltx_settings.cpython-310.pyc create mode 100644 scripts/__pycache__/ltx_inference.cpython-310.pyc diff --git a/api/__pycache__/ltx_serve.cpython-310.pyc b/api/__pycache__/ltx_serve.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9550f81861977dab352c755a187148bab03a9008 GIT binary patch literal 12725 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 Z|FvNg$2j=Se^Z*EyCF#@E@A!q{{ttkno9rx literal 0 HcmV?d00001 diff --git a/api/logs/combined_api.log b/api/logs/combined_api.log new file mode 100644 index 0000000..a1b0a5a --- /dev/null +++ b/api/logs/combined_api.log @@ -0,0 +1 @@ +2024-12-23 14:03:00.055 | INFO | __main__:main:220 - Starting Combined Video Generation Server diff --git a/api/ltx_serve.py b/api/ltx_serve.py index fb320f8..ace769c 100644 --- a/api/ltx_serve.py +++ b/api/ltx_serve.py @@ -1,5 +1,13 @@ """ LitServe API implementation for LTX video generation service. + +This module provides a FastAPI-based service for generating videos using the LTX model. +It handles request validation, video generation, S3 upload, and monitoring through Prometheus. + +Key Components: + - PrometheusLogger: Custom metrics logging + - VideoGenerationRequest: Request validation model + - LTXVideoAPI: Main API implementation """ import os @@ -33,7 +41,14 @@ multiprocess.MultiProcessCollector(registry) class PrometheusLogger(Logger): - """Custom logger for Prometheus metrics.""" + """Custom logger for Prometheus metrics. + + Implements metric collection for video generation request processing times + using Prometheus Histograms. Metrics are stored in a multi-process compatible registry. + + Attributes: + function_duration (Histogram): Prometheus histogram for tracking processing times + """ def __init__(self): super().__init__() @@ -45,11 +60,31 @@ def __init__(self): ) def process(self, key: str, value: float) -> None: - """Process and record metric.""" + """Process and record a metric value. + + Args: + key (str): The name of the function or operation being measured + value (float): The duration or metric value to record + """ self.function_duration.labels(function_name=key).observe(value) class VideoGenerationRequest(BaseModel): - """Model representing a video generation request.""" + """Model representing a video generation request. + + Validates and normalizes input parameters for video generation. + Provides default values and constraints for all generation parameters. + + Attributes: + prompt (str): Main text description for video generation + negative_prompt (Optional[str]): Text description of elements to avoid + num_inference_steps (int): Number of denoising steps (1-100) + guidance_scale (float): Controls adherence to prompt (1.0-20.0) + height (int): Video height in pixels (256-720, multiple of 32) + width (int): Video width in pixels (256-1280, multiple of 32) + num_frames (int): Number of frames to generate (1-257) + frame_rate (int): Output video frame rate (1-60) + seed (Optional[int]): Random seed for reproducibility + """ prompt: str = Field(..., description="Text description of the video to generate") negative_prompt: Optional[str] = Field( @@ -97,10 +132,27 @@ class VideoGenerationRequest(BaseModel): seed: Optional[int] = Field(None, description="Random seed for generation") class LTXVideoAPI(LitAPI): - """API for LTX video generation using LitServer.""" + """API for LTX video generation using LitServer. + + Implements the core video generation workflow including model initialization, + request processing, video generation, and result handling. + + Attributes: + settings (LTXVideoSettings): Configuration for video generation + engine (LTXInference): Video generation inference engine + """ def setup(self, device: str) -> None: - """Initialize the LTX video generation model.""" + """Initialize the LTX video generation model. + + Sets up the video generation engine and loads models onto the specified device. + + Args: + device (str): Target device for model execution ('cuda', 'cpu', etc.) + + Raises: + Exception: If model initialization fails + """ try: logger.info(f"Initializing LTX video generation on device: {device}") @@ -120,7 +172,19 @@ def decode_request( self, request: Union[Dict[str, Any], List[Dict[str, Any]]] ) -> List[Dict[str, Any]]: - """Decode and validate the incoming request.""" + """Decode and validate the incoming request. + + Converts raw request data into validated VideoGenerationRequest objects. + + Args: + request: Single request dict or list of request dicts + + Returns: + List of validated request dictionaries + + Raises: + ValidationError: If request validation fails + """ try: # Ensure request is a list if not isinstance(request, list): @@ -141,7 +205,19 @@ def batch( self, inputs: Union[Dict[str, Any], List[Dict[str, Any]]] ) -> Dict[str, List[Any]]: - """Prepare inputs for batch processing.""" + """Prepare inputs for batch processing. + + Organizes single or multiple requests into a batched format for processing. + + Args: + inputs: Single input dict or list of input dicts + + Returns: + Dictionary with lists of batched parameters + + Raises: + Exception: If batch preparation fails + """ try: # Convert single input to list if not isinstance(inputs, list): @@ -176,7 +252,23 @@ def batch( raise def predict(self, inputs: List[Dict[str, Any]]) -> List[Dict[str, Any]]: - """Process inputs and generate videos.""" + """Process inputs and generate videos. + + Core video generation method that handles the complete pipeline: + - Parameter validation + - Video generation + - S3 upload + - Performance monitoring + + Args: + inputs: List of validated generation requests + + Returns: + List of generation results including video URLs and metadata + + Raises: + Exception: If video generation or upload fails + """ results = [] try: @@ -317,7 +409,16 @@ def encode_response( } def main(): - """Main entry point for the API server.""" + """Main entry point for the API server. + + Initializes and starts the Litser server with: + - Prometheus metrics endpoint + - Configured logging + - LTX video generation API + - Server settings for batching and acceleration + + Exits with status code 1 if server initialization fails. + """ # Initialize Prometheus logger prometheus_logger = PrometheusLogger() prometheus_logger.mount( diff --git a/api/serve.py b/api/serve.py index cf6fb61..9239144 100644 --- a/api/serve.py +++ b/api/serve.py @@ -1,180 +1,158 @@ """ -Combined API router for multiple LitServe-based models. +Combined API router for LTX and Mochi video generation services. -This script imports multiple model-specific LitAPI classes (e.g., LTXVideoAPI -and MochiVideoAPI) and integrates them into a single endpoint. Clients specify -which model to invoke by providing a `model_name` field in the request body. - -Features: -- Single endpoint routing for multiple models -- Prometheus metrics for request duration tracking -- Comprehensive logging (stdout and file) with loguru -- Detailed docstrings and structured JSON responses -- Extensible: Just add new model APIs and register them in `model_apis`. +This module provides a unified endpoint that can handle requests for both +LTX and Mochi video generation models. Clients specify which model to use +via the 'model_name' parameter in their requests. Usage: -1. Ensure `ltx_serve.py` and `mochi_serve.py` are in the same directory. -2. Run `python combined_serve.py`. -3. Send POST requests to `http://localhost:8000/predict` with JSON like: - { - "model_name": "ltx", - "prompt": "Generate a video about a sunny day at the beach" - } - - or - - { - "model_name": "mochi", - "prompt": "Generate a video about a futuristic city" - } + POST /predict + { + "model_name": "ltx", # or "mochi" + "prompt": "your video prompt here", + ...other model-specific parameters... + } """ import sys import os -import time from typing import Dict, Any, List, Union from pydantic import BaseModel, Field from loguru import logger - import torch import litserve as ls -from prometheus_client import ( - CollectorRegistry, - Histogram, - make_asgi_app, - multiprocess -) - -# Import the individual model APIs +from prometheus_client import CollectorRegistry, Histogram, make_asgi_app, multiprocess from ltx_serve import LTXVideoAPI from mochi_serve import MochiVideoAPI # Setup Prometheus multiprocess mode -os.environ["PROMETHEUS_MULTIPROC_DIR"] = "/tmp/prometheus_multiproc_dir" -if not os.path.exists("/tmp/prometheus_multiproc_dir"): - os.makedirs("/tmp/prometheus_multiproc_dir") +os.environ["PROMETHEUS_MULTIPROC_DIR"] = "/tmp/prometheus_multiproc" +if not os.path.exists("/tmp/prometheus_multiproc"): + os.makedirs("/tmp/prometheus_multiproc") registry = CollectorRegistry() multiprocess.MultiProcessCollector(registry) class PrometheusLogger(ls.Logger): - """Custom logger for Prometheus metrics.""" + """Custom logger for tracking combined API metrics.""" + def __init__(self): super().__init__() self.function_duration = Histogram( - "combined_request_processing_seconds", - "Time spent processing combined API request", - ["function_name"], + "combined_request_duration_seconds", + "Time spent processing video generation requests", + ["model_name", "function_name"], registry=registry ) def process(self, key: str, value: float) -> None: - """Record metric observations for function durations.""" - self.function_duration.labels(function_name=key).observe(value) + """Record metric observations.""" + model_name, func_name = key.split(":", 1) if ":" in key else ("unknown", key) + self.function_duration.labels( + model_name=model_name, + function_name=func_name + ).observe(value) class CombinedRequest(BaseModel): - """ - Pydantic model for incoming requests to the combined endpoint. - The `model_name` field is used to select which model to route to. - Other fields depend on the target model, so they are optional here. - """ - model_name: str = Field(..., description="Name of the model to use (e.g., 'ltx' or 'mochi').") - # Any additional fields will be passed through to the selected model's decode_request. - # We keep this flexible by using an extra allowed attributes pattern. - # For more strict validation, define fields matching each model's requirements. + """Request model for the combined API endpoint.""" + + model_name: str = Field( + ..., + description="Model to use for video generation ('ltx' or 'mochi')" + ) + class Config: - extra = "allow" + extra = "allow" # Allow additional fields for model-specific parameters -class CombinedAPI(ls.LitAPI): - """ - A combined API class that delegates requests to multiple model-specific APIs - based on the `model_name` field in the request. +class CombinedVideoAPI(ls.LitAPI): + """Combined API for serving both LTX and Mochi video generation models.""" - This approach allows adding new models by: - 1. Importing their API class. - 2. Initializing and registering them in `model_apis` dictionary. - """ def setup(self, device: str) -> None: - """Setup all sub-model APIs and logging/metrics.""" - - logger.info(f"Initializing combined API with device={device}") + """Initialize both video generation models. + + Args: + device: Target device for model execution + """ + logger.info(f"Setting up combined video API on device: {device}") - # Initialize sub-model APIs + # Initialize both APIs self.ltx_api = LTXVideoAPI() self.mochi_api = MochiVideoAPI() - - # Setup each sub-model on the provided device + + # Setup each model self.ltx_api.setup(device=device) self.mochi_api.setup(device=device) - - # Register them in a dictionary for easy routing + + # Register models for routing self.model_apis = { "ltx": self.ltx_api, "mochi": self.mochi_api } - - logger.info("Combined API setup completed successfully.") + + logger.info("Successfully initialized all models") def decode_request( self, request: Union[Dict[str, Any], List[Dict[str, Any]]] ) -> Dict[str, Any]: - """ - Decode the incoming request to determine which model to use. - We expect `model_name` to route the request accordingly. - The rest of the fields will be passed to the chosen model's decode_request. + """Validate request and determine target model. + + Args: + request: Raw request data + + Returns: + Decoded request with model selection + + Raises: + ValueError: If model_name is invalid """ if isinstance(request, list): - # We handle only single requests for simplicity - request = request[0] - + request = request[0] # Handle single requests for now + validated = CombinedRequest(**request).dict() model_name = validated.pop("model_name").lower() - + if model_name not in self.model_apis: - raise ValueError(f"Unknown model_name '{model_name}'. Available: {list(self.model_apis.keys())}") - - # We'll store the selected model_name and request data + raise ValueError( + f"Invalid model_name: {model_name}. " + f"Available models: {list(self.model_apis.keys())}" + ) + return { "model_name": model_name, "request_data": validated } def predict(self, inputs: Dict[str, Any]) -> Dict[str, Any]: - """ - Perform prediction by routing to the chosen model API. - - Steps: - 1. Extract model_name and request_data. - 2. Pass request_data to the chosen model's decode_request -> predict pipeline. - 3. Return the predictions from the model. + """Route request to appropriate model and generate video. + + Args: + inputs: Decoded request data + + Returns: + Generation results from selected model """ model_name = inputs["model_name"] request_data = inputs["request_data"] model_api = self.model_apis[model_name] - - start_time = time.time() - + try: - # The sub-model APIs typically handle lists of requests. - # We'll wrap request_data in a list if needed. + # Process request through selected model decoded = model_api.decode_request(request_data) - # decoded is typically a list of requests for that model predictions = model_api.predict(decoded) - # predictions is typically a list of results - result = predictions[0] if predictions else {"status": "error", "error": "No result returned"} - - end_time = time.time() - self.log("combined_inference_time", end_time - start_time) - + result = predictions[0] if predictions else { + "status": "error", + "error": "No result returned" + } + return { "model_name": model_name, "result": result } - + except Exception as e: import traceback - logger.error(f"Error in combined predict: {e}\n{traceback.format_exc()}") + logger.error(f"Error in {model_name} prediction: {str(e)}") return { "model_name": model_name, "status": "error", @@ -186,41 +164,41 @@ def predict(self, inputs: Dict[str, Any]) -> Dict[str, Any]: torch.cuda.empty_cache() def encode_response(self, output: Dict[str, Any]) -> Dict[str, Any]: - """ - Encode the final response. We call the chosen model's encode_response if the result - is from a model inference. If there's an error at the combined level, we return a generic error response. + """Encode final response using model-specific encoder. + + Args: + output: Raw model output + + Returns: + Encoded response ready for client """ model_name = output.get("model_name") if model_name and model_name in self.model_apis: - # If there's a result from the model, encode it using the model's encoder result = output.get("result", {}) + if result.get("status") == "error": - # Model-specific error case return { "status": "error", "error": result.get("error", "Unknown error"), - "traceback": result.get("traceback", None) + "traceback": result.get("traceback") } - # Successful result + encoded = self.model_apis[model_name].encode_response(result) - # Add the model name to the final response for clarity encoded["model_name"] = model_name return encoded else: - # If we got here, there's a top-level routing error return { "status": "error", - "error": output.get("error", "Unknown top-level error"), - "traceback": output.get("traceback", None) + "error": output.get("error", "Unknown routing error"), + "traceback": output.get("traceback") } - def main(): - """Main entry point to run the combined server.""" - # Set up Prometheus logger + """Initialize and start the combined video generation server.""" + # Setup Prometheus metrics prometheus_logger = PrometheusLogger() prometheus_logger.mount( - path="/api/v1/metrics", + path="/metrics", app=make_asgi_app(registry=registry) ) @@ -238,18 +216,17 @@ def main(): level="DEBUG" ) - logger.info("Starting Combined Video Generation Server on port 8000") - - # Initialize and run the combined server - api = CombinedAPI() + # Start server + logger.info("Starting Combined Video Generation Server") + api = CombinedVideoAPI() server = ls.LitServer( api, - api_path="/predict", # A single endpoint for all models + api_path="/predict", accelerator="auto", devices="auto", max_batch_size=1, track_requests=True, - loggers=prometheus_logger + loggers=[prometheus_logger] ) server.run(port=8000) diff --git a/configs/__pycache__/aws_settings.cpython-310.pyc b/configs/__pycache__/aws_settings.cpython-310.pyc index ceb99676be70ea766c96ee40e418ab5abcdba179..54af652fffff69665530980f3c4ce87ffcd56d92 100644 GIT binary patch delta 41 vcmdnSvYLfEpO=@50SG2%W^Ux3z$l=uUzDF;qVJoTmzkTNoRK+s8)E|i;9LxP delta 52 zcmZ3@vWTKkmz$k5`pOK%Ns$ZH^npaY)pPQMNnVX-Sk*Qx?lstJg GV*>znOb~Pc diff --git a/configs/__pycache__/ltx_settings.cpython-310.pyc b/configs/__pycache__/ltx_settings.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b41f2e71d8e7d8cce3d95227ea2186f2084dd91a GIT binary patch literal 10959 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 literal 0 HcmV?d00001 diff --git a/configs/__pycache__/mochi_settings.cpython-310.pyc b/configs/__pycache__/mochi_settings.cpython-310.pyc index b8e3ebaea429c20310861a202352bc20f7e7bcc2..e7cefaf68d8c076d8c3ba1dd1587ce884cbc9731 100644 GIT binary patch delta 527 zcmZXRKTE?v6u|FlQd67Ow$|DvXxj*41}TF02a2nc4hjxgBzkFcSQEWQ9Tn6~kaDZ& zhj0+Tf*+xS=-}Yw;O69e5p^)f{qFbf9q-0|FBaPwZ0 z4L1qPIR$S7JP%%QiXQHdfES(7*hj%jPAT>=@Uk-&d! zA^oK9@wOlFX9|IO%vt2WHRXZ!Vobmr1me?fh%k&At32RwJ$an6s!NdRY5sU=0@Juz8m@7Whv5)avd^jwjs)}iVDI&nDQZQ zCoRzapnOYPC&Q=%JcvXNO>K2THxhX~TR;>MB}5G|h4{NaHf%zu0Q^B+tUUzH>!wb1 qnuDniz*I2$9@#`zjnCUDK}~t1+tc3-Vf!7vEtH>v|8A1+y7dKhL38;4 delta 663 zcmZ{iy>HV%7{+}`oR7v%^Wmm;KAJQQsFsi{p-vEqtuR#xHZPWwyT(^Jc6Giq5=)16 zWQi;>@n3Z9$Y0?J29TK9Sm1pv7%GHMe(v`?clY|W<@eUMr^mX!qrf%2f3p0w)xVN& z+aJ+&gO%y-OrcG;#oDZ6Dd1b++pfVnz#U-2-D6$gJ>agppXd9)rfcSG0ry-h=RWYj z?d3e2DK8azKu5O<9o-b%K0Ts`baGpA2ekQCv8S1S_lex7v*%6_ub8u*uOqp3Ry^XX zcoA?X5ep|-2!1IOXT$h1fO!!|S4>Doy;V$En4}k#H&0J9lSTeKWS%c2izJUDFA4dA zN6WL!c$hIS;qO>_UpeW0CW?}kgS;|-T?C_UIF-To59vk6`7@ z9*Q3B?V}7(hUu%iU6}%A)p@$9Pp%sn@1hhiE%Hc;7TPvi^*oGyDLNP!C|wj21^W`m zDC38MO$ikQf0E>J4ke=XHKLIw+*Qd| K=V|GMHu()IU7l?K diff --git a/scripts/__pycache__/ltx_inference.cpython-310.pyc b/scripts/__pycache__/ltx_inference.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..78ede1dc3f46547a54c95b02458d59ff67543531 GIT binary patch literal 10705 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 I%nkqTf0a)VIRF3v delta 1385 zcmZuw&u<$=6rLH|>-Bnf?Zo+En-EMONv(#aq@h$Lq!0vA5d~GLfaYRtJriex*SpNl zCat?Bf>c~kE1|tnKtbZr9*{seBjAd}f$PEr@i%}39AMrgrKn<8`|W%4-n{qb&G&vg z_x{|RZ&?PC&l6wFb;@;weg);fPev-w$uHbSAI`n9fDy$s-?hEcdP&K8x9knA4`H;5 zXn`6x5HIl{f9I+YlJlM-gSU6QLf!zw+fOXy8p`Ghs zwv%rQZ%(r3B4;L4M&RMyMag2E`HPWr6lFC9&}t!AOw( zjFd1&F^&syCK!*=R(2~FXM+hPX>l%iR7v?*3uct0$NAv6k_t5Qaeh!#5wkH?5z)Ru zbGva76zNo?mW$%z=lB-hGO1QW12ZPv6IM+2@PNc*%ib!{ynOYWutN{tRH4fQT@1yh z7zV#sr-hptSuWbIP$MQPk+Qsj))4qXefNL9O=)#RKadYX|S3rhTwtU(Zax+OMrKA>3Z4!JQuUy++6+JA~i3K4|9oG1*Uk zGWlk7Vx`|$Wj)3n<*Vq?*m1>XBjCOlh_lkaU%Tfa$rU)<@t9yd1QVB6f|4I9wd%YS z`opgSy&9pjt#W}!GCQ(3tM0Zre#8vvndXGg+nZ_8b9#}}Z9#F|f_g5eIm)g?9S&EY zY8#L(jFflTSd#0Dl=BJtj<{b3p=9+QhYE@P7nWAL$weelcJ1w6DQ zH_ApY%3qpoN7PA{t4ph=VKt+wN()Z6>$m0D(A4srtF3?42P-Ofm}q&-^ZB(_6gnOD zQSx2&r%?#ap9NS3IGVbzYI9TS&<`BTYWKXwswj2LZ9fp#HMXWSl#{f6(L8V49JFSIznu7!C-7qO>Ev`J zEm3!4BMK#XPDH}(hTKU0nw(fsC4m3`g-!J(&!TKlx#UyQ_pOK%Ns$ZH^npaY)pPQMNnVX-Sk*Qx?lss9K Gc^v?Z>kzR3 diff --git a/scripts/__pycache__/s3_manager.cpython-310.pyc b/scripts/__pycache__/s3_manager.cpython-310.pyc index 15dfbf817f5e8f7dd75279a117dfadc1973e1c12..428ecab3138a3995e09a309c603fc4a48c4b4269 100644 GIT binary patch delta 42 wcmdlWvQ&gSpO=@50SG2%W^Uw;VG>Z)FUrp^(f7^F%goJB&dA){#I%kb0P8IbdjJ3c delta 53 zcmZ1~vO$D9pO=@50SI*0>TKkWVUjk`&&bbB)h|sd%_}L@&&|xs%*{{E$kZ<`O5R+~ Hw2mDBf~*jA