Upload folder using huggingface_hub
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .changeset/README.md +8 -0
- .changeset/changeset.cjs +280 -0
- .changeset/config.json +11 -0
- .changeset/every-bears-peel.md +6 -0
- .changeset/fix_changelogs.cjs +122 -0
- .config/.prettierignore +30 -0
- .config/.prettierrc.json +7 -0
- .config/basevite.config.ts +90 -0
- .config/copy_frontend.py +59 -0
- .config/eslint.config.js +153 -0
- .config/playwright-ct.config.ts +41 -0
- .config/playwright-setup.js +152 -0
- .config/playwright.config.js +24 -0
- .config/playwright/index.html +12 -0
- .config/playwright/index.ts +2 -0
- .config/postcss.config.cjs +8 -0
- .config/setup_vite_tests.ts +11 -0
- .config/tailwind.config.cjs +12 -0
- .config/vitest.config.ts +3 -0
- .devcontainer/devcontainer.json +41 -0
- .dockerignore +40 -0
- .editorconfig +8 -0
- .git-blame-ignore-revs +14 -0
- .gitattributes +17 -0
- .github/ISSUE_TEMPLATE/bug_report_template.yml +69 -0
- .github/ISSUE_TEMPLATE/config.yml +5 -0
- .github/ISSUE_TEMPLATE/feature_request.md +19 -0
- .github/PULL_REQUEST_TEMPLATE.md +18 -0
- .github/actions/install-all-deps/action.yml +60 -0
- .github/actions/install-frontend-deps/action.yml +51 -0
- .github/stale +17 -0
- .github/workflows/backend.yml +244 -0
- .github/workflows/build-pr.yml +76 -0
- .github/workflows/check-demo-notebooks.yml +50 -0
- .github/workflows/comment-queue.yml +36 -0
- .github/workflows/delete-stale-spaces.yml +35 -0
- .github/workflows/deploy-chromatic.yml +88 -0
- .github/workflows/deploy-pr-to-spaces.yml +99 -0
- .github/workflows/deploy-website.yml +108 -0
- .github/workflows/generate-changeset.yml +88 -0
- .github/workflows/large-files.yml +21 -0
- .github/workflows/publish-npm.yml +77 -0
- .github/workflows/report-notebook-status-pr.yml +47 -0
- .github/workflows/trigger-changeset.yml +19 -0
- .github/workflows/ui.yml +103 -0
- .gitignore +80 -0
- .vscode/extensions.json +9 -0
- .vscode/settings.json +23 -0
- CHANGELOG.md +0 -0
- CITATION.cff +45 -0
.changeset/README.md
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Changesets
|
2 |
+
|
3 |
+
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
|
4 |
+
with multi-package repos, or single-package repos to help you version and publish your code. You can
|
5 |
+
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
|
6 |
+
|
7 |
+
We have a quick list of common questions to get you started engaging with this project in
|
8 |
+
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
|
.changeset/changeset.cjs
ADDED
@@ -0,0 +1,280 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const { getPackagesSync } = require("@manypkg/get-packages");
|
2 |
+
const gh = require("@changesets/get-github-info");
|
3 |
+
const { existsSync, readFileSync, writeFileSync } = require("fs");
|
4 |
+
const { join } = require("path");
|
5 |
+
|
6 |
+
const { getInfo, getInfoFromPullRequest } = gh;
|
7 |
+
const { packages, rootDir } = getPackagesSync(process.cwd());
|
8 |
+
|
9 |
+
/**
|
10 |
+
* @typedef {{packageJson: {name: string, python?: boolean}, dir: string}} Package
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* @typedef {{summary: string, id: string, commit: string, releases: {name: string}}} Changeset
|
15 |
+
*/
|
16 |
+
|
17 |
+
/**
|
18 |
+
*
|
19 |
+
* @param {string} package_name The name of the package to find the directories for
|
20 |
+
* @returns {string[]} The directories for the package
|
21 |
+
*/
|
22 |
+
function find_packages_dirs(package_name) {
|
23 |
+
/** @type {string[]} */
|
24 |
+
let package_dirs = [];
|
25 |
+
|
26 |
+
/** @type {Package | undefined} */
|
27 |
+
const _package = packages.find((p) => p.packageJson.name === package_name);
|
28 |
+
if (!_package) throw new Error(`Package ${package_name} not found`);
|
29 |
+
|
30 |
+
package_dirs.push(_package.dir);
|
31 |
+
if (_package.packageJson.python) {
|
32 |
+
package_dirs.push(join(_package.dir, ".."));
|
33 |
+
}
|
34 |
+
return package_dirs;
|
35 |
+
}
|
36 |
+
|
37 |
+
const changelogFunctions = {
|
38 |
+
/**
|
39 |
+
*
|
40 |
+
* @param {Changeset[]} changesets The changesets that have been created
|
41 |
+
* @param {any} dependenciesUpdated The dependencies that have been updated
|
42 |
+
* @param {any} options The options passed to the changelog generator
|
43 |
+
* @returns {Promise<string>} The release line for the dependencies
|
44 |
+
*/
|
45 |
+
getDependencyReleaseLine: async (
|
46 |
+
changesets,
|
47 |
+
dependenciesUpdated,
|
48 |
+
options
|
49 |
+
) => {
|
50 |
+
if (!options.repo) {
|
51 |
+
throw new Error(
|
52 |
+
'Please provide a repo to this changelog generator like this:\n"changelog": ["@changesets/changelog-github", { "repo": "org/repo" }]'
|
53 |
+
);
|
54 |
+
}
|
55 |
+
if (dependenciesUpdated.length === 0) return "";
|
56 |
+
|
57 |
+
const changesetLink = `- Updated dependencies [${(
|
58 |
+
await Promise.all(
|
59 |
+
changesets.map(async (cs) => {
|
60 |
+
if (cs.commit) {
|
61 |
+
let { links } = await getInfo({
|
62 |
+
repo: options.repo,
|
63 |
+
commit: cs.commit
|
64 |
+
});
|
65 |
+
return links.commit;
|
66 |
+
}
|
67 |
+
})
|
68 |
+
)
|
69 |
+
)
|
70 |
+
.filter((_) => _)
|
71 |
+
.join(", ")}]:`;
|
72 |
+
|
73 |
+
const updatedDepenenciesList = dependenciesUpdated.map(
|
74 |
+
/**
|
75 |
+
*
|
76 |
+
* @param {any} dependency The dependency that has been updated
|
77 |
+
* @returns {string} The formatted dependency
|
78 |
+
*/
|
79 |
+
(dependency) => ` - ${dependency.name}@${dependency.newVersion}`
|
80 |
+
);
|
81 |
+
|
82 |
+
return [changesetLink, ...updatedDepenenciesList].join("\n");
|
83 |
+
},
|
84 |
+
/**
|
85 |
+
*
|
86 |
+
* @param {{summary: string, id: string, commit: string, releases: {name: string}[]}} changeset The changeset that has been created
|
87 |
+
* @param {any} type The type of changeset
|
88 |
+
* @param {any} options The options passed to the changelog generator
|
89 |
+
* @returns {Promise<string>} The release line for the changeset
|
90 |
+
*/
|
91 |
+
getReleaseLine: async (changeset, type, options) => {
|
92 |
+
if (!options || !options.repo) {
|
93 |
+
throw new Error(
|
94 |
+
'Please provide a repo to this changelog generator like this:\n"changelog": ["@changesets/changelog-github", { "repo": "org/repo" }]'
|
95 |
+
);
|
96 |
+
}
|
97 |
+
|
98 |
+
let prFromSummary;
|
99 |
+
let commitFromSummary;
|
100 |
+
/**
|
101 |
+
* @type {string[]}
|
102 |
+
*/
|
103 |
+
let usersFromSummary = [];
|
104 |
+
|
105 |
+
const replacedChangelog = changeset.summary
|
106 |
+
.replace(/^\s*(?:pr|pull|pull\s+request):\s*#?(\d+)/im, (_, pr) => {
|
107 |
+
let num = Number(pr);
|
108 |
+
if (!isNaN(num)) prFromSummary = num;
|
109 |
+
return "";
|
110 |
+
})
|
111 |
+
.replace(/^\s*commit:\s*([^\s]+)/im, (_, commit) => {
|
112 |
+
commitFromSummary = commit;
|
113 |
+
return "";
|
114 |
+
})
|
115 |
+
.replace(/^\s*(?:author|user):\s*@?([^\s]+)/gim, (_, user) => {
|
116 |
+
usersFromSummary.push(user);
|
117 |
+
return "";
|
118 |
+
})
|
119 |
+
.trim();
|
120 |
+
|
121 |
+
const [firstLine, ...futureLines] = replacedChangelog
|
122 |
+
.split("\n")
|
123 |
+
.map((l) => l.trimRight());
|
124 |
+
|
125 |
+
const links = await (async () => {
|
126 |
+
if (prFromSummary !== undefined) {
|
127 |
+
let { links } = await getInfoFromPullRequest({
|
128 |
+
repo: options.repo,
|
129 |
+
pull: prFromSummary
|
130 |
+
});
|
131 |
+
if (commitFromSummary) {
|
132 |
+
links = {
|
133 |
+
...links,
|
134 |
+
commit: `[\`${commitFromSummary}\`](https://github.com/${options.repo}/commit/${commitFromSummary})`
|
135 |
+
};
|
136 |
+
}
|
137 |
+
return links;
|
138 |
+
}
|
139 |
+
const commitToFetchFrom = commitFromSummary || changeset.commit;
|
140 |
+
if (commitToFetchFrom) {
|
141 |
+
let { links } = await getInfo({
|
142 |
+
repo: options.repo,
|
143 |
+
commit: commitToFetchFrom
|
144 |
+
});
|
145 |
+
return links;
|
146 |
+
}
|
147 |
+
return {
|
148 |
+
commit: null,
|
149 |
+
pull: null,
|
150 |
+
user: null
|
151 |
+
};
|
152 |
+
})();
|
153 |
+
|
154 |
+
const users =
|
155 |
+
usersFromSummary && usersFromSummary.length
|
156 |
+
? usersFromSummary
|
157 |
+
.map(
|
158 |
+
(userFromSummary) =>
|
159 |
+
`[@${userFromSummary}](https://github.com/${userFromSummary})`
|
160 |
+
)
|
161 |
+
.join(", ")
|
162 |
+
: links.user;
|
163 |
+
|
164 |
+
const prefix = [
|
165 |
+
links.pull === null ? "" : `${links.pull}`,
|
166 |
+
links.commit === null ? "" : `${links.commit}`
|
167 |
+
]
|
168 |
+
.join(" ")
|
169 |
+
.trim();
|
170 |
+
|
171 |
+
const suffix = users === null ? "" : ` Thanks ${users}!`;
|
172 |
+
|
173 |
+
/**
|
174 |
+
* @typedef {{[key: string]: string[] | {dirs: string[], current_changelog: string, feat: {summary: string}[], fix: {summary: string}[], highlight: {summary: string}[]}}} ChangesetMeta
|
175 |
+
*/
|
176 |
+
|
177 |
+
/**
|
178 |
+
* @type { ChangesetMeta & { _handled: string[] } }}
|
179 |
+
*/
|
180 |
+
let lines;
|
181 |
+
if (existsSync(join(rootDir, ".changeset", "_changelog.json"))) {
|
182 |
+
lines = JSON.parse(
|
183 |
+
readFileSync(join(rootDir, ".changeset", "_changelog.json"), "utf-8")
|
184 |
+
);
|
185 |
+
} else {
|
186 |
+
lines = {
|
187 |
+
_handled: []
|
188 |
+
};
|
189 |
+
}
|
190 |
+
|
191 |
+
if (lines._handled.includes(changeset.id)) {
|
192 |
+
return "done";
|
193 |
+
}
|
194 |
+
lines._handled.push(changeset.id);
|
195 |
+
|
196 |
+
changeset.releases.forEach((release) => {
|
197 |
+
if (!lines[release.name])
|
198 |
+
lines[release.name] = {
|
199 |
+
dirs: find_packages_dirs(release.name),
|
200 |
+
current_changelog: "",
|
201 |
+
feat: [],
|
202 |
+
fix: [],
|
203 |
+
highlight: []
|
204 |
+
};
|
205 |
+
|
206 |
+
const changelog_path = join(
|
207 |
+
//@ts-ignore
|
208 |
+
lines[release.name].dirs[1] || lines[release.name].dirs[0],
|
209 |
+
"CHANGELOG.md"
|
210 |
+
);
|
211 |
+
|
212 |
+
if (existsSync(changelog_path)) {
|
213 |
+
//@ts-ignore
|
214 |
+
lines[release.name].current_changelog = readFileSync(
|
215 |
+
changelog_path,
|
216 |
+
"utf-8"
|
217 |
+
)
|
218 |
+
.replace(`# ${release.name}`, "")
|
219 |
+
.trim();
|
220 |
+
}
|
221 |
+
|
222 |
+
const [, _type, summary] = changeset.summary
|
223 |
+
.trim()
|
224 |
+
.match(/^(feat|fix|highlight)\s*:\s*([^]*)/im) || [
|
225 |
+
,
|
226 |
+
"feat",
|
227 |
+
changeset.summary
|
228 |
+
];
|
229 |
+
|
230 |
+
let formatted_summary = "";
|
231 |
+
|
232 |
+
if (_type === "highlight") {
|
233 |
+
const [heading, ...rest] = summary.trim().split("\n");
|
234 |
+
const _heading = `${heading} ${prefix ? `(${prefix})` : ""}`;
|
235 |
+
const _rest = rest.concat(["", suffix]);
|
236 |
+
|
237 |
+
formatted_summary = `${_heading}\n${_rest.join("\n")}`;
|
238 |
+
} else {
|
239 |
+
formatted_summary = handle_line(summary, prefix, suffix);
|
240 |
+
}
|
241 |
+
|
242 |
+
//@ts-ignore
|
243 |
+
lines[release.name][_type].push({
|
244 |
+
summary: formatted_summary
|
245 |
+
});
|
246 |
+
});
|
247 |
+
|
248 |
+
writeFileSync(
|
249 |
+
join(rootDir, ".changeset", "_changelog.json"),
|
250 |
+
JSON.stringify(lines, null, 2)
|
251 |
+
);
|
252 |
+
|
253 |
+
return `\n\n-${prefix ? `${prefix} -` : ""} ${firstLine}\n${futureLines
|
254 |
+
.map((l) => ` ${l}`)
|
255 |
+
.join("\n")}`;
|
256 |
+
}
|
257 |
+
};
|
258 |
+
|
259 |
+
/**
|
260 |
+
* @param {string} str The changelog entry
|
261 |
+
* @param {string} prefix The prefix to add to the first line
|
262 |
+
* @param {string} suffix The suffix to add to the last line
|
263 |
+
* @returns {string} The formatted changelog entry
|
264 |
+
*/
|
265 |
+
function handle_line(str, prefix, suffix) {
|
266 |
+
const [_s, ...lines] = str.split("\n").filter(Boolean);
|
267 |
+
|
268 |
+
const desc = `${prefix ? `${prefix} -` : ""} ${_s.replace(
|
269 |
+
/[\s\.]$/,
|
270 |
+
""
|
271 |
+
)}. ${suffix}`;
|
272 |
+
|
273 |
+
if (_s.length === 1) {
|
274 |
+
return desc;
|
275 |
+
}
|
276 |
+
|
277 |
+
return [desc, ...lines.map((l) => ` ${l}`)].join("/n");
|
278 |
+
}
|
279 |
+
|
280 |
+
module.exports = changelogFunctions;
|
.changeset/config.json
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
|
3 |
+
"changelog": ["./changeset.cjs", { "repo": "gradio-app/gradio" }],
|
4 |
+
"commit": false,
|
5 |
+
"fixed": [],
|
6 |
+
"linked": [],
|
7 |
+
"access": "public",
|
8 |
+
"baseBranch": "main",
|
9 |
+
"updateInternalDependencies": "patch",
|
10 |
+
"ignore": ["@gradio/spaces-test", "@gradio/cdn-test"]
|
11 |
+
}
|
.changeset/every-bears-peel.md
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
"@gradio/audio": patch
|
3 |
+
"gradio": patch
|
4 |
+
---
|
5 |
+
|
6 |
+
fix:Fix audio recording events not dispatching
|
.changeset/fix_changelogs.cjs
ADDED
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const { join } = require("path");
|
2 |
+
const { readFileSync, existsSync, writeFileSync, unlinkSync } = require("fs");
|
3 |
+
const { getPackagesSync } = require("@manypkg/get-packages");
|
4 |
+
|
5 |
+
const RE_PKG_NAME = /^[\w-]+\b/;
|
6 |
+
const pkg_meta = getPackagesSync(process.cwd());
|
7 |
+
|
8 |
+
/**
|
9 |
+
* @typedef {{dirs: string[], highlight: {summary: string}[], feat: {summary: string}[], fix: {summary: string}[], current_changelog: string}} ChangesetMeta
|
10 |
+
*/
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @typedef {{[key: string]: ChangesetMeta}} ChangesetMetaCollection
|
14 |
+
*/
|
15 |
+
|
16 |
+
function run() {
|
17 |
+
if (!existsSync(join(pkg_meta.rootDir, ".changeset", "_changelog.json"))) {
|
18 |
+
console.warn("No changesets to process");
|
19 |
+
return;
|
20 |
+
}
|
21 |
+
|
22 |
+
/**
|
23 |
+
* @type { ChangesetMetaCollection & { _handled: string[] } }}
|
24 |
+
*/
|
25 |
+
const { _handled, ...packages } = JSON.parse(
|
26 |
+
readFileSync(
|
27 |
+
join(pkg_meta.rootDir, ".changeset", "_changelog.json"),
|
28 |
+
"utf-8"
|
29 |
+
)
|
30 |
+
);
|
31 |
+
|
32 |
+
/**
|
33 |
+
* @typedef { {packageJson: {name: string, version: string, python: boolean}, dir: string} } PackageMeta
|
34 |
+
*/
|
35 |
+
|
36 |
+
/**
|
37 |
+
* @type { {[key:string]: PackageMeta} }
|
38 |
+
*/
|
39 |
+
const all_packages = pkg_meta.packages.reduce((acc, pkg) => {
|
40 |
+
acc[pkg.packageJson.name] = /**@type {PackageMeta} */ (
|
41 |
+
/** @type {unknown} */ (pkg)
|
42 |
+
);
|
43 |
+
return acc;
|
44 |
+
}, /** @type {{[key:string] : PackageMeta}} */ ({}));
|
45 |
+
|
46 |
+
for (const pkg_name in packages) {
|
47 |
+
const { dirs, highlight, feat, fix, current_changelog } =
|
48 |
+
/**@type {ChangesetMeta} */ (packages[pkg_name]);
|
49 |
+
|
50 |
+
const { version, python } = all_packages[pkg_name].packageJson;
|
51 |
+
|
52 |
+
const highlights = highlight.map((h) => `${h.summary}`);
|
53 |
+
const features = feat.map((f) => `- ${f.summary}`);
|
54 |
+
const fixes = fix.map((f) => `- ${f.summary}`);
|
55 |
+
|
56 |
+
const release_notes = /** @type {[string[], string][]} */ ([
|
57 |
+
[highlights, "### Highlights"],
|
58 |
+
[features, "### Features"],
|
59 |
+
[fixes, "### Fixes"]
|
60 |
+
])
|
61 |
+
.filter(([s], i) => s.length > 0)
|
62 |
+
.map(([lines, title]) => {
|
63 |
+
if (title === "### Highlights") {
|
64 |
+
return `${title}\n\n${lines.join("\n\n")}`;
|
65 |
+
}
|
66 |
+
|
67 |
+
return `${title}\n\n${lines.join("\n")}`;
|
68 |
+
})
|
69 |
+
.join("\n\n");
|
70 |
+
|
71 |
+
const new_changelog = `# ${pkg_name}
|
72 |
+
|
73 |
+
## ${version}
|
74 |
+
|
75 |
+
${release_notes}
|
76 |
+
|
77 |
+
${current_changelog.replace(`# ${pkg_name}`, "").trim()}
|
78 |
+
`.trim();
|
79 |
+
|
80 |
+
dirs.forEach((dir) => {
|
81 |
+
writeFileSync(join(dir, "CHANGELOG.md"), new_changelog);
|
82 |
+
});
|
83 |
+
|
84 |
+
if (python) {
|
85 |
+
bump_local_dependents(pkg_name, version);
|
86 |
+
}
|
87 |
+
}
|
88 |
+
|
89 |
+
unlinkSync(join(pkg_meta.rootDir, ".changeset", "_changelog.json"));
|
90 |
+
|
91 |
+
/**
|
92 |
+
* @param {string} pkg_to_bump The name of the package to bump
|
93 |
+
* @param {string} version The version to bump to
|
94 |
+
* @returns {void}
|
95 |
+
* */
|
96 |
+
function bump_local_dependents(pkg_to_bump, version) {
|
97 |
+
for (const pkg_name in all_packages) {
|
98 |
+
const {
|
99 |
+
dir,
|
100 |
+
packageJson: { python }
|
101 |
+
} = all_packages[pkg_name];
|
102 |
+
|
103 |
+
if (!python) continue;
|
104 |
+
|
105 |
+
const requirements_path = join(dir, "..", "requirements.txt");
|
106 |
+
const requirements = readFileSync(requirements_path, "utf-8").split("\n");
|
107 |
+
|
108 |
+
const pkg_index = requirements.findIndex((line) => {
|
109 |
+
const m = line.trim().match(RE_PKG_NAME);
|
110 |
+
if (!m) return false;
|
111 |
+
return m[0] === pkg_to_bump;
|
112 |
+
});
|
113 |
+
|
114 |
+
if (pkg_index !== -1) {
|
115 |
+
requirements[pkg_index] = `${pkg_to_bump}==${version}`;
|
116 |
+
writeFileSync(requirements_path, requirements.join("\n"));
|
117 |
+
}
|
118 |
+
}
|
119 |
+
}
|
120 |
+
}
|
121 |
+
|
122 |
+
run();
|
.config/.prettierignore
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
**/js/app/public/**
|
2 |
+
**/pnpm-workspace.yaml
|
3 |
+
**/js/app/dist/**
|
4 |
+
**/js/wasm/dist/**
|
5 |
+
**/client/js/dist/**
|
6 |
+
**/js/lite/dist/**
|
7 |
+
**/pnpm-lock.yaml
|
8 |
+
**/js/plot/src/Plot.svelte
|
9 |
+
**/.svelte-kit/**
|
10 |
+
**/demo/**
|
11 |
+
**/gradio/**
|
12 |
+
**/.pnpm-store/**
|
13 |
+
**/.venv/**
|
14 |
+
**/.github/**
|
15 |
+
/guides/**
|
16 |
+
**/.mypy_cache/**
|
17 |
+
!test-strategy.md
|
18 |
+
**/js/_space-test/**
|
19 |
+
../js/app/src/lite/theme.css
|
20 |
+
../js/storybook/theme.css
|
21 |
+
**/gradio_cached_examples/**
|
22 |
+
**/storybook-static/**
|
23 |
+
**/.vscode/**
|
24 |
+
sweep.yaml
|
25 |
+
**/.vercel/**
|
26 |
+
**/build/**
|
27 |
+
**/*.md
|
28 |
+
**/src/lib/json/**/*
|
29 |
+
**/playwright/.cache/**/*
|
30 |
+
**/theme/src/pollen.css
|
.config/.prettierrc.json
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"useTabs": true,
|
3 |
+
"singleQuote": false,
|
4 |
+
"trailingComma": "none",
|
5 |
+
"printWidth": 80,
|
6 |
+
"plugins": ["prettier-plugin-svelte"]
|
7 |
+
}
|
.config/basevite.config.ts
ADDED
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { defineConfig } from "vite";
|
2 |
+
import { svelte } from "@sveltejs/vite-plugin-svelte";
|
3 |
+
import sveltePreprocess from "svelte-preprocess";
|
4 |
+
// @ts-ignore
|
5 |
+
import custom_media from "postcss-custom-media";
|
6 |
+
import global_data from "@csstools/postcss-global-data";
|
7 |
+
// @ts-ignore
|
8 |
+
import prefixer from "postcss-prefix-selector";
|
9 |
+
import { readFileSync } from "fs";
|
10 |
+
import { join } from "path";
|
11 |
+
import { fileURLToPath } from "url";
|
12 |
+
|
13 |
+
const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
14 |
+
const version_path = join(__dirname, "..", "gradio", "package.json");
|
15 |
+
const theme_token_path = join(
|
16 |
+
__dirname,
|
17 |
+
"..",
|
18 |
+
"js",
|
19 |
+
"theme",
|
20 |
+
"src",
|
21 |
+
"tokens.css"
|
22 |
+
);
|
23 |
+
|
24 |
+
const version = JSON.parse(readFileSync(version_path, { encoding: "utf-8" }))
|
25 |
+
.version.trim()
|
26 |
+
.replace(/\./g, "-");
|
27 |
+
|
28 |
+
//@ts-ignore
|
29 |
+
export default defineConfig(({ mode }) => {
|
30 |
+
const production = mode === "production";
|
31 |
+
|
32 |
+
return {
|
33 |
+
server: {
|
34 |
+
port: 9876
|
35 |
+
},
|
36 |
+
|
37 |
+
build: {
|
38 |
+
sourcemap: false,
|
39 |
+
target: "esnext",
|
40 |
+
minify: production
|
41 |
+
},
|
42 |
+
define: {
|
43 |
+
BUILD_MODE: production ? JSON.stringify("prod") : JSON.stringify("dev"),
|
44 |
+
BACKEND_URL: production
|
45 |
+
? JSON.stringify("")
|
46 |
+
: JSON.stringify("http://localhost:7860/"),
|
47 |
+
GRADIO_VERSION: JSON.stringify(version)
|
48 |
+
},
|
49 |
+
css: {
|
50 |
+
postcss: {
|
51 |
+
plugins: [
|
52 |
+
prefixer({
|
53 |
+
prefix: `.gradio-container-${version}`,
|
54 |
+
// @ts-ignore
|
55 |
+
transform(prefix, selector, prefixedSelector, fileName) {
|
56 |
+
if (selector.indexOf("gradio-container") > -1) {
|
57 |
+
return prefix;
|
58 |
+
} else if (
|
59 |
+
selector.indexOf(":root") > -1 ||
|
60 |
+
selector.indexOf("dark") > -1 ||
|
61 |
+
fileName.indexOf(".svelte") > -1
|
62 |
+
) {
|
63 |
+
return selector;
|
64 |
+
}
|
65 |
+
return prefixedSelector;
|
66 |
+
}
|
67 |
+
}),
|
68 |
+
custom_media()
|
69 |
+
]
|
70 |
+
}
|
71 |
+
},
|
72 |
+
plugins: [
|
73 |
+
svelte({
|
74 |
+
inspector: true,
|
75 |
+
compilerOptions: {
|
76 |
+
dev: !production
|
77 |
+
},
|
78 |
+
hot: !process.env.VITEST && !production,
|
79 |
+
preprocess: sveltePreprocess({
|
80 |
+
postcss: {
|
81 |
+
plugins: [
|
82 |
+
global_data({ files: [theme_token_path] }),
|
83 |
+
custom_media()
|
84 |
+
]
|
85 |
+
}
|
86 |
+
})
|
87 |
+
})
|
88 |
+
]
|
89 |
+
};
|
90 |
+
});
|
.config/copy_frontend.py
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
import shutil
|
4 |
+
import pathlib
|
5 |
+
from typing import Any
|
6 |
+
|
7 |
+
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
|
8 |
+
|
9 |
+
|
10 |
+
def copy_js_code(root: str | pathlib.Path):
|
11 |
+
NOT_COMPONENT = [
|
12 |
+
"app",
|
13 |
+
"node_modules",
|
14 |
+
"storybook",
|
15 |
+
"playwright-report",
|
16 |
+
"workbench",
|
17 |
+
"tooltils",
|
18 |
+
]
|
19 |
+
for entry in (pathlib.Path(root) / "js").iterdir():
|
20 |
+
if (
|
21 |
+
entry.is_dir()
|
22 |
+
and not str(entry.name).startswith("_")
|
23 |
+
and not str(entry.name) in NOT_COMPONENT
|
24 |
+
):
|
25 |
+
|
26 |
+
def ignore(s, names):
|
27 |
+
ignored = []
|
28 |
+
for n in names:
|
29 |
+
if (
|
30 |
+
n.startswith("CHANGELOG")
|
31 |
+
or n.startswith("README.md")
|
32 |
+
or n.startswith("node_modules")
|
33 |
+
or ".test." in n
|
34 |
+
or ".stories." in n
|
35 |
+
or ".spec." in n
|
36 |
+
):
|
37 |
+
ignored.append(n)
|
38 |
+
return ignored
|
39 |
+
shutil.copytree(
|
40 |
+
str(entry),
|
41 |
+
str(pathlib.Path("gradio") / "_frontend_code" / entry.name),
|
42 |
+
ignore=ignore,
|
43 |
+
dirs_exist_ok=True,
|
44 |
+
)
|
45 |
+
shutil.copytree(
|
46 |
+
str(pathlib.Path(root) / "client" / "js"),
|
47 |
+
str(pathlib.Path("gradio") / "_frontend_code" / "client"),
|
48 |
+
ignore=lambda d, names: ["node_modules"],
|
49 |
+
dirs_exist_ok=True,
|
50 |
+
)
|
51 |
+
|
52 |
+
|
53 |
+
class BuildHook(BuildHookInterface):
|
54 |
+
def initialize(self, version: str, build_data: dict[str, Any]) -> None:
|
55 |
+
copy_js_code(self.root)
|
56 |
+
|
57 |
+
|
58 |
+
if __name__ == "__main__":
|
59 |
+
copy_js_code(pathlib.Path("..").resolve())
|
.config/eslint.config.js
ADDED
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import globals from "globals";
|
2 |
+
import ts_plugin from "@typescript-eslint/eslint-plugin";
|
3 |
+
import js_plugin from "@eslint/js";
|
4 |
+
|
5 |
+
import typescriptParser from "@typescript-eslint/parser";
|
6 |
+
import sveltePlugin from "eslint-plugin-svelte";
|
7 |
+
import svelteParser from "svelte-eslint-parser";
|
8 |
+
|
9 |
+
const ts_rules_disabled = Object.fromEntries(
|
10 |
+
Object.keys(ts_plugin.rules).map((rule) => [
|
11 |
+
`@typescript-eslint/${rule}`,
|
12 |
+
"off"
|
13 |
+
])
|
14 |
+
);
|
15 |
+
const js_rules_disabled = Object.fromEntries(
|
16 |
+
Object.keys(js_plugin.configs.all.rules).map((rule) => [rule, "off"])
|
17 |
+
);
|
18 |
+
|
19 |
+
const js_rules = {
|
20 |
+
...js_rules_disabled,
|
21 |
+
"no-console": ["error", { allow: ["warn", "error", "debug", "info"] }],
|
22 |
+
"no-constant-condition": "error",
|
23 |
+
"no-dupe-args": "error",
|
24 |
+
"no-extra-boolean-cast": "error",
|
25 |
+
"no-unexpected-multiline": "error",
|
26 |
+
"no-unreachable": "error",
|
27 |
+
"valid-jsdoc": "error",
|
28 |
+
"array-callback-return": "error",
|
29 |
+
complexity: "error",
|
30 |
+
"no-else-return": "error",
|
31 |
+
"no-useless-return": "error",
|
32 |
+
"no-undef": "error",
|
33 |
+
"valid-jsdoc": [
|
34 |
+
"error",
|
35 |
+
{
|
36 |
+
requireReturn: false,
|
37 |
+
requireParamDescription: true,
|
38 |
+
requireReturnDescription: true,
|
39 |
+
requireReturnType: false,
|
40 |
+
requireParamType: false
|
41 |
+
}
|
42 |
+
]
|
43 |
+
};
|
44 |
+
|
45 |
+
const ts_rules = {
|
46 |
+
...ts_rules_disabled,
|
47 |
+
"@typescript-eslint/adjacent-overload-signatures": "error",
|
48 |
+
"@typescript-eslint/explicit-function-return-type": [
|
49 |
+
"error",
|
50 |
+
{ allowExpressions: true }
|
51 |
+
],
|
52 |
+
"@typescript-eslint/consistent-type-exports": "error",
|
53 |
+
"@typescript-eslint/ban-types": "error",
|
54 |
+
"@typescript-eslint/array-type": "error",
|
55 |
+
"@typescript-eslint/no-inferrable-types": "error"
|
56 |
+
};
|
57 |
+
|
58 |
+
const { browser, es2021, node } = globals;
|
59 |
+
|
60 |
+
export default [
|
61 |
+
{
|
62 |
+
ignores: [
|
63 |
+
".svelte-kit/**/*",
|
64 |
+
"**/node_modules/**",
|
65 |
+
"**/dist/**",
|
66 |
+
"**/.config/*",
|
67 |
+
"**/*.spec.ts",
|
68 |
+
"**/*.test.ts",
|
69 |
+
"**/*.node-test.ts",
|
70 |
+
"js/app/test/**/*",
|
71 |
+
"**/*vite.config.ts",
|
72 |
+
"**/_website/**/*",
|
73 |
+
"**/_spaces-test/**/*",
|
74 |
+
"**/preview/test/**/*"
|
75 |
+
]
|
76 |
+
},
|
77 |
+
{
|
78 |
+
files: ["**/*.js", "**/*.cjs"],
|
79 |
+
languageOptions: {
|
80 |
+
globals: {
|
81 |
+
...browser,
|
82 |
+
...es2021,
|
83 |
+
...node
|
84 |
+
}
|
85 |
+
},
|
86 |
+
|
87 |
+
plugins: {
|
88 |
+
"eslint:recommended": js_plugin
|
89 |
+
},
|
90 |
+
rules: js_rules
|
91 |
+
},
|
92 |
+
|
93 |
+
{
|
94 |
+
files: ["**/*.ts"],
|
95 |
+
languageOptions: {
|
96 |
+
parser: typescriptParser,
|
97 |
+
parserOptions: {
|
98 |
+
project: "./tsconfig.json",
|
99 |
+
extraFileExtensions: [".svelte"]
|
100 |
+
},
|
101 |
+
globals: {
|
102 |
+
...browser,
|
103 |
+
...es2021,
|
104 |
+
...node
|
105 |
+
}
|
106 |
+
},
|
107 |
+
|
108 |
+
plugins: {
|
109 |
+
"@typescript-eslint": ts_plugin,
|
110 |
+
"eslint:recommended": js_plugin
|
111 |
+
},
|
112 |
+
rules: {
|
113 |
+
...ts_rules,
|
114 |
+
...js_rules,
|
115 |
+
"no-undef": "off"
|
116 |
+
}
|
117 |
+
},
|
118 |
+
{
|
119 |
+
files: ["**/client/js/**"],
|
120 |
+
languageOptions: {
|
121 |
+
parserOptions: {
|
122 |
+
project: "./client/js/tsconfig.json"
|
123 |
+
}
|
124 |
+
}
|
125 |
+
},
|
126 |
+
{
|
127 |
+
files: ["**/*.svelte"],
|
128 |
+
languageOptions: {
|
129 |
+
parser: svelteParser,
|
130 |
+
parserOptions: {
|
131 |
+
parser: typescriptParser,
|
132 |
+
project: "./tsconfig.json",
|
133 |
+
extraFileExtensions: [".svelte"]
|
134 |
+
},
|
135 |
+
globals: {
|
136 |
+
...browser,
|
137 |
+
...es2021
|
138 |
+
}
|
139 |
+
},
|
140 |
+
plugins: {
|
141 |
+
svelte: sveltePlugin,
|
142 |
+
"@typescript-eslint": ts_plugin,
|
143 |
+
"eslint:recommended": js_plugin
|
144 |
+
},
|
145 |
+
rules: {
|
146 |
+
...ts_rules,
|
147 |
+
...js_rules,
|
148 |
+
...sveltePlugin.configs.recommended.rules,
|
149 |
+
"svelte/no-at-html-tags": "off",
|
150 |
+
"no-undef": "off"
|
151 |
+
}
|
152 |
+
}
|
153 |
+
];
|
.config/playwright-ct.config.ts
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { defineConfig, devices } from "@playwright/experimental-ct-svelte";
|
2 |
+
import config from "./basevite.config";
|
3 |
+
|
4 |
+
/**
|
5 |
+
* See https://playwright.dev/docs/test-configuration.
|
6 |
+
*/
|
7 |
+
export default defineConfig({
|
8 |
+
testDir: "../",
|
9 |
+
/* The base directory, relative to the config file, for snapshot files created with toMatchSnapshot and toHaveScreenshot. */
|
10 |
+
snapshotDir: "./__snapshots__",
|
11 |
+
/* Maximum time one test can run for. */
|
12 |
+
timeout: 10 * 1000,
|
13 |
+
/* Run tests in files in parallel */
|
14 |
+
fullyParallel: true,
|
15 |
+
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
16 |
+
forbidOnly: !!process.env.CI,
|
17 |
+
/* Retry on CI only */
|
18 |
+
retries: process.env.CI ? 2 : 0,
|
19 |
+
/* Opt out of parallel tests on CI. */
|
20 |
+
workers: process.env.CI ? 1 : undefined,
|
21 |
+
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
22 |
+
reporter: "html",
|
23 |
+
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
24 |
+
use: {
|
25 |
+
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
26 |
+
trace: "on-first-retry",
|
27 |
+
|
28 |
+
/* Port to use for Playwright component endpoint. */
|
29 |
+
ctPort: 3100,
|
30 |
+
ctViteConfig: config({ mode: "development" })
|
31 |
+
},
|
32 |
+
testMatch: "*.component.spec.ts",
|
33 |
+
|
34 |
+
/* Configure projects for major browsers */
|
35 |
+
projects: [
|
36 |
+
{
|
37 |
+
name: "chromium",
|
38 |
+
use: { ...devices["Desktop Chrome"] }
|
39 |
+
}
|
40 |
+
]
|
41 |
+
});
|
.config/playwright-setup.js
ADDED
@@ -0,0 +1,152 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { spawn } from "node:child_process";
|
2 |
+
import { join, basename } from "path";
|
3 |
+
import { fileURLToPath } from "url";
|
4 |
+
import { readdirSync, writeFileSync } from "fs";
|
5 |
+
import net from "net";
|
6 |
+
|
7 |
+
import kl from "kleur";
|
8 |
+
|
9 |
+
const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
10 |
+
const TEST_APP_PATH = join(__dirname, "./test.py");
|
11 |
+
const TEST_FILES_PATH = join(__dirname, "..", "js", "app", "test");
|
12 |
+
const ROOT = join(__dirname, "..");
|
13 |
+
|
14 |
+
const test_files = readdirSync(TEST_FILES_PATH)
|
15 |
+
.filter(
|
16 |
+
(f) =>
|
17 |
+
f.endsWith("spec.ts") &&
|
18 |
+
!f.endsWith(".skip.spec.ts") &&
|
19 |
+
!f.endsWith(".component.spec.ts")
|
20 |
+
)
|
21 |
+
.map((f) => basename(f, ".spec.ts"));
|
22 |
+
|
23 |
+
export default async function global_setup() {
|
24 |
+
const verbose = process.env.GRADIO_TEST_VERBOSE;
|
25 |
+
|
26 |
+
const port = await find_free_port(7860, 8860);
|
27 |
+
process.env.GRADIO_E2E_TEST_PORT = port;
|
28 |
+
|
29 |
+
process.stdout.write(kl.yellow("\nCreating test gradio app.\n\n"));
|
30 |
+
|
31 |
+
const test_app = make_app(test_files, port);
|
32 |
+
process.stdout.write(kl.yellow("App created. Starting test server.\n\n"));
|
33 |
+
|
34 |
+
process.stdout.write(kl.bgBlue(" =========================== \n"));
|
35 |
+
process.stdout.write(kl.bgBlue(" === PYTHON STARTUP LOGS === \n"));
|
36 |
+
process.stdout.write(kl.bgBlue(" =========================== \n\n"));
|
37 |
+
|
38 |
+
writeFileSync(TEST_APP_PATH, test_app);
|
39 |
+
|
40 |
+
const app = await spawn_gradio_app(TEST_APP_PATH, port, verbose);
|
41 |
+
|
42 |
+
process.stdout.write(
|
43 |
+
kl.green(`\n\nServer started. Running tests on port ${port}.\n`)
|
44 |
+
);
|
45 |
+
|
46 |
+
return () => {
|
47 |
+
process.stdout.write(kl.green(`\nTests complete, cleaning up!\n`));
|
48 |
+
|
49 |
+
kill_process(app);
|
50 |
+
};
|
51 |
+
}
|
52 |
+
const INFO_RE = /^INFO:/;
|
53 |
+
|
54 |
+
function spawn_gradio_app(app, port, verbose) {
|
55 |
+
const PORT_RE = new RegExp(`:${port}`);
|
56 |
+
|
57 |
+
return new Promise((res, rej) => {
|
58 |
+
const _process = spawn(`python`, [app], {
|
59 |
+
shell: true,
|
60 |
+
stdio: "pipe",
|
61 |
+
cwd: ROOT,
|
62 |
+
env: {
|
63 |
+
...process.env,
|
64 |
+
GRADIO_SERVER_PORT: `7879`,
|
65 |
+
PYTHONUNBUFFERED: "true",
|
66 |
+
GRADIO_ANALYTICS_ENABLED: "False"
|
67 |
+
}
|
68 |
+
});
|
69 |
+
_process.stdout.setEncoding("utf8");
|
70 |
+
|
71 |
+
function std_out(data) {
|
72 |
+
const _data = data.toString();
|
73 |
+
const is_info = INFO_RE.test(_data);
|
74 |
+
|
75 |
+
if (is_info) {
|
76 |
+
process.stdout.write(kl.yellow(_data));
|
77 |
+
}
|
78 |
+
|
79 |
+
if (!is_info) {
|
80 |
+
process.stdout.write(`${_data}\n`);
|
81 |
+
}
|
82 |
+
|
83 |
+
if (PORT_RE.test(_data)) {
|
84 |
+
process.stdout.write(kl.bgBlue("\n =========== END =========== "));
|
85 |
+
|
86 |
+
res(_process);
|
87 |
+
|
88 |
+
if (!verbose) {
|
89 |
+
_process.stdout.off("data", std_out);
|
90 |
+
_process.stderr.off("data", std_out);
|
91 |
+
}
|
92 |
+
}
|
93 |
+
}
|
94 |
+
|
95 |
+
_process.stdout.on("data", std_out);
|
96 |
+
_process.stderr.on("data", std_out);
|
97 |
+
_process.on("exit", () => kill_process(_process));
|
98 |
+
_process.on("close", () => kill_process(_process));
|
99 |
+
_process.on("disconnect", () => kill_process(_process));
|
100 |
+
});
|
101 |
+
}
|
102 |
+
|
103 |
+
function kill_process(process) {
|
104 |
+
process.kill("SIGKILL");
|
105 |
+
}
|
106 |
+
|
107 |
+
function make_app(demos, port) {
|
108 |
+
return `import gradio as gr
|
109 |
+
import uvicorn
|
110 |
+
from fastapi import FastAPI
|
111 |
+
import gradio as gr
|
112 |
+
${demos.map((d) => `from demo.${d}.run import demo as ${d}`).join("\n")}
|
113 |
+
|
114 |
+
app = FastAPI()
|
115 |
+
${demos
|
116 |
+
.map((d) => `app = gr.mount_gradio_app(app, ${d}, path="/${d}")`)
|
117 |
+
.join("\n")}
|
118 |
+
|
119 |
+
config = uvicorn.Config(app, port=${port}, log_level="info")
|
120 |
+
server = uvicorn.Server(config=config)
|
121 |
+
server.run()`;
|
122 |
+
}
|
123 |
+
|
124 |
+
export async function find_free_port(start_port, end_port) {
|
125 |
+
for (let port = start_port; port < end_port; port++) {
|
126 |
+
if (await is_free_port(port)) {
|
127 |
+
return port;
|
128 |
+
}
|
129 |
+
}
|
130 |
+
|
131 |
+
throw new Error(
|
132 |
+
`Could not find free ports: there were not enough ports available.`
|
133 |
+
);
|
134 |
+
}
|
135 |
+
|
136 |
+
export function is_free_port(port) {
|
137 |
+
return new Promise((accept, reject) => {
|
138 |
+
const sock = net.createConnection(port, "127.0.0.1");
|
139 |
+
sock.once("connect", () => {
|
140 |
+
sock.end();
|
141 |
+
accept(false);
|
142 |
+
});
|
143 |
+
sock.once("error", (e) => {
|
144 |
+
sock.destroy();
|
145 |
+
if (e.code === "ECONNREFUSED") {
|
146 |
+
accept(true);
|
147 |
+
} else {
|
148 |
+
reject(e);
|
149 |
+
}
|
150 |
+
});
|
151 |
+
});
|
152 |
+
}
|
.config/playwright.config.js
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { defineConfig } from "@playwright/test";
|
2 |
+
|
3 |
+
export default defineConfig({
|
4 |
+
use: {
|
5 |
+
screenshot: "only-on-failure",
|
6 |
+
trace: "retain-on-failure",
|
7 |
+
permissions: ["clipboard-read", "clipboard-write", "microphone"],
|
8 |
+
bypassCSP: true,
|
9 |
+
launchOptions: {
|
10 |
+
args: [
|
11 |
+
"--disable-web-security",
|
12 |
+
"--use-fake-device-for-media-stream",
|
13 |
+
"--use-fake-ui-for-media-stream",
|
14 |
+
"--use-file-for-fake-audio-capture=../gradio/test_data/test_audio.wav"
|
15 |
+
]
|
16 |
+
}
|
17 |
+
},
|
18 |
+
expect: { timeout: 60000 },
|
19 |
+
timeout: 90000,
|
20 |
+
testMatch: /.*.spec.ts/,
|
21 |
+
testDir: "..",
|
22 |
+
globalSetup: "./playwright-setup.js",
|
23 |
+
workers: process.env.CI ? 1 : undefined
|
24 |
+
});
|
.config/playwright/index.html
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!doctype html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8" />
|
5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
6 |
+
<title>Testing Page</title>
|
7 |
+
</head>
|
8 |
+
<body>
|
9 |
+
<div id="root"></div>
|
10 |
+
<script type="module" src="./index.ts"></script>
|
11 |
+
</body>
|
12 |
+
</html>
|
.config/playwright/index.ts
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
// Import styles, initialize component theme here.
|
2 |
+
// import '../src/common.css';
|
.config/postcss.config.cjs
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const tailwindcss = require("tailwindcss");
|
2 |
+
const autoprefixer = require("autoprefixer");
|
3 |
+
const nested = require("tailwindcss/nesting");
|
4 |
+
const tw_config = require("./tailwind.config.cjs");
|
5 |
+
|
6 |
+
module.exports = {
|
7 |
+
plugins: [nested, tailwindcss(tw_config), autoprefixer]
|
8 |
+
};
|
.config/setup_vite_tests.ts
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import type { TestingLibraryMatchers } from "@testing-library/jest-dom/matchers";
|
2 |
+
import matchers from "@testing-library/jest-dom/matchers";
|
3 |
+
import { expect } from "vitest";
|
4 |
+
|
5 |
+
declare module "vitest" {
|
6 |
+
interface Assertion<T = any>
|
7 |
+
extends jest.Matchers<void, T>,
|
8 |
+
TestingLibraryMatchers<T, void> {}
|
9 |
+
}
|
10 |
+
|
11 |
+
expect.extend(matchers);
|
.config/tailwind.config.cjs
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
module.exports = {
|
2 |
+
content: [
|
3 |
+
"./src/**/*.{html,js,svelte,ts}",
|
4 |
+
"**/@gradio/**/*.{html,js,svelte,ts}"
|
5 |
+
],
|
6 |
+
|
7 |
+
theme: {
|
8 |
+
extend: {}
|
9 |
+
},
|
10 |
+
|
11 |
+
plugins: [require("@tailwindcss/forms")]
|
12 |
+
};
|
.config/vitest.config.ts
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
import config from "../js/app/vite.config";
|
2 |
+
|
3 |
+
export default config;
|
.devcontainer/devcontainer.json
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// See https://containers.dev
|
2 |
+
{
|
3 |
+
"name": "Python 3",
|
4 |
+
"image": "mcr.microsoft.com/devcontainers/python:0-3.9",
|
5 |
+
|
6 |
+
// See https://containers.dev/features
|
7 |
+
"features": {
|
8 |
+
"ghcr.io/devcontainers/features/git:1": {},
|
9 |
+
"ghcr.io/devcontainers/features/node:1": {},
|
10 |
+
"ghcr.io/devcontainers-contrib/features/ffmpeg-apt-get:1": {}
|
11 |
+
},
|
12 |
+
|
13 |
+
"hostRequirements": {
|
14 |
+
"cpus": 4,
|
15 |
+
"memory": "8gb",
|
16 |
+
"storage": "32gb"
|
17 |
+
},
|
18 |
+
|
19 |
+
"customizations": {
|
20 |
+
"vscode": {
|
21 |
+
"extensions": [
|
22 |
+
"ms-python.python",
|
23 |
+
"ms-python.vscode-pylance",
|
24 |
+
"ms-python.black-formatter",
|
25 |
+
"ms-toolsai.jupyter",
|
26 |
+
"esbenp.prettier-vscode",
|
27 |
+
"svelte.svelte-vscode",
|
28 |
+
"phoenisx.cssvar"
|
29 |
+
],
|
30 |
+
"remote.autoForwardPorts": false
|
31 |
+
}
|
32 |
+
},
|
33 |
+
|
34 |
+
"forwardPorts": [7860, 9876],
|
35 |
+
"portsAttributes": {
|
36 |
+
"7860": { "label": "gradio port" },
|
37 |
+
"9876": { "label": "gradio dev port" }
|
38 |
+
},
|
39 |
+
|
40 |
+
"postCreateCommand": "export NODE_OPTIONS=\"--max-old-space-size=8192\" && chmod +x scripts/install_gradio.sh scripts/install_test_requirements.sh scripts/build_frontend.sh && ./scripts/install_gradio.sh && ./scripts/install_test_requirements.sh && ./scripts/build_frontend.sh"
|
41 |
+
}
|
.dockerignore
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Python build
|
2 |
+
.eggs/
|
3 |
+
gradio.egg-info/*
|
4 |
+
!gradio.egg-info/requires.txt
|
5 |
+
!gradio.egg-info/PKG-INFO
|
6 |
+
dist/
|
7 |
+
*.pyc
|
8 |
+
__pycache__/
|
9 |
+
*.py[cod]
|
10 |
+
*$py.class
|
11 |
+
build/
|
12 |
+
|
13 |
+
# JS build
|
14 |
+
gradio/templates/frontend/static
|
15 |
+
gradio/templates/frontend/cdn
|
16 |
+
|
17 |
+
# Secrets
|
18 |
+
.env
|
19 |
+
|
20 |
+
# Gradio run artifacts
|
21 |
+
*.db
|
22 |
+
*.sqlite3
|
23 |
+
gradio/launches.json
|
24 |
+
|
25 |
+
# Tests
|
26 |
+
.coverage
|
27 |
+
coverage.xml
|
28 |
+
test.txt
|
29 |
+
|
30 |
+
# Demos
|
31 |
+
demo/tmp.zip
|
32 |
+
demo/flagged
|
33 |
+
demo/files/*.avi
|
34 |
+
demo/files/*.mp4
|
35 |
+
|
36 |
+
# Etc
|
37 |
+
.idea/*
|
38 |
+
.DS_Store
|
39 |
+
*.bak
|
40 |
+
workspace.code-workspace
|
.editorconfig
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
root = true
|
3 |
+
|
4 |
+
[{js/**,client/js/**}]
|
5 |
+
end_of_line = lf
|
6 |
+
insert_final_newline = true
|
7 |
+
indent_style = tab
|
8 |
+
tab_width = 2
|
.git-blame-ignore-revs
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# https://github.com/gradio-app/gradio/pull/4487 - refactor components.py to separate files
|
2 |
+
69f36f98535c904e7cac2b4942cecc747ed7443c
|
3 |
+
# Format the codebase
|
4 |
+
cc0cff893f9d7d472788adc2510c123967b384fe
|
5 |
+
# Switch from black to ruff
|
6 |
+
8a70e83db9c7751b46058cdd2514e6bddeef6210
|
7 |
+
# format (#4810)
|
8 |
+
7fa5e766ce0f89f1fb84c329e62c9df9c332120a
|
9 |
+
# lint website
|
10 |
+
4bf301324b3b180fa32166ff1774312b01334c88
|
11 |
+
# format frontend with prettier
|
12 |
+
980b9f60eb49ed81e4957debe7b23a559a4d4b51
|
13 |
+
# Refactor component directories (#5074)
|
14 |
+
1419538ea795caa391e3de809379f10639e9e764
|
.gitattributes
CHANGED
@@ -33,3 +33,20 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
demo/blocks_flipper/screenshot.gif filter=lfs diff=lfs merge=lfs -text
|
37 |
+
demo/blocks_neural_instrument_coding/sax.wav filter=lfs diff=lfs merge=lfs -text
|
38 |
+
demo/calculator/screenshot.gif filter=lfs diff=lfs merge=lfs -text
|
39 |
+
demo/dataset/files/world.mp4 filter=lfs diff=lfs merge=lfs -text
|
40 |
+
demo/fake_diffusion_with_gif/image.gif filter=lfs diff=lfs merge=lfs -text
|
41 |
+
demo/hello_world_2/screenshot.gif filter=lfs diff=lfs merge=lfs -text
|
42 |
+
demo/hello_world_4/screenshot.gif filter=lfs diff=lfs merge=lfs -text
|
43 |
+
demo/image_mod/screenshot.png filter=lfs diff=lfs merge=lfs -text
|
44 |
+
demo/kitchen_sink/files/world.mp4 filter=lfs diff=lfs merge=lfs -text
|
45 |
+
demo/sales_projections/screenshot.gif filter=lfs diff=lfs merge=lfs -text
|
46 |
+
demo/sepia_filter/screenshot.gif filter=lfs diff=lfs merge=lfs -text
|
47 |
+
demo/unispeech-speaker-verification/samples/kirsten_dunst.wav filter=lfs diff=lfs merge=lfs -text
|
48 |
+
demo/video_component/files/world.mp4 filter=lfs diff=lfs merge=lfs -text
|
49 |
+
guides/assets/hf_demo.mp4 filter=lfs diff=lfs merge=lfs -text
|
50 |
+
guides/cn/assets/hf_demo.mp4 filter=lfs diff=lfs merge=lfs -text
|
51 |
+
js/app/test/files/file_test.ogg filter=lfs diff=lfs merge=lfs -text
|
52 |
+
test/test_files/rotated_image.jpeg filter=lfs diff=lfs merge=lfs -text
|
.github/ISSUE_TEMPLATE/bug_report_template.yml
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: "\U0001F41E Bug report"
|
2 |
+
description: Report a bug on Gradio
|
3 |
+
labels: ["bug"]
|
4 |
+
body:
|
5 |
+
- type: markdown
|
6 |
+
attributes:
|
7 |
+
value: |
|
8 |
+
Thanks for taking the time to fill out this bug report! Before you get started, please [search to see](https://github.com/gradio-app/gradio/issues) if an issue already exists for the bug you encountered
|
9 |
+
- type: textarea
|
10 |
+
id: bug-description
|
11 |
+
attributes:
|
12 |
+
label: Describe the bug
|
13 |
+
description: Please provide a concise description of what the bug is, in clear English. If you intend to submit a PR for this issue, tell us in the description.
|
14 |
+
placeholder: Bug description
|
15 |
+
validations:
|
16 |
+
required: true
|
17 |
+
- type: checkboxes
|
18 |
+
attributes:
|
19 |
+
label: Have you searched existing issues? 🔎
|
20 |
+
description: Please search to see if an issue already exists for the issue you encountered.
|
21 |
+
options:
|
22 |
+
- label: I have searched and found no existing issues
|
23 |
+
required: true
|
24 |
+
- type: textarea
|
25 |
+
id: reproduction
|
26 |
+
attributes:
|
27 |
+
label: Reproduction
|
28 |
+
description: Please provide a minimal example, with code, that can be run to reproduce the issue. Do NOT provide screenshots of code, or link to external repos or applications. Use ``` to format code blocks.
|
29 |
+
placeholder: Reproduction
|
30 |
+
value: |
|
31 |
+
```python
|
32 |
+
import gradio as gr
|
33 |
+
|
34 |
+
```
|
35 |
+
validations:
|
36 |
+
required: true
|
37 |
+
- type: textarea
|
38 |
+
id: screenshot
|
39 |
+
attributes:
|
40 |
+
label: Screenshot
|
41 |
+
description: If relevant, please include screenshot(s) of your Gradio app so that we can understand what the issue is.
|
42 |
+
- type: textarea
|
43 |
+
id: logs
|
44 |
+
attributes:
|
45 |
+
label: Logs
|
46 |
+
description: "Please include the full stacktrace of the errors you get from Python or Javascript. If you are running in a colab notebooks, you can get the logs with by setting `debug=True`, i.e: `gradio.Interface.launch(debug=True)`"
|
47 |
+
render: shell
|
48 |
+
- type: textarea
|
49 |
+
id: system-info
|
50 |
+
attributes:
|
51 |
+
label: System Info
|
52 |
+
description: Please ensure you are running the latest version of Gradio. You can get the Gradio version and all its dependencies by running `gradio environment`
|
53 |
+
render: shell
|
54 |
+
validations:
|
55 |
+
required: true
|
56 |
+
- type: dropdown
|
57 |
+
id: severity
|
58 |
+
attributes:
|
59 |
+
label: Severity
|
60 |
+
description: Select the severity of this issue
|
61 |
+
options:
|
62 |
+
- I can work around it
|
63 |
+
- Blocking usage of gradio
|
64 |
+
validations:
|
65 |
+
required: true
|
66 |
+
- type: markdown
|
67 |
+
attributes:
|
68 |
+
value: |
|
69 |
+
📌 Please ensure that you have filled all of the required sections above, and that the reproduction you have provided is [minimal, complete, and reproducible](https://stackoverflow.com/help/minimal-reproducible-example). Incomplete issues will be closed.
|
.github/ISSUE_TEMPLATE/config.yml
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
blank_issues_enabled: false
|
2 |
+
contact_links:
|
3 |
+
- name: 💡 General questions
|
4 |
+
url: https://discord.com/invite/feTf9x3ZSB
|
5 |
+
about: Have general questions about how to use Gradio? Please ask in our community Discord for quicker responses
|
.github/ISSUE_TEMPLATE/feature_request.md
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
name: ⚡ Feature request
|
3 |
+
about: Suggest an improvement or new feature or a new Guide for Gradio
|
4 |
+
title: ''
|
5 |
+
labels: ''
|
6 |
+
assignees: ''
|
7 |
+
|
8 |
+
---
|
9 |
+
- [ ] I have searched to see if a similar issue already exists.
|
10 |
+
|
11 |
+
|
12 |
+
**Is your feature request related to a problem? Please describe.**
|
13 |
+
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
14 |
+
|
15 |
+
**Describe the solution you'd like**
|
16 |
+
A clear and concise description of what you want to happen.
|
17 |
+
|
18 |
+
**Additional context**
|
19 |
+
Add any other context or screenshots about the feature request here.
|
.github/PULL_REQUEST_TEMPLATE.md
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
## Description
|
2 |
+
|
3 |
+
Please include a concise summary, in clear English, of the changes in this pull request. If it closes an issue, please mention it here.
|
4 |
+
|
5 |
+
Closes: #(issue)
|
6 |
+
|
7 |
+
## 🎯 PRs Should Target Issues
|
8 |
+
|
9 |
+
Before your create a PR, please check to see if there is [an existing issue](https://github.com/gradio-app/gradio/issues) for this change. If not, please create an issue before you create this PR, unless the fix is very small.
|
10 |
+
|
11 |
+
Not adhering to this guideline will result in the PR being closed.
|
12 |
+
|
13 |
+
## Tests
|
14 |
+
|
15 |
+
1. PRs will only be merged if tests pass on CI. To run the tests locally, please set up [your Gradio environment locally](https://github.com/gradio-app/gradio/blob/main/CONTRIBUTING.md) and run the tests: `bash scripts/run_all_tests.sh`
|
16 |
+
|
17 |
+
2. You may need to run the linters: `bash scripts/format_backend.sh` and `bash scripts/format_frontend.sh`
|
18 |
+
|
.github/actions/install-all-deps/action.yml
ADDED
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: 'install all deps'
|
2 |
+
description: 'Install all deps'
|
3 |
+
|
4 |
+
inputs:
|
5 |
+
always-install-pnpm:
|
6 |
+
description: 'Dictates whether or not we should install pnpm & dependencies, regardless of the cache'
|
7 |
+
default: 'false'
|
8 |
+
node_auth_token:
|
9 |
+
description: 'Node auth token'
|
10 |
+
default: ""
|
11 |
+
npm_token:
|
12 |
+
description: 'npm token'
|
13 |
+
default: ""
|
14 |
+
skip_build:
|
15 |
+
description: 'Skip build'
|
16 |
+
default: 'false'
|
17 |
+
|
18 |
+
runs:
|
19 |
+
using: "composite"
|
20 |
+
steps:
|
21 |
+
- name: Install Python
|
22 |
+
uses: actions/setup-python@v5
|
23 |
+
with:
|
24 |
+
python-version: 3.8
|
25 |
+
cache: pip
|
26 |
+
cache-dependency-path: |
|
27 |
+
client/python/requirements.txt
|
28 |
+
requirements.txt
|
29 |
+
test/requirements.txt
|
30 |
+
- name: Create env
|
31 |
+
shell: bash
|
32 |
+
run: |
|
33 |
+
python -m pip install --upgrade virtualenv
|
34 |
+
python -m virtualenv venv
|
35 |
+
- uses: actions/cache@v4
|
36 |
+
id: cache
|
37 |
+
with:
|
38 |
+
path: |
|
39 |
+
venv/*
|
40 |
+
key: gradio-lib-ubuntu-latest-pip-${{ hashFiles('client/python/requirements.txt') }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('test/requirements.txt') }}
|
41 |
+
- name: Install Gradio and Client Libraries Locally (Linux)
|
42 |
+
shell: bash
|
43 |
+
run: |
|
44 |
+
. venv/bin/activate
|
45 |
+
python -m pip install -e client/python
|
46 |
+
python -m pip install -e .
|
47 |
+
- name: Install ffmpeg
|
48 |
+
uses: FedericoCarboni/setup-ffmpeg@v2
|
49 |
+
- name: install-frontend
|
50 |
+
uses: "./.github/actions/install-frontend-deps"
|
51 |
+
with:
|
52 |
+
always-install-pnpm: ${{ inputs.always-install-pnpm }}
|
53 |
+
node_auth_token: ${{ inputs.node_auth_token }}
|
54 |
+
npm_token: ${{ inputs.npm_token }}
|
55 |
+
skip_build: ${{ inputs.skip_build }}
|
56 |
+
- name: generate json
|
57 |
+
shell: bash
|
58 |
+
run: |
|
59 |
+
. venv/bin/activate
|
60 |
+
python js/_website/generate_jsons/generate.py
|
.github/actions/install-frontend-deps/action.yml
ADDED
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: 'install frontend'
|
2 |
+
description: 'Install frontend deps'
|
3 |
+
|
4 |
+
inputs:
|
5 |
+
always-install-pnpm:
|
6 |
+
description: 'Dictates whether or not we should install pnpm & dependencies, regardless of the cache'
|
7 |
+
default: 'false'
|
8 |
+
node_auth_token:
|
9 |
+
description: 'Node auth token'
|
10 |
+
default: ""
|
11 |
+
npm_token:
|
12 |
+
description: 'npm token'
|
13 |
+
default: ""
|
14 |
+
skip_build:
|
15 |
+
description: 'Skip build'
|
16 |
+
default: 'false'
|
17 |
+
|
18 |
+
runs:
|
19 |
+
using: "composite"
|
20 |
+
steps:
|
21 |
+
- uses: actions/cache@v4
|
22 |
+
id: frontend-cache
|
23 |
+
with:
|
24 |
+
path: |
|
25 |
+
gradio/templates/*
|
26 |
+
key: gradio-lib-front-end-${{ hashFiles('js/**', 'client/js/**')}}
|
27 |
+
- name: Install pnpm
|
28 |
+
if: steps.frontend-cache.outputs.cache-hit != 'true' || inputs.always-install-pnpm == 'true'
|
29 |
+
uses: pnpm/action-setup@v2
|
30 |
+
with:
|
31 |
+
version: 8.9
|
32 |
+
- uses: actions/setup-node@v4
|
33 |
+
with:
|
34 |
+
node-version: 18
|
35 |
+
cache: pnpm
|
36 |
+
cache-dependency-path: pnpm-lock.yaml
|
37 |
+
env:
|
38 |
+
NODE_AUTH_TOKEN: ${{ inputs.always-install-pnpm }}
|
39 |
+
NPM_TOKEN: ${{ inputs.always-install-pnpm }}
|
40 |
+
- name: Install deps
|
41 |
+
if: steps.frontend-cache.outputs.cache-hit != 'true' || inputs.always-install-pnpm == 'true'
|
42 |
+
shell: bash
|
43 |
+
run: pnpm i --frozen-lockfile --ignore-scripts
|
44 |
+
- name: Build Css
|
45 |
+
if: inputs.always-install-pnpm == 'true'
|
46 |
+
shell: bash
|
47 |
+
run: pnpm css
|
48 |
+
- name: Build frontend
|
49 |
+
if: inputs.skip_build == 'false' && steps.frontend-cache.outputs.cache-hit != 'true'
|
50 |
+
shell: bash
|
51 |
+
run: pnpm build
|
.github/stale
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Number of days of inactivity before an issue becomes stale
|
2 |
+
daysUntilStale: 30
|
3 |
+
# Number of days of inactivity before a stale issue is closed
|
4 |
+
daysUntilClose: 7
|
5 |
+
# Issues with these labels will never be considered stale
|
6 |
+
exemptLabels:
|
7 |
+
- pinned
|
8 |
+
- security
|
9 |
+
# Label to use when marking an issue as stale
|
10 |
+
staleLabel: wontfix
|
11 |
+
# Comment to post when marking an issue as stale. Set to `false` to disable
|
12 |
+
markComment: >
|
13 |
+
This issue has been automatically marked as stale because it has not had
|
14 |
+
recent activity. It will be closed if no further activity occurs. Thank you
|
15 |
+
for your contributions.
|
16 |
+
# Comment to post when closing a stale issue. Set to `false` to disable
|
17 |
+
closeComment: false
|
.github/workflows/backend.yml
ADDED
@@ -0,0 +1,244 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: gradio-backend
|
2 |
+
|
3 |
+
on:
|
4 |
+
push:
|
5 |
+
branches:
|
6 |
+
- "main"
|
7 |
+
pull_request:
|
8 |
+
types: [opened, synchronize, reopened, labeled, unlabeled]
|
9 |
+
|
10 |
+
concurrency:
|
11 |
+
group: backend-${{ github.ref }}-${{ github.event_name == 'push' || github.event.inputs.fire != null }}
|
12 |
+
cancel-in-progress: true
|
13 |
+
|
14 |
+
env:
|
15 |
+
NODE_OPTIONS: "--max-old-space-size=4096"
|
16 |
+
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
17 |
+
|
18 |
+
jobs:
|
19 |
+
changes:
|
20 |
+
runs-on: ubuntu-latest
|
21 |
+
outputs:
|
22 |
+
python-client: ${{ steps.changes.outputs.python-client }}
|
23 |
+
gradio: ${{ steps.changes.outputs.gradio }}
|
24 |
+
test: ${{ steps.changes.outputs.test }}
|
25 |
+
workflows: ${{ steps.changes.outputs.workflows }}
|
26 |
+
scripts: ${{ steps.changes.outputs.scripts }}
|
27 |
+
client-scripts: ${{ steps.changes.outputs.client-scripts }}
|
28 |
+
steps:
|
29 |
+
- uses: actions/checkout@v3
|
30 |
+
- uses: dorny/paths-filter@v2
|
31 |
+
id: changes
|
32 |
+
with:
|
33 |
+
filters: |
|
34 |
+
python-client:
|
35 |
+
- 'client/python/**'
|
36 |
+
- 'gradio/**'
|
37 |
+
- 'requirements.txt'
|
38 |
+
gradio:
|
39 |
+
- 'client/python/**'
|
40 |
+
- 'gradio/**'
|
41 |
+
- 'requirements.txt'
|
42 |
+
test:
|
43 |
+
- 'test/**'
|
44 |
+
workflows:
|
45 |
+
- '.github/**'
|
46 |
+
scripts:
|
47 |
+
- 'scripts/**'
|
48 |
+
client-test:
|
49 |
+
needs: [changes]
|
50 |
+
if: needs.changes.outputs.python-client == 'true' || needs.changes.outputs.workflows == 'true'
|
51 |
+
strategy:
|
52 |
+
matrix:
|
53 |
+
os: ["ubuntu-latest", "windows-latest"]
|
54 |
+
test-type: ["not flaky", "flaky"]
|
55 |
+
python-version: ["3.8"]
|
56 |
+
exclude:
|
57 |
+
- os: ${{ github.event_name == 'pull_request' && contains( github.event.pull_request.labels.*.name, 'windows-tests') && 'dummy' || 'windows-latest' }}
|
58 |
+
- test-type: ${{ github.event_name == 'pull_request' && contains( github.event.pull_request.labels.*.name, 'flaky-tests') && 'dummy' || 'flaky' }}
|
59 |
+
runs-on: ${{ matrix.os }}
|
60 |
+
continue-on-error: true
|
61 |
+
steps:
|
62 |
+
- uses: actions/checkout@v3
|
63 |
+
- name: Install Python
|
64 |
+
uses: actions/setup-python@v5
|
65 |
+
with:
|
66 |
+
python-version: ${{ matrix.python-version }}
|
67 |
+
cache: pip
|
68 |
+
cache-dependency-path: |
|
69 |
+
client/python/requirements.txt
|
70 |
+
requirements.txt
|
71 |
+
test/requirements.txt
|
72 |
+
- name: Create env
|
73 |
+
run: |
|
74 |
+
python -m pip install --upgrade virtualenv
|
75 |
+
python -m virtualenv venv
|
76 |
+
- uses: actions/cache@master
|
77 |
+
id: cache
|
78 |
+
with:
|
79 |
+
path: |
|
80 |
+
client/python/venv/*
|
81 |
+
key: python-client-${{ runner.os }}-pip-${{ hashFiles('client/python/requirements.txt') }}-${{ hashFiles('client/python/test/requirements.txt') }}
|
82 |
+
- uses: actions/cache@v4
|
83 |
+
id: frontend-cache
|
84 |
+
with:
|
85 |
+
path: |
|
86 |
+
gradio/templates/*
|
87 |
+
key: gradio-lib-front-end-${{ hashFiles('js/**', 'client/js/**')}}
|
88 |
+
- name: Install pnpm
|
89 |
+
if: steps.frontend-cache.outputs.cache-hit != 'true'
|
90 |
+
uses: pnpm/action-setup@v2
|
91 |
+
with:
|
92 |
+
version: 8
|
93 |
+
- uses: actions/setup-node@v4
|
94 |
+
if: steps.frontend-cache.outputs.cache-hit != 'true'
|
95 |
+
with:
|
96 |
+
node-version: 18
|
97 |
+
cache: pnpm
|
98 |
+
cache-dependency-path: pnpm-lock.yaml
|
99 |
+
- name: Build Frontend
|
100 |
+
if: steps.frontend-cache.outputs.cache-hit != 'true'
|
101 |
+
run: |
|
102 |
+
pnpm i --frozen-lockfile --ignore-scripts
|
103 |
+
pnpm build
|
104 |
+
- name: Install Test Requirements (Linux)
|
105 |
+
if: runner.os == 'Linux'
|
106 |
+
run: |
|
107 |
+
. venv/bin/activate
|
108 |
+
python -m pip install -r client/python/test/requirements.txt
|
109 |
+
- name: Install ffmpeg
|
110 |
+
uses: FedericoCarboni/setup-ffmpeg@v2
|
111 |
+
- name: Install Gradio and Client Libraries Locally (Linux)
|
112 |
+
if: runner.os == 'Linux'
|
113 |
+
run: |
|
114 |
+
. venv/bin/activate
|
115 |
+
python -m pip install client/python
|
116 |
+
python -m pip install ".[oauth]"
|
117 |
+
- name: Lint (Linux)
|
118 |
+
if: runner.os == 'Linux'
|
119 |
+
run: |
|
120 |
+
. venv/bin/activate
|
121 |
+
bash client/python/scripts/lint.sh
|
122 |
+
- name: Tests (Linux)
|
123 |
+
if: runner.os == 'Linux'
|
124 |
+
run: |
|
125 |
+
. venv/bin/activate
|
126 |
+
python -m pytest -m "${{ matrix.test-type }}" client/python/
|
127 |
+
- name: Install Test Requirements (Windows)
|
128 |
+
if: runner.os == 'Windows'
|
129 |
+
run: |
|
130 |
+
venv\Scripts\activate
|
131 |
+
pip install -r client/python/test/requirements.txt
|
132 |
+
- name: Install Gradio and Client Libraries Locally (Windows)
|
133 |
+
if: runner.os == 'Windows'
|
134 |
+
run: |
|
135 |
+
venv\Scripts\activate
|
136 |
+
python -m pip install client/python
|
137 |
+
python -m pip install ".[oauth]"
|
138 |
+
- name: Tests (Windows)
|
139 |
+
if: runner.os == 'Windows'
|
140 |
+
run: |
|
141 |
+
venv\Scripts\activate
|
142 |
+
python -m pytest -m "${{ matrix.test-type }}" client/python/
|
143 |
+
test:
|
144 |
+
needs: [changes]
|
145 |
+
if: needs.changes.outputs.gradio == 'true' || needs.changes.outputs.workflows == 'true' || needs.changes.outputs.scripts == 'true' || needs.changes.outputs.test == 'true'
|
146 |
+
strategy:
|
147 |
+
matrix:
|
148 |
+
os: ["ubuntu-latest", "windows-latest"]
|
149 |
+
test-type: ["not flaky", "flaky"]
|
150 |
+
python-version: ["3.8"]
|
151 |
+
exclude:
|
152 |
+
- os: ${{ github.event_name == 'pull_request' && contains( github.event.pull_request.labels.*.name, 'windows-tests') && 'dummy' || 'windows-latest' }}
|
153 |
+
- test-type: ${{ github.event_name == 'pull_request' && contains( github.event.pull_request.labels.*.name, 'flaky-tests') && 'dummy' || 'flaky' }}
|
154 |
+
runs-on: ${{ matrix.os }}
|
155 |
+
continue-on-error: true
|
156 |
+
steps:
|
157 |
+
- uses: actions/checkout@v3
|
158 |
+
- name: Install Python
|
159 |
+
uses: actions/setup-python@v5
|
160 |
+
with:
|
161 |
+
python-version: ${{ matrix.python-version }}
|
162 |
+
cache: pip
|
163 |
+
cache-dependency-path: |
|
164 |
+
client/python/requirements.txt
|
165 |
+
requirements.txt
|
166 |
+
test/requirements.txt
|
167 |
+
- name: Create env
|
168 |
+
run: |
|
169 |
+
python -m pip install --upgrade virtualenv
|
170 |
+
python -m virtualenv venv
|
171 |
+
- uses: actions/cache@v4
|
172 |
+
id: cache
|
173 |
+
with:
|
174 |
+
path: |
|
175 |
+
venv/*
|
176 |
+
key: gradio-lib-${{ runner.os }}-pip-${{ hashFiles('client/python/requirements.txt') }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('test/requirements.txt') }}
|
177 |
+
- uses: actions/cache@v4
|
178 |
+
id: frontend-cache
|
179 |
+
with:
|
180 |
+
path: |
|
181 |
+
gradio/templates/*
|
182 |
+
gradio/node/*
|
183 |
+
key: gradio-lib-front-end-${{ hashFiles('js/**', 'client/js/**')}}
|
184 |
+
- name: Install pnpm
|
185 |
+
if: steps.frontend-cache.outputs.cache-hit != 'true'
|
186 |
+
uses: pnpm/action-setup@v2
|
187 |
+
with:
|
188 |
+
version: 8
|
189 |
+
- uses: actions/setup-node@v4
|
190 |
+
if: steps.frontend-cache.outputs.cache-hit != 'true'
|
191 |
+
with:
|
192 |
+
node-version: 18
|
193 |
+
cache: pnpm
|
194 |
+
cache-dependency-path: pnpm-lock.yaml
|
195 |
+
- name: Build frontend
|
196 |
+
if: steps.frontend-cache.outputs.cache-hit != 'true'
|
197 |
+
run: |
|
198 |
+
pnpm i --frozen-lockfile --ignore-scripts
|
199 |
+
pnpm build
|
200 |
+
- name: Install Gradio and Client Libraries Locally (Linux)
|
201 |
+
if: runner.os == 'Linux'
|
202 |
+
run: |
|
203 |
+
. venv/bin/activate
|
204 |
+
python -m pip install client/python
|
205 |
+
python -m pip install ".[oauth]"
|
206 |
+
- name: Install Test Dependencies (Linux)
|
207 |
+
if: steps.cache.outputs.cache-hit != 'true' && runner.os == 'Linux'
|
208 |
+
run: |
|
209 |
+
. venv/bin/activate
|
210 |
+
bash scripts/install_test_requirements.sh
|
211 |
+
- name: Install ffmpeg
|
212 |
+
uses: FedericoCarboni/setup-ffmpeg@v2
|
213 |
+
- name: Lint (Linux)
|
214 |
+
if: runner.os == 'Linux'
|
215 |
+
run: |
|
216 |
+
. venv/bin/activate
|
217 |
+
bash scripts/lint_backend.sh
|
218 |
+
- name: Typecheck (Linux)
|
219 |
+
if: runner.os == 'Linux'
|
220 |
+
run: |
|
221 |
+
. venv/bin/activate
|
222 |
+
bash scripts/type_check_backend.sh
|
223 |
+
- name: Run tests (Linux)
|
224 |
+
if: runner.os == 'Linux'
|
225 |
+
run: |
|
226 |
+
. venv/bin/activate
|
227 |
+
python -m pytest -m "${{ matrix.test-type }}" --ignore=client
|
228 |
+
- name: Install Gradio and Client Libraries Locally (Windows)
|
229 |
+
if: runner.os == 'Windows'
|
230 |
+
run: |
|
231 |
+
venv\Scripts\activate
|
232 |
+
python -m pip install client/python
|
233 |
+
python -m pip install ".[oauth]"
|
234 |
+
- name: Install Test Dependencies (Windows)
|
235 |
+
if: steps.cache.outputs.cache-hit != 'true' && runner.os == 'Windows'
|
236 |
+
run: |
|
237 |
+
venv\Scripts\activate
|
238 |
+
python -m pip install . -r test/requirements.txt
|
239 |
+
- name: Run tests (Windows)
|
240 |
+
if: runner.os == 'Windows'
|
241 |
+
run: |
|
242 |
+
venv\Scripts\activate
|
243 |
+
python -m pytest -m "${{ matrix.test-type }}" --ignore=client
|
244 |
+
echo "The exit code for pytest was $LASTEXITCODE"
|
.github/workflows/build-pr.yml
ADDED
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Build PR Artifacts
|
2 |
+
|
3 |
+
on:
|
4 |
+
workflow_dispatch:
|
5 |
+
pull_request:
|
6 |
+
branches:
|
7 |
+
- main
|
8 |
+
|
9 |
+
jobs:
|
10 |
+
comment-spaces-start:
|
11 |
+
uses: "./.github/workflows/comment-queue.yml"
|
12 |
+
secrets:
|
13 |
+
gh_token: ${{ secrets.COMMENT_TOKEN }}
|
14 |
+
with:
|
15 |
+
pr_number: ${{ github.event.pull_request.number }}
|
16 |
+
message: spaces~pending~null
|
17 |
+
build_pr:
|
18 |
+
runs-on: ubuntu-latest
|
19 |
+
steps:
|
20 |
+
- uses: actions/checkout@v3
|
21 |
+
- name: Install Python
|
22 |
+
uses: actions/setup-python@v5
|
23 |
+
with:
|
24 |
+
python-version: '3.9'
|
25 |
+
- name: Install pnpm
|
26 |
+
uses: pnpm/action-setup@v2
|
27 |
+
with:
|
28 |
+
version: 8
|
29 |
+
- uses: actions/setup-node@v4
|
30 |
+
with:
|
31 |
+
node-version: 18
|
32 |
+
cache: pnpm
|
33 |
+
cache-dependency-path: pnpm-lock.yaml
|
34 |
+
- name: Install pip
|
35 |
+
run: python -m pip install build requests
|
36 |
+
- name: Get PR Number
|
37 |
+
id: get_pr_number
|
38 |
+
run: |
|
39 |
+
if ${{ github.event_name == 'pull_request' }}; then
|
40 |
+
echo "GRADIO_VERSION=$(python -c 'import requests;print(requests.get("https://pypi.org/pypi/gradio/json").json()["info"]["version"])')" >> $GITHUB_OUTPUT
|
41 |
+
python -c "import os;print(os.environ['GITHUB_REF'].split('/')[2])" > pr_number.txt
|
42 |
+
echo "PR_NUMBER=$(cat pr_number.txt)" >> $GITHUB_OUTPUT
|
43 |
+
else
|
44 |
+
echo "GRADIO_VERSION=$(python -c 'import json; print(json.load(open("gradio/package.json"))["version"])')" >> $GITHUB_OUTPUT
|
45 |
+
echo "PR_NUMBER='main'" >> $GITHUB_OUTPUT
|
46 |
+
fi
|
47 |
+
- name: Build pr package
|
48 |
+
run: |
|
49 |
+
python -c 'import json; j = json.load(open("gradio/package.json")); j["version"] = "${{ steps.get_pr_number.outputs.GRADIO_VERSION }}"; json.dump(j, open("gradio/package.json", "w"))'
|
50 |
+
pnpm i --frozen-lockfile --ignore-scripts
|
51 |
+
pnpm build
|
52 |
+
python3 -m build -w
|
53 |
+
env:
|
54 |
+
NODE_OPTIONS: --max_old_space_size=8192
|
55 |
+
- name: Upload wheel
|
56 |
+
uses: actions/upload-artifact@v4
|
57 |
+
with:
|
58 |
+
name: gradio-${{ steps.get_pr_number.outputs.GRADIO_VERSION }}-py3-none-any.whl
|
59 |
+
path: dist/gradio-${{ steps.get_pr_number.outputs.GRADIO_VERSION }}-py3-none-any.whl
|
60 |
+
- name: Set up Demos
|
61 |
+
run: |
|
62 |
+
python scripts/copy_demos.py https://gradio-builds.s3.amazonaws.com/${{ github.sha }}/gradio-${{ steps.get_pr_number.outputs.GRADIO_VERSION }}-py3-none-any.whl \
|
63 |
+
"gradio-client @ git+https://github.com/gradio-app/gradio@${{ github.sha }}#subdirectory=client/python"
|
64 |
+
- name: Upload all_demos
|
65 |
+
uses: actions/upload-artifact@v4
|
66 |
+
with:
|
67 |
+
name: all_demos
|
68 |
+
path: demo/all_demos
|
69 |
+
- name: Create metadata artifact
|
70 |
+
run: |
|
71 |
+
python -c "import json; json.dump({'gh_sha': '${{ github.sha }}', 'pr_number': ${{ steps.get_pr_number.outputs.pr_number }}, 'version': '${{ steps.get_pr_number.outputs.GRADIO_VERSION }}', 'wheel': 'gradio-${{ steps.get_pr_number.outputs.GRADIO_VERSION }}-py3-none-any.whl'}, open('metadata.json', 'w'))"
|
72 |
+
- name: Upload metadata
|
73 |
+
uses: actions/upload-artifact@v4
|
74 |
+
with:
|
75 |
+
name: metadata.json
|
76 |
+
path: metadata.json
|
.github/workflows/check-demo-notebooks.yml
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# This workflow will check if the run.py files in every demo match the run.ipynb notebooks.
|
2 |
+
|
3 |
+
name: Check Demos Match Notebooks
|
4 |
+
|
5 |
+
on:
|
6 |
+
pull_request:
|
7 |
+
types: [opened, synchronize, reopened]
|
8 |
+
paths:
|
9 |
+
- 'demo/**'
|
10 |
+
|
11 |
+
jobs:
|
12 |
+
comment-notebook-start:
|
13 |
+
uses: "./.github/workflows/comment-queue.yml"
|
14 |
+
secrets:
|
15 |
+
gh_token: ${{ secrets.COMMENT_TOKEN }}
|
16 |
+
with:
|
17 |
+
pr_number: ${{ github.event.pull_request.number }}
|
18 |
+
message: notebooks~pending~null
|
19 |
+
check-notebooks:
|
20 |
+
name: Generate Notebooks and Check
|
21 |
+
runs-on: ubuntu-latest
|
22 |
+
steps:
|
23 |
+
- name: Checkout
|
24 |
+
uses: actions/checkout@v3
|
25 |
+
with:
|
26 |
+
ref: ${{ github.event.pull_request.head.ref }}
|
27 |
+
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
28 |
+
- name: Generate Notebooks
|
29 |
+
run: |
|
30 |
+
pip install nbformat && cd demo && python generate_notebooks.py
|
31 |
+
- name: Print Git Status
|
32 |
+
run: echo $(git status) && echo $(git diff)
|
33 |
+
- name: Assert Notebooks Match
|
34 |
+
id: assertNotebooksMatch
|
35 |
+
run: git status | grep "nothing to commit, working tree clean"
|
36 |
+
- name: Get PR Number
|
37 |
+
if: always()
|
38 |
+
run: |
|
39 |
+
python -c "import os;print(os.environ['GITHUB_REF'].split('/')[2])" > pr_number.txt
|
40 |
+
echo "PR_NUMBER=$(cat pr_number.txt)" >> $GITHUB_ENV
|
41 |
+
- name: Upload PR Number
|
42 |
+
if: always()
|
43 |
+
run: |
|
44 |
+
python -c "import json; json.dump({'pr_number': ${{ env.PR_NUMBER }}}, open('metadata.json', 'w'))"
|
45 |
+
- name: Upload metadata
|
46 |
+
if: always()
|
47 |
+
uses: actions/upload-artifact@v4
|
48 |
+
with:
|
49 |
+
name: metadata.json
|
50 |
+
path: metadata.json
|
.github/workflows/comment-queue.yml
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Comment on pull request without race conditions
|
2 |
+
|
3 |
+
on:
|
4 |
+
workflow_call:
|
5 |
+
inputs:
|
6 |
+
pr_number:
|
7 |
+
type: string
|
8 |
+
message:
|
9 |
+
required: true
|
10 |
+
type: string
|
11 |
+
tag:
|
12 |
+
required: false
|
13 |
+
type: string
|
14 |
+
default: "previews"
|
15 |
+
additional_text:
|
16 |
+
required: false
|
17 |
+
type: string
|
18 |
+
default: ""
|
19 |
+
secrets:
|
20 |
+
gh_token:
|
21 |
+
required: true
|
22 |
+
|
23 |
+
jobs:
|
24 |
+
comment:
|
25 |
+
concurrency:
|
26 |
+
group: ${{inputs.pr_number || inputs.tag}}
|
27 |
+
runs-on: ubuntu-latest
|
28 |
+
steps:
|
29 |
+
- name: comment on pr
|
30 |
+
uses: "gradio-app/github/actions/comment-pr@main"
|
31 |
+
with:
|
32 |
+
gh_token: ${{ secrets.gh_token }}
|
33 |
+
tag: ${{ inputs.tag }}
|
34 |
+
pr_number: ${{ inputs.pr_number}}
|
35 |
+
message: ${{ inputs.message }}
|
36 |
+
additional_text: ${{ inputs.additional_text }}
|
.github/workflows/delete-stale-spaces.yml
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Delete Stale Spaces
|
2 |
+
|
3 |
+
on:
|
4 |
+
schedule:
|
5 |
+
- cron: '0 0 * * *'
|
6 |
+
workflow_dispatch:
|
7 |
+
inputs:
|
8 |
+
daysStale:
|
9 |
+
description: 'How stale a space needs to be to be deleted (days)'
|
10 |
+
required: true
|
11 |
+
default: '7'
|
12 |
+
|
13 |
+
|
14 |
+
jobs:
|
15 |
+
delete-old-spaces:
|
16 |
+
runs-on: ubuntu-latest
|
17 |
+
steps:
|
18 |
+
- uses: actions/checkout@v3
|
19 |
+
- name: Install Python
|
20 |
+
uses: actions/setup-python@v5
|
21 |
+
with:
|
22 |
+
python-version: '3.9'
|
23 |
+
- name: Install pip
|
24 |
+
run: python -m pip install pip wheel requests
|
25 |
+
- name: Install Hub Client Library
|
26 |
+
run: pip install huggingface-hub==0.9.1
|
27 |
+
- name: Set daysStale
|
28 |
+
env:
|
29 |
+
DEFAULT_DAYS_STALE: '7'
|
30 |
+
run: echo "DAYS_STALE=${{ github.event.inputs.daysStale || env.DEFAULT_DAYS_STALE }}" >> $GITHUB_ENV
|
31 |
+
- name: Find and delete stale spaces
|
32 |
+
run: |
|
33 |
+
python scripts/delete_old_spaces.py $DAYS_STALE \
|
34 |
+
gradio-pr-deploys \
|
35 |
+
${{ secrets.SPACES_DEPLOY_TOKEN }}
|
.github/workflows/deploy-chromatic.yml
ADDED
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: 'deploy to chromatic'
|
2 |
+
|
3 |
+
on:
|
4 |
+
push:
|
5 |
+
paths:
|
6 |
+
- 'js/**'
|
7 |
+
- 'gradio/themes/**'
|
8 |
+
- '.github/workflows/deploy-chromatic.yml'
|
9 |
+
- '!js/_website/**'
|
10 |
+
|
11 |
+
|
12 |
+
jobs:
|
13 |
+
get-current-pr:
|
14 |
+
runs-on: ubuntu-latest
|
15 |
+
outputs:
|
16 |
+
pr_found: ${{ steps.get-pr.outputs.pr_found }}
|
17 |
+
pr_number: ${{ steps.get-pr.outputs.number }}
|
18 |
+
pr_labels: ${{ steps.get-pr.outputs.pr_labels }}
|
19 |
+
steps:
|
20 |
+
- uses: 8BitJonny/[email protected]
|
21 |
+
id: get-pr
|
22 |
+
with:
|
23 |
+
filterOutDraft: true
|
24 |
+
comment-chromatic-start:
|
25 |
+
uses: "./.github/workflows/comment-queue.yml"
|
26 |
+
needs: get-current-pr
|
27 |
+
secrets:
|
28 |
+
gh_token: ${{ secrets.COMMENT_TOKEN }}
|
29 |
+
with:
|
30 |
+
pr_number: ${{ needs.get-current-pr.outputs.pr_number }}
|
31 |
+
message: |
|
32 |
+
storybook~pending~null
|
33 |
+
visual~pending~0~0~null
|
34 |
+
chromatic-deployment:
|
35 |
+
needs: get-current-pr
|
36 |
+
runs-on: ubuntu-latest
|
37 |
+
outputs:
|
38 |
+
changes: ${{ steps.publish-chromatic.outputs.changeCount }}
|
39 |
+
errors: ${{ steps.publish-chromatic.outputs.errorCount }}
|
40 |
+
storybook_url: ${{ steps.publish-chromatic.outputs.storybookUrl }}
|
41 |
+
build_url: ${{ steps.publish-chromatic.outputs.buildUrl }}
|
42 |
+
if: ${{ github.repository == 'gradio-app/gradio' && !contains(needs.get-current-pr.outputs.pr_labels, 'no-visual-update') }}
|
43 |
+
steps:
|
44 |
+
- uses: actions/checkout@v3
|
45 |
+
with:
|
46 |
+
fetch-depth: 0
|
47 |
+
- name: install dependencies
|
48 |
+
uses: "./.github/actions/install-all-deps"
|
49 |
+
with:
|
50 |
+
always-install-pnpm: true
|
51 |
+
skip_build: 'true'
|
52 |
+
- name: build client
|
53 |
+
run: pnpm --filter @gradio/client build
|
54 |
+
- name: generate theme.css
|
55 |
+
run: |
|
56 |
+
. venv/bin/activate
|
57 |
+
python scripts/generate_theme.py --outfile js/storybook/theme.css
|
58 |
+
- name: build storybook
|
59 |
+
run: pnpm build-storybook --quiet
|
60 |
+
- name: publish to chromatic
|
61 |
+
id: publish-chromatic
|
62 |
+
uses: chromaui/action@v10
|
63 |
+
with:
|
64 |
+
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
65 |
+
token: ${{ secrets.GITHUB_TOKEN }}
|
66 |
+
onlyChanged: true
|
67 |
+
exitOnceUploaded: true
|
68 |
+
comment-chromatic-end:
|
69 |
+
uses: "./.github/workflows/comment-queue.yml"
|
70 |
+
needs: [chromatic-deployment, get-current-pr]
|
71 |
+
secrets:
|
72 |
+
gh_token: ${{ secrets.COMMENT_TOKEN }}
|
73 |
+
with:
|
74 |
+
pr_number: ${{ needs.get-current-pr.outputs.pr_number }}
|
75 |
+
message: |
|
76 |
+
storybook~success~${{ needs.chromatic-deployment.outputs.storybook_url }}
|
77 |
+
visual~success~${{ needs.chromatic-deployment.outputs.changes }}~${{ needs.chromatic-deployment.outputs.errors }}~${{ needs.chromatic-deployment.outputs.build_url }}
|
78 |
+
comment-chromatic-fail:
|
79 |
+
uses: "./.github/workflows/comment-queue.yml"
|
80 |
+
needs: [chromatic-deployment, get-current-pr]
|
81 |
+
if: always() && needs.chromatic-deployment.result == 'failure'
|
82 |
+
secrets:
|
83 |
+
gh_token: ${{ secrets.COMMENT_TOKEN }}
|
84 |
+
with:
|
85 |
+
pr_number: ${{ needs.get-current-pr.outputs.pr_number }}
|
86 |
+
message: |
|
87 |
+
storybook~failure~https://github.com/gradio-app/gradio/actions/runs/${{github.run_id}}/
|
88 |
+
visual~failure~0~0~https://github.com/gradio-app/gradio/actions/runs/${{github.run_id}}/
|
.github/workflows/deploy-pr-to-spaces.yml
ADDED
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Deploy PR to Spaces
|
2 |
+
|
3 |
+
on:
|
4 |
+
workflow_run:
|
5 |
+
workflows: [Build PR Artifacts]
|
6 |
+
types:
|
7 |
+
- completed
|
8 |
+
|
9 |
+
jobs:
|
10 |
+
deploy-current-pr:
|
11 |
+
outputs:
|
12 |
+
pr_number: ${{ steps.set-outputs.outputs.pr_number }}
|
13 |
+
space_url: ${{ steps.upload-demo.outputs.SPACE_URL }}
|
14 |
+
sha: ${{ steps.set-outputs.outputs.gh_sha }}
|
15 |
+
gradio_version: ${{ steps.set-outputs.outputs.gradio_version }}
|
16 |
+
runs-on: ubuntu-latest
|
17 |
+
steps:
|
18 |
+
- uses: actions/checkout@v3
|
19 |
+
- name: Install Python
|
20 |
+
uses: actions/setup-python@v5
|
21 |
+
with:
|
22 |
+
python-version: '3.9'
|
23 |
+
- name: Install pip
|
24 |
+
run: python -m pip install build requests
|
25 |
+
- name: Download metadata
|
26 |
+
run: python scripts/download_artifacts.py ${{github.event.workflow_run.id }} metadata.json ${{ secrets.COMMENT_TOKEN }} --owner ${{ github.repository_owner }}
|
27 |
+
- run: unzip metadata.json.zip
|
28 |
+
- name: set outputs
|
29 |
+
id: set-outputs
|
30 |
+
run: |
|
31 |
+
echo "wheel_name=$(python -c 'import json; print(json.load(open("metadata.json"))["wheel"])')" >> $GITHUB_OUTPUT
|
32 |
+
echo "gh_sha=$(python -c 'import json; print(json.load(open("metadata.json"))["gh_sha"])')" >> $GITHUB_OUTPUT
|
33 |
+
echo "gradio_version=$(python -c 'import json; print(json.load(open("metadata.json"))["version"])')" >> $GITHUB_OUTPUT
|
34 |
+
echo "pr_number=$(python -c 'import json; print(json.load(open("metadata.json"))["pr_number"])')" >> $GITHUB_OUTPUT
|
35 |
+
- name: 'Download wheel'
|
36 |
+
run: python scripts/download_artifacts.py ${{ github.event.workflow_run.id }} ${{ steps.set-outputs.outputs.wheel_name }} ${{ secrets.COMMENT_TOKEN }} --owner ${{ github.repository_owner }}
|
37 |
+
- run: unzip ${{ steps.set-outputs.outputs.wheel_name }}.zip
|
38 |
+
- name: Upload wheel
|
39 |
+
run: |
|
40 |
+
export AWS_ACCESS_KEY_ID=${{ secrets.PR_DEPLOY_KEY }}
|
41 |
+
export AWS_SECRET_ACCESS_KEY=${{ secrets.PR_DEPLOY_SECRET }}
|
42 |
+
export AWS_DEFAULT_REGION=us-east-1
|
43 |
+
aws s3 cp ${{ steps.set-outputs.outputs.wheel_name }} s3://gradio-builds/${{ steps.set-outputs.outputs.gh_sha }}/
|
44 |
+
- name: Install Hub Client Library
|
45 |
+
run: pip install huggingface-hub
|
46 |
+
- name: 'Download all_demos'
|
47 |
+
run: python scripts/download_artifacts.py ${{ github.event.workflow_run.id }} all_demos ${{ secrets.COMMENT_TOKEN }} --owner ${{ github.repository_owner }}
|
48 |
+
- run: unzip all_demos.zip -d all_demos
|
49 |
+
- run: cp -R all_demos/* demo/all_demos
|
50 |
+
- name: Upload demo to spaces
|
51 |
+
if: github.event.workflow_run.event == 'pull_request'
|
52 |
+
id: upload-demo
|
53 |
+
run: |
|
54 |
+
python scripts/upload_demo_to_space.py all_demos \
|
55 |
+
gradio-pr-deploys/pr-${{ steps.set-outputs.outputs.pr_number }}-all-demos \
|
56 |
+
${{ secrets.SPACES_DEPLOY_TOKEN }} \
|
57 |
+
--gradio-version ${{ steps.set-outputs.outputs.gradio_version }} > url.txt
|
58 |
+
echo "SPACE_URL=$(cat url.txt)" >> $GITHUB_OUTPUT
|
59 |
+
- name: Upload Website Demos
|
60 |
+
if: >
|
61 |
+
github.event.workflow_run.event == 'workflow_dispatch' &&
|
62 |
+
github.event.workflow_run.conclusion == 'success'
|
63 |
+
id: upload-website-demos
|
64 |
+
run: |
|
65 |
+
python scripts/upload_website_demos.py --AUTH_TOKEN ${{ secrets.WEBSITE_SPACES_DEPLOY_TOKEN }} \
|
66 |
+
--WHEEL_URL https://gradio-builds.s3.amazonaws.com/${{ steps.set-outputs.outputs.gh_sha }}/ \
|
67 |
+
--GRADIO_VERSION ${{ steps.set-outputs.outputs.gradio_version }}
|
68 |
+
|
69 |
+
comment-spaces-success:
|
70 |
+
uses: "./.github/workflows/comment-queue.yml"
|
71 |
+
needs: [deploy-current-pr]
|
72 |
+
if: >
|
73 |
+
github.event.workflow_run.event == 'pull_request' &&
|
74 |
+
github.event.workflow_run.conclusion == 'success' &&
|
75 |
+
needs.deploy-current-pr.result == 'success'
|
76 |
+
secrets:
|
77 |
+
gh_token: ${{ secrets.COMMENT_TOKEN }}
|
78 |
+
with:
|
79 |
+
pr_number: ${{ needs.deploy-current-pr.outputs.pr_number }}
|
80 |
+
message: spaces~success~${{ needs.deploy-current-pr.outputs.space_url }}
|
81 |
+
additional_text: |
|
82 |
+
**Install Gradio from this PR**
|
83 |
+
```bash
|
84 |
+
pip install https://gradio-builds.s3.amazonaws.com/${{ needs.deploy-current-pr.outputs.sha }}/gradio-${{ needs.deploy-current-pr.outputs.gradio_version }}-py3-none-any.whl
|
85 |
+
```
|
86 |
+
|
87 |
+
**Install Gradio Python Client from this PR**
|
88 |
+
```bash
|
89 |
+
pip install "gradio-client @ git+https://github.com/gradio-app/gradio@${{ needs.deploy-current-pr.outputs.sha }}#subdirectory=client/python"
|
90 |
+
```
|
91 |
+
comment-spaces-failure:
|
92 |
+
uses: "./.github/workflows/comment-queue.yml"
|
93 |
+
needs: [deploy-current-pr]
|
94 |
+
if: always() && needs.deploy-current-pr.result == 'failure'
|
95 |
+
secrets:
|
96 |
+
gh_token: ${{ secrets.COMMENT_TOKEN }}
|
97 |
+
with:
|
98 |
+
pr_number: ${{ needs.deploy-current-pr.outputs.pr_number }}
|
99 |
+
message: spaces~failure~https://github.com/gradio-app/gradio/actions/runs/${{github.run_id}}/
|
.github/workflows/deploy-website.yml
ADDED
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: "deploy website"
|
2 |
+
|
3 |
+
on:
|
4 |
+
workflow_call:
|
5 |
+
inputs:
|
6 |
+
branch_name:
|
7 |
+
description: "The branch name"
|
8 |
+
type: string
|
9 |
+
pr_number:
|
10 |
+
description: "The PR number"
|
11 |
+
type: string
|
12 |
+
secrets:
|
13 |
+
vercel_token:
|
14 |
+
description: "Vercel API token"
|
15 |
+
gh_token:
|
16 |
+
description: "Github token"
|
17 |
+
required: true
|
18 |
+
vercel_org_id:
|
19 |
+
description: "Vercel organization ID"
|
20 |
+
required: true
|
21 |
+
vercel_project_id:
|
22 |
+
description: "Vercel project ID"
|
23 |
+
required: true
|
24 |
+
|
25 |
+
env:
|
26 |
+
VERCEL_ORG_ID: ${{ secrets.vercel_org_id }}
|
27 |
+
VERCEL_PROJECT_ID: ${{ secrets.vercel_project_id }}
|
28 |
+
|
29 |
+
jobs:
|
30 |
+
comment-deploy-start:
|
31 |
+
uses: "./.github/workflows/comment-queue.yml"
|
32 |
+
secrets:
|
33 |
+
gh_token: ${{ secrets.gh_token }}
|
34 |
+
with:
|
35 |
+
pr_number: ${{ inputs.pr_number }}
|
36 |
+
message: website~pending~null
|
37 |
+
deploy:
|
38 |
+
name: "Deploy website"
|
39 |
+
runs-on: ubuntu-latest
|
40 |
+
outputs:
|
41 |
+
vercel_url: ${{ steps.output_url.outputs.vercel_url }}
|
42 |
+
steps:
|
43 |
+
- uses: actions/checkout@v3
|
44 |
+
- name: install dependencies
|
45 |
+
uses: "./.github/actions/install-frontend-deps"
|
46 |
+
with:
|
47 |
+
always-install-pnpm: true
|
48 |
+
skip_build: true
|
49 |
+
- name: download artifacts
|
50 |
+
uses: actions/download-artifact@v4
|
51 |
+
with:
|
52 |
+
name: website-json-${{ inputs.pr_number }}
|
53 |
+
path: |
|
54 |
+
./js/_website/src/lib/json
|
55 |
+
- name: echo artifact path
|
56 |
+
shell: bash
|
57 |
+
run: ls ./js/_website/src/lib/json
|
58 |
+
- name: Install Vercel CLI
|
59 |
+
shell: bash
|
60 |
+
run: pnpm install --global vercel@latest
|
61 |
+
# preview
|
62 |
+
- name: Pull Vercel Environment Information
|
63 |
+
shell: bash
|
64 |
+
if: github.event_name == 'pull_request'
|
65 |
+
run: vercel pull --yes --environment=preview --token=${{ secrets.vercel_token }}
|
66 |
+
- name: Build Project Artifacts
|
67 |
+
if: github.event_name == 'pull_request'
|
68 |
+
shell: bash
|
69 |
+
run: vercel build --token=${{ secrets.vercel_token }}
|
70 |
+
- name: Deploy Project Artifacts to Vercel
|
71 |
+
if: github.event_name == 'pull_request'
|
72 |
+
id: output_url
|
73 |
+
shell: bash
|
74 |
+
run: echo "vercel_url=$(vercel deploy --prebuilt --token=${{ secrets.vercel_token }})" >> $GITHUB_OUTPUT
|
75 |
+
# production
|
76 |
+
- name: Pull Vercel Environment Information
|
77 |
+
if: github.event_name == 'push' && inputs.branch_name == 'main'
|
78 |
+
shell: bash
|
79 |
+
run: vercel pull --yes --environment=production --token=${{ secrets.vercel_token }}
|
80 |
+
- name: Build Project Artifacts
|
81 |
+
if: github.event_name == 'push' && inputs.branch_name == 'main'
|
82 |
+
shell: bash
|
83 |
+
run: vercel build --prod --token=${{ secrets.vercel_token }}
|
84 |
+
- name: Deploy Project Artifacts to Vercel
|
85 |
+
if: github.event_name == 'push' && inputs.branch_name == 'main'
|
86 |
+
shell: bash
|
87 |
+
run: echo "VERCEL_URL=$(vercel deploy --prebuilt --prod --token=${{ secrets.vercel_token }})" >> $GITHUB_ENV
|
88 |
+
- name: echo vercel url
|
89 |
+
shell: bash
|
90 |
+
run: echo $VERCEL_URL #add to comment
|
91 |
+
comment-deploy-success:
|
92 |
+
uses: "./.github/workflows/comment-queue.yml"
|
93 |
+
needs: deploy
|
94 |
+
if: needs.deploy.result == 'success'
|
95 |
+
secrets:
|
96 |
+
gh_token: ${{ secrets.gh_token }}
|
97 |
+
with:
|
98 |
+
pr_number: ${{ inputs.pr_number }}
|
99 |
+
message: website~success~${{needs.deploy.outputs.vercel_url}}
|
100 |
+
comment-deploy-failure:
|
101 |
+
uses: "./.github/workflows/comment-queue.yml"
|
102 |
+
needs: deploy
|
103 |
+
if: always() && needs.deploy.result == 'failure'
|
104 |
+
secrets:
|
105 |
+
gh_token: ${{ secrets.gh_token }}
|
106 |
+
with:
|
107 |
+
pr_number: ${{ inputs.pr_number }}
|
108 |
+
message: website~failure~https://github.com/gradio-app/gradio/actions/runs/${{github.run_id}}/
|
.github/workflows/generate-changeset.yml
ADDED
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Generate changeset
|
2 |
+
on:
|
3 |
+
workflow_run:
|
4 |
+
workflows: ["trigger changeset generation"]
|
5 |
+
types:
|
6 |
+
- completed
|
7 |
+
|
8 |
+
env:
|
9 |
+
CI: true
|
10 |
+
NODE_OPTIONS: "--max-old-space-size=4096"
|
11 |
+
|
12 |
+
concurrency:
|
13 |
+
group: ${{ github.event.workflow_run.head_repository.full_name }}::${{ github.event.workflow_run.head_branch }}
|
14 |
+
|
15 |
+
jobs:
|
16 |
+
get-pr:
|
17 |
+
runs-on: ubuntu-latest
|
18 |
+
if: github.event.workflow_run.conclusion == 'success'
|
19 |
+
outputs:
|
20 |
+
found_pr: ${{ steps.pr_details.outputs.found_pr }}
|
21 |
+
pr_number: ${{ steps.pr_details.outputs.pr_number }}
|
22 |
+
source_repo: ${{ steps.pr_details.outputs.source_repo }}
|
23 |
+
source_branch: ${{ steps.pr_details.outputs.source_branch }}
|
24 |
+
steps:
|
25 |
+
- name: get pr details
|
26 |
+
id: pr_details
|
27 |
+
uses: gradio-app/github/actions/find-pr@main
|
28 |
+
with:
|
29 |
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
30 |
+
comment-changes-start:
|
31 |
+
uses: "./.github/workflows/comment-queue.yml"
|
32 |
+
needs: get-pr
|
33 |
+
secrets:
|
34 |
+
gh_token: ${{ secrets.COMMENT_TOKEN }}
|
35 |
+
with:
|
36 |
+
pr_number: ${{ needs.get-pr.outputs.pr_number }}
|
37 |
+
message: changes~pending~null
|
38 |
+
version:
|
39 |
+
permissions: write-all
|
40 |
+
name: static checks
|
41 |
+
needs: get-pr
|
42 |
+
runs-on: ubuntu-22.04
|
43 |
+
if: needs.get-pr.outputs.found_pr == 'true'
|
44 |
+
outputs:
|
45 |
+
skipped: ${{ steps.version.outputs.skipped }}
|
46 |
+
comment_url: ${{ steps.version.outputs.comment_url }}
|
47 |
+
steps:
|
48 |
+
- uses: actions/checkout@v3
|
49 |
+
with:
|
50 |
+
repository: ${{ needs.get-pr.outputs.source_repo }}
|
51 |
+
ref: ${{ needs.get-pr.outputs.source_branch }}
|
52 |
+
fetch-depth: 0
|
53 |
+
token: ${{ secrets.COMMENT_TOKEN }}
|
54 |
+
- name: generate changeset
|
55 |
+
id: version
|
56 |
+
uses: "gradio-app/github/actions/generate-changeset@main"
|
57 |
+
with:
|
58 |
+
github_token: ${{ secrets.COMMENT_TOKEN }}
|
59 |
+
main_pkg: gradio
|
60 |
+
pr_number: ${{ needs.get-pr.outputs.pr_number }}
|
61 |
+
branch_name: ${{ needs.get-pr.outputs.source_branch }}
|
62 |
+
comment-changes-skipped:
|
63 |
+
uses: "./.github/workflows/comment-queue.yml"
|
64 |
+
needs: [get-pr, version]
|
65 |
+
if: needs.version.result == 'success' && needs.version.outputs.skipped == 'true'
|
66 |
+
secrets:
|
67 |
+
gh_token: ${{ secrets.COMMENT_TOKEN }}
|
68 |
+
with:
|
69 |
+
pr_number: ${{ needs.get-pr.outputs.pr_number }}
|
70 |
+
message: changes~warning~https://github.com/gradio-app/gradio/actions/runs/${{github.run_id}}/
|
71 |
+
comment-changes-success:
|
72 |
+
uses: "./.github/workflows/comment-queue.yml"
|
73 |
+
needs: [get-pr, version]
|
74 |
+
if: needs.version.result == 'success' && needs.version.outputs.skipped == 'false'
|
75 |
+
secrets:
|
76 |
+
gh_token: ${{ secrets.COMMENT_TOKEN }}
|
77 |
+
with:
|
78 |
+
pr_number: ${{ needs.get-pr.outputs.pr_number }}
|
79 |
+
message: changes~success~${{ needs.version.outputs.comment_url }}
|
80 |
+
comment-changes-failure:
|
81 |
+
uses: "./.github/workflows/comment-queue.yml"
|
82 |
+
needs: [get-pr, version]
|
83 |
+
if: always() && needs.version.result == 'failure'
|
84 |
+
secrets:
|
85 |
+
gh_token: ${{ secrets.COMMENT_TOKEN }}
|
86 |
+
with:
|
87 |
+
pr_number: ${{ needs.get-pr.outputs.pr_number }}
|
88 |
+
message: changes~failure~https://github.com/gradio-app/gradio/actions/runs/${{github.run_id}}/
|
.github/workflows/large-files.yml
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Check for large files
|
2 |
+
|
3 |
+
on:
|
4 |
+
pull_request:
|
5 |
+
|
6 |
+
jobs:
|
7 |
+
check-files:
|
8 |
+
runs-on: ubuntu-latest
|
9 |
+
if: github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name
|
10 |
+
|
11 |
+
steps:
|
12 |
+
- name: Checkout
|
13 |
+
uses: actions/checkout@v3
|
14 |
+
with:
|
15 |
+
ref: ${{ github.event.pull_request.head.ref }}
|
16 |
+
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
17 |
+
- name: Check for large files
|
18 |
+
uses: actionsdesk/[email protected]
|
19 |
+
with:
|
20 |
+
filesizelimit: 5MB
|
21 |
+
|
.github/workflows/publish-npm.yml
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Changesets
|
2 |
+
on:
|
3 |
+
push:
|
4 |
+
branches:
|
5 |
+
- main
|
6 |
+
|
7 |
+
env:
|
8 |
+
CI: true
|
9 |
+
PNPM_CACHE_FOLDER: .pnpm-store
|
10 |
+
NODE_OPTIONS: "--max-old-space-size=4096"
|
11 |
+
jobs:
|
12 |
+
version_or_publish:
|
13 |
+
runs-on: ubuntu-22.04
|
14 |
+
steps:
|
15 |
+
- name: checkout repo
|
16 |
+
uses: actions/checkout@v3
|
17 |
+
with:
|
18 |
+
fetch-depth: 0
|
19 |
+
persist-credentials: false
|
20 |
+
- name: install dependencies
|
21 |
+
uses: "./.github/actions/install-all-deps"
|
22 |
+
with:
|
23 |
+
always-install-pnpm: true
|
24 |
+
node_auth_token: ${{ secrets.NPM_TOKEN }}
|
25 |
+
npm_token: ${{ secrets.NPM_TOKEN }}
|
26 |
+
skip_build: 'true'
|
27 |
+
- name: Build packages
|
28 |
+
run: |
|
29 |
+
. venv/bin/activate
|
30 |
+
pip install build
|
31 |
+
pnpm --filter @gradio/client --filter @gradio/lite build
|
32 |
+
- name: create and publish versions
|
33 |
+
id: changesets
|
34 |
+
uses: changesets/action@v1
|
35 |
+
with:
|
36 |
+
version: pnpm ci:version
|
37 |
+
commit: "chore: update versions"
|
38 |
+
title: "chore: update versions"
|
39 |
+
publish: pnpm ci:publish
|
40 |
+
env:
|
41 |
+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
42 |
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
43 |
+
GITHUB_TOKEN: ${{ secrets.GRADIO_PAT }}
|
44 |
+
- name: add label to skip chromatic build
|
45 |
+
if: ${{ steps.changesets.outputs.pullRequestNumber != '' && steps.changesets.outputs.pullRequestNumber != 'undefined' }}
|
46 |
+
run: gh pr edit "$PR_NUMBER" --add-label "no-visual-update"
|
47 |
+
env:
|
48 |
+
PR_NUMBER: ${{ steps.changesets.outputs.pullRequestNumber }}
|
49 |
+
GITHUB_TOKEN: ${{ secrets.GRADIO_PAT }}
|
50 |
+
- name: add label to run flaky tests
|
51 |
+
if: ${{ steps.changesets.outputs.pullRequestNumber != '' && steps.changesets.outputs.pullRequestNumber != 'undefined' }}
|
52 |
+
run: gh pr edit "$PR_NUMBER" --add-label "flaky-tests"
|
53 |
+
env:
|
54 |
+
PR_NUMBER: ${{ steps.changesets.outputs.pullRequestNumber }}
|
55 |
+
GITHUB_TOKEN: ${{ secrets.GRADIO_PAT }}
|
56 |
+
- name: add label to run backend tests on Windows
|
57 |
+
if: ${{ steps.changesets.outputs.pullRequestNumber != '' && steps.changesets.outputs.pullRequestNumber != 'undefined' }}
|
58 |
+
run: gh pr edit "$PR_NUMBER" --add-label "windows-tests"
|
59 |
+
env:
|
60 |
+
PR_NUMBER: ${{ steps.changesets.outputs.pullRequestNumber }}
|
61 |
+
GITHUB_TOKEN: ${{ secrets.GRADIO_PAT }}
|
62 |
+
- name: publish to pypi
|
63 |
+
if: steps.changesets.outputs.hasChangesets != 'true'
|
64 |
+
uses: "gradio-app/github/actions/publish-pypi@main"
|
65 |
+
env:
|
66 |
+
AWS_ACCESS_KEY_ID: ${{ secrets.AWSACCESSKEYID }}
|
67 |
+
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWSSECRETKEY }}
|
68 |
+
AWS_DEFAULT_REGION: us-west-2
|
69 |
+
with:
|
70 |
+
user: __token__
|
71 |
+
passwords: |
|
72 |
+
gradio:${{ secrets.PYPI_API_TOKEN }}
|
73 |
+
gradio_client:${{ secrets.PYPI_GRADIO_CLIENT_TOKEN }}
|
74 |
+
- name: trigger spaces deploy workflow
|
75 |
+
env:
|
76 |
+
GITHUB_TOKEN: ${{ secrets.COMMENT_TOKEN }}
|
77 |
+
run: gh workflow run build-pr.yml
|
.github/workflows/report-notebook-status-pr.yml
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
on:
|
2 |
+
workflow_run:
|
3 |
+
workflows: [Check Demos Match Notebooks]
|
4 |
+
types: [completed]
|
5 |
+
|
6 |
+
jobs:
|
7 |
+
get-pr-number:
|
8 |
+
runs-on: ubuntu-latest
|
9 |
+
outputs:
|
10 |
+
pr_number: ${{ steps.pr_number.outputs.pr_number }}
|
11 |
+
steps:
|
12 |
+
- uses: actions/checkout@v3
|
13 |
+
- name: Install Python
|
14 |
+
uses: actions/setup-python@v5
|
15 |
+
with:
|
16 |
+
python-version: '3.9'
|
17 |
+
- name: Install pip
|
18 |
+
run: python -m pip install requests
|
19 |
+
- name: Download metadata
|
20 |
+
run: python scripts/download_artifacts.py ${{github.event.workflow_run.id }} metadata.json ${{ secrets.COMMENT_TOKEN }} --owner ${{ github.repository_owner }}
|
21 |
+
- run: unzip metadata.json.zip
|
22 |
+
- name: Pipe metadata to env
|
23 |
+
id: pr_number
|
24 |
+
run: echo "pr_number=$(python -c 'import json; print(json.load(open("metadata.json"))["pr_number"])')" >> $GITHUB_OUTPUT
|
25 |
+
comment-success:
|
26 |
+
uses: "./.github/workflows/comment-queue.yml"
|
27 |
+
if: ${{ github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.name == 'Check Demos Match Notebooks'}}
|
28 |
+
needs: get-pr-number
|
29 |
+
secrets:
|
30 |
+
gh_token: ${{ secrets.COMMENT_TOKEN }}
|
31 |
+
with:
|
32 |
+
pr_number: ${{ needs.get-pr-number.outputs.pr_number }}
|
33 |
+
message: notebooks~success~null
|
34 |
+
comment-failure:
|
35 |
+
uses: "./.github/workflows/comment-queue.yml"
|
36 |
+
if: ${{ github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.name == 'Check Demos Match Notebooks'}}
|
37 |
+
needs: get-pr-number
|
38 |
+
secrets:
|
39 |
+
gh_token: ${{ secrets.COMMENT_TOKEN }}
|
40 |
+
with:
|
41 |
+
pr_number: ${{ needs.get-pr-number.outputs.pr_number }}
|
42 |
+
message: notebooks~failure~https://github.com/gradio-app/gradio/actions/runs/${{github.run_id}}/
|
43 |
+
additional_text: |
|
44 |
+
The demo notebooks don't match the run.py files. Please run this command from the root of the repo and then commit the changes:
|
45 |
+
```bash
|
46 |
+
pip install nbformat && cd demo && python generate_notebooks.py
|
47 |
+
```
|
.github/workflows/trigger-changeset.yml
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: trigger changeset generation
|
2 |
+
on:
|
3 |
+
pull_request:
|
4 |
+
types: [opened, synchronize, reopened, edited, labeled, unlabeled]
|
5 |
+
branches:
|
6 |
+
- main
|
7 |
+
issue_comment:
|
8 |
+
types: [edited]
|
9 |
+
|
10 |
+
jobs:
|
11 |
+
version:
|
12 |
+
permissions: write-all
|
13 |
+
name: static checks
|
14 |
+
runs-on: ubuntu-22.04
|
15 |
+
if: github.event.sender.login != 'gradio-pr-bot'
|
16 |
+
steps:
|
17 |
+
- run: echo ${{ github.event_name }}
|
18 |
+
- run: echo ${{ github.event.sender.login }}
|
19 |
+
- run: echo "Triggering changeset generation"
|
.github/workflows/ui.yml
ADDED
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: gradio-ui
|
2 |
+
|
3 |
+
on:
|
4 |
+
push:
|
5 |
+
branches:
|
6 |
+
- "main"
|
7 |
+
pull_request:
|
8 |
+
|
9 |
+
env:
|
10 |
+
CI: true
|
11 |
+
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
|
12 |
+
NODE_OPTIONS: "--max-old-space-size=4096"
|
13 |
+
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
|
14 |
+
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
|
15 |
+
concurrency:
|
16 |
+
group: deploy-${{ github.ref }}-${{ github.event_name == 'push' || github.event.inputs.fire != null }}
|
17 |
+
cancel-in-progress: true
|
18 |
+
|
19 |
+
jobs:
|
20 |
+
quick-checks:
|
21 |
+
name: static checks
|
22 |
+
runs-on: ubuntu-22.04
|
23 |
+
steps:
|
24 |
+
- uses: actions/checkout@v3
|
25 |
+
- name: install dependencies
|
26 |
+
uses: "./.github/actions/install-frontend-deps"
|
27 |
+
with:
|
28 |
+
always-install-pnpm: true
|
29 |
+
- name: build client
|
30 |
+
run: pnpm --filter @gradio/client build
|
31 |
+
- name: build the wasm module
|
32 |
+
run: pnpm --filter @gradio/wasm build
|
33 |
+
- name: format check
|
34 |
+
run: pnpm format:check
|
35 |
+
- name: lint
|
36 |
+
run: pnpm lint
|
37 |
+
- name: typecheck
|
38 |
+
run: pnpm ts:check
|
39 |
+
- name: unit tests
|
40 |
+
run: pnpm test:run
|
41 |
+
functional-test:
|
42 |
+
runs-on: ubuntu-latest
|
43 |
+
outputs:
|
44 |
+
source_branch: ${{ steps.pr_details.outputs.source_branch }}
|
45 |
+
pr_number: ${{ steps.pr_details.outputs.pr_number }}
|
46 |
+
steps:
|
47 |
+
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4
|
48 |
+
- name: install dependencies
|
49 |
+
id: install_deps
|
50 |
+
uses: "./.github/actions/install-all-deps"
|
51 |
+
with:
|
52 |
+
always-install-pnpm: true
|
53 |
+
- name: get pr details
|
54 |
+
id: pr_details
|
55 |
+
uses: gradio-app/github/actions/find-pr@main
|
56 |
+
with:
|
57 |
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
58 |
+
- name: deploy json to aws
|
59 |
+
if: steps.pr_details.outputs.source_branch == 'changeset-release/main'
|
60 |
+
run: |
|
61 |
+
export AWS_ACCESS_KEY_ID=${{ secrets.AWSACCESSKEYID }}
|
62 |
+
export AWS_SECRET_ACCESS_KEY=${{ secrets.AWSSECRETKEY }}
|
63 |
+
export AWS_DEFAULT_REGION=us-west-2
|
64 |
+
version=$(jq -r .version js/_website/src/lib/json/version.json)
|
65 |
+
aws s3 cp ./js/_website/src/lib/json/ s3://gradio-docs-json/$version/ --recursive
|
66 |
+
- name: install outbreak_forecast dependencies
|
67 |
+
run: |
|
68 |
+
. venv/bin/activate
|
69 |
+
python -m pip install -r demo/outbreak_forecast/requirements.txt
|
70 |
+
- run: pnpm exec playwright install chromium
|
71 |
+
- name: run browser tests
|
72 |
+
run: |
|
73 |
+
. venv/bin/activate
|
74 |
+
CI=1 pnpm test:browser
|
75 |
+
- name: upload screenshots
|
76 |
+
uses: actions/upload-artifact@v4
|
77 |
+
if: always()
|
78 |
+
with:
|
79 |
+
name: playwright-screenshots
|
80 |
+
path: |
|
81 |
+
./test-results
|
82 |
+
- name: run browser component tests
|
83 |
+
run: |
|
84 |
+
. venv/bin/activate
|
85 |
+
pnpm run test:ct
|
86 |
+
- name: save artifacts
|
87 |
+
uses: actions/upload-artifact@v4
|
88 |
+
with:
|
89 |
+
name: website-json-${{ steps.pr_details.outputs.pr_number }}
|
90 |
+
path: |
|
91 |
+
./js/_website/src/lib/json
|
92 |
+
deploy_to_vercel:
|
93 |
+
uses: "./.github/workflows/deploy-website.yml"
|
94 |
+
needs: functional-test
|
95 |
+
if: always()
|
96 |
+
secrets:
|
97 |
+
gh_token: ${{ secrets.COMMENT_TOKEN }}
|
98 |
+
vercel_token: ${{ secrets.VERCEL_TOKEN }}
|
99 |
+
vercel_org_id: ${{ secrets.VERCEL_ORG_ID }}
|
100 |
+
vercel_project_id: ${{ secrets.VERCEL_PROJECT_ID }}
|
101 |
+
with:
|
102 |
+
branch_name: ${{ needs.functional-test.outputs.source_branch }}
|
103 |
+
pr_number: ${{ needs.functional-test.outputs.pr_number }}
|
.gitignore
ADDED
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Python build
|
2 |
+
.eggs/
|
3 |
+
gradio.egg-info
|
4 |
+
dist/
|
5 |
+
*.pyc
|
6 |
+
__pycache__/
|
7 |
+
*.py[cod]
|
8 |
+
*$py.class
|
9 |
+
build/
|
10 |
+
__tmp/*
|
11 |
+
*.pyi
|
12 |
+
py.typed
|
13 |
+
|
14 |
+
# JS build
|
15 |
+
gradio/templates/*
|
16 |
+
gradio/node/*
|
17 |
+
gradio/_frontend_code/*
|
18 |
+
js/gradio-preview/test/*
|
19 |
+
|
20 |
+
# Secrets
|
21 |
+
.env
|
22 |
+
|
23 |
+
# Gradio run artifacts
|
24 |
+
*.db
|
25 |
+
*.sqlite3
|
26 |
+
gradio/launches.json
|
27 |
+
flagged/
|
28 |
+
gradio_cached_examples/
|
29 |
+
tmp.zip
|
30 |
+
|
31 |
+
# Tests
|
32 |
+
.coverage
|
33 |
+
coverage.xml
|
34 |
+
test.txt
|
35 |
+
**/snapshots/**/*.png
|
36 |
+
playwright-report/
|
37 |
+
|
38 |
+
# Demos
|
39 |
+
demo/tmp.zip
|
40 |
+
demo/files/*.avi
|
41 |
+
demo/files/*.mp4
|
42 |
+
demo/all_demos/demos/*
|
43 |
+
demo/all_demos/requirements.txt
|
44 |
+
demo/*/config.json
|
45 |
+
demo/annotatedimage_component/*.png
|
46 |
+
|
47 |
+
# Etc
|
48 |
+
.idea/*
|
49 |
+
.DS_Store
|
50 |
+
*.bak
|
51 |
+
workspace.code-workspace
|
52 |
+
*.h5
|
53 |
+
|
54 |
+
# dev containers
|
55 |
+
.pnpm-store/
|
56 |
+
|
57 |
+
# log files
|
58 |
+
.pnpm-debug.log
|
59 |
+
|
60 |
+
# Local virtualenv for devs
|
61 |
+
.venv*
|
62 |
+
|
63 |
+
# FRP
|
64 |
+
gradio/frpc_*
|
65 |
+
.vercel
|
66 |
+
|
67 |
+
# js
|
68 |
+
node_modules
|
69 |
+
public/build/
|
70 |
+
test-results
|
71 |
+
client/js/test.js
|
72 |
+
.config/test.py
|
73 |
+
|
74 |
+
# storybook
|
75 |
+
storybook-static
|
76 |
+
build-storybook.log
|
77 |
+
js/storybook/theme.css
|
78 |
+
|
79 |
+
# playwright
|
80 |
+
.config/playwright/.cache
|
.vscode/extensions.json
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"recommendations": [
|
3 |
+
"dbaeumer.vscode-eslint",
|
4 |
+
"phoenisx.cssvar",
|
5 |
+
"esbenp.prettier-vscode",
|
6 |
+
"svelte.svelte-vscode",
|
7 |
+
"charliermarsh.ruff"
|
8 |
+
]
|
9 |
+
}
|
.vscode/settings.json
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"python.formatting.provider": "none",
|
3 |
+
"cssvar.files": ["./js/node_modules/pollen-css/pollen.css"],
|
4 |
+
"cssvar.ignore": [],
|
5 |
+
"cssvar.disableSort": true,
|
6 |
+
"cssvar.extensions": ["js", "css", "html", "jsx", "tsx", "svelte"],
|
7 |
+
"python.analysis.extraPaths": ["./gradio/themes/utils"],
|
8 |
+
"svelte.plugin.svelte.format.enable": true,
|
9 |
+
"svelte.plugin.svelte.diagnostics.enable": false,
|
10 |
+
"svelte.enable-ts-plugin": true,
|
11 |
+
"prettier.configPath": ".config/.prettierrc.json",
|
12 |
+
"prettier.ignorePath": ".config/.prettierignore",
|
13 |
+
"python.analysis.typeCheckingMode": "basic",
|
14 |
+
"python.testing.pytestArgs": ["."],
|
15 |
+
"python.testing.unittestEnabled": false,
|
16 |
+
"python.testing.pytestEnabled": true,
|
17 |
+
"eslint.validate": ["javascript", "typescript", "html", "markdown", "svelte"],
|
18 |
+
"eslint.experimental.useFlatConfig": true,
|
19 |
+
"eslint.options": {
|
20 |
+
"overrideConfigFile": "./.config/eslint.config.js"
|
21 |
+
},
|
22 |
+
"typescript.tsdk": "node_modules/typescript/lib"
|
23 |
+
}
|
CHANGELOG.md
ADDED
The diff for this file is too large to render.
See raw diff
|
|
CITATION.cff
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
cff-version: 1.2.0
|
2 |
+
message: Please cite this project using these metadata.
|
3 |
+
title: "Gradio: Hassle-free sharing and testing of ML models in the wild"
|
4 |
+
abstract: >-
|
5 |
+
Accessibility is a major challenge of machine learning (ML).
|
6 |
+
Typical ML models are built by specialists and require
|
7 |
+
specialized hardware/software as well as ML experience to
|
8 |
+
validate. This makes it challenging for non-technical
|
9 |
+
collaborators and endpoint users (e.g. physicians) to easily
|
10 |
+
provide feedback on model development and to gain trust in
|
11 |
+
ML. The accessibility challenge also makes collaboration
|
12 |
+
more difficult and limits the ML researcher's exposure to
|
13 |
+
realistic data and scenarios that occur in the wild. To
|
14 |
+
improve accessibility and facilitate collaboration, we
|
15 |
+
developed an open-source Python package, Gradio, which
|
16 |
+
allows researchers to rapidly generate a visual interface
|
17 |
+
for their ML models. Gradio makes accessing any ML model as
|
18 |
+
easy as sharing a URL. Our development of Gradio is informed
|
19 |
+
by interviews with a number of machine learning researchers
|
20 |
+
who participate in interdisciplinary collaborations. Their
|
21 |
+
feedback identified that Gradio should support a variety of
|
22 |
+
interfaces and frameworks, allow for easy sharing of the
|
23 |
+
interface, allow for input manipulation and interactive
|
24 |
+
inference by the domain expert, as well as allow embedding
|
25 |
+
the interface in iPython notebooks. We developed these
|
26 |
+
features and carried out a case study to understand Gradio's
|
27 |
+
usefulness and usability in the setting of a machine
|
28 |
+
learning collaboration between a researcher and a
|
29 |
+
cardiologist.
|
30 |
+
authors:
|
31 |
+
- family-names: Abid
|
32 |
+
given-names: Abubakar
|
33 |
+
- family-names: Abdalla
|
34 |
+
given-names: Ali
|
35 |
+
- family-names: Abid
|
36 |
+
given-names: Ali
|
37 |
+
- family-names: Khan
|
38 |
+
given-names: Dawood
|
39 |
+
- family-names: Alfozan
|
40 |
+
given-names: Abdulrahman
|
41 |
+
- family-names: Zou
|
42 |
+
given-names: James
|
43 |
+
doi: 10.48550/arXiv.1906.02569
|
44 |
+
date-released: 2019-06-06
|
45 |
+
url: https://arxiv.org/abs/1906.02569
|