@ohm_studio/sdk 0.1.0

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 ADDED
@@ -0,0 +1,95 @@
1
+ # @ohm_studio/sdk
2
+
3
+ OHM Studio SDK for **JavaScript / TypeScript / React** — turn voice into structured clinical JSON, FHIR-ready, multi-language. Works in the browser, Node 18+, and Next.js (server actions, route handlers, edge runtime).
4
+
5
+ > For React Native, install [`@ohm_studio/sdk-react-native`](https://www.npmjs.com/package/@ohm_studio/sdk-react-native) instead.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @ohm_studio/sdk
11
+ # or
12
+ pnpm add @ohm_studio/sdk
13
+ # or
14
+ yarn add @ohm_studio/sdk
15
+ ```
16
+
17
+ ## Quickstart
18
+
19
+ ```ts
20
+ import { OHM } from "@ohm_studio/sdk";
21
+
22
+ const ohm = new OHM({
23
+ apiKey: process.env.OHM_API_KEY!, // ohms_live_* or ohms_test_*
24
+ baseUrl: "https://api.ohm.doctor", // override for self-host
25
+ });
26
+
27
+ // Text → structured JSON
28
+ const { data } = await ohm.extract({
29
+ apiSlug: "opd-clinic",
30
+ text: transcript,
31
+ });
32
+
33
+ // Audio → structured JSON in one call
34
+ const { transcript, data } = await ohm.audio.extract({
35
+ apiSlug: "opd-clinic",
36
+ file: blob, // File / Blob / { buffer, name?, type? }
37
+ });
38
+
39
+ // Summarize free text — patient / handover / executive / progress-note
40
+ const { summary } = await ohm.summarize({
41
+ text: longConsult,
42
+ style: "patient",
43
+ maxLines: 5,
44
+ });
45
+ ```
46
+
47
+ ## React hooks
48
+
49
+ ```tsx
50
+ import { OHM } from "@ohm_studio/sdk";
51
+ import { OhmProvider, useOhmAudioExtract } from "@ohm_studio/sdk/react";
52
+
53
+ const ohm = new OHM({ apiKey: process.env.NEXT_PUBLIC_OHM_TEST_KEY });
54
+
55
+ export default function App({ children }) {
56
+ return <OhmProvider client={ohm}>{children}</OhmProvider>;
57
+ }
58
+
59
+ function Recorder() {
60
+ const { mutateAsync, data, isPending, error } = useOhmAudioExtract({
61
+ apiSlug: "opd-clinic",
62
+ });
63
+ // ...
64
+ }
65
+ ```
66
+
67
+ ## Error handling
68
+
69
+ ```ts
70
+ import {
71
+ OHMAuthError,
72
+ OHMRateLimitError,
73
+ OHMValidationError,
74
+ } from "@ohm_studio/sdk";
75
+
76
+ try {
77
+ await ohm.extract({ apiSlug: "opd", text });
78
+ } catch (e) {
79
+ if (e instanceof OHMRateLimitError) await sleep(e.retryAfterSec! * 1000);
80
+ if (e instanceof OHMAuthError) rotateKey();
81
+ if (e instanceof OHMValidationError) showFieldErrors(e.fields);
82
+ }
83
+ ```
84
+
85
+ ## Bundle size
86
+
87
+ `@ohm_studio/sdk` core ships < 25 KB gzipped. React hooks subentry adds ~3 KB. Zero polyfills for Node 18+ / modern browsers.
88
+
89
+ ## Documentation
90
+
91
+ Full reference, cookbook, and OpenAPI playground: [docs.ohm.doctor](https://docs.ohm.doctor)
92
+
93
+ ## License
94
+
95
+ MIT
@@ -0,0 +1,31 @@
1
+ import { OHMCoreClient } from "@ohm_studio/sdk-core";
2
+ import type { OHMClientOptions } from "@ohm_studio/sdk-core";
3
+ export * from "@ohm_studio/sdk-core";
4
+ /**
5
+ * OHM Studio SDK for JavaScript / TypeScript.
6
+ *
7
+ * Works in:
8
+ * - browser (uses the global `fetch` and `FormData`)
9
+ * - Node 18+ (uses native fetch)
10
+ * - Next.js (server actions, route handlers, edge runtime)
11
+ *
12
+ * For React Native, use `@ohm_studio/sdk-react-native` instead — it adapts the
13
+ * file shape and streaming transport for the RN runtime.
14
+ *
15
+ * @example
16
+ * const ohm = new OHM({ apiKey: process.env.OHM_API_KEY! });
17
+ * const { data } = await ohm.extract({
18
+ * apiSlug: "opd-clinic",
19
+ * text: transcript,
20
+ * });
21
+ */
22
+ export declare class OHM extends OHMCoreClient {
23
+ constructor(opts: OHMClientOptions);
24
+ protected runMultipart<T>(opts: {
25
+ path: string;
26
+ file: any;
27
+ fields?: Record<string, string>;
28
+ }): Promise<T>;
29
+ }
30
+ export default OHM;
31
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,cAAc,sBAAsB,CAAC;AAErC;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,GAAI,SAAQ,aAAa;gBACxB,IAAI,EAAE,gBAAgB;cAIlB,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE;QACpC,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,GAAG,CAAC;QACV,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACjC,GAAG,OAAO,CAAC,CAAC,CAAC;CAuBf;AAED,eAAe,GAAG,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,51 @@
1
+ import { OHMCoreClient } from "@ohm_studio/sdk-core";
2
+ export * from "@ohm_studio/sdk-core";
3
+ /**
4
+ * OHM Studio SDK for JavaScript / TypeScript.
5
+ *
6
+ * Works in:
7
+ * - browser (uses the global `fetch` and `FormData`)
8
+ * - Node 18+ (uses native fetch)
9
+ * - Next.js (server actions, route handlers, edge runtime)
10
+ *
11
+ * For React Native, use `@ohm_studio/sdk-react-native` instead — it adapts the
12
+ * file shape and streaming transport for the RN runtime.
13
+ *
14
+ * @example
15
+ * const ohm = new OHM({ apiKey: process.env.OHM_API_KEY! });
16
+ * const { data } = await ohm.extract({
17
+ * apiSlug: "opd-clinic",
18
+ * text: transcript,
19
+ * });
20
+ */
21
+ export class OHM extends OHMCoreClient {
22
+ constructor(opts) {
23
+ super(opts);
24
+ }
25
+ async runMultipart(opts) {
26
+ const fd = new FormData();
27
+ // Browser File / Blob, or a Node Buffer (which the user must wrap as Blob).
28
+ if (typeof File !== "undefined" && opts.file instanceof File) {
29
+ fd.append("file", opts.file);
30
+ }
31
+ else if (typeof Blob !== "undefined" && opts.file instanceof Blob) {
32
+ fd.append("file", opts.file, "audio.bin");
33
+ }
34
+ else if (opts.file && typeof opts.file === "object" && "buffer" in opts.file) {
35
+ // Node-style { buffer, name?, type? }
36
+ const blob = new Blob([opts.file.buffer], {
37
+ type: opts.file.type || "application/octet-stream",
38
+ });
39
+ fd.append("file", blob, opts.file.name || "audio.bin");
40
+ }
41
+ else {
42
+ throw new Error("Unsupported file input — pass a File, Blob, or { buffer, name?, type? }");
43
+ }
44
+ for (const [k, v] of Object.entries(opts.fields || {})) {
45
+ fd.append(k, v);
46
+ }
47
+ return this.requestRaw("POST", opts.path, { body: fd });
48
+ }
49
+ }
50
+ export default OHM;
51
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,cAAc,sBAAsB,CAAC;AAErC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,GAAI,SAAQ,aAAa;IACpC,YAAY,IAAsB;QAChC,KAAK,CAAC,IAAI,CAAC,CAAC;IACd,CAAC;IAES,KAAK,CAAC,YAAY,CAAI,IAI/B;QACC,MAAM,EAAE,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC1B,4EAA4E;QAC5E,IAAI,OAAO,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,IAAI,YAAY,IAAI,EAAE,CAAC;YAC7D,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;aAAM,IAAI,OAAO,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,IAAI,YAAY,IAAI,EAAE,CAAC;YACpE,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QAC5C,CAAC;aAAM,IAAI,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC/E,sCAAsC;YACtC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;gBACxC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,0BAA0B;aACnD,CAAC,CAAC;YACH,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,WAAW,CAAC,CAAC;QACzD,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CACb,yEAAyE,CAC1E,CAAC;QACJ,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;YACvD,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,IAAI,CAAC,UAAU,CAAI,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IAC7D,CAAC;CACF;AAED,eAAe,GAAG,CAAC"}
@@ -0,0 +1,36 @@
1
+ import { type ReactNode } from "react";
2
+ import type { AudioExtractInput, AudioExtractResult, ExtractInput, ExtractResult, SummarizeInput, SummarizeResult } from "@ohm_studio/sdk-core";
3
+ import { OHM } from "../index";
4
+ export declare function OhmProvider({ client, children, }: {
5
+ client: OHM;
6
+ children: ReactNode;
7
+ }): import("react").FunctionComponentElement<import("react").ProviderProps<OHM | null>>;
8
+ export declare function useOhmExtract<T = Record<string, unknown>>(opts: {
9
+ apiSlug: string;
10
+ }): {
11
+ mutateAsync: (input: Omit<ExtractInput, "apiSlug">) => Promise<ExtractResult<T>>;
12
+ mutate: (input: Omit<ExtractInput, "apiSlug">) => void;
13
+ reset: () => void;
14
+ data: ExtractResult<T> | null;
15
+ error: Error | null;
16
+ isPending: boolean;
17
+ };
18
+ export declare function useOhmAudioExtract<T = Record<string, unknown>>(opts: {
19
+ apiSlug: string;
20
+ }): {
21
+ mutateAsync: (input: Omit<AudioExtractInput, "apiSlug">) => Promise<AudioExtractResult<T>>;
22
+ mutate: (input: Omit<AudioExtractInput, "apiSlug">) => void;
23
+ reset: () => void;
24
+ data: AudioExtractResult<T> | null;
25
+ error: Error | null;
26
+ isPending: boolean;
27
+ };
28
+ export declare function useOhmSummarize(): {
29
+ mutateAsync: (input: SummarizeInput) => Promise<SummarizeResult>;
30
+ mutate: (input: SummarizeInput) => void;
31
+ reset: () => void;
32
+ data: SummarizeResult | null;
33
+ error: Error | null;
34
+ isPending: boolean;
35
+ };
36
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAClB,YAAY,EACZ,aAAa,EACb,cAAc,EACd,eAAe,EAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAa/B,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,QAAQ,GACT,EAAE;IACD,MAAM,EAAE,GAAG,CAAC;IACZ,QAAQ,EAAE,SAAS,CAAC;CACrB,uFAEA;AAoDD,wBAAgB,aAAa,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE;IAC/D,OAAO,EAAE,MAAM,CAAC;CACjB;;;;;WAxCQ,KAAK,GAAG,IAAI;eACR,OAAO;EA4CnB;AAED,wBAAgB,kBAAkB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE;IACpE,OAAO,EAAE,MAAM,CAAC;CACjB;;;;;WAjDQ,KAAK,GAAG,IAAI;eACR,OAAO;EAqDnB;AAED,wBAAgB,eAAe;;;;;WAxDtB,KAAK,GAAG,IAAI;eACR,OAAO;EA2DnB"}
@@ -0,0 +1,58 @@
1
+ import { createContext, createElement, useCallback, useContext, useState, } from "react";
2
+ /**
3
+ * React hooks for @ohm_studio/sdk. Mirrors `@ohm_studio/sdk-react-native/react` so a
4
+ * snippet copies cleanly between web and mobile codebases.
5
+ *
6
+ * The hooks are thin and DEPENDENCY-FREE — no TanStack Query required.
7
+ * If you'd rather use Query, the underlying `client.extract` /
8
+ * `client.audio.extract` calls slot into `useMutation` directly.
9
+ */
10
+ const OhmContext = createContext(null);
11
+ export function OhmProvider({ client, children, }) {
12
+ return createElement(OhmContext.Provider, { value: client }, children);
13
+ }
14
+ function useClient() {
15
+ const c = useContext(OhmContext);
16
+ if (!c) {
17
+ throw new Error("useOhm hooks must be wrapped in <OhmProvider client={ohm}>");
18
+ }
19
+ return c;
20
+ }
21
+ function useOhmMutation(fn) {
22
+ const client = useClient();
23
+ const [state, setState] = useState({
24
+ data: null,
25
+ error: null,
26
+ isPending: false,
27
+ });
28
+ const mutateAsync = useCallback(async (input) => {
29
+ setState({ data: null, error: null, isPending: true });
30
+ try {
31
+ const data = await fn(client, input);
32
+ setState({ data, error: null, isPending: false });
33
+ return data;
34
+ }
35
+ catch (err) {
36
+ setState({ data: null, error: err, isPending: false });
37
+ throw err;
38
+ }
39
+ }, [client, fn]);
40
+ return {
41
+ ...state,
42
+ mutateAsync,
43
+ mutate: (input) => {
44
+ void mutateAsync(input);
45
+ },
46
+ reset: () => setState({ data: null, error: null, isPending: false }),
47
+ };
48
+ }
49
+ export function useOhmExtract(opts) {
50
+ return useOhmMutation((c, input) => c.extract({ ...input, apiSlug: opts.apiSlug }));
51
+ }
52
+ export function useOhmAudioExtract(opts) {
53
+ return useOhmMutation((c, input) => c.audio.extract({ ...input, apiSlug: opts.apiSlug }));
54
+ }
55
+ export function useOhmSummarize() {
56
+ return useOhmMutation((c, input) => c.summarize(input));
57
+ }
58
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,aAAa,EACb,WAAW,EACX,UAAU,EACV,QAAQ,GAET,MAAM,OAAO,CAAC;AAWf;;;;;;;GAOG;AAEH,MAAM,UAAU,GAAG,aAAa,CAAa,IAAI,CAAC,CAAC;AAEnD,MAAM,UAAU,WAAW,CAAC,EAC1B,MAAM,EACN,QAAQ,GAIT;IACC,OAAO,aAAa,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,QAAQ,CAAC,CAAC;AACzE,CAAC;AAED,SAAS,SAAS;IAChB,MAAM,CAAC,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IACjC,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,IAAI,KAAK,CACb,4DAA4D,CAC7D,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAQD,SAAS,cAAc,CACrB,EAAoD;IAEpD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAyB;QACzD,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,IAAI;QACX,SAAS,EAAE,KAAK;KACjB,CAAC,CAAC;IACH,MAAM,WAAW,GAAG,WAAW,CAC7B,KAAK,EAAE,KAAa,EAAE,EAAE;QACtB,QAAQ,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvD,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YACrC,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;YAClD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,QAAQ,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;YACvD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC,EACD,CAAC,MAAM,EAAE,EAAE,CAAC,CACb,CAAC;IACF,OAAO;QACL,GAAG,KAAK;QACR,WAAW;QACX,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACxB,KAAK,WAAW,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;QACD,KAAK,EAAE,GAAG,EAAE,CACV,QAAQ,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;KAC1D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAA8B,IAE1D;IACC,OAAO,cAAc,CAGnB,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAI,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,kBAAkB,CAA8B,IAE/D;IACC,OAAO,cAAc,CAGnB,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAI,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,cAAc,CAAkC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAClE,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CACnB,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@ohm_studio/sdk",
3
+ "version": "0.1.0",
4
+ "description": "OHM Studio SDK for JavaScript / TypeScript / React. Voice-to-structured-JSON clinical extraction APIs.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js"
14
+ },
15
+ "./react": {
16
+ "types": "./dist/react/index.d.ts",
17
+ "import": "./dist/react/index.js"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "README.md"
23
+ ],
24
+ "keywords": [
25
+ "ohm",
26
+ "clinical",
27
+ "ehr",
28
+ "fhir",
29
+ "stt",
30
+ "extraction",
31
+ "ai",
32
+ "llm",
33
+ "react"
34
+ ],
35
+ "homepage": "https://docs.ohm.doctor",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/aivfkesavan/OHM_Products",
39
+ "directory": "packages/sdk-js"
40
+ },
41
+ "publishConfig": {
42
+ "access": "public"
43
+ },
44
+ "dependencies": {
45
+ "@ohm_studio/sdk-core": "0.1.0"
46
+ },
47
+ "peerDependencies": {
48
+ "react": ">=17"
49
+ },
50
+ "peerDependenciesMeta": {
51
+ "react": {
52
+ "optional": true
53
+ }
54
+ },
55
+ "devDependencies": {
56
+ "@types/react": "^18.3.23",
57
+ "react": "^18.3.1",
58
+ "typescript": "^5.8.3"
59
+ },
60
+ "scripts": {
61
+ "build": "tsc -p tsconfig.json",
62
+ "typecheck": "tsc -p tsconfig.json --noEmit"
63
+ }
64
+ }