<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gate of AI</title>
    <description>The latest articles on DEV Community by Gate of AI (@gateofai).</description>
    <link>https://dev.to/gateofai</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3946864%2Fb6132c64-945e-41fa-915b-6b3276be957d.png</url>
      <title>DEV Community: Gate of AI</title>
      <link>https://dev.to/gateofai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gateofai"/>
    <language>en</language>
    <item>
      <title>Build a Secure Node.js AI API Gateway</title>
      <dc:creator>Gate of AI</dc:creator>
      <pubDate>Thu, 13 Aug 2026 18:13:39 +0000</pubDate>
      <link>https://dev.to/gateofai/build-a-secure-nodejs-ai-api-gateway-5503</link>
      <guid>https://dev.to/gateofai/build-a-secure-nodejs-ai-api-gateway-5503</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🚀 Technical Briefing:&lt;/strong&gt; This tutorial is part of our deep-dive series on Agentic Workflows at &lt;a href="https://gateofai.com" rel="noopener noreferrer"&gt;Gate of AI&lt;/a&gt;. For the full technical breakdown, interactive code sandbox, and the native Arabic translation, visit the &lt;a href="https://gateofai.com/tutorial/nodejs-ai-api-gateway-tutorial/" rel="noopener noreferrer"&gt;original article here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;p&amp;gt;Build a small Node.js AI API gateway that accepts validated JSON, assigns request IDs, applies a local per-client limit, and forwards approved work to a server-side model service without exposing provider credentials to browser code.&amp;lt;/p&amp;gt;



&amp;lt;h2&amp;gt;Prerequisites&amp;lt;/h2&amp;gt;
&amp;lt;ul&amp;gt;
  &amp;lt;li&amp;gt;Node.js 18 or later. This tutorial uses the runtime’s built-in &amp;lt;code&amp;gt;http&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;crypto&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;fetch&amp;lt;/code&amp;gt; capabilities.&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;Basic familiarity with JavaScript, JSON, HTTP requests, environment variables, and a terminal.&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;A model service that your gateway is permitted to call over HTTP. The gateway does not contain a model or a model-provider SDK.&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;A REST client such as &amp;lt;code&amp;gt;curl&amp;lt;/code&amp;gt;, Postman, Bruno, Insomnia, or the VS Code REST Client extension.&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;



&amp;lt;h2&amp;gt;What You Are Building&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;This tutorial builds a deliberately small Node.js AI API gateway. A client sends a JSON request to &amp;lt;code&amp;gt;POST /api/chat&amp;lt;/code&amp;gt;. The gateway checks that the request has the expected shape, rejects oversized payloads, assigns a request ID, applies a local rate limit, and forwards the validated request to a separate model service over HTTP. The gateway then returns the model service response to the caller.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;The architectural idea is grounded in a commonly used separation of concerns: a web backend serves HTTP APIs while a model service performs the core predictive task. The verified context describes an example stack with a web frontend, load balancer, Node.js REST API backend, distributed task queue, and a model service. This article implements only the Node.js gateway boundary. It does not claim to prescribe a complete production architecture, a particular model vendor, or a particular model-serving framework.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Keeping the gateway separate from the model service gives an application one place to apply input rules and operational controls before work reaches an AI system. It also means browser applications call your service rather than receiving a sensitive upstream credential. The exact authentication, authorization, data-retention, safety review, and deployment requirements depend on your organisation and use case, so they are intentionally not represented as universal defaults in this example.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;The implementation avoids unverified provider-specific SDK calls, model names, token limits, and model-response schemas. Instead, it defines a small JSON contract owned by this application. That is useful when the model service is an internal service, a separately operated inference API, or an adapter that you maintain elsewhere.&amp;lt;/p&amp;gt;



&amp;lt;h2&amp;gt;Gateway Responsibilities and Boundaries&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;A gateway should have a narrow job. In this tutorial it does five things: it accepts HTTP requests, parses limited-size JSON, validates required fields, records an opaque request ID, and forwards safe input to an upstream model service. It does not attempt to decide whether a generated answer is correct. It does not train a model. It does not embed keys in a frontend bundle. It also does not assume that every model service uses the same request or response structure.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Our public request contract is intentionally simple:&amp;lt;/p&amp;gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;{
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;"messages": [&lt;br&gt;
    { "role": "user", "content": "Explain an API gateway." }&lt;br&gt;
  ]&lt;br&gt;
}&lt;br&gt;
    &lt;/p&gt;
&lt;p&gt;The gateway accepts up to 20 messages, permits only &lt;code&gt;system&lt;/code&gt;, &lt;code&gt;user&lt;/code&gt;, and &lt;code&gt;assistant&lt;/code&gt; roles, and limits each message to 12,000 characters by default. These are application controls rather than token measurements. Characters and model tokens are not the same unit, so a character limit should not be presented as a precise cost or usage limit.&lt;/p&gt;
&lt;br&gt;
    &lt;p&gt;The upstream service in this tutorial receives a wrapper containing a request ID and the validated messages. Its expected successful response is JSON. The gateway does not transform that JSON into a vendor-neutral completion format because no provider response format is verified in the available context. Owning a small, documented internal contract is safer than guessing at a provider API.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;h2&amp;gt;Step 1: Create the Project and Environment File&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;Create a new project directory. This version uses no third-party dependency, which makes the example easy to inspect and keeps its runtime surface small. The built-in Node.js HTTP server is sufficient for a focused gateway demonstration.&amp;lt;/p&amp;gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;mkdir nodejs-ai-api-gateway
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;cd nodejs-ai-api-gateway&lt;br&gt;
npm init -y&lt;br&gt;
npm pkg set type=module&lt;br&gt;
npm pkg set scripts.start="node src/server.js"&lt;br&gt;
npm pkg set scripts.dev="node --watch src/server.js"&lt;br&gt;
npm pkg set engines.node="&amp;gt;=18.0.0"&lt;br&gt;
mkdir -p src&lt;br&gt;
    &lt;/p&gt;
&lt;p&gt;Create a &lt;code&gt;.gitignore&lt;/code&gt; file before creating local configuration. Never commit credentials or deployment-specific environment files to source control.&lt;/p&gt;
&lt;br&gt;
    &lt;pre&gt;&lt;code&gt;node_modules&lt;br&gt;
.env&lt;br&gt;
.env.local&lt;br&gt;
.env.production&lt;br&gt;
logs&lt;br&gt;
coverage&lt;br&gt;
npm-debug.log*&lt;br&gt;
.DS_Store&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
    &lt;p&gt;Next, create &lt;code&gt;.env&lt;/code&gt;. &lt;code&gt;MODEL_SERVICE_URL&lt;/code&gt; is the only required upstream setting. The URL must point to a service that your deployment can reach and is authorised to use. The example uses a loopback URL only as a local-development value.&lt;/p&gt;
&lt;br&gt;
    &lt;pre&gt;&lt;code&gt;PORT=3001&lt;br&gt;
