Specifically, I want the below example to work:
from typing import List
from pydantic import BaseModel
from fastapi import FastAPI, UploadFile, File
app = FastAPI()
class DataConfiguration(BaseModel):
textColumnNames: List[str]
idColumn: str
@app.post("/data")
async def data(dataConfiguration: DataConfiguration,
csvFile: UploadFile = File(...)):
# read requested id and text columns from csvFile
pass
If this is not the proper way for a POST
request, please let me know how to select the required columns from an uploaded CSV file in FastAPI.
2
As per FastAPI documentation:
You can declare multiple
Form
parameters in a path operation, but you
can’t also declareBody
fields that you expect to receive asJSON
, as
the request will have the body encoded using
application/x-www-form-urlencoded
instead ofapplication/json
(when the form includes files, it is encoded asmultipart/form-data
).This is not a limitation of FastAPI, it’s part of the
HTTP
protocol.
Note that you need to have python-multipart
installed, as uploaded files are sent as “form data”. For instance:
pip install python-multipart
It should also be noted that in the examples below, the endpoints are defined with normal def
, but you could also use async def
(depending on your needs). Please have a look at this answer for more details on def
vs async def
in FastAPI.
If you are looking for how to upload both files and a list
of dictionaries/JSON data, please have a look at this answer, as well as this answer and this answer for working examples.
I would also recommend taking a look at this answer, which provides a much faster approach to uploading files (optionally, together with Form
or JSON data), as using FastAPI/Starlette’s UploadFile
(as in the examples provided below) might be quite slow; especially, when uploading rather large files.
Method 1
As described here, one can define files and form fileds at the same time using File
and Form
. In case you had a large number of parameters and would like to define them separately from the endpoint, please have a look at this answer on how to declare multiple Form
fields, using either a dependency class or Pydantic model. Also, for more details on Jinja2Templates
, please have a look at the relevant documentation, as well as the first section of this answer, regarding a small change on TemplateResponse
recently by Starlette.
app.py
from fastapi import Form, File, UploadFile, Request, FastAPI
from typing import List
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
app = FastAPI()
templates = Jinja2Templates(directory="templates")
@app.post("/submit")
def submit(
name: str = Form(...),
point: float = Form(...),
is_accepted: bool = Form(...),
files: List[UploadFile] = File(...),
):
return {
"JSON Payload": {"name": name, "point": point, "is_accepted": is_accepted},
"Filenames": [file.filename for file in files],
}
@app.get("/", response_class=HTMLResponse)
async def main(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
You could test the above example by accessing the template below at http://127.0.0.1:8000
. If your template does not include any Jinja code, you could instead return a simple HTMLResponse
. See this answer as well, if you are looking for a JavaScript Fetch API solution.
templates/index.html
<!DOCTYPE html>
<html>
<body>
<form method="post" action="http://127.0.0.1:8000/submit" enctype="multipart/form-data">
name : <input type="text" name="name" value="foo"><br>
point : <input type="text" name="point" value=0.134><br>
is_accepted : <input type="text" name="is_accepted" value=True><br>
<label for="files">Choose file(s) to upload</label>
<input type="file" id="files" name="files" multiple>
<input type="submit" value="submit">
</form>
</body>
</html>
You could also test this example using the interactive OpenAPI/Swagger UI autodocs at /docs
, e.g., http://127.0.0.1:8000/docs
, or using Python requests
, as shown below:
test.py
import requests
url = 'http://127.0.0.1:8000/submit'
files = [('files', open('test_files/a.txt', 'rb')), ('files', open('test_files/b.txt', 'rb'))]
data = {"name": "foo", "point": 0.13, "is_accepted": False}
resp = requests.post(url=url, data=data, files=files)
print(resp.json())
Method 2
One could also use Pydantic models, along with Dependencies, to inform the /submit
endpoint (in the example below) that the parameterized variable base
depends on the Base
class. Please note that this method expects the base
data as query
(not body
) parameters, which are then validated against and converted into the Pydantic model (in this case, the Base
model). Also, note that one should never pass sensitive data through the query string, as this poses serious security risks—please have a look at this answer for more details.
When returning a Pydantic model instance (e.g, base
) from a FastAPI endpoint (e.g., /submit
), it would automatically be converted into a JSON string, behind the scenes, using the jsonable_encoder
, as explained in detail in this answer. However, if you would like to have the model converted into a JSON string on your own within the endpoint, you could use Pydantic’s model_dump_json()
(in Pydantic V2), e.g., base.model_dump_json()
, and return a custom Response
directly, as explained in the linked answer earlier; thus, avoiding the use of jsonable_encoder
. Otherwise, in order to convert the model into a dict
on your own, you could use Pydantic’s model_dump()
(in Pydantic V2), e.g., base.model_dump()
, or simply dict(base)
(Note that returning a dict
object from an endpoint, FastAPI would still use the jsonable_encoder
, behind the scenes, as explained in the linked answer above). You may also have a look at this answer for the relevant Pydantic methods and documentation.
Apart from using a Pydantic model for the query parameters, one could also define query parameters directly in the endpoint, as demonstrated in this answer, as well as this answer and this answer.
Besides the base
query parameters, the following /submit
endpoint also expects Files
encoded as multipart/form-data
in the request body.
app.py
from fastapi import Form, File, UploadFile, Request, FastAPI, Depends
from typing import List, Optional
from fastapi.responses import HTMLResponse
from pydantic import BaseModel
from fastapi.templating import Jinja2Templates
app = FastAPI()
templates = Jinja2Templates(directory="templates")
class Base(BaseModel):
name: str
point: Optional[float] = None
is_accepted: Optional[bool] = False
@app.post("/submit")
def submit(base: Base = Depends(), files: List[UploadFile] = File(...)):
return {
"JSON Payload": base,
"Filenames": [file.filename for file in files],
}
@app.get("/", response_class=HTMLResponse)
async def main(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
The template below now uses JavaScript to modify the action
attribute of the form
element, in order to pass the form
data as query
params to the URL instead of form-data
in the request body.
templates/index.html
<!DOCTYPE html>
<html>
<body>
<form method="post" id="myForm" onsubmit="transformFormData();" enctype="multipart/form-data">
name : <input type="text" name="name" value="foo"><br>
point : <input type="text" name="point" value=0.134><br>
is_accepted : <input type="text" name="is_accepted" value=True><br>
<label for="files">Choose file(s) to upload</label>
<input type="file" id="files" name="files" multiple>
<input type="submit" value="submit">
</form>
<script>
function transformFormData(){
var myForm = document.getElementById('myForm');
var qs = new URLSearchParams(new FormData(myForm)).toString();
myForm.action = 'http://127.0.0.1:8000/submit?' + qs;
}
</script>
</body>
</html>
If, instead, you would like to perform a JavaScript fetch()
request, you could use the following template (see related answer on submiting HTML form as well):
<!DOCTYPE html>
<html>
<body>
<form id="myForm" >
name : <input type="text" name="name" value="foo"><br>
point : <input type="text" name="point" value=0.134><br>
is_accepted : <input type="text" name="is_accepted" value=True><br>
</form>
<label for="fileInput">Choose file(s) to upload</label>
<input type="file" id="fileInput" onchange="reset()" multiple><br>
<input type="button" value="Submit" onclick="submitUsingFetch()">
<p id="resp"></p>
<script>
function reset() {
var resp = document.getElementById("resp");
resp.innerHTML = "";
resp.style.color = "black";
}
function submitUsingFetch() {
var resp = document.getElementById("resp");
var fileInput = document.getElementById('fileInput');
if (fileInput.files[0]) {
var formData = new FormData();
for (const file of fileInput.files)
formData.append('files', file);
var myForm = document.getElementById('myForm');
var qs = new URLSearchParams(new FormData(myForm)).toString();
fetch('/submit?' + qs, {
method: 'POST',
body: formData,
})
.then(response => response.json())
.then(data => {
resp.innerHTML = JSON.stringify(data); // data is a JSON object
})
.catch(error => {
console.error(error);
});
} else {
resp.innerHTML = "Please choose some file(s)...";
resp.style.color = "red";
}
}
</script>
</body>
</html>
As mentioned earlier, you could also use Swagger UI or Python requests
for testing. Note that the data should now be passed to the params
(not the data
) argument of requests.post()
, as the data are now sent as query
parameters, not form-data
, which was the case in Method 1 earlier.
test.py
import requests
url = 'http://127.0.0.1:8000/submit'
files = [('files', open('test_files/a.txt', 'rb')), ('files', open('test_files/b.txt', 'rb'))]
params = {"name": "foo", "point": 0.13, "is_accepted": False}
resp = requests.post(url=url, params=params, files=files)
print(resp.json())
Method 3
Another option would be to pass the body data as a JSON string in a single Form
parameter. To that end, you would need to create a dependency function on server side.
A dependency is “just a function that can take all the same parameters that a path operation function (also known as endpoint) can take. You can think of it as a path operation function without the decorator”. Hence, you would need to declare the dependency in the same way you would do with your endpoint (i.e., the parameters’ names and types in the dependency should be the ones expected by FastAPI, when a client sends an HTTP request to that endpoint, e.g., data: str = Form(...)
). Then, create a new parameter (e.g., base
) in your endpoint, using Depends()
and pass the dependency function as a parameter to it (Note: Don’t call it directly, meaning don’t add the parentheses at the end of your function’s name, but instead use Depends(checker)
, where checker
is the name of your dependency function). Whenever a new request arrives, FastAPI will take care of calling your dependency, getting the result and assigning that result to the parameter (e.g., base
) in your endpoint. For more details on dependencies, please have a look at the links provided earlier.
In this case, the dependency should be used to parse the (JSON string) data
using the parse_raw
method (Note: In Pydantic V2 parse_raw
has been deprecated and replaced by model_validate_json
), as well as validate the data
against the corresponding Pydantic model. If ValidationError
is raised, an HTTP_422_UNPROCESSABLE_ENTITY
error should be sent back to the client, including the error message; otherwise, an instance of that model (e.g., Base
) is assigned to the parameter in the endpoint.
app.py
from fastapi import FastAPI, status, Form, UploadFile, File, Depends, Request
from pydantic import BaseModel, ValidationError
from fastapi.exceptions import HTTPException
from fastapi.encoders import jsonable_encoder
from typing import Optional, List
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse
app = FastAPI()
templates = Jinja2Templates(directory="templates")
class Base(BaseModel):
name: str
point: Optional[float] = None
is_accepted: Optional[bool] = False
def checker(data: str = Form(...)):
try:
return Base.model_validate_json(data)
except ValidationError as e:
raise HTTPException(
detail=jsonable_encoder(e.errors()),
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
)
@app.post("/submit")
def submit(base: Base = Depends(checker), files: List[UploadFile] = File(...)):
return {"JSON Payload": base, "Filenames": [file.filename for file in files]}
@app.get("/", response_class=HTMLResponse)
async def main(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
Generic Checker
dependency class
In case you had multiple models and would like to avoid creating a checker
function for each model, you could instead create a generic Checker
dependency class, as described in the docs (see this answer as well), and use it for every different model in your API. Example:
# ... rest of the code is the same as above
class Other(BaseModel):
msg: str
details: Base
class Checker:
def __init__(self, model: BaseModel):
self.model = model
def __call__(self, data: str = Form(...)):
try:
return self.model.model_validate_json(data)
except ValidationError as e:
raise HTTPException(
detail=jsonable_encoder(e.errors()),
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
)
@app.post("/submit")
def submit(base: Base = Depends(Checker(Base)), files: List[UploadFile] = File(...)):
pass
@app.post("/submit_other")
def submit_other(other: Other = Depends(Checker(Other)), files: List[UploadFile] = File(...)):
pass
Arbitrary JSON data
In case validating the input data against a Pydantic model wasn’t important to you, but, instead, you would like to receive arbitrary JSON data and simply check whether or not a valid JSON string was sent by the client, use the below (orjson
, as shown here, could be used instead of the standard json
module):
# ...
from json import JSONDecodeError
import json
def checker(data: str = Form(...)):
try:
return json.loads(data)
except JSONDecodeError:
raise HTTPException(status_code=400, detail='Invalid JSON data')
@app.post("/submit")
def submit(payload: dict = Depends(checker), files: List[UploadFile] = File(...)):
pass
Alternatively, you could simply use the Json
type from Pydantic (as shown here):
from pydantic import Json
@app.post("/submit")
def submit(data: Json = Form(), files: List[UploadFile] = File(...)):
pass
Test using Python requests
test.py
Note that in JSON
, boolean values are represented using the true
or false
literals in lower case, whereas in Python they must be capitalized as either True
or False
.
import requests
url = 'http://127.0.0.1:8000/submit'
files = [('files', open('test_files/a.txt', 'rb')), ('files', open('test_files/b.txt', 'rb'))]
data = {'data': '{"name": "foo", "point": 0.13, "is_accepted": false}'}
resp = requests.post(url=url, data=data, files=files)
print(resp.json())
Or, if you prefer:
import requests
import json
url = 'http://127.0.0.1:8000/submit'
files = [('files', open('test_files/a.txt', 'rb')), ('files', open('test_files/b.txt', 'rb'))]
data = {'data': json.dumps({"name": "foo", "point": 0.13, "is_accepted": False})}
resp = requests.post(url=url, data=data, files=files)
print(resp.json())
P.S. To test the /submit_other
endpoint (described in the generic Checker
class earlier) using Python requests
, replace the data
attribute in the example above with the one below:
import requests
import json
url = 'http://127.0.0.1:8000/submit_other'
data = {'data': json.dumps({"msg": "Hi", "details": {"name": "bar", "point": 0.11, "is_accepted": True}})}
# ... rest of the code is the same as above
Test using Fetch API or Axios
You might find this answer helpful as well, if you are looking for how to convert entries from HTML <form>
into a JSON string.
templates/index.html
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.27.2/axios.min.js"></script>
</head>
<body>
<input type="file" id="fileInput" name="file" onchange="reset()" multiple><br>
<input type="button" value="Submit using fetch" onclick="submitUsingFetch()">
<input type="button" value="Submit using axios" onclick="submitUsingAxios()">
<p id="resp"></p>
<script>
function reset() {
var resp = document.getElementById("resp");
resp.innerHTML = "";
resp.style.color = "black";
}
function submitUsingFetch() {
var resp = document.getElementById("resp");
var fileInput = document.getElementById('fileInput');
if (fileInput.files[0]) {
var formData = new FormData();
formData.append("data", JSON.stringify({"name": "foo", "point": 0.13, "is_accepted": false}));
for (const file of fileInput.files)
formData.append('files', file);
fetch('/submit', {
method: 'POST',
body: formData,
})
.then(response => response.json())
.then(data => {
resp.innerHTML = JSON.stringify(data); // data is a JSON object
})
.catch(error => {
console.error(error);
});
} else {
resp.innerHTML = "Please choose some file(s)...";
resp.style.color = "red";
}
}
function submitUsingAxios() {
var resp = document.getElementById("resp");
var fileInput = document.getElementById('fileInput');
if (fileInput.files[0]) {
var formData = new FormData();
formData.append("data", JSON.stringify({"name": "foo", "point": 0.13, "is_accepted": false}));
for (const file of fileInput.files)
formData.append('files', file);
axios({
method: 'POST',
url: '/submit',
data: formData,
})
.then(response => {
resp.innerHTML = JSON.stringify(response.data); // response.data is a JSON object
})
.catch(error => {
console.error(error);
});
} else {
resp.innerHTML = "Please choose some file(s)...";
resp.style.color = "red";
}
}
</script>
</body>
</html>
Method 4
A further method comes from the github discussion here, and incorporates a custom class with a classmethod used to transform a given JSON
string into a Python dictionary, which is then used for validation against the Pydantic model (Note that, compared to the example given in the aforementioned github link, the example below uses @model_validator(mode='before')
, since the introduction of Pydantic V2).
Similar to Method 3 above, the input data should be passed as a single Form
parameter in the form of JSON
string (Note that defining the data
parameter in the example below with either Body
or Form
would work regardless—Form
is a class that inherits directly from Body
. That is, FastAPI would still expect the JSON string as form-data
, not application/json
, as in this case the request will have the body encoded using multipart/form-data
). Thus, the exact same test.py examples and index.html template provided in Method 3 above could be used for testing the application example below as well.
app.py
from fastapi import FastAPI, File, Body, UploadFile, Request
from pydantic import BaseModel, model_validator
from typing import Optional, List
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse
import json
app = FastAPI()
templates = Jinja2Templates(directory="templates")
class Base(BaseModel):
name: str
point: Optional[float] = None
is_accepted: Optional[bool] = False
@model_validator(mode='before')
@classmethod
def validate_to_json(cls, value):
if isinstance(value, str):
return cls(**json.loads(value))
return value
@app.post("/submit")
def submit(data: Base = Body(...), files: List[UploadFile] = File(...)):
return {"JSON Payload": data, "Filenames": [file.filename for file in files]}
@app.get("/", response_class=HTMLResponse)
async def main(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
Method 5
Another solution would be to convert the file bytes into a base64
-format string and add it to the JSON object, along with other data that you might want to send over to the server. However, I would not highly recommend using this approach for the reasons explained below—it has been added, though, to this answer as an alternative option, for the sake of completeness.
The reason I would not suggest using it is because encoding file(s) using base64
would essentially increase the size of the file, and hence, increase bandwidth utilization, as well as the time and resources (e.g., CPU usage) required to upload the file (especially, when the API is going to be used by multiple users at the same time), as base64 encoding and decoding would need to take place on client and server side, respectively (this approach could only be useful for very tiny images). As per MDN’s documentation:
Each Base64 digit represents exactly 6 bits of data. So, three 8-bits
bytes of the input string/binary file (3×8 bits = 24 bits) can be
represented by four 6-bit Base64 digits (4×6 = 24 bits).This means that the Base64 version of a string or file will be at
least 133% the size of its source (a ~33% increase). The increase
may be larger if the encoded data is small. For example, the string
"a"
withlength === 1
gets encoded to"YQ=="
withlength === 4
— a 300% increase.
Using this approach, which again I would not recommend for the reasons discussed above, you would need to make sure to define the endpoint with normal def
, as base64.b64decode()
performs a blocking operation that would block the event loop, and hence the entire server—have a look at this answer for more details. Otherwise, to use async def
endpoint, you should execute the decoding function in an external ThreadPool
or ProcessPool
(again, see this answer on how to do that), as well as use aiofiles
to write the file to disk (see this answer as well).
The example below provides client test examples in Python requests
and JavaScript as well.
app.py
from fastapi import FastAPI, Request, HTTPException
from typing import List
from fastapi.responses import HTMLResponse
from pydantic import BaseModel
from fastapi.templating import Jinja2Templates
import base64
import binascii
app = FastAPI()
templates = Jinja2Templates(directory='templates')
class Bas64File(BaseModel):
filename: str
owner: str
bas64_str: str
@app.post('/submit')
def submit(files: List[Bas64File]):
for file in files:
try:
contents = base64.b64decode(file.bas64_str.encode('utf-8'))
with open(file.filename, 'wb') as f:
f.write(contents)
except base64.binascii.Error as e:
raise HTTPException(
400, detail='There was an error decoding the base64 string'
)
except Exception:
raise HTTPException(
500, detail='There was an error uploading the file(s)'
)
return {'Filenames': [file.filename for file in files]}
@app.get('/', response_class=HTMLResponse)
async def main(request: Request):
return templates.TemplateResponse('index.html', {'request': request})
Test using Python requests
test.py
import requests
import os
import glob
import base64
url = 'http://127.0.0.1:8000/submit'
paths = glob.glob('files/*', recursive=True)
payload = []
for p in paths:
with open(p, 'rb') as f:
bas64_str = base64.b64encode(f.read()).decode('utf-8')
payload.append({'filename': os.path.basename(p), 'owner': 'me', 'bas64_str': bas64_str})
resp = requests.post(url=url, json=payload)
print(resp.json())
Test using Fetch API
templates/index.html
<input type="file" id="fileInput" onchange="base64Handler()" multiple><br>
<script>
async function base64Handler() {
var fileInput = document.getElementById('fileInput');
var payload = [];
for (const file of fileInput.files) {
var dict = {};
dict.filename = file.name;
dict.owner = 'me';
base64String = await this.toBase64(file);
dict.bas64_str = base64String.replace("data:", "").replace(/^.+,/, "");
payload.push(dict);
}
uploadFiles(payload);
}
function toBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
};
function uploadFiles(payload) {
fetch('/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
})
.then(response => {
console.log(response);
})
.catch(error => {
console.error(error);
});
}
</script>
6
You can’t mix form-data with json.
Per FastAPI documentation:
Warning:
You can declare multipleFile
andForm
parameters in a path operation, but you can’t also declareBody
fields that you expect to receive as JSON, as the request will have the body encoded usingmultipart/form-data
instead ofapplication/json
.
This is not a limitation of FastAPI, it’s part of the HTTP protocol.
You can, however, use Form(...)
as a workaround to attach extra string as form-data
:
from typing import List
from fastapi import FastAPI, UploadFile, File, Form
app = FastAPI()
@app.post("/data")
async def data(textColumnNames: List[str] = Form(...),
idColumn: str = Form(...),
csvFile: UploadFile = File(...)):
pass
3
If you are using pydantic v2
:
import json
@app.post(/endpoint)
async def endpoint(file: UploadFile, payload: A)
class A(BaseModel):
attr: str
@model_validator(mode="before")
@classmethod
def to_py_dict(cls, data):
return json.loads(data)
Your request shall be a multipart/form-data, the payload key’s value will be a string in JSON’s format, and when it reaches the model’s serialization stage, the @model_validator will execute before that, and then you can transform the value into a python’s dict and return it to the serialization.
0
I went with the very elegant Method3 from @Chris (originally proposed from @M.Winkwns). However, I modified it slightly to work with any Pydantic model:
from typing import Type, TypeVar
from pydantic import BaseModel, ValidationError
from fastapi import Form
Serialized = TypeVar("Serialized", bound=BaseModel)
def form_json_deserializer(schema: Type[Serialized], data: str = Form(...)) -> Serialized:
"""
Helper to serialize request data not automatically included in an application/json body but
within somewhere else like a form parameter. This makes an assumption that the form parameter with JSON data is called 'data'
:param schema: Pydantic model to serialize into
:param data: raw str data representing the Pydantic model
:raises ValidationError: if there are errors parsing the given 'data' into the given 'schema'
"""
try:
return schema.parse_raw(data)
except ValidationError as e
raise HTTPException(detail=jsonable_encoder(e.errors()), status_code=status.HTTP_422_UNPROCESSABLE_ENTITY)
When you use it in an endpoint you can then use functools.partial
to bind the specific Pydantic model:
import functools
from pydantic import BaseModel
from fastapi import Form, File, UploadFile, FastAPI
class OtherStuff(BaseModel):
stuff: str
class Base(BaseModel):
name: str
stuff: OtherStuff
@app.post("/upload")
async def upload(
data: Base = Depends(functools.partial(form_json_deserializer, Base)),
files: Sequence[UploadFile] = File(...)
) -> Base:
return data
As stated by @Chris (and just for completeness):
As per FastAPI documentation,
You can declare multiple Form parameters in a path operation, but you can’t also declare Body fields that you expect to receive as JSON, as the request will have the body encoded using application/x-www-form-urlencoded instead of application/json. (But when the form includes files, it is encoded as multipart/form-data)
This is not a limitation of FastAPI, it’s part of the HTTP protocol.
Since his Method1 wasn’t an option and Method2 can’t work for deeply nested datatypes I came up with a different solution:
Simply convert your datatype to a string/json and call pydantics parse_raw
function
from pydantic import BaseModel
from fastapi import Form, File, UploadFile, FastAPI
class OtherStuff(BaseModel):
stuff: str
class Base(BaseModel):
name: str
stuff: OtherStuff
@app.post("/submit")
async def submit(base: str = Form(...), files: List[UploadFile] = File(...)):
try:
model = Base.parse_raw(base)
except pydantic.ValidationError as e:
raise HTTPException(
detail=jsonable_encoder(e.errors()),
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY
) from e
return {"JSON Payload ": received_data, "Uploaded Filenames": [file.filename for file in files]}
Example using pythantic models for cleaner documentation. The file is encoded to base64 any other logic can be applied.
class BaseTestUser(BaseModel):
name: str
image_1920: str
class UpdateUserEncodeFile(BaseTestUser):
def __init__(self, name: str = Form(...), image_1920: UploadFile = File(...)):
super().__init__(name=name, image_1920=base64.b64encode(image_1920.file.read()))
#routers
@router.put("/users/{id}/encoded", status_code=status.HTTP_200_OK)
def user_update_encode(id: int, user:UpdateUserEncodeFile=Depends()):
return user
Not an alternative, but an addendum to Chris’s generous response above /a/70640522/20479, that helped me with my code, but only after some debugging because I’d changed some variable names.
So the gotcha is that the mapping to parameter names and form field names is key.
Take Chris’s excellent method 3, which I ended up using. The last example of plain json exemplifies what confused me:
In the FastAPI service, we have:
def checker(data: str = Form(...)):
...
@app.post("/submit")
def submit(data: dict = Depends(checker), files: List[UploadFile] = File(...)):
pass
and in the client code we see:
files = [('files', open('test_files/a.txt', 'rb')), ('files', ...
data = {'data': '{"name":...}
resp = requests.post(url=url, data=data, files=files)
Note that the terms data
and files
appear no fewer than 6 times each in the code I excerpted. We also see That’s what tripped me up with hard-to-resolve errors including info like [{'loc': ('body', 'data'), 'msg': 'field required', 'type': 'value_error.missing'}]
(which I’ve learnt to read as “there’s a missing form field named ‘data’ expected in the ‘body’ of this request)
So the catch is that the first data in submit
is the function parameter and it’s name doesn’t have to match anything other than references to it below in the function (which are left to the imagination). This parameter is arbitrary and could be foo
here.
The one in def checker(data:...
, however, is crucial. It can have any name, but must be used in the request, specifically as the dict key in the form. (Read that again).
i.e. it matches the second ‘data’ in this line:
data = {'data': '{"name":...}
This is because checker
is a FastAPI dependency function, so its parameters are used in place of parameters in path operation function. (That’s the whole point of dependencies: reusing parameter sets instead of repeating them).
See the details here: https://fastapi.tiangolo.com/tutorial/dependencies/. The phrase that helped me was down the page where it says:
And it has the same shape and structure that all your path operation functions have.
You can think of it as a path operation function without the “decorator” (without the @app.get(“/some-path”)).
(Note that def submit...
is an example of a “path operation function”)
Meanwhile, the first data
in the client line
resp = requests.post(url=url, data=data, files=files)
is required by the requests post
method (so if you change that one, you’ll find out soon).
Similarly the only values of files
that have to match are the ones in the dict created in the client and the parameter name in the function. The rest are either required parameters for the requests post
function, or arbitrary choices.
Don’t get me wrong – calling the arbitrary variable by the same name as the parameter to which you assign it, is very pythonic – just that it tripped me up in understanding Chris’s answer.
To make it clearer, I’m transcribing my excerpt below, replacing the word “data” where I can. (And adding an assertion and a write..)
Service:
def checker(foo: str = Form(...)):
return "dingo"
...
@app.post("/submit")
def submit(quux: dict = Depends(checker), bananas: List[UploadFile] = File(...)):
assert quux == "dingo" # quux assigned to return value of checker
# write bananas to local files:
and in the client:
apples = [('bananas', open('test_files/a.txt', 'rb')), ('bananas', ...
baz = {'foo': { 'name': '...'} ... }
resp = requests.post(url=url, data=baz, files=apples)
Now there’s only one ‘data’ and its required by requests (and by the same method in httpx, which is what I’m using)
The biggest two gotchas here are:
-
the dependency function param
checker(foo
must be provided in the form data{'foo': {...
-
the client must provide names matching the form fields as keys in the dict / json of the request body. Look carefully at the 2 appearances of ‘foo’ and the 4 of ‘bananas’ in my code.
0
Sinh nhật phong cách metal
Tổ chức sinh nhật tại nhà jazz
Dịch vụ sinh nhật xuất sắc hơn
Tiệc sinh nhật cho nhà ngôn ngữ học
Thuê nhóm nhảy metal sinh nhật
Sinh nhật chủ đề sang trọng
Tổ chức sinh nhật tại nhà pop
Dịch vụ sinh nhật hoàn mỹ hơn
Tiệc sinh nhật cho nhà văn học
Trang trí sinh nhật bằng đồ garnet
Sinh nhật phong cách punk rock
Tổ chức sinh nhật tại nhà reggae
Dịch vụ sinh nhật tuyệt vời hơn nữa
Tiệc sinh nhật cho nhà khảo cổ học
Thuê nhóm nhảy punk sinh nhật
Sinh nhật chủ đề ấm cúng
Tổ chức sinh nhật tại nhà blues
Dịch vụ sinh nhật đỉnh cao hơn nữa
Tiệc sinh nhật cho nhà địa lý học
Trang trí sinh nhật bằng đồ aquamarine
Sinh nhật phong cách alternative
Tổ chức sinh nhật tại nhà country
Dịch vụ sinh nhật chất lượng hơn
Tiệc sinh nhật cho nhà thiên văn học
Thuê nhóm nhảy alternative sinh nhật
Sinh nhật chủ đề lãng mạn
Tổ chức sinh nhật tại nhà folk
Dịch vụ sinh nhật sáng chói hơn nữa
Tiệc sinh nhật cho nhà triết học
Trang trí sinh nhật bằng đồ citrine
Sinh nhật phong cách ska
Tổ chức sinh nhật tại nhà techno
Dịch vụ sinh nhật rực rỡ hơn nữa
Tiệc sinh nhật cho nhà kinh tế học
Thuê nhóm nhảy ska sinh nhật
Sinh nhật chủ đề truyền thống
Tổ chức sinh nhật tại nhà electronic
Dịch vụ sinh nhật lung linh hơn nữa
Tiệc sinh nhật cho nhà sử học
Trang trí sinh nhật bằng đồ peridot
Sinh nhật phong cách R&B
Tổ chức sinh nhật tại nhà disco
Dịch vụ sinh nhật đẹp hơn nữa
Tiệc sinh nhật cho nhà nhân học
Thuê nhóm nhảy R&B sinh nhật
Sinh nhật chủ đề phá cách
Tổ chức sinh nhật tại nhà funk
Dịch vụ sinh nhật hoàn toàn hơn nữa
Tiệc sinh nhật cho nhà luật học
Trang trí sinh nhật bằng đồ moonstone
Sinh nhật phong cách gospel
Tổ chức sinh nhật tại nhà soul
Dịch vụ sinh nhật độc đáo hơn nữa
Tiệc sinh nhật cho nhà chính trị học
Thuê nhóm nhảy gospel sinh nhật
Sinh nhật chủ đề nghệ thuật
Tổ chức sinh nhật tại nhà rap
Dịch vụ sinh nhật xuất sắc hơn nữa
Tiệc sinh nhật cho nhà tài chính học
Trang trí sinh nhật bằng đồ onyx
Sinh nhật phong cách hip hop dance
Tổ chức sinh nhật tại nhà indie
Dịch vụ sinh nhật hoàn mỹ hơn nữa
Tiệc sinh nhật cho nhà quản trị học
Thuê nhóm nhảy hip hop sinh nhật
Sinh nhật chủ đề đồng quê
Tổ chức sinh nhật tại nhà acoustic
Dịch vụ sinh nhật tuyệt vời hơn hết
Tiệc sinh nhật cho nhà kỹ thuật học
Trang trí sinh nhật bằng đồ jade
Sinh nhật phong cách breakdance
Tổ chức sinh nhật tại nhà chill
Dịch vụ sinh nhật đỉnh cao hơn hết
Tiệc sinh nhật cho nhà công nghệ học
Thuê nhóm nhảy breakdance sinh nhật
Sinh nhật chủ đề hoàng gia
Tổ chức sinh nhật tại nhà lounge
Dịch vụ sinh nhật chất lượng hơn hết
Tiệc sinh nhật cho nhà nghiên cứu học
Trang trí sinh nhật bằng đồ lapis lazuli
Sinh nhật phong cách street dance
Tổ chức sinh nhật tại nhà classical
Dịch vụ sinh nhật sáng chói hơn hết
Tiệc sinh nhật cho nhà phân tích học
Thuê nhóm nhảy street sinh nhật
Sinh nhật chủ đề huyền bí
Tổ chức sinh nhật tại nhà grunge
Dịch vụ sinh nhật rực rỡ hơn hết
Tiệc sinh nhật cho nhà xã hội học
Trang trí sinh nhật bằng đồ malachite
Sinh nhật phong cách contemporary
Tổ chức sinh nhật tại nhà metal
Dịch vụ sinh nhật lung linh hơn hết
Tiệc sinh nhật cho nhà giáo dục học
Thuê nhóm nhảy contemporary sinh nhật
Sinh nhật chủ đề nhiệt đới
Tổ chức sinh nhật tại nhà punk rock
Dịch vụ sinh nhật đẹp hơn hết
Tiệc sinh nhật cho nhà tâm lý học
Trang trí sinh nhật bằng đồ amber
Sinh nhật phong cách ballet
Tổ chức sinh nhật tại nhà alternative
Dịch vụ sinh nhật hoàn toàn hơn hết
Tiệc sinh nhật cho nhà ngôn ngữ học
Thuê nhóm nhảy ballet sinh nhật
Sinh nhật chủ đề mùa đông
Tổ chức sinh nhật tại nhà ska
Dịch vụ sinh nhật độc đáo hơn hết
Trợ lý AI thông minh nhất cho bạn
Khám phá công nghệ AI tại đây
Trải nghiệm trợ lý ảo tuyệt vời
Công cụ AI hỗ trợ mọi công việc
Tăng năng suất với AI thông minh
AI thay đổi cách bạn làm việc
Trợ lý ảo đáng tin cậy nhất
Khám phá tương lai với AI
Công nghệ AI tiên tiến cho bạn
Hỗ trợ thông minh từ trợ lý AI
AI giúp bạn tiết kiệm thời gian
Trợ lý ảo tốt nhất hiện nay
Công nghệ AI đỉnh cao
Khám phá sức mạnh của AI
Trợ lý AI hỗ trợ 24/7
Công cụ AI cho mọi nhu cầu
AI thông minh, nhanh chóng
Trợ lý ảo dẫn đầu xu hướng
Công nghệ AI dành cho bạn
Hỗ trợ công việc với AI
Trợ lý AI tối ưu hóa công việc
Khám phá AI hiện đại
Công cụ AI đáng kinh ngạc
Trợ lý ảo thông minh vượt trội
AI giúp bạn thành công
Công nghệ AI đáng tin cậy
Trợ lý ảo cho tương lai
Khám phá công cụ AI mới
AI hỗ trợ mọi lúc mọi nơi
Trợ lý ảo thông minh hàng đầu
Công nghệ AI thay đổi cuộc sống
Hỗ trợ tối đa với AI
Trợ lý AI sáng tạo nhất
Công cụ AI mạnh mẽ
Khám phá trợ lý ảo AI
AI thông minh cho mọi người
Trợ lý ảo tối ưu nhất
Công nghệ AI vượt trội
Hỗ trợ công việc bằng AI
Trợ lý AI cho mọi ngành
Khám phá sức mạnh AI
Công cụ AI thông minh nhất
Trợ lý ảo dẫn dắt tương lai
AI hỗ trợ không giới hạn
Công nghệ AI sáng tạo
Trợ lý ảo hiệu quả nhất
Khám phá công nghệ AI đỉnh cao
AI giúp bạn tỏa sáng
Trợ lý ảo thông minh toàn diện
Công cụ AI thay đổi mọi thứ
Trợ lý AI giúp bạn làm việc nhanh hơn
Công nghệ AI hiện đại nhất hiện nay
Trải nghiệm AI thông minh vượt bậc
Công cụ AI hỗ trợ sáng tạo
Trợ lý ảo dành cho mọi nhà
AI tối ưu hóa công việc hàng ngày
Khám phá trợ lý AI tiên tiến
Công nghệ AI cho doanh nghiệp
Trợ lý ảo giúp bạn tiết kiệm sức lực
AI thông minh hỗ trợ cá nhân
Công cụ AI cho tương lai gần
Trợ lý ảo tối ưu mọi tác vụ
Khám phá công nghệ AI độc đáo
AI giúp bạn đạt hiệu quả cao
Trợ lý ảo thông minh và thân thiện
Công nghệ AI dành cho mọi ngành
Trợ lý AI hỗ trợ liên tục
Khám phá sức mạnh AI vượt trội
Công cụ AI giúp bạn nổi bật
Trợ lý ảo cho công việc hiện đại
AI thông minh dẫn đầu thời đại
Công nghệ AI hỗ trợ toàn diện
Trợ lý ảo giúp bạn sáng tạo hơn
Khám phá AI thông minh hàng đầu
Công cụ AI tối ưu cho bạn
Trợ lý AI thay đổi cách làm việc
Công nghệ AI mạnh mẽ và linh hoạt
Trợ lý ảo thông minh cho mọi người
AI hỗ trợ công việc hiệu quả
Khám phá công cụ AI sáng tạo
Trợ lý ảo giúp bạn thành công hơn
Công nghệ AI dẫn dắt tương lai
Trợ lý AI tối ưu cho doanh nghiệp
AI thông minh hỗ trợ mọi lúc
Công cụ AI dành cho sáng tạo
Trợ lý ảo giúp bạn tiết kiệm chi phí
Khám phá trợ lý AI độc quyền
Công nghệ AI thay đổi mọi ngành
Trợ lý AI thông minh cho cuộc sống
AI hỗ trợ công việc nhóm
Công cụ AI hiện đại và mạnh mẽ
Trợ lý ảo tối ưu hóa thời gian
Khám phá sức mạnh AI thông minh
Công nghệ AI cho mọi nhu cầu
Trợ lý AI giúp bạn đi trước thời đại
AI thông minh hỗ trợ cá nhân hóa
Công cụ AI tối ưu cho công việc
Trợ lý ảo dẫn đầu công nghệ
Khám phá AI vượt xa mong đợi
Công nghệ AI sáng tạo không ngừng
Trợ lý AI thông minh và hiệu quả
AI hỗ trợ bạn mọi lúc mọi nơi
Công cụ AI thay đổi cách sống
Trợ lý ảo tối ưu cho tương lai
Khám phá công nghệ AI tiên phong
Công nghệ AI giúp bạn tỏa sáng
Trợ lý AI hỗ trợ công việc sáng tạo
AI thông minh cho mọi lĩnh vực
Công cụ AI dẫn đầu xu hướng
Trợ lý ảo giúp bạn phát triển
Khám phá trợ lý AI mạnh mẽ
Công nghệ AI hỗ trợ không ngừng
Trợ lý AI thông minh cho doanh nhân
AI tối ưu hóa mọi quy trình
Công cụ AI sáng tạo và thông minh
Trợ lý ảo giúp bạn quản lý thời gian
Khám phá sức mạnh của công nghệ AI
Công nghệ AI thay đổi cách nghĩ
Trợ lý AI hỗ trợ mọi dự án
AI thông minh cho cuộc sống hiện đại
Công cụ AI giúp bạn đi xa hơn
Trợ lý ảo tối ưu cho sáng tạo
Khám phá AI thông minh vượt trội
Công nghệ AI dành cho tương lai
Trợ lý AI giúp bạn thành công lớn
AI hỗ trợ công việc hiệu quả hơn
Công cụ AI thông minh và linh hoạt
Trợ lý ảo dẫn đầu mọi xu hướng
Khám phá công nghệ AI sáng tạo
Công nghệ AI tối ưu hóa cuộc sống
Trợ lý AI thông minh cho mọi ngành
AI giúp bạn quản lý công việc
Công cụ AI dành cho thành công
Trợ lý ảo hỗ trợ không giới hạn
Khám phá trợ lý AI thông minh nhất
Công nghệ AI thay đổi mọi thứ
Trợ lý AI tối ưu cho doanh nghiệp
AI thông minh hỗ trợ sáng tạo
Công cụ AI giúp bạn tiết kiệm thời gian
Trợ lý ảo dẫn dắt tương lai
Khám phá sức mạnh AI hiện đại
Công nghệ AI cho mọi người
Trợ lý AI thông minh và đáng tin cậy
AI hỗ trợ bạn vượt qua thử thách
Công cụ AI tối ưu hóa công việc
Trợ lý ảo giúp bạn phát triển nhanh
Khám phá công nghệ AI tiên tiến
Công nghệ AI sáng tạo cho bạn
Trợ lý AI hỗ trợ mọi nhu cầu
AI thông minh thay đổi cuộc chơi
Công cụ AI dẫn đầu mọi lĩnh vực
Trợ lý ảo tối ưu cho mọi tác vụ
Khám phá trợ lý AI vượt trội
Công nghệ AI giúp bạn thành công
Trợ lý AI thông minh cho tương lai
AI hỗ trợ công việc sáng tạo
Công cụ AI thông minh vượt bậc
Trợ lý ảo giúp bạn quản lý hiệu quả
Khám phá sức mạnh AI sáng tạo
Công nghệ AI tối ưu cho cuộc sống
Trợ lý AI thông minh và hiện đại
AI giúp bạn đi trước xu hướng
Công cụ AI hỗ trợ không ngừng
Trợ lý ảo dẫn đầu công nghệ AI
Khám phá công nghệ AI thông minh
Công nghệ AI thay đổi cách làm việc
Trợ lý AI tối ưu hóa sáng tạo
AI thông minh cho mọi công việc
Công cụ AI giúp bạn phát triển
Trợ lý ảo hỗ trợ mọi lúc
Khám phá trợ lý AI tiên phong
Công nghệ AI sáng tạo vượt trội
Trợ lý AI thông minh cho doanh nghiệp
AI giúp bạn tối ưu hóa thời gian
Công cụ AI mạnh mẽ cho bạn
Trợ lý ảo dẫn dắt mọi ngành
Khám phá sức mạnh AI thông minh
Công nghệ AI hỗ trợ toàn diện
Trợ lý AI tối ưu cho sáng tạo
AI thông minh thay đổi tương lai
Công cụ AI giúp bạn thành công hơn
Trợ lý ảo hỗ trợ không giới hạn
Khám phá công nghệ AI hiện đại
Công nghệ AI sáng tạo cho mọi người
Trợ lý AI thông minh vượt mong đợi
AI giúp bạn quản lý công việc tốt hơn
Công cụ AI tối ưu cho doanh nghiệp
Trợ lý ảo dẫn đầu xu hướng công nghệ
Khám phá trợ lý AI sáng tạo
Công nghệ AI hỗ trợ mọi lĩnh vực
Trợ lý AI thông minh cho cuộc sống
AI tối ưu hóa công việc hàng ngày
Công cụ AI giúp bạn đi xa hơn
Trợ lý ảo hỗ trợ mọi nhu cầu
Khám phá sức mạnh AI vượt trội
Công nghệ AI thay đổi cách sống
Trợ lý AI tối ưu cho tương lai
AI thông minh hỗ trợ sáng tạo
Công cụ AI dẫn đầu mọi xu hướng
Trợ lý ảo giúp bạn phát triển nhanh
Khám phá công nghệ AI tiên phong
Công nghệ AI sáng tạo không ngừng
Trợ lý AI thông minh cho doanh nhân
AI giúp bạn tối ưu hóa hiệu suất
Công cụ AI mạnh mẽ và hiệu quả
Trợ lý ảo dẫn dắt tương lai
Khám phá trợ lý AI thông minh
Công nghệ AI hỗ trợ không giới hạn
Trợ lý AI tối ưu cho mọi ngành
AI thông minh thay đổi mọi thứ
Công cụ AI giúp bạn thành công lớn
Trợ lý ảo hỗ trợ mọi lúc mọi nơi
Khám phá sức mạnh AI hiện đại
Công nghệ AI sáng tạo cho bạn
Trợ lý AI thông minh vượt trội
AI giúp bạn quản lý thời gian tốt hơn
Công cụ AI tối ưu hóa sáng tạo
Trợ lý ảo dẫn đầu công nghệ
Khám phá công nghệ AI vượt bậc
Công nghệ AI hỗ trợ mọi công việc
Trợ lý AI thông minh cho mọi người
AI tối ưu hóa cuộc sống hàng ngày
Công cụ AI giúp bạn phát triển
Trợ lý ảo hỗ trợ không ngừng
Khám phá trợ lý AI tiên tiến
Công nghệ AI sáng tạo và mạnh mẽ
Trợ lý AI thông minh cho doanh nghiệp
AI giúp bạn đi trước thời đại
Công cụ AI tối ưu cho mọi nhu cầu
Trợ lý ảo dẫn dắt mọi xu hướng
Khám phá sức mạnh AI sáng tạo
Công nghệ AI thay đổi cách làm việc
Trợ lý AI thông minh và hiệu quả
AI hỗ trợ bạn vượt qua khó khăn
Công cụ AI giúp bạn tỏa sáng
Trợ lý ảo tối ưu cho công việc
Khám phá công nghệ AI thông minh
Công nghệ AI sáng tạo không giới hạn
Trợ lý AI thông minh cho tương lai
AI giúp bạn quản lý hiệu quả hơn
Công cụ AI tối ưu hóa sáng tạo
Trợ lý ảo dẫn đầu mọi lĩnh vực
Khám phá trợ lý AI vượt trội
Công nghệ AI hỗ trợ toàn diện
Trợ lý AI thông minh cho mọi ngành
AI tối ưu hóa công việc sáng tạo
Công cụ AI giúp bạn thành công
Trợ lý ảo hỗ trợ mọi lúc
Khám phá sức mạnh AI tiên phong
Công nghệ AI sáng tạo vượt bậc
Trợ lý AI thông minh và mạnh mẽ
AI giúp bạn tối ưu hóa thời gian
Công cụ AI dẫn đầu công nghệ
Trợ lý ảo tối ưu cho doanh nghiệp
Khám phá công nghệ AI hiện đại
Công nghệ AI hỗ trợ không ngừng
Trợ lý AI thông minh cho cuộc sống
AI tối ưu hóa mọi công việc
Công cụ AI giúp bạn phát triển nhanh
Trợ lý ảo dẫn dắt tương lai
Khám phá trợ lý AI sáng tạo
Công nghệ AI thay đổi mọi ngành
Trợ lý AI thông minh vượt trội
AI giúp bạn quản lý công việc
Công cụ AI tối ưu cho sáng tạo
Trợ lý ảo hỗ trợ mọi nhu cầu
Khám phá sức mạnh AI thông minh
Công nghệ AI sáng tạo cho bạn
Trợ lý AI thông minh và hiệu quả
AI tối ưu hóa cuộc sống hiện đại
Công cụ AI giúp bạn đi trước xu hướng
Trợ lý ảo dẫn đầu mọi xu hướng
Khám phá công nghệ AI tiên tiến
Công nghệ AI hỗ trợ toàn diện
Trợ lý AI thông minh cho doanh nghiệp
AI giúp bạn tối ưu hóa công việc
Công cụ AI sáng tạo và mạnh mẽ
Trợ lý ảo tối ưu cho tương lai
Khám phá trợ lý AI vượt bậc
Công nghệ AI thay đổi cách sống
Trợ lý AI thông minh cho mọi người
AI hỗ trợ bạn thành công lớn
Công cụ AI giúp bạn phát triển
Trợ lý ảo dẫn dắt mọi lĩnh vực
Khám phá sức mạnh AI sáng tạo
Công nghệ AI tối ưu cho bạn
Trợ lý AI thông minh và đáng tin cậy
AI giúp bạn quản lý thời gian
Công cụ AI hỗ trợ không giới hạn
Trợ lý ảo tối ưu hóa sáng tạo
Khám phá công nghệ AI thông minh
Công nghệ AI sáng tạo vượt trội
Trợ lý AI thông minh cho doanh nhân
AI tối ưu hóa mọi quy trình
Công cụ AI giúp bạn tỏa sáng
Trợ lý ảo dẫn đầu công nghệ
Khám phá trợ lý AI tiên phong
Công nghệ AI hỗ trợ mọi lúc
Trợ lý AI thông minh vượt mong đợi
AI giúp bạn đi trước thời đại
Công cụ AI tối ưu cho công việc
Trợ lý ảo hỗ trợ không ngừng
Khám phá sức mạnh AI hiện đại
Công nghệ AI sáng tạo cho mọi ngành
Trợ lý AI thông minh và hiệu quả
AI tối ưu hóa cuộc sống hàng ngày
Công cụ AI giúp bạn phát triển nhanh
Trợ lý ảo dẫn dắt tương lai
Khám phá công nghệ AI vượt trội
Công nghệ AI hỗ trợ toàn diện
Trợ lý AI thông minh cho mọi người
AI giúp bạn quản lý công việc
Công cụ AI tối ưu hóa sáng tạo
Trợ lý ảo hỗ trợ mọi nhu cầu
Khám phá trợ lý AI sáng tạo
Công nghệ AI thay đổi mọi thứ
Trợ lý AI thông minh vượt bậc
AI tối ưu hóa công việc hiệu quả
Công cụ AI giúp bạn thành công
Trợ lý ảo dẫn đầu mọi xu hướng
Khám phá sức mạnh AI thông minh
Công nghệ AI sáng tạo không ngừng
Trợ lý AI thông minh cho doanh nghiệp
AI giúp bạn tối ưu hóa thời gian
Công cụ AI hỗ trợ không giới hạn
Trợ lý ảo tối ưu cho tương lai
Khám phá công nghệ AI tiên tiến
Công nghệ AI sáng tạo vượt trội
Trợ lý AI thông minh và mạnh mẽ
AI tối ưu hóa mọi công việc
Công cụ AI giúp bạn phát triển
Trợ lý ảo dẫn dắt mọi lĩnh vực
Khám phá trợ lý AI vượt trội
Công nghệ AI hỗ trợ toàn diện
Trợ lý AI thông minh cho mọi ngành
AI giúp bạn quản lý hiệu quả
Công cụ AI tối ưu hóa sáng tạo
Trợ lý ảo hỗ trợ không ngừng
Khám phá sức mạnh AI hiện đại
Công nghệ AI sáng tạo cho bạn
Trợ lý AI thông minh vượt mong đợi
AI tối ưu hóa cuộc sống hiện đại
Công cụ AI giúp bạn đi trước xu hướng
Trợ lý ảo dẫn đầu công nghệ
Khám phá công nghệ AI thông minh
Công nghệ AI hỗ trợ mọi lúc
Trợ lý AI thông minh cho doanh nhân
AI giúp bạn tối ưu hóa công việc
Công cụ AI sáng tạo và hiệu quả
Trợ lý ảo tối ưu cho mọi người
Khám phá trợ lý AI tiên phong
Công nghệ AI thay đổi cách sống
Trợ lý AI thông minh vượt trội
AI tối ưu hóa mọi quy trình
Công cụ AI giúp bạn thành công lớn
Trợ lý ảo dẫn dắt tương lai
Khám phá sức mạnh AI sáng tạo
Công nghệ AI hỗ trợ không giới hạn
Trợ lý AI thông minh cho mọi ngành
AI giúp bạn quản lý thời gian
Công cụ AI tối ưu cho sáng tạo
Trợ lý ảo hỗ trợ mọi nhu cầu
Khám phá công nghệ AI vượt bậc
Công nghệ AI sáng tạo cho bạn
Trợ lý AI thông minh và hiệu quả
AI tối ưu hóa công việc hàng ngày
Công cụ AI giúp bạn phát triển
Trợ lý ảo dẫn đầu mọi xu hướng
Khám phá trợ lý AI thông minh
Công nghệ AI hỗ trợ toàn diện
Trợ lý AI thông minh vượt mong đợi
AI giúp bạn đi trước thời đại
Công cụ AI tối ưu cho doanh nghiệp
Trợ lý ảo hỗ trợ không ngừng
Khám phá sức mạnh AI hiện đại
Công nghệ AI sáng tạo không ngừng
Trợ lý AI thông minh cho mọi người
AI tối ưu hóa mọi công việc
Công cụ AI giúp bạn thành công
Trợ lý ảo dẫn dắt mọi lĩnh vực
Khám phá công nghệ AI tiên tiến
Công nghệ AI hỗ trợ mọi lúc
Trợ lý AI thông minh vượt trội
AI giúp bạn quản lý hiệu quả
Công cụ AI tối ưu hóa sáng tạo
Trợ lý ảo hỗ trợ không giới hạn
Khám phá trợ lý AI sáng tạo
Công nghệ AI thay đổi cách sống
Trợ lý AI thông minh cho doanh nghiệp
AI tối ưu hóa công việc sáng tạo
Công cụ AI giúp bạn phát triển nhanh
Trợ lý ảo dẫn đầu công nghệ
Khám phá sức mạnh AI vượt bậc
Công nghệ AI sáng tạo cho bạn
Trợ lý AI thông minh và hiệu quả
AI giúp bạn đi trước xu hướng
Công cụ AI tối ưu cho mọi người
Trợ lý ảo hỗ trợ mọi lúc mọi nơi
Khám phá công nghệ AI thông minh
Công nghệ AI hỗ trợ không ngừng
Trợ lý AI thông minh vượt mong đợi
AI tối ưu hóa cuộc sống hiện đại
Công cụ AI giúp bạn thành công lớn
Trợ lý ảo dẫn dắt tương lai
Khám phá trợ lý AI tiên phong
Công nghệ AI sáng tạo vượt trội
Trợ lý AI thông minh cho doanh nhân
AI giúp bạn quản lý thời gian
Công cụ AI tối ưu hóa công việc
Trợ lý ảo hỗ trợ không giới hạn
Khám phá sức mạnh AI sáng tạo
Công nghệ AI thay đổi mọi ngành
Trợ lý AI thông minh và mạnh mẽ
AI tối ưu hóa mọi quy trình
Công cụ AI giúp bạn phát triển
Trợ lý ảo dẫn đầu mọi xu hướng
Khám phá công nghệ AI vượt trội
Công nghệ AI hỗ trợ toàn diện
Trợ lý AI thông minh cho mọi người
AI giúp bạn đi trước thời đại
Công cụ AI tối ưu cho sáng tạo
Trợ lý ảo hỗ trợ mọi lúc
Khám phá trợ lý AI thông minh
Công nghệ AI sáng tạo không ngừng
Trợ lý AI thông minh vượt bậc
AI tối ưu hóa công việc hiệu quả
Công cụ AI giúp bạn thành công
Trợ lý ảo dẫn dắt mọi lĩnh vực
Khám phá sức mạnh AI tiên phong
Công nghệ AI hỗ trợ không giới hạn
Trợ lý AI thông minh cho doanh nghiệp
AI giúp bạn quản lý hiệu quả
Công cụ AI tối ưu hóa sáng tạo
Trợ lý ảo hỗ trợ mọi nhu cầu
Khám phá công nghệ AI hiện đại
Công nghệ AI sáng tạo cho bạn
Trợ lý AI thông minh và hiệu quả
AI tối ưu hóa cuộc sống hàng ngày
Công cụ AI giúp bạn phát triển nhanh
Trợ lý ảo dẫn đầu công nghệ
Khám phá trợ lý AI vượt trội
Công nghệ AI hỗ trợ toàn diện
Trợ lý AI thông minh vượt mong đợi
AI giúp bạn đi trước xu hướng
Công cụ AI tối ưu cho doanh nghiệp
Trợ lý ảo hỗ trợ không ngừng
Khám phá sức mạnh AI sáng tạo
Công nghệ AI thay đổi mọi thứ
Trợ lý AI thông minh cho mọi người
AI tối ưu hóa mọi công việc
Công cụ AI giúp bạn thành công lớn
Trợ lý ảo dẫn dắt tương lai
Khám phá công nghệ AI tiên phong
Công nghệ AI sáng tạo vượt trội
Trợ lý AI thông minh và mạnh mẽ
AI giúp bạn quản lý thời gian
Công cụ AI tối ưu hóa công việc
Trợ lý ảo hỗ trợ không giới hạn
Khám phá trợ lý AI thông minh
Công nghệ AI hỗ trợ mọi lúc
Trợ lý AI thông minh vượt bậc
AI tối ưu hóa cuộc sống hiện đại
Công cụ AI giúp bạn phát triển
Trợ lý ảo dẫn đầu mọi xu hướng
Khám phá sức mạnh AI vượt trội
Công nghệ AI sáng tạo cho bạn
Trợ lý AI thông minh và hiệu quả
AI giúp bạn đi trước thời đại
Công cụ AI tối ưu cho sáng tạo
Trợ lý ảo hỗ trợ mọi nhu cầu
Khám phá công nghệ AI hiện đại
Công nghệ AI hỗ trợ không ngừng
Trợ lý AI thông minh vượt mong đợi
AI tối ưu hóa mọi quy trình
Công cụ AI giúp bạn thành công
Trợ lý ảo dẫn dắt mọi lĩnh vực
Khám phá trợ lý AI tiên phong
Công nghệ AI sáng tạo vượt trội
Trợ lý AI thông minh cho doanh nghiệp
AI giúp bạn quản lý hiệu quả
Công cụ AI tối ưu hóa sáng tạo
Trợ lý ảo hỗ trợ không giới hạn
Khám phá sức mạnh AI thông minh
Công nghệ AI thay đổi cách sống
Trợ lý AI thông minh và mạnh mẽ
AI tối ưu hóa công việc hàng ngày
Công cụ AI giúp bạn phát triển nhanh
Trợ lý ảo dẫn đầu công nghệ
Khám phá công nghệ AI vượt bậc
Công nghệ AI sáng tạo cho bạn
Trợ lý AI thông minh vượt trội
AI giúp bạn đi trước xu hướng
Công cụ AI tối ưu cho mọi người
Trợ lý ảo hỗ trợ mọi lúc mọi nơi
Khám phá trợ lý AI thông minh
Công nghệ AI hỗ trợ không ngừng
Trợ lý AI thông minh vượt mong đợi
AI tối ưu hóa cuộc sống hiện đại
Công cụ AI giúp bạn thành công lớn
Trợ lý ảo dẫn dắt tương lai
Khám phá sức mạnh AI tiên phong
Công nghệ AI sáng tạo vượt trội
Trợ lý AI thông minh cho doanh nhân
AI giúp bạn quản lý thời gian
Công cụ AI tối ưu hóa công việc
Trợ lý ảo hỗ trợ không giới hạn
Khám phá công nghệ AI hiện đại
Công nghệ AI hỗ trợ mọi lúc
Trợ lý AI thông minh vượt bậc
AI tối ưu hóa mọi quy trình
Công cụ AI giúp bạn phát triển
Trợ lý ảo dẫn đầu mọi xu hướng
Khám phá trợ lý AI thông minh
Công nghệ AI sáng tạo không ngừng
Trợ lý AI thông minh vượt trội
AI giúp bạn đi trước thời đại
Công cụ AI tối ưu cho sáng tạo
Trợ lý ảo hỗ trợ mọi nhu cầu
Khám phá sức mạnh AI vượt bậc
Công nghệ AI thay đổi cách sống
Trợ lý AI thông minh và hiệu quả
AI tối ưu hóa công việc hàng ngày
Công cụ AI giúp bạn thành công
Trợ lý ảo dẫn dắt mọi lĩnh vực
Khám phá công nghệ AI tiên phong
Công nghệ AI sáng tạo vượt trội
Trợ lý AI thông minh cho doanh nghiệp
AI giúp bạn quản lý hiệu quả
Công cụ AI tối ưu hóa sáng tạo
Trợ lý ảo hỗ trợ không ngừng
Khám phá trợ lý AI thông minh
Công nghệ AI hỗ trợ toàn diện
Trợ lý AI thông minh vượt mong đợi
AI tối ưu hóa mọi công việc
Công cụ AI giúp bạn phát triển nhanh
Trợ lý ảo dẫn đầu công nghệ
Khám phá sức mạnh AI sáng tạo
Công nghệ AI thay đổi mọi ngành
Trợ lý AI thông minh và mạnh mẽ
AI giúp bạn đi trước xu hướng
Công cụ AI tối ưu cho mọi người
Trợ lý ảo hỗ trợ mọi lúc mọi nơi
Khám phá công nghệ AI vượt trội
Công nghệ AI sáng tạo không ngừng
Trợ lý AI thông minh vượt bậc
AI tối ưu hóa cuộc sống hiện đại
Công cụ AI giúp bạn thành công lớn
Trợ lý ảo dẫn dắt tương lai
Khám phá trợ lý AI tiên phong
Công nghệ AI hỗ trợ không giới hạn
Trợ lý AI thông minh cho doanh nhân
AI giúp bạn quản lý thời gian
Công cụ AI tối ưu hóa công việc
Trợ lý ảo hỗ trợ mọi nhu cầu
Khám phá sức mạnh AI thông minh
Công nghệ AI sáng tạo cho bạn
Trợ lý AI thông minh và hiệu quả
AI tối ưu hóa mọi quy trình
Công cụ AI giúp bạn phát triển
Trợ lý ảo dẫn đầu mọi xu hướng
Khám phá công nghệ AI hiện đại
Công nghệ AI hỗ trợ toàn diện
Trợ lý AI thông minh vượt trội
AI giúp bạn đi trước thời đại
Công cụ AI tối ưu cho sáng tạo
Trợ lý ảo hỗ trợ không ngừng
Khám phá trợ lý AI thông minh
Công nghệ AI sáng tạo vượt bậc
Trợ lý AI thông minh cho doanh nghiệp
AI tối ưu hóa công việc hàng ngày
Công cụ AI giúp bạn thành công
Trợ lý ảo dẫn dắt mọi lĩnh vực
Khám phá sức mạnh AI tiên phong
Công nghệ AI hỗ trợ mọi lúc
Trợ lý AI thông minh vượt mong đợi
AI giúp bạn quản lý hiệu quả
Công cụ AI tối ưu hóa sáng tạo
Trợ lý ảo hỗ trợ không giới hạn
Khám phá công nghệ AI vượt trội
Công nghệ AI sáng tạo cho bạn
Trợ lý AI thông minh và mạnh mẽ
AI tối ưu hóa mọi công việc
Công cụ AI giúp bạn phát triển nhanh
Trợ lý ảo dẫn đầu công nghệ
Khám phá trợ lý AI thông minh
Công nghệ AI hỗ trợ không ngừng
Trợ lý AI thông minh vượt bậc
AI giúp bạn đi trước xu hướng
Công cụ AI tối ưu cho mọi người
Trợ lý ảo hỗ trợ mọi lúc mọi nơi
Khám phá sức mạnh AI sáng tạo
Công nghệ AI thay đổi cách sống
Trợ lý AI thông minh vượt trội
AI tối ưu hóa cuộc sống hiện đại
Công cụ AI giúp bạn thành công lớn
Trợ lý ảo dẫn dắt tương lai
Khám phá công nghệ AI tiên phong
Công nghệ AI sáng tạo không ngừng
Trợ lý AI thông minh cho doanh nhân
AI giúp bạn quản lý thời gian
Công cụ AI tối ưu hóa công việc
Trợ lý ảo hỗ trợ không giới hạn
Khám phá trợ lý AI thông minh
Công nghệ AI hỗ trợ mọi lúc
Trợ lý AI thông minh vượt mong đợi
AI tối ưu hóa mọi quy trình
Công cụ AI giúp bạn phát triển
Trợ lý ảo dẫn đầu mọi xu hướng
Khám phá sức mạnh AI vượt trội
Công nghệ AI sáng tạo cho bạn
Trợ lý AI thông minh và hiệu quả
AI giúp bạn đi trước thời đại
Công cụ AI tối ưu cho sáng tạo
Trợ lý ảo hỗ trợ mọi nhu cầu
Khám phá công nghệ AI hiện đại
Công nghệ AI hỗ trợ không ngừng
Trợ lý AI thông minh vượt bậc
AI tối ưu hóa công việc hàng ngày
Công cụ AI giúp bạn thành công
Trợ lý ảo dẫn dắt mọi lĩnh vực
Khám phá trợ lý AI tiên phong
Công nghệ AI sáng tạo vượt trội
Trợ lý AI thông minh cho doanh nghiệp
AI giúp bạn quản lý hiệu quả
Công cụ AI tối ưu hóa sáng tạo
Trợ lý ảo hỗ trợ không giới hạn
Khám phá sức mạnh AI thông minh
Công nghệ AI thay đổi cách sống
Trợ lý AI thông minh và mạnh mẽ
AI tối ưu hóa mọi công việc
Công cụ AI giúp bạn phát triển nhanh
Trợ lý ảo dẫn đầu công nghệ
Khám phá công nghệ AI vượt trội
Công nghệ AI sáng tạo cho bạn
Trợ lý AI thông minh vượt mong đợi
AI giúp bạn đi trước xu hướng
Công cụ AI tối ưu cho mọi người
Trợ lý ảo hỗ trợ mọi lúc mọi nơi
Khám phá trợ lý AI thông minh
Công nghệ AI hỗ trợ không ngừng
Trợ lý AI thông minh vượt bậc
AI tối ưu hóa cuộc sống hiện đại
Công cụ AI giúp bạn thành công lớn
Trợ lý ảo dẫn dắt tương lai
Khám phá sức mạnh AI tiên phong
Công nghệ AI sáng tạo vượt trội
Trợ lý AI thông minh cho doanh nhân
AI giúp bạn quản lý thời gian
Công cụ AI tối ưu hóa công việc
Trợ lý ảo hỗ trợ không giới hạn
Khám phá công nghệ AI hiện đại
Công nghệ AI hỗ trợ mọi lúc
Trợ lý AI thông minh vượt mong đợi
AI tối ưu hóa mọi quy trình
Công cụ AI giúp bạn phát triển
Trợ lý ảo dẫn đầu mọi xu hướng
Khám phá trợ lý AI thông minh
Công nghệ AI sáng tạo không ngừng
Trợ lý AI thông minh vượt trội
AI giúp bạn đi trước thời đại
Công cụ AI tối ưu cho sáng tạo
Trợ lý ảo hỗ trợ mọi nhu cầu
Khám phá sức mạnh AI vượt bậc
Công nghệ AI thay đổi cách sống
Trợ lý AI thông minh và hiệu quả
AI tối ưu hóa công việc hàng ngày
Công cụ AI giúp bạn thành công
Trợ lý ảo dẫn dắt mọi lĩnh vực
Khám phá công nghệ AI tiên phong
Công nghệ AI sáng tạo vượt trội
Trợ lý AI thông minh cho doanh nghiệp
AI giúp bạn quản lý hiệu quả
Công cụ AI tối ưu hóa sáng tạo
Trợ lý ảo hỗ trợ không giới hạn
Khám phá trợ lý AI thông minh
Công nghệ AI hỗ trợ toàn diện
Trợ lý AI thông minh vượt mong đợi
AI tối ưu hóa mọi công việc
Công cụ AI giúp bạn phát triển nhanh
Trợ lý ảo dẫn đầu công nghệ
Khám phá sức mạnh AI sáng tạo
Công nghệ AI thay đổi mọi ngành
Trợ lý AI thông minh và mạnh mẽ
AI giúp bạn đi trước xu hướng
Công cụ AI tối ưu cho mọi người
Trợ lý ảo hỗ trợ mọi lúc mọi nơi
Khám phá công nghệ AI vượt trội
Công nghệ AI sáng tạo không ngừng
Trợ lý AI thông minh vượt bậc
AI tối ưu hóa cuộc sống hiện đại
Công cụ AI giúp bạn thành công lớn
Trợ lý ảo dẫn dắt tương lai
Khám phá trợ lý AI tiên phong
Công nghệ AI hỗ trợ không giới hạn
Trợ lý AI thông minh cho doanh nhân
AI giúp bạn quản lý thời gian
Xổ số miền Nam Kết quả xổ số miền Nam XSMN hôm nay KQXS miền Nam XSMN trực tiếp KQXS hôm nay Xổ số kiến thiết miền Nam Dự đoán XSMN Xổ số miền Nam 24h XSMN chuẩn Kết quả xổ số nhanh Xổ số miền Nam hôm qua XSMN VIP Xổ số miền Nam 7 ngày Xổ số miền Nam chính xác XSMN 3 miền XSMN mới nhất Trực tiếp xổ số miền Nam Xổ số miền Nam hôm nay KQXS miền Nam chính xác Xổ số miền Nam hàng ngày Xổ số miền Nam nhanh nhất Dò vé số miền Nam Xổ số miền Nam chính thống Xổ số kiến thiết Kết quả xổ số miền Nam mới nhất XSMN cực nhanh Thống kê XSMN Dò xổ số miền Nam Xổ số online miền Nam KQXS hôm qua Xổ số nhanh nhất XSMN uy tín KQXS hôm nay nhanh nhất Dự đoán KQXS miền Nam Xổ số siêu tốc Xổ số VIP Xổ số miền Nam 30 ngày Lịch mở thưởng XSMN Xổ số hôm nay XSMN 2025 Dò vé số hôm nay Xổ số miền Nam miễn phí Trực tiếp KQXS miền Nam Dò xổ số nhanh Dự đoán XSMN chuẩn Xổ số 3 miền chính xác Thống kê xổ số miền Nam Dự đoán lô đề XSMN Kết quả XSMN online Kết quả xổ số 3 miền Dò xổ số VIP XSMN miễn phí Xổ số dễ trúng Xổ số miền Nam mỗi ngày Dự đoán XSMN hôm nay Thống kê kết quả XSMN Xổ số miền Nam hôm nay nhanh nhất Xổ số miền Nam mới nhất Xổ số miền Nam hôm qua Dự đoán xổ số miền Nam