I've managed to merge two codes using FastAPI in Python. The challenge now is sending an image in Base64 format via JSON for interpretation. However, I'm encountering issues, as C# returns System.Net.WebException: 'The remote server returned an error: (500) Internal Server Error'
.
Any ideas?
Here are my codes:
Python
import tensorflow as tf
from fastapi import FastAPI
import json
import base64
from PIL import Image
import io
#from flask import request
from fastapi import Request
app = FastAPI()
# Load the saved model
cnn = tf.keras.models.load_model('modelo_cnn.h5')
# Test functions to verify the connection
# @app.get('/prueba0/')
# def prueba0():
# return "Hello, I'm connecting..."
# Test function to sum two numbers
@app.get('/prueba1/{a}/{b}')
def prueba1(a: int, b: int):
return a + b
# Test function to display a message
@app.get('/prueba2/{text}')
def prueba2(text: str):
return "Hello, your message was... " + text
#########################################################################################
# Overlap identification function
@app.post('/traslape/')
def traslape(request: Request):
global cnn
# Get data from the request body
body = request.body()
# Decode JSON data
data = json.loads(body)
# # # Open the JSON file (image)
# with open(image) as f:
# img = json.load(f)
# # Decode the image
# image = base64.b64decode(img["image"])
# # Open the image from bytes using Pillow
# image = Image.open(io.BytesIO(image))
# # Concatenate images horizontally
# #imagen_completa = tf.concat([imagen_i, imagen_d], axis=1)
# # Apply gamma correction to the image
# gamma = tf.convert_to_tensor(0.6)
# gamma_corrected = tf.pow(imagen / 255.0, gamma) * 255.0 # imagen_completa
# image_bw = tf.cast(gamma_corrected, tf.uint8)
# # Convert the image to grayscale
# grayscale_image = tf.image.rgb_to_grayscale(image_bw)
# # Define new dimensions
# new_height = 360
# new_width = 500
# # Resize the image
# imagen_completa_resize = tf.image.resize(grayscale_image, [new_height, new_width])
# # Perform classification using the loaded model
# result = cnn.predict(imagen_completa_resize)
# if result[0][0] > result[0][1]:
# result = False # No mask
# else:
# result = True # With mask
return True
using System;
using System.IO;
using System.Net;
using System.Text;
namespace comunica_api
{
class Program
{
static void Main(string[] args)
{
// Path to the image in your local file system
string imagePath = @"C:\Users\VirtualImages[00]20240418_124751_028.jpg";
try
{
// Read the bytes of the image from the file
byte[] imageBytes = File.ReadAllBytes(imagePath);
// Convert the bytes to a Base64 formatted string
string base64String = Convert.ToBase64String(imageBytes);
// URL of the API
string url = "http://localhost:8000/traslape/";
// Data to send
string json = "{\"image\": \"" + base64String + "\"}";
// Create the HTTP request
var request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST"; // Use the POST method
request.ContentType = "application/json"; // Set content type as JSON
request.ContentLength = json.Length;
// Convert JSON string to bytes
byte[] jsonBytes = Encoding.UTF8.GetBytes(json);
// Print the request content before sending it
Console.WriteLine("Request:");
Console.WriteLine("URL: " + url);
Console.WriteLine("Method: " + request.Method);
Console.WriteLine("Headers:");
foreach (var header in request.Headers)
{
Console.WriteLine(header.ToString());
}
Console.WriteLine("Body:");
Console.WriteLine(json);
// Write bytes into the request body using StreamWriter
using (Stream requestStream = request.GetRequestStream())
using (StreamWriter writer = new StreamWriter(requestStream))
{
// Write JSON string into the request body
writer.Write(json);
}
// Send the request and get the response
// HERE IS THE ERROR
using (var response = (HttpWebResponse)request.GetResponse())
//
{
// Read the response from the server
using (var streamReader = new StreamReader(response.GetResponseStream()))
{
// Read the response as a string and display it in the console
string responseText = streamReader.ReadToEnd();
Console.WriteLine("API Response:");
Console.WriteLine(responseText);
}
}
}
catch (FileNotFoundException)
{
Console.WriteLine("The specified image could not be found.");
}
catch (WebException ex)
{
// Handle any communication error with the API
Console.WriteLine("API Communication Error:");
Console.WriteLine(ex.Message);
}
// Wait for the user to press Enter before exiting the program
Console.ReadLine();
}
}
}
The issue is with the way you are reading the request
body
on server side. The request.body()
method returns a coroutine, and thus, it should be await
ed, meaning that the endpoint should be defined with async def
as well—see this answer for more details on def
vs async def
endpoints and how FastAPI handles them. Example:
@app.post('/traslape/')
async def traslape(request: Request):
body = await request.body()
data = json.loads(body)
return "whatever"
Note that since you are converting the body into JSON, you could directly do that using the following instead:
data = await request.json()
Retrieving the body on your own and then converting it into JSON is useful when you would like using other (maybe faster) JSON encoders, such as orjson
, as demnonstrated in this answer, as well as this answer and this answer (you might find this helpful as well, when it comes to returning JSON data in FastAPI).
If you would like having the endpoint defined with def
instead and still be able to get the raw body of a POST
request, solutions could be found in the following answer:
Using FastAPI in a sync way, how can I get the raw body of a POST request?
Related posts demonstrating how to upload/deal with base64 images in FastAPI could be found here, as well as here and here. Note that you don't necessarily need to send an image as a base64 string encoded as application/json
or application/x-www-form-urlencoded
in the request body; you could instead upload it encoded as multipart/form-data
, as shown in this answer and the relevant included references in that answer.