MODEL_SERVICE_URL=&lt;a href="http://127.0.0.1:8080/generate" rel="noopener noreferrer"&gt;http://127.0.0.1:8080/generate&lt;/a&gt;&lt;br&gt;
ALLOWED_ORIGIN=&lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;&lt;br&gt;
MAX_BODY_BYTES=262144&lt;br&gt;
MAX_MESSAGE_CHARS=12000&lt;br&gt;
MAX_CONVERSATION_MESSAGES=20&lt;br&gt;
REQUESTS_PER_MINUTE=30&lt;br&gt;
UPSTREAM_TIMEOUT_MS=30000&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
    &lt;p&gt;Do not put upstream credentials in browser-exposed environment variables. If the model service requires credentials, keep them in the gateway’s server-side deployment environment and attach them only on the server. This tutorial does not include an authorization header because its name, format, and credential lifecycle are not established by the verified context.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;h2&amp;gt;Step 2: Validate Configuration at Startup&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;Create &amp;lt;code&amp;gt;src/config.js&amp;lt;/code&amp;gt;. Environment variables arrive as strings, so the module explicitly parses numerical values and fails early when required configuration is invalid. Startup validation is preferable to discovering a malformed port or URL only after traffic arrives.&amp;lt;/p&amp;gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;import process from "node:process";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;function readPositiveInteger(name, fallback, minimum, maximum) {&lt;br&gt;
  const raw = process.env[name] ?? String(fallback);&lt;br&gt;
  const value = Number.parseInt(raw, 10);&lt;/p&gt;

&lt;p&gt;if (!Number.isInteger(value) || value &amp;lt; minimum || value &amp;gt; maximum) {&lt;br&gt;
    throw new Error(&lt;code&gt;${name} must be an integer from ${minimum} to ${maximum}.&lt;/code&gt;);&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;return value;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;function readUrl(name) {&lt;br&gt;
  const raw = process.env[name];&lt;/p&gt;

&lt;p&gt;if (!raw) {&lt;br&gt;
    throw new Error(&lt;code&gt;${name} is required.&lt;/code&gt;);&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;try {&lt;br&gt;
    return new URL(raw).toString();&lt;br&gt;
  } catch {&lt;br&gt;
    throw new Error(&lt;code&gt;${name} must be a valid URL.&lt;/code&gt;);&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;export const config = Object.freeze({&lt;br&gt;
  port: readPositiveInteger("PORT", 3001, 1, 65535),&lt;br&gt;
  modelServiceUrl: readUrl("MODEL_SERVICE_URL"),&lt;br&gt;
  allowedOrigin: process.env.ALLOWED_ORIGIN ?? "&lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;",&lt;br&gt;
  maxBodyBytes: readPositiveInteger("MAX_BODY_BYTES", 262144, 1024, 1048576),&lt;br&gt;
  maxMessageChars: readPositiveInteger("MAX_MESSAGE_CHARS", 12000, 1, 100000),&lt;br&gt;
  maxConversationMessages: readPositiveInteger(&lt;br&gt;
    "MAX_CONVERSATION_MESSAGES",&lt;br&gt;
    20,&lt;br&gt;
    1,&lt;br&gt;
    100&lt;br&gt;
  ),&lt;br&gt;
  requestsPerMinute: readPositiveInteger(&lt;br&gt;
    "REQUESTS_PER_MINUTE",&lt;br&gt;
    30,&lt;br&gt;
    1,&lt;br&gt;
    10000&lt;br&gt;
  ),&lt;br&gt;
  upstreamTimeoutMs: readPositiveInteger(&lt;br&gt;
    "UPSTREAM_TIMEOUT_MS",&lt;br&gt;
    30000,&lt;br&gt;
    1000,&lt;br&gt;
    120000&lt;br&gt;
  )&lt;br&gt;
});&lt;br&gt;
    &lt;/p&gt;
&lt;p&gt;For local development, load environment values before starting Node. One straightforward option is to export the values in your shell. Deployment platforms should inject server-side environment variables through their own protected configuration mechanism. The code above intentionally does not rely on an unverified configuration library.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;h2&amp;gt;Step 3: Build the Node.js Gateway&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;Create &amp;lt;code&amp;gt;src/server.js&amp;lt;/code&amp;gt;. The server is complete and uses only Node.js modules. It accepts &amp;lt;code&amp;gt;POST /api/chat&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;GET /health&amp;lt;/code&amp;gt;. It handles preflight requests for one configured browser origin, but CORS is not authentication. A public gateway still needs an authentication and authorization design appropriate to its users.&amp;lt;/p&amp;gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;import crypto from "node:crypto";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;import http from "node:http";&lt;br&gt;
import { config } from "./config.js";&lt;/p&gt;

&lt;p&gt;const rateWindows = new Map();&lt;/p&gt;

&lt;p&gt;function sendJson(response, statusCode, body, requestId) {&lt;br&gt;
  const payload = JSON.stringify(body);&lt;br&gt;
  response.writeHead(statusCode, {&lt;br&gt;
    "Content-Type": "application/json; charset=utf-8",&lt;br&gt;
    "Content-Length": Buffer.byteLength(payload),&lt;br&gt;
    "X-Request-Id": requestId,&lt;br&gt;
    "Cache-Control": "no-store"&lt;br&gt;
  });&lt;br&gt;
  response.end(payload);&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;function getRequestId(request) {&lt;br&gt;
  const supplied = request.headers["x-request-id"];&lt;br&gt;
  if (typeof supplied === "string" &amp;amp;&amp;amp; supplied.length &amp;gt; 0 &amp;amp;&amp;amp; supplied.length &amp;lt;= 128) {&lt;br&gt;
    return supplied;&lt;br&gt;
  }&lt;br&gt;
  return crypto.randomUUID();&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;function applyCors(request, response) {&lt;br&gt;
  const origin = request.headers.origin;&lt;/p&gt;

&lt;p&gt;if (origin === config.allowedOrigin) {&lt;br&gt;
    response.setHeader("Access-Control-Allow-Origin", origin);&lt;br&gt;
    response.setHeader("Vary", "Origin");&lt;br&gt;
    response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");&lt;br&gt;
    response.setHeader("Access-Control-Allow-Headers", "Content-Type, X-Request-Id");&lt;br&gt;
    response.setHeader("Access-Control-Max-Age", "86400");&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;function clientKey(request) {&lt;br&gt;
  return request.socket.remoteAddress ?? "unknown";&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;function isRateLimited(request) {&lt;br&gt;
  const key = clientKey(request);&lt;br&gt;
  const now = Date.now();&lt;br&gt;
  const windowStart = now - 60_000;&lt;br&gt;
  const recent = (rateWindows.get(key) ?? []).filter((timestamp) =&amp;gt; timestamp &amp;gt; windowStart);&lt;/p&gt;

&lt;p&gt;if (recent.length &amp;gt;= config.requestsPerMinute) {&lt;br&gt;
    rateWindows.set(key, recent);&lt;br&gt;
    return true;&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;recent.push(now);&lt;br&gt;
  rateWindows.set(key, recent);&lt;br&gt;
  return false;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;function readJsonBody(request) {&lt;br&gt;
  return new Promise((resolve, reject) =&amp;gt; {&lt;br&gt;
    let totalBytes = 0;&lt;br&gt;
    const chunks = [];&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;request.on("data", (chunk) =&amp;amp;gt; {
  totalBytes += chunk.length;
  if (totalBytes &amp;amp;gt; config.maxBodyBytes) {
    reject(new Error("BODY_TOO_LARGE"));
    request.destroy();
    return;
  }
  chunks.push(chunk);
});

request.on("end", () =&amp;amp;gt; {
  try {
    const text = Buffer.concat(chunks).toString("utf8");
    resolve(JSON.parse(text));
  } catch {
    reject(new Error("INVALID_JSON"));
  }
});

request.on("error", reject);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;});&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;function validateChatRequest(value) {&lt;br&gt;
  if (!value || typeof value !== "object" || Array.isArray(value)) {&lt;br&gt;
    return "Request body must be a JSON object.";&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;if (!Array.isArray(value.messages) || value.messages.length === 0) {&lt;br&gt;
    return "messages must be a non-empty array.";&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;if (value.messages.length &amp;gt; config.maxConversationMessages) {&lt;br&gt;
    return &lt;code&gt;messages must contain at most ${config.maxConversationMessages} items.&lt;/code&gt;;&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;const roles = new Set(["system", "user", "assistant"]);&lt;br&gt;
  let systemCount = 0;&lt;/p&gt;

&lt;p&gt;for (const message of value.messages) {&lt;br&gt;
    if (!message || typeof message !== "object" || Array.isArray(message)) {&lt;br&gt;
      return "Each message must be an object.";&lt;br&gt;
    }&lt;br&gt;
    if (!roles.has(message.role)) {&lt;br&gt;
      return "Each message role must be system, user, or assistant.";&lt;br&gt;
    }&lt;br&gt;
    if (typeof message.content !== "string" || message.content.trim().length === 0) {&lt;br&gt;
      return "Each message content value must be a non-empty string.";&lt;br&gt;
    }&lt;br&gt;
    if (message.content.length &amp;gt; config.maxMessageChars) {&lt;br&gt;
      return &lt;code&gt;Each message content value must be at most ${config.maxMessageChars} characters.&lt;/code&gt;;&lt;br&gt;
    }&lt;br&gt;
    if (message.role === "system") systemCount += 1;&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;if (systemCount &amp;gt; 1) return "Only one system message is allowed.";&lt;br&gt;
  if (value.messages[0].role === "assistant") {&lt;br&gt;
    return "The first message cannot use the assistant role.";&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;return null;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;async function forwardToModelService(input, requestId) {&lt;br&gt;
  const timeout = AbortSignal.timeout(config.upstreamTimeoutMs);&lt;br&gt;
  const upstreamResponse = await fetch(config.modelServiceUrl, {&lt;br&gt;
    method: "POST",&lt;br&gt;
    headers: {&lt;br&gt;
      "Content-Type": "application/json",&lt;br&gt;
      "X-Request-Id": requestId&lt;br&gt;
    },&lt;br&gt;
    body: JSON.stringify({ requestId, messages: input.messages }),&lt;br&gt;
    signal: timeout&lt;br&gt;
  });&lt;/p&gt;

&lt;p&gt;const contentType = upstreamResponse.headers.get("content-type") ?? "";&lt;br&gt;
  const responseBody = contentType.includes("application/json")&lt;br&gt;
    ? await upstreamResponse.json()&lt;br&gt;
    : { message: await upstreamResponse.text() };&lt;/p&gt;

&lt;p&gt;return { status: upstreamResponse.status, body: responseBody };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;const server = http.createServer(async (request, response) =&amp;gt; {&lt;br&gt;
  const requestId = getRequestId(request);&lt;br&gt;
  applyCors(request, response);&lt;/p&gt;

&lt;p&gt;if (request.method === "OPTIONS") {&lt;br&gt;
    response.writeHead(204, { "X-Request-Id": requestId });&lt;br&gt;
    response.end();&lt;br&gt;
    return;&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;if (request.method === "GET" &amp;amp;&amp;amp; request.url === "/health") {&lt;br&gt;
    sendJson(response, 200, { status: "ok", service: "nodejs-ai-api-gateway" }, requestId);&lt;br&gt;
    return;&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;if (request.method !== "POST" || request.url !== "/api/chat") {&lt;br&gt;
    sendJson(response, 404, { error: { code: "NOT_FOUND", message: "Route not found." } }, requestId);&lt;br&gt;
    return;&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;if (isRateLimited(request)) {&lt;br&gt;
    sendJson(response, 429, { error: { code: "RATE_LIMITED", message: "Try again shortly." } }, requestId);&lt;br&gt;
    return;&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;if (!request.headers["content-type"]?.includes("application/json")) {&lt;br&gt;
    sendJson(response, 415, { error: { code: "UNSUPPORTED_MEDIA_TYPE", message: "Use application/json." } }, requestId);&lt;br&gt;
    return;&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;try {&lt;br&gt;
    const input = await readJsonBody(request);&lt;br&gt;
    const validationError = validateChatRequest(input);&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (validationError) {
  sendJson(response, 400, { error: { code: "INVALID_REQUEST", message: validationError } }, requestId);
  return;
}

const upstream = await forwardToModelService(input, requestId);
sendJson(response, upstream.status, { requestId, data: upstream.body }, requestId);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;} catch (error) {&lt;br&gt;
    if (error.message === "BODY_TOO_LARGE") {&lt;br&gt;
      sendJson(response, 413, { error: { code: "BODY_TOO_LARGE", message: "Request body exceeds the configured limit." } }, requestId);&lt;br&gt;
      return;&lt;br&gt;
    }&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (error.message === "INVALID_JSON") {
  sendJson(response, 400, { error: { code: "INVALID_JSON", message: "Request body must contain valid JSON." } }, requestId);
  return;
}

console.error(JSON.stringify({ requestId, error: String(error) }));
sendJson(response, 502, { error: { code: "MODEL_SERVICE_ERROR", message: "The model service could not be reached or did not complete the request." } }, requestId);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;server.listen(config.port, () =&amp;gt; {&lt;br&gt;
  console.log(JSON.stringify({ event: "listening", port: config.port }));&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;function shutdown(signal) {&lt;br&gt;
  console.log(JSON.stringify({ event: "shutdown_started", signal }));&lt;br&gt;
  server.close(() =&amp;gt; process.exit(0));&lt;br&gt;
  setTimeout(() =&amp;gt; process.exit(1), 10_000).unref();&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;process.on("SIGINT", () =&amp;gt; shutdown("SIGINT"));&lt;br&gt;
process.on("SIGTERM", () =&amp;gt; shutdown("SIGTERM"));&lt;br&gt;
    &lt;/p&gt;
&lt;p&gt;The local rate limiter uses process memory and the socket address as its key. This is suitable only for a single-process demonstration. When a service runs behind a load balancer or on multiple instances, each process has its own memory and may observe a different client address. Use a shared, deliberately designed rate-limit mechanism and authenticated identity signals before treating limits as an enforceable organisation-wide control.&lt;/p&gt;
&lt;br&gt;
    &lt;p&gt;The server logs only an opaque request ID and an error string in the catch path. It does not intentionally log message content. This is a practical default because prompts may contain sensitive business information, source code, or personal information. If you need content logging for a defined evaluation process, decide separately what may be retained, who may access it, and how deletion and incident response work.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;h2&amp;gt;Step 4: Run and Test the Gateway&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;Set the environment variables in your shell, then start the server. The exact shell syntax differs by operating system. On a Unix-like shell, the following starts the application with the example local URL.&amp;lt;/p&amp;gt;
&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;export PORT=3001
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;export MODEL_SERVICE_URL=&lt;a href="http://127.0.0.1:8080/generate" rel="noopener noreferrer"&gt;http://127.0.0.1:8080/generate&lt;/a&gt;&lt;br&gt;
export ALLOWED_ORIGIN=&lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;&lt;br&gt;
npm run dev&lt;br&gt;
    &lt;/p&gt;
&lt;p&gt;First test the health endpoint. It does not call the model service.&lt;/p&gt;
&lt;br&gt;
    &lt;pre&gt;&lt;code&gt;curl --include &lt;a href="http://localhost:3001/health" rel="noopener noreferrer"&gt;http://localhost:3001/health&lt;/a&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
    &lt;p&gt;Then send a valid chat request. This request will reach the configured model service, so it can succeed only when that service is available and implements the contract expected by your application.&lt;/p&gt;
&lt;br&gt;
    &lt;pre&gt;&lt;code&gt;curl --include --request POST &lt;a href="http://localhost:3001/api/chat" rel="noopener noreferrer"&gt;http://localhost:3001/api/chat&lt;/a&gt; \&lt;br&gt;
  --header "Content-Type: application/json" \&lt;br&gt;
  --data '{&lt;br&gt;
    "messages": [&lt;br&gt;
      { "role": "system", "content": "Answer concisely." },&lt;br&gt;
      { "role": "user", "content": "What is an API gateway?" }&lt;br&gt;
    ]&lt;br&gt;
  }'&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
    &lt;p&gt;Also test negative paths. Send malformed JSON to confirm the gateway returns &lt;code&gt;400&lt;/code&gt;. Send a request with an invalid role to verify the application-level schema. Finally, temporarily stop the model service to check the gateway’s &lt;code&gt;502&lt;/code&gt; response. Failure testing is essential because network availability and upstream behaviour are not guaranteed.&lt;/p&gt;
&lt;br&gt;
    &lt;pre&gt;&lt;code&gt;curl --include --request POST &lt;a href="http://localhost:3001/api/chat" rel="noopener noreferrer"&gt;http://localhost:3001/api/chat&lt;/a&gt; \&lt;br&gt;
  --header "Content-Type: application/json" \&lt;br&gt;
  --data '{"messages":[{"role":"unknown","content":"Hello"}]}'&lt;/code&gt;&lt;/pre&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;h2&amp;gt;What to Build Next&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;Start with authentication. CORS controls which compliant browsers may read a response; it does not establish who is allowed to use an endpoint. Add an authentication mechanism appropriate to your application, then associate requests with a user, service, organisation, or tenant before applying meaningful quotas.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Next, define the model-service contract explicitly. Document the accepted request body, expected response body, timeout behaviour, error statuses, and versioning strategy. If you introduce a queue for long-running work, make the request lifecycle explicit rather than pretending every task will complete during one synchronous HTTP call. The verified context’s example architecture includes a distributed task queue alongside a Node.js backend and model service, which is a useful direction to evaluate for workloads that do not fit a simple request-response interaction.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;For scale, put the gateway behind infrastructure that your team operates and monitors. The verified context describes a load balancer as part of an example production stack. If you deploy multiple gateway instances, replace the in-memory limiter with a shared approach, ensure request IDs flow through every service, and test how client address information is handled by your proxy configuration.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;For GCC and Middle East deployments, avoid unsupported assumptions about local hosting, legal requirements, or named government programmes. Instead, have legal, security, and data-governance stakeholders assess where data is processed, what information is sent to the model service, how long records are retained, and which regional contractual or regulatory obligations apply to the specific organisation. A gateway boundary makes those controls easier to place consistently, but it does not itself establish compliance.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Finally, keep dependencies and runtime components patched. The verified context includes a National Vulnerability Database entry, reinforcing the practical need to monitor security advisories relevant to the software you operate. Review advisories, test upgrades, and maintain a repeatable deployment process. A compact gateway with a clear contract is easier to test, audit, and evolve than provider-specific calls scattered across browser and backend applications.&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Build a RAG System with OpenAI API</title>
      <dc:creator>Gate of AI</dc:creator>
      <pubDate>Thu, 13 Aug 2026 18:09:13 +0000</pubDate>
      <link>https://dev.to/gateofai/build-a-rag-system-with-openai-api-h2i</link>
      <guid>https://dev.to/gateofai/build-a-rag-system-with-openai-api-h2i</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🚀 Technical Briefing:&lt;/strong&gt; This tutorial is part of our deep-dive series on Agentic Workflows at &lt;a href="https://gateofai.com" rel="noopener noreferrer"&gt;Gate of AI&lt;/a&gt;. For the full technical breakdown, interactive code sandbox, and the native Arabic translation, visit the &lt;a href="https://gateofai.com/tutorial/build-rag-system-openai-api/" rel="noopener noreferrer"&gt;original article here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;span&amp;gt;Tutorial&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;Advanced&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;⏱ 60 min read&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;© Gate of AI 2026-07-27&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this tutorial, you'll build a Retrieval-Augmented Generation (RAG) system using the latest techniques to enhance your AI application's accuracy and responsiveness.&lt;/p&gt;


&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;br&gt;
  &lt;ul&gt;

    &lt;li&gt;Python 3.10 or higher&lt;/li&gt;

    &lt;li&gt;OpenAI API key&lt;/li&gt;

    &lt;li&gt;Familiarity with RESTful APIs and JSON&lt;/li&gt;

  &lt;/ul&gt;


&lt;h2&gt;What We're Building&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;In this comprehensive tutorial, we will create a Retrieval-Augmented Generation (RAG) system that leverages the capabilities of modern APIs. The system will enhance the accuracy and relevance of AI-generated content by incorporating real-time data retrieval from external sources. Our final project will allow for dynamic interaction with users, providing responses informed by the latest available data, thus overcoming the limitations of static knowledge bases.&lt;/p&gt;
&lt;br&gt;
  &lt;p&gt;The RAG system will integrate seamlessly with existing applications, enabling developers to deploy AI solutions that are not only more informative but also contextually aware. This will be particularly useful in scenarios where up-to-date information is crucial, such as customer support, content creation, and personalized recommendations.&lt;/p&gt;


&lt;h2&gt;Setup and Installation&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;To get started, we need to set up our development environment by installing the necessary packages and configuring environment variables. This ensures that our application can communicate effectively with the APIs and handle data retrieval operations.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;pip install openai requests&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;Next, we'll define our environment variables in a &lt;code&gt;.env&lt;/code&gt; file. This file will store sensitive information such as API keys securely.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;&lt;br&gt;
OPENAI_API_KEY=your_openai_api_key&lt;br&gt;
  &lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;Step 1: Setting Up the API Client&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;In this step, we will initialize the API client for OpenAI. This setup is crucial as it allows our application to send requests and receive responses from the API.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;&lt;br&gt;
import os&lt;br&gt;
from openai import OpenAI
&lt;h1&gt;
  
  
  Load API key from environment variables
&lt;/h1&gt;

&lt;p&gt;openai_api_key = os.getenv("OPENAI_API_KEY")&lt;/p&gt;
&lt;h1&gt;
  
  
  Initialize the API client
&lt;/h1&gt;

&lt;p&gt;client = OpenAI(api_key=openai_api_key)&lt;br&gt;
  &lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;The code above loads the API key from our &lt;code&gt;.env&lt;/code&gt; file using the &lt;code&gt;os&lt;/code&gt; library and initializes the client with this key. This setup ensures secure and authenticated communication with the API.&lt;/p&gt;


&lt;h2&gt;Step 2: Implementing the Retrieval Logic&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;In this step, we will implement the logic to retrieve relevant information from external sources. This is a critical component of the RAG system, as it enhances the model's responses with up-to-date data.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;&lt;br&gt;
import requests

&lt;p&gt;def retrieve_data(query):&lt;br&gt;
    # Example external data source&lt;br&gt;
    url = "&lt;a href="https://api.example.com/search" rel="noopener noreferrer"&gt;https://api.example.com/search&lt;/a&gt;"&lt;br&gt;
    params = {"q": query}&lt;br&gt;
    response = requests.get(url, params=params)&lt;br&gt;
    response.raise_for_status()&lt;br&gt;
    return response.json()&lt;/p&gt;
&lt;h1&gt;
  
  
  Example usage
&lt;/h1&gt;

&lt;p&gt;data = retrieve_data("latest AI trends")&lt;br&gt;
print(data)&lt;br&gt;
  &lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;This function uses the &lt;code&gt;requests&lt;/code&gt; library to perform a GET request to an external API. It takes a query string, sends it to the data source, and returns the JSON response. This retrieved data will be used to augment the AI model's output.&lt;/p&gt;


&lt;h2&gt;Step 3: Integrating Retrieval with Generation&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;Now, let's integrate the data retrieval with the generation capabilities of the OpenAI API. This combination will enable our system to provide more accurate and contextually relevant responses.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;&lt;br&gt;
def generate_response(prompt, retrieved_data):&lt;br&gt;
    # Combine the prompt with retrieved data&lt;br&gt;
    combined_input = f"{prompt}\n\nAdditional Information:\n{retrieved_data}"
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Generate response using OpenAI
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": combined_input}]
).choices[0].message['content']

return response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  Example usage
&lt;/h1&gt;

&lt;p&gt;prompt = "Discuss the impact of AI on modern education."&lt;br&gt;
retrieved_data = retrieve_data("AI impact on education")&lt;br&gt;
output = generate_response(prompt, retrieved_data)&lt;br&gt;
print("Response:", output)&lt;br&gt;
  &lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;In this function, we first combine the user's prompt with additional data retrieved from external sources. We then call the OpenAI API to generate a response. This approach ensures that the output is enriched with current information, making it more relevant and accurate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚠️ Common Mistake:&lt;/strong&gt; Ensure that your API key is correctly set up in the environment variables. A common issue is forgetting to restart the terminal or IDE after setting up the &lt;code&gt;.env&lt;/code&gt; file, which can lead to authentication errors.&lt;/p&gt;


&lt;h2&gt;Testing Your Implementation&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;It's essential to verify that the system works as expected. We'll run a series of tests to ensure that both data retrieval and response generation are functioning correctly.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;
&lt;h1&gt;
  
  
  Test retrieval function
&lt;/h1&gt;

&lt;p&gt;test_data = retrieve_data("test query")&lt;br&gt;
assert test_data is not None, "Data retrieval failed!"&lt;/p&gt;
&lt;h1&gt;
  
  
  Test generation function
&lt;/h1&gt;

&lt;p&gt;test_prompt = "Explain the significance of climate change."&lt;br&gt;
test_retrieved_data = retrieve_data("climate change significance")&lt;br&gt;
test_output = generate_response(test_prompt, test_retrieved_data)&lt;/p&gt;

&lt;p&gt;assert len(test_output) &amp;gt; 0, "Generation failed!"&lt;br&gt;
  &lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;These tests check that the retrieval function returns data and that the generation function produces a response. If any assertions fail, it indicates an issue with the respective component that needs addressing.&lt;/p&gt;


&lt;h2&gt;What to Build Next&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;Having completed this tutorial, you can extend the RAG system in several ways:&lt;/p&gt;
&lt;br&gt;
  &lt;ul&gt;

    &lt;li&gt;Integrate additional data sources to enhance the breadth of information available to the system.&lt;/li&gt;

    &lt;li&gt;Implement a more sophisticated aggregation method for combining retrieved data with the AI prompt.&lt;/li&gt;

    &lt;li&gt;Optimize performance by caching frequent queries to reduce latency and API costs.&lt;/li&gt;

  &lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Fine-Tuning LLMs with Python: A 2026 Guide</title>
      <dc:creator>Gate of AI</dc:creator>
      <pubDate>Thu, 13 Aug 2026 18:09:01 +0000</pubDate>
      <link>https://dev.to/gateofai/fine-tuning-llms-with-python-a-2026-guide-329a</link>
      <guid>https://dev.to/gateofai/fine-tuning-llms-with-python-a-2026-guide-329a</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🚀 Technical Briefing:&lt;/strong&gt; This tutorial is part of our deep-dive series on Agentic Workflows at &lt;a href="https://gateofai.com" rel="noopener noreferrer"&gt;Gate of AI&lt;/a&gt;. For the full technical breakdown, interactive code sandbox, and the native Arabic translation, visit the &lt;a href="https://gateofai.com/tutorial/fine-tuning-llms-python-2026-guide/" rel="noopener noreferrer"&gt;original article here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;span&amp;gt;Tutorial&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;Advanced&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;⏱ 45 min read&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;© Gate of AI 2026-07-28&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this tutorial, you'll learn how to fine-tune large language models using Python to improve performance on specific tasks, leveraging modern APIs and best practices for optimal results.&lt;/p&gt;


&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;br&gt;
  &lt;ul&gt;

    &lt;li&gt;Python 3.10 or later&lt;/li&gt;

    &lt;li&gt;Access to OpenAI API with a valid API key&lt;/li&gt;

    &lt;li&gt;Basic understanding of machine learning and NLP&lt;/li&gt;

  &lt;/ul&gt;


&lt;h2&gt;What We're Building&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;This tutorial will guide you through the process of fine-tuning a large language model (LLM) to perform a specific task, such as sentiment analysis or conversational AI customization. By the end of this guide, you will have a fine-tuned model that can deliver responses tailored to your specific needs, whether it's improving accuracy on niche datasets or customizing the tone and style of the output.&lt;/p&gt;
&lt;br&gt;
  &lt;p&gt;The finished project will involve setting up the environment, preparing a dataset, configuring the model for fine-tuning, and executing the training process. You will also learn how to test the model to ensure it meets your requirements and explore potential enhancements to further refine its capabilities.&lt;/p&gt;


&lt;h2&gt;Setup and Installation&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;To start, you'll need to set up your development environment. This involves installing necessary Python libraries and preparing your system to handle large datasets and model computations efficiently.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;pip install transformers datasets&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;You'll need to configure environment variables to store your API keys securely. This is crucial for accessing the OpenAI API and other cloud-based services.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;
&lt;h1&gt;
  
  
  .env file
&lt;/h1&gt;

&lt;p&gt;OPENAI_API_KEY=your_openai_api_key_here&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;Step 1: Preparing Your Dataset&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;The first step in fine-tuning involves preparing a high-quality dataset. This dataset should be representative of the tasks you want the model to perform better on. You might need to curate or clean the data to ensure consistency and accuracy.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;&lt;br&gt;
import pandas as pd
&lt;h1&gt;
  
  
  Load your dataset
&lt;/h1&gt;

&lt;p&gt;dataset = pd.read_csv('your_dataset.csv')&lt;/p&gt;
&lt;h1&gt;
  
  
  Inspect the dataset
&lt;/h1&gt;

&lt;p&gt;print(dataset.head())&lt;/p&gt;
&lt;h1&gt;
  
  
  Clean and preprocess the dataset
&lt;/h1&gt;

&lt;p&gt;def preprocess(text):&lt;br&gt;
    return text.strip().lower()&lt;/p&gt;

&lt;p&gt;dataset['text'] = dataset['text'].apply(preprocess)&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;In this code snippet, we load a dataset using pandas and apply basic preprocessing to clean the text, which involves stripping whitespace and converting to lowercase. This ensures that our data is uniform and ready for fine-tuning.&lt;/p&gt;


&lt;h2&gt;Step 2: Configuring the Model&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;Next, you'll configure the language model for fine-tuning. This involves setting up the model architecture and tokenizer. The Hugging Face Transformers library provides an easy interface for this purpose.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;&lt;br&gt;
from transformers import AutoModelForCausalLM, AutoTokenizer
&lt;h1&gt;
  
  
  Load pre-trained model and tokenizer
&lt;/h1&gt;

&lt;p&gt;model_name = "gpt-3.5-turbo"&lt;br&gt;
tokenizer = AutoTokenizer.from_pretrained(model_name)&lt;br&gt;
model = AutoModelForCausalLM.from_pretrained(model_name)&lt;/p&gt;
&lt;h1&gt;
  
  
  Print model details
&lt;/h1&gt;

&lt;p&gt;print(model.config)&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;Here, we load a pre-trained model and tokenizer using the Transformers library. We then print the model configuration to understand its current settings, which will help us decide on any modifications needed for fine-tuning.&lt;/p&gt;


&lt;h2&gt;Step 3: Fine-Tuning the Model&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;With the model configured, you can now proceed to fine-tune it using your dataset. This process involves training the model on the dataset to adjust its weights and biases, optimizing it for your specific tasks.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;&lt;br&gt;
from transformers import Trainer, TrainingArguments
&lt;h1&gt;
  
  
  Define training arguments
&lt;/h1&gt;

&lt;p&gt;training_args = TrainingArguments(&lt;br&gt;
    output_dir='./results',&lt;br&gt;
    evaluation_strategy="epoch",&lt;br&gt;
    per_device_train_batch_size=2,&lt;br&gt;
    num_train_epochs=3,&lt;br&gt;
    save_steps=10,&lt;br&gt;
    save_total_limit=2,&lt;br&gt;
)&lt;/p&gt;
&lt;h1&gt;
  
  
  Initialize Trainer
&lt;/h1&gt;

&lt;p&gt;trainer = Trainer(&lt;br&gt;
    model=model,&lt;br&gt;
    args=training_args,&lt;br&gt;
    train_dataset=dataset,&lt;br&gt;
    tokenizer=tokenizer,&lt;br&gt;
)&lt;/p&gt;
&lt;h1&gt;
  
  
  Start training
&lt;/h1&gt;

&lt;p&gt;trainer.train()&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;This code sets up the training arguments and initializes a Trainer object. The training arguments include settings like batch size and number of epochs. The Trainer handles the fine-tuning process, applying the dataset to the model and adjusting its parameters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚠️ Common Mistake:&lt;/strong&gt; Ensure your dataset is preprocessed correctly. Inconsistent data formats can lead to errors during training, causing the model to underperform.&lt;/p&gt;


&lt;h2&gt;Testing Your Implementation&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;After fine-tuning, it's crucial to test your model to verify its performance. You should check if the model meets the desired accuracy and style requirements for your specific use case.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;
&lt;h1&gt;
  
  
  Test the model
&lt;/h1&gt;

&lt;p&gt;test_text = "Input text for the model"&lt;br&gt;
input_ids = tokenizer.encode(test_text, return_tensors='pt')&lt;br&gt;
output = model.generate(input_ids)&lt;/p&gt;
&lt;h1&gt;
  
  
  Decode and print output
&lt;/h1&gt;

&lt;p&gt;decoded_output = tokenizer.decode(output[0], skip_special_tokens=True)&lt;br&gt;
print(decoded_output)&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;This test script encodes a sample input text, runs it through the fine-tuned model, and decodes the output. The result should reflect the improved capabilities of your model based on the fine-tuning.&lt;/p&gt;


&lt;h2&gt;What to Build Next&lt;/h2&gt;
&lt;br&gt;
  &lt;ul&gt;

    &lt;li&gt;Explore multi-turn conversation fine-tuning to enhance interactive applications.&lt;/li&gt;

    &lt;li&gt;Integrate your model into a web application using a framework like Flask or FastAPI.&lt;/li&gt;

    &lt;li&gt;Experiment with different datasets to fine-tune your model for various domain-specific tasks.&lt;/li&gt;

  &lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Build AI App with Meta Llama 3 &amp; LangChain</title>
      <dc:creator>Gate of AI</dc:creator>
      <pubDate>Thu, 13 Aug 2026 18:08:49 +0000</pubDate>
      <link>https://dev.to/gateofai/build-ai-app-with-meta-llama-3-langchain-36hp</link>
      <guid>https://dev.to/gateofai/build-ai-app-with-meta-llama-3-langchain-36hp</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🚀 Technical Briefing:&lt;/strong&gt; This tutorial is part of our deep-dive series on Agentic Workflows at &lt;a href="https://gateofai.com" rel="noopener noreferrer"&gt;Gate of AI&lt;/a&gt;. For the full technical breakdown, interactive code sandbox, and the native Arabic translation, visit the &lt;a href="https://gateofai.com/tutorial/build-ai-app-meta-llama3-langchain/" rel="noopener noreferrer"&gt;original article here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;span&amp;gt;Tutorial&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;Intermediate&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;⏱ 45 min read&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;© Gate of AI 2026-07-29&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this tutorial, you'll build a scalable generative AI application utilizing Meta's Llama 3 and LangChain for orchestrating complex workflows.&lt;/p&gt;


&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;br&gt;
  &lt;ul&gt;

    &lt;li&gt;Python 3.10 or higher&lt;/li&gt;

    &lt;li&gt;Meta Llama 3 API access&lt;/li&gt;

    &lt;li&gt;Basic understanding of Python and AI concepts&lt;/li&gt;

  &lt;/ul&gt;


&lt;h2&gt;What We're Building&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;In this tutorial, we'll create a generative AI application that leverages the power of Meta's Llama 3 model. This application will be capable of generating human-like text based on prompts provided by the user. By integrating with LangChain, we will orchestrate complex workflows that include memory management, tool usage, and state persistence.&lt;/p&gt;
&lt;br&gt;
  &lt;p&gt;The finished project will allow users to input text prompts and receive coherent, contextually relevant responses generated by Llama 3. This application will demonstrate the capabilities of modern AI frameworks in handling natural language processing tasks with efficiency and scalability.&lt;/p&gt;


&lt;h2&gt;Setup and Installation&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;To start, we need to install the necessary libraries that will allow us to interact with Meta Llama 3 and LangChain. Ensure that you have Python 3.10 or higher installed on your system.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;pip install torch langchain&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;Next, configure the environment variables required for accessing the Llama 3 API. Create a &lt;code&gt;.env&lt;/code&gt; file in your project directory with the following variables:&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;LLAMA_API_KEY=your_llama_api_key_here&lt;br&gt;
LANGCHAIN_API_KEY=your_langchain_api_key_here&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;Step 1: Initializing the Llama 3 Model&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;In this step, we'll set up the Llama 3 model using the torch library. This will involve initializing the model with the API key and preparing it for text generation.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;from torch import Llama3
&lt;h1&gt;
  
  
  Initialize the Llama 3 model
&lt;/h1&gt;

&lt;p&gt;llama_model = Llama3(api_key="your_llama_api_key_here")&lt;/p&gt;
&lt;h1&gt;
  
  
  Set model parameters
&lt;/h1&gt;

&lt;p&gt;llama_model.configure(max_length=150, temperature=0.7)&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;Here, we initialize the Llama 3 model by passing the API key. The &lt;code&gt;configure&lt;/code&gt; method is used to set parameters such as &lt;code&gt;max_length&lt;/code&gt; which determines the maximum length of generated text, and &lt;code&gt;temperature&lt;/code&gt; which controls the randomness of the output.&lt;/p&gt;


&lt;h2&gt;Step 2: Integrating with LangChain&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;LangChain helps manage the orchestration of AI models and tools. We'll create a LangChain agent that interfaces with Llama 3 for generating text based on user inputs.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;from langchain import LangChain
&lt;h1&gt;
  
  
  Initialize LangChain
&lt;/h1&gt;

&lt;p&gt;langchain = LangChain(api_key="your_langchain_api_key_here")&lt;/p&gt;
&lt;h1&gt;
  
  
  Register the Llama 3 model as a tool
&lt;/h1&gt;

&lt;p&gt;langchain.register_tool("text_generator", llama_model)&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;In this step, we initialize a &lt;code&gt;LangChain&lt;/code&gt; and register our Llama 3 model as a tool named "text_generator". This allows the agent to invoke the model for text generation tasks.&lt;/p&gt;


&lt;h2&gt;Step 3: Developing the Application Interface&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;Now, let's create a simple interface for our application where users can input prompts and receive generated text responses.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;def generate_response(prompt):&lt;br&gt;
    # Use LangChain to generate text&lt;br&gt;
    response = langchain.invoke_tool("text_generator", input_data=prompt)&lt;br&gt;
    return response
&lt;h1&gt;
  
  
  Example usage
&lt;/h1&gt;

&lt;p&gt;user_prompt = "Tell me a story about a brave knight."&lt;br&gt;
print(generate_response(user_prompt))&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;The &lt;code&gt;generate_response&lt;/code&gt; function takes a user prompt and uses the LangChain to invoke the Llama 3 model. The generated response is then returned and can be printed or used in further application logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚠️ Common Mistake:&lt;/strong&gt; Ensure your API keys are valid and correctly set in the environment variables. Invalid keys will result in authentication errors.&lt;/p&gt;


&lt;h2&gt;Testing Your Implementation&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;To verify your application works correctly, run the script and input various prompts. You should receive coherent and contextually relevant responses from the Llama 3 model.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;python your_script.py&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;Check the console output for the generated text. If the responses are not as expected, revisit the configuration and ensure the model parameters are set appropriately.&lt;/p&gt;


&lt;h2&gt;What to Build Next&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;Once you've built this basic application, consider extending it with the following projects:&lt;/p&gt;
&lt;br&gt;
  &lt;ul&gt;

    &lt;li&gt;Integrate a user-friendly web interface using Flask or Django.&lt;/li&gt;

    &lt;li&gt;Expand the application to handle multiple languages with additional model configurations.&lt;/li&gt;

    &lt;li&gt;Implement a persistent memory feature to maintain context across multiple interactions.&lt;/li&gt;

  &lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Build a Governance-Aware AI Sandbox with Node.js</title>
      <dc:creator>Gate of AI</dc:creator>
      <pubDate>Thu, 13 Aug 2026 18:08:34 +0000</pubDate>
      <link>https://dev.to/gateofai/build-a-governance-aware-ai-sandbox-with-nodejs-40ej</link>
      <guid>https://dev.to/gateofai/build-a-governance-aware-ai-sandbox-with-nodejs-40ej</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🚀 Technical Briefing:&lt;/strong&gt; This tutorial is part of our deep-dive series on Agentic Workflows at &lt;a href="https://gateofai.com" rel="noopener noreferrer"&gt;Gate of AI&lt;/a&gt;. For the full technical breakdown, interactive code sandbox, and the native Arabic translation, visit the &lt;a href="https://gateofai.com/tutorial/build-governance-aware-ai-sandbox-nodejs/" rel="noopener noreferrer"&gt;original article here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;span&amp;gt;Tutorial&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;Advanced&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;⏱ 120 min read&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;© Gate of AI 2026-07-30&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Learn how to build a governance-aware AI sandbox using Node.js and Express, complete with RBAC, middleware, and AI integration, leveraging the latest AI governance features.&lt;/p&gt;


&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;br&gt;
  &lt;ul&gt;

    &lt;li&gt;Node.js 18.x&lt;/li&gt;

    &lt;li&gt;Express 5.x&lt;/li&gt;

    &lt;li&gt;TypeScript 5.4&lt;/li&gt;

    &lt;li&gt;API keys for OpenAI and Hugging Face&lt;/li&gt;

    &lt;li&gt;Advanced understanding of backend development&lt;/li&gt;

  &lt;/ul&gt;


&lt;h2&gt;What We're Building&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;In this tutorial, we will create a robust backend system using Node.js and Express, designed to enforce governance rules and manage AI services securely. The system will feature a modular monolithic architecture with middleware for token validation, RBAC (Role-Based Access Control), and project-level scoping. It will also integrate external AI services like OpenAI and Hugging Face to perform inference tasks.&lt;/p&gt;
&lt;br&gt;
  &lt;p&gt;The AI sandbox will serve as a controlled environment where developers can experiment with AI models while adhering to strict governance policies. This is particularly useful for organizations that need to ensure compliance and security in AI-driven applications, aligning with initiatives like Saudi Vision 2030.&lt;/p&gt;


&lt;h2&gt;Setup and Installation&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;We'll start by setting up the project environment. This involves installing Node.js, Express, and TypeScript, as well as configuring the necessary environment variables for API access.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;npm install &lt;a href="mailto:express@5.x"&gt;express@5.x&lt;/a&gt; &lt;a href="mailto:typescript@5.4"&gt;typescript@5.4&lt;/a&gt; better-sqlite3 dotenv&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;Next, create a &lt;code&gt;.env&lt;/code&gt; file to store API keys and other sensitive information securely. This file should not be committed to your version control system.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;&lt;br&gt;
API_KEY_OPENAI=your_openai_api_key&lt;br&gt;
API_KEY_HF=your_huggingface_api_key&lt;br&gt;
DB_PATH=./database.sqlite&lt;br&gt;
  &lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;Step 1: Setting Up the Express Server&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;In this step, we will set up a basic Express server with TypeScript. This server will serve as the foundation of our AI sandbox.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;&lt;br&gt;
import express, { Request, Response, NextFunction } from 'express';&lt;br&gt;
import dotenv from 'dotenv';

&lt;p&gt;dotenv.config();&lt;/p&gt;

&lt;p&gt;const app = express();&lt;br&gt;
const PORT = process.env.PORT || 3000;&lt;/p&gt;

&lt;p&gt;app.use(express.json());&lt;/p&gt;

&lt;p&gt;app.get('/', (req: Request, res: Response) =&amp;gt; {&lt;br&gt;
  res.send('Welcome to the AI Sandbox!');&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;app.listen(PORT, () =&amp;gt; {&lt;br&gt;
  console.log(&lt;code&gt;Server is running on port ${PORT}&lt;/code&gt;);&lt;br&gt;
});&lt;br&gt;
  &lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;Here, we import necessary modules, configure environment variables, and set up an Express application. We define a basic route to test the server setup and start the server on the specified port.&lt;/p&gt;


&lt;h2&gt;Step 2: Implementing Middleware for Governance&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;Middleware plays a crucial role in enforcing governance rules. We will implement middleware for token validation and RBAC.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;&lt;br&gt;
function tokenValidation(req: Request, res: Response, next: NextFunction) {&lt;br&gt;
  const token = req.headers['authorization'];&lt;br&gt;
  if (token === process.env.VALID_TOKEN) {&lt;br&gt;
    next();&lt;br&gt;
  } else {&lt;br&gt;
    res.status(403).send('Forbidden');&lt;br&gt;
  }&lt;br&gt;
}

&lt;p&gt;function rbacMiddleware(role: string) {&lt;br&gt;
  return (req: Request, res: Response, next: NextFunction) =&amp;gt; {&lt;br&gt;
    const userRole = req.headers['x-user-role'];&lt;br&gt;
    if (userRole === role) {&lt;br&gt;
      next();&lt;br&gt;
    } else {&lt;br&gt;
      res.status(403).send('Access Denied');&lt;br&gt;
    }&lt;br&gt;
  };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;app.use(tokenValidation);&lt;br&gt;
app.use(rbacMiddleware('admin'));&lt;br&gt;
  &lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;The &lt;code&gt;tokenValidation&lt;/code&gt; middleware checks if the request contains a valid authorization token. The &lt;code&gt;rbacMiddleware&lt;/code&gt; function is a factory that returns middleware enforcing role-based access control for a specific role.&lt;/p&gt;


&lt;h2&gt;Step 3: Integrating AI Services&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;In this step, we will integrate AI services using OpenAI and Hugging Face APIs. This allows our sandbox to perform AI tasks such as text generation or sentiment analysis.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;&lt;br&gt;
import { OpenAI } from 'openai';&lt;br&gt;
import axios from 'axios';

&lt;p&gt;const openai = new OpenAI(process.env.API_KEY_OPENAI);&lt;/p&gt;

&lt;p&gt;app.post('/generate-text', async (req: Request, res: Response) =&amp;gt; {&lt;br&gt;
  try {&lt;br&gt;
    const { prompt } = req.body;&lt;br&gt;
    const response = await openai.chat.completions.create({&lt;br&gt;
      model: 'gpt-4o',&lt;br&gt;
      messages: [{ role: 'user', content: prompt }]&lt;br&gt;
    });&lt;br&gt;
    res.json(response.choices[0].message);&lt;br&gt;
  } catch (error) {&lt;br&gt;
    res.status(500).send('Error generating text');&lt;br&gt;
  }&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;app.post('/analyze-sentiment', async (req: Request, res: Response) =&amp;gt; {&lt;br&gt;
  try {&lt;br&gt;
    const { text } = req.body;&lt;br&gt;
    const response = await axios.post('&lt;a href="https://api-inference.huggingface.co/models/sentiment-analysis" rel="noopener noreferrer"&gt;https://api-inference.huggingface.co/models/sentiment-analysis&lt;/a&gt;', { inputs: text }, {&lt;br&gt;
      headers: { Authorization: &lt;code&gt;Bearer ${process.env.API_KEY_HF}&lt;/code&gt; }&lt;br&gt;
    });&lt;br&gt;
    res.json(response.data);&lt;br&gt;
  } catch (error) {&lt;br&gt;
    res.status(500).send('Error analyzing sentiment');&lt;br&gt;
  }&lt;br&gt;
});&lt;br&gt;
  &lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;We initialize the OpenAI client and define endpoints for text generation and sentiment analysis. These endpoints use the respective APIs to process requests and return results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚠️ Common Mistake:&lt;/strong&gt; Ensure that your API keys are correctly set in the environment variables and that your server has internet access to connect to external APIs.&lt;/p&gt;


&lt;h2&gt;Testing Your Implementation&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;To verify the implementation, use tools like Postman to send requests to the endpoints. Ensure that the middleware correctly enforces governance rules, and the AI services return expected results.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;&lt;br&gt;
curl -X POST &lt;a href="http://localhost:3000/generate-text" rel="noopener noreferrer"&gt;http://localhost:3000/generate-text&lt;/a&gt; \&lt;br&gt;
-H "Content-Type: application/json" \&lt;br&gt;
-H "Authorization: Bearer YOUR_VALID_TOKEN" \&lt;br&gt;
-d '{"prompt": "Hello AI"}'

&lt;p&gt;curl -X POST &lt;a href="http://localhost:3000/analyze-sentiment" rel="noopener noreferrer"&gt;http://localhost:3000/analyze-sentiment&lt;/a&gt; \&lt;br&gt;
-H "Content-Type: application/json" \&lt;br&gt;
-H "Authorization: Bearer YOUR_VALID_TOKEN" \&lt;br&gt;
-d '{"text": "I love programming!"}'&lt;br&gt;
  &lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;What to Build Next&lt;/h2&gt;
&lt;br&gt;
  &lt;ul&gt;

    &lt;li&gt;Extend the sandbox to support more AI models and tasks.&lt;/li&gt;

    &lt;li&gt;Implement a UI using Next.js to interact with the AI sandbox.&lt;/li&gt;

    &lt;li&gt;Integrate logging and monitoring to track usage and performance.&lt;/li&gt;

  &lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>discuss</category>
    </item>
    <item>
      <title>FastAPI Mistral Ticket Router: Safe GCC Guide</title>
      <dc:creator>Gate of AI</dc:creator>
      <pubDate>Thu, 13 Aug 2026 18:08:19 +0000</pubDate>
      <link>https://dev.to/gateofai/fastapi-mistral-ticket-router-safe-gcc-guide-h7p</link>
      <guid>https://dev.to/gateofai/fastapi-mistral-ticket-router-safe-gcc-guide-h7p</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🚀 Technical Briefing:&lt;/strong&gt; This tutorial is part of our deep-dive series on Agentic Workflows at &lt;a href="https://gateofai.com" rel="noopener noreferrer"&gt;Gate of AI&lt;/a&gt;. For the full technical breakdown, interactive code sandbox, and the native Arabic translation, visit the &lt;a href="https://gateofai.com/tutorial/fastapi-mistral-ticket-router-guide/" rel="noopener noreferrer"&gt;original article here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Build a secure FastAPI ticket-routing foundation with strict request validation, deterministic escalation policies, SQLite audit records, and a safe integration boundary for a verified Mistral API implementation.&lt;/p&gt;

&lt;h2&gt;Important Accuracy Note Before You Start&lt;/h2&gt;

&lt;p&gt;The supplied source material confirms that Mistral AI is a Paris-based AI company and describes it as an OpenAI competitor. It does not provide official API documentation, supported model IDs, Python SDK package details, chat-completion method signatures, structured-output parameters, pricing, regional hosting commitments, or deployment guarantees.&lt;/p&gt;

&lt;p&gt;For that reason, this tutorial does not present unverified Mistral SDK code as production-ready fact. Instead, it builds a complete, runnable FastAPI ticket router with a deterministic local classifier and a clearly defined provider boundary. After consulting current official Mistral documentation and completing your own evaluation, replace the local classifier implementation at that boundary with the verified Mistral integration appropriate to your account and approved model.&lt;/p&gt;

&lt;p&gt;This is a safer engineering approach than copying an unverified model alias, SDK method, or JSON-mode option into a customer-facing workflow. The rest of the service—input contracts, audit storage, authorization, routing policy, tests, and operational controls—remains useful regardless of which approved AI provider or model you connect later.&lt;/p&gt;

&lt;h2&gt;What You Will Build&lt;/h2&gt;

&lt;p&gt;You will build a FastAPI service exposing &lt;code&gt;POST /tickets/classify&lt;/code&gt;. A client sends a support ticket with a ticket ID, subject, body, customer tier, and source. The service validates the request, classifies it into a limited taxonomy, applies deterministic escalation rules, records an audit event in SQLite, and returns a typed JSON response.&lt;/p&gt;

&lt;p&gt;The working baseline intentionally uses transparent keyword rules rather than pretending that an unverified external model call is available. It is not intended to replace an evaluated LLM. Its purpose is to give your team a safe, testable routing baseline and a precise interface for an eventual Mistral-backed classifier.&lt;/p&gt;

&lt;p&gt;This architecture is useful for service desks, customer support teams, internal IT queues, security intake, logistics exceptions, and account-management workflows. It is particularly relevant in GCC organisations adopting AI under programmes such as Saudi Vision 2030 and the UAE National Strategy for Artificial Intelligence: automation should preserve review paths, clear ownership, and auditable decisions when tickets may contain customer, employee, or security-sensitive information.&lt;/p&gt;

&lt;h2&gt;Prerequisites and Installation&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.10 or newer.&lt;/li&gt;
&lt;li&gt;Basic familiarity with virtual environments, HTTP APIs, and JSON.&lt;/li&gt;
&lt;li&gt;FastAPI, Uvicorn, Pydantic Settings, and pytest.&lt;/li&gt;
&lt;li&gt;A future Mistral API account only when you are ready to implement the provider adapter from current official documentation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create the project and install dependencies:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;mkdir fastapi-ticket-router
cd fastapi-ticket-router

python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip

cat &amp;gt; requirements.txt &amp;lt;&amp;lt;'EOF'
fastapi&amp;gt;=0.115.0
uvicorn[standard]&amp;gt;=0.30.0
pydantic&amp;gt;=2.8.0
pydantic-settings&amp;gt;=2.4.0
pytest&amp;gt;=8.3.0
EOF

pip install -r requirements.txt
mkdir -p app tests
touch app/__init__.py&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Create a local environment file. The application API key protects your own endpoint; it is separate from any future AI-provider credential. Do not commit this file to source control.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cat &amp;gt; .env &amp;lt;&amp;lt;'EOF'
APP_API_KEY=replace-with-a-long-random-secret
DATABASE_PATH=./ticket_router.db
MAX_TICKET_CHARACTERS=12000
EOF

cat &amp;gt; .gitignore &amp;lt;&amp;lt;'EOF'
.venv/
.env
__pycache__/
.pytest_cache/
*.pyc
ticket_router.db
EOF&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For production, place secrets in the encrypted secret-management facility approved by your cloud or platform team. Never send an AI-provider API key to browser JavaScript, mobile clients, public repositories, or client-side environment variables.&lt;/p&gt;

&lt;h2&gt;Step 1: Define Strict Contracts and Configuration&lt;/h2&gt;

&lt;p&gt;LLM integration should sit behind a deterministic API contract. Downstream systems should receive a finite set of categories, bounded confidence values, and explicit review flags—not arbitrary free-form text. Create &lt;code&gt;app/config.py&lt;/code&gt; and &lt;code&gt;app/schemas.py&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cat &amp;gt; app/config.py &amp;lt;&amp;lt;'EOF'
from functools import lru_cache
from pydantic import Field, SecretStr
from pydantic_settings import BaseSettings, SettingsConfigDict


class Settings(BaseSettings):
    model_config = SettingsConfigDict(env_file=".env", extra="ignore")
    app_api_key: SecretStr
    database_path: str = "./ticket_router.db"
    max_ticket_characters: int = Field(default=12000, ge=500, le=50000)


@lru_cache
def get_settings() -&amp;gt; Settings:
    return Settings()
EOF

cat &amp;gt; app/schemas.py &amp;lt;&amp;lt;'EOF'
from enum import Enum
from pydantic import BaseModel, Field, field_validator


class CustomerTier(str, Enum):
    free = "free"
    standard = "standard"
    business = "business"
    enterprise = "enterprise"


class TicketCategory(str, Enum):
    billing = "billing"
    account_access = "account_access"
    technical_issue = "technical_issue"
    security = "security"
    sales = "sales"
    feature_request = "feature_request"
    cancellation = "cancellation"
    abuse = "abuse"
    other = "other"


class Urgency(str, Enum):
    low = "low"
    normal = "normal"
    high = "high"
    critical = "critical"


class TicketInput(BaseModel):
    ticket_id: str = Field(min_length=3, max_length=100, pattern=r"^[A-Za-z0-9_-]+$")
    subject: str = Field(min_length=3, max_length=300)
    body: str = Field(min_length=10, max_length=12000)
    customer_tier: CustomerTier = CustomerTier.standard
    source: str = Field(default="api", max_length=50)

    @field_validator("subject", "body")
    @classmethod
    def reject_blank_text(cls, value: str) -&amp;gt; str:
        value = value.strip()
        if not value:
            raise ValueError("must not be blank")
        return value


class ClassificationResult(BaseModel):
    category: TicketCategory
    urgency: Urgency
    confidence: float = Field(ge=0.0, le=1.0)
    recommended_team: str = Field(min_length=2, max_length=80)
    customer_summary: str = Field(min_length=10, max_length=500)
    requires_human_review: bool
    review_reason: str | None = Field(default=None, max_length=300)


class ClassificationResponse(BaseModel):
    ticket_id: str
    classifier: str
    result: ClassificationResult
EOF&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The enums are a safety boundary. If a future AI model proposes a category outside this list, validate and reject it before any routing action occurs. Keep prompt instructions, provider output, and final routing policy separate.&lt;/p&gt;

&lt;h2&gt;Step 2: Add the Deterministic Classifier and Policy Layer&lt;/h2&gt;

&lt;p&gt;Create a baseline classifier. Security-related language is always routed to Security Operations and always requires human review. This is deliberate: high-risk escalation should not depend solely on a probability returned by a model.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cat &amp;gt; app/classifier.py &amp;lt;&amp;lt;'EOF'
from app.schemas import ClassificationResult, TicketCategory, TicketInput, Urgency

SECURITY_TERMS = ("api key", "credential", "breach", "compromised", "unauthorized", "fraud")
BILLING_TERMS = ("invoice", "refund", "charge", "payment", "subscription")
ACCESS_TERMS = ("login", "password", "mfa", "sso", "locked out")
TECHNICAL_TERMS = ("error", "outage", "bug", "api", "integration", "slow")


def apply_safety_policy(result: ClassificationResult) -&amp;gt; ClassificationResult:
    updated = result.model_copy(deep=True)
    if updated.category == TicketCategory.security:
        updated.recommended_team = "Security Operations"
        updated.requires_human_review = True
        updated.review_reason = "Security-related ticket requires human verification."
    elif updated.urgency == Urgency.critical:
        updated.requires_human_review = True
        updated.review_reason = "Critical urgency requires immediate human review."
    elif updated.confidence &amp;lt; 0.70:
        updated.requires_human_review = True
        updated.review_reason = "Confidence is below the automated-routing threshold."
    elif not updated.requires_human_review:
        updated.review_reason = None
    return updated


def classify_ticket(ticket: TicketInput) -&amp;gt; ClassificationResult:
    text = f"{ticket.subject} {ticket.body}".lower()
    category = TicketCategory.other
    team = "General Support"
    urgency = Urgency.normal
    confidence = 0.72

    if any(term in text for term in SECURITY_TERMS):
        category, team, urgency, confidence = TicketCategory.security, "Security Operations", Urgency.high, 0.90
    elif any(term in text for term in BILLING_TERMS):
        category, team, confidence = TicketCategory.billing, "Billing Support", 0.82
    elif any(term in text for term in ACCESS_TERMS):
        category, team, confidence = TicketCategory.account_access, "Identity Support", 0.82
    elif any(term in text for term in TECHNICAL_TERMS):
        category, team, confidence = TicketCategory.technical_issue, "Technical Support", 0.78

    result = ClassificationResult(
        category=category,
        urgency=urgency,
        confidence=confidence,
        recommended_team=team,
        customer_summary=f"Ticket received: {ticket.subject}",
        requires_human_review=False,
        review_reason=None,
    )
    return apply_safety_policy(result)
EOF&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When implementing the future Mistral adapter, preserve the function contract: accept &lt;code&gt;TicketInput&lt;/code&gt;, return &lt;code&gt;ClassificationResult&lt;/code&gt;, validate all provider output with Pydantic, and call &lt;code&gt;apply_safety_policy&lt;/code&gt; after validation. Do not let a provider response directly select an operational queue.&lt;/p&gt;

&lt;h2&gt;Step 3: Store Audit Records in SQLite&lt;/h2&gt;

&lt;p&gt;An audit record should identify the ticket, classifier, final validated decision, and timestamp. SQLite is suitable for local development, demos, and single-instance low-volume services. Use a managed relational database with backups, access controls, and migrations for larger production workloads.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cat &amp;gt; app/database.py &amp;lt;&amp;lt;'EOF'
import json
import sqlite3
from datetime import datetime, timezone
from pathlib import Path
from app.schemas import ClassificationResponse


def connection(path: str) -&amp;gt; sqlite3.Connection:
    Path(path).parent.mkdir(parents=True, exist_ok=True)
    return sqlite3.connect(path)


def initialize_database(path: str) -&amp;gt; None:
    with connection(path) as db:
        db.execute("""
        CREATE TABLE IF NOT EXISTS ticket_audits (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            ticket_id TEXT NOT NULL,
            classifier TEXT NOT NULL,
            result_json TEXT NOT NULL,
            created_at TEXT NOT NULL
        )
        """)


def save_audit(path: str, response: ClassificationResponse) -&amp;gt; None:
    with connection(path) as db:
        db.execute(
            "INSERT INTO ticket_audits(ticket_id, classifier, result_json, created_at) VALUES (?, ?, ?, ?)",
            (response.ticket_id, response.classifier,
             json.dumps(response.result.model_dump(mode="json")),
             datetime.now(timezone.utc).isoformat()),
        )
EOF&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Audit data can contain personal or commercially sensitive information. Define retention, deletion, access, encryption, and incident-response procedures before processing production tickets. GCC deployments should also assess applicable contractual, sectoral, and data-residency requirements with qualified legal and security stakeholders rather than assuming that a particular cloud or AI configuration meets local obligations.&lt;/p&gt;

&lt;h2&gt;Step 4: Expose the FastAPI Endpoint&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;cat &amp;gt; app/main.py &amp;lt;&amp;lt;'EOF'
import hmac
from contextlib import asynccontextmanager
from fastapi import Depends, FastAPI, Header, HTTPException, status
from app.classifier import classify_ticket
from app.config import Settings, get_settings
from app.database import initialize_database, save_audit
from app.schemas import ClassificationResponse, TicketInput


@asynccontextmanager
async def lifespan(app: FastAPI):
    initialize_database(get_settings().database_path)
    yield


app = FastAPI(title="FastAPI Ticket Router", version="1.0.0", lifespan=lifespan)


def require_api_key(
    x_api_key: str | None = Header(default=None, alias="X-API-Key"),
    settings: Settings = Depends(get_settings),
) -&amp;gt; None:
    expected = settings.app_api_key.get_secret_value()
    if x_api_key is None or not hmac.compare_digest(x_api_key, expected):
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid or missing API key")


@app.get("/health")
async def health() -&amp;gt; dict[str, str]:
    return {"status": "ok"}


@app.post("/tickets/classify", response_model=ClassificationResponse, dependencies=[Depends(require_api_key)])
async def route_ticket(ticket: TicketInput, settings: Settings = Depends(get_settings)) -&amp;gt; ClassificationResponse:
    if len(ticket.body) &amp;gt; settings.max_ticket_characters:
        raise HTTPException(status_code=422, detail="Ticket body exceeds configured maximum")
    response = ClassificationResponse(
        ticket_id=ticket.ticket_id,
        classifier="deterministic-baseline",
        result=classify_ticket(ticket),
    )
    save_audit(settings.database_path, response)
    return response
EOF

uvicorn app.main:app --reload --host 127.0.0.1 --port 8000&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Test the endpoint in another terminal:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;curl --request POST http://127.0.0.1:8000/tickets/classify \
  --header "Content-Type: application/json" \
  --header "X-API-Key: replace-with-a-long-random-secret" \
  --data '{"ticket_id":"SUP-1042","subject":"Possible API key exposure","body":"A production API key appeared in CI logs. Please investigate unauthorized use.","customer_tier":"enterprise","source":"support"}'&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The response must route the ticket to Security Operations and set &lt;code&gt;requires_human_review&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;. This is enforced by code, not by an optional model instruction.&lt;/p&gt;

&lt;h2&gt;Test the Non-Negotiable Policy&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;cat &amp;gt; tests/test_policy.py &amp;lt;&amp;lt;'EOF'
from app.classifier import classify_ticket
from app.schemas import TicketInput


def test_security_ticket_requires_human_review() -&amp;gt; None:
    result = classify_ticket(TicketInput(
        ticket_id="SUP-1",
        subject="Credential exposure",
        body="Our API key may be compromised and used by an unknown party.",
    ))
    assert result.recommended_team == "Security Operations"
    assert result.requires_human_review is True
    assert result.review_reason is not None
EOF

pytest -q&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Do not unit-test live provider calls as part of the standard test suite. Live calls are network-dependent, potentially billable, and variable. Instead, use unit tests for schemas and deterministic policy; then run controlled integration tests against an approved provider environment using sanitized fixtures.&lt;/p&gt;

&lt;h2&gt;Replacing the Baseline with a Verified Mistral Integration&lt;/h2&gt;

&lt;p&gt;Before changing the classifier, obtain the current official Mistral documentation for your account and verify the SDK version, authentication approach, supported model ID, request schema, response schema, structured-output option, error handling, rate limits, and data-processing terms. None of these implementation details are established in the supplied context.&lt;/p&gt;

&lt;p&gt;Implement the provider adapter behind the existing classifier boundary. Serialize ticket content as data rather than instructions; validate the resulting JSON against &lt;code&gt;ClassificationResult&lt;/code&gt;; reject malformed or out-of-taxonomy values; record the approved model identifier in the audit trail; and apply &lt;code&gt;apply_safety_policy&lt;/code&gt; after the model output is validated.&lt;/p&gt;

&lt;p&gt;Evaluate the integration on a versioned, sanitized dataset before release. Track category quality, security false negatives, human-review rate, latency, schema-valid response rate, override rate, and cost per ticket. For critical security, financial, healthcare, or public-sector workflows, design a safe failure mode: if the AI provider is unavailable or output validation fails, send the ticket to a human-review queue instead of silently guessing.&lt;/p&gt;

&lt;p&gt;For organisations working with SDAIA, G42, NEOM, stc, e&amp;amp;, or other regional enterprises, the key question is not simply whether an AI model can classify a ticket. The production question is whether the end-to-end system has approved data handling, accountable operators, reliable auditability, and a documented escalation path. This FastAPI foundation supports that discipline while leaving the model provider replaceable.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Python OpenAI Structured JSON Tutorial</title>
      <dc:creator>Gate of AI</dc:creator>
      <pubDate>Thu, 13 Aug 2026 18:08:05 +0000</pubDate>
      <link>https://dev.to/gateofai/python-openai-structured-json-tutorial-2k4a</link>
      <guid>https://dev.to/gateofai/python-openai-structured-json-tutorial-2k4a</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🚀 Technical Briefing:&lt;/strong&gt; This tutorial is part of our deep-dive series on Agentic Workflows at &lt;a href="https://gateofai.com" rel="noopener noreferrer"&gt;Gate of AI&lt;/a&gt;. For the full technical breakdown, interactive code sandbox, and the native Arabic translation, visit the &lt;a href="https://gateofai.com/tutorial/python-openai-structured-json-tutorial/" rel="noopener noreferrer"&gt;original article here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tutorial&lt;/p&gt;

&lt;h1&gt;Python Structured JSON Extraction with OpenAI&lt;/h1&gt;

&lt;p&gt;Build a Python command-line tool that loads travel-journal files, requests JSON-shaped extraction from an OpenAI chat model, validates every response with Pydantic, and writes a reusable report.&lt;/p&gt;

&lt;h2&gt;What You Will Build&lt;/h2&gt;

&lt;p&gt;This tutorial builds &lt;code&gt;travel_journal_analyzer&lt;/code&gt;, a small but production-minded Python application. It accepts a text, Markdown, CSV file, or a directory containing those formats. It converts each source into a consistent &lt;code&gt;JournalEntry&lt;/code&gt;, sends the entry to an OpenAI chat model, validates the returned JSON locally, and writes one JSON report for downstream software.&lt;/p&gt;

&lt;p&gt;The report has a deliberately narrow purpose: identify cities mentioned in an entry, explicitly named restaurants, dishes, ratings where stated, sentiment, practical tips, and a concise summary. The application does not treat a valid JSON shape as proof that a claim is true. Its prompt instructs the model to extract facts only from the supplied entry, while local validation checks the data contract before results are exported.&lt;/p&gt;

&lt;p&gt;Reliable structured extraction combines two boundaries. The first is the requested JSON schema: it defines the fields an application expects. The second is local validation with Pydantic: it rejects malformed values, such as a rating outside a five-point range. Research on structured generation describes the importance of reliable, typed output for applications that need predictable data rather than unconstrained prose. In practical Python work, these boundaries make testing and maintenance substantially easier.&lt;/p&gt;

&lt;h2&gt;Prerequisites and Setup&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.10 or later.&lt;/li&gt;
&lt;li&gt;An OpenAI API key and access to a chat model configured through an environment variable.&lt;/li&gt;
&lt;li&gt;Basic familiarity with a terminal, files, and Python functions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create a project and isolated virtual environment:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;mkdir travel-journal-analyzer
cd travel-journal-analyzer
python -m venv .venv

# macOS or Linux
source .venv/bin/activate

# Windows PowerShell
# .venv\Scripts\Activate.ps1

python -m pip install --upgrade pip
python -m pip install "openai&amp;gt;=1.0.0" "pydantic&amp;gt;=2.7.0" "python-dotenv&amp;gt;=1.0.1" "pytest&amp;gt;=8.0.0"
mkdir data output tests&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Create &lt;code&gt;.env&lt;/code&gt;. Keep this file out of source control. API keys belong in environment variables locally and in a deployment secret manager in production.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;OPENAI_API_KEY=your-api-key
OPENAI_MODEL=your-chat-model
MAX_ENTRY_CHARACTERS=12000
REQUEST_TIMEOUT_SECONDS=45&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Create &lt;code&gt;.gitignore&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;.env
.venv/
__pycache__/
.pytest_cache/
output/
*.pyc&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This tutorial uses the modern client-based OpenAI Python pattern: &lt;code&gt;from openai import OpenAI&lt;/code&gt;, then &lt;code&gt;client.chat.completions.create(...)&lt;/code&gt;. Do not use legacy module-level completion calls.&lt;/p&gt;

&lt;h2&gt;Step 1: Define the Data Contract&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;models.py&lt;/code&gt;. Nullable fields represent facts that the source did not provide. That is preferable to inventing a city, cuisine, or rating.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;from __future__ import annotations

from typing import Literal
from pydantic import BaseModel, Field, field_validator


class JournalEntry(BaseModel):
    source_name: str = Field(min_length=1, max_length=255)
    entry_id: str = Field(min_length=1, max_length=100)
    text: str = Field(min_length=1)

    @field_validator("text")
    @classmethod
    def validate_text(cls, value: str) -&amp;gt; str:
        cleaned = value.strip()
        if not cleaned:
            raise ValueError("Journal entry text cannot be blank.")
        return cleaned


class RestaurantFinding(BaseModel):
    name: str = Field(min_length=1, max_length=200)
    city: str | None = Field(default=None, max_length=120)
    country: str | None = Field(default=None, max_length=120)
    cuisine: str | None = Field(default=None, max_length=120)
    dishes: list[str] = Field(default_factory=list)
    rating_out_of_five: float | None = Field(default=None, ge=0, le=5)
    sentiment: Literal["positive", "neutral", "negative"]
    recommendation_reason: str = Field(min_length=1, max_length=600)


class JournalAnalysis(BaseModel):
    entry_id: str = Field(min_length=1, max_length=100)
    cities_mentioned: list[str] = Field(default_factory=list)
    restaurants: list[RestaurantFinding] = Field(default_factory=list)
    travel_tips: list[str] = Field(default_factory=list)
    concise_summary: str = Field(min_length=1, max_length=1000)


class AnalysisReport(BaseModel):
    generated_at_utc: str
    model: str
    total_entries: int = Field(ge=0)
    successful_analyses: int = Field(ge=0)
    failed_entries: list[str] = Field(default_factory=list)
    analyses: list[JournalAnalysis] = Field(default_factory=list)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The models are not merely documentation. &lt;code&gt;JournalAnalysis.model_validate_json()&lt;/code&gt; turns the model response into a validated object. A response with an invalid sentiment label or a six-point rating fails before it reaches a database, spreadsheet, or customer-facing interface.&lt;/p&gt;

&lt;h2&gt;Step 2: Load Text and CSV Inputs&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;journal_loader.py&lt;/code&gt;. Plain-text and Markdown files create one entry each. A CSV file requires a &lt;code&gt;text&lt;/code&gt; column and creates one entry for every non-empty row. The character limit prevents unexpectedly large requests.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;from __future__ import annotations

import csv
from pathlib import Path
from models import JournalEntry

SUPPORTED_SUFFIXES = {".txt", ".md", ".csv"}


def load_journal_entries(path_value: str, max_characters: int) -&amp;gt; list[JournalEntry]:
    path = Path(path_value).expanduser().resolve()
    if not path.exists():
        raise FileNotFoundError(f"Input path does not exist: {path}")

    if path.is_dir():
        entries: list[JournalEntry] = []
        for child in sorted(path.iterdir()):
            if child.is_file() and child.suffix.lower() in SUPPORTED_SUFFIXES:
                entries.extend(load_journal_entries(str(child), max_characters))
        if not entries:
            raise ValueError("Directory contains no supported input files.")
        return entries

    if path.suffix.lower() in {".txt", ".md"}:
        text = path.read_text(encoding="utf-8").strip()
        _check_length(text, path.name, max_characters)
        return [JournalEntry(source_name=path.name, entry_id=path.stem, text=text)]

    if path.suffix.lower() != ".csv":
        raise ValueError("Use a .txt, .md, .csv file, or directory.")

    entries = []
    with path.open("r", encoding="utf-8-sig", newline="") as handle:
        reader = csv.DictReader(handle)
        if not reader.fieldnames or "text" not in reader.fieldnames:
            raise ValueError("CSV must contain a column named 'text'.")
        for row_number, row in enumerate(reader, start=2):
            text = (row.get("text") or "").strip()
            if not text:
                continue
            _check_length(text, f"{path.name} row {row_number}", max_characters)
            entries.append(JournalEntry(
                source_name=(row.get("source_name") or path.name).strip(),
                entry_id=(row.get("entry_id") or f"{path.stem}-{row_number}").strip(),
                text=text,
            ))
    if not entries:
        raise ValueError("CSV contains no non-empty text rows.")
    return entries


def _check_length(text: str, label: str, maximum: int) -&amp;gt; None:
    if not text:
        raise ValueError(f"{label} is empty.")
    if len(text) &amp;gt; maximum:
        raise ValueError(f"{label} exceeds the {maximum}-character limit.")&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Save this sample as &lt;code&gt;data/journal.txt&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;We arrived in Lisbon on a rainy Thursday.
For dinner, we booked Taberna da Rua das Flores. The grilled octopus was tender,
and I would rate the experience 4.5 out of 5. Reserve ahead because it is small.

Two days later in Porto, Cafe Santiago served a memorable francesinha.
The sandwich was rich but the service was slow, so I felt neutral overall.&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Step 3: Request JSON and Validate It&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;analyzer.py&lt;/code&gt;. The schema below is passed as a requested response format. Your configured model must support the selected response-format capability; verify that support in the current OpenAI documentation for the model available to your account before deploying. Regardless of the upstream response constraint, the code performs local Pydantic validation.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;from __future__ import annotations

from openai import OpenAI
from pydantic import ValidationError

from models import JournalAnalysis, JournalEntry

SCHEMA = {
    "name": "travel_journal_analysis",
    "strict": True,
    "schema": {
        "type": "object",
        "additionalProperties": False,
        "properties": {
            "entry_id": {"type": "string"},
            "cities_mentioned": {"type": "array", "items": {"type": "string"}},
            "restaurants": {"type": "array", "items": {"type": "object", "additionalProperties": False, "properties": {
                "name": {"type": "string"}, "city": {"type": ["string", "null"]},
                "country": {"type": ["string", "null"]}, "cuisine": {"type": ["string", "null"]},
                "dishes": {"type": "array", "items": {"type": "string"}},
                "rating_out_of_five": {"type": ["number", "null"]},
                "sentiment": {"type": "string", "enum": ["positive", "neutral", "negative"]},
                "recommendation_reason": {"type": "string"}
            }, "required": ["name", "city", "country", "cuisine", "dishes", "rating_out_of_five", "sentiment", "recommendation_reason"]}},
            "travel_tips": {"type": "array", "items": {"type": "string"}},
            "concise_summary": {"type": "string"}
        },
        "required": ["entry_id", "cities_mentioned", "restaurants", "travel_tips", "concise_summary"]
    }
}

SYSTEM_PROMPT = """Extract facts only from the journal entry.
Include restaurants only when explicitly named. Never invent facts.
Use null for unknown scalar values. Return only schema-conforming JSON."""


class JournalAnalyzer:
    def __init__(self, api_key: str, model: str, timeout: float) -&amp;gt; None:
        self.model = model
        self.client = OpenAI(api_key=api_key, timeout=timeout, max_retries=0)

    def analyze(self, entry: JournalEntry) -&amp;gt; JournalAnalysis:
        completion = self.client.chat.completions.create(
            model=self.model,
            temperature=0,
            response_format={"type": "json_schema", "json_schema": SCHEMA},
            messages=[
                {"role": "system", "content": SYSTEM_PROMPT},
                {"role": "user", "content": f"Required entry_id: {entry.entry_id}\n\nJournal:\n{entry.text}"},
            ],
        )
        content = completion.choices[0].message.content
        if not content:
            raise RuntimeError("The model returned an empty response.")
        try:
            result = JournalAnalysis.model_validate_json(content)
        except ValidationError as error:
            raise RuntimeError(f"Local schema validation failed: {error}") from error
        if result.entry_id != entry.entry_id:
            raise RuntimeError("Response entry_id does not match the input entry.")
        return result&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The extraction policy is intentionally conservative. An unnamed kiosk may be discussed negatively in a journal, but it must not become an invented restaurant record. If unnamed venues matter to the product, add a distinct field and clearly communicate that it represents an unnamed mention, not an official venue identity.&lt;/p&gt;

&lt;h2&gt;Step 4: Create the Command-Line Application&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;from __future__ import annotations

import argparse
import os
from datetime import datetime, timezone
from pathlib import Path
from dotenv import load_dotenv

from analyzer import JournalAnalyzer
from journal_loader import load_journal_entries
from models import AnalysisReport


def main() -&amp;gt; int:
    parser = argparse.ArgumentParser()
    parser.add_argument("input_path")
    parser.add_argument("--output", default="output/travel-analysis.json")
    args = parser.parse_args()

    load_dotenv()
    api_key = os.getenv("OPENAI_API_KEY", "").strip()
    model = os.getenv("OPENAI_MODEL", "").strip()
    if not api_key or not model:
        raise RuntimeError("Set OPENAI_API_KEY and OPENAI_MODEL in .env or your shell.")

    maximum = int(os.getenv("MAX_ENTRY_CHARACTERS", "12000"))
    timeout = float(os.getenv("REQUEST_TIMEOUT_SECONDS", "45"))
    entries = load_journal_entries(args.input_path, maximum)
    analyzer = JournalAnalyzer(api_key, model, timeout)

    analyses = []
    failed = []
    for entry in entries:
        try:
            analyses.append(analyzer.analyze(entry))
        except RuntimeError as error:
            failed.append(entry.entry_id)
            print(f"Failed {entry.entry_id}: {error}")

    report = AnalysisReport(
        generated_at_utc=datetime.now(timezone.utc).isoformat(),
        model=model,
        total_entries=len(entries),
        successful_analyses=len(analyses),
        failed_entries=failed,
        analyses=analyses,
    )
    destination = Path(args.output)
    destination.parent.mkdir(parents=True, exist_ok=True)
    temporary = destination.with_suffix(destination.suffix + ".tmp")
    temporary.write_text(report.model_dump_json(indent=2), encoding="utf-8")
    temporary.replace(destination)
    print(f"Wrote {report.successful_analyses}/{report.total_entries} analyses to {destination}")
    return 1 if failed else 0


if __name__ == "__main__":
    raise SystemExit(main())&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Run the tool and inspect the output:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;python main.py data/journal.txt --output output/journal-report.json
python -m json.tool output/journal-report.json&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The temporary-file replacement avoids leaving a partially written final report if the process stops during serialization. The process returns a non-zero status when one or more entries fail, which is useful in scheduled jobs and CI.&lt;/p&gt;

&lt;h2&gt;Testing and Production Checks&lt;/h2&gt;

&lt;p&gt;Test deterministic components without calling an API. For example, verify that the loader rejects a CSV without a &lt;code&gt;text&lt;/code&gt; column, that blank rows are skipped, and that ratings over five fail Pydantic validation. Mock the OpenAI client for analyzer unit tests, then run a small intentional smoke test with a real credential.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;from models import RestaurantFinding
from pydantic import ValidationError
import pytest


def test_invalid_rating_is_rejected():
    with pytest.raises(ValidationError):
        RestaurantFinding(
            name="Example", sentiment="positive",
            rating_out_of_five=6,
            recommendation_reason="Unsupported rating range.",
        )&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Schema validity is not factual validity. Review representative outputs for named-entity grounding, rating fidelity, correct sentiment, and unsupported details. Maintain a permissioned evaluation set when changing prompts, model configuration, schemas, or SDK versions. Avoid logging raw journal content by default because travel notes can contain personal data.&lt;/p&gt;

&lt;p&gt;For GCC and Middle East deployments, apply the same data-handling discipline to Arabic and English input, local privacy obligations, data residency requirements, and organizational retention rules. This tutorial does not make claims about a particular regional provider, initiative, or infrastructure arrangement; teams should validate those requirements with their legal, security, and platform stakeholders before production use.&lt;/p&gt;

&lt;h2&gt;Next Steps&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Store approved findings in SQLite and hash source entries to avoid repeated analysis.&lt;/li&gt;
&lt;li&gt;Add a human review step before publishing recommendations.&lt;/li&gt;
&lt;li&gt;Track input size, latency, failures, model configuration, and evaluation results without retaining unnecessary journal text.&lt;/li&gt;
&lt;li&gt;Add explicit source excerpts to the schema if reviewers need faster fact verification.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The central lesson is simple: use typed contracts and controlled inputs to turn flexible model output into application data, then test both the software boundary and the factual usefulness of the result.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Integrating AI APIs with Advanced Libraries</title>
      <dc:creator>Gate of AI</dc:creator>
      <pubDate>Wed, 22 Jul 2026 09:11:48 +0000</pubDate>
      <link>https://dev.to/gateofai/integrating-ai-apis-with-advanced-libraries-241n</link>
      <guid>https://dev.to/gateofai/integrating-ai-apis-with-advanced-libraries-241n</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🚀 Technical Briefing:&lt;/strong&gt; This tutorial is part of our deep-dive series on Agentic Workflows at &lt;a href="https://gateofai.com" rel="noopener noreferrer"&gt;Gate of AI&lt;/a&gt;. For the full technical breakdown, interactive code sandbox, and the native Arabic translation, visit the &lt;a href="https://gateofai.com/tutorial/integrating-ai-apis-advanced-libraries/" rel="noopener noreferrer"&gt;original article here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;span&amp;gt;Tutorial&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;Intermediate&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;⏱ 45 min read&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;© Gate of AI 2026-07-20&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this tutorial, we will integrate AI capabilities into your application using the latest API-driven interactions with powerful language models, focusing on real-time data processing and analysis.&lt;/p&gt;


&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;br&gt;
  &lt;ul&gt;

    &lt;li&gt;R version 4.2.0 or newer&lt;/li&gt;

    &lt;li&gt;Latest API client libraries installed&lt;/li&gt;

    &lt;li&gt;API key from a verified AI provider&lt;/li&gt;

    &lt;li&gt;Intermediate programming skills in R&lt;/li&gt;

  &lt;/ul&gt;


&lt;h2&gt;What We're Building&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;This tutorial will guide you through creating a robust application that leverages modern API client libraries to interact with AI models. Our end goal is to build a system that can dynamically generate language-based outputs or embeddings, depending on user input or data streams.&lt;/p&gt;
&lt;br&gt;
  &lt;p&gt;The finished project will allow users to input text prompts, which the application will process to call the AI model's API. The model will return processed language data, which can be used for various applications like generating content, analyzing text, or creating data embeddings for further processing in machine learning pipelines.&lt;/p&gt;


&lt;h2&gt;Setup and Installation&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;To start, ensure that the latest API client libraries are correctly installed in your R environment, along with all necessary dependencies for API communication. This setup includes configuring environment variables to securely handle API keys.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;install.packages("httr")&lt;br&gt;
install.packages("dotenv")&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;Next, create a .env file in your project directory to store your API keys securely. This file should not be shared or included in version control.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;&lt;br&gt;
API_KEY=your_api_key&lt;br&gt;
  &lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;Use the &lt;code&gt;dotenv&lt;/code&gt; package to load these environment variables into your R session:&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;library(dotenv)&lt;br&gt;
dotenv::load_dot_env()&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;Step 1: Setting Up API Communication&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;This step involves setting up a function to handle API requests to the AI model. We'll create a function that prepares the request, sends it, and processes the response.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;&lt;br&gt;
library(httr)

&lt;p&gt;send_api_request &amp;lt;- function(prompt, model_type = "gpt-4o") {&lt;br&gt;
  api_key &amp;lt;- Sys.getenv("API_KEY")&lt;br&gt;
  response &amp;lt;- POST(&lt;br&gt;
    url = "&lt;a href="https://api.example.com/v1/chat/completions" rel="noopener noreferrer"&gt;https://api.example.com/v1/chat/completions&lt;/a&gt;",&lt;br&gt;
    add_headers(Authorization = paste("Bearer", api_key)),&lt;br&gt;
    body = list(&lt;br&gt;
      model = model_type,&lt;br&gt;
      messages = list(list(role = "user", content = prompt))&lt;br&gt;
    ),&lt;br&gt;
    encode = "json"&lt;br&gt;
  )&lt;/p&gt;

&lt;p&gt;stop_for_status(response)&lt;br&gt;
  content(response, "parsed")&lt;br&gt;
}&lt;br&gt;
  &lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;This function uses the &lt;code&gt;httr&lt;/code&gt; package to send a POST request to the API with the user's prompt. It handles authorization by using the API key stored in environment variables and returns the parsed JSON response.&lt;/p&gt;


&lt;h2&gt;Step 2: Processing API Responses&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;Once we have the response from the API, we need to process it to extract the relevant information and present it in a user-friendly format.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;&lt;br&gt;
process_response &amp;lt;- function(api_response) {&lt;br&gt;
  choices &amp;lt;- api_response$choices&lt;br&gt;
  if (length(choices) &amp;gt; 0) {&lt;br&gt;
    return(choices[[1]]$message$content)&lt;br&gt;
  } else {&lt;br&gt;
    stop("No valid response from API")&lt;br&gt;
  }&lt;br&gt;
}
&lt;h1&gt;
  
  
  Example usage
&lt;/h1&gt;

&lt;p&gt;response &amp;lt;- send_api_request("Tell me a joke.")&lt;br&gt;
joke &amp;lt;- process_response(response)&lt;br&gt;
print(joke)&lt;br&gt;
  &lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;This code extracts the content of the message from the API's response. If the response contains valid data, it returns the text; otherwise, it raises an error.&lt;/p&gt;


&lt;h2&gt;Step 3: Integrating with Advanced Libraries&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;In this step, we will integrate our API communication functions with advanced libraries to leverage their capabilities for more sophisticated data handling and manipulation.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;
&lt;h1&gt;
  
  
  Assuming a hypothetical advanced library for embeddings
&lt;/h1&gt;

&lt;p&gt;library(AdvancedAI)&lt;/p&gt;

&lt;p&gt;generate_embeddings &amp;lt;- function(text_input) {&lt;br&gt;
  model_response &amp;lt;- send_api_request(text_input, model_type = "gpt-4o")&lt;br&gt;
  processed_text &amp;lt;- process_response(model_response)&lt;/p&gt;

&lt;p&gt;# Use AdvancedAI to generate embeddings&lt;br&gt;
  embeddings &amp;lt;- AdvancedAI::generate_embeddings(processed_text)&lt;br&gt;
  return(embeddings)&lt;br&gt;
}&lt;/p&gt;
&lt;h1&gt;
  
  
  Example usage
&lt;/h1&gt;

&lt;p&gt;embedding_result &amp;lt;- generate_embeddings("Analyze this sentence for sentiment.")&lt;br&gt;
print(embedding_result)&lt;br&gt;
  &lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;This function integrates the API request with advanced embedding generation capabilities, allowing us to convert processed text into embeddings for further analysis or machine learning applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚠️ Common Mistake:&lt;/strong&gt; Ensure that the API keys are correctly set in your environment. A common issue is not loading the .env file correctly, leading to failed authentication. Always verify your environment variables are loaded before making API requests.&lt;/p&gt;


&lt;h2&gt;Testing Your Implementation&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;To verify that your implementation works correctly, test the functions with various inputs and ensure the outputs are as expected. You can use the following code to do so:&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;&lt;br&gt;
test_prompt &amp;lt;- "What is the capital of France?"&lt;br&gt;
response &amp;lt;- send_api_request(test_prompt)&lt;br&gt;
print(process_response(response))
&lt;h1&gt;
  
  
  Test embedding generation
&lt;/h1&gt;

&lt;p&gt;embedding_test &amp;lt;- generate_embeddings("Test this embedding function.")&lt;br&gt;
print(embedding_test)&lt;br&gt;
  &lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;When run, the first test should return "Paris" as the capital of France, and the second test should return a vector of embeddings indicating the function's success in processing the input.&lt;/p&gt;


&lt;h2&gt;What to Build Next&lt;/h2&gt;
&lt;br&gt;
  &lt;ul&gt;

    &lt;li&gt;Extend the application to handle multi-turn conversations by maintaining a chat history.&lt;/li&gt;

    &lt;li&gt;Integrate sentiment analysis and topic modeling using advanced libraries and API responses for more enriched data insights.&lt;/li&gt;

    &lt;li&gt;Build a web interface using Shiny to allow non-technical users to interact with the AI-driven application easily.&lt;/li&gt;

  &lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Mastering AI Prompt Engineering in 2026</title>
      <dc:creator>Gate of AI</dc:creator>
      <pubDate>Wed, 22 Jul 2026 09:11:34 +0000</pubDate>
      <link>https://dev.to/gateofai/mastering-ai-prompt-engineering-in-2026-2408</link>
      <guid>https://dev.to/gateofai/mastering-ai-prompt-engineering-in-2026-2408</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🚀 Technical Briefing:&lt;/strong&gt; This tutorial is part of our deep-dive series on Agentic Workflows at &lt;a href="https://gateofai.com" rel="noopener noreferrer"&gt;Gate of AI&lt;/a&gt;. For the full technical breakdown, interactive code sandbox, and the native Arabic translation, visit the &lt;a href="https://gateofai.com/tutorial/mastering-ai-prompt-engineering-2026/" rel="noopener noreferrer"&gt;original article here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;span&amp;gt;Tutorial&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;Advanced&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;⏱ 45 min read&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;© Gate of AI 2026-07-18&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Learn how to craft effective prompts for AI models to enhance performance and accuracy in various applications, with insights from the latest research.&lt;/p&gt;


&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;br&gt;
  &lt;ul&gt;

    &lt;li&gt;Python 3.10 or later&lt;/li&gt;

    &lt;li&gt;OpenAI and Anthropic API keys&lt;/li&gt;

    &lt;li&gt;Familiarity with AI model concepts and prompt engineering&lt;/li&gt;

  &lt;/ul&gt;


&lt;h2&gt;What We're Building&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;In this comprehensive tutorial, we will delve into the art and science of prompt engineering for AI models using the latest techniques available in 2026. By the end of this tutorial, you'll be able to design prompts that yield highly accurate and contextually relevant responses from AI models like OpenAI's GPT-4o and Anthropic's Claude-3-5-sonnet-20241022.&lt;/p&gt;
&lt;br&gt;
  &lt;p&gt;The finished project will enable you to create tailored AI interactions that can be applied across various domains such as customer support, content generation, and data analysis, significantly improving model output quality and applicability.&lt;/p&gt;


&lt;h2&gt;Setup and Installation&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;To get started with prompt engineering, you need to set up your environment with the necessary tools and libraries. We'll be using Python as our primary language due to its rich ecosystem of AI and machine learning libraries.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;pip install openai anthropic&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;Next, you need to configure your environment variables to securely store your API keys. This is crucial for authenticating requests to the AI services.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;
&lt;h1&gt;
  
  
  .env file
&lt;/h1&gt;

&lt;p&gt;OPENAI_API_KEY=your-openai-api-key&lt;br&gt;
ANTHROPIC_API_KEY=your-anthropic-api-key&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;Step 1: Understanding Prompt Basics&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;Before diving into advanced techniques, it's essential to understand the basics of prompt engineering. A prompt is the input you provide to an AI model to guide its response. The quality of the prompt directly influences the model's output.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;&lt;br&gt;
from openai import OpenAI

&lt;p&gt;client = OpenAI(api_key='your-openai-api-key')&lt;/p&gt;

&lt;p&gt;response = client.chat.completions.create(&lt;br&gt;
    model="gpt-4o",&lt;br&gt;
    messages=[&lt;br&gt;
        {"role": "system", "content": "You are a helpful assistant."},&lt;br&gt;
        {"role": "user", "content": "Can you summarize the key benefits of AI in healthcare?"}&lt;br&gt;
    ]&lt;br&gt;
)&lt;/p&gt;

&lt;p&gt;print(response.choices[0].message['content'])&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;In this code, we initialize the OpenAI client and send a chat completion request. The system message sets the context, while the user message is the prompt. The model then generates a response based on these inputs.&lt;/p&gt;


&lt;h2&gt;Step 2: Implementing Few-shot Prompting&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;Few-shot prompting involves providing the AI model with examples of the input-output pair you expect. This technique helps the model understand the desired pattern and improves response accuracy.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;&lt;br&gt;
from anthropic import Anthropic

&lt;p&gt;client = Anthropic(api_key='your-anthropic-api-key')&lt;/p&gt;

&lt;p&gt;response = client.messages.create(&lt;br&gt;
    model="claude-3-5-sonnet-20241022",&lt;br&gt;
    messages=[&lt;br&gt;
        {"role": "system", "content": "You are an expert in financial markets."},&lt;br&gt;
        {"role": "user", "content": "Here's an example of a market analysis: ..."},&lt;br&gt;
        {"role": "user", "content": "Can you analyze the following market data: ..."}&lt;br&gt;
    ]&lt;br&gt;
)&lt;/p&gt;

&lt;p&gt;print(response.choices[0].message['content'])&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;This example demonstrates how to provide the model with context and examples to guide its analysis of new data. The few-shot approach is particularly useful when the model needs to understand specific styles or formats.&lt;/p&gt;


&lt;h2&gt;Step 3: Utilizing Chain-of-Thought Prompting&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;Chain-of-thought prompting encourages the model to think through problems step by step, leading to more logical and comprehensive outputs. This technique is beneficial for complex problem-solving and reasoning tasks.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;&lt;br&gt;
response = client.chat.completions.create(&lt;br&gt;
    model="gpt-4o",&lt;br&gt;
    messages=[&lt;br&gt;
        {"role": "system", "content": "You are a problem-solving assistant."},&lt;br&gt;
        {"role": "user", "content": "Explain the process of photosynthesis step by step."}&lt;br&gt;
    ]&lt;br&gt;
)

&lt;p&gt;print(response.choices[0].message['content'])&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;Here, the model is prompted to break down the process of photosynthesis into logical steps, demonstrating its understanding of the topic while providing a clear, concise explanation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚠️ Common Mistake:&lt;/strong&gt; Avoid using overly complex or ambiguous language in your prompts, as this can confuse the model and lead to inaccurate responses. Always aim for clarity and simplicity.&lt;/p&gt;


&lt;h2&gt;Testing Your Implementation&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;To ensure your prompts are effective, you should test them across various scenarios and inputs. This will help you refine your approach and improve the model's performance.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;&lt;br&gt;
def test_prompt(prompt, expected_output):&lt;br&gt;
    response = client.chat.completions.create(&lt;br&gt;
        model="gpt-4o",&lt;br&gt;
        messages=[&lt;br&gt;
            {"role": "system", "content": "You are a helpful assistant."},&lt;br&gt;
            {"role": "user", "content": prompt}&lt;br&gt;
        ]&lt;br&gt;
    )&lt;br&gt;
    assert response.choices[0].message['content'] == expected_output, "Test failed!"
&lt;h1&gt;
  
  
  Example test case
&lt;/h1&gt;

&lt;p&gt;test_prompt("Summarize the benefits of AI in education.", "AI can personalize learning experiences, automate administrative tasks, and provide real-time analytics.")&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;This test function checks whether the model's output matches the expected result, allowing you to verify the effectiveness of your prompts.&lt;/p&gt;


&lt;h2&gt;What to Build Next&lt;/h2&gt;
&lt;br&gt;
  &lt;ul&gt;

    &lt;li&gt;Develop a chatbot using advanced prompt engineering techniques for customer service.&lt;/li&gt;

    &lt;li&gt;Create a content generation tool that leverages few-shot and chain-of-thought prompting.&lt;/li&gt;

    &lt;li&gt;Integrate AI models into a data analysis platform to automate insights generation.&lt;/li&gt;

  &lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Build Conversational AI with OpenAI &amp; Anthropic</title>
      <dc:creator>Gate of AI</dc:creator>
      <pubDate>Tue, 14 Jul 2026 14:54:48 +0000</pubDate>
      <link>https://dev.to/gateofai/build-conversational-ai-with-openai-anthropic-dki</link>
      <guid>https://dev.to/gateofai/build-conversational-ai-with-openai-anthropic-dki</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🚀 Technical Briefing:&lt;/strong&gt; This tutorial is part of our deep-dive series on Agentic Workflows at &lt;a href="https://gateofai.com" rel="noopener noreferrer"&gt;Gate of AI&lt;/a&gt;. For the full technical breakdown, interactive code sandbox, and the native Arabic translation, visit the &lt;a href="https://gateofai.com/tutorial/build-conversational-ai-openai-anthropic/" rel="noopener noreferrer"&gt;original article here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;span&amp;gt;Tutorial&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;Intermediate&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;⏱ 45 min read&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;© Gate of AI 2026-07-14&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this tutorial, we will build a robust conversational AI by integrating OpenAI, Anthropic, and Mistral APIs, showcasing their unique strengths in generating and managing conversations.&lt;/p&gt;


&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;br&gt;
  &lt;ul&gt;

    &lt;li&gt;Node.js v18 or later&lt;/li&gt;

    &lt;li&gt;API keys for OpenAI, Anthropic, and Mistral&lt;/li&gt;

    &lt;li&gt;Intermediate understanding of JavaScript and API integration&lt;/li&gt;

  &lt;/ul&gt;


&lt;h2&gt;What We're Building&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;In this project, we will create a conversational AI application that leverages the latest advancements in AI models from OpenAI, Anthropic, and Mistral. Our application will be able to handle complex dialogues by dynamically selecting the best model for each user query based on predefined criteria such as context length, cost, and response type.&lt;/p&gt;
&lt;br&gt;
  &lt;p&gt;The final product will be a web-based chat interface where users can interact with our AI, which intelligently routes queries to the most suitable AI model. This setup not only demonstrates the capabilities of each API but also provides a flexible architecture that can be extended or modified to include additional models or features.&lt;/p&gt;


&lt;h2&gt;Setup and Installation&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;To get started, we need to set up our development environment. We'll use Node.js for our server-side logic and a simple HTML/CSS/JavaScript frontend to interact with our backend.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;npm init -y&lt;br&gt;
npm install express dotenv openai anthropic mistral&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;Next, we need to configure our environment variables to securely store our API keys. Create a &lt;code&gt;.env&lt;/code&gt; file in the root of your project with the following content:&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;OPENAI_API_KEY=your_openai_api_key&lt;br&gt;
ANTHROPIC_API_KEY=your_anthropic_api_key&lt;br&gt;
MISTRAL_API_KEY=your_mistral_api_key&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;Step 1: Setting Up Express Server&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;We will first set up an Express server to handle HTTP requests from our frontend. This server will act as a middleman between our client-side application and the various AI APIs.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;const express = require('express');&lt;br&gt;
const dotenv = require('dotenv');&lt;br&gt;
dotenv.config();

&lt;p&gt;const app = express();&lt;br&gt;
app.use(express.json());&lt;/p&gt;

&lt;p&gt;const PORT = process.env.PORT || 3000;&lt;/p&gt;

&lt;p&gt;app.listen(PORT, () =&amp;gt; {&lt;br&gt;
  console.log(&lt;code&gt;Server is running on port ${PORT}&lt;/code&gt;);&lt;br&gt;
});&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;In this setup, we import the necessary modules and initialize our Express app. We also configure it to parse JSON payloads and listen on a specified port, which defaults to 3000 if not set in the environment variables.&lt;/p&gt;


&lt;h2&gt;Step 2: Integrating OpenAI API&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;Next, we'll integrate the OpenAI API. This API will handle general conversational tasks and provide responses based on user queries.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;import { OpenAI } from 'openai';

&lt;p&gt;const client = new OpenAI(process.env.OPENAI_API_KEY);&lt;/p&gt;

&lt;p&gt;app.post('/api/openai', async (req, res) =&amp;gt; {&lt;br&gt;
  try {&lt;br&gt;
    const { message } = req.body;&lt;br&gt;
    const response = await client.chat.completions.create({&lt;br&gt;
      model: "gpt-5.6",&lt;br&gt;
      messages: [{ role: "user", content: message }],&lt;br&gt;
    });&lt;br&gt;
    res.json(response);&lt;br&gt;
  } catch (error) {&lt;br&gt;
    res.status(500).json({ error: error.message });&lt;br&gt;
  }&lt;br&gt;
});&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;This code sets up an endpoint to handle POST requests at &lt;code&gt;/api/openai&lt;/code&gt;. It uses the OpenAI client to send a user message to the GPT-5.6 model and returns the response. Error handling is included to manage any issues that arise during the API request.&lt;/p&gt;


&lt;h2&gt;Step 3: Integrating Anthropic API&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;Now, we will integrate the Anthropic API, which is known for its safety and alignment capabilities, making it ideal for sensitive or ethical queries. Ensure to verify the latest API integration methods from Anthropic's official documentation.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;// Placeholder for Anthropic API integration&lt;br&gt;
// Verify with Anthropic's latest API documentation&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;Step 4: Integrating Mistral API&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;Finally, we'll integrate the Mistral API. Mistral models are designed for efficient handling of specialized tasks, making them a great choice for domain-specific queries. Verify the integration details with Mistral's latest API documentation.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;// Placeholder for Mistral API integration&lt;br&gt;
// Verify with Mistral's latest API documentation&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;⚠️ Common Mistake:&lt;/strong&gt; Ensure that your API keys are correctly set in the &lt;code&gt;.env&lt;/code&gt; file and that the environment variables are loaded properly. Forgetting to configure these can lead to authentication errors.&lt;/p&gt;


&lt;h2&gt;Testing Your Implementation&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;To verify that our setup is working correctly, we can use a tool like Postman to send POST requests to each of our API endpoints with a sample message. Ensure that each API responds with a valid completion and that errors are handled gracefully.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;// Example POST request payload&lt;br&gt;
{&lt;br&gt;
  "message": "What is the weather like today?"&lt;br&gt;
}&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;Send this payload to each endpoint and check the responses to ensure they're accurate and relevant to the input.&lt;/p&gt;


&lt;h2&gt;What to Build Next&lt;/h2&gt;
&lt;br&gt;
  &lt;ul&gt;

    &lt;li&gt;Enhance the chat interface with real-time updates using WebSockets.&lt;/li&gt;

    &lt;li&gt;Implement a model selection algorithm to dynamically choose the best model based on query type.&lt;/li&gt;

    &lt;li&gt;Add user authentication to personalize and secure the chat experience.&lt;/li&gt;

  &lt;/ul&gt;


&lt;h2&gt;GCC/Middle East Relevance&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;Integrating conversational AI systems aligns with regional initiatives like Saudi Vision 2030 and the UAE National Strategy for AI. These frameworks emphasize the importance of AI in transforming industries and enhancing digital infrastructure. Collaborations with local entities such as SDAIA and G42 can further enhance AI capabilities in the region.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Automate AI Workflows with OpenAI &amp; Anthropic</title>
      <dc:creator>Gate of AI</dc:creator>
      <pubDate>Tue, 14 Jul 2026 14:54:37 +0000</pubDate>
      <link>https://dev.to/gateofai/automate-ai-workflows-with-openai-anthropic-2jk5</link>
      <guid>https://dev.to/gateofai/automate-ai-workflows-with-openai-anthropic-2jk5</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🚀 Technical Briefing:&lt;/strong&gt; This tutorial is part of our deep-dive series on Agentic Workflows at &lt;a href="https://gateofai.com" rel="noopener noreferrer"&gt;Gate of AI&lt;/a&gt;. For the full technical breakdown, interactive code sandbox, and the native Arabic translation, visit the &lt;a href="https://gateofai.com/tutorial/automate-ai-workflows-openai-anthropic/" rel="noopener noreferrer"&gt;original article here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;span&amp;gt;Tutorial&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;Advanced&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;⏱ 45 min read&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;© Gate of AI 2026-07-08&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Learn how to automate complex AI workflows using the latest OpenAI and Anthropic APIs to enhance efficiency and scalability, with a focus on GCC/Middle East applications.&lt;/p&gt;


&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;br&gt;
  &lt;ul&gt;

    &lt;li&gt;Python 3.10 or later&lt;/li&gt;

    &lt;li&gt;OpenAI and Anthropic API keys&lt;/li&gt;

    &lt;li&gt;Advanced understanding of AI and API integrations&lt;/li&gt;

  &lt;/ul&gt;


&lt;h2&gt;What We're Building&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;In this tutorial, we will create an automated AI workflow that leverages the capabilities of both OpenAI's latest models and Anthropic's Claude models. This project will demonstrate how to integrate multiple AI models to handle complex tasks such as natural language understanding, sentiment analysis, and data summarization.&lt;/p&gt;
&lt;br&gt;
  &lt;p&gt;The final application will automate data processing tasks, reducing manual intervention and enhancing accuracy and efficiency. It will serve as a robust foundation for integrating AI into business processes, enabling scalable and intelligent solutions, particularly in the GCC/Middle East region, aligning with initiatives like Saudi Vision 2030.&lt;/p&gt;


&lt;h2&gt;Setup and Installation&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;To begin, we need to set up our development environment. This involves installing the necessary Python packages and configuring environment variables for API keys.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;pip install openai anthropic&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;Next, we need to set up our environment variables to securely store our API keys. Create a &lt;code&gt;.env&lt;/code&gt; file in your project directory with the following content:&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;OPENAI_API_KEY=your_openai_api_key_here&lt;br&gt;
ANTHROPIC_API_KEY=your_anthropic_api_key_here&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;Step 1: Integrating OpenAI API&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;In this step, we'll integrate the OpenAI API to handle tasks such as language generation and sentiment analysis. This integration will allow us to automate the process of interpreting and generating text-based data.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;from openai import OpenAI&lt;br&gt;
import os&lt;br&gt;
from dotenv import load_dotenv

&lt;p&gt;load_dotenv()&lt;/p&gt;

&lt;p&gt;client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))&lt;/p&gt;

&lt;p&gt;def generate_text(prompt):&lt;br&gt;
    response = client.chat.completions.create(&lt;br&gt;
        model="gpt-4o",&lt;br&gt;
        messages=[{"role": "system", "content": "You are an assistant."}, {"role": "user", "content": prompt}]&lt;br&gt;
    )&lt;br&gt;
    return response.choices[0].message.content&lt;/p&gt;

&lt;p&gt;print(generate_text("Explain the benefits of AI automation."))&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;This code initializes the OpenAI client and defines a function &lt;code&gt;generate_text&lt;/code&gt; that interacts with the GPT-4o model to generate responses based on the input prompt.&lt;/p&gt;


&lt;h2&gt;Step 2: Integrating Anthropic API&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;Next, we'll integrate the Anthropic API to utilize Claude's capabilities for tasks such as data summarization and context understanding. This will complement our OpenAI integration by providing additional AI functionalities.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;from anthropic import Anthropic

&lt;p&gt;anthropic_client = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))&lt;/p&gt;

&lt;p&gt;def summarize_text(text):&lt;br&gt;
    response = anthropic_client.messages.create(&lt;br&gt;
        model="claude-3-5-sonnet-20241022",&lt;br&gt;
        prompt=f"Summarize the following text: {text}",&lt;br&gt;
        max_tokens=150&lt;br&gt;
    )&lt;br&gt;
    return response.choices[0].text&lt;/p&gt;

&lt;p&gt;print(summarize_text("OpenAI and Anthropic are leading AI research companies..."))&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;This segment of code sets up the Anthropic client and defines the &lt;code&gt;summarize_text&lt;/code&gt; function, which requests a summary of the provided text from the Claude model.&lt;/p&gt;


&lt;h2&gt;Step 3: Automating Workflow Integration&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;In the final step, we will integrate both APIs into a unified workflow that automates the processing of data from input to output. This workflow will demonstrate the use of both models in a cohesive application.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;def process_data(input_text):&lt;br&gt;
    # Step 1: Generate contextual information using OpenAI&lt;br&gt;
    context = generate_text(f"Provide context for: {input_text}")
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Step 2: Summarize the contextual information using Anthropic
summary = summarize_text(context)

return {
    "context": context,
    "summary": summary
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;input_data = "The impact of AI on modern industries is profound..."&lt;br&gt;
result = process_data(input_data)&lt;/p&gt;

&lt;p&gt;print("Context:", result["context"])&lt;br&gt;
print("Summary:", result["summary"])&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;This function, &lt;code&gt;process_data&lt;/code&gt;, orchestrates the workflow by generating context using OpenAI and summarizing it with Anthropic, thus providing a streamlined process for handling complex data tasks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚠️ Common Mistake:&lt;/strong&gt; Ensure that your API keys are correctly set up in the environment variables. Misconfigured keys can lead to authentication errors that are difficult to debug.&lt;/p&gt;


&lt;h2&gt;Testing Your Implementation&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;To verify the workflow, run the script and check the output. You should see a detailed context and a concise summary of the input text, demonstrating the effective integration of both AI models.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;# Command to run the script&lt;br&gt;
python automate_workflow.py&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;What to Build Next&lt;/h2&gt;
&lt;br&gt;
  &lt;ul&gt;

    &lt;li&gt;Extend the workflow to include more complex data processing tasks such as classification and anomaly detection.&lt;/li&gt;

    &lt;li&gt;Integrate a database to store and retrieve processed data efficiently.&lt;/li&gt;

    &lt;li&gt;Build a web interface to allow users to input data and receive AI-generated insights in real-time.&lt;/li&gt;

  &lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Build an AI Chatbot with OpenAI GPT-4o</title>
      <dc:creator>Gate of AI</dc:creator>
      <pubDate>Tue, 14 Jul 2026 14:54:24 +0000</pubDate>
      <link>https://dev.to/gateofai/build-an-ai-chatbot-with-openai-gpt-4o-1f1j</link>
      <guid>https://dev.to/gateofai/build-an-ai-chatbot-with-openai-gpt-4o-1f1j</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🚀 Technical Briefing:&lt;/strong&gt; This tutorial is part of our deep-dive series on Agentic Workflows at &lt;a href="https://gateofai.com" rel="noopener noreferrer"&gt;Gate of AI&lt;/a&gt;. For the full technical breakdown, interactive code sandbox, and the native Arabic translation, visit the &lt;a href="https://gateofai.com/tutorial/build-ai-chatbot-openai-gpt4o/" rel="noopener noreferrer"&gt;original article here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;span&amp;gt;Tutorial&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;Intermediate&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;⏱ 45 min read&amp;lt;/span&amp;gt;
&amp;lt;span&amp;gt;© Gate of AI 2026-07-11&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this comprehensive tutorial, you will build a responsive AI chatbot using JavaScript and OpenAI's latest GPT-4o, enhancing user interaction through seamless AI integration.&lt;/p&gt;


&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;br&gt;
  &lt;ul&gt;

    &lt;li&gt;Node.js version 18 or higher&lt;/li&gt;

    &lt;li&gt;OpenAI API key&lt;/li&gt;

    &lt;li&gt;Intermediate JavaScript knowledge&lt;/li&gt;

  &lt;/ul&gt;


&lt;h2&gt;What We're Building&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;This tutorial guides you through creating a dynamic AI-powered chatbot. The chatbot will leverage OpenAI's GPT-4o model for generating human-like responses, including recognizing emotional cues and engaging in rapid voice interactions. The end product will be a web-based chatbot capable of understanding and responding to user queries in a conversational manner.&lt;/p&gt;
&lt;br&gt;
  &lt;p&gt;The chatbot will be built using modern JavaScript practices, ensuring it is both efficient and easy to maintain. You'll learn how to set up the OpenAI client, handle asynchronous operations, and manage state effectively in a chat application context.&lt;/p&gt;


&lt;h2&gt;Setup and Installation&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;To get started, you will need to set up a Node.js environment and install the necessary packages. This includes the OpenAI SDK, which allows us to interact with the GPT-4o model.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;npm install openai dotenv express&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;Next, configure your environment variables to securely store your OpenAI API key. Create a &lt;code&gt;.env&lt;/code&gt; file in the root of your project directory.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;&lt;br&gt;
OPENAI_API_KEY=your_openai_api_key_here&lt;br&gt;
  &lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;Step 1: Setting Up the Server&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;This step involves creating a simple Express server to handle HTTP requests. The server will act as the backend for our chatbot, interfacing with the OpenAI API.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;&lt;br&gt;
const express = require('express');&lt;br&gt;
const dotenv = require('dotenv');&lt;br&gt;
const { OpenAI } = require('openai');

&lt;p&gt;dotenv.config();&lt;br&gt;
const app = express();&lt;br&gt;
app.use(express.json());&lt;/p&gt;

&lt;p&gt;const client = new OpenAI(process.env.OPENAI_API_KEY);&lt;/p&gt;

&lt;p&gt;app.post('/api/chat', async (req, res) =&amp;gt; {&lt;br&gt;
  const { message } = req.body;&lt;br&gt;
  try {&lt;br&gt;
    const response = await client.chat.completions.create({&lt;br&gt;
      model: "gpt-4o",&lt;br&gt;
      messages: [{ role: "user", content: message }]&lt;br&gt;
    });&lt;br&gt;
    res.json({ reply: response.choices[0].message.content });&lt;br&gt;
  } catch (error) {&lt;br&gt;
    console.error(error);&lt;br&gt;
    res.status(500).json({ error: 'Error processing request' });&lt;br&gt;
  }&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;app.listen(3000, () =&amp;gt; {&lt;br&gt;
  console.log('Server is running on &lt;a href="http://localhost:3000'" rel="noopener noreferrer"&gt;http://localhost:3000'&lt;/a&gt;);&lt;br&gt;
});&lt;br&gt;
  &lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;This code sets up an Express server that listens for POST requests on the &lt;code&gt;/api/chat&lt;/code&gt; endpoint. It uses the OpenAI client to send the user message to the GPT-4o model and returns the AI's response.&lt;/p&gt;


&lt;h2&gt;Step 2: Creating the Frontend&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;In this step, you'll create a basic HTML page with a form for user input and an area to display the chatbot's responses.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;


AI Chatbot
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;body { font-family: Arial, sans-serif; }
#chat { max-width: 600px; margin: 20px auto; }
#messages { border: 1px solid #ccc; padding: 10px; height: 300px; overflow-y: scroll; }
#user-input { width: 100%; padding: 10px; }








document.getElementById('user-input').addEventListener('keydown', async function(e) {
  if (e.key === 'Enter') {
    const message = e.target.value;
    e.target.value = '';
    const messagesDiv = document.getElementById('messages');
    messagesDiv.innerHTML += `&amp;amp;lt;div&amp;amp;gt;&amp;amp;lt;strong&amp;amp;gt;You:&amp;amp;lt;/strong&amp;amp;gt; ${message}&amp;amp;lt;/div&amp;amp;gt;`;

    const response = await fetch('/api/chat', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ message })
    });
    const data = await response.json();
    messagesDiv.innerHTML += `&amp;amp;lt;div&amp;amp;gt;&amp;amp;lt;strong&amp;amp;gt;Bot:&amp;amp;lt;/strong&amp;amp;gt; ${data.reply}&amp;amp;lt;/div&amp;amp;gt;`;
    messagesDiv.scrollTop = messagesDiv.scrollHeight;
  }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;This HTML page includes a simple chat interface. When the user presses Enter, the message is sent to the server, and the response is displayed in the chat window.&lt;/p&gt;


&lt;h2&gt;Step 3: Enhancing the Chat Experience&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;To improve user experience, we'll add features like loading indicators and error handling in the frontend.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;

&lt;p&gt;const userInput = document.getElementById('user-input');&lt;br&gt;
  const messagesDiv = document.getElementById('messages');&lt;/p&gt;

&lt;p&gt;userInput.addEventListener('keydown', async function(e) {&lt;br&gt;
    if (e.key === 'Enter') {&lt;br&gt;
      const message = e.target.value;&lt;br&gt;
      e.target.value = '';&lt;br&gt;
      messagesDiv.innerHTML += &lt;code&gt;&amp;amp;lt;div&amp;amp;gt;&amp;amp;lt;strong&amp;amp;gt;You:&amp;amp;lt;/strong&amp;amp;gt; ${message}&amp;amp;lt;/div&amp;amp;gt;&lt;/code&gt;;&lt;br&gt;
      messagesDiv.innerHTML += &lt;code&gt;&amp;amp;lt;div id="loading"&amp;amp;gt;Bot is typing...&amp;amp;lt;/div&amp;amp;gt;&lt;/code&gt;;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  try {
    const response = await fetch('/api/chat', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ message })
    });
    const data = await response.json();
    document.getElementById('loading').remove();
    messagesDiv.innerHTML += `&amp;amp;lt;div&amp;amp;gt;&amp;amp;lt;strong&amp;amp;gt;Bot:&amp;amp;lt;/strong&amp;amp;gt; ${data.reply}&amp;amp;lt;/div&amp;amp;gt;`;
  } catch (error) {
    document.getElementById('loading').remove();
    messagesDiv.innerHTML += `&amp;amp;lt;div&amp;amp;gt;&amp;amp;lt;strong&amp;amp;gt;Error:&amp;amp;lt;/strong&amp;amp;gt; Unable to fetch response&amp;amp;lt;/div&amp;amp;gt;`;
  }
  messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;});&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
  &lt;p&gt;This script adds a "Bot is typing..." indicator while waiting for the response and handles any errors that occur during the fetch operation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚠️ Common Mistake:&lt;/strong&gt; Ensure that the server is running and accessible from the frontend. Network errors can occur if the server is not active or if there are CORS issues.&lt;/p&gt;


&lt;h2&gt;Testing Your Implementation&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;To verify that your chatbot works, open the HTML file in a browser and try sending a few messages. You should see your input and the bot's responses in the chat window.&lt;/p&gt;
&lt;br&gt;
  &lt;pre&gt;&lt;code&gt;
&lt;h1&gt;
  
  
  Ensure your server is running
&lt;/h1&gt;

&lt;p&gt;node server.js&lt;/p&gt;
&lt;h1&gt;
  
  
  Open the HTML file in a browser and interact with the chatbot
&lt;/h1&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;What to Build Next&lt;/h2&gt;
&lt;br&gt;
  &lt;ul&gt;

    &lt;li&gt;Add a database to store chat history and analyze user interactions.&lt;/li&gt;

    &lt;li&gt;Integrate speech recognition to allow voice input and output, aligning with the capabilities of GPT-4o.&lt;/li&gt;

    &lt;li&gt;Expand the chatbot's capabilities by integrating additional APIs for more diverse responses.&lt;/li&gt;

  &lt;/ul&gt;

&lt;p&gt;Incorporating AI technologies like GPT-4o can significantly enhance digital transformation initiatives in the GCC region, supporting goals such as Saudi Vision 2030 and the UAE's National Strategy for AI. By leveraging these advanced AI capabilities, businesses can improve customer engagement and operational efficiency.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>discuss</category>
    </item>
  </channel>
</rss>
