@elizaos/skills 2.0.0-alpha.43 → 2.0.0-alpha.430
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 +4 -0
- package/dist/formatter.d.ts.map +1 -1
- package/dist/formatter.js +3 -3
- package/dist/frontmatter.d.ts +13 -1
- package/dist/frontmatter.d.ts.map +1 -1
- package/dist/frontmatter.js +51 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +10 -3
- package/dist/resolver.d.ts +17 -0
- package/dist/resolver.d.ts.map +1 -1
- package/dist/resolver.js +54 -1
- package/dist/types.d.ts +38 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +7 -6
- package/skills/apple-reminders/SKILL.md +1 -1
- package/skills/blucli/SKILL.md +1 -1
- package/skills/bluebubbles/SKILL.md +1 -1
- package/skills/camsnap/SKILL.md +1 -1
- package/skills/canvas/SKILL.md +6 -6
- package/skills/coding-agent/SKILL.md +2 -2
- package/skills/eliza-app-development/SKILL.md +62 -0
- package/skills/eliza-app-development/references/repo-map.md +70 -0
- package/skills/eliza-app-development/references/runtime-and-cloud.md +61 -0
- package/skills/eliza-cloud/SKILL.md +39 -0
- package/skills/eliza-cloud/references/apps-and-containers.md +73 -0
- package/skills/eliza-cloud/references/cloud-backend-and-monetization.md +99 -0
- package/skills/elizaos/SKILL.md +27 -0
- package/skills/elizaos/references/core-abstractions.md +101 -0
- package/skills/elizaos/references/plugin-development.md +74 -0
- package/skills/github/SKILL.md +1 -1
- package/skills/imsg/SKILL.md +1 -1
- package/skills/nano-banana-pro/SKILL.md +1 -1
- package/skills/nano-pdf/SKILL.md +1 -1
- package/skills/notion/SKILL.md +1 -1
- package/skills/obsidian/SKILL.md +1 -1
- package/skills/ordercli/SKILL.md +1 -1
- package/skills/skill-creator/SKILL.md +1 -1
- package/skills/slack/SKILL.md +1 -1
- package/skills/spotify-player/SKILL.md +1 -1
- package/skills/tmux/SKILL.md +1 -1
- package/skills/trello/SKILL.md +1 -1
- package/skills/wacli/SKILL.md +1 -1
- package/skills/weather/SKILL.md +1 -1
- package/skills/yara-authoring/SKILL.md +111 -0
- package/skills/bear-notes/SKILL.md +0 -107
- package/skills/bird/SKILL.md +0 -224
- package/skills/blogwatcher/SKILL.md +0 -69
- package/skills/clawhub/SKILL.md +0 -77
- package/skills/eightctl/SKILL.md +0 -50
- package/skills/food-order/SKILL.md +0 -48
- package/skills/gemini/SKILL.md +0 -43
- package/skills/gifgrep/SKILL.md +0 -79
- package/skills/gog/SKILL.md +0 -116
- package/skills/goplaces/SKILL.md +0 -52
- package/skills/himalaya/SKILL.md +0 -257
- package/skills/himalaya/references/configuration.md +0 -184
- package/skills/himalaya/references/message-composition.md +0 -199
- package/skills/local-places/SERVER_README.md +0 -101
- package/skills/local-places/SKILL.md +0 -102
- package/skills/local-places/pyproject.toml +0 -21
- package/skills/local-places/src/local_places/__init__.py +0 -2
- package/skills/local-places/src/local_places/google_places.py +0 -314
- package/skills/local-places/src/local_places/main.py +0 -65
- package/skills/local-places/src/local_places/schemas.py +0 -107
- package/skills/mcporter/SKILL.md +0 -61
- package/skills/model-usage/SKILL.md +0 -69
- package/skills/model-usage/references/codexbar-cli.md +0 -33
- package/skills/model-usage/scripts/model_usage.py +0 -310
- package/skills/openai-image-gen/SKILL.md +0 -89
- package/skills/openai-image-gen/scripts/gen.py +0 -240
- package/skills/openai-whisper/SKILL.md +0 -38
- package/skills/openai-whisper-api/SKILL.md +0 -52
- package/skills/openai-whisper-api/scripts/transcribe.sh +0 -85
- package/skills/openhue/SKILL.md +0 -51
- package/skills/oracle/SKILL.md +0 -125
- package/skills/peekaboo/SKILL.md +0 -190
- package/skills/sag/SKILL.md +0 -87
- package/skills/session-logs/SKILL.md +0 -115
- package/skills/sharp-edges/.claude-plugin/plugin.json +0 -10
- package/skills/sharp-edges/README.md +0 -48
- package/skills/sharp-edges/SKILL.md +0 -292
- package/skills/sharp-edges/skills/sharp-edges/SKILL.md +0 -292
- package/skills/sharp-edges/skills/sharp-edges/references/auth-patterns.md +0 -252
- package/skills/sharp-edges/skills/sharp-edges/references/case-studies.md +0 -274
- package/skills/sharp-edges/skills/sharp-edges/references/config-patterns.md +0 -333
- package/skills/sharp-edges/skills/sharp-edges/references/crypto-apis.md +0 -190
- package/skills/sharp-edges/skills/sharp-edges/references/lang-c.md +0 -205
- package/skills/sharp-edges/skills/sharp-edges/references/lang-csharp.md +0 -285
- package/skills/sharp-edges/skills/sharp-edges/references/lang-go.md +0 -270
- package/skills/sharp-edges/skills/sharp-edges/references/lang-java.md +0 -263
- package/skills/sharp-edges/skills/sharp-edges/references/lang-javascript.md +0 -269
- package/skills/sharp-edges/skills/sharp-edges/references/lang-kotlin.md +0 -265
- package/skills/sharp-edges/skills/sharp-edges/references/lang-php.md +0 -245
- package/skills/sharp-edges/skills/sharp-edges/references/lang-python.md +0 -274
- package/skills/sharp-edges/skills/sharp-edges/references/lang-ruby.md +0 -273
- package/skills/sharp-edges/skills/sharp-edges/references/lang-rust.md +0 -272
- package/skills/sharp-edges/skills/sharp-edges/references/lang-swift.md +0 -287
- package/skills/sharp-edges/skills/sharp-edges/references/language-specific.md +0 -588
- package/skills/sherpa-onnx-tts/SKILL.md +0 -103
- package/skills/sherpa-onnx-tts/bin/sherpa-onnx-tts +0 -178
- package/skills/songsee/SKILL.md +0 -49
- package/skills/sonoscli/SKILL.md +0 -46
- package/skills/spec-to-code-compliance/.claude-plugin/plugin.json +0 -10
- package/skills/spec-to-code-compliance/README.md +0 -67
- package/skills/spec-to-code-compliance/SKILL.md +0 -349
- package/skills/spec-to-code-compliance/commands/spec-compliance.md +0 -22
- package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/SKILL.md +0 -349
- package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/resources/COMPLETENESS_CHECKLIST.md +0 -69
- package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/resources/IR_EXAMPLES.md +0 -417
- package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/resources/OUTPUT_REQUIREMENTS.md +0 -105
- package/skills/static-analysis/.claude-plugin/plugin.json +0 -8
- package/skills/static-analysis/README.md +0 -59
- package/skills/static-analysis/SKILL.md +0 -91
- package/skills/static-analysis/skills/codeql/SKILL.md +0 -315
- package/skills/static-analysis/skills/sarif-parsing/SKILL.md +0 -479
- package/skills/static-analysis/skills/sarif-parsing/resources/jq-queries.md +0 -162
- package/skills/static-analysis/skills/sarif-parsing/resources/sarif_helpers.py +0 -331
- package/skills/static-analysis/skills/semgrep/SKILL.md +0 -337
- package/skills/summarize/SKILL.md +0 -87
- package/skills/testing-handbook-skills/.claude-plugin/plugin.json +0 -8
- package/skills/testing-handbook-skills/README.md +0 -241
- package/skills/testing-handbook-skills/SKILL.md +0 -104
- package/skills/testing-handbook-skills/scripts/pyproject.toml +0 -8
- package/skills/testing-handbook-skills/scripts/validate-skills.py +0 -657
- package/skills/testing-handbook-skills/skills/address-sanitizer/SKILL.md +0 -341
- package/skills/testing-handbook-skills/skills/aflpp/SKILL.md +0 -640
- package/skills/testing-handbook-skills/skills/atheris/SKILL.md +0 -515
- package/skills/testing-handbook-skills/skills/cargo-fuzz/SKILL.md +0 -454
- package/skills/testing-handbook-skills/skills/codeql/SKILL.md +0 -549
- package/skills/testing-handbook-skills/skills/constant-time-testing/SKILL.md +0 -507
- package/skills/testing-handbook-skills/skills/coverage-analysis/SKILL.md +0 -607
- package/skills/testing-handbook-skills/skills/fuzzing-dictionary/SKILL.md +0 -297
- package/skills/testing-handbook-skills/skills/fuzzing-obstacles/SKILL.md +0 -426
- package/skills/testing-handbook-skills/skills/harness-writing/SKILL.md +0 -614
- package/skills/testing-handbook-skills/skills/libafl/SKILL.md +0 -625
- package/skills/testing-handbook-skills/skills/libfuzzer/SKILL.md +0 -795
- package/skills/testing-handbook-skills/skills/ossfuzz/SKILL.md +0 -426
- package/skills/testing-handbook-skills/skills/ruzzy/SKILL.md +0 -443
- package/skills/testing-handbook-skills/skills/semgrep/SKILL.md +0 -601
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/SKILL.md +0 -372
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/agent-prompt.md +0 -280
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/discovery.md +0 -452
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/domain-skill.md +0 -504
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/fuzzer-skill.md +0 -454
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/technique-skill.md +0 -527
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/tool-skill.md +0 -366
- package/skills/testing-handbook-skills/skills/testing-handbook-generator/testing.md +0 -482
- package/skills/testing-handbook-skills/skills/wycheproof/SKILL.md +0 -533
- package/skills/video-frames/SKILL.md +0 -46
- package/skills/video-frames/scripts/frame.sh +0 -81
- package/skills/voice-call/SKILL.md +0 -45
|
@@ -1,310 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Summarize CodexBar local cost usage by model.
|
|
4
|
-
|
|
5
|
-
Defaults to current model (most recent daily entry), or list all models.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from __future__ import annotations
|
|
9
|
-
|
|
10
|
-
import argparse
|
|
11
|
-
import json
|
|
12
|
-
import os
|
|
13
|
-
import subprocess
|
|
14
|
-
import sys
|
|
15
|
-
from dataclasses import dataclass
|
|
16
|
-
from datetime import date, datetime, timedelta
|
|
17
|
-
from typing import Any, Dict, Iterable, List, Optional, Tuple
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def eprint(msg: str) -> None:
|
|
21
|
-
print(msg, file=sys.stderr)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def run_codexbar_cost(provider: str) -> List[Dict[str, Any]]:
|
|
25
|
-
cmd = ["codexbar", "cost", "--format", "json", "--provider", provider]
|
|
26
|
-
try:
|
|
27
|
-
output = subprocess.check_output(cmd, text=True)
|
|
28
|
-
except FileNotFoundError:
|
|
29
|
-
raise RuntimeError("codexbar not found on PATH. Install CodexBar CLI first.")
|
|
30
|
-
except subprocess.CalledProcessError as exc:
|
|
31
|
-
raise RuntimeError(f"codexbar cost failed (exit {exc.returncode}).")
|
|
32
|
-
try:
|
|
33
|
-
payload = json.loads(output)
|
|
34
|
-
except json.JSONDecodeError as exc:
|
|
35
|
-
raise RuntimeError(f"Failed to parse codexbar JSON output: {exc}")
|
|
36
|
-
if not isinstance(payload, list):
|
|
37
|
-
raise RuntimeError("Expected codexbar cost JSON array.")
|
|
38
|
-
return payload
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def load_payload(input_path: Optional[str], provider: str) -> Dict[str, Any]:
|
|
42
|
-
if input_path:
|
|
43
|
-
if input_path == "-":
|
|
44
|
-
raw = sys.stdin.read()
|
|
45
|
-
else:
|
|
46
|
-
with open(input_path, "r", encoding="utf-8") as handle:
|
|
47
|
-
raw = handle.read()
|
|
48
|
-
data = json.loads(raw)
|
|
49
|
-
else:
|
|
50
|
-
data = run_codexbar_cost(provider)
|
|
51
|
-
|
|
52
|
-
if isinstance(data, dict):
|
|
53
|
-
return data
|
|
54
|
-
|
|
55
|
-
if isinstance(data, list):
|
|
56
|
-
for entry in data:
|
|
57
|
-
if isinstance(entry, dict) and entry.get("provider") == provider:
|
|
58
|
-
return entry
|
|
59
|
-
raise RuntimeError(f"Provider '{provider}' not found in codexbar payload.")
|
|
60
|
-
|
|
61
|
-
raise RuntimeError("Unsupported JSON input format.")
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
@dataclass
|
|
65
|
-
class ModelCost:
|
|
66
|
-
model: str
|
|
67
|
-
cost: float
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def parse_daily_entries(payload: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
71
|
-
daily = payload.get("daily")
|
|
72
|
-
if not daily:
|
|
73
|
-
return []
|
|
74
|
-
if not isinstance(daily, list):
|
|
75
|
-
return []
|
|
76
|
-
return [entry for entry in daily if isinstance(entry, dict)]
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
def parse_date(value: str) -> Optional[date]:
|
|
80
|
-
try:
|
|
81
|
-
return datetime.strptime(value, "%Y-%m-%d").date()
|
|
82
|
-
except Exception:
|
|
83
|
-
return None
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def filter_by_days(entries: List[Dict[str, Any]], days: Optional[int]) -> List[Dict[str, Any]]:
|
|
87
|
-
if not days:
|
|
88
|
-
return entries
|
|
89
|
-
cutoff = date.today() - timedelta(days=days - 1)
|
|
90
|
-
filtered: List[Dict[str, Any]] = []
|
|
91
|
-
for entry in entries:
|
|
92
|
-
day = entry.get("date")
|
|
93
|
-
if not isinstance(day, str):
|
|
94
|
-
continue
|
|
95
|
-
parsed = parse_date(day)
|
|
96
|
-
if parsed and parsed >= cutoff:
|
|
97
|
-
filtered.append(entry)
|
|
98
|
-
return filtered
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
def aggregate_costs(entries: Iterable[Dict[str, Any]]) -> Dict[str, float]:
|
|
102
|
-
totals: Dict[str, float] = {}
|
|
103
|
-
for entry in entries:
|
|
104
|
-
breakdowns = entry.get("modelBreakdowns")
|
|
105
|
-
if not breakdowns:
|
|
106
|
-
continue
|
|
107
|
-
if not isinstance(breakdowns, list):
|
|
108
|
-
continue
|
|
109
|
-
for item in breakdowns:
|
|
110
|
-
if not isinstance(item, dict):
|
|
111
|
-
continue
|
|
112
|
-
model = item.get("modelName")
|
|
113
|
-
cost = item.get("cost")
|
|
114
|
-
if not isinstance(model, str):
|
|
115
|
-
continue
|
|
116
|
-
if not isinstance(cost, (int, float)):
|
|
117
|
-
continue
|
|
118
|
-
totals[model] = totals.get(model, 0.0) + float(cost)
|
|
119
|
-
return totals
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
def pick_current_model(entries: List[Dict[str, Any]]) -> Tuple[Optional[str], Optional[str]]:
|
|
123
|
-
if not entries:
|
|
124
|
-
return None, None
|
|
125
|
-
sorted_entries = sorted(
|
|
126
|
-
entries,
|
|
127
|
-
key=lambda entry: entry.get("date") or "",
|
|
128
|
-
)
|
|
129
|
-
for entry in reversed(sorted_entries):
|
|
130
|
-
breakdowns = entry.get("modelBreakdowns")
|
|
131
|
-
if isinstance(breakdowns, list) and breakdowns:
|
|
132
|
-
scored: List[ModelCost] = []
|
|
133
|
-
for item in breakdowns:
|
|
134
|
-
if not isinstance(item, dict):
|
|
135
|
-
continue
|
|
136
|
-
model = item.get("modelName")
|
|
137
|
-
cost = item.get("cost")
|
|
138
|
-
if isinstance(model, str) and isinstance(cost, (int, float)):
|
|
139
|
-
scored.append(ModelCost(model=model, cost=float(cost)))
|
|
140
|
-
if scored:
|
|
141
|
-
scored.sort(key=lambda item: item.cost, reverse=True)
|
|
142
|
-
return scored[0].model, entry.get("date") if isinstance(entry.get("date"), str) else None
|
|
143
|
-
models_used = entry.get("modelsUsed")
|
|
144
|
-
if isinstance(models_used, list) and models_used:
|
|
145
|
-
last = models_used[-1]
|
|
146
|
-
if isinstance(last, str):
|
|
147
|
-
return last, entry.get("date") if isinstance(entry.get("date"), str) else None
|
|
148
|
-
return None, None
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
def usd(value: Optional[float]) -> str:
|
|
152
|
-
if value is None:
|
|
153
|
-
return "—"
|
|
154
|
-
return f"${value:,.2f}"
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
def latest_day_cost(entries: List[Dict[str, Any]], model: str) -> Tuple[Optional[str], Optional[float]]:
|
|
158
|
-
if not entries:
|
|
159
|
-
return None, None
|
|
160
|
-
sorted_entries = sorted(
|
|
161
|
-
entries,
|
|
162
|
-
key=lambda entry: entry.get("date") or "",
|
|
163
|
-
)
|
|
164
|
-
for entry in reversed(sorted_entries):
|
|
165
|
-
breakdowns = entry.get("modelBreakdowns")
|
|
166
|
-
if not isinstance(breakdowns, list):
|
|
167
|
-
continue
|
|
168
|
-
for item in breakdowns:
|
|
169
|
-
if not isinstance(item, dict):
|
|
170
|
-
continue
|
|
171
|
-
if item.get("modelName") == model:
|
|
172
|
-
cost = item.get("cost") if isinstance(item.get("cost"), (int, float)) else None
|
|
173
|
-
day = entry.get("date") if isinstance(entry.get("date"), str) else None
|
|
174
|
-
return day, float(cost) if cost is not None else None
|
|
175
|
-
return None, None
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
def render_text_current(
|
|
179
|
-
provider: str,
|
|
180
|
-
model: str,
|
|
181
|
-
latest_date: Optional[str],
|
|
182
|
-
total_cost: Optional[float],
|
|
183
|
-
latest_cost: Optional[float],
|
|
184
|
-
latest_cost_date: Optional[str],
|
|
185
|
-
entry_count: int,
|
|
186
|
-
) -> str:
|
|
187
|
-
lines = [f"Provider: {provider}", f"Current model: {model}"]
|
|
188
|
-
if latest_date:
|
|
189
|
-
lines.append(f"Latest model date: {latest_date}")
|
|
190
|
-
lines.append(f"Total cost (rows): {usd(total_cost)}")
|
|
191
|
-
if latest_cost_date:
|
|
192
|
-
lines.append(f"Latest day cost: {usd(latest_cost)} ({latest_cost_date})")
|
|
193
|
-
lines.append(f"Daily rows: {entry_count}")
|
|
194
|
-
return "\n".join(lines)
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
def render_text_all(provider: str, totals: Dict[str, float]) -> str:
|
|
198
|
-
lines = [f"Provider: {provider}", "Models:"]
|
|
199
|
-
for model, cost in sorted(totals.items(), key=lambda item: item[1], reverse=True):
|
|
200
|
-
lines.append(f"- {model}: {usd(cost)}")
|
|
201
|
-
return "\n".join(lines)
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
def build_json_current(
|
|
205
|
-
provider: str,
|
|
206
|
-
model: str,
|
|
207
|
-
latest_date: Optional[str],
|
|
208
|
-
total_cost: Optional[float],
|
|
209
|
-
latest_cost: Optional[float],
|
|
210
|
-
latest_cost_date: Optional[str],
|
|
211
|
-
entry_count: int,
|
|
212
|
-
) -> Dict[str, Any]:
|
|
213
|
-
return {
|
|
214
|
-
"provider": provider,
|
|
215
|
-
"mode": "current",
|
|
216
|
-
"model": model,
|
|
217
|
-
"latestModelDate": latest_date,
|
|
218
|
-
"totalCostUSD": total_cost,
|
|
219
|
-
"latestDayCostUSD": latest_cost,
|
|
220
|
-
"latestDayCostDate": latest_cost_date,
|
|
221
|
-
"dailyRowCount": entry_count,
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
def build_json_all(provider: str, totals: Dict[str, float]) -> Dict[str, Any]:
|
|
226
|
-
return {
|
|
227
|
-
"provider": provider,
|
|
228
|
-
"mode": "all",
|
|
229
|
-
"models": [
|
|
230
|
-
{"model": model, "totalCostUSD": cost}
|
|
231
|
-
for model, cost in sorted(totals.items(), key=lambda item: item[1], reverse=True)
|
|
232
|
-
],
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
def main() -> int:
|
|
237
|
-
parser = argparse.ArgumentParser(description="Summarize CodexBar model usage from local cost logs.")
|
|
238
|
-
parser.add_argument("--provider", choices=["codex", "claude"], default="codex")
|
|
239
|
-
parser.add_argument("--mode", choices=["current", "all"], default="current")
|
|
240
|
-
parser.add_argument("--model", help="Explicit model name to report instead of auto-current.")
|
|
241
|
-
parser.add_argument("--input", help="Path to codexbar cost JSON (or '-' for stdin).")
|
|
242
|
-
parser.add_argument("--days", type=int, help="Limit to last N days (based on daily rows).")
|
|
243
|
-
parser.add_argument("--format", choices=["text", "json"], default="text")
|
|
244
|
-
parser.add_argument("--pretty", action="store_true", help="Pretty-print JSON output.")
|
|
245
|
-
|
|
246
|
-
args = parser.parse_args()
|
|
247
|
-
|
|
248
|
-
try:
|
|
249
|
-
payload = load_payload(args.input, args.provider)
|
|
250
|
-
except Exception as exc:
|
|
251
|
-
eprint(str(exc))
|
|
252
|
-
return 1
|
|
253
|
-
|
|
254
|
-
entries = parse_daily_entries(payload)
|
|
255
|
-
entries = filter_by_days(entries, args.days)
|
|
256
|
-
|
|
257
|
-
if args.mode == "current":
|
|
258
|
-
model = args.model
|
|
259
|
-
latest_date = None
|
|
260
|
-
if not model:
|
|
261
|
-
model, latest_date = pick_current_model(entries)
|
|
262
|
-
if not model:
|
|
263
|
-
eprint("No model data found in codexbar cost payload.")
|
|
264
|
-
return 2
|
|
265
|
-
totals = aggregate_costs(entries)
|
|
266
|
-
total_cost = totals.get(model)
|
|
267
|
-
latest_cost_date, latest_cost = latest_day_cost(entries, model)
|
|
268
|
-
|
|
269
|
-
if args.format == "json":
|
|
270
|
-
payload_out = build_json_current(
|
|
271
|
-
provider=args.provider,
|
|
272
|
-
model=model,
|
|
273
|
-
latest_date=latest_date,
|
|
274
|
-
total_cost=total_cost,
|
|
275
|
-
latest_cost=latest_cost,
|
|
276
|
-
latest_cost_date=latest_cost_date,
|
|
277
|
-
entry_count=len(entries),
|
|
278
|
-
)
|
|
279
|
-
indent = 2 if args.pretty else None
|
|
280
|
-
print(json.dumps(payload_out, indent=indent, sort_keys=args.pretty))
|
|
281
|
-
else:
|
|
282
|
-
print(
|
|
283
|
-
render_text_current(
|
|
284
|
-
provider=args.provider,
|
|
285
|
-
model=model,
|
|
286
|
-
latest_date=latest_date,
|
|
287
|
-
total_cost=total_cost,
|
|
288
|
-
latest_cost=latest_cost,
|
|
289
|
-
latest_cost_date=latest_cost_date,
|
|
290
|
-
entry_count=len(entries),
|
|
291
|
-
)
|
|
292
|
-
)
|
|
293
|
-
return 0
|
|
294
|
-
|
|
295
|
-
totals = aggregate_costs(entries)
|
|
296
|
-
if not totals:
|
|
297
|
-
eprint("No model breakdowns found in codexbar cost payload.")
|
|
298
|
-
return 2
|
|
299
|
-
|
|
300
|
-
if args.format == "json":
|
|
301
|
-
payload_out = build_json_all(provider=args.provider, totals=totals)
|
|
302
|
-
indent = 2 if args.pretty else None
|
|
303
|
-
print(json.dumps(payload_out, indent=indent, sort_keys=args.pretty))
|
|
304
|
-
else:
|
|
305
|
-
print(render_text_all(provider=args.provider, totals=totals))
|
|
306
|
-
return 0
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
if __name__ == "__main__":
|
|
310
|
-
raise SystemExit(main())
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: openai-image-gen
|
|
3
|
-
description: Batch-generate images via OpenAI Images API. Random prompt sampler + `index.html` gallery.
|
|
4
|
-
homepage: https://platform.openai.com/docs/api-reference/images
|
|
5
|
-
metadata:
|
|
6
|
-
{
|
|
7
|
-
"otto":
|
|
8
|
-
{
|
|
9
|
-
"emoji": "🖼️",
|
|
10
|
-
"requires": { "bins": ["python3"], "env": ["OPENAI_API_KEY"] },
|
|
11
|
-
"primaryEnv": "OPENAI_API_KEY",
|
|
12
|
-
"install":
|
|
13
|
-
[
|
|
14
|
-
{
|
|
15
|
-
"id": "python-brew",
|
|
16
|
-
"kind": "brew",
|
|
17
|
-
"formula": "python",
|
|
18
|
-
"bins": ["python3"],
|
|
19
|
-
"label": "Install Python (brew)",
|
|
20
|
-
},
|
|
21
|
-
],
|
|
22
|
-
},
|
|
23
|
-
}
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
# OpenAI Image Gen
|
|
27
|
-
|
|
28
|
-
Generate a handful of “random but structured” prompts and render them via the OpenAI Images API.
|
|
29
|
-
|
|
30
|
-
## Run
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
python3 {baseDir}/scripts/gen.py
|
|
34
|
-
open ~/Projects/tmp/openai-image-gen-*/index.html # if ~/Projects/tmp exists; else ./tmp/...
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
Useful flags:
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
# GPT image models with various options
|
|
41
|
-
python3 {baseDir}/scripts/gen.py --count 16 --model gpt-image-1
|
|
42
|
-
python3 {baseDir}/scripts/gen.py --prompt "ultra-detailed studio photo of a futuristic cityscape" --count 4
|
|
43
|
-
python3 {baseDir}/scripts/gen.py --size 1536x1024 --quality high --out-dir ./out/images
|
|
44
|
-
python3 {baseDir}/scripts/gen.py --model gpt-image-1.5 --background transparent --output-format webp
|
|
45
|
-
|
|
46
|
-
# DALL-E 3 (note: count is automatically limited to 1)
|
|
47
|
-
python3 {baseDir}/scripts/gen.py --model dall-e-3 --quality hd --size 1792x1024 --style vivid
|
|
48
|
-
python3 {baseDir}/scripts/gen.py --model dall-e-3 --style natural --prompt "serene mountain landscape"
|
|
49
|
-
|
|
50
|
-
# DALL-E 2
|
|
51
|
-
python3 {baseDir}/scripts/gen.py --model dall-e-2 --size 512x512 --count 4
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
## Model-Specific Parameters
|
|
55
|
-
|
|
56
|
-
Different models support different parameter values. The script automatically selects appropriate defaults based on the model.
|
|
57
|
-
|
|
58
|
-
### Size
|
|
59
|
-
|
|
60
|
-
- **GPT image models** (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`): `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or `auto`
|
|
61
|
-
- Default: `1024x1024`
|
|
62
|
-
- **dall-e-3**: `1024x1024`, `1792x1024`, or `1024x1792`
|
|
63
|
-
- Default: `1024x1024`
|
|
64
|
-
- **dall-e-2**: `256x256`, `512x512`, or `1024x1024`
|
|
65
|
-
- Default: `1024x1024`
|
|
66
|
-
|
|
67
|
-
### Quality
|
|
68
|
-
|
|
69
|
-
- **GPT image models**: `auto`, `high`, `medium`, or `low`
|
|
70
|
-
- Default: `high`
|
|
71
|
-
- **dall-e-3**: `hd` or `standard`
|
|
72
|
-
- Default: `standard`
|
|
73
|
-
- **dall-e-2**: `standard` only
|
|
74
|
-
- Default: `standard`
|
|
75
|
-
|
|
76
|
-
### Other Notable Differences
|
|
77
|
-
|
|
78
|
-
- **dall-e-3** only supports generating 1 image at a time (`n=1`). The script automatically limits count to 1 when using this model.
|
|
79
|
-
- **GPT image models** support additional parameters:
|
|
80
|
-
- `--background`: `transparent`, `opaque`, or `auto` (default)
|
|
81
|
-
- `--output-format`: `png` (default), `jpeg`, or `webp`
|
|
82
|
-
- Note: `stream` and `moderation` are available via API but not yet implemented in this script
|
|
83
|
-
- **dall-e-3** has a `--style` parameter: `vivid` (hyper-real, dramatic) or `natural` (more natural looking)
|
|
84
|
-
|
|
85
|
-
## Output
|
|
86
|
-
|
|
87
|
-
- `*.png`, `*.jpeg`, or `*.webp` images (output format depends on model + `--output-format`)
|
|
88
|
-
- `prompts.json` (prompt → file mapping)
|
|
89
|
-
- `index.html` (thumbnail gallery)
|
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
import argparse
|
|
3
|
-
import base64
|
|
4
|
-
import datetime as dt
|
|
5
|
-
import json
|
|
6
|
-
import os
|
|
7
|
-
import random
|
|
8
|
-
import re
|
|
9
|
-
import sys
|
|
10
|
-
import urllib.error
|
|
11
|
-
import urllib.request
|
|
12
|
-
from pathlib import Path
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def slugify(text: str) -> str:
|
|
16
|
-
text = text.lower().strip()
|
|
17
|
-
text = re.sub(r"[^a-z0-9]+", "-", text)
|
|
18
|
-
text = re.sub(r"-{2,}", "-", text).strip("-")
|
|
19
|
-
return text or "image"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def default_out_dir() -> Path:
|
|
23
|
-
now = dt.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
|
|
24
|
-
preferred = Path.home() / "Projects" / "tmp"
|
|
25
|
-
base = preferred if preferred.is_dir() else Path("./tmp")
|
|
26
|
-
base.mkdir(parents=True, exist_ok=True)
|
|
27
|
-
return base / f"openai-image-gen-{now}"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def pick_prompts(count: int) -> list[str]:
|
|
31
|
-
subjects = [
|
|
32
|
-
"a futuristic cityscape",
|
|
33
|
-
"a brutalist lighthouse",
|
|
34
|
-
"a cozy reading nook",
|
|
35
|
-
"a cyberpunk noodle shop",
|
|
36
|
-
"a Vienna street at dusk",
|
|
37
|
-
"a minimalist product photo",
|
|
38
|
-
"a surreal underwater library",
|
|
39
|
-
]
|
|
40
|
-
styles = [
|
|
41
|
-
"ultra-detailed studio photo",
|
|
42
|
-
"35mm film still",
|
|
43
|
-
"isometric illustration",
|
|
44
|
-
"editorial photography",
|
|
45
|
-
"soft watercolor",
|
|
46
|
-
"architectural render",
|
|
47
|
-
"high-contrast monochrome",
|
|
48
|
-
]
|
|
49
|
-
lighting = [
|
|
50
|
-
"golden hour",
|
|
51
|
-
"overcast soft light",
|
|
52
|
-
"neon lighting",
|
|
53
|
-
"dramatic rim light",
|
|
54
|
-
"candlelight",
|
|
55
|
-
"foggy atmosphere",
|
|
56
|
-
]
|
|
57
|
-
prompts: list[str] = []
|
|
58
|
-
for _ in range(count):
|
|
59
|
-
prompts.append(
|
|
60
|
-
f"{random.choice(styles)} of {random.choice(subjects)}, {random.choice(lighting)}"
|
|
61
|
-
)
|
|
62
|
-
return prompts
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def get_model_defaults(model: str) -> tuple[str, str]:
|
|
66
|
-
"""Return (default_size, default_quality) for the given model."""
|
|
67
|
-
if model == "dall-e-2":
|
|
68
|
-
# quality will be ignored
|
|
69
|
-
return ("1024x1024", "standard")
|
|
70
|
-
elif model == "dall-e-3":
|
|
71
|
-
return ("1024x1024", "standard")
|
|
72
|
-
else:
|
|
73
|
-
# GPT image or future models
|
|
74
|
-
return ("1024x1024", "high")
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def request_images(
|
|
78
|
-
api_key: str,
|
|
79
|
-
prompt: str,
|
|
80
|
-
model: str,
|
|
81
|
-
size: str,
|
|
82
|
-
quality: str,
|
|
83
|
-
background: str = "",
|
|
84
|
-
output_format: str = "",
|
|
85
|
-
style: str = "",
|
|
86
|
-
) -> dict:
|
|
87
|
-
url = "https://api.openai.com/v1/images/generations"
|
|
88
|
-
args = {
|
|
89
|
-
"model": model,
|
|
90
|
-
"prompt": prompt,
|
|
91
|
-
"size": size,
|
|
92
|
-
"n": 1,
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
# Quality parameter - dall-e-2 doesn't accept this parameter
|
|
96
|
-
if model != "dall-e-2":
|
|
97
|
-
args["quality"] = quality
|
|
98
|
-
|
|
99
|
-
# Note: response_format no longer supported by OpenAI Images API
|
|
100
|
-
# dall-e models now return URLs by default
|
|
101
|
-
|
|
102
|
-
if model.startswith("gpt-image"):
|
|
103
|
-
if background:
|
|
104
|
-
args["background"] = background
|
|
105
|
-
if output_format:
|
|
106
|
-
args["output_format"] = output_format
|
|
107
|
-
|
|
108
|
-
if model == "dall-e-3" and style:
|
|
109
|
-
args["style"] = style
|
|
110
|
-
|
|
111
|
-
body = json.dumps(args).encode("utf-8")
|
|
112
|
-
req = urllib.request.Request(
|
|
113
|
-
url,
|
|
114
|
-
method="POST",
|
|
115
|
-
headers={
|
|
116
|
-
"Authorization": f"Bearer {api_key}",
|
|
117
|
-
"Content-Type": "application/json",
|
|
118
|
-
},
|
|
119
|
-
data=body,
|
|
120
|
-
)
|
|
121
|
-
try:
|
|
122
|
-
with urllib.request.urlopen(req, timeout=300) as resp:
|
|
123
|
-
return json.loads(resp.read().decode("utf-8"))
|
|
124
|
-
except urllib.error.HTTPError as e:
|
|
125
|
-
payload = e.read().decode("utf-8", errors="replace")
|
|
126
|
-
raise RuntimeError(f"OpenAI Images API failed ({e.code}): {payload}") from e
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
def write_gallery(out_dir: Path, items: list[dict]) -> None:
|
|
130
|
-
thumbs = "\n".join(
|
|
131
|
-
[
|
|
132
|
-
f"""
|
|
133
|
-
<figure>
|
|
134
|
-
<a href="{it["file"]}"><img src="{it["file"]}" loading="lazy" /></a>
|
|
135
|
-
<figcaption>{it["prompt"]}</figcaption>
|
|
136
|
-
</figure>
|
|
137
|
-
""".strip()
|
|
138
|
-
for it in items
|
|
139
|
-
]
|
|
140
|
-
)
|
|
141
|
-
html = f"""<!doctype html>
|
|
142
|
-
<meta charset="utf-8" />
|
|
143
|
-
<title>openai-image-gen</title>
|
|
144
|
-
<style>
|
|
145
|
-
:root {{ color-scheme: dark; }}
|
|
146
|
-
body {{ margin: 24px; font: 14px/1.4 ui-sans-serif, system-ui; background: #0b0f14; color: #e8edf2; }}
|
|
147
|
-
h1 {{ font-size: 18px; margin: 0 0 16px; }}
|
|
148
|
-
.grid {{ display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 16px; }}
|
|
149
|
-
figure {{ margin: 0; padding: 12px; border: 1px solid #1e2a36; border-radius: 14px; background: #0f1620; }}
|
|
150
|
-
img {{ width: 100%; height: auto; border-radius: 10px; display: block; }}
|
|
151
|
-
figcaption {{ margin-top: 10px; color: #b7c2cc; }}
|
|
152
|
-
code {{ color: #9cd1ff; }}
|
|
153
|
-
</style>
|
|
154
|
-
<h1>openai-image-gen</h1>
|
|
155
|
-
<p>Output: <code>{out_dir.as_posix()}</code></p>
|
|
156
|
-
<div class="grid">
|
|
157
|
-
{thumbs}
|
|
158
|
-
</div>
|
|
159
|
-
"""
|
|
160
|
-
(out_dir / "index.html").write_text(html, encoding="utf-8")
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
def main() -> int:
|
|
164
|
-
ap = argparse.ArgumentParser(description="Generate images via OpenAI Images API.")
|
|
165
|
-
ap.add_argument("--prompt", help="Single prompt. If omitted, random prompts are generated.")
|
|
166
|
-
ap.add_argument("--count", type=int, default=8, help="How many images to generate.")
|
|
167
|
-
ap.add_argument("--model", default="gpt-image-1", help="Image model id.")
|
|
168
|
-
ap.add_argument("--size", default="", help="Image size (e.g. 1024x1024, 1536x1024). Defaults based on model if not specified.")
|
|
169
|
-
ap.add_argument("--quality", default="", help="Image quality (e.g. high, standard). Defaults based on model if not specified.")
|
|
170
|
-
ap.add_argument("--background", default="", help="Background transparency (GPT models only): transparent, opaque, or auto.")
|
|
171
|
-
ap.add_argument("--output-format", default="", help="Output format (GPT models only): png, jpeg, or webp.")
|
|
172
|
-
ap.add_argument("--style", default="", help="Image style (dall-e-3 only): vivid or natural.")
|
|
173
|
-
ap.add_argument("--out-dir", default="", help="Output directory (default: ./tmp/openai-image-gen-<ts>).")
|
|
174
|
-
args = ap.parse_args()
|
|
175
|
-
|
|
176
|
-
api_key = (os.environ.get("OPENAI_API_KEY") or "").strip()
|
|
177
|
-
if not api_key:
|
|
178
|
-
print("Missing OPENAI_API_KEY", file=sys.stderr)
|
|
179
|
-
return 2
|
|
180
|
-
|
|
181
|
-
# Apply model-specific defaults if not specified
|
|
182
|
-
default_size, default_quality = get_model_defaults(args.model)
|
|
183
|
-
size = args.size or default_size
|
|
184
|
-
quality = args.quality or default_quality
|
|
185
|
-
|
|
186
|
-
count = args.count
|
|
187
|
-
if args.model == "dall-e-3" and count > 1:
|
|
188
|
-
print(f"Warning: dall-e-3 only supports generating 1 image at a time. Reducing count from {count} to 1.", file=sys.stderr)
|
|
189
|
-
count = 1
|
|
190
|
-
|
|
191
|
-
out_dir = Path(args.out_dir).expanduser() if args.out_dir else default_out_dir()
|
|
192
|
-
out_dir.mkdir(parents=True, exist_ok=True)
|
|
193
|
-
|
|
194
|
-
prompts = [args.prompt] * count if args.prompt else pick_prompts(count)
|
|
195
|
-
|
|
196
|
-
# Determine file extension based on output format
|
|
197
|
-
if args.model.startswith("gpt-image") and args.output_format:
|
|
198
|
-
file_ext = args.output_format
|
|
199
|
-
else:
|
|
200
|
-
file_ext = "png"
|
|
201
|
-
|
|
202
|
-
items: list[dict] = []
|
|
203
|
-
for idx, prompt in enumerate(prompts, start=1):
|
|
204
|
-
print(f"[{idx}/{len(prompts)}] {prompt}")
|
|
205
|
-
res = request_images(
|
|
206
|
-
api_key,
|
|
207
|
-
prompt,
|
|
208
|
-
args.model,
|
|
209
|
-
size,
|
|
210
|
-
quality,
|
|
211
|
-
args.background,
|
|
212
|
-
args.output_format,
|
|
213
|
-
args.style,
|
|
214
|
-
)
|
|
215
|
-
data = res.get("data", [{}])[0]
|
|
216
|
-
image_b64 = data.get("b64_json")
|
|
217
|
-
image_url = data.get("url")
|
|
218
|
-
if not image_b64 and not image_url:
|
|
219
|
-
raise RuntimeError(f"Unexpected response: {json.dumps(res)[:400]}")
|
|
220
|
-
|
|
221
|
-
filename = f"{idx:03d}-{slugify(prompt)[:40]}.{file_ext}"
|
|
222
|
-
filepath = out_dir / filename
|
|
223
|
-
if image_b64:
|
|
224
|
-
filepath.write_bytes(base64.b64decode(image_b64))
|
|
225
|
-
else:
|
|
226
|
-
try:
|
|
227
|
-
urllib.request.urlretrieve(image_url, filepath)
|
|
228
|
-
except urllib.error.URLError as e:
|
|
229
|
-
raise RuntimeError(f"Failed to download image from {image_url}: {e}") from e
|
|
230
|
-
|
|
231
|
-
items.append({"prompt": prompt, "file": filename})
|
|
232
|
-
|
|
233
|
-
(out_dir / "prompts.json").write_text(json.dumps(items, indent=2), encoding="utf-8")
|
|
234
|
-
write_gallery(out_dir, items)
|
|
235
|
-
print(f"\nWrote: {(out_dir / 'index.html').as_posix()}")
|
|
236
|
-
return 0
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
if __name__ == "__main__":
|
|
240
|
-
raise SystemExit(main())
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: openai-whisper
|
|
3
|
-
description: Local speech-to-text with the Whisper CLI (no API key).
|
|
4
|
-
homepage: https://openai.com/research/whisper
|
|
5
|
-
metadata:
|
|
6
|
-
{
|
|
7
|
-
"otto":
|
|
8
|
-
{
|
|
9
|
-
"emoji": "🎙️",
|
|
10
|
-
"requires": { "bins": ["whisper"] },
|
|
11
|
-
"install":
|
|
12
|
-
[
|
|
13
|
-
{
|
|
14
|
-
"id": "brew",
|
|
15
|
-
"kind": "brew",
|
|
16
|
-
"formula": "openai-whisper",
|
|
17
|
-
"bins": ["whisper"],
|
|
18
|
-
"label": "Install OpenAI Whisper (brew)",
|
|
19
|
-
},
|
|
20
|
-
],
|
|
21
|
-
},
|
|
22
|
-
}
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
# Whisper (CLI)
|
|
26
|
-
|
|
27
|
-
Use `whisper` to transcribe audio locally.
|
|
28
|
-
|
|
29
|
-
Quick start
|
|
30
|
-
|
|
31
|
-
- `whisper /path/audio.mp3 --model medium --output_format txt --output_dir .`
|
|
32
|
-
- `whisper /path/audio.m4a --task translate --output_format srt`
|
|
33
|
-
|
|
34
|
-
Notes
|
|
35
|
-
|
|
36
|
-
- Models download to `~/.cache/whisper` on first run.
|
|
37
|
-
- `--model` defaults to `turbo` on this install.
|
|
38
|
-
- Use smaller models for speed, larger for accuracy.
|