autopreso 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,6 +11,10 @@
11
11
 
12
12
  <h3 align="center">Let the whiteboard whiteboard itself.</h3>
13
13
 
14
+ <p align="center">
15
+ <img src="https://raw.githubusercontent.com/kunchenguid/autopreso/main/assets/autopreso.png" alt="autopreso whiteboard hero screenshot" width="960" />
16
+ </p>
17
+
14
18
  > [!WARNING]
15
19
  > autopreso is in **alpha** and under active development. Expect rough edges, breaking changes, and the occasional weird drawing. Bug reports welcome.
16
20
 
@@ -112,8 +116,8 @@ When no settings file exists, autopreso picks providers based on what it finds i
112
116
  | ------------------------------------------ | ------------------------------ | -------------------------- |
113
117
  | Nothing | OpenAI `gpt-5.5` (needs a key) | Moonshine `medium` (macOS) |
114
118
  | `OPENAI_API_KEY` in env | OpenAI `gpt-5.5` | OpenAI Realtime |
115
- | Codex CLI signed in (`~/.codex/auth.json`) | Codex `gpt-5.5` | Moonshine `medium` |
116
- | Codex CLI signed in + `OPENAI_API_KEY` | Codex `gpt-5.5` | OpenAI Realtime |
119
+ | Codex CLI signed in (`~/.codex/auth.json`) | Codex `gpt-5.5-fast` | Moonshine `medium` |
120
+ | Codex CLI signed in + `OPENAI_API_KEY` | Codex `gpt-5.5-fast` | OpenAI Realtime |
117
121
  | `OLLAMA_MODEL` set | Ollama (your model) | Moonshine `medium` |
118
122
 
119
123
  Auto-detection precedence: **Codex CLI auth wins over `OLLAMA_MODEL` wins over `OPENAI_API_KEY`** for the agent. Transcription flips to OpenAI Realtime any time an OpenAI key is present, otherwise Moonshine. After first run, this auto-detection no longer applies - change providers from the in-app status panel.
@@ -127,6 +131,7 @@ Provider variables only seed `settings.json` on first run. Once the file exists,
127
131
  | `PORT` | Port to listen on. Default: `3210`. |
128
132
  | `OPENAI_API_KEY` | Seeds the OpenAI key for both agent and Realtime STT. |
129
133
  | `OPENAI_MODEL` | Seeds the OpenAI agent model. |
134
+ | `OPENAI_BASE_URL` | Seeds the OpenAI agent API base URL. |
130
135
  | `CODEX_MODEL` | Seeds the Codex model. |
131
136
  | `OLLAMA_MODEL` | Seeds the Ollama model. |
132
137
  | `AUTOPRESO_CACHE_LOG` | Cache usage log path. Default: `~/.config/autopreso/logs/cache.log`. |
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autopreso",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Realtime speech to presentation. Let the whiteboard whiteboard itself.",
5
5
  "license": "MIT",
6
6
  "author": "Kun Chen <kun@kunchenguid.com>",
@@ -32,6 +32,7 @@
32
32
  "autopreso": "src/cli.js"
33
33
  },
