# Options

```toml
model = "gemini-3-flash-preview"
input_concurrency = 6
```

# Before All

```lua
local p_utils = require("pricing_utils")

local base_dir = p_utils.base_dir

-- NOTE: Just delete the .md file for the provider name to have it load it. 

-- GROQ      - https://console.groq.com/docs/models pricing: https://groq.com/pricing/
-- OPENAI    - https://platform.openai.com/docs/pricing/
-- ANTHROPIC - https://platform.claude.com/docs/en/about-claude/pricing
--             https://claude.com/pricing#api
--             Overview https://docs.anthropic.com/en/docs/about-claude/models/overview
-- GEMINI    - https://ai.google.dev/pricing
-- XAI       - https://console.x.ai/team/5577cfb2-dfde-4893-9817-4eb4de1d4098/models
-- FIREWORKS - Login with filter https://app.fireworks.ai/models?filter=LLM&serverless=true, 
--             Static https://fireworks.ai/pricing#serverless-pricing
-- TOGETHER  - login models price: https://api.together.ai/models
--             names In the browser window: console.log($$('td[id]').map(td => td.id).join('\n'));
local inputs = {
   -- This openai link does not work with puppeteer, needs to copy/paste conine in the pricing-openai.md
   {name = "openai",    do_json = false,  url = ""},
   {name = "gemini",    do_json = false,  url = ""},
   {name = "deepseek",  do_json = false,  url = "https://api-docs.deepseek.com/quick_start/pricing"},
   {name = "anthropic", do_json = true,   url = ""},
   {name = "xai",       do_json = false,  url = ""}, 
   {name = "groq",      do_json = false,  url = ""},
   {name = "fireworks", do_json = false,  url = ""},
   {name = "together",  do_json = false,  url = ""}
}

-- Agument inputs
for _, input in ipairs(inputs) do
    input._display  = input.name
    input.md_path   = base_dir .. "/.data/pricing-" .. input.name .. ".md"
    input.html_path = base_dir .. "/.data/pricing-" .. input.name .. ".html"
    input.json_path = base_dir .. "/.data/pricing-" .. input.name .. ".json"
end

return aip.flow.before_all_response({
    inputs     = inputs
})
```

# Data

```lua
local md_path   = input.md_path
local json_path = input.json_path
local html_path = input.html_path

if not input.do_json  then
    return aip.flow.skip("" .. input.name .. " marked as do_json = false, so skipping")
end

if aip.path.exists(html_path) then 
    local slim_html = aip.file.save_html_to_slim(html_path)
    aip.file.save_html_to_md(slim_html.path, md_path)
end 

if not aip.path.exists(md_path) then
    return aip.flow.skip("" .. input.name .. " no md " .. md_path .. " so skipping")
end

-- local rem_url = input.url
-- if not aip.path.exists(md_path) then 
--     local req = {
--         jsonrpc = "2.0",
--         method = "get_md",
--         params = { url = rem_url },
--         id = 1
--     }
-- 
--     -- Yes, it will require to have this mini rpc service (just wrapper on top of puppeteer)
--     local res = aip.web.post("http://localhost:3000/jsonrpc", req)
-- 
--     local content = res.content.result.content
--     aip.file.save(md_path, content)
-- end




local file = aip.file.load(md_path)

return {
    provider = input.name,
    content = file.content
}
```

# Instruction

Here are the data for this {{data.provider}} AI Provider: 

```md
{{data.content}}
```

Create a pricing JSON for this provider, following the following rules (pick the right rules for this provider)


- Make sure all models are all lowercase
- for OpenAI models
    - for OpenAI modelsDo not add the gpt-image-1 or audio models
    - for OpenAI models Only take the "standards" pricing,
    - For OpenAI Models, set `cache_write: null` when not defined. 
    - for OpenAI models ignore the legacy models
    - For OpenAI Models, model starting with `gpt-5.2`. and `gpt-5-mini` are all `recent: true`, and then everything else is `recent: false`. 
    - For OpenAI Models, ignore the lines have have dates like text, like `2024-05-13` 
    - For OpenAI Models, only take the Text tokens section, ignore the other sections. 
    - For OpenAI Models, there are not cash write, so, only input and cached when present, and then the output. 
