tune-sdk 0.1.11 → 0.1.13

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/bin/cli.js CHANGED
@@ -1,115 +1,133 @@
1
- #!/usr/bin/env node
1
+ var tune, rpc;
2
2
 
3
- // Minimal inline argument parser
4
- const args = {};
5
- let currentKey = null;
6
-
7
- process.argv.slice(2).forEach(arg => {
8
- if (arg.startsWith('--')) {
9
- const [key, value] = arg.substring(2).split('=');
10
- if (typeof value !== 'undefined') {
11
- args[key] = value;
12
- currentKey = null;
3
+ function parseArgs(args) {
4
+ var curKey, res, res1, key, value, _ref, _len;
5
+ var curKey;
6
+ curKey = null;
7
+ var res;
8
+ res = args.reduce((function(memo, arg) {
9
+ var key, value, _ref, _i;
10
+ if (arg.startsWith("--")) {
11
+ _ref = arg.substring(2)
12
+ .split("=");
13
+ key = _ref[0];
14
+ value = _ref[1];
15
+ if (!!value) {
16
+ memo[key] = value;
17
+ curKey = null;
18
+ } else {
19
+ curKey = key;
20
+ memo[key] = true;
21
+ }
22
+ } else if (curKey) {
23
+ memo[curKey] = arg;
24
+ curKey = null;
25
+ }
26
+ return memo;
27
+ }), {});
28
+ var res1;
29
+ res1 = {};
30
+ _ref = res;
31
+ for (key in _ref) {
32
+ value = _ref[key];
33
+ if (key.startsWith("set-")) {
34
+ res1.params = res1.params || {}
35
+ res1.params[key.substr(4)] = value;
13
36
  } else {
14
- currentKey = key;
15
- args[currentKey] = true
37
+ res1[key] = value;
16
38
  }
17
- } else if (currentKey) {
18
- args[currentKey] = arg;
19
- currentKey = null;
20
39
  }
21
- });
22
-
23
- const tune = require('../dist/tune.js');
24
- const { fsctx } = require('../dist/fsctx.js');
25
- const fs = require("fs");
26
- const path = require("path");
27
-
40
+ return res1;
41
+ }
42
+ parseArgs;
43
+ tune = require("../dist/tune.js");
44
+ rpc = require("../dist/rpc.js");
45
+ async function rpc(args, ctx) {
46
+ var server;
47
+ var server;
48
+ return (server = jsonrpc());
49
+ }
50
+ rpc;
51
+ async function run(args, ctx) {
52
+ var stopVal, params;
53
+ var stopVal;
54
+ stopVal = args.stop || "assistant";
55
+ if ((stopVal !== "step" && stopVal !== "assistant")) stopVal = (function(msgs) {
56
+ var lastMsg;
57
+ if (!msgs.length) return false;
58
+ var lastMsg;
59
+ lastMsg = msgs["slice"](-1)[0];
60
+ if (!lastMsg.content) return false;
61
+ return (-1 !== lastMsg.content.inexOf(args.stop || "assistant"));
62
+ });
63
+ var params;
64
+ params = args.params;
65
+ delete args.params;
66
+ return ctx.file2run(args, params);
67
+ }
68
+ run;
28
69
  async function main() {
29
- try {
30
- let chat = ""
31
- // where to search for inclusions
32
- let dirs = [];
33
-
34
- if (args.filename && fs.existsSync(args.filename)) {
35
- chat = fs.readFileSync(args.filename, "utf8")
36
- dirs.push(path.dirname(path.resolve(args.filename)))
37
- }
38
-
39
- if (!chat && args.system) {
40
- chat = `system:\n${args.system}`
41
- }
42
-
43
- if (args.user) {
44
- chat = `${chat}\nuser:\n${args.user}`
45
- }
46
-
47
- if(process.env.TUNE_PATH) {
48
- dirs = dirs.concat(process.env.TUNE_PATH.split(path.delimiter))
49
- }
50
-
51
- dirs.push(process.cwd())
52
-
53
- const ctx = tune.makeContext(process.env)
54
- if (args.filename) {
55
- ctx.stack.push({
56
- filename: args.filename,
57
- name: path.basename(args.filename),
58
- dirname: path.dirname(path.resolve(args.filename))
59
- })
70
+ var dirs, args, ctx, dir, ctxName, ext, module, m, _i, _res, _ref, _len, _ref0, _i0, _res0, _ref1, _len0, _ref2;
71
+ var dirs;
72
+ var args;
73
+ dirs = [];
74
+ args = parseArgs(process.argv.slice(2));
75
+ if (args.path) {
76
+ dirs = args.path.split(path.delimiter);
77
+ } else {
78
+ if (process.env.TUNE_PATH) dirs = process.env.TUNE_PATH.split(path.delimiter);
79
+ dirs.push(process.cwd());
80
+ }
81
+ ctx = tune.makeContext(process.env);
82
+ _res = [];
83
+ _ref = dirs;
84
+ for (_i = 0, _len = _ref.length; _i < _len; ++_i) {
85
+ dir = _ref[_i];
86
+ var ctxName;
87
+ ctxName = ["default.ctx.js", "default.ctx.cjs", "default.ctx.mjs"]
88
+ .map((function(name) {
89
+ return path.join(dir, name);
90
+ }))
91
+ .find((function(name) {
92
+ return fs.existsSync(name);
93
+ }));
94
+ if (!ctxName) continue;
95
+ var ext;
96
+ var module;
97
+ ext = path.extname(filename);
98
+ module = null;
99
+ if ((ext === ".js" || ext === ".cjs")) {
100
+ module = require(ctxName);
101
+ } else {
102
+ module = await import(ctxName);
103
+ module = module.default;
60
104
  }
61
- ctx.use(fsctx(dirs))
62
-
63
- for (const dir of dirs) {
64
- let filename = ["default.ctx.js", "default.ctx.cjs", "default.ctx.mjs"].find(name => fs.existsSync(path.join(dir, name)));
65
- if (!filename) continue;
66
- filename = path.join(dir, filename);
67
- let ext = path.extname(filename);
68
- let module
69
- if ((ext === ".js" || ext === ".cjs")) {
70
- module = require(filename);
71
- } else {
72
- module = await import(filename);
73
- module = module.default;
74
- }
75
- if (typeof module === "function") {
76
- ctx.use(module);
77
- } else if (Array.isArray(module)) {
78
- for (const m of module) {
79
- if (typeof m === "function") {
80
- ctx.use(m)
81
- } else {
82
- throw(Error(`err: Context file export is not an array of functions or function ${filename}`))
83
- }
105
+ if ((typeof module === "function")) {
106
+ _ref0 = ctx.use(module);
107
+ } else if (Array.isArray(module)) {
108
+ _res0 = [];
109
+ _ref1 = module;
110
+ for (_i0 = 0, _len0 = _ref1.length; _i0 < _len0; ++_i0) {
111
+ m = _ref1[_i0];
112
+ if ((typeof m === "function")) {
113
+ _ref2 = ctx.use(module);
114
+ } else {
115
+ _ref2 = undefined;
116
+ throw Error(tpl("err: Context file export is not an array of functions or function {}", ctxName));
84
117
  }
85
- } else {
86
- throw(Error(`err: Context file export is not an array of functions or function ${filename}`))
118
+ if (typeof _ref2 !== 'undefined') _res0.push(_ref2);
87
119
  }
120
+ _ref0 = _res0;
121
+ } else {
122
+ _ref0 = undefined;
123
+ throw Error(tpl("err: Context file export is not an array of functions or function {}", ctxName));
88
124
  }
89
- let stopVal = args.stop || "assistant";
90
- if (stopVal !== "step" && stopVal != "assistant") {
91
- stopVal = function(msgs) {
92
- if (!msgs.length) return false
93
- const lastMsg = msgs[msgs.length - 1]
94
- if (!lastMsg.content) return false
95
- return (lastMsg.content.indexOf(args.stop) !== -1)
96
- }
97
- }
98
-
99
- let res = await tune.text2run(chat, ctx, { stop: stopVal })
100
-
101
- const longFormatRegex = /^(system|user|tool_call|tool_result|assistant|error):/;
102
- res = tune.msg2text(res, longFormatRegex.test(chat))
103
- if (args.filename && args.save) {
104
- chat += "\n" + res
105
- fs.writeFileSync(args.filename, chat)
106
- }
107
- if (!args.save) {
108
- console.log(res)
109
- }
110
- } catch (e) {
111
- console.error(e)
125
+ if (typeof _ref0 !== 'undefined') _res.push(_ref0);
112
126
  }
127
+ return _res;
113
128
  }
114
-
115
- main()
129
+ main;
130
+ exports.parseArgs = parseArgs;
131
+ exports.rpc = rpc;
132
+ exports.main = main;
133
+ exports.run = run;
package/dist/fsctx.js CHANGED
@@ -1,4 +1,4 @@
1
- var path, tune, envmd, TuneError, text2run, file2run;
1
+ var path, tune, fs, envmd, TuneError, text2run, file2run;
2
2
 
3
3
  function extend() {
4
4
  var _i;
@@ -616,6 +616,7 @@ if (typeof window !== "undefined") {
616
616
  }
617
617
  path = require("path");
618
618
  tune = require("./tune");
619
+ fs = require("fs");
619
620
  envmd = tune.envmd;
620
621
  TuneError = tune.TuneError;
621
622
  text2run = tune.text2run;
@@ -1062,6 +1063,53 @@ function fsMix(paths, opts, fs) {
1062
1063
  });
1063
1064
  }
1064
1065
  fsMix;
1066
+ async function curFile(name, params) {
1067
+ var filename, value, _ref;
1068
+ if ((!this.stack || !this.stack.length)) return;
1069
+ filename = this.stack[0].filename;
1070
+ switch (name) {
1071
+ case "__filename":
1072
+ _ref = filename;
1073
+ break;
1074
+ case "__dirname":
1075
+ _ref = path.dirname(filename);
1076
+ break;
1077
+ case "__basename":
1078
+ _ref = path.basename(filename);
1079
+ break;
1080
+ case "__name":
1081
+ _ref = path.parse(filename).name;
1082
+ break;
1083
+ case "__ext":
1084
+ _ref = path.parse(filename).ext;
1085
+ break;
1086
+ default:
1087
+ _ref = undefined;
1088
+ }
1089
+ value = _ref;
1090
+ return (value ? {
1091
+ type: "text",
1092
+ read: (async function() {
1093
+ return value;
1094
+ })
1095
+ } : undefined);
1096
+ }
1097
+ curFile;
1098
+
1099
+ function defaultWrite(opts) {
1100
+ async function write(filename, data) {
1101
+ var directory;
1102
+ var directory;
1103
+ directory = path.dirname(filename);
1104
+ fs.mkdirSync(directory, {
1105
+ recursive: true
1106
+ });
1107
+ fs.writeFileSync(filename, data);
1108
+ return true;
1109
+ }
1110
+ return write;
1111
+ }
1112
+ defaultWrite;
1065
1113
 
1066
1114
  function tpl(str) {
1067
1115
  var _i;
@@ -1086,4 +1134,6 @@ exports.runFile = runFile;
1086
1134
  exports.fsMix = fsMix;
1087
1135
  exports.fsMod = fsMod;
1088
1136
  exports.fsText = fsText;
1137
+ exports.defaultWrite = defaultWrite;
1138
+ exports.curFile = curFile;
1089
1139
  exports.pparse = pparse;
package/dist/rpc.js ADDED
@@ -0,0 +1,211 @@
1
+ function AsyncIter() {
2
+ return (this[Symbol.asyncIterator] = this);
3
+ }
4
+ AsyncIter;
5
+ AsyncIter.prototype.next = (async function() {
6
+ var self, result;
7
+ var self;
8
+ self = this;
9
+ await _once((function() {
10
+ return (!!self.err || !!self.result);
11
+ }), (function() {
12
+ return undefined;
13
+ }));
14
+ var result;
15
+ result = self.result;
16
+ self.result = undefined;
17
+ if (self.err) throw self.err;
18
+ return result;
19
+ });
20
+
21
+ function jsonrpc(params, exports) {
22
+ var client;
23
+ var client;
24
+ client = new JSONRPC(params, exports);
25
+ return new Proxy({}, {
26
+ get: (function(target, prop, receiver) {
27
+ return (function(params, stream) {
28
+ return client._call(prop, params, stream);
29
+ });
30
+ }),
31
+ set: (function(obj, prop, value) {
32
+ return (client[prop] = value);
33
+ })
34
+ });
35
+ }
36
+ jsonrpc;
37
+
38
+ function concatU8A(u8arrays) {
39
+ var totalLen, res, offset, arr, _i, _ref, _len;
40
+ var totalLen;
41
+ var res;
42
+ var offset;
43
+ totalLen = u8arrays.reduce((function(acc, arr) {
44
+ return (acc + arr.length);
45
+ }), 0);
46
+ res = new Uint8Array(totalLen);
47
+ offset = 0;
48
+ _ref = u8arrays;
49
+ for (_i = 0, _len = _ref.length; _i < _len; ++_i) {
50
+ arr = _ref[_i];
51
+ res.set(arr, offset);
52
+ offset = offset + arr.length;
53
+ }
54
+ return res;
55
+ }
56
+ concatU8A;
57
+
58
+ function JSONRPC(params, exports) {
59
+ var self;
60
+ this.msgId = 1;
61
+ this.chunks = [];
62
+ this.debug = params.debug;
63
+ this.name = params.name;
64
+ this.exports = exports || params.exports || {}
65
+ this.callbacks = {};
66
+ this.iterators = {};
67
+ this.reader = params.inStream.getReader();
68
+ this.writer = params.outStream.getWriter();
69
+ self = this;
70
+ this.decoder = new TextDecoder();
71
+ assert.ok(params.inStream, "inStream has to be defined and be a ReadableStream");
72
+ assert.ok(params.outStream, "outStream has to be defined and be a WritableStream");
73
+ async function pump() {
74
+ var res, value, done, buf, newlineIdx, line, msg, cb, iter, err, m, r, chunk, _res, _ref, _ref0;
75
+ var res;
76
+ res = await self.reader.read();
77
+ var value;
78
+ var done;
79
+ value = res.value;
80
+ done = res.done;
81
+ if (done) return;
82
+ self.chunks.push(value);
83
+ var buf;
84
+ var newlineIdx;
85
+ buf = concatU8A(self.chunks);
86
+ newlineIdx = 0;
87
+ while (-1 !== (newlineIdx = buf.indexOf(10))) {
88
+ var line;
89
+ line = self.decoder.decode(buf.subarray(0, newlineIdx));
90
+ buf = buf.subarray(newlineIdx + 1);
91
+ self.chunks = [buf];
92
+ if (self.debug) console.log(self.name, line);
93
+ var msg;
94
+ msg = JSON.parse(line);
95
+ if (!msg.id) {
96
+ console.log("message has no id, skipping", msg);
97
+ continue;
98
+ }
99
+ var cb;
100
+ var iter;
101
+ cb = self.callbacks[msg.id];
102
+ iter = self.iterators[msg.id];
103
+ if (((cb || iter) && (((typeof msg !== 'undefined') && (typeof msg.result !== 'undefined')) || msg.error))) {
104
+ if ((cb && ((typeof msg !== 'undefined') && (typeof msg.result !== 'undefined')))) {
105
+ cb.resolve(msg.result);
106
+ } else if (iter && ((typeof msg !== 'undefined') && (typeof msg.result !== 'undefined'))) {
107
+ iter.result = {
108
+ value: msg.result
109
+ };
110
+ if (msg.done) {
111
+ iter.result.done = true;
112
+ delete self.iterators[msg.id];
113
+ }
114
+ } else if (cb && msg.error) {
115
+ var err;
116
+ err = new Error(msg.error.message);
117
+ err.stack = msg.error.stack;
118
+ cb.reject(err);
119
+ } else if (iter && msg.error) {
120
+ iter.err = new Error(msg.error.message);
121
+ iter.err.stack = msg.error.stack;
122
+ }
123
+ if (cb) delete self.callbacks[msg.id];
124
+ } else if (msg.method) {
125
+ if (!self.exports[msg.method]) {
126
+ self._error(msg.id, "method not found: " + msg.method);
127
+ continue;
128
+ }
129
+ var m;
130
+ var r;
131
+ var chunk;
132
+ m = msg;
133
+ r = undefined;
134
+ chunk = {};
135
+ try {
136
+ r = await self.exports[m.method](msg.params, msg.stream);
137
+ if (((typeof r !== 'undefined') && !!r[Symbol.asyncIterator])) {
138
+ _res = [];
139
+ while (!chunk.done) {
140
+ chunk = await r.next();
141
+ if (chunk.err) throw chunk.err;
142
+ if (typeof(_ref = !!chunk.value ? self._result(m.id, chunk.value, chunk.done) : undefined) !== 'undefined') _res.push(_ref);
143
+ }
144
+ _ref0 = _res;
145
+ } else {
146
+ _ref0 = self._result(m.id, r, true);
147
+ }
148
+ _ref0;
149
+ } catch (e) {
150
+ self._error(m.id, e.message, e.stack);
151
+ }
152
+ }
153
+ }
154
+ return pump();
155
+ }
156
+ pump;
157
+ pump();
158
+ return this;
159
+ }
160
+ JSONRPC;
161
+ JSONRPC.prototype._write = (async function(payload) {
162
+ var encoder, data;
163
+ var encoder;
164
+ var data;
165
+ encoder = new TextEncoder();
166
+ data = encoder.encode(JSON.stringify(payload) + "\n");
167
+ return await this.writer.write(data);
168
+ });
169
+ JSONRPC.prototype._error = (function(msgId, message, stack) {
170
+ return this._write({
171
+ jsonrpc: "2.0",
172
+ id: msgId,
173
+ error: {
174
+ message: message,
175
+ stack: stack
176
+ }
177
+ });
178
+ });
179
+ JSONRPC.prototype._result = (function(msgId, result, done) {
180
+ return (function(self, payload) {
181
+ if (done) payload.done = true;
182
+ return self._write(payload);
183
+ })(this, {
184
+ jsonrpc: "2.0",
185
+ id: msgId,
186
+ result: ((typeof result !== 'undefined') ? result : null)
187
+ });
188
+ });
189
+ JSONRPC.prototype._call = (async function(method, params, stream) {
190
+ var self, msgId;
191
+ var self;
192
+ var msgId;
193
+ self = this;
194
+ msgId = self.msgId;
195
+ self.msgId++;
196
+ self._write({
197
+ jsonrpc: "2.0",
198
+ id: msgId,
199
+ method: method,
200
+ params: params,
201
+ stream: stream
202
+ });
203
+ if (!stream) return new Promise((function(resolve, reject) {
204
+ return (self.callbacks[msgId] = {
205
+ resolve: resolve,
206
+ reject: reject
207
+ });
208
+ }));
209
+ return (self.iterators[msgId] = new AsyncIter());
210
+ });
211
+ exports.jsonrpc = jsonrpc;
package/dist/tune.js CHANGED
@@ -2099,12 +2099,12 @@ function text2run(text, ctx, opts) {
2099
2099
  }
2100
2100
  text2run;
2101
2101
  async function file2run(args, params, ctx) {
2102
- var lctx, text, node, res, longFormatRegex, response, _ref;
2102
+ var lctx, uext, node, text, res, longFormatRegex, response, _ref;
2103
2103
  var lctx;
2104
2104
  lctx = ctx.clone();
2105
2105
  lctx.ms.unshift(envmd(params));
2106
- var text;
2107
- text = "";
2106
+ var uext;
2107
+ uext = "";
2108
2108
  if (args.filename) {
2109
2109
  node = await ctx.resolve(args.filename);
2110
2110
  if (node) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tune-sdk",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "tune - your everyday LLM toolkit.",
5
5
  "main": "dist/tune.js",
6
6
  "module": "dist/tune.mjs",
@@ -9,6 +9,9 @@
9
9
  ".": {
10
10
  "require": "./dist/tune.js",
11
11
  "import": "./dist/tune.mjs"
12
+ },
13
+ "./fsctx": {
14
+ "require": "./dist/fsctx.js"
12
15
  }
13
16
  },
14
17
  "keywords": [
@@ -1,51 +1,20 @@
1
1
  const fs = require('fs')
2
2
  const path = require('path')
3
3
 
4
- const { runFile, fsMix } = require("../dist/fsctx.js");
4
+ const { curFile, fsMix, defaultWrite } = require("../dist/fsctx.js");
5
+ const { file2run, makeContext } = require("../dist/tune.js");
5
6
 
6
7
  async function makeSchema(params, ctx) {
7
- return runFile(path.join(__dirname, "schema.tool.chat"), ctx, params);
8
+ return file2run({ filename: path.join(__dirname, "schema.tool.chat")}, params, ctx);
8
9
  }
9
10
  let dirs = [];
10
11
  if (process.env.TUNE_PATH) {
11
12
  dirs = process.env.TUNE_PATH.split(path.delimiter);
12
13
  }
13
-
14
+ console.log(defaultWrite())
14
15
 
15
16
  module.exports = [
16
- async function filename(name, params) {
17
- if (!this.stack || !this.stack.length) {
18
- return
19
- }
20
- const { filename } = this.stack[0];
21
- let value
22
- switch(name) {
23
- case "__filename":
24
- value = filename
25
- break
26
- case "__dirname":
27
- value = path.dirname(filename)
28
- break
29
- case "__basename":
30
- value = path.basename(filename)
31
- break
32
- case "__name":
33
- value = path.parse(filename).name
34
- break
35
- case "__ext":
36
- value = path.parse(filename).ext
37
- break
38
- default:
39
- break
40
- }
41
- if (value) {
42
- return {
43
- type: "text",
44
- read: async () => value
45
- }
46
- }
47
- return
48
- },
17
+ curFile,
49
18
  fsMix(dirs, { makeSchema }),
50
19
  require("./openai.ctx.js"),
51
20
  require("./openrouter.ctx.js"),
@@ -53,9 +22,5 @@ module.exports = [
53
22
  require("./gemini.ctx.js"),
54
23
  require("./mistral.ctx.js"),
55
24
  require("./groq.ctx.js"),
56
- async function write(filename, data) {
57
- const directory = path.dirname(filename);
58
- fs.mkdirSync(directory, { recursive: true });
59
- fs.writeFileSync(filename, data)
60
- }
61
- ];
25
+ defaultWrite()
26
+ ]
@@ -0,0 +1,48 @@
1
+ {
2
+ "description": "Transcribe audio using Groq Whisper API",
3
+ "parameters": {
4
+ "type": "object",
5
+ "properties": {
6
+ "file": {
7
+ "type": "string",
8
+ "description": "Path to the audio file to transcribe"
9
+ },
10
+ "url": {
11
+ "type": "string",
12
+ "description": "URL of the audio file to transcribe"
13
+ },
14
+ "model": {
15
+ "type": "string",
16
+ "description": "Model to use for transcription",
17
+ "default": "whisper-large-v3-turbo"
18
+ },
19
+ "language": {
20
+ "type": "string",
21
+ "description": "Language spoken in the audio"
22
+ },
23
+ "text": {
24
+ "type": "string",
25
+ "description": "Optional text prompt to guide transcription"
26
+ },
27
+ "response_format": {
28
+ "type": "string",
29
+ "description": "Format of the transcription response",
30
+ "enum": ["json", "verbose_json", "text"],
31
+ "default": "json"
32
+ },
33
+ "temperature": {
34
+ "type": "number",
35
+ "description": "Sampling temperature for transcription",
36
+ "default": 0
37
+ },
38
+ "timestamp_granularities": {
39
+ "type": "array",
40
+ "items": {
41
+ "type": "string"
42
+ },
43
+ "description": "Timestamp granularities to include if response_format is verbose_json",
44
+ "default": ["segment"]
45
+ }
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,59 @@
1
+ import fs from 'fs';
2
+
3
+ export default async function groqWhisper({
4
+ file,
5
+ url,
6
+ model = "whisper-large-v3-turbo",
7
+ language,
8
+ text,
9
+ response_format = "json",
10
+ temperature = 0,
11
+ timestamp_granularities = ["segment"]
12
+ }, ctx) {
13
+ const key = await ctx.read("GROQ_KEY");
14
+
15
+ const formData = new FormData();
16
+
17
+ // Add file or url
18
+ if (file) {
19
+ if (!fs.existsSync(file)) {
20
+ return "file not found"
21
+ }
22
+ const fileBlob = await fs.openAsBlob(file);
23
+ formData.append('file', fileBlob, file);
24
+ } else if (url) {
25
+ formData.append('url', url);
26
+ } else {
27
+ throw new Error('Either file or url parameter is required');
28
+ }
29
+
30
+ // Add required model
31
+ formData.append('model', model);
32
+
33
+ // Add optional parameters
34
+ if (language) formData.append('language', language);
35
+ if (text) formData.append('prompt', text);
36
+ if (response_format) formData.append('response_format', response_format);
37
+ if (temperature !== undefined) formData.append('temperature', temperature.toString());
38
+ if (timestamp_granularities && response_format === 'verbose_json') {
39
+ timestamp_granularities.forEach(granularity => {
40
+ formData.append('timestamp_granularities[]', granularity);
41
+ });
42
+ }
43
+
44
+ const response = await fetch("https://api.groq.com/openai/v1/audio/transcriptions", {
45
+ method: "POST",
46
+ headers: {
47
+ "Authorization": `Bearer ${key}`,
48
+ },
49
+ body: formData,
50
+ });
51
+
52
+ if (!response.ok) {
53
+ const errorText = await response.text();
54
+ throw new Error(`Error: ${response.status} ${response.statusText}\n${errorText}`);
55
+ }
56
+
57
+ const result = await response.json();
58
+ return result;
59
+ }
@@ -0,0 +1,49 @@
1
+ {
2
+ "description": "Convert audio file to text using OpenAI's transcription API with advanced options",
3
+ "parameters": {
4
+ "type": "object",
5
+ "properties": {
6
+ "file": {
7
+ "type": "string",
8
+ "description": "Path or identifier of the audio file to transcribe"
9
+ },
10
+ "model": {
11
+ "type": "string",
12
+ "description": "Model to use for transcription",
13
+ "default": "gpt-4o-transcribe"
14
+ },
15
+ "language": {
16
+ "type": "string",
17
+ "description": "Language spoken in the audio, optional"
18
+ },
19
+ "prompt": {
20
+ "type": "string",
21
+ "description": "Prompt to guide transcription, optional"
22
+ },
23
+ "response_format": {
24
+ "type": "string",
25
+ "enum": ["json", "verbose_json", "text"],
26
+ "description": "Format of the transcription response",
27
+ "default": "json"
28
+ },
29
+ "temperature": {
30
+ "type": "number",
31
+ "description": "Sampling temperature for transcription",
32
+ "default": 0
33
+ },
34
+ "timestamp_granularities": {
35
+ "type": "array",
36
+ "items": {
37
+ "type": "string"
38
+ },
39
+ "description": "Timestamp granularities for detailed transcription, supported only for whisper-1 model with verbose_json response_format"
40
+ },
41
+ "stream": {
42
+ "type": "boolean",
43
+ "description": "Whether to return a streaming response",
44
+ "default": false
45
+ }
46
+ },
47
+ "required": ["file"]
48
+ }
49
+ }
@@ -0,0 +1,66 @@
1
+ import fs from 'fs';
2
+
3
+ export default async function openaiSTT({
4
+ file,
5
+ model = "gpt-4o-transcribe",
6
+ language,
7
+ prompt,
8
+ response_format = "json",
9
+ temperature = 0,
10
+ timestamp_granularities,
11
+ stream = false
12
+ }, ctx) {
13
+ const key = await ctx.read("OPENAI_KEY");
14
+
15
+ if (!file) {
16
+ throw new Error('File parameter is required');
17
+ }
18
+
19
+ const formData = new FormData();
20
+
21
+ // Add file
22
+ const fileBlob = await fs.openAsBlob(file);
23
+ formData.append('file', fileBlob, file);
24
+
25
+ // Add required model
26
+ formData.append('model', model);
27
+
28
+ // Add optional parameters
29
+ if (language) formData.append('language', language);
30
+ if (prompt) formData.append('prompt', prompt);
31
+ if (response_format) formData.append('response_format', response_format);
32
+ if (temperature !== undefined) formData.append('temperature', temperature.toString());
33
+ if (stream) formData.append('stream', stream.toString());
34
+
35
+ // Timestamp granularities (only supported for whisper-1 with verbose_json)
36
+ if (timestamp_granularities && model === 'whisper-1' && response_format === 'verbose_json') {
37
+ timestamp_granularities.forEach(granularity => {
38
+ formData.append('timestamp_granularities[]', granularity);
39
+ });
40
+ }
41
+
42
+ const response = await fetch("https://api.openai.com/v1/audio/transcriptions", {
43
+ method: "POST",
44
+ headers: {
45
+ "Authorization": `Bearer ${key}`,
46
+ },
47
+ body: formData,
48
+ });
49
+
50
+ if (!response.ok) {
51
+ const errorText = await response.text();
52
+ throw new Error(`Error: ${response.status} ${response.statusText}\n${errorText}`);
53
+ }
54
+
55
+ if (stream) {
56
+ // For streaming responses, return the response stream
57
+ return response.body;
58
+ } else {
59
+ // For non-streaming responses, parse JSON or return text based on response_format
60
+ if (response_format === 'text') {
61
+ return await response.text();
62
+ } else {
63
+ return await response.json();
64
+ }
65
+ }
66
+ }