34
34
  "files": [
35
+ "assets/",
35
36
  "LICENSE",
36
37
  "public/",
37
38
  "src/"
package/public/app.js CHANGED
@@ -11,7 +11,7 @@ import { STARTER_ELEMENTS } from "./starter-elements.js";
11
11
  const SAMPLE_RATE = 24000;
12
12
  const REASONING_EFFORTS = ["none", "low", "medium", "high", "xhigh"];
13
13
  const OPENAI_AGENT_MODELS = ["gpt-5.5", "gpt-5.4", "gpt-5.4-mini"];
14
- const CODEX_AGENT_MODELS = ["gpt-5.5", "gpt-5.5-fast", "gpt-5.4"];
14
+ const CODEX_AGENT_MODELS = ["gpt-5.5-fast", "gpt-5.5", "gpt-5.4"];
15
15
  const OPENAI_TRANSCRIPTION_MODELS = [
16
16
  "gpt-realtime-whisper",
17
17
  "gpt-4o-transcribe",
@@ -1331,6 +1331,9 @@ function AgentEditor({ settings, onSave, onCancel }) {
1331
1331
  const [reasoningEffort, setReasoningEffort] = React.useState(
1332
1332
  settings.agent.openai.reasoningEffort,
1333
1333
  );
1334
+ const [openaiBaseURL, setOpenaiBaseURL] = React.useState(
1335
+ settings.agent.openai.baseURL,
1336
+ );
1334
1337
  const [codexModel, setCodexModel] = React.useState(
1335
1338
  settings.agent.codex.model,
1336
1339
  );
@@ -1354,6 +1357,7 @@ function AgentEditor({ settings, onSave, onCancel }) {
1354
1357
  if (provider === "openai") {
1355
1358
  patch.agent.openai.model = openaiModel;
1356
1359
  patch.agent.openai.reasoningEffort = reasoningEffort;
1360
+ patch.agent.openai.baseURL = openaiBaseURL;
1357
1361
  } else if (provider === "codex") {
1358
1362
  patch.agent.codex.model = codexModel;
1359
1363
  } else {
@@ -1429,7 +1433,7 @@ function AgentEditor({ settings, onSave, onCancel }) {
1429
1433
  : null,
1430
1434
  needsOpenAIKey
1431
1435
  ? field(
1432
- "OpenAI key",
1436
+ "API key",
1433
1437
  React.createElement("input", {
1434
1438
  type: "password",
1435
1439
  value: openaiKey,
@@ -1441,7 +1445,7 @@ function AgentEditor({ settings, onSave, onCancel }) {
1441
1445
  : null,
1442
1446
  provider === "openai" && settings.hasOpenAIKey
1443
1447
  ? field(
1444
- "OpenAI key",
1448
+ "API key",
1445
1449
  React.createElement("input", {
1446
1450
  type: "password",
1447
1451
  value: openaiKey,
@@ -1451,6 +1455,17 @@ function AgentEditor({ settings, onSave, onCancel }) {
1451
1455
  }),
1452
1456
  )
1453
1457
  : null,
1458
+ provider === "openai"
1459
+ ? field(
1460
+ "Base URL",
1461
+ React.createElement("input", {
1462
+ type: "text",
1463
+ value: openaiBaseURL,
1464
+ onChange: (e) => setOpenaiBaseURL(e.target.value),
1465
+ disabled: busy,
1466
+ }),
1467
+ )
1468
+ : null,
1454
1469
  errorText
1455
1470
  ? React.createElement("div", { className: "editor-error" }, errorText)
1456
1471
  : null,
@@ -1543,7 +1558,7 @@ function TranscriptionEditor({ settings, onSave, onCancel }) {
1543
1558
  : null,
1544
1559
  needsOpenAIKey
1545
1560
  ? field(
1546
- "OpenAI key",
1561
+ "API key",
1547
1562
  React.createElement("input", {
1548
1563
  type: "password",
1549
1564
  value: openaiKey,
@@ -1555,7 +1570,7 @@ function TranscriptionEditor({ settings, onSave, onCancel }) {
1555
1570
  : null,
1556
1571
  provider === "openai" && settings.hasOpenAIKey
1557
1572
  ? field(
1558
- "OpenAI key",
1573
+ "API key",
1559
1574
  React.createElement("input", {
1560
1575
  type: "password",
1561
1576
  value: openaiKey,
@@ -3,7 +3,9 @@ import { createOpenAI } from "@ai-sdk/openai";
3
3
  import { DEFAULT_CODEX_BASE_URL, createCodexFetch, readCodexCliAuthSync } from "./codex-auth.js";
4
4
 
5
5
  const DEFAULT_OPENAI_AGENT_MODEL = "gpt-5.5";
6
+ const DEFAULT_CODEX_AGENT_MODEL = "gpt-5.5-fast";
6
7
  const DEFAULT_OPENAI_REASONING_EFFORT = "low";
8
+ const DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1";
7
9
  const DEFAULT_OLLAMA_BASE_URL = "http://localhost:11434/v1";
8
10
  const OPENAI_REASONING_EFFORTS = new Set(["none", "low", "medium", "high", "xhigh"]);
9
11
 
@@ -12,6 +14,7 @@ export function defaultWhiteboardAgentProvider(options = {}) {
12
14
  provider: "openai",
13
15
  model: DEFAULT_OPENAI_AGENT_MODEL,
14
16
  apiKey: options.openaiApiKey,
17
+ baseURL: DEFAULT_OPENAI_BASE_URL,
15
18
  reasoningEffort: DEFAULT_OPENAI_REASONING_EFFORT,
16
19
  };
17
20
  }
@@ -33,7 +36,7 @@ export function resolveAgentProviderFromSettings({ settings, env = process.env }
33
36
  if (provider === "codex") {
34
37
  const codexAuth = readCodexCliAuthSync(env);
35
38
  if (!codexAuth) throw new Error("Codex CLI auth not found. Run `codex` and sign in with ChatGPT.");
36
- const codexModel = resolveCodexModel(settings.agent.codex.model || DEFAULT_OPENAI_AGENT_MODEL);
39
+ const codexModel = resolveCodexModel(settings.agent.codex.model || DEFAULT_CODEX_AGENT_MODEL);
37
40
  return {
38
41
  provider: "codex",
39
42
  ...codexModel,
@@ -50,6 +53,7 @@ export function resolveAgentProviderFromSettings({ settings, env = process.env }
50
53
  model: settings.agent.openai.model || DEFAULT_OPENAI_AGENT_MODEL,
51
54
  apiKey,
52
55
  reasoningEffort: validateReasoningEffort(settings.agent.openai.reasoningEffort),
56
+ baseURL: withoutTrailingSlash(cleanEnvValue(settings.agent.openai.baseURL) ?? DEFAULT_OPENAI_BASE_URL),
53
57
  };
54
58
  }
55
59
 
@@ -81,7 +85,10 @@ export function createWhiteboardAgentModel(agentProvider) {
81
85
  return codex.responses(agentProvider.model);
82
86
  }
83
87
 
84
- const openai = createOpenAI({ apiKey: agentProvider.apiKey });
88
+ const openai = createOpenAI({
89
+ apiKey: agentProvider.apiKey,
90
+ baseURL: agentProvider.baseURL,
91
+ });
85
92
  return openai(agentProvider.model);
86
93
  }
87
94
 
package/src/cli.js CHANGED
@@ -76,6 +76,7 @@ Environment:
76
76
  PORT Port to listen on. Default: 3210
77
77
  OPENAI_API_KEY Seeds the OpenAI key on first run if no settings file exists
78
78
  OPENAI_MODEL Seeds the OpenAI agent model on first run
79
+ OPENAI_BASE_URL Seeds the OpenAI agent API base URL on first run
79
80
  OPENAI_REASONING_EFFORT Seeds reasoning effort on first run (none, low, medium, high, xhigh)
80
81
  CODEX_HOME Codex CLI home directory. Default: ~/.codex
81
82
  CODEX_MODEL Seeds the Codex model on first run
@@ -8,8 +8,8 @@ export const MAX_AGENT_INSTRUCTIONS_CHARS = 100_000;
8
8
  export const DEFAULT_SETTINGS = Object.freeze({
9
9
  agent: {
10
10
  provider: "openai",
11
- openai: { model: "gpt-5.5", reasoningEffort: "low" },
12
- codex: { model: "gpt-5.5", baseURL: "https://chatgpt.com/backend-api/codex" },
11
+ openai: { model: "gpt-5.5", reasoningEffort: "low", baseURL: "https://api.openai.com/v1" },
12
+ codex: { model: "gpt-5.5-fast", baseURL: "https://chatgpt.com/backend-api/codex" },
13
13
  ollama: { model: "", baseURL: "http://localhost:11434/v1" },
14
14
  },
15
15
  transcription: {
@@ -102,6 +102,9 @@ function seedFromEnv(settings, env, readCodexAuth) {
102
102
  const openaiModel = trimOrEmpty(env.OPENAI_MODEL);
103
103
  if (openaiModel) next.agent.openai.model = openaiModel;
104
104
 
105
+ const openaiBaseURL = trimOrEmpty(env.OPENAI_BASE_URL);
106
+ if (openaiBaseURL) next.agent.openai.baseURL = openaiBaseURL;
107
+
105
108
  const reasoningEffort = trimOrEmpty(env.OPENAI_REASONING_EFFORT);
106
109
  if (reasoningEffort) next.agent.openai.reasoningEffort = reasoningEffort;
107
110