@app.post('/process_image', response_class=HTMLResponse, status_code=200)
async def process_image(request: Request, file: UploadFile = File(...)):
    try:
        start_time = time.time()  # Record start time
        image_contents = await file.read()
        image = Image.open(io.BytesIO(image_contents))
        image_array = np.array(image)

        # First Model Prediction: Detect lines in the image
        visualised_origine, instances_lines = await run_prediction('model_final_lines', image_array)
        
        # Initialize results list to store information for each line
        results = []

        async def process_instance_lines(instance_idx, i):
            if i>5:
                return results
            if instances_lines.pred_classes[instance_idx] != 0:
                return
            polygon = instances_lines.pred_masks[instance_idx].cpu().numpy().astype(np.uint8)
            contours, _ = cv2.findContours(polygon, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
            if not contours:
                return
            print(f"Processing Contours for Instance {i}")

            # Process contours for each detected line
            for contour_idx, contour in enumerate(contours):
                x, y, w, h = cv2.boundingRect(contour)
                area = w * h
                # Add a condition based on width and height
                if w < 1500 and h < 80:
                    continue

                mask = np.zeros_like(image_array, dtype=np.uint8)
                cv2.drawContours(mask, [contour], contourIdx=-1, color=(255,) * mask.shape[2], thickness=cv2.FILLED)
                masked_image = cv2.bitwise_and(image_array, mask)
                cropped_image = masked_image[y:y + h, x:x + w]

                # Second Model Prediction: Detect letters within each line
                letter_prediction, instance_letter = await run_prediction('model_letter', cropped_image)
                
                # Encode the cropped image of the line
                encoded_cropped_line = await encode_image_to_base64(cropped_image)

                # Initialize list to store information for each detected letter within the line
                letters_list = []

                # Process contours for each detected letter within the line
                for contour_idx_letter, contour_letter in enumerate(contours):
                    print(f"Processing letter {contour_idx_letter} in line {i}")
                    x_letter, y_letter, w_letter, h_letter = cv2.boundingRect(contour_letter)
                    area_letter = w_letter * h_letter
                    

                    mask_letter = np.zeros_like(image_array, dtype=np.uint8)
                    cv2.drawContours(mask_letter, [contour_letter], contourIdx=-1, color=(255,) * mask.shape[2], thickness=cv2.FILLED)
                    masked_image_letter = cv2.bitwise_and(image_array, mask_letter)
                    cropped_image_letter = masked_image_letter[y_letter:y_letter + h_letter, x_letter:x_letter + w_letter]
                    
                    # Encode the letter prediction
                    prediction_letters = await encode_image_to_base64(letter_prediction)

                    # Encode the cropped image of the letter
                    encoded_image_letter = await encode_image_to_base64(cropped_image_letter)
                    
                    # Add the test character
                    test = classify_character(cropped_image_letter, model5)
                    
                    # Add information for each detected letter to the letters_list
                    letters_list.append({'original': encoded_image_letter, 
                                         'prediction': prediction_letters,
                                         'contour_idx': contour_idx_letter, 
                                         'instance_idx': i, 
                                         'area': area_letter, 
                                         'test': test})

                # Add information for the line to the results list
                results.append({'image_original': encoded_cropped_line,
                                'image_lines': encoded_cropped_line,
                                'letters': letters_list})

        # Process each detected line
        await asyncio.gather(*(process_instance_lines(instance_idx, i) for i, instance_idx in enumerate(range(len(instances_lines)))))

        # Encode the original image and the predicted lines image
        encoded_image = await encode_image_to_base64(image_array)
        encoded_predicted = await encode_image_to_base64(visualised_origine)

        end_time = time.time()  # Record end time
        processing_time = end_time - start_time
        print(f"Total processing time: {processing_time} seconds")

        # Return the results in a template response
        return templates.TemplateResponse(
            "result_template.html",
            {
                "request": request,
                "code": 200,
                "encoded_image": encoded_image,
                "encoded_predicted": encoded_predicted,
                "message": "Success",
                "results": results,
                "processing_time": processing_time  # Pass processing time to template
            }
        )

    except Exception as e:
        logging.error(f"Error processing image: {e}")
        return templates.TemplateResponse(
            "result_template.html",
            {
                "request": request,
                "code": 500,
                "message": f"Error: {e}",
            }
        )  
" the crop of letter is not working