SPARK - Simple Personal AI Reasoning Kernel

SPARK

Working on a small project with 120b and Whisper as well as OpenAI API.

Images are 1440 x 900, they are also CRISP as they are GIF and lossless.

Right clicking on the images and opening in a new tab on a computer screen will give you the best experience. See detailed explanation of process below.

2 Likes

Hi @phyde1001 !

I am looking at your recording on a mobile screen and have absolutely no clue what’s happening.

Can you elaborate a little bit?

1 Like

Hey, sorry — here’s a clearer breakdown of what’s happening.

SPARK = Simple Personal AI Reasoning Kernel.
It’s a small local “brain loop” running on my DGX Spark.
It listens to speech, understands intent with embeddings, and picks which code module (what I call Agent GIFs) should run.

Here’s the pipeline:

  1. Speech In
    Browser captures audio and sends a WAV to my DGX Spark.
  2. Local Speech Recognition
    Whisper Small + Whisper Large run locally on GPU.
  3. Semantic Understanding
    The transcript is embedded using a local embedding model (nomic-embed-text).
    I compare it against embeddings of ~100 modules (“trees”).
  4. Intent Routing (the kernel part)
    SPARK finds the closest match using cosine similarity.
    If confidence is low, it defers to a local 120B model to reason about the safest/correct module.
  5. Module Execution
    The chosen module runs.
    A module is basically an Agent GIF: a self-contained unit (HTML/JS/PHP/text) embedded inside a GIF file.

So in the demo:

  • “What’s the weather in London?” → Weather module
  • “Where is OpenAI based?” → Info module
  • etc.

More detail:

It’s recording speech through the browser, running that through browser speech recognition, saving WAV files, and uploading them to local Whisper Small + Large.
Then it checks which module to execute by comparing embeddings (or asks local 120B to choose).

I’m not using OSS 120B function calling — rolled my own version for now.

In the first example the user asks for weather in London; in the second, where OpenAI is based (California).

Next step is auto-generating modules with GPT-5+ as I have demonstrated in other posts.

download

Modules are basically Agent GIFs.

Would appreciate any feedback — I’m sure I’m making lots of mistakes along the way :slightly_smiling_face:

2 Likes

Fun little demo with my son. He’s interested in robotics but not got further than 3D yet…

Our goal here was to get GPT-5 to CREATE different hand positions based only on the code and a single ‘Neutral hand’ example for a P5.js 3D hand automatically from simple voice commands.

Watch out for:

Thumbs Up
Knockout
Peace
Gimme Five
And back to Thumbs Up again

Sorry not realtime video, in reality we have about a 5-10 second delay with Whisper on spark and a 10 second delay for gpt-5 right now but the last Thumbs up (which skips the GPT-5 stage) was only about 5 seconds for speech.

Spark3DHand

Images are 1440 x 900, they are also CRISP as they are GIF and lossless.

Right clicking on the image and opening in a new tab on a computer screen will give you the best experience.

Feedback always very welcome. :slight_smile:

1 Like

Legal Check Module - You never know where it could come in handy? ^^

LegalCheck

System

You are a policy analysis assistant.

Your job is to answer questions about a website’s legal and policy documents
(e.g., Terms of Use, Service Terms, Privacy Policy, Cookie Policy, Billing or
Credits Terms, Subscription Terms, Refund Policy, Acceptable Use Policy, etc.).

You will be given:

  • A single root policy URL (entry point), such as https://example.com/policies
  • A natural language question from the user
  • A JSON schema describing the exact structure you must output

