File size: 2,544 Bytes
564e576
 
719022a
cce2203
564e576
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
719022a
 
564e576
719022a
 
 
 
 
 
 
 
 
 
 
 
564e576
 
 
 
 
 
 
719022a
 
 
 
 
 
 
 
 
 
 
 
564e576
cce2203
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import { env } from "$env/dynamic/private";
import { Client } from "@gradio/client";
import { SignJWT } from "jose";
import JSON5 from "json5";

export type GradioImage = {
	path: string;
	url: string;
	orig_name: string;
	is_stream: boolean;
	meta: Record<string, unknown>;
};

type GradioResponse = {
	data: unknown[];
};

export async function callSpace<TInput extends unknown[], TOutput extends unknown[]>(
	name: string,
	func: string,
	parameters: TInput,
	ipToken: string | undefined
): Promise<TOutput> {
	class CustomClient extends Client {
		fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {
			init = init || {};
			init.headers = {
				...(init.headers || {}),
				...(ipToken ? { "X-IP-Token": ipToken } : {}),
			};
			return super.fetch(input, init);
		}
	}

	const client = await CustomClient.connect(name, {
		hf_token: (env.HF_TOKEN ?? env.HF_ACCESS_TOKEN) as unknown as `hf_${string}`,
	});
	return await client
		.predict(func, parameters)
		.then((res) => (res as unknown as GradioResponse).data as TOutput);
}

export async function getIpToken(ip: string, username?: string) {
	const ipTokenSecret = env.IP_TOKEN_SECRET;
	if (!ipTokenSecret) {
		return;
	}
	return await new SignJWT({ ip, user: username })
		.setProtectedHeader({ alg: "HS256" })
		.setIssuedAt()
		.setExpirationTime("1m")
		.sign(new TextEncoder().encode(ipTokenSecret));
}

export { toolHasName } from "$lib/utils/tools";

export async function extractJson(text: string): Promise<unknown[]> {
	const calls: string[] = [];

	let codeBlocks = Array.from(text.matchAll(/```json\n(.*?)```/gs))
		.map(([, block]) => block)
		// remove trailing comma
		.map((block) => block.trim().replace(/,$/, ""));

	// if there is no code block, try to find the first json object
	// by trimming the string and trying to parse with JSON5
	if (codeBlocks.length === 0) {
		const start = [text.indexOf("["), text.indexOf("{")]
			.filter((i) => i !== -1)
			.reduce((a, b) => Math.max(a, b), -Infinity);
		const end = [text.lastIndexOf("]"), text.lastIndexOf("}")]
			.filter((i) => i !== -1)
			.reduce((a, b) => Math.min(a, b), Infinity);

		if (start === -Infinity || end === Infinity) {
			return [""];
		}

		const json = text.substring(start, end + 1);
		codeBlocks = [json];
	}

	// grab only the capture group from the regex match
	for (const block of codeBlocks) {
		// make it an array if it's not already
		let call = JSON5.parse(block);
		if (!Array.isArray(call)) {
			call = [call];
		}
		calls.push(call);
	}
	return calls.flat();
}