# Options

```toml
model = "gpt-5-mini"
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/
-- 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 = true,  url = ""},
   
   {name = "gemini",    do_json = false,  url = "https://ai.google.dev/pricing"},
   {name = "deepseek",  do_json = false,  url = "https://api-docs.deepseek.com/quick_start/pricing"},
   {name = "anthropic", do_json = false,  url = "https://docs.anthropic.com/en/docs/about-claude/models/overview"},

   {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.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 aipack.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 aipack.skip("" .. input.name .. " marked as do_json = false, so skipping")
end

if not aip.path.exists(html_path) then 
    return aipack.skip("" .. input.name .. " no html " .. html_path .. " so skipping")
end 

local slim_html = aip.file.save_html_to_slim(html_path)
aip.file.save_html_to_md(slim_html.path, md_path)


-- 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

From this content for the {{data.provider}}: 

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

- Create a pricing JSON
- Make sure all models are all lowercase
- 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`
- 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 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 Models (Claude), the `.` should be replaced by `-`
- 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 (Claude), make sure you get the model names from the model is, and remove the `-2025...`
- For Anthropic models (Claude), `claude-3-7-sonnet` need to be marked as `recent: false`
- 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.
- but for gemini model, keep the `.` in the name.
- For Gemini model, `gemini-2.5-pro-preview` and `gemini-2.5-flash-preview` remove the `-preview` in the name
- For deepseek model, ignore the discound price
- for OpenAI models
    - Do not add the gpt-image-1
    - 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 openAI models, the -4o, 4.1, and codex family models are `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)

```