File size: 2,869 Bytes
9ada4bc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import {
	get_space_hardware,
	hardware_types,
	set_space_timeout
} from "../helpers/spaces";
import type { DuplicateOptions } from "../types";
import { Client } from "../client";
import { SPACE_METADATA_ERROR_MSG } from "../constants";
import {
	get_cookie_header,
	parse_and_set_cookies
} from "../helpers/init_helpers";
import { process_endpoint } from "../helpers/api_info";

export async function duplicate(
	app_reference: string,
	options: DuplicateOptions
): Promise<Client> {
	const { hf_token, private: _private, hardware, timeout, auth } = options;

	if (hardware && !hardware_types.includes(hardware)) {
		throw new Error(
			`Invalid hardware type provided. Valid types are: ${hardware_types
				.map((v) => `"${v}"`)
				.join(",")}.`
		);
	}

	const { http_protocol, host } = await process_endpoint(
		app_reference,
		hf_token
	);

	let cookies: string[] | null = null;

	if (auth) {
		const cookie_header = await get_cookie_header(
			http_protocol,
			host,
			auth,
			fetch
		);

		if (cookie_header) cookies = parse_and_set_cookies(cookie_header);
	}

	const headers = {
		Authorization: `Bearer ${hf_token}`,
		"Content-Type": "application/json",
		...(cookies ? { Cookie: cookies.join("; ") } : {})
	};

	const user = (
		await (
			await fetch(`https://huggingface.co/api/whoami-v2`, {
				headers
			})
		).json()
	).name;

	const space_name = app_reference.split("/")[1];
	const body: {
		repository: string;
		private?: boolean;
		hardware?: string;
	} = {
		repository: `${user}/${space_name}`
	};

	if (_private) {
		body.private = true;
	}

	let original_hardware;

	try {
		if (!hardware) {
			original_hardware = await get_space_hardware(app_reference, hf_token);
		}
	} catch (e) {
		throw Error(SPACE_METADATA_ERROR_MSG + (e as Error).message);
	}

	const requested_hardware = hardware || original_hardware || "cpu-basic";

	body.hardware = requested_hardware;

	try {
		const response = await fetch(
			`https://huggingface.co/api/spaces/${app_reference}/duplicate`,
			{
				method: "POST",
				headers,
				body: JSON.stringify(body)
			}
		);

		if (response.status === 409) {
			try {
				const client = await Client.connect(`${user}/${space_name}`, options);
				return client;
			} catch (error) {
				console.error("Failed to connect Client instance:", error);
				throw error;
			}
		} else if (response.status !== 200) {
			throw new Error(response.statusText);
		}

		const duplicated_space = await response.json();

		await set_space_timeout(`${user}/${space_name}`, timeout || 300, hf_token);

		return await Client.connect(
			get_space_reference(duplicated_space.url),
			options
		);
	} catch (e: any) {
		throw new Error(e);
	}
}

function get_space_reference(url: string): any {
	const regex = /https:\/\/huggingface.co\/spaces\/([^/]+\/[^/]+)/;
	const match = url.match(regex);
	if (match) {
		return match[1];
	}
}