Files
wehub-resource-sync 7254f7b4d1
Build / Build (macos-latest) (push) Has been cancelled
Build / Build (ubuntu-latest) (push) Has been cancelled
Build / Build (windows-latest) (push) Has been cancelled
Build / Analyze (javascript) (push) Has been cancelled
Build / Analyze (python) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:37:45 +08:00

287 lines
10 KiB
JavaScript

import * as protobuf from './protobuf.js';
const mediapipe = {};
mediapipe.ModelFactory = class {
async match(context) {
const tags = await context.tags('pbtxt');
if (tags.has('node') && ['input_stream', 'output_stream', 'input_side_packet', 'output_side_packet'].some((key) => tags.has(key) || tags.has(`node.${key}`))) {
return context.set('mediapipe.pbtxt');
}
return null;
}
async open(context) {
// mediapipe.proto = await context.require('./mediapipe-proto');
mediapipe.proto = {};
let config = null;
try {
const reader = await context.read('protobuf.text');
// const config = mediapipe.proto.mediapipe.CalculatorGraphConfig.decodeText(reader);
config = new mediapipe.Object(reader);
} catch (error) {
const message = error && error.message ? error.message : error.toString();
throw new mediapipe.Error(`File text format is not mediapipe.CalculatorGraphConfig (${message.replace(/\.$/, '')}).`);
}
return new mediapipe.Model(config);
}
};
mediapipe.Model = class {
constructor(config) {
this.format = 'MediaPipe';
this.modules = [new mediapipe.Graph(config)];
}
};
mediapipe.Graph = class {
constructor(config) {
config = config || {};
this.inputs = [];
this.outputs = [];
this.nodes = [];
const types = new Map();
const type = (list) => {
if (!Array.isArray(list)) {
list = list ? [list] : [];
}
return list.map((item) => {
const parts = item.split(':');
const name = parts.pop();
const type = parts.join(':');
if (!types.has(name)) {
const value = new Set();
if (type) {
value.add(type);
}
types.set(name, value);
} else if (type && !types.get(name).has(type)) {
types.get(name).add(type);
}
return name;
});
};
config.input_stream = type(config.input_stream);
config.output_stream = type(config.output_stream);
config.input_side_packet = type(config.input_side_packet);
config.output_side_packet = type(config.output_side_packet);
if (!Array.isArray(config.node)) {
config.node = config.node ? [config.node] : [];
}
for (const node of config.node) {
node.input_stream = type(node.input_stream);
node.output_stream = type(node.output_stream);
node.input_side_packet = type(node.input_side_packet);
node.output_side_packet = type(node.output_side_packet);
}
const values = new Map();
for (const [name, value] of types) {
const type = Array.from(value).join(',');
values.set(name, new mediapipe.Value(name, type || null));
}
const value = (name) => {
return values.get(name);
};
for (const name of config.input_stream) {
const argument = new mediapipe.Argument(name, [value(name)]);
this.inputs.push(argument);
}
for (const name of config.output_stream) {
const argument = new mediapipe.Argument(name, [value(name)]);
this.outputs.push(argument);
}
for (const name of config.input_side_packet) {
const argument = new mediapipe.Argument(name, [value(name, type)]);
this.inputs.push(argument);
}
for (const output of config.output_side_packet) {
const parts = output.split(':');
const type = (parts.length > 1) ? parts.shift() : '';
const name = parts.shift();
const argument = new mediapipe.Argument(name, [value(name, type)]);
this.outputs.push(argument);
}
for (const node of config.node) {
this.nodes.push(new mediapipe.Node(node, value));
}
}
};
mediapipe.Node = class {
constructor(node, value) {
const type = node.calculator || '?';
this.name = '';
this.type = { name: type.replace(/Calculator$/, '') };
this.inputs = [];
this.outputs = [];
this.attributes = [];
if (node.input_stream) {
const values = node.input_stream.map((name) => value(name));
const argument = new mediapipe.Argument('input_stream', values);
this.inputs.push(argument);
}
if (node.output_stream) {
const values = node.output_stream.map((name) => value(name));
this.outputs.push(new mediapipe.Argument('output_stream', values));
}
if (node.input_side_packet) {
const values = node.input_side_packet.map((name) => value(name));
this.inputs.push(new mediapipe.Argument('output_stream', values));
}
if (node.output_side_packet) {
const values = node.output_side_packet.map((name) => value(name));
this.outputs.push(new mediapipe.Argument('output_side_packet', values));
}
const options = new Map();
if (node.options) {
for (const key of Object.keys(node.options)) {
options.set(key, node.options[key]);
}
}
let node_options = node.node_options;
if (!Array.isArray(node_options)) {
node_options = node_options ? [node_options] : [];
}
if (mediapipe.proto.google && node_options.every((options) => options instanceof mediapipe.proto.google.protobuf.Any)) {
for (const entry of node_options) {
const value = new RegExp(/^\{(.*)\}\s*$/, 's').exec(entry.value);
const buffer = new TextEncoder('utf-8').encode(value[1]);
const reader = protobuf.TextReader.open(buffer);
if (entry.type_url.startsWith('type.googleapis.com/mediapipe.')) {
const type = entry.type_url.split('.').pop();
if (mediapipe.proto && mediapipe.proto.mediapipe && mediapipe.proto.mediapipe[type]) {
const message = mediapipe.proto.mediapipe[type].decodeText(reader);
for (const key of Object.keys(message)) {
options.set(key, message[key]);
}
continue;
}
}
const message = new mediapipe.Object(reader);
for (const [name, value] of Object.entries(message)) {
options.set(name, value);
}
}
} else {
for (const option of node_options) {
for (const [name, value] of Object.entries(option)) {
if (name !== '__type__') {
options.set(name, value);
}
}
}
}
for (const [name, value] of options) {
const attribute = new mediapipe.Argument(name, value);
this.attributes.push(attribute);
}
}
};
mediapipe.Argument = class {
constructor(name, value) {
this.name = name;
this.value = value;
}
};
mediapipe.Value = class {
constructor(name, type = null) {
if (typeof name !== 'string') {
throw new mediapipe.Error(`Invalid value identifier '${JSON.stringify(name)}'.`);
}
this.name = name;
this.type = type;
}
};
mediapipe.Object = class {
constructor(reader, block) {
if (!block) {
reader.start();
}
const type = reader.token();
if (type.startsWith('[') && type.endsWith(']')) {
this.__type__ = type.substring(1, type.length - 1);
reader.next();
reader.match(':');
reader.start();
}
const arrayTags = new Set();
while (!reader.end()) {
const tag = reader.tag();
const next = reader.token();
let obj = null;
if (next === '{') {
reader.start();
obj = new mediapipe.Object(reader, true);
if (obj.__type__) {
while (!reader.end()) {
if (!Array.isArray(obj)) {
obj = [obj];
}
const token = reader.token();
if (token.startsWith('[') && token.endsWith(']')) {
obj.push(new mediapipe.Object(reader, true));
continue;
}
break;
}
}
} else if (next.startsWith('"') && next.endsWith('"')) {
obj = next.substring(1, next.length - 1);
reader.next();
} else if (next === 'true' || next === 'false') {
obj = next;
reader.next();
} else if (reader.first()) {
obj = [];
while (!reader.last()) {
const data = reader.token();
reader.next();
if (!isNaN(data)) {
obj.push(parseFloat(data));
}
}
} else if (isNaN(next)) {
obj = next;
reader.next();
} else {
obj = parseFloat(next);
reader.next();
}
if (this[tag] && (!Array.isArray(this[tag]) || arrayTags.has(tag))) {
this[tag] = [this[tag]];
arrayTags.delete(tag);
}
if (this[tag]) {
this[tag].push(obj);
} else {
if (Array.isArray(obj)) {
arrayTags.add(tag);
}
this[tag] = obj;
}
reader.match(',');
}
}
};
mediapipe.Error = class extends Error {
constructor(message) {
super(message);
this.name = 'Error loading MediaPipe model.';
}
};
export const ModelFactory = mediapipe.ModelFactory;