{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "dcb093c5",
   "metadata": {},
   "source": [
    "# LLM tooling for D3.js\n",
    "\n",
    "<p style=\"font-style: italic; font-size: 18px; color: dimgray;\">ChatGPT and Gemini</p>\n",
    "\n",
    "Anton Antonov   \n",
    "[RakuForPrediction at WordPress](https://rakuforprediction.wordpress.com)   \n",
    "September 2025"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fc255d8f",
   "metadata": {},
   "source": [
    "-----\n",
    "\n",
    "## Introduction"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "04e8bf87",
   "metadata": {},
   "source": [
    "This notebook shows how to do parallel [Function Calling](https://ai.google.dev/gemini-api/docs/function-calling) workflows with Large Language Models (LLMs) of Gemini. \n",
    "\n",
    "The Raku package [\"WWW::Gemini\"](https://github.com/antononcube/Raku-WWW-Gemini), [AAp2], is used."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a874186",
   "metadata": {},
   "source": [
    "-----\n",
    "\n",
    "## Setup"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "097abe6f",
   "metadata": {},
   "source": [
    "Load packages:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "95d84f7a",
   "metadata": {},
   "outputs": [],
   "source": [
    "use JSON::Fast;\n",
    "use LLM::Functions;\n",
    "use LLM::Tooling;\n",
    "use Chemistry::Stoichiometry;\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e0e10660",
   "metadata": {},
   "source": [
    "Define LLM access configurations:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8d96238d",
   "metadata": {},
   "outputs": [],
   "source": [
    "sink my $conf5-mini = llm-configuration('ChatGPT', model => 'gpt-5-mini');\n",
    "sink my $conf41-mini = llm-configuration('ChatGPT', model => 'gpt-4.1-mini', :8192max-tokens, temperature => 0.4);\n",
    "sink my $conf-gemini-flash = llm-configuration('Gemini', model => 'gemini-2.0-flash', :8192max-tokens, temperature => 0.4);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6efae8bb",
   "metadata": {},
   "source": [
    "### JavaScript::D3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "78f89d5c",
   "metadata": {},
   "outputs": [],
   "source": [
    "#%javascript\n",
    "require.config({\n",
    "     paths: {\n",
    "     d3: 'https://d3js.org/d3.v7.min'\n",
    "}});\n",
    "\n",
    "require(['d3'], function(d3) {\n",
    "     console.log(d3);\n",
    "});"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "131a8ead",
   "metadata": {},
   "outputs": [],
   "source": [
    "#%js\n",
    "js-d3-list-line-plot(10.rand xx 30, background => 'none')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd022748",
   "metadata": {},
   "source": [
    "----\n",
    "\n",
    "## Diagram"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fbfa151f",
   "metadata": {},
   "source": [
    "Here is a [Mermaid-JS](https://mermaid.js.org) diagram that shows _single-pass_ LLM-and-tool interaction:\n",
    "\n",
    "\n",
    "```mermaid\n",
    "sequenceDiagram\n",
    "    participant Developer\n",
    "    participant Model as LLM Service (Gemini)\n",
    "    participant Tool as External Function\n",
    "\n",
    "    Note over Developer, Model: 1. Tool Definitions + Messages\n",
    "    Developer->>Model: molecular-mass(molecule) <br> \"What's the mass of SO2?\"\n",
    "\n",
    "    Note over Model: 2. Tool Calls\n",
    "    Model->>Tool: molecular-mass(\"SO2\")\n",
    "\n",
    "    Note over Tool: 3. Execute Function Code\n",
    "    Tool->>Model: {\"mass\": 64.058}\n",
    "\n",
    "    Note over Model: 4. Results\n",
    "    Model->>Developer: {\"mass\": 64.058}\n",
    "\n",
    "    Note over Developer: 5. Final Response\n",
    "    Developer->>Model: The molecular mass of SO2 is 64.058.\n",
    "```\n",
    "\n",
    "\n",
    "**Remark:** Instead of one invocation of a local tool -- as shown in the diagram -- often enough multiple LLM-&-local-computer interactions are used for LLM-tool computation.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d4fd58df",
   "metadata": {},
   "source": [
    "----\n",
    "\n",
    "## JavaScript graphics via [D3.js](https://d3js.org)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "384b868e",
   "metadata": {},
   "source": [
    "Define tools:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a7a18071",
   "metadata": {},
   "outputs": [],
   "source": [
    "sink my @js-tool-specs = (\n",
    "{\n",
    "    :name(\"js-d3-random-mondrian\"),\n",
    "    :description(\"Make the JavaScript code of a random Mondrian plot\"),\n",
    "    :parameters({\n",
    "        :type(\"object\"),\n",
    "        :properties( {\n",
    "            \"\\$width\" => { :description(\"Width of the plot\"), :type(\"integer\") },\n",
    "            \"\\$height\" => { :description(\"Height of the plot\"), :type(\"integer\") }\n",
    "            }),\n",
    "        :required([]),\n",
    "    }),\n",
    "},\n",
    ");"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "05c449b6",
   "metadata": {},
   "outputs": [],
   "source": [
    "sink my @js-tool-objects =\n",
    "        LLM::Tool.new(&js-d3-random-mondrian),\n",
    "        LLM::Tool.new(&js-d3-random-mandala)\n",
    "        ;\n",
    "\n",
    "sink my $conf = llm-configuration($conf-gemini-flash, tools => @js-tool-objects);\n",
    "#sink my $conf = llm-configuration($conf41-mini, tools => @js-tool-objects);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "328c32d4",
   "metadata": {},
   "outputs": [
    {
     "ename": "",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31mThe Kernel crashed while executing code in the current cell or a previous cell. \n",
      "\u001b[1;31mPlease review the code in the cell(s) to identify a possible cause of the failure. \n",
      "\u001b[1;31mClick <a href='https://aka.ms/vscodeJupyterKernelCrash'>here</a> for more info. \n",
      "\u001b[1;31mView Jupyter <a href='command:jupyter.viewOutput'>log</a> for further details."
     ]
    }
   ],
   "source": [
    "#% js\n",
    "my $request = q:to/END/;\n",
    "Generate a random Mondrian with dark gray background and image width == 450. \n",
    "Stop generating immediately when you obtain JavaScript / D3.js code.\n",
    "Make sure the argument $color-palette to be Whatever.\n",
    "END\n",
    "\n",
    "my $res = \n",
    "    llm-synthesize([\n",
    "        $request, \n",
    "        llm-prompt('NothingElse')('D3.js code')\n",
    "        ], \n",
    "        e => llm-configuration($conf41-mini, tools => @js-tool-objects)\n",
    "    ):echo;\n",
    "\n",
    "$res .= subst(/ '```javascript' | '```'/, :g)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6e42571e",
   "metadata": {},
   "source": [
    "-----\n",
    "\n",
    "## References"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6e7d12e8",
   "metadata": {},
   "source": [
    "### Articles, blog posts\n",
    "\n",
    "[AA1] Anton Antonov,\n",
    "[\"LLM function calling workflows (Part 1, OpenAI)\"](https://rakuforprediction.wordpress.com/2025/06/01/llm-function-calling-workflows-part-1-openai/),\n",
    "(2025),\n",
    "[RakuForPrediction at WordPress](https://rakuforprediction.wordpress.com).\n",
    "\n",
    "[AA2] Anton Antonov,\n",
    "[\"LLM function calling workflows (Part 2, Google's Gemini)\"](https://rakuforprediction.wordpress.com/2025/06/01/llm-function-calling-workflows-part-2-google-gemini/),\n",
    "(2025),\n",
    "[RakuForPrediction at WordPress](https://rakuforprediction.wordpress.com).\n",
    "\n",
    "[AA3] Anton Antonov,\n",
    "[\"LLM function calling workflows (Part 3, Facilitation)\"](https://rakuforprediction.wordpress.com/2025/06/08/llm-function-calling-workflows-part-3-facilitation/),\n",
    "(2025),\n",
    "[RakuForPrediction at WordPress](https://rakuforprediction.wordpress.com).\n",
    "\n",
    "[Gem1] Google Gemini,\n",
    "[\"Gemini Developer API\"](https://ai.google.dev/gemini-api/docs).\n",
    "\n",
    "[WRI1] Wolfram Research, Inc.\n",
    "[\"LLM-Related Functionality\" guide](https://reference.wolfram.com/language/guide/LLMFunctions.html).\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "37641916",
   "metadata": {},
   "source": [
    "### Packages \n",
    "\n",
    "[AAp1] Anton Antonov,\n",
    "[WWW::OpenAI Raku package](https://github.com/antononcube/Raku-WWW-OpenAI),\n",
    "(2023-2025),\n",
    "[GitHub/antononcube](https://github.com/antononcube).\n",
    "\n",
    "[AAp2] Anton Antonov,\n",
    "[WWW::Gemini Raku package](https://github.com/antononcube/Raku-WWW-Gemini),\n",
    "(2023-2025),\n",
    "[GitHub/antononcube](https://github.com/antononcube).\n",
    "\n",
    "[AAp3] Anton Antonov,\n",
    "[LLM::Functions Raku package](https://github.com/antononcube/Raku-LLM-Functions),\n",
    "(2023-2025),\n",
    "[GitHub/antononcube](https://github.com/antononcube)."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "RakuChatbook",
   "language": "raku",
   "name": "raku"
  },
  "language_info": {
   "file_extension": ".raku",
   "mimetype": "text/x-raku",
   "name": "raku",
   "version": "6.d"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