You MUST follow these rules:

  1. Use the available tools (such as web_search) to search and browse for
    relevant policy pages.
  2. Restrict your browsing and reasoning to:
    • Pages on the same domain as the root URL, and
    • Pages directly linked from that root URL or clearly part of the site’s
      official policies or legal documents.
  3. Prefer pages that look like policy/terms/legal documents, such as those with
    URLs or titles containing words like: terms, use, service, billing, credit,
    subscription, refund, cancellation, acceptable use, privacy, cookie, policy,
    legal, or agreement.
  4. Answer ONLY using text that you have actually retrieved or been provided.
    Do NOT guess or invent policy details.
  5. If the policy information is missing, unclear, incomplete, or contradictory,
    you must reflect that honestly in the structured output (e.g., by using
    “unclear” or “not_mentioned” and adding notes to uncertainty_notes).
  6. Think from the perspective of a reasonable consumer when determining whether
    a potential issue exists and how severe it is.
  7. Your final output MUST be a single JSON object that EXACTLY follows the
    provided JSON schema (policy_question_checker). Output NOTHING else.
User

Question: Will my credits or account balance expire, and under what conditions?

Root policy URL (entry point):
https://openai.com/policies

Instructions:

  • Treat the root URL as the main entry point for this website’s policies and legal documents.
  • Use web_search and browsing tools to find ALL relevant legal/policy pages on the same domain
    that can answer the question. This may include Terms of Use, Service Terms, Billing or Credit
    Terms, Refund/Cancellation Policy, Service Terms, Acceptable Use Policy, Privacy Policy, and
    any other related documents.
  • Base your answer ONLY on the text found in these official policies.
  • Then return ONLY a JSON object that matches the policy_question_checker schema.
policy_question_checker

{
“name”: “policy_question_checker”,
“schema”: {
“type”: “object”,
“properties”: {
“question”: { “type”: “string” },
“document_name”: { “type”: “string” },
“document_url”: {
“type”: “string”,
“description”: “URL of the policy document used for this answer, if available.”
},
“answer”: { “type”: “string” },
“answer_category”: {
“type”: “string”,
“enum”: [
“yes”,
“no”,
“partially”,
“unclear”,
“not_mentioned”,
“not_applicable”
]
},
“problem_detected”: { “type”: “boolean” },
“problem_type”: {
“type”: “array”,
“items”: {
“type”: “string”,
“enum”: [
“expiry_or_forfeiture”,
“unexpected_fees_or_charges”,
“data_retention_or_privacy_concern”,
“unilateral_changes_by_provider”,
“limitation_of_liability”,
“refund_or_cancellation_restriction”,
“ambiguous_language”,
“jurisdiction_or_dispute_resolution_issue”,
“access_or_suspension_risk”,
“other”
]
}
},
“severity”: {
“type”: “string”,
“enum”: [“none”, “low”, “medium”, “high”, “critical”]
},
“relevant_clauses”: {
“type”: “array”,
“items”: {
“type”: “object”,
“properties”: {
“section_title”: { “type”: “string” },
“section_anchor_or_number”: { “type”: “string” },
“excerpt”: { “type”: “string” },
“reason_relevance”: { “type”: “string” }
},
“required”: [
“section_title”,
“section_anchor_or_number”,
“excerpt”,
“reason_relevance”
],
“additionalProperties”: false
}
},
“uncertainty_notes”: { “type”: “string” },
“follow_up_questions”: {
“type”: “array”,
“items”: { “type”: “string” }
},
“confidence”: {
“type”: “number”,
“minimum”: 0,
“maximum”: 1
}
},
“required”: [
“question”,
“document_name”,
“document_url”,
“answer”,
“answer_category”,
“problem_detected”,
“problem_type”,
“severity”,
“relevant_clauses”,
“uncertainty_notes”,
“follow_up_questions”,
“confidence”
],
“additionalProperties”: false
},
“strict”: true
}

Result
“Yes. OpenAI’s Service Credits (your credit “balance”) expire if unused. Specifically, unused Service Credits expire one year after the date of purchase or issuance…”

Images are 1440 x 900, they are also CRISP as they are GIF and lossless.

Right clicking on the image and opening in a new tab on a computer screen will give you the best experience.

Check out the next post it’s a little more serious

