@epfml/discojs-web 3.0.1-p20240821133014.0 → 3.0.1-p20240826092658.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/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export * from './data/index.js';
2
- export * from './memory/index.js';
1
+ export * from "./loaders/index.js";
2
+ export * from "./memory/index.js";
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export * from './data/index.js';
2
- export * from './memory/index.js';
1
+ export * from "./loaders/index.js";
2
+ export * from "./memory/index.js";
@@ -0,0 +1,2 @@
1
+ import { Dataset } from "@epfml/discojs";
2
+ export declare function load(file: File): Dataset<Partial<Record<string, string>>>;
@@ -0,0 +1,36 @@
1
+ import Papa from "papaparse";
2
+ import { Dataset } from "@epfml/discojs";
3
+ function isRecordOfString(raw) {
4
+ if (typeof raw !== "object" || raw === null)
5
+ return false;
6
+ const record = raw;
7
+ for (const v of Object.values(record))
8
+ if (typeof v !== "string")
9
+ return false;
10
+ return true;
11
+ }
12
+ export function load(file) {
13
+ return new Dataset(async function* () {
14
+ // papaparse uses callback for streams and can't easily be converted to async generator
15
+ // maybe another library does it better but I didn't find one at the time
16
+ yield* await new Promise((resolve, reject) => {
17
+ Papa.parse(file, {
18
+ header: true,
19
+ dynamicTyping: false,
20
+ skipEmptyLines: true, // TODO needed to avoid parsing last empty line
21
+ complete(results) {
22
+ if (results.errors.length > 0) {
23
+ reject(results.errors);
24
+ return;
25
+ }
26
+ const rows = results.data.map((row) => {
27
+ if (!isRecordOfString(row))
28
+ throw new Error("excepted object of string to string");
29
+ return row;
30
+ });
31
+ resolve(rows);
32
+ },
33
+ });
34
+ });
35
+ });
36
+ }
@@ -0,0 +1,2 @@
1
+ import { Image as DiscoImage } from "@epfml/discojs";
2
+ export declare function load(file: Blob): Promise<DiscoImage<4>>;
@@ -0,0 +1,15 @@
1
+ import { Image as DiscoImage } from "@epfml/discojs";
2
+ export async function load(file) {
3
+ const image = new Image();
4
+ const url = URL.createObjectURL(file);
5
+ image.src = url;
6
+ await image.decode();
7
+ URL.revokeObjectURL(url);
8
+ const [width, height] = [image.naturalWidth, image.naturalHeight];
9
+ const context = new OffscreenCanvas(width, height).getContext("2d");
10
+ if (context === null)
11
+ throw new Error("unable to setup image convertor");
12
+ context.drawImage(image, 0, 0);
13
+ const data = new Uint8Array(context.getImageData(0, 0, width, height).data);
14
+ return new DiscoImage(data, width, height, 4);
15
+ }
@@ -0,0 +1,3 @@
1
+ export { load as loadCSV } from "./csv.js";
2
+ export { load as loadImage } from "./image.js";
3
+ export { load as loadText } from "./text.js";
@@ -0,0 +1,3 @@
1
+ export { load as loadCSV } from "./csv.js";
2
+ export { load as loadImage } from "./image.js";
3
+ export { load as loadText } from "./text.js";
@@ -0,0 +1,2 @@
1
+ import { Dataset, Text } from "@epfml/discojs";
2
+ export declare function load(file: Blob): Dataset<Text>;
@@ -0,0 +1,37 @@
1
+ import { Dataset } from "@epfml/discojs";
2
+ class LineStream extends TransformStream {
3
+ constructor() {
4
+ let current_line = "";
5
+ super({
6
+ transform: (chunk, controller) => {
7
+ const [head, ...lines] = chunk.split(/\r\n|\r|\n/);
8
+ const first_line = current_line + head;
9
+ if (lines.length === 0) {
10
+ current_line = first_line;
11
+ return;
12
+ }
13
+ controller.enqueue(first_line);
14
+ for (const line of lines.slice(0, -1))
15
+ controller.enqueue(line);
16
+ current_line = lines[lines.length - 1];
17
+ },
18
+ flush: (controller) => controller.enqueue(current_line),
19
+ });
20
+ }
21
+ }
22
+ export function load(file) {
23
+ return new Dataset(async function* () {
24
+ const reader = file
25
+ .stream()
26
+ .pipeThrough(new TextDecoderStream())
27
+ .pipeThrough(new LineStream())
28
+ .getReader();
29
+ while (true) {
30
+ const { value: chunk, done } = await reader.read();
31
+ if (chunk !== undefined)
32
+ yield chunk;
33
+ if (done)
34
+ break;
35
+ }
36
+ });
37
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epfml/discojs-web",
3
- "version": "3.0.1-p20240821133014.0",
3
+ "version": "3.0.1-p20240826092658.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -8,7 +8,7 @@
8
8
  "watch": "nodemon --ext ts --ignore dist --watch ../discojs/dist --watch . --exec npm run",
9
9
  "build": "tsc",
10
10
  "lint": "npx eslint .",
11
- "test": ": nothing"
11
+ "test": "vitest --run"
12
12
  },
