@hypit/hypit 0.2.4 → 0.2.5
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/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# `@hypit/provider-monid`
|
|
2
2
|
|
|
3
|
-
Hypit Runtime Provider for a [Monid](https://monid.ai) workspace. It runs Monid's
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Hypit Runtime Provider for a [Monid](https://monid.ai) workspace. It runs Monid's generation
|
|
4
|
+
endpoints through `POST /v1/run`, polls `GET /v1/runs/{runId}` until the run is terminal, downloads
|
|
5
|
+
the returned video and stores it in the current Build.
|
|
6
6
|
|
|
7
7
|
| Capability | Monid endpoint |
|
|
8
8
|
| --- | --- |
|
|
@@ -10,20 +10,32 @@ downloads the returned `video_url` and stores the video in the current Build.
|
|
|
10
10
|
| `@hypit/seedance@1#seedance-2-fast` | `bytedance` `/v1/video/seedance-2.0-fast` |
|
|
11
11
|
| `@hypit/seedance@1#seedance-2-mini` | `bytedance` `/v1/video/seedance-2.0-mini` |
|
|
12
12
|
| `@hypit/seedance@1#seedance-2.5` | `bytedance` `/v1/video/seedance-2.5` |
|
|
13
|
+
| `@hypit/minimax-h3@1#minimax-h3` | `minimax` `/v1/video/minimax-h3` |
|
|
13
14
|
|
|
14
|
-
Monid's catalogue
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
`
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
15
|
+
Monid's catalogue lists further generation endpoints, including the H3 Fast, Max and Max Turbo
|
|
16
|
+
variants and Hailuo 2.3; their models are not the ones the Distribution describes. Input schemas
|
|
17
|
+
are published through the authenticated `inspect` operation, which is where the request bodies
|
|
18
|
+
above come from.
|
|
19
|
+
|
|
20
|
+
Every mapped endpoint relays a BytePlus ModelArk request: one `content` array holding the prompt
|
|
21
|
+
and each media input as a typed item with its `role` (`first_frame`, `last_frame`,
|
|
22
|
+
`reference_image`, `reference_video`, `reference_audio`), then `resolution`, `ratio` and
|
|
23
|
+
`duration`.
|
|
24
|
+
|
|
25
|
+
The Seedance endpoints add `generate_audio`. Monid documents no web search field for them, so
|
|
26
|
+
`web-search="true"` is unsupported, and Seedance 2.5 frame mode (`first-frame` present) requires
|
|
27
|
+
`aspect-ratio="adaptive"`. Seedance visual references may carry `person-reference`; the Provider
|
|
28
|
+
accepts the declaration and transmits nothing for it, since the endpoint has no field for it.
|
|
29
|
+
Seedance rejects reference images and videos that contain a real human face; Monid offers no way to
|
|
30
|
+
register authorized portrait material, so such a request fails with the upstream moderation error.
|
|
31
|
+
|
|
32
|
+
MiniMax H3 names its model in the body and takes neither of those two fields. The endpoint requires
|
|
33
|
+
a resolution, so a request that states none is sent at `2K`, the resolution the HypiHub Provider
|
|
34
|
+
also selects. It also requires a ratio that is not `adaptive` for text-to-video, while frame mode
|
|
35
|
+
resolves the framing from the uploaded image and reference-to-video defaults to adaptive: a
|
|
36
|
+
text-to-video request carrying no `aspect-ratio` is reported unsupported before any reference is
|
|
37
|
+
resolved, and the other two modes are sent as `adaptive`. H3 returns its video at `content.url`
|
|
38
|
+
rather than the ModelArk `video_url`.
|
|
27
39
|
|
|
28
40
|
Reference media are uploaded through the workspace file system Monid provides for this purpose
|
|
29
41
|
(`sfs`): `/put` signs an upload for `hypit/<resource>.<ext>`, the bytes are `PUT` to that URL, and
|
|
@@ -2,13 +2,21 @@ import type { ModuleRef } from "@hypit/protocol";
|
|
|
2
2
|
import type { GenerationWireMapping } from "@hypit/generation";
|
|
3
3
|
|
|
4
4
|
const SEEDANCE: ModuleRef = { name: "@hypit/seedance", version: "1" };
|
|
5
|
+
const MINIMAX_H3: ModuleRef = { name: "@hypit/minimax-h3", version: "1" };
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* One mapping plus the Monid provider that relays the endpoint. Monid addresses an endpoint by
|
|
9
|
+
* provider and path, so the provider travels with the mapping rather than being assumed.
|
|
10
|
+
*/
|
|
11
|
+
export type MonidMapping = GenerationWireMapping & { readonly service: string };
|
|
5
12
|
|
|
6
13
|
/**
|
|
7
14
|
* Monid `bytedance` endpoints and the fields their ModelArk request body takes. Media fields name
|
|
8
15
|
* the `role` of a `content` item; routes.ts folds them into that array. `personReference` is
|
|
9
16
|
* accepted on visual references and not transmitted: the endpoint has no field for it.
|
|
10
17
|
*/
|
|
11
|
-
const seedance = (name: string, endpoint: string):
|
|
18
|
+
const seedance = (name: string, endpoint: string): MonidMapping => ({
|
|
19
|
+
service: "bytedance",
|
|
12
20
|
capability: { module: SEEDANCE, name }, result: "video", routes: [{ model: endpoint }],
|
|
13
21
|
fields: {
|
|
14
22
|
prompt: { as: "value", field: "text" },
|
|
@@ -25,9 +33,34 @@ const seedance = (name: string, endpoint: string): GenerationWireMapping => ({
|
|
|
25
33
|
},
|
|
26
34
|
});
|
|
27
35
|
|
|
28
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Monid's `minimax` MiniMax-H3 endpoint. It takes the same role-tagged `content` array as the
|
|
38
|
+
* ModelArk endpoints above, names the model in the body, and carries neither a generated-audio nor
|
|
39
|
+
* a web-search field. `resolution` is required by the endpoint while the model's port is optional,
|
|
40
|
+
* so an unstated resolution is sent as the 2K the HypiHub Provider also selects.
|
|
41
|
+
*/
|
|
42
|
+
const minimaxH3: MonidMapping = {
|
|
43
|
+
service: "minimax",
|
|
44
|
+
capability: { module: MINIMAX_H3, name: "minimax-h3" }, result: "video",
|
|
45
|
+
routes: [{ model: "/v1/video/minimax-h3" }],
|
|
46
|
+
constants: { model: "MiniMax-H3" },
|
|
47
|
+
fields: {
|
|
48
|
+
prompt: { as: "value", field: "text" },
|
|
49
|
+
referenceImage: { as: "urlArray", field: "reference_image" },
|
|
50
|
+
referenceVideo: { as: "urlArray", field: "reference_video" },
|
|
51
|
+
referenceAudio: { as: "urlArray", field: "reference_audio" },
|
|
52
|
+
firstFrame: { as: "url", field: "first_frame" },
|
|
53
|
+
lastFrame: { as: "url", field: "last_frame" },
|
|
54
|
+
resolution: { as: "value", field: "resolution", whenAbsent: "2K" },
|
|
55
|
+
aspectRatio: { as: "value", field: "ratio" },
|
|
56
|
+
duration: { as: "value", field: "duration" },
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const monidMappings: readonly MonidMapping[] = [
|
|
29
61
|
seedance("seedance-2", "/v1/video/seedance-2.0"),
|
|
30
62
|
seedance("seedance-2-fast", "/v1/video/seedance-2.0-fast"),
|
|
31
63
|
seedance("seedance-2-mini", "/v1/video/seedance-2.0-mini"),
|
|
32
64
|
seedance("seedance-2.5", "/v1/video/seedance-2.5"),
|
|
65
|
+
minimaxH3,
|
|
33
66
|
];
|
|
@@ -65,11 +65,14 @@ function httpsUrl(value: unknown, subject: string): string {
|
|
|
65
65
|
assert(typeof value === "string" && /^https?:\/\//u.test(value), `${subject} has no URL`);
|
|
66
66
|
return value;
|
|
67
67
|
}
|
|
68
|
-
/**
|
|
68
|
+
/**
|
|
69
|
+
* The relayed result. The ModelArk endpoints return the task's `video_url`; MiniMax-H3 returns the
|
|
70
|
+
* video at `content.url`. The link expires, so collection downloads it rather than storing it.
|
|
71
|
+
*/
|
|
69
72
|
function outputVideoUrl(run: Record<string, unknown>): string {
|
|
70
73
|
const output = object(run.output, "Monid run output");
|
|
71
|
-
const
|
|
72
|
-
return httpsUrl(output.video_url ??
|
|
74
|
+
const content = output.content === undefined ? undefined : object(output.content, "Monid run output content");
|
|
75
|
+
return httpsUrl(output.video_url ?? content?.video_url ?? content?.url, "Monid run output");
|
|
73
76
|
}
|
|
74
77
|
const extensions: Readonly<Record<string, string>> = {
|
|
75
78
|
"image/jpeg": "jpg", "image/png": "png", "image/webp": "webp", "video/mp4": "mp4", "video/quicktime": "mov",
|
|
@@ -160,7 +163,7 @@ function endpoint(client: MonidClient, pollIntervalMs: number, maxOperationMs: n
|
|
|
160
163
|
const route = monidRouteForCapability(context.need.capability);
|
|
161
164
|
assert(route !== undefined, "Monid does not implement this exact capability");
|
|
162
165
|
const request = route.prepare(context.need.constraints);
|
|
163
|
-
await context.reportProgress?.({ phase: `Preparing Monid request:
|
|
166
|
+
await context.reportProgress?.({ phase: `Preparing Monid request: ${request.service} ${request.endpoint}` });
|
|
164
167
|
let input: Record<string, unknown>;
|
|
165
168
|
try {
|
|
166
169
|
input = await request.compile(resolverFor(client, context, publicAssetUrl));
|
|
@@ -168,8 +171,8 @@ function endpoint(client: MonidClient, pollIntervalMs: number, maxOperationMs: n
|
|
|
168
171
|
throw new MonidServiceError(error instanceof MonidServiceError ? error.code : "MONID_ERROR",
|
|
169
172
|
`Monid request preparation failed; endpoint=${request.endpoint}; generation not submitted: ${failureMessage(error)}`);
|
|
170
173
|
}
|
|
171
|
-
await context.reportProgress?.({ phase: `Submitting Monid request:
|
|
172
|
-
const { body: run } = await client.run({ provider:
|
|
174
|
+
await context.reportProgress?.({ phase: `Submitting Monid request: ${request.service} ${request.endpoint}` });
|
|
175
|
+
const { body: run } = await client.run({ provider: request.service, endpoint: request.endpoint, input }, apiKey(context.credentials));
|
|
173
176
|
const handle: Handle = { contract: "hypit.monid-operation@1", runId: runId(run), route: route.key, startedAt: Date.now() };
|
|
174
177
|
const receipt = { id: handle.runId };
|
|
175
178
|
const ended = monidTerminalStatuses.includes(String(run.status) as typeof monidTerminalStatuses[number]);
|
|
@@ -230,7 +233,7 @@ export function createMonidProvider(options: CreateMonidProviderOptions = {}) {
|
|
|
230
233
|
const asyncEndpoint = endpoint(client, pollIntervalMs, operationTimeoutMs, options.publicAssetUrl);
|
|
231
234
|
return defineEndpointPackage({
|
|
232
235
|
module: monidProviderModuleRef, facet: "gateway", instance: options.instance ?? "monid.default", pool: options.pool ?? options.instance ?? "monid.default",
|
|
233
|
-
pricing: { kind: "page", url: "https://monid.ai/tools
|
|
236
|
+
pricing: { kind: "page", url: "https://monid.ai/tools" },
|
|
234
237
|
credentials: { apiKey: options.apiKey ?? credentialRef("os", "monid.api-key") },
|
|
235
238
|
credentialInputs: { apiKey: { label: "Monid API key" } },
|
|
236
239
|
defaultConcurrency: options.defaultConcurrency ?? 4,
|
|
@@ -4,19 +4,22 @@ import {
|
|
|
4
4
|
generationTypes,
|
|
5
5
|
sealGeneratedVideoSet,
|
|
6
6
|
} from "@hypit/generation";
|
|
7
|
-
import type { GenerationArtifactUrlResolver, GenerationRequest
|
|
7
|
+
import type { GenerationArtifactUrlResolver, GenerationRequest } from "@hypit/generation";
|
|
8
8
|
import { canonicalize } from "@hypit/protocol";
|
|
9
9
|
import type { BlobRef, CapabilityRef, CanonicalValue, StoredValue, TypeRef } from "@hypit/protocol";
|
|
10
10
|
import type { EndpointRequest, EndpointSupport } from "@hypit/endpoint-kit";
|
|
11
11
|
import { monidMappings } from "./mapping.js";
|
|
12
|
+
import type { MonidMapping } from "./mapping.js";
|
|
12
13
|
|
|
13
14
|
export type MonidPreparedRequest = {
|
|
14
|
-
/** Monid
|
|
15
|
+
/** Monid provider relaying the endpoint. */
|
|
16
|
+
readonly service: string;
|
|
17
|
+
/** Monid endpoint path under that provider. */
|
|
15
18
|
readonly endpoint: string;
|
|
16
19
|
readonly compile: (resolve: GenerationArtifactUrlResolver) => Promise<Record<string, unknown>>;
|
|
17
20
|
};
|
|
18
21
|
|
|
19
|
-
export type MonidRoute =
|
|
22
|
+
export type MonidRoute = MonidMapping & {
|
|
20
23
|
readonly key: string;
|
|
21
24
|
readonly returns: TypeRef;
|
|
22
25
|
readonly supports: (request: EndpointRequest) => EndpointSupport;
|
|
@@ -35,7 +38,21 @@ function strings(value: unknown): readonly string[] {
|
|
|
35
38
|
return Array.isArray(value) ? value.filter((item): item is string => typeof item === "string" && item.length > 0) : [];
|
|
36
39
|
}
|
|
37
40
|
|
|
38
|
-
function
|
|
41
|
+
function referenceToVideo(request: GenerationRequest): boolean {
|
|
42
|
+
return present(request, "referenceImage") || present(request, "referenceVideo") || present(request, "referenceAudio");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function rejection(mapping: MonidMapping, request: GenerationRequest): string | undefined {
|
|
46
|
+
if (mapping.capability.name === "minimax-h3") {
|
|
47
|
+
// MiniMax-H3 resolves the framing from the uploaded image in frame mode and defaults
|
|
48
|
+
// reference-to-video to adaptive. Text-to-video carries no such source, and the endpoint
|
|
49
|
+
// takes no adaptive ratio there, so the aspect ratio has to be stated.
|
|
50
|
+
if (!present(request, "firstFrame") && !present(request, "lastFrame") && !referenceToVideo(request)
|
|
51
|
+
&& scalar(request, "aspectRatio") === undefined) {
|
|
52
|
+
return "MiniMax H3 text-to-video on Monid requires an aspect ratio";
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
39
56
|
if (scalar(request, "webSearch") === true) {
|
|
40
57
|
return "Monid's Seedance endpoints document no web search field";
|
|
41
58
|
}
|
|
@@ -54,6 +71,7 @@ function arkInput(input: Record<string, unknown>): Record<string, unknown> {
|
|
|
54
71
|
const first = input.first_frame;
|
|
55
72
|
const last = input.last_frame;
|
|
56
73
|
return {
|
|
74
|
+
...(typeof input.model === "string" ? { model: input.model } : {}),
|
|
57
75
|
content: [
|
|
58
76
|
{ type: "text", text: input.text },
|
|
59
77
|
...(typeof first === "string" ? [contentItem("image_url", first, "first_frame")] : []),
|
|
@@ -69,6 +87,15 @@ function arkInput(input: Record<string, unknown>): Record<string, unknown> {
|
|
|
69
87
|
};
|
|
70
88
|
}
|
|
71
89
|
|
|
90
|
+
/**
|
|
91
|
+
* MiniMax-H3 takes a required ratio: frame mode and reference-to-video both resolve to adaptive,
|
|
92
|
+
* and rejection() has already required a stated ratio for text-to-video.
|
|
93
|
+
*/
|
|
94
|
+
function minimaxH3Input(input: Record<string, unknown>): Record<string, unknown> {
|
|
95
|
+
const body = arkInput(input);
|
|
96
|
+
return { ...body, ratio: body.ratio ?? "adaptive" };
|
|
97
|
+
}
|
|
98
|
+
|
|
72
99
|
function capabilityKey(capability: CapabilityRef): string {
|
|
73
100
|
return `${capability.module.name}@${capability.module.version}#${capability.name}`;
|
|
74
101
|
}
|
|
@@ -85,9 +112,11 @@ export const monidRoutes: readonly MonidRoute[] = monidMappings.map((mapping) =>
|
|
|
85
112
|
const request = constraints as unknown as GenerationRequest;
|
|
86
113
|
const reason = rejection(mapping, request);
|
|
87
114
|
if (reason !== undefined) throw new Error(reason);
|
|
115
|
+
const body = mapping.capability.name === "minimax-h3" ? minimaxH3Input : arkInput;
|
|
88
116
|
return {
|
|
117
|
+
service: mapping.service,
|
|
89
118
|
endpoint: selectWireModelForRequest(mapping, request),
|
|
90
|
-
compile: async (resolve) =>
|
|
119
|
+
compile: async (resolve) => body((await compileWireRequest(mapping, request, resolve)).input as Record<string, unknown>),
|
|
91
120
|
};
|
|
92
121
|
},
|
|
93
122
|
packageResult: (artifacts) => ({
|