OK my next SPARK project is Mold reduction…

We have a recent mold issue in our small house, caused by a broken gutter… Not uncommon… According to the BBC article above 1.3 Million homes in the UK have this issue, having lived in China for 10 years I know this isn’t only an issue here… That’s super unhealthy for a lot of families…

The reality to fighting mold is not just cleaning or building work but also about PREVENTION…

You can do this with money… A faster spin cycle washing machine meaning less water when drying indoors (if you have no outdoor area)…, or with dehumidifiers, which may help but are a big cost outlay for low income families.

The cost of electricity also becomes a factor.

On the ground I have found timing and weather to be major factors… It’s no good washing and hanging clothes when it’s about to rain, or when it’s going to be very cold so it costs lots more to heat the house when venting the property.

I get lost in code and tend to do chores on auto-pilot… Here is my simple personal AI aided solution to this very real issue… It’s not perfected yet, but I think it’s a good fit here.

For this project/module I am using Met Office Weather API and working out washing/cleaning schedules using a function written in GPT-5 on the API. The goal is to work out more optimal times to put on washing every few days to prevent the mold.

My goal is to understand and fix this problem moving forward, as we transition to an AI (cheaper than air) future for my (Healthier) family and creating a net value add in the long term (while sharing this process for others to copy).

For this project I will use:

Met Office Weather API (Global Spot Data - Free for personal use)
GPT-5 (Pretty much vibe coding to work out an algorithm for this house)
Elbow Grease

Mold

This project is completely replicatable with a little vibe coding.

What the Indoor Drying Planner Does

This tool processes hourly Met Office data and analyses humidity, dew-point, temperature, visibility, pressure trends and precipitation risk to estimate when indoor air will clear moisture most efficiently. It identifies the best 6-hour, 12-hour and 24-hour drying windows, and highlights the safest daytime hours (09:00–21:00) to start washing so moisture doesn’t accumulate overnight.

The aim is simple:
reduce indoor humidity spikes, speed up evaporation, and lower mould risk by choosing the least harmful drying times.

By avoiding saturated air, fog, rain-loaded periods, and cold night-time traps, the algorithm attempts to reduce the number of hours a home spends above 70–85% relative humidity — the zone where mould thrives — which in (GPT-5) theory could reduce mould spread by 30–60%, and practically by up to 70–90% in small UK homes that rely on indoor drying.

Important:
This is a conceptual and untested model.
It uses building-physics principles and forecast data to guide decision-making, but real-world results will vary depending on ventilation, insulation, heating habits and specific home conditions.

It’s ultimately a low-cost, data-driven idea intended to make indoor drying healthier and more energy-efficient for families without outdoor space.

Feedback and domain specific corrections welcome :slight_smile:

