cosmosdb
21 TopicsMake your own private ChatGPT
Introduction Creating your own private ChatGPT allows you to leverage AI capabilities while ensuring data privacy and security. This guide walks you through building a secure, customized chatbot using tools like Azure OpenAI, Cosmos DB and Azure App service. Why Build a Private ChatGPT? With the rise of AI-driven applications, organizations, people often face challenges related to data privacy, customization, and integration. Building a private ChatGPT addresses these concerns by: Maintaining Data Privacy: Keep sensitive information within your infrastructure. Customizing Responses: Tailor the chatbot’s behavior and language to suit your requirements. Ensuring Security: Leverage enterprise-grade security protocols. Avoiding Data Sharing: Prevent your data from being used to train external models. If organizations do not take these measures their data may go into future model training and can leak your sensitive data to public. Eg: Chatgpt collects personal data mentioned in their privacy policy Prerequisites Before you begin, ensure you have: Access to Azure OpenAI Service. A development environment set up with Python. Basic knowledge of FastAPI and MongoDB. An Azure account with necessary permissions. If you do not have Azure subscription, try Azure for students for FREE. Step 1: Set Up Azure OpenAI Log in to the Azure Portal and create an Azure OpenAI resource. Deploy a model, such as GPT-4o (multimodal), and note down the endpoint and API key. Note there is also an option of keyless authentication. Configure permissions to control access. Step 2: Use Chatgpt like app sample You can select any repository to be as base template for your app, in this I will be using the third option AOAIchat. It is developed by me. GitHub - mckaywrigley/chatbot-ui: AI chat for any model. Azure-Samples/azure-search-openai-demo: A sample app for the Retrieval-Augmented Generation pattern running in Azure, using Azure AI Search for retrieval and Azure OpenAI large language models to power ChatGPT-style and Q&A experiences. sourabhkv/AOAIchat: Azure OpenAI chat This architecture diagram represents a typical flow for a private ChatGPT application with the following components: App UX (User Interface): This is the front-end application (mobile, web, or desktop) where users interact with the chatbot. It sends the user's input (prompt) and displays the AI's responses. App Service: Acts as the backend application, handling user requests and coordinating with other services. Functions: Receives user inputs and prepares them for processing by the Azure OpenAI service. Streams AI responses back to the App UX. Reads from and writes to Cosmos DB to manage chat history. Azure OpenAI Service: This is the core AI service, processing the user input and generating responses using models like GPT-4o. The App Service sends the user input (along with context) to this service and receives the AI-generated responses. Cosmos DB: A NoSQL database used to store and manage chat history. Operations: Writes user messages and AI-generated responses for future reference or analysis. Reads chat history to provide context for AI responses, enabling more intelligent and contextual conversations. Data Flow: User inputs are sent from the App UX to the App Service. The App Service forwards the input (with additional context, if needed) to Azure OpenAI. Azure OpenAI generates a response, which is streamed back to the App UX via the App Service. The App Service writes user inputs and AI responses to Cosmos DB for persistence. This architecture ensures scalability, secure data handling, and the ability to provide contextual responses by integrating database and AI services. What can you do with my template? AOAIchat supports personal, enterprise chat enabled by RAG People can enable RAG mode if they want to search within their database, else it behaves like normal ChatGPT. It supports multimodality, (supports image, text input) also depends on model deployed in Azure AI foundry. Step 3: Deploy to Azure Deploy a Cosmos DB account in nearest region Deploy Azure OpenAI model (gpt-4o, gpt-4o-mini recommended) Deploy Azure App service, try using container I would recommend B1plan to your nearest region, select docker registry sourabhkv/aoaichatdb:0.1 startup command uvicorn app:app --host 0.0.0.0 --port 80 After app service starts, put all environment variables The application requires the following environment variables to be set for proper configuration: Environment Variable Description AZURE_OPENAI_ENDPOINT The endpoint for Azure OpenAI API. AZURE_OPENAI_API_KEY API key for accessing Azure OpenAI. DEPLOYMENT_NAME Azure OpenAI deployment name. API_VERSION API version for Azure OpenAI. MAX_TOKENS Maximum tokens for API responses. MONGO_DETAILS MongoDB connection string. AZURE_OPENAI_ENDPOINT=<your_azure_openai_endpoint> AZURE_OPENAI_API_KEY=<your_azure_openai_api_key> DEPLOYMENT_NAME=<your_deployment_name> API_VERSION=<your_api_version> MAX_TOKENS=<max_tokens> MONGO_DETAILS=<your_mongo_connection_string> Optional feature: implement authentication to secure access. Within app service select Authentication and select service providers. I went with Entra based authentication with single tenant. There is option of multi-tenant, personal accounts as well. Restart App service and within 2 minutes your private ChatGPT is ready. Pricing Pricing may depend on the plan you have deployed resources and region. Check Azure calculator for price estimation. My estimate for pricing I deployed all my resources in Sweden central Cosmos DB config - Cosmos DB for MongoDB (RU) serverless config with single write master, 2 GB transactional storage, 2 backup plan (FREE) ~ 0.75$ Azure OpenAI service - plan S0, model gpt-4o-mini global deployment, Input 20000 tokens, Output 10000 tokens ~ 9.00$ App service plan - OS Linux, Tier B1, instance count 1 ~13.14$ Total monthly cost = 22.89$ This price may vary in future, in region I calculated my configuration in Azure calculator Governance Azure OpenAI provides content filters to block any kind of input that violates responsible AI practices. Categories include Hate and Fairness Sexual Violence Self-harm User Prompt Attacks (direct and indirect) The content filtering system detects and takes action on specific categories of potentially harmful content in both input prompts and output completions. Azure OpenAI Service includes default safety settings applied to all models set as medium. Content filters can be modified to different level depending on use case. It supports RAG, I have provided detailed solution for it in my GitHub. Practical implementation GE Aerospace, in partnership with Microsoft and Accenture, has launched a company-wide generative AI platform, leveraging Microsoft Azure and Azure OpenAI Service. This solution aims to transform asset tracking and compliance in aviation, enabling quick access to maintenance records and reducing manual processing time from days to minutes. It supports informed decision-making by providing insights into aircraft leasing, compliance gaps, and asset health. For enterprises implementing private ChatGPT solutions, this illustrates the potential of generative AI for streamlining document-intensive processes while ensuring data security and compliance through cloud-based infrastructure like Azure. GE Aerospace Launches Company-wide Generative AI Platform for Employees | GE Aerospace News Build your own private ChatGPT style app with enterprise-ready architecture - By Microsoft Mechanics How to make private ChatGPT for FREE? It can be FREE if all of the setup is running locally on your hardware. Cosmos DB <-> MongoDB. Azure OpenAI <-> Ollama / LM studio Refer this NOTE : I have used gpt-4o, gpt-4o-mini these values are hardcoded in webpage, if you are using other models, you might have to change them in index.html. App Service <-> Local machine Register for Github models to access API for FREE. Note: GitHub models have rate limit for different models. Useful links sourabhkv/AOAIchat: Azure OpenAI chat What is RAG? Get started with Azure OpenAI API Chat with Azure OpenAI models using your own data5KViews1like0CommentsGetting Started with Azure Cosmos DB SDK for TypeScript/JavaScript (4.2.0)
In this blog, we will walk through how to get started with Azure Cosmos DB SDK for TypeScript. Using the SDK, we'll cover how to set up a Cosmos DB client, interact with containers and items, and perform basic CRUD operations such as creating, updating, querying, and deleting items. By the end of this tutorial, you'll have a solid understanding of how to integrate Azure Cosmos DB into your TypeScript applications. What is an SDK? An SDK (Software Development Kit) is a collection of software development tools, libraries, and documentation that helps developers integrate and interact with a service or platform. In this case, the Azure Cosmos DB SDK for JavaScript/TypeScript provides a set of tools to interact with the Cosmos DB service, making it easier to perform operations like database and container management, data insertion, querying, and more. What is the Azure Cosmos DB Client Library for JavaScript/TypeScript? The Azure Cosmos DB Client Library for JavaScript/TypeScript is a package that allows developers to interact with Azure Cosmos DB through an easy-to-use API. It supports operations for creating databases, containers, and documents, as well as querying and updating documents. For our example, we will be using the SQL API, which is the most widely used API in Cosmos DB, and will show how to use the SDK for basic CRUD operations. To get started, make sure to install the SDK by running: npm i @azure/cosmos Prerequisites Before we can start interacting with Cosmos DB, we need to make sure we have the following prerequisites in place: 1. Azure Subscription You need an active Azure subscription. If you don’t have one, you can Sign up for a free Azure account, or Azure for students to get $100 azure credit. 2. Azure Cosmos DB Account To interact with Cosmos DB, you need to have a Azure Cosmos DB API account. Create one from the Azure Portal and keep the Endpoint URL and Primary Key handy. If you dont know how to do so check out this blog Getting started with Azure Cosmos Database (A Deep Dive) Overview of Cosmos Client Concepts Before diving into code, let's briefly go over the essential concepts you will interact with in Azure Cosmos DB. 1. Database A Database is a container for data in Cosmos DB. You can think of it as a high-level entity under which collections (containers) are stored. client.databases("<db id>") for creating new databases, and reading/querying all databases 2. Container A Container (formerly known as a collection) is a logical unit for storing items (documents). In Cosmos DB, each container is independent, and the items within a container are stored as JSON-like documents. Operations for reading, replacing, or deleting a specific, existing container by id. For creating new containers and reading/querying all containers; use .containers() ie .container(id).read() 3. Partition Key A Partition Key is used to distribute data across multiple physical partitions. When you insert data into a container, you must define a partition key. This helps Cosmos DB scale and optimize read and write operations. 4. Item An Item in Cosmos DB is a single piece of data that resides in a container. It is typically stored as a JSON document, and each item must have a unique ID and be associated with a partition key. Used to perform operations on a specific item. read method const { resource,statusCode } = await usersContainer.item(id, id).read<TUser>(); delete method const { statusCode } = await usersContainer.item(id, id).delete() 5. Items Items in Cosmos DB is used for Operations for creating new items and reading/querying all items. Used to perform operations on a many items. query method const { resources } = await usersContainer.items.query(querySpec).fetchAll(); read all items method const { resources} = await usersContainer.items.readAll<TUser[]>().fetchAll(); upsert (update or insert if item doesn't exist) const { resource } = await usersContainer.items.upsert<Partial<TUser>>(user); Environment Variables Setup Create a .env file in the root directory of your project with the following contents: NODE_ENV=DEVELOPMENT AZURE_COSMOS_DB_ENDPOINT=https://<your-cosmos-db-account>.documents.azure.com:443 AZURE_COSMOS_DB_KEY=<your-primary-key> AZURE_COSMOS_DB_DATABASE_NAME=<your-database-name> Let's set up a simple node app Initialize the Project Create a new directory for your project and navigate into it: mkdir simple-node-app cd simple-node-app Initialize a new Node.js project with default settings: npm init -y Install Dependencies Install the necessary dependencies for Express, TypeScript, and other tools: npm install @azure/cosmos zod uuid dotenv npm install --save-dev typescript rimraf tsx @types/node Configure TypeScript Create a tsconfig.json file in the root of your project with the following content: { "compilerOptions": { /* Base Options: */ "target": "es2022", "esModuleInterop": true, "skipLibCheck": true, "moduleResolution": "nodenext", "resolveJsonModule": true, /* Strictness */ "strict": true, "allowUnreachableCode": false, "noUnusedLocals": true, // "noUnusedParameters": true, "strictBindCallApply": true, /* If transpiling with TypeScript: */ "module": "NodeNext", "outDir": "dist", "rootDir": "./", "lib": [ "ES2022" ], }, "include": [ "./*.ts" ], "exclude": [ "node_modules", "dist" ] } Loading Environment Variables Create env.ts to securely and type safe load our env variables using zod add below code //./env.ts import dotenv from 'dotenv'; import { z } from 'zod'; // Load environment variables from .env file dotenv.config(); // Define the environment schema const EnvSchema = z.object({ // Node Server Configuration NODE_ENV: z.enum(['PRODUCTION', 'DEVELOPMENT']).default('DEVELOPMENT'), // CosmosDB Configuration AZURE_COSMOS_DB_ENDPOINT: z.string({ required_error: "AZURE_COSMOS_DB_ENDPOINT is required", invalid_type_error: "AZURE_COSMOS_DB_ENDPOINT must be a string", }), AZURE_COSMOS_DB_KEY: z.string({ required_error: "AZURE_COSMOS_DB_KEY is required", invalid_type_error: "AZURE_COSMOS_DB_KEY must be a string", }), AZURE_COSMOS_DB_DATABASE_NAME: z.string({ required_error: "AZURE_COSMOS_DB DB Name is required", invalid_type_error: "AZURE_COSMOS_DB must be a string", }), }); // Parse and validate the environment variables export const env = EnvSchema.parse(process.env); // Configuration object consolidating all settings const config = { nodeEnv: env.NODE_ENV, cosmos: { endpoint: env.AZURE_COSMOS_DB_ENDPOINT, key: env.AZURE_COSMOS_DB_KEY, database: env.AZURE_COSMOS_DB_DATABASE_NAME, containers: { users: 'usersContainer', }, }, }; export default config; Securely Setting Up Cosmos Client Instance To interact with Cosmos DB, we need to securely set up a CosmosClient instance. Here's how to initialize the client using environment variables for security. Create cosmosClient.ts and add below code // ./cosmosdb.config.ts import { PartitionKeyDefinitionVersion, PartitionKeyKind, Database, CosmosClient, Container, CosmosDbDiagnosticLevel, ErrorResponse, RestError, AbortError, TimeoutError } from '@azure/cosmos'; import config from './env'; let client: CosmosClient; let database: Database; let usersContainer: Container; async function initializeCosmosDB(): Promise<void> { try { // Create a new CosmosClient instance client = new CosmosClient({ endpoint: config.cosmos.endpoint, key: config.cosmos.key, diagnosticLevel: config.nodeEnv === 'PRODUCTION' ? CosmosDbDiagnosticLevel.info : CosmosDbDiagnosticLevel.debug }); // Create or get the database const { database: db } = await client.databases.createIfNotExists({ id: config.cosmos.database }); database = db; console.log(`Database '${config.cosmos.database}' initialized.`); // Initialize containers usersContainer = await createUsersContainer(); console.log('Cosmos DB initialized successfully.'); } catch (error: any) { return handleCosmosError(error); } } // Create the users container async function createUsersContainer(): Promise<Container> { const containerDefinition = { id: config.cosmos.containers.users, partitionKey: { paths: ['/id'], version: PartitionKeyDefinitionVersion.V2, kind: PartitionKeyKind.Hash, }, }; try { const { container } = await database.containers.createIfNotExists(containerDefinition); console.log(`'${container.id}' is ready.`); // const { container, diagnostics } = await database.containers.createIfNotExists(containerDefinition); // console.log(diagnostics.clientConfig) Contains aggregates diagnostic details for the client configuration // console.log(diagnostics.diagnosticNode) is intended for debugging non-production environments only return container; } catch (error: any) { return handleCosmosError(error); } } // Getter functions for containers function getUsersContainer(): Container { if (!usersContainer) { throw new Error('user container is not initialized.'); } return usersContainer; } const handleCosmosError = (error: any) => { if (error instanceof RestError) { throw new Error(`error: ${error.name}, message: ${error.message}`); } else if (error instanceof ErrorResponse) { throw new Error(`Error: ${error.message}, message: ${error.message}`); } else if (error instanceof AbortError) { throw new Error(error.message); } else if (error instanceof TimeoutError) { throw new Error(`TimeoutError code: ${error.code}, message: ${error.message}`); } else if (error.code === 409) { //if you try to create an item using an id that's already in use in your Cosmos DB database, a 409 error is returned throw new Error('Conflict occurred while creating an item using an existing ID.'); } else { console.log(JSON.stringify(error)); throw new Error('An error occurred while processing your request.'); } }; export { initializeCosmosDB, getUsersContainer, handleCosmosError }; This code is for initializing and interacting with Azure Cosmos DB using the Azure Cosmos SDK in a Node.js environment. Here's a brief and straightforward explanation of what each part does: Imports: The code imports several classes and enums from azure/cosmos that are needed to interact with Cosmos DB, like CosmosClient, Database, Container, and various error types. Variables: client, database, and usersContainer are declared to hold references to the Cosmos DB client, database, and a specific container for user data. initializeCosmosDB() function: Purpose: Initializes the Cosmos DB client, database, and container. Steps: Creates a new CosmosClient with credentials from the config (like endpoint, key, and diagnosticLevel). Attempts to create or retrieve a database (using createIfNotExists). Logs success and proceeds to initialize the usersContainer by calling createUsersContainer(). createUsersContainer() function: Purpose: Creates a container for storing user data in Cosmos DB with a partition key. Steps: Defines a partition key for the container (using /id as the partition key path). Attempts to create the container (or retrieves it if it already exists) with the given definition. Returns the container instance. getUsersContainer() function: Purpose: Returns the usersContainer object if it exists. Throws an error if the container is not initialized. handleCosmosError() function: Purpose: Handles errors thrown by Cosmos DB operations. Error Handling: It checks the type of error (e.g., RestError, ErrorResponse, AbortError, TimeoutError) and throws a formatted error message. Specifically handles conflict errors (HTTP 409) when attempting to create an item with an existing ID. Key Exported Functions: initializeCosmosDB: Initializes the Cosmos DB client and container. getUsersContainer: Returns the initialized users container. handleCosmosError: Custom error handler for Cosmos DB operations. Create User Schema This code defines data validation schemas using Zod, a TypeScript-first schema declaration and validation library. Create user.schema.ts and add below code // ./user.schema.ts import { z } from 'zod'; const coerceDate = z.preprocess((arg) => { if (typeof arg === 'string' || arg instanceof Date) { return new Date(arg); } else { return arg; } }, z.date()); export const userSchema = z.object({ id: z.string().uuid(), fullname: z.string(), email: z.string().email(), address: z.string(), createdAt: coerceDate.default(() => new Date()), }) const responseSchema = z.object({ statusCode: z.number(), message: z.string(), }) export type TResponse = z.infer<typeof responseSchema>; export type TUser = z.infer<typeof userSchema>; Here's a concise breakdown of the code: 1. coerceDate Schema: Purpose: This schema is designed to coerce a value into a Date object. How it works: z.preprocess() allows preprocessing of input before applying the base schema (z.date()). If the input is a string or an instance of Date, it converts it into a Date object. If the input is neither of these, it returns the original input without modification. Use: The coerceDate is used later in the userSchema to ensure that the createdAt field is always a valid Date object. 2. userSchema: Purpose: Defines the structure and validation rules for a user object. Fields: id: A required string that must be a valid UUID (z.string().uuid()). fullname: A required string. email: A required string that must be a valid email format (z.string().email()). address: A required string. createdAt: A Date field, which defaults to the current date/time if not provided (z.date() with default(() => new Date())), and uses coerceDate for preprocessing to ensure the value is a valid Date object. 3. responseSchema: Purpose: Defines the structure of a response object. Fields: statusCode: A required number (z.number()). message: A required string. 4. Type Inference: TResponse and TUser are TypeScript types that are automatically inferred from the responseSchema and userSchema, respectively. z.infer<typeof schema> generates TypeScript types based on the Zod schema, so: TResponse will be inferred as { statusCode: number, message: string }. TUser will be inferred as { id: string, fullname: string, email: string, address: string, createdAt: Date }. Let's implement Create Read Delete and Update Create user.service.ts and add the code below // ./user.service.ts import { SqlQuerySpec } from '@azure/cosmos'; import { getUsersContainer, handleCosmosError } from './cosmosClient'; import { TResponse, TUser } from './user.schema'; // Save user service export const saveUserService = async (user: TUser): Promise<Partial<TUser>> => { try { const usersContainer = getUsersContainer(); const res = await usersContainer.items.create<TUser>(user); if (!res.resource) { throw new Error('Failed to save user.'); } return res.resource; } catch (error: any) { return handleCosmosError(error); } }; // Update user service export const updateUserService = async (user: Partial<TUser>): Promise<Partial<TUser>> => { try { const usersContainer = getUsersContainer(); const { resource } = await usersContainer.items.upsert<Partial<TUser>>(user); if (!resource) { throw new Error('Failed to update user.'); } return resource; } catch (error: any) { return handleCosmosError(error); } }; // Fetch users service export const fetchUsersService = async (): Promise<TUser[] | null> => { try { const usersContainer = getUsersContainer(); const querySpec: SqlQuerySpec = { query: 'SELECT * FROM c ORDER BY c._ts DESC', }; const { resources } = await usersContainer.items.query<TUser[]>(querySpec).fetchAll(); return resources.flat(); } catch (error: any) { return handleCosmosError(error); } }; // Fetch user by email service export const fetchUserByEmailService = async (email: string): Promise<TUser | null> => { try { const usersContainer = getUsersContainer(); const querySpec: SqlQuerySpec = { query: 'SELECT * FROM c WHERE c.email = ', parameters: [ { name: '@email', value: email }, ], }; const { resources } = await usersContainer.items.query<TUser>(querySpec).fetchAll(); return resources.length > 0 ? resources[0] : null; } catch (error: any) { return handleCosmosError(error); } } // Fetch user by ID service export const fetchUserByIdService = async (id: string): Promise<TUser | null> => { try { const usersContainer = getUsersContainer(); const { resource } = await usersContainer.item(id, id).read<TUser>(); if (!resource) { return null; } return resource; } catch (error: any) { return handleCosmosError(error); } }; // Delete user by ID service export const deleteUserByIdService = async (id: string): Promise<TResponse> => { try { const usersContainer = getUsersContainer(); const userIsAvailable = fetchUserByIdService(id); if (!userIsAvailable) { throw new Error('User not found'); } const { statusCode } = await usersContainer.item(id, id).delete(); if (statusCode !== 204) { throw new Error('Failed to delete user.'); } return { statusCode, message: 'User deleted successfully', } } catch (error: any) { return handleCosmosError(error); } }; This code provides a set of service functions to interact with the Cosmos DB container for managing user data, including create, update, fetch, and delete operations. Here's a brief breakdown of each function: 1. saveUserService: Purpose: Saves a new user to the Cosmos DB container. How it works: Retrieves the usersContainer using getUsersContainer(). Uses items.create<TUser>(user) to create a new user document in the container. If the operation fails (i.e., no resource is returned), it throws an error. Returns the saved user object (with partial properties). Error Handling: Catches any error and passes it to handleCosmosError(). 2. updateUserService: Purpose: Updates an existing user in the Cosmos DB container. How it works: Retrieves the usersContainer. Uses items.upsert<Partial<TUser>>(user) to either insert or update the user data. If no resource is returned, an error is thrown. Returns the updated user object. Error Handling: Catches any error and passes it to handleCosmosError(). 3. fetchUsersService: Purpose: Fetches all users from the Cosmos DB container. How it works: Retrieves the usersContainer. Executes a SQL query (SELECT * FROM c ORDER BY c._ts DESC) to fetch all users ordered by timestamp (_ts). If the query is successful, it returns the list of users. If an error occurs, it is passed to handleCosmosError(). Return Type: Returns an array of TUser[] or null if no users are found. 4. fetchUserByEmailService: Purpose: Fetches a user by their email address. How it works: Retrieves the usersContainer. Executes a SQL query to search for a user by email (SELECT * FROM c WHERE c.email = Email). If the query finds a matching user, it returns the user object, otherwise returns null. Error Handling: Catches any error and passes it to handleCosmosError(). 5. fetchUserByIdService: Purpose: Fetches a user by their unique id. How it works: Retrieves the usersContainer. Uses item(id, id).read<TUser>() to read a user by its id. If no user is found, returns null. If the user is found, returns the user object. Error Handling: Catches any error and passes it to handleCosmosError(). 6. deleteUserByIdService: Purpose: Deletes a user by their unique id. How it works: Retrieves the usersContainer. Checks if the user exists by calling fetchUserByIdService(id). If the user is not found, throws an error. Deletes the user using item(id, id).delete(). Returns a response object with statusCode and a success message if the deletion is successful. Error Handling: Catches any error and passes it to handleCosmosError(). Summary of the Service Functions: Save a new user (saveUserService). Update an existing user (updateUserService). Fetch all users (fetchUsersService), a user by email (fetchUserByEmailService), or by id (fetchUserByIdService). Delete a user by id (deleteUserByIdService). Key Points: Upsert operation (upsert): If the user exists, it is updated; if not, it is created. Error Handling: All errors are passed to a centralized handleCosmosError() function, which ensures consistent error responses. Querying: Uses SQL-like queries in Cosmos DB to fetch users based on conditions (e.g., email or id). Type Safety: The services rely on the TUser and TResponse types from the schema, ensuring that the input and output adhere to the expected structure. This structure makes the service functions reusable and maintainable, while providing clean, type-safe interactions with the Azure Cosmos DB. Let's Create Server.ts Create server.ts and add the code below. //./server.ts import { initializeCosmosDB } from "./cosmosClient"; import { v4 as uuidv4 } from 'uuid'; import { TUser } from "./user.schema"; import { fetchUsersService, fetchUserByIdService, deleteUserByIdService, saveUserService, updateUserService, fetchUserByEmailService } from "./user.service"; // Start server (async () => { try { // Initialize CosmosDB await initializeCosmosDB(); // Create a new user const newUser: TUser = { id: uuidv4(), fullname: "John Doe", email: "john.doe@example.com", address: "Nairobi, Kenya", createdAt: new Date() }; const createdUser = await saveUserService(newUser); console.log('User created:', createdUser); // Fetch all users const users = await fetchUsersService(); console.log('Fetched users:', users); let userID = "81b4c47c-f222-487b-a5a1-805463c565a0"; // Fetch user by ID const user = await fetchUserByIdService(userID); console.log('Fetched user with ID:', user); //search for user by email const userByEmail = await fetchUserByEmailService("john.doe@example.com"); console.log('Fetched user with email:', userByEmail); // Update user const updatedUser = await updateUserService({ id: userID, fullname: "Jonathan Doe" }); console.log('User updated:', updatedUser); // Delete user const deleteResponse = await deleteUserByIdService(userID); console.log('Delete response:', deleteResponse); } catch (error: any) { console.error('Error:', error.message); } finally { process.exit(0); } })(); This server.ts file is the entry point of an application that interacts with Azure Cosmos DB to manage user data. It initializes the Cosmos DB connection and performs various CRUD operations (Create, Read, Update, Delete) on user records. Breakdown of the Code: 1. Imports: initializeCosmosDB: Initializes the Cosmos DB connection and sets up the database and container. uuidv4: Generates a unique identifier (UUID) for the id field of the user object. TUser: Type definition for a user, ensuring that the user object follows the correct structure (from user.schema.ts). Service Functions: These are the CRUD operations that interact with the Cosmos DB (fetchUsersService, fetchUserByIdService, etc.). 2. Asynchronous IIFE (Immediately Invoked Function Expression): The entire script runs inside an async IIFE, which is an asynchronous function that executes immediately when the file is run. 3. Workflow: Here’s what the script does step-by-step: Initialize Cosmos DB: The initializeCosmosDB() function is called to set up the connection to Cosmos DB. If the connection is successful, it logs Cosmos DB initialized. to the console. Create a New User: A new user is created with a unique ID (uuidv4()), full name, email, address, and a createdAt timestamp. The saveUserService(newUser) function is called to save the new user to the Cosmos DB container. If successful, the created user is logged to the console. Fetch All Users: The fetchUsersService() function is called to fetch all users from the Cosmos DB. The list of users is logged to the console. Fetch User by ID: The fetchUserByIdService(userID) function is called with a hardcoded userID to fetch a specific user by their unique ID. The user (if found) is logged to the console. Fetch User by Email: The fetchUserByEmailService(email) function is called to find a user by their email address ("john.doe@example.com"). The user (if found) is logged to the console. Update User: The updateUserService({ id: userID, fullname: "Jonathan Doe" }) function is called to update the user's full name. The updated user is logged to the console. Delete User: The deleteUserByIdService(userID) function is called to delete the user with the specified ID. The response from the deletion (status code and message) is logged to the console. 4. Error Handling: If any operation fails, the catch block catches the error and logs the error message to the console. This ensures that any issues (e.g., database connection failure, user not found, etc.) are reported. 5. Exit Process: After all operations are completed (or if an error occurs), the script exits the process with process.exit(0) to ensure the Node.js process terminates cleanly. Example Output: If everything runs successfully, the console output would look like this (assuming the hardcoded userID exists in the database and the operations succeed): Cosmos DB initialized. User created: { id: 'some-uuid', fullname: 'John Doe', email: 'john.doe@example.com', address: 'Nairobi, Kenya', createdAt: 2024-11-28T12:34:56.789Z } Fetched users: [{ id: 'some-uuid', fullname: 'John Doe', email: 'john.doe@example.com', address: 'Nairobi, Kenya', createdAt: 2024-11-28T12:34:56.789Z }] Fetched user with ID: { id: '81b4c47c-f222-487b-a5a1-805463c565a0', fullname: 'John Doe', email: 'john.doe@example.com', address: 'Nairobi, Kenya', createdAt: 2024-11-28T12:34:56.789Z } Fetched user with email: { id: 'some-uuid', fullname: 'John Doe', email: 'john.doe@example.com', address: 'Nairobi, Kenya', createdAt: 2024-11-28T12:34:56.789Z } User updated: { id: '81b4c47c-f222-487b-a5a1-805463c565a0', fullname: 'Jonathan Doe', email: 'john.doe@example.com', address: 'Nairobi, Kenya', createdAt: 2024-11-28T12:34:56.789Z } Delete response: { statusCode: 204, message: 'User deleted successfully' } Error Handling The SDK generates various types of errors that can occur during an operation. ErrorResponse is thrown if the response of an operation returns an error code of >=400. TimeoutError is thrown if Abort is called internally due to timeout. AbortError is thrown if any user passed signal caused the abort. RestError is thrown in case of failure of underlying system call due to network issues. Errors generated by any devDependencies. For Eg. azure/identity package could throw CredentialUnavailableError. Following is an example for handling errors of type ErrorResponse, TimeoutError, AbortError, and RestError. import { ErrorResponse, RestError, AbortError, TimeoutError } from '@azure/cosmos'; const handleCosmosError = (error: any) => { if (error instanceof RestError) { throw new Error(`error: ${error.name}, message: ${error.message}`); } else if (error instanceof ErrorResponse) { throw new Error(`Error: ${error.message}, message: ${error.message}`); } else if (error instanceof AbortError) { throw new Error(error.message); } else if (error instanceof TimeoutError) { throw new Error(`TimeoutError code: ${error.code}, message: ${error.message}`); } else if (error.code === 409) { //if you try to create an item using an id that's already in use in your Cosmos DB database, a 409 error is returned throw new Error('Conflict occurred while creating an item using an existing ID.'); } else { console.log(JSON.stringify(error)); throw new Error('An error occurred while processing your request.'); } }; Read More Quickstart Guide for Azure Cosmos DB Javascript SDK v4 Best practices for JavaScript SDK in Azure Cosmos DB for NoSQL Visit the JavaScript SDK v4 Release Notes page for the rest of our documentation and sample code. Announcing JavaScript SDK v4 for Azure Cosmos DB459Views1like0CommentsEssentials for building and modernizing AI apps on Azure
Building and modernizing AI applications is complex—but Azure Essentials simplifies the journey. With a structured, three-stage approach—Readiness and Foundation, Design and Govern, Manage and Optimize—it provides tools, best practices, and expert guidance to tackle key challenges like skilled resource gaps, modernization, and security. Discover how to streamline AI app development, enhance scalability, and achieve cost efficiency while driving business value. Ready to transform your AI journey? Explore the Azure Essentials Hub today.Build Intelligent Apps Code-First with Prompty and Azure AI
Want to build a custom copilot from scratch? Join us for Azure AI Week on the #30DaysOfIA as we go from prompt to production, building two different application scenarios, code-first with Prompty Assets on the Azure AI platform.3.1KViews2likes1CommentMicrosoft Build 2024: Essential Guide for AI Developers at Startups and Cloud-First Companies
Generative AI is advancing fast, with OpenAI’s GPT-4o leading the way. GPT-4o boasts improved multilingual understanding, faster responses, lower costs, and real-time processing of text, audio, and images. This boosts new Generative AI (GenAI) use cases. Explore cutting-edge solutions like models, frameworks, vector databases, and LLM observability platforms. Born-in-the-cloud companies are at the forefront of this AI revolution. Be part of the future at Microsoft Build 2024!