- For Fireworks models: 
    - For the Fireworks models, the model name is after the `/models/fireworks/`. So, `/models/fireworks/qwen3-coder-480b-a35b-instruct` the model name will be `qwen3-coder-480b-a35b-instruct`
    - For the Fireworks models, when only one price, it means same price for input and output. 
    - For the fireworks models, have only the gpt-oss, qwen3, Kimi, lama 4, and gml 4 are to be flagged recent, the rest flagged recent = false. 
    - For the fireworks models, when end with date like versioning like `qwen3-235b-a22b-thinking-2507` remove the versioning, so it becomes `qwen3-235b-a22b-thinking`
- For Together Models:
    - For together models only add models that have pricing. 
    - For together models, when one price, means it is the same for input / output
    - For the together models, the model name is what is in the model name section. make sure to use that name that match the one of the pricing. 
    - The together model names are in the <h1>Names</h1> section. 
    - Set the flag `recent: true` only for the model names that match the `<h1>recent</h1>` list, and all the other should be `recent: false`
    - Also, only extract the models about Llama, qwen, deepseek, glm, gemma, mixtral, mistral, and openai. 
- For Anthropic 
    - Here are the correct patterns to usefor the anthropic models (use use `-` rather than `.` in the model names)
        - `claude-opus-4-5`, ...,  `claude-sonnet-4-5`, `claude-haiku-4-5`
        - `claude-opus-4-1`, `claude-sonnet-4`, 
        - `claude-3-7-sonnet`, `claude-opus-4`, `claude-3-5-haiku`
    - So match the model names in the pages to those one. 
    - For Anthropic Models (Claude), Make sure to have only one `recent: true` for each model type, Sonnet, Haiku, Opus. Pick the highest number for each of them to mark as `recent: true`
    - Make sure to remove / not add the "deprecated" ones
    - For Anthropic Models (Claude), the name/value is inverse. For value, and then, label of this value. 
    - For Anthropic Models (Claude), when caching write value, put it in `.cache_write`, and then, the cache value goes in `.cached`
    - For Anthropic Models, cache write price, take the `5m` price
    - For Anthropic models (Claude), make sure you get the model names from the model is, and remove the `-2025...`
    - For Anthropic models (Claude), only sonnet/haiku 4.5 and opus 4.1 are recent: true, all others are recent: false
- For gemini models,
    - For gemini models there is no `caching write`, so cache value is for the `.cached` property. 
    - For Gemini models, do not add the audio or tts model.
    - For gemini models, keep the `.` in the name.
    - For Gemini models, `gemini-3-pro-preview` and `gemini-3-flash-preview` remove the `-preview` in the name
    - For Gemini models, for `gemini-2.5-pro` remove the release number after pro like the `-09...` same for other gemini models. Just have the main one. 
    - For the Gemini models, add new models for 
      - `gemini-flash-latest` based on `gemini flash 2.5` pricing. 
      - `gemini-pro-latest` based on `gemini pro 2.5` pricing. 
      - Not that bothg of this latest will be `recent: false` as they ar aboused on the 2.5
    - For gemini models all only `gemini-3...` are marked with `recent: true` and and the rest are false.
    - For gemini models, only add the model that starts with `gemini...`
- For Groq models, 
    - For Groq models there are two sections in the markdown, the pricing and the name. Make sure to take the name from the name section, and infer the "display name" to get the pricing. 
    - For Groq models, the models that are both section name and price, mark them as `recent: true`, if they are not in the model names, then `recent: false`    
- Do not put in code block, just the raw json, pretty formatted.
- If caching price not available, set to `null`
- If price has text and audio, take the text price
- When decimal, do not end with 0s. Just up to the number. 

with following schema

```ts
{
    models:
        {
            name: string,
            input: {
                cache_write: number | null,
                cached: number | null,
                normal: number | null,
            },
            output: number, 
            recent: boolean, // default true if not sure
        }[]
}
```


# Output 

```lua
local content = ai_response.content
content = aip.md.outer_block_content_or_raw(content)

aip.file.save(input.json_path, content)
```

# After All


```lua
local p_utils = require("pricing_utils")

local json_path = p_utils.json_all_path

-- == Prep the final json
local content = "{\n"

local last_idx = #inputs

for k, input in pairs(inputs) do
  local json_path = input.json_path
  local file_content = aip.file.load(json_path).content
  content = content .. "\"" .. input.name .. "\": " .. file_content
  if k == last_idx then 
    content = content .. "\n"
  else
    content = content .. ",\n"
  end
end

content = content .. "}"

-- == Normalize json
local json    = aip.json.parse(content)
local content = aip.json.stringify_pretty(json)

-- == Save final json
aip.file.save(json_path, content)

```