Reference Code (PHP)
function GetIndoorDryingPlanFromTimeSeries(array $timeSeries): array
{
    // Helper: parse ISO time → (DateTime in UK, formatted string, hour 0–23)
    $parseTimeUK = function (?string $iso): array {
        if (!$iso) return [null, null, null];
        try {
            $dt = new DateTime($iso, new DateTimeZone('UTC'));
            $dt->setTimezone(new DateTimeZone('Europe/London'));
            return [
                $dt,
                $dt->format('D j M Y, H:i'),
                (int)$dt->format('G') // 0–23
            ];
        } catch (Exception $e) {
            return [null, $iso, null];
        }
    };

    $formatTimeUK = function (?string $iso) use ($parseTimeUK): ?string {
        [, $formatted, ] = $parseTimeUK($iso);
        return $formatted;
    };

    // ---------- 0. Normalise + sort by time ----------
    usort($timeSeries, function ($a, $b) {
        return strcmp($a['time'] ?? '', $b['time'] ?? '');
    });

    // Derive simple pressure tendency from mslp (R/F/S)
    $prevMslp = null;
    foreach ($timeSeries as $i => $row) {
        $mslp = isset($row['mslp']) ? (float)$row['mslp'] : null;
        if ($prevMslp === null || $mslp === null) {
            $timeSeries[$i]['pressure_tendency'] = '';
        } else {
            $delta = $mslp - $prevMslp;
            if ($delta > 0) {
                $timeSeries[$i]['pressure_tendency'] = 'R';
            } elseif ($delta < 0) {
                $timeSeries[$i]['pressure_tendency'] = 'F';
            } else {
                $timeSeries[$i]['pressure_tendency'] = 'S';
            }
        }
        $prevMslp = $mslp;
    }

    // ---------- 1. Indoor drying stress score per row ----------
    $stressRow = function(array $row): float
    {
        $h = isset($row['screenRelativeHumidity'])
            ? (float)$row['screenRelativeHumidity']
            : (float)($row['humidity'] ?? 0);

        if (isset($row['maxScreenAirTemp'], $row['minScreenAirTemp'])) {
            $t = ((float)$row['maxScreenAirTemp'] + (float)$row['minScreenAirTemp']) / 2.0;
        } elseif (isset($row['feelsLikeTemp'])) {
            $t = (float)$row['feelsLikeTemp'];
        } else {
            $t = (float)($row['screenTemperature'] ?? $row['temperature'] ?? 0);
        }

        $v  = (float)($row['visibility'] ?? 0);
        $pt = (string)($row['pressure_tendency'] ?? '');
        $wc = isset($row['significantWeatherCode'])
            ? (int)$row['significantWeatherCode']
            : (int)($row['weather_code'] ?? 0);

        $ws = isset($row['windSpeed10m'])
            ? (float)$row['windSpeed10m']
            : (float)($row['wind_speed'] ?? 0);

        $precipProb = isset($row['probOfPrecipitation'])
            ? (float)$row['probOfPrecipitation']
            : (float)($row['probOfRain'] ?? 0);

        $hourUK = isset($row['hour_uk']) ? (int)$row['hour_uk'] : null;

        // Rising pressure → clearing/drying
        $pressureBonus = ($pt === 'R' ? 2.0 : ($pt === 'F' ? -2.0 : 0.0));

        $weatherPenalty = 0.0;
        if ($wc !== 0) {
            $weatherPenalty += 5.0;
        }
        if ($v < 10000) {
            $weatherPenalty += 5.0;
        }
        if ($precipProb >= 50) {
            $weatherPenalty += 10.0;
        } elseif ($precipProb >= 20) {
            $weatherPenalty += 5.0;
        }

        // Simple dew point estimate (approximation)
        $indoorTempAssumed = 18.0; // °C
        $dewPoint = $t - ((100.0 - $h) / 5.0);
        $drynessPotential = $indoorTempAssumed - $dewPoint;
        if ($drynessPotential < 0) {
            $drynessPotential = 0.0;
        }

        $dryingScore =
            ($drynessPotential * 3.0) +
            ((100.0 - $h) * 0.5) +
            ($v / 10000.0) +
            ($ws * 0.5) +
            $pressureBonus -
            ($precipProb * 0.2) -
            $weatherPenalty;

        $indoorStress = 100.0 - $dryingScore;

        // *** NEW: big penalty for night-time (outside 09:00–21:00 UK) ***
        if ($hourUK !== null && ($hourUK < 9 || $hourUK > 21)) {
            $indoorStress += 40.0;   // tune this if you like
        }

        return $indoorStress;
    };

    // ---------- 2. Add stress + datetime + hour_uk ----------
    $Data = [];
    foreach ($timeSeries as $row) {
        $row['datetime'] = $row['time'] ?? null;
        [, , $hourUK] = $parseTimeUK($row['datetime']);
        $row['hour_uk'] = $hourUK;
        $row['indoor_stress'] = $stressRow($row);
        $Data[] = $row;
    }

    $n = count($Data);
    if ($n === 0) {
        return [
            'best_hours'      => [],
            'best_6h_window'  => null,
            'best_12h_window' => null,
            'best_24h_window' => null,
            'rows'            => [],
            'summary_text'    => '<div class="drying-plan-summary"><p>No data available.</p></div>',
        ];
    }

    // ---------- 3. Helper: best (lowest-stress) sliding window ----------
    $bestWindow = function (array $rows, int $windowHours): ?array
    {
        $count = count($rows);
        if ($count === 0 || $windowHours <= 0) return null;

        $windowSize = min($windowHours, $count);
        $stressValues = array_column($rows, 'indoor_stress');

        $sum = array_sum(array_slice($stressValues, 0, $windowSize));
        $bestSum   = $sum;
        $bestStart = 0;

        for ($i = $windowSize; $i < $count; $i++) {
            $sum += $stressValues[$i] - $stressValues[$i - $windowSize];
            if ($sum < $bestSum) {
                $bestSum   = $sum;
                $bestStart = $i - $windowSize + 1;
            }
        }

        $bestEnd = $bestStart + $windowSize - 1;

        return [
            'start_index'    => $bestStart,
            'end_index'      => $bestEnd,
            'start_time'     => $rows[$bestStart]['datetime'] ?? null,
            'end_time'       => $rows[$bestEnd]['datetime'] ?? null,
            'total_stress'   => $bestSum,
            'average_stress' => $bestSum / $windowSize,
        ];
    };

    // ---------- 4. Best individual hours (lowest stress, 09:00–21:00 only) ----------
    $byStress = $Data;
    usort($byStress, function ($a, $b) {
        $sa = (float)($a['indoor_stress'] ?? 0);
        $sb = (float)($b['indoor_stress'] ?? 0);
        return $sa <=> $sb;
    });

    $bestHoursClean = [];
    foreach ($byStress as $row) {
        $iso = $row['datetime'] ?? null;
        [, $ukStr, $hourUK] = $parseTimeUK($iso);

        if ($hourUK === null) continue;
        if ($hourUK < 9 || $hourUK > 21) continue;

        $bestHoursClean[] = [
            'datetime'      => $iso,
            'datetime_uk'   => $ukStr,
            'indoor_stress' => (float)($row['indoor_stress'] ?? 0),
        ];

        if (count($bestHoursClean) >= 6) break;
    }

    // Fallback if somehow no daytime hours qualify
    if (empty($bestHoursClean) && !empty($byStress)) {
        $fallback = array_slice($byStress, 0, min(3, count($byStress)));
        foreach ($fallback as $row) {
            $iso = $row['datetime'] ?? null;
            [, $ukStr, ] = $parseTimeUK($iso);
            $bestHoursClean[] = [
                'datetime'      => $iso,
                'datetime_uk'   => $ukStr,
                'indoor_stress' => (float)($row['indoor_stress'] ?? 0),
            ];
        }
    }

    // ---------- 5. Best 6h, 12h, 24h windows (now with night penalty baked in) ----------
    $best6  = $bestWindow($Data, 6);
    $best12 = $bestWindow($Data, 12);
    $best24 = $bestWindow($Data, 24);

    // ---------- 6. Quality labels ----------
    $stressLabel = function (?array $win): string {
        if (!$win) return 'unknown';
        $avg = $win['average_stress'];
        if ($avg <= 40) return 'very good';
        if ($avg <= 55) return 'good';
        if ($avg <= 70) return 'fair';
        return 'poor';
    };

    $label6  = $stressLabel($best6);
    $label12 = $stressLabel($best12);
    $label24 = $stressLabel($best24);

    // ---------- 7. HTML summary block ----------
    $html  = '<div class="drying-plan-summary" style="font-family:system-ui,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-size:14px;line-height:1.5;color:#222;padding:10px 14px;border:1px solid #ccc;border-radius:8px;max-width:640px;background:#fafafa;">';
    $html .= '<h2 style="margin:0 0 8px;font-size:16px;">Indoor Drying Plan</h2>';

    $html .= '<ul style="margin:0 0 10px 18px;padding:0;">';

    if ($best24 && $best24['start_time'] && $best24['end_time']) {
        $html .= '<li><strong>Best 24-hour period</strong> (least mould / humidity stress):<br>'
            . htmlspecialchars($formatTimeUK($best24['start_time'])) . ' → '
            . htmlspecialchars($formatTimeUK($best24['end_time'])) . '<br>'
            . 'Average stress: ' . round($best24['average_stress'], 1)
            . ' (' . htmlspecialchars($label24) . ')</li>';
    }

    if ($best12 && $best12['start_time'] && $best12['end_time']) {
        $html .= '<li style="margin-top:6px;"><strong>Good 12-hour block</strong>:<br>'
            . htmlspecialchars($formatTimeUK($best12['start_time'])) . ' → '
            . htmlspecialchars($formatTimeUK($best12['end_time'])) . '<br>'
            . 'Average stress: ' . round($best12['average_stress'], 1)
            . ' (' . htmlspecialchars($label12) . ')</li>';
    }

    if ($best6 && $best6['start_time'] && $best6['end_time']) {
        $html .= '<li style="margin-top:6px;"><strong>Best 6-hour stretch</strong> (ideal to have clothes hanging):<br>'
            . htmlspecialchars($formatTimeUK($best6['start_time'])) . ' → '
            . htmlspecialchars($formatTimeUK($best6['end_time'])) . '<br>'
            . 'Average stress: ' . round($best6['average_stress'], 1)
            . ' (' . htmlspecialchars($label6) . ')</li>';
    }

    $html .= '</ul>';

    if (!empty($bestHoursClean)) {
        $html .= '<p style="margin:8px 0 4px;"><strong>Good hours to start a wash (between 09:00 and 21:00 UK):</strong></p>';
        $html .= '<ul style="margin:0 0 4px 18px;padding:0;">';
        foreach ($bestHoursClean as $h) {
            $html .= '<li>'
                . htmlspecialchars($h['datetime_uk'] ?? $h['datetime'])
                . ' — stress ' . round($h['indoor_stress'], 1)
                . '</li>';
        }
        $html .= '</ul>';
    }

    $html .= '<p style="margin:8px 0 0;font-size:12px;color:#555;">'
          . 'Lower stress means less time with very high humidity, '
          . 'so less condensation and mould risk when drying clothes indoors. '
          . 'Night-time hours are penalised so suggestions favour daytime (09:00–21:00).'
          . '</p>';

    $html .= '</div>';

    // Convenience: add UK times to windows
    $addUkTimes = function (?array $win) use ($formatTimeUK) {
        if (!$win) return null;
        $win['start_time_uk'] = $formatTimeUK($win['start_time'] ?? null);
        $win['end_time_uk']   = $formatTimeUK($win['end_time'] ?? null);
        return $win;
    };
    $best6  = $addUkTimes($best6);
    $best12 = $addUkTimes($best12);
    $best24 = $addUkTimes($best24);

    return [
        'best_hours'      => $bestHoursClean,
        'best_6h_window'  => $best6,
        'best_12h_window' => $best12,
        'best_24h_window' => $best24,
        'rows'            => $Data,
        'summary_text'    => $html,
    ];
}

OK gutter fixed, new dehumidifier and drying plan but still something missing from this algorithm…

Time to get back to the Carbon Intensity checker I vibe coded last October… From simple chat request to (almost) returning 1H increment Carbon Intensity data using o1 (Was it really only last September o1 came out?)

Right clicking on the image and opening in a new tab on a computer screen will give you the best experience.

Result:
Combined Met Office Weather API and NESO Carbon Intensity API to create an optimal washing/drying schedule to prevent mould growth and reduce Carbon Emissions.

I guess everyone does this anyway right? I’m probably a bit slow on the uptake.

1 Like