By using aiohttp with the Paradigm API, you can leverage the power of asynchronous programming in Python to improve the speed of your API requests.
By using asyncio and the aiohttp library, you can send multiple requests simultaneously, significantly reducing wait time and improving response time for batch operations.
Efficiency and ScalabilityAsynchronous requests enable non-blocking operations, making your application more efficient and scalable, especially when making multiple simultaneous API calls.
asyncio is a Python library that provides a framework for writing concurrent code using the async and await syntax. It is particularly useful for high-level structured network code and I/O-bound operations. You can find more information about Asyncio here.
To use asynchronous features, use aiohttp.ClientSession. Initialize the session with your API key and the appropriate endpoint.
Copy
import aiohttpimport asyncioimport os# Retrieve authentication informationapi_key = os.getenv("PARADIGM_API_KEY")base_url = os.getenv("PARADIGM_BASE_URL", "https://paradigm.lighton.ai/api/v2")names = ["Alice", "Bob", "Charlie", "David", "Emma", "Frank", "Grace", "Hannah", "Ian", "Jessica", "Kevin", "Linda", "Michael", "Nancy", "Olivia", "Peter", "Quincy", "Rachel", "Samuel", "Tiffany"]# as an example we will use this batch of messagesmessages_batch = [[{"role": "user", "content": f"Say hello to the new user on Paradigm! Give a short one-sentence highly personalized welcome to: {name}"}] for name in names]
When comparing asynchronous execution with traditional synchronous (sequential) execution, asynchronous operations generally complete in much less time, with potential for even greater improvement depending on the length of different requests. This is particularly true for I/O-bound tasks like API requests. The efficiency gains from asynchronous execution come from its non-blocking nature, which allows other tasks to continue without waiting for I/O operations to complete.
Best Practices
Always use await with async functions to avoid runtime errors.
Reuse the same ClientSession for multiple requests to improve performance.
Always close the session properly using the async with context manager.
For Jupyter notebooks, run asynchronous code via a separate Python script using the magic command !python file_to_execute.py in a cell to avoid event loop issues.
By incorporating asynchronous requests into your application, you can achieve greater efficiency and scalability, particularly when handling a large number of API calls.
To compare synchronous and asynchronous API calls in a practical scenario, you can use the following snippet. This snippet will create a Python file, speed_test.py, implementing synchronous and asynchronous API requests, respectively. You can then run this script to observe the difference in execution time, demonstrating the efficiency of asynchronous programming for batch requests.
speed_test.py
Copy
import osimport timeimport requestsimport aiohttpimport asyncio# Configurationapi_key = os.getenv("PARADIGM_API_KEY")base_url = os.getenv("PARADIGM_BASE_URL", "https://paradigm.lighton.ai/api/v2")names = ["Alice", "Bob", "Charlie", "David", "Emma", "Frank", "Grace", "Hannah", "Ian", "Jessica", "Kevin", "Linda", "Michael", "Nancy", "Olivia", "Peter", "Quincy", "Rachel", "Samuel", "Tiffany"]# Synchronous function to send messagesdef sync_send_message(name): headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" } messages = [{"role": "user", "content": f"Say hello to the new user on Paradigm! Give a short one-sentence highly personalized welcome to: {name}"}] payload = { "model": "alfred-4.2", "messages": messages, "temperature": 0.4, "max_tokens": 150 } response = requests.post(f"{base_url}/chat/completions", headers=headers, json=payload) return response.json()# Asynchronous function to send messagesasync def async_send_message(session, messages, model="alfred-4.2", temperature=0.4, max_tokens=150): headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" } payload = { "model": model, "messages": messages, "temperature": temperature, "max_tokens": max_tokens } async with session.post(f"{base_url}/chat/completions", headers=headers, json=payload) as response: data = await response.json() return datadef sync_main(): responses = [] start_time = time.time() for name in names: response = sync_send_message(name) responses.append(response) duration = time.time() - start_time print(f"Synchronous execution took {duration:.2f} seconds.")async def async_main(): start_time = time.time() async with aiohttp.ClientSession() as session: tasks = [ async_send_message( session, [{"role": "user", "content": f"Say hello to the new user on Paradigm! Give a short one-sentence highly personalized welcome to: {name}"}], model="alfred-4.2", temperature=0.4 ) for name in names ] responses = await asyncio.gather(*tasks) duration = time.time() - start_time print(f"Asynchronous execution took {duration:.2f} seconds.")if __name__ == "__main__": async_start_time = time.time() asyncio.run(async_main()) async_times = time.time() - async_start_time sync_start_time = time.time() sync_main() sync_times = time.time() - sync_start_time improvement_factor = sync_times / async_times print(f"Improvement factor: {improvement_factor:.2f}")
To run the comparison:
Execute the code snippet above in a Jupyter notebook cell to create speed_test.py.
Run the script in the Jupyter notebook or a terminal using the command !python speed_test.py.
This script will first run the asynchronous version, displaying the total execution time. It will then run the synchronous version, doing the same. Comparing the two execution times will illustrate the efficiency gains achievable with asynchronous API calls.In our case, we obtained the following output:
Copy
Asynchronous execution took 1.86 seconds.Synchronous execution took 10.33 seconds.Improvement factor: 5.55
Leveraging asynchronous API requests via aiohttp can significantly improve application performance and scalability. As demonstrated, asynchronous execution can be nearly 5 times faster than synchronous methods, offering significant efficiency gains. This approach is essential for handling high-volume API interactions, ensuring application efficiency.