Start forecasting

Use your historic attendance data to generate AI-driven forecasts for people, teams, and locations, helping predict future space needs.

Prerequisites

  • Completed Add historic attendance (including session finish if you batched)

  • Node.js v18+ and npm v9+

  • A valid gospace API key in your .env file

  • At least one populated location with historic occupancy data

Note: Any fields ending with _inc include adjustments for minimum targets, people intentions (bookings), and contingencies.


1) Trigger a forecast run

If your project is configured for automatic rebuilds, you can skip this step. Otherwise, trigger forecasting explicitly.

Create start-forecast.ts:

import "dotenv/config";
import GospaceAI from "@gospace-ai/api";

async function main() {
  const gospace = new GospaceAI(process.env.GOSPACE_API_KEY!);

  // Kick off a forecast rebuild for a location and optional date range
  const res = await gospace.system.startForecast({
    location_id: "68499cf4af8729934aae208a",
    // Optional time window. If omitted, backend will choose sensible defaults.
    // starts_at: "2025-06-20T00:00:00Z",
    // ends_at: "2025-07-31T23:59:59Z",
    // Optional control flags
    // force_rebuild: true
  });

  console.log(JSON.stringify(res.data, null, 2));
  // Expect a job or task identifier you can poll
}

main().catch((err) => {
  console.error("Start forecast failed:", err);
  process.exit(1);
});

2) (Optional) Poll job status

If startForecast returns a job, poll until it’s complete.

import "dotenv/config";
import GospaceAI from "@gospace-ai/api";

const JOB_ID = "your_forecast_job_id";

async function main() {
  const gospace = new GospaceAI(process.env.GOSPACE_API_KEY!);

  for (;;) {
    const status = await gospace.system.getForecastJob({ job_id: JOB_ID });
    console.log(status.data.state);
    if (status.data.state === "completed") break;
    if (status.data.state === "failed") throw new Error("Forecast job failed");
    await new Promise((r) => setTimeout(r, 3000));
  }

  console.log("Forecast ready.");
}

main().catch((e) => {
  console.error(e);
  process.exit(1);
});

3) Fetch forecasts

A) People forecast (per person, optionally scoped to team)

Create get-people-forecast.ts:

import "dotenv/config";
import GospaceAI from "@gospace-ai/api";

async function main() {
  const gospace = new GospaceAI(process.env.GOSPACE_API_KEY!);

  const res = await gospace.system.getPeopleForecast({
    location_id: "68499cf4af8729934aae208a",
    // Optional filters:
    // people_id: "68518a559c86c18f01ee84e4",
    // team_id: "68518a549c86c18f01ee84b0",
    starts_at: "2025-06-29T23:00:00Z",
    ends_at: "2025-07-07T22:59:00Z",
    skip: 0,
    limit: 25,
  });

  // Example shape (truncated):
  // {
  //   success: true,
  //   data: { forecast: [ { starts_at, ends_at, location_id, people_id, team_id, forecasted_desk, forecasted_room, forecasted_total }, ... ] },
  //   pagination: { current_results: { from, to }, total_results },
  //   identifier: "get_forecast_successful"
  // }

  console.log(JSON.stringify(res.data, null, 2));
}

main().catch((err) => {
  console.error("Get people forecast failed:", err);
  process.exit(1);
});

B) Team forecast (aggregated by team)

Create get-team-forecast.ts:

import "dotenv/config";
import GospaceAI from "@gospace-ai/api";

async function main() {
  const gospace = new GospaceAI(process.env.GOSPACE_API_KEY!);

  const res = await gospace.system.getTeamForecast({
    location_id: "68499cf4af8729934aae208a",
    starts_at: "2025-06-20T23:00:00Z",
    ends_at: "2025-06-22T22:59:00Z",
    skip: 0,
    limit: 25,
  });

  // Records include *_inc fields:
  // forecasted_desks, forecasted_rooms, forecasted_total,
  // forecasted_desks_inc, forecasted_rooms_inc, forecasted_total_inc

  console.log(JSON.stringify(res.data, null, 2));
}

main().catch((err) => {
  console.error("Get team forecast failed:", err);
  process.exit(1);
});

C) Location forecast (location‑level totals)

Create get-location-forecast.ts:

import "dotenv/config";
import GospaceAI from "@gospace-ai/api";

async function main() {
  const gospace = new GospaceAI(process.env.GOSPACE_API_KEY!);

  const res = await gospace.system.getLocationForecast({
    location_id: "68499cf4af8729934aae208a",
    starts_at: "2025-06-20T23:00:00Z",
    ends_at: "2025-07-23T22:59:00Z",
    skip: 0,
    limit: 25,
  });

  // Records include *_inc fields for adjusted capacity planning.

  console.log(JSON.stringify(res.data, null, 2));
}

main().catch((err) => {
  console.error("Get location forecast failed:", err);
  process.exit(1);
});

4) Turn forecasts into capacity requirements

Daily desk and room requirements (using *_inc)

type LocationForecast = {
  starts_at: string;
  ends_at: string;
  location_id: string;
  forecasted_desks_inc: number;
  forecasted_rooms_inc: number;
  forecasted_total_inc: number;
};

function summarizeCapacity(rows: LocationForecast[]) {
  return rows.reduce(
    (acc, r) => {
      acc.maxDesks = Math.max(acc.maxDesks, r.forecasted_desks_inc);
      acc.maxRooms = Math.max(acc.maxRooms, r.forecasted_rooms_inc);
      acc.maxTotal = Math.max(acc.maxTotal, r.forecasted_total_inc);
      return acc;
    },
    { maxDesks: 0, maxRooms: 0, maxTotal: 0 }
  );
}

// Example usage:
// const summary = summarizeCapacity(res.data.forecast);
// console.log(summary); // { maxDesks, maxRooms, maxTotal }

Aggregating per‑team to size team neighborhoods

type TeamForecast = {
  team_id: string;
  starts_at: string;
  forecasted_desks_inc: number;
};

function peakPerTeam(rows: TeamForecast[]) {
  const map = new Map<string, number>();
  for (const r of rows) {
    map.set(r.team_id, Math.max(map.get(r.team_id) ?? 0, r.forecasted_desks_inc));
  }
  return map; // team_id -> peak desks required
}

Checking person‑level confidence

Use people forecasts to validate outliers (e.g., unexpected spikes for specific individuals or teams) before making seating or room allocation changes.


Tips

  • Use _inc fields to plan for the real world (targets, bookings, contingencies).

  • Choose consistent day boundaries (starts_at/ends_at) that match your business day/timezone.

  • Use pagination (skip, limit) to iterate long horizons.

  • Rebuild forecasts after significant new history or policy changes (e.g., new minimum targets).

Last updated

Was this helpful?