13
13
  "repository": {
14
14
  "type": "git",
@@ -20,9 +20,13 @@
20
20
  "homepage": "https://github.com/epfml/disco#readme",
21
21
  "dependencies": {
22
22
  "@epfml/discojs": "*",
23
- "@tensorflow/tfjs": "4"
23
+ "@tensorflow/tfjs": "4",
24
+ "papaparse": "5"
24
25
  },
25
26
  "devDependencies": {
26
- "nodemon": "3"
27
+ "@types/papaparse": "5",
28
+ "jsdom": "24",
29
+ "nodemon": "3",
30
+ "vitest": "1"
27
31
  }
28
32
  }
@@ -1,5 +0,0 @@
1
- import * as tf from '@tensorflow/tfjs';
2
- import { data } from '@epfml/discojs';
3
- export declare class ImageLoader extends data.ImageLoader<File> {
4
- readImageFrom(source: File): Promise<tf.Tensor3D>;
5
- }
@@ -1,7 +0,0 @@
1
- import * as tf from '@tensorflow/tfjs';
2
- import { data } from '@epfml/discojs';
3
- export class ImageLoader extends data.ImageLoader {
4
- async readImageFrom(source) {
5
- return tf.browser.fromPixels(await createImageBitmap(source));
6
- }
7
- }
@@ -1,3 +0,0 @@
1
- export { ImageLoader as WebImageLoader } from './image_loader.js';
2
- export { TabularLoader as WebTabularLoader } from './tabular_loader.js';
3
- export { TextLoader as WebTextLoader } from './text_loader.js';
@@ -1,3 +0,0 @@
1
- export { ImageLoader as WebImageLoader } from './image_loader.js';
2
- export { TabularLoader as WebTabularLoader } from './tabular_loader.js';
3
- export { TextLoader as WebTextLoader } from './text_loader.js';
@@ -1,4 +0,0 @@
1
- import { data } from '@epfml/discojs';
2
- export declare class TabularLoader extends data.TabularLoader<File> {
3
- loadDatasetFrom(source: File, csvConfig: Record<string, unknown>): Promise<data.Dataset>;
4
- }
@@ -1,8 +0,0 @@
1
- import * as tf from '@tensorflow/tfjs';
2
- import { data } from '@epfml/discojs';
3
- export class TabularLoader extends data.TabularLoader {
4
- async loadDatasetFrom(source, csvConfig) {
5
- const file = new tf.data.FileDataSource(source);
6
- return Promise.resolve(new tf.data.CSVDataset(file, csvConfig));
7
- }
8
- }
@@ -1,4 +0,0 @@
1
- import { data } from '@epfml/discojs';
2
- export declare class TextLoader extends data.TextLoader<File> {
3
- loadDatasetFrom(source: File): Promise<data.Dataset>;
4
- }
@@ -1,9 +0,0 @@
1
- import * as tf from '@tensorflow/tfjs';
2
- import { data } from '@epfml/discojs';
3
- export class TextLoader extends data.TextLoader {
4
- loadDatasetFrom(source) {
5
- const file = new tf.data.FileDataSource(source);
6
- const dataset = new tf.data.TextLineDataset(file).filter(s => s !== ' '); // newline creates empty strings
7
- return Promise.resolve(dataset);
8
- }
9
- }