From fdd57eda85c4a3d96219578c56069d2ea2fcca6e Mon Sep 17 00:00:00 2001 From: notmd Date: Wed, 1 Feb 2023 19:45:43 +0700 Subject: [PATCH 001/152] setup bundle analyzer --- website/next.config.js | 7 +- website/package-lock.json | 336 ++++++++++++++++++++++++++++++++++++++ website/package.json | 2 + 3 files changed, 344 insertions(+), 1 deletion(-) diff --git a/website/next.config.js b/website/next.config.js index a84ce736..cd8805c9 100644 --- a/website/next.config.js +++ b/website/next.config.js @@ -21,4 +21,9 @@ const nextConfig = { i18n, }; -module.exports = nextConfig; +const withBundleAnalyzer = require("@next/bundle-analyzer")({ + enabled: process.env.ANALYZE === "true", + openAnalyzer: true, +}); + +module.exports = withBundleAnalyzer(nextConfig); diff --git a/website/package-lock.json b/website/package-lock.json index 41167055..b6d7343c 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -19,6 +19,7 @@ "@heroicons/react": "^2.0.13", "@marsidev/react-turnstile": "^0.0.7", "@next-auth/prisma-adapter": "^1.0.5", + "@next/bundle-analyzer": "^13.1.6", "@next/font": "^13.1.0", "@prisma/client": "^4.7.1", "@tailwindcss/forms": "^0.5.3", @@ -5774,6 +5775,14 @@ "next-auth": "^4" } }, + "node_modules/@next/bundle-analyzer": { + "version": "13.1.6", + "resolved": "https://registry.npmjs.org/@next/bundle-analyzer/-/bundle-analyzer-13.1.6.tgz", + "integrity": "sha512-rJS9CtLoGT58mL+v2ISKANosFFWP/0YKYByHQ3vTaZrbQP8b1rYRxd2QVMJmnSXaFkiP9URt1XJ6OdGyVq5b6g==", + "dependencies": { + "webpack-bundle-analyzer": "4.7.0" + } + }, "node_modules/@next/env": { "version": "13.0.6", "resolved": "https://registry.npmjs.org/@next/env/-/env-13.0.6.tgz", @@ -6187,6 +6196,11 @@ "node": ">= 8" } }, + "node_modules/@polka/url": { + "version": "1.0.0-next.21", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", + "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==" + }, "node_modules/@popperjs/core": { "version": "2.11.6", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", @@ -18259,6 +18273,11 @@ "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", "dev": true }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, "node_modules/duplexify": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", @@ -21089,6 +21108,20 @@ "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/handlebars": { "version": "4.7.7", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", @@ -27754,6 +27787,14 @@ "rimraf": "bin.js" } }, + "node_modules/mrmime": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", + "engines": { + "node": ">=10" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -31447,6 +31488,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "bin": { + "opener": "bin/opener-bin.js" + } + }, "node_modules/openid-client": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.3.1.tgz", @@ -34817,6 +34866,19 @@ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" }, + "node_modules/sirv": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz", + "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==", + "dependencies": { + "@polka/url": "^1.0.0-next.20", + "mrmime": "^1.0.0", + "totalist": "^1.0.0" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -36352,6 +36414,14 @@ "node": ">=0.6" } }, + "node_modules/totalist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", + "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==", + "engines": { + "node": ">=6" + } + }, "node_modules/tough-cookie": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", @@ -37783,6 +37853,139 @@ } } }, + "node_modules/webpack-bundle-analyzer": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.7.0.tgz", + "integrity": "sha512-j9b8ynpJS4K+zfO5GGwsAcQX4ZHpWV+yRiHDiL+bE0XHJ8NiPYLTNVQdlFYWxtpg9lfAQNlwJg16J9AJtFSXRg==", + "dependencies": { + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "chalk": "^4.1.0", + "commander": "^7.2.0", + "gzip-size": "^6.0.0", + "lodash": "^4.17.20", + "opener": "^1.5.2", + "sirv": "^1.0.7", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/webpack-dev-middleware": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-4.3.0.tgz", @@ -42529,6 +42732,14 @@ "integrity": "sha512-VqMS11IxPXrPGXw6Oul6jcyS/n8GLOWzRMrPr3EMdtD6eOalM6zz05j08PcNiis8QzkfuYnCv49OvufTuaEwYQ==", "requires": {} }, + "@next/bundle-analyzer": { + "version": "13.1.6", + "resolved": "https://registry.npmjs.org/@next/bundle-analyzer/-/bundle-analyzer-13.1.6.tgz", + "integrity": "sha512-rJS9CtLoGT58mL+v2ISKANosFFWP/0YKYByHQ3vTaZrbQP8b1rYRxd2QVMJmnSXaFkiP9URt1XJ6OdGyVq5b6g==", + "requires": { + "webpack-bundle-analyzer": "4.7.0" + } + }, "@next/env": { "version": "13.0.6", "resolved": "https://registry.npmjs.org/@next/env/-/env-13.0.6.tgz", @@ -42758,6 +42969,11 @@ } } }, + "@polka/url": { + "version": "1.0.0-next.21", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", + "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==" + }, "@popperjs/core": { "version": "2.11.6", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", @@ -52149,6 +52365,11 @@ "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", "dev": true }, + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, "duplexify": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", @@ -54367,6 +54588,14 @@ "integrity": "sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==", "dev": true }, + "gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "requires": { + "duplexer": "^0.1.2" + } + }, "handlebars": { "version": "4.7.7", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", @@ -59420,6 +59649,11 @@ } } }, + "mrmime": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==" + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -61934,6 +62168,11 @@ "is-wsl": "^2.2.0" } }, + "opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==" + }, "openid-client": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.3.1.tgz", @@ -64472,6 +64711,16 @@ } } }, + "sirv": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz", + "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==", + "requires": { + "@polka/url": "^1.0.0-next.20", + "mrmime": "^1.0.0", + "totalist": "^1.0.0" + } + }, "sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -65697,6 +65946,11 @@ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true }, + "totalist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", + "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==" + }, "tough-cookie": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", @@ -66809,6 +67063,88 @@ } } }, + "webpack-bundle-analyzer": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.7.0.tgz", + "integrity": "sha512-j9b8ynpJS4K+zfO5GGwsAcQX4ZHpWV+yRiHDiL+bE0XHJ8NiPYLTNVQdlFYWxtpg9lfAQNlwJg16J9AJtFSXRg==", + "requires": { + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "chalk": "^4.1.0", + "commander": "^7.2.0", + "gzip-size": "^6.0.0", + "lodash": "^4.17.20", + "opener": "^1.5.2", + "sirv": "^1.0.7", + "ws": "^7.3.1" + }, + "dependencies": { + "acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==" + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "requires": {} + } + } + }, "webpack-dev-middleware": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-4.3.0.tgz", diff --git a/website/package.json b/website/package.json index 8c495a2c..4390c8fe 100644 --- a/website/package.json +++ b/website/package.json @@ -6,6 +6,7 @@ "scripts": { "dev": "next dev", "build": "next build", + "build:analyze": "ANALYZE=true next build", "start": "next start", "lint": "next lint", "typecheck": "tsc --noEmit", @@ -36,6 +37,7 @@ "@heroicons/react": "^2.0.13", "@marsidev/react-turnstile": "^0.0.7", "@next-auth/prisma-adapter": "^1.0.5", + "@next/bundle-analyzer": "^13.1.6", "@next/font": "^13.1.0", "@prisma/client": "^4.7.1", "@tailwindcss/forms": "^0.5.3", From ff94e3a6e04e243bc12ca5863deb7a4f8a29cb40 Mon Sep 17 00:00:00 2001 From: notmd Date: Wed, 1 Feb 2023 20:30:04 +0700 Subject: [PATCH 002/152] support window --- website/package-lock.json | 28 ++++++++++++++++++++++++++++ website/package.json | 3 ++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/website/package-lock.json b/website/package-lock.json index b6d7343c..ba6002e6 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -74,6 +74,7 @@ "@types/react": "18.0.26", "@typescript-eslint/eslint-plugin": "^5.47.1", "babel-loader": "^8.3.0", + "cross-env": "^7.0.3", "cypress": "^12.2.0", "cypress-image-diff-js": "^1.23.0", "eslint-plugin-storybook": "^0.6.8", @@ -17174,6 +17175,24 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "devOptional": true }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -51522,6 +51541,15 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "devOptional": true }, + "cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.1" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", diff --git a/website/package.json b/website/package.json index 4390c8fe..0ec21cc2 100644 --- a/website/package.json +++ b/website/package.json @@ -6,7 +6,7 @@ "scripts": { "dev": "next dev", "build": "next build", - "build:analyze": "ANALYZE=true next build", + "build:analyze": "cross-env ANALYZE=true next build", "start": "next start", "lint": "next lint", "typecheck": "tsc --noEmit", @@ -92,6 +92,7 @@ "@types/react": "18.0.26", "@typescript-eslint/eslint-plugin": "^5.47.1", "babel-loader": "^8.3.0", + "cross-env": "^7.0.3", "cypress": "^12.2.0", "cypress-image-diff-js": "^1.23.0", "eslint-plugin-storybook": "^0.6.8", From 0b9b8ed927cbfa0aadfe3f8fe046a3f167656294 Mon Sep 17 00:00:00 2001 From: notmd Date: Thu, 2 Feb 2023 00:29:46 +0700 Subject: [PATCH 003/152] allow to enable/disable email sigin via env variable --- docker-compose.yaml | 1 + website/.env | 1 + website/src/pages/api/auth/[...nextauth].ts | 4 ++++ website/src/pages/auth/signin.tsx | 4 +++- website/types/env.d.ts | 1 + 5 files changed, 10 insertions(+), 1 deletion(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 9a0202e7..57a50191 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -128,6 +128,7 @@ services: - NEXT_PUBLIC_CLOUDFARE_CAPTCHA_SITE_KEY=1x00000000000000000000AA - CLOUDFLARE_CAPTCHA_SERCERT_KEY=1x0000000000000000000000000000000AA - NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN_CAPTCHA=true + - NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN=true depends_on: webdb: condition: service_healthy diff --git a/website/.env b/website/.env index e81374e7..2579036f 100644 --- a/website/.env +++ b/website/.env @@ -21,3 +21,4 @@ EMAIL_FROM=info@example.com NEXT_PUBLIC_CLOUDFLARE_CAPTCHA_SITE_KEY=1x00000000000000000000AA CLOUDFLARE_CAPTCHA_SERCERT_KEY=1x0000000000000000000000000000000AA NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN_CAPTCHA=false +NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN=true diff --git a/website/src/pages/api/auth/[...nextauth].ts b/website/src/pages/api/auth/[...nextauth].ts index 5a316256..5b763b2c 100644 --- a/website/src/pages/api/auth/[...nextauth].ts +++ b/website/src/pages/api/auth/[...nextauth].ts @@ -165,6 +165,10 @@ export default function auth(req: NextApiRequest, res: NextApiResponse) { return true; } + if (account.provider === "email" && !boolean(process.env.NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN)) { + return false; + } + const captcha = req.body.captcha; const res = await checkCaptcha(captcha, getIp(req)); diff --git a/website/src/pages/auth/signin.tsx b/website/src/pages/auth/signin.tsx index b65fa742..62cd93f7 100644 --- a/website/src/pages/auth/signin.tsx +++ b/website/src/pages/auth/signin.tsx @@ -80,7 +80,9 @@ function Signin({ providers }: SigninProps) { {credentials && } - {email && } + {email && boolean(process.env.NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN) && ( + + )} {discord && ( + + + ))} ); diff --git a/website/src/components/Messages/LabelInputGroup.tsx b/website/src/components/Messages/LabelInputGroup.tsx index 51383128..2193a9f2 100644 --- a/website/src/components/Messages/LabelInputGroup.tsx +++ b/website/src/components/Messages/LabelInputGroup.tsx @@ -1,10 +1,12 @@ import { Text, VStack } from "@chakra-ui/react"; +import { useTranslation } from "next-i18next"; +import { Explain } from "src/components/Explain"; +import { LabelFlagGroup } from "src/components/Messages/LabelFlagGroup"; +import { LabelLikertGroup } from "src/components/Survey/LabelLikertGroup"; +import { LabelYesNoGroup } from "src/components/Messages/LabelYesNoGroup"; +import { getTypeSafei18nKey } from "src/lib/i18n"; import { Label } from "src/types/Tasks"; -import { LabelLikertGroup } from "../Survey/LabelLikertGroup"; -import { LabelFlagGroup } from "./LabelFlagGroup"; -import { LabelYesNoGroup } from "./LabelYesNoGroup"; - export interface LabelInputInstructions { yesNoInstruction: string; flagInstruction: string; @@ -28,6 +30,7 @@ export const LabelInputGroup = ({ instructions, onChange, }: LabelInputGroupProps) => { + const { t } = useTranslation("labelling"); const yesNoIndexes = labels.map((label, idx) => (label.widget === "yes_no" ? idx : null)).filter((v) => v !== null); const flagIndexes = labels.map((label, idx) => (label.widget === "flag" ? idx : null)).filter((v) => v !== null); const likertIndexes = labels.map((label, idx) => (label.widget === "likert" ? idx : null)).filter((v) => v !== null); @@ -52,7 +55,17 @@ export const LabelInputGroup = ({ )} {flagIndexes.length > 0 && ( - {instructions.flagInstruction} + + {instructions.flagInstruction} + + `${t(getTypeSafei18nKey(labels[idx].name))}: ${t( + getTypeSafei18nKey(`${labels[idx].name}.explanation`) + )}` + )} + />{" "} + values[idx])} labelNames={flagIndexes.map((idx) => labels[idx].name)} From 28ee771a979c745f8e403dc0cb752d16832952d9 Mon Sep 17 00:00:00 2001 From: notmd Date: Thu, 2 Feb 2023 20:23:00 +0700 Subject: [PATCH 016/152] System config parameter view --- website/src/components/AdminArea.tsx | 19 ++ website/src/components/Layout.tsx | 12 +- website/src/components/SideMenu.tsx | 1 - website/src/lib/oasst_api_client.ts | 9 + website/src/pages/_app.tsx | 23 +- website/src/pages/admin/index.tsx | 35 +-- website/src/pages/admin/parameters.tsx | 36 +++ website/src/pages/admin/status/index.tsx | 233 +++++++++----------- website/src/pages/api/admin/parameters.ts | 16 ++ website/src/pages/dashboard.tsx | 2 +- website/src/pages/index.tsx | 1 - website/src/styles/Theme/components/Card.ts | 14 +- 12 files changed, 223 insertions(+), 178 deletions(-) create mode 100644 website/src/components/AdminArea.tsx create mode 100644 website/src/pages/admin/parameters.tsx create mode 100644 website/src/pages/api/admin/parameters.ts diff --git a/website/src/components/AdminArea.tsx b/website/src/components/AdminArea.tsx new file mode 100644 index 00000000..8e6d1229 --- /dev/null +++ b/website/src/components/AdminArea.tsx @@ -0,0 +1,19 @@ +import { useRouter } from "next/router"; +import { useSession } from "next-auth/react"; +import { ReactNode, useEffect } from "react"; + +export const AdminArea = ({ children }: { children: ReactNode }) => { + const router = useRouter(); + const { data: session, status } = useSession(); + + useEffect(() => { + if (status === "loading") { + return; + } + if (session?.user.role === "admin") { + return; + } + router.push("/"); + }, [router, session, status]); + return
{status === "loading" ? "loading..." : children}
; +}; diff --git a/website/src/components/Layout.tsx b/website/src/components/Layout.tsx index 1b5bf430..2f89ae47 100644 --- a/website/src/components/Layout.tsx +++ b/website/src/components/Layout.tsx @@ -1,7 +1,7 @@ // https://nextjs.org/docs/basic-features/layouts import { Box, Grid } from "@chakra-ui/react"; -import { Activity, BarChart2, Layout, MessageSquare, Users } from "lucide-react"; +import { Activity, BarChart2, Layout, MessageSquare, Settings, Users } from "lucide-react"; import type { NextPage } from "next"; import { Header } from "src/components/Header"; @@ -37,19 +37,16 @@ export const getDashboardLayout = (page: React.ReactElement) => ( { label: "Dashboard", pathname: "/dashboard", - desc: "Dashboard Home", icon: Layout, }, { label: "Messages", pathname: "/messages", - desc: "Messages Dashboard", icon: MessageSquare, }, { label: "Leaderboard", pathname: "/leaderboard", - desc: "User Leaderboard", icon: BarChart2, }, ]} @@ -72,15 +69,18 @@ export const getAdminLayout = (page: React.ReactElement) => ( { label: "Users", pathname: "/admin", - desc: "Users Dashboard", icon: Users, }, { label: "Status", pathname: "/admin/status", - desc: "Status Dashboard", icon: Activity, }, + { + label: "Parameters", + pathname: "/admin/parameters", + icon: Settings, + }, ]} > {page} diff --git a/website/src/components/SideMenu.tsx b/website/src/components/SideMenu.tsx index 25dabf30..51c03d7a 100644 --- a/website/src/components/SideMenu.tsx +++ b/website/src/components/SideMenu.tsx @@ -6,7 +6,6 @@ import { useRouter } from "next/router"; export interface MenuButtonOption { label: string; pathname: string; - desc: string; icon: LucideIcon; } diff --git a/website/src/lib/oasst_api_client.ts b/website/src/lib/oasst_api_client.ts index 51e691b3..8cd2ae76 100644 --- a/website/src/lib/oasst_api_client.ts +++ b/website/src/lib/oasst_api_client.ts @@ -29,6 +29,15 @@ export class OasstApiClient { }; } } + + fetch_full_settings() { + return this.get>("/api/v1/admin/backend_settings/full"); + } + + fetch_public_settings() { + return this.get>("/api/v1/admin/backend_settings/public"); + } + // TODO return a strongly typed Task? // This method is used to store a task in RegisteredTask.task. // This is a raw Json type, so we can't use it to strongly type the task. diff --git a/website/src/pages/_app.tsx b/website/src/pages/_app.tsx index adadfe56..5b2421ea 100644 --- a/website/src/pages/_app.tsx +++ b/website/src/pages/_app.tsx @@ -2,8 +2,9 @@ import "../styles/globals.css"; import "focus-visible"; import type { AppProps } from "next/app"; +import Head from "next/head"; import { SessionProvider } from "next-auth/react"; -import { appWithTranslation } from "next-i18next"; +import { appWithTranslation, useTranslation } from "next-i18next"; import { FlagsProvider } from "react-feature-flags"; import { getDefaultLayout, NextPageWithLayout } from "src/components/Layout"; import flags from "src/flags"; @@ -24,15 +25,21 @@ const swrConfig: SWRConfiguration = { function MyApp({ Component, pageProps: { session, cookies, ...pageProps } }: AppPropsWithLayout) { const getLayout = Component.getLayout ?? getDefaultLayout; const page = getLayout(); + const { t } = useTranslation(); return ( - - - - {page} - - - + <> + + + + + + + {page} + + + + ); } export { getServerSideProps }; diff --git a/website/src/pages/admin/index.tsx b/website/src/pages/admin/index.tsx index ede9f59c..34a24ff6 100644 --- a/website/src/pages/admin/index.tsx +++ b/website/src/pages/admin/index.tsx @@ -1,7 +1,4 @@ -import Head from "next/head"; -import { useRouter } from "next/router"; -import { useSession } from "next-auth/react"; -import { useEffect } from "react"; +import { AdminArea } from "src/components/AdminArea"; import { getAdminLayout } from "src/components/Layout"; import { UserTable } from "src/components/UserTable"; export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props"; @@ -11,34 +8,10 @@ export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_ * admins the ability to manage their access rights. */ const AdminIndex = () => { - const router = useRouter(); - const { data: session, status } = useSession(); - - // Check when the user session is loaded and re-route if the user is not an - // admin. This follows the suggestion by NextJS for handling private pages: - // https://nextjs.org/docs/api-reference/next/router#usage - // - // All admin pages should use the same check and routing steps. - useEffect(() => { - if (status === "loading") { - return; - } - if (session?.user?.role === "admin") { - return; - } - router.push("/"); - }, [router, session, status]); return ( - <> - - Open Assistant - - -
{status === "loading" ? "loading..." : }
- + + + ); }; diff --git a/website/src/pages/admin/parameters.tsx b/website/src/pages/admin/parameters.tsx new file mode 100644 index 00000000..ac33a04b --- /dev/null +++ b/website/src/pages/admin/parameters.tsx @@ -0,0 +1,36 @@ +import { Card, CardBody, CircularProgress } from "@chakra-ui/react"; +import Head from "next/head"; +import { AdminArea } from "src/components/AdminArea"; +import { getAdminLayout } from "src/components/Layout"; +import { get } from "src/lib/api"; +import useSWRImmutable from "swr/immutable"; +export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props"; + +export default function Parameters() { + const { data, isLoading, error } = useSWRImmutable("/api/admin/parameters", get); + + return ( + <> + + Parameters - Open Assistant + + + + + {isLoading && } + {error && "Unable to load data"} + {data && ( + + +
{JSON.stringify(data, null, 2)}
+
+
+ )} +
+
+
+ + ); +} + +Parameters.getLayout = getAdminLayout; diff --git a/website/src/pages/admin/status/index.tsx b/website/src/pages/admin/status/index.tsx index 54305122..9218b7fa 100644 --- a/website/src/pages/admin/status/index.tsx +++ b/website/src/pages/admin/status/index.tsx @@ -13,12 +13,9 @@ import { Th, Thead, Tr, - useColorMode, } from "@chakra-ui/react"; import Head from "next/head"; -import { useRouter } from "next/router"; -import { useSession } from "next-auth/react"; -import { useEffect } from "react"; +import { AdminArea } from "src/components/AdminArea"; import { getAdminLayout } from "src/components/Layout"; import { get } from "src/lib/api"; import useSWRImmutable from "swr/immutable"; @@ -30,31 +27,7 @@ export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_ */ const StatusIndex = () => { - const router = useRouter(); - const { data: session, status } = useSession(); - - const { colorMode } = useColorMode(); - const dataBackgroundColor = colorMode === "light" ? "gray.100" : "gray.800"; - // Check when the user session is loaded and re-route if the user is not an - // admin. This follows the suggestion by NextJS for handling private pages: - // https://nextjs.org/docs/api-reference/next/router#usage - // - // All admin pages should use the same check and routing steps. - useEffect(() => { - if (status === "loading") { - return; - } - if (session?.user?.role === "admin") { - return; - } - router.push("/"); - }, [router, session, status]); - - const { - data: dataStatus, - error: errorStatus, - isLoading: isLoadingStatus, - } = useSWRImmutable("/api/admin/status", get); + const { data: dataStatus, error: errorStatus } = useSWRImmutable("/api/admin/status", get); const { tasksAvailability, stats, treeManager } = dataStatus || {}; @@ -62,110 +35,114 @@ const StatusIndex = () => { <> Status - Open Assistant - - - - - - /api/v1/tasks/availability - - - {tasksAvailability?.status === "fulfilled" ? ( -
{JSON.stringify(tasksAvailability.value, null, 2)}
- ) : tasksAvailability?.status === "rejected" ? ( -
{JSON.stringify(tasksAvailability.reason, null, 2)}
- ) : errorStatus ? ( -
{JSON.stringify(errorStatus, null, 2)}
- ) : ( - - )} -
-
-
- - - - - /api/v1/stats/ - - - {stats?.status === "fulfilled" ? ( -
{JSON.stringify(stats.value, null, 2)}
- ) : stats?.status === "rejected" ? ( -
{JSON.stringify(stats.reason, null, 2)}
- ) : errorStatus ? ( -
{JSON.stringify(errorStatus, null, 2)}
- ) : ( - - )} -
-
-
-
-
- - - - /api/v1/stats/tree_manager - - {treeManager?.status === "fulfilled" ? ( - - - state_counts + + + + + + /api/v1/tasks/availability - -
{JSON.stringify(treeManager.value.state_counts, null, 2)}
-
- -
+ + + {tasksAvailability?.status === "fulfilled" ? ( +
{JSON.stringify(tasksAvailability.value, null, 2)}
+ ) : tasksAvailability?.status === "rejected" ? ( +
{JSON.stringify(tasksAvailability.reason, null, 2)}
+ ) : errorStatus ? ( +
{JSON.stringify(errorStatus, null, 2)}
+ ) : ( + + )} +
+
+
+
+ + + + + /api/v1/stats/ + + + + {stats?.status === "fulfilled" ? ( +
{JSON.stringify(stats.value, null, 2)}
+ ) : stats?.status === "rejected" ? ( +
{JSON.stringify(stats.reason, null, 2)}
+ ) : errorStatus ? ( +
{JSON.stringify(errorStatus, null, 2)}
+ ) : ( + + )} +
+
+
+
+
+
+ + + + /api/v1/stats/tree_manager + + {treeManager?.status === "fulfilled" ? ( + - message_counts + state_counts - - Tree Manager - - - - - - - - - - - - - {treeManager.value.message_counts.map( - ({ message_tree_id, state, depth, oldest, youngest, count, goal_tree_size }) => ( - - - - - - - - - - ) - )} - -
Message Tree IDStateDepthOldestYoungestCountGoal Tree Size
{message_tree_id}{state}{depth}{oldest}{youngest}{count}{goal_tree_size}
- -
- ) : treeManager?.status === "rejected" ? ( -
{JSON.stringify(treeManager.reason, null, 2)}
- ) : errorStatus ? ( -
{JSON.stringify(errorStatus, null, 2)}
- ) : ( - - )} -
-
+ + +
{JSON.stringify(treeManager.value.state_counts, null, 2)}
+
+
+ +
+ + message_counts + + + Tree Manager + + + + + + + + + + + + + {treeManager.value.message_counts.map( + ({ message_tree_id, state, depth, oldest, youngest, count, goal_tree_size }) => ( + + + + + + + + + + ) + )} + +
Message Tree IDStateDepthOldestYoungestCountGoal Tree Size
{message_tree_id}{state}{depth}{oldest}{youngest}{count}{goal_tree_size}
+
+
+ ) : treeManager?.status === "rejected" ? ( +
{JSON.stringify(treeManager.reason, null, 2)}
+ ) : errorStatus ? ( +
{JSON.stringify(errorStatus, null, 2)}
+ ) : ( + + )} +
+
+ ); }; diff --git a/website/src/pages/api/admin/parameters.ts b/website/src/pages/api/admin/parameters.ts new file mode 100644 index 00000000..73e04329 --- /dev/null +++ b/website/src/pages/api/admin/parameters.ts @@ -0,0 +1,16 @@ +import { withRole } from "src/lib/auth"; +import { createApiClient } from "src/lib/oasst_client_factory"; + +export default withRole("admin", async (_, res, token) => { + const client = await createApiClient(token); + + try { + const fullSettings = await client.fetch_full_settings(); + + return res.json(fullSettings); + } catch { + const publicSettings = await client.fetch_public_settings(); + + return res.json(publicSettings); + } +}); diff --git a/website/src/pages/dashboard.tsx b/website/src/pages/dashboard.tsx index e9fe3a18..b34a89a3 100644 --- a/website/src/pages/dashboard.tsx +++ b/website/src/pages/dashboard.tsx @@ -41,7 +41,7 @@ const Dashboard = () => { <> {`${t("dashboard")} - ${t("common:title")}`} - + diff --git a/website/src/pages/index.tsx b/website/src/pages/index.tsx index 6ac7dd38..e53142e3 100644 --- a/website/src/pages/index.tsx +++ b/website/src/pages/index.tsx @@ -24,7 +24,6 @@ const Home = () => { <> {t("title")} - diff --git a/website/src/styles/Theme/components/Card.ts b/website/src/styles/Theme/components/Card.ts index 8cd66031..c60261a4 100644 --- a/website/src/styles/Theme/components/Card.ts +++ b/website/src/styles/Theme/components/Card.ts @@ -17,11 +17,21 @@ export const cardTheme = defineMultiStyleConfig({ footer: {}, }; }), - variants: { - elevated: definePartsStyle({ + sizes: { + md: definePartsStyle({ container: { borderRadius: "xl", }, }), }, + variants: { + json: definePartsStyle(({ colorMode }) => { + const isLightMode = colorMode === "light"; + return { + container: { + backgroundColor: isLightMode ? "gray.100" : "gray.800", + }, + }; + }), + }, }); From fa9a0cc77637f521332f7183ebda226195844035 Mon Sep 17 00:00:00 2001 From: notmd Date: Thu, 2 Feb 2023 20:26:24 +0700 Subject: [PATCH 017/152] fix build --- website/src/pages/admin/index.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/website/src/pages/admin/index.tsx b/website/src/pages/admin/index.tsx index 34a24ff6..a4b77508 100644 --- a/website/src/pages/admin/index.tsx +++ b/website/src/pages/admin/index.tsx @@ -1,3 +1,4 @@ +import Head from "next/head"; import { AdminArea } from "src/components/AdminArea"; import { getAdminLayout } from "src/components/Layout"; import { UserTable } from "src/components/UserTable"; @@ -9,9 +10,14 @@ export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_ */ const AdminIndex = () => { return ( - - - + <> + + Open Assistant + + + + + ); }; From e9add425e607454241ff0ab9b273e534637741eb Mon Sep 17 00:00:00 2001 From: rjmacarthy Date: Tue, 31 Jan 2023 19:44:12 +0000 Subject: [PATCH 018/152] Add delete message feature Remove deleted property from Message Add dedicated route for delete_message Pre-commit Revert change to promp_repository fetch_message Remove blank line --- website/public/locales/en/common.json | 3 ++- .../components/Messages/MessageTableEntry.tsx | 17 ++++++++++++++--- website/src/lib/api.ts | 2 ++ website/src/lib/oasst_api_client.ts | 17 ++++++++++++++++- .../src/pages/api/admin/delete_message/[id].ts | 15 +++++++++++++++ 5 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 website/src/pages/api/admin/delete_message/[id].ts diff --git a/website/public/locales/en/common.json b/website/public/locales/en/common.json index 6298a32c..86540b2d 100644 --- a/website/public/locales/en/common.json +++ b/website/public/locales/en/common.json @@ -18,5 +18,6 @@ "sign_out": "Sign Out", "terms_of_service": "Terms of Service", "title": "Open Assistant", - "yes": "Yes" + "yes": "Yes", + "delete": "Delete" } diff --git a/website/src/components/Messages/MessageTableEntry.tsx b/website/src/components/Messages/MessageTableEntry.tsx index 63c90a33..63b1cf32 100644 --- a/website/src/components/Messages/MessageTableEntry.tsx +++ b/website/src/components/Messages/MessageTableEntry.tsx @@ -14,7 +14,7 @@ import { useDisclosure, } from "@chakra-ui/react"; import { boolean } from "boolean"; -import { ClipboardList, Flag, MessageSquare, MoreHorizontal, User } from "lucide-react"; +import { ClipboardList, Flag, MessageSquare, MoreHorizontal, Trash, User } from "lucide-react"; import { useRouter } from "next/router"; import { useSession } from "next-auth/react"; import { useTranslation } from "next-i18next"; @@ -22,9 +22,10 @@ import { useCallback, useEffect, useMemo, useState } from "react"; import { LabelMessagePopup } from "src/components/Messages/LabelPopup"; import { getEmojiIcon, MessageEmojiButton } from "src/components/Messages/MessageEmojiButton"; import { ReportPopup } from "src/components/Messages/ReportPopup"; -import { post } from "src/lib/api"; +import { del, post } from "src/lib/api"; import { colors } from "src/styles/Theme/colors"; import { Message, MessageEmojis } from "src/types/Conversation"; +import { mutate } from "swr"; import useSWRMutation from "swr/mutation"; interface MessageTableEntryProps { @@ -153,9 +154,16 @@ const MessageActions = ({ onReport: () => void; message: Message; }) => { - const { t } = useTranslation("message"); + const { t } = useTranslation(["message", "common"]); + const { trigger } = useSWRMutation(`/api/admin/delete_message/${message.id}`, del); const { data } = useSession() || {}; const role = data?.user?.role; + + const handleDelete = async () => { + await trigger(); + mutate((key) => typeof key === "string" && key.startsWith("/api/messages"), undefined, { revalidate: true }); + }; + return ( @@ -186,6 +194,9 @@ const MessageActions = ({ }> {t("view_user")} + }> + {t("common:delete")} + )} diff --git a/website/src/lib/api.ts b/website/src/lib/api.ts index bbb6d7e7..6c3bd900 100644 --- a/website/src/lib/api.ts +++ b/website/src/lib/api.ts @@ -17,6 +17,8 @@ export const get = (url: string) => api.get(url).then((res) => res.data); export const post = (url: string, { arg: data }) => api.post(url, data).then((res) => res.data); +export const del = (url: string) => api.delete(url).then((res) => res.data); + api.interceptors.response.use( (response) => response, (error) => { diff --git a/website/src/lib/oasst_api_client.ts b/website/src/lib/oasst_api_client.ts index 51e691b3..68428ae3 100644 --- a/website/src/lib/oasst_api_client.ts +++ b/website/src/lib/oasst_api_client.ts @@ -89,6 +89,13 @@ export class OasstApiClient { return this.get(`/api/v1/messages/${message_id}?username=${user.id}&auth_method=${user.auth_method}`); } + /** + * Delete a message by its id + */ + async delete_message(message_id: string): Promise { + return this.delete(`/api/v1/messages/${message_id}`); + } + /** * Send a report about a message */ @@ -202,6 +209,10 @@ export class OasstApiClient { return this.request("PUT", path); } + private async delete(path: string) { + return this.request("DELETE", path); + } + private async get(path: string, query?: Record) { if (!query) { return this.request("GET", path); @@ -216,7 +227,11 @@ export class OasstApiClient { return this.request("GET", `${path}?${params}`); } - private async request(method: "GET" | "POST" | "PUT", path: string, init?: RequestInit): Promise { + private async request( + method: "GET" | "POST" | "PUT" | "DELETE", + path: string, + init?: RequestInit + ): Promise { const resp = await fetch(`${this.oasstApiUrl}${path}`, { method, ...init, diff --git a/website/src/pages/api/admin/delete_message/[id].ts b/website/src/pages/api/admin/delete_message/[id].ts new file mode 100644 index 00000000..3dc607ed --- /dev/null +++ b/website/src/pages/api/admin/delete_message/[id].ts @@ -0,0 +1,15 @@ +import { withRole } from "src/lib/auth"; +import { createApiClient } from "src/lib/oasst_client_factory"; + +const handler = withRole("admin", async (req, res, token) => { + const { id } = req.query; + try { + const client = await createApiClient(token); + await client.delete_message(id as string); + res.status(200).json({ message: "Message deleted" }); + } catch (e) { + res.status(500).json({ message: "Failed to delete message" }); + } +}); + +export default handler; From 2db3450e9a0c56fce87456d63bb27e921f56bbf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=B6pf?= Date: Thu, 2 Feb 2023 16:10:38 +0100 Subject: [PATCH 019/152] add trollboards --- ...02_02_1544-4d7e0b0ebe84_add_troll_stats.py | 59 +++++ backend/oasst_backend/api/v1/api.py | 2 + backend/oasst_backend/api/v1/trollboards.py | 21 ++ backend/oasst_backend/models/__init__.py | 2 + backend/oasst_backend/models/troll_stats.py | 59 +++++ .../oasst_backend/user_stats_repository.py | 244 +++++++++++++++++- oasst-shared/oasst_shared/schemas/protocol.py | 41 +++ 7 files changed, 420 insertions(+), 8 deletions(-) create mode 100644 backend/alembic/versions/2023_02_02_1544-4d7e0b0ebe84_add_troll_stats.py create mode 100644 backend/oasst_backend/api/v1/trollboards.py create mode 100644 backend/oasst_backend/models/troll_stats.py diff --git a/backend/alembic/versions/2023_02_02_1544-4d7e0b0ebe84_add_troll_stats.py b/backend/alembic/versions/2023_02_02_1544-4d7e0b0ebe84_add_troll_stats.py new file mode 100644 index 00000000..aa9b1ffe --- /dev/null +++ b/backend/alembic/versions/2023_02_02_1544-4d7e0b0ebe84_add_troll_stats.py @@ -0,0 +1,59 @@ +"""add troll_stats + +Revision ID: 4d7e0b0ebe84 +Revises: 9e7ec4a9e3f2 +Create Date: 2023-02-02 15:44:12.647260 + +""" +import sqlalchemy as sa +import sqlmodel +from alembic import op +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = "4d7e0b0ebe84" +down_revision = "9e7ec4a9e3f2" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "troll_stats", + sa.Column("user_id", postgresql.UUID(as_uuid=True), nullable=False), + sa.Column("base_date", sa.DateTime(timezone=True), nullable=True), + sa.Column( + "modified_date", sa.DateTime(timezone=True), server_default=sa.text("CURRENT_TIMESTAMP"), nullable=False + ), + sa.Column("time_frame", sqlmodel.sql.sqltypes.AutoString(), nullable=False), + sa.Column("troll_score", sa.Integer(), nullable=False), + sa.Column("rank", sa.Integer(), nullable=True), + sa.Column("red_flags", sa.Integer(), nullable=False), + sa.Column("upvotes", sa.Integer(), nullable=False), + sa.Column("downvotes", sa.Integer(), nullable=False), + sa.Column("spam_prompts", sa.Integer(), nullable=False), + sa.Column("quality", sa.Float(), nullable=True), + sa.Column("humor", sa.Float(), nullable=True), + sa.Column("toxicity", sa.Float(), nullable=True), + sa.Column("violence", sa.Float(), nullable=True), + sa.Column("helpfulness", sa.Float(), nullable=True), + sa.Column("spam", sa.Integer(), nullable=False), + sa.Column("lang_mismach", sa.Integer(), nullable=False), + sa.Column("not_appropriate", sa.Integer(), nullable=False), + sa.Column("pii", sa.Integer(), nullable=False), + sa.Column("hate_speech", sa.Integer(), nullable=False), + sa.Column("sexual_content", sa.Integer(), nullable=False), + sa.Column("political_content", sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(["user_id"], ["user.id"], ondelete="CASCADE"), + sa.PrimaryKeyConstraint("user_id", "time_frame"), + ) + op.create_index("ix_troll_stats__timeframe__user_id", "troll_stats", ["time_frame", "user_id"], unique=True) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_index("ix_troll_stats__timeframe__user_id", table_name="troll_stats") + op.drop_table("troll_stats") + # ### end Alembic commands ### diff --git a/backend/oasst_backend/api/v1/api.py b/backend/oasst_backend/api/v1/api.py index 003f039f..331a7841 100644 --- a/backend/oasst_backend/api/v1/api.py +++ b/backend/oasst_backend/api/v1/api.py @@ -10,6 +10,7 @@ from oasst_backend.api.v1 import ( stats, tasks, text_labels, + trollboards, users, ) @@ -22,6 +23,7 @@ api_router.include_router(users.router, prefix="/users", tags=["users"]) api_router.include_router(frontend_users.router, prefix="/frontend_users", tags=["frontend_users"]) api_router.include_router(stats.router, prefix="/stats", tags=["stats"]) api_router.include_router(leaderboards.router, prefix="/leaderboards", tags=["leaderboards"]) +api_router.include_router(trollboards.router, prefix="/trollboards", tags=["trollboards"]) api_router.include_router(hugging_face.router, prefix="/hf", tags=["hugging_face"]) api_router.include_router(admin.router, prefix="/admin", tags=["admin"]) api_router.include_router(auth.router, prefix="/auth", tags=["auth"]) diff --git a/backend/oasst_backend/api/v1/trollboards.py b/backend/oasst_backend/api/v1/trollboards.py new file mode 100644 index 00000000..4ba5c256 --- /dev/null +++ b/backend/oasst_backend/api/v1/trollboards.py @@ -0,0 +1,21 @@ +from typing import Optional + +from fastapi import APIRouter, Depends, Query +from oasst_backend.api import deps +from oasst_backend.models import ApiClient +from oasst_backend.user_stats_repository import UserStatsRepository, UserStatsTimeFrame +from oasst_shared.schemas.protocol import TrollboardStats +from sqlmodel import Session + +router = APIRouter() + + +@router.get("/{time_frame}", response_model=TrollboardStats) +def get_trollboard( + time_frame: UserStatsTimeFrame, + max_count: Optional[int] = Query(100, gt=0, le=10000), + api_client: ApiClient = Depends(deps.get_trusted_api_client), + db: Session = Depends(deps.get_db), +) -> TrollboardStats: + usr = UserStatsRepository(db) + return usr.get_trollboard(time_frame, limit=max_count) diff --git a/backend/oasst_backend/models/__init__.py b/backend/oasst_backend/models/__init__.py index 420c0ccd..65594dde 100644 --- a/backend/oasst_backend/models/__init__.py +++ b/backend/oasst_backend/models/__init__.py @@ -8,6 +8,7 @@ from .message_toxicity import MessageToxicity from .message_tree_state import MessageTreeState from .task import Task from .text_labels import TextLabels +from .troll_stats import TrollStats from .user import User from .user_stats import UserStats, UserStatsTimeFrame @@ -26,4 +27,5 @@ __all__ = [ "Journal", "JournalIntegration", "MessageEmoji", + "TrollStats", ] diff --git a/backend/oasst_backend/models/troll_stats.py b/backend/oasst_backend/models/troll_stats.py new file mode 100644 index 00000000..2cef7246 --- /dev/null +++ b/backend/oasst_backend/models/troll_stats.py @@ -0,0 +1,59 @@ +from datetime import datetime +from typing import Optional +from uuid import UUID + +import sqlalchemy as sa +import sqlalchemy.dialects.postgresql as pg +from sqlmodel import Field, Index, SQLModel + + +class TrollStats(SQLModel, table=True): + __tablename__ = "troll_stats" + __table_args__ = (Index("ix_troll_stats__timeframe__user_id", "time_frame", "user_id", unique=True),) + + time_frame: Optional[str] = Field(nullable=False, primary_key=True) + user_id: Optional[UUID] = Field( + sa_column=sa.Column(pg.UUID(as_uuid=True), sa.ForeignKey("user.id", ondelete="CASCADE"), primary_key=True) + ) + base_date: Optional[datetime] = Field(sa_column=sa.Column(sa.DateTime(timezone=True), nullable=True)) + + troll_score: int = 0 + modified_date: Optional[datetime] = Field( + sa_column=sa.Column(sa.DateTime(timezone=True), nullable=False, server_default=sa.func.current_timestamp()) + ) + + rank: int = Field(nullable=True) + + red_flags: int = 0 # num reported messages of user + upvotes: int = 0 # num up-voted messages of user + downvotes: int = 0 # num down-voted messages of user + + spam_prompts: int = 0 + + quality: float = Field(nullable=True) + humor: float = Field(nullable=True) + toxicity: float = Field(nullable=True) + violence: float = Field(nullable=True) + helpfulness: float = Field(nullable=True) + + spam: int = 0 + lang_mismach: int = 0 + not_appropriate: int = 0 + pii: int = 0 + hate_speech: int = 0 + sexual_content: int = 0 + political_content: int = 0 + + def compute_troll_score(self) -> int: + return ( + self.red_flags * 3 + - self.upvotes + + self.downvotes + + self.spam_prompts + + self.lang_mismach + + self.not_appropriate + + self.pii + + self.hate_speech + + self.sexual_content + + self.political_content + ) diff --git a/backend/oasst_backend/user_stats_repository.py b/backend/oasst_backend/user_stats_repository.py index 3862d098..4c28b293 100644 --- a/backend/oasst_backend/user_stats_repository.py +++ b/backend/oasst_backend/user_stats_repository.py @@ -5,19 +5,31 @@ from uuid import UUID import sqlalchemy as sa from loguru import logger from oasst_backend.config import settings -from oasst_backend.models import Message, MessageReaction, Task, User, UserStats, UserStatsTimeFrame +from oasst_backend.models import ( + Message, + MessageReaction, + MessageTreeState, + Task, + TextLabels, + TrollStats, + User, + UserStats, + UserStatsTimeFrame, +) from oasst_backend.models.db_payload import ( LabelAssistantReplyPayload, LabelPrompterReplyPayload, RankingReactionPayload, ) -from oasst_shared.schemas.protocol import LeaderboardStats, UserScore +from oasst_backend.models.message_tree_state import State as TreeState +from oasst_shared.schemas.protocol import EmojiCode, LeaderboardStats, TextLabel, TrollboardStats, TrollScore, UserScore from oasst_shared.utils import log_timing, utcnow from sqlalchemy.dialects import postgresql +from sqlalchemy.sql.functions import coalesce from sqlmodel import Session, delete, func, text -def _create_user_score(r, highlighted_user_id: UUID | None): +def _create_user_score(r, highlighted_user_id: UUID | None) -> UserScore: if r["UserStats"]: d = r["UserStats"].dict() else: @@ -37,6 +49,24 @@ def _create_user_score(r, highlighted_user_id: UUID | None): return UserScore(**d) +def _create_troll_score(r, highlighted_user_id: UUID | None) -> TrollScore: + if r["TrollStats"]: + d = r["TrollStats"].dict() + else: + d = {"modified_date": utcnow()} + for k in [ + "user_id", + "username", + "auth_method", + "display_name", + "last_activity_date", + ]: + d[k] = r[k] + if highlighted_user_id: + d["highlighted"] = r["user_id"] == highlighted_user_id + return TrollScore(**d) + + class UserStatsRepository: def __init__(self, session: Session): self.session = session @@ -133,6 +163,38 @@ class UserStatsRepository: stats_by_timeframe = {tf.value: _create_user_score(r, user_id) for tf in UserStatsTimeFrame} return stats_by_timeframe + def get_trollboard( + self, + time_frame: UserStatsTimeFrame, + limit: int = 100, + highlighted_user_id: Optional[UUID] = None, + ) -> TrollboardStats: + """ + Get trollboard stats for the specified time frame + """ + + qry = ( + self.session.query( + User.id.label("user_id"), + User.username, + User.auth_method, + User.display_name, + User.last_activity_date, + TrollStats, + ) + .join(TrollStats, User.id == TrollStats.user_id) + .filter(TrollStats.time_frame == time_frame.value) + .order_by(TrollStats.rank) + .limit(limit) + ) + + trollboard = [_create_troll_score(r, highlighted_user_id) for r in self.session.exec(qry)] + if len(trollboard) > 0: + last_update = max(x.modified_date for x in trollboard) + else: + last_update = utcnow() + return TrollboardStats(time_frame=time_frame.value, trollboard=trollboard, last_updated=last_update) + def query_total_prompts_per_user( self, reference_time: Optional[datetime] = None, only_reviewed: Optional[bool] = True ): @@ -292,10 +354,145 @@ class UserStatsRepository: self.session.add_all(stats_by_user.values()) self.session.flush() - self.update_ranks(time_frame=time_frame) + self.update_leader_ranks(time_frame=time_frame) + + def query_message_emoji_counts_per_user(self, reference_time: Optional[datetime] = None): + qry = self.session.query( + Message.user_id, + func.sum(coalesce(Message.emojis[EmojiCode.thumbs_up].cast(sa.Integer), 0)).label("up"), + func.sum(coalesce(Message.emojis[EmojiCode.thumbs_down].cast(sa.Integer), 0)).label("down"), + func.sum(coalesce(Message.emojis[EmojiCode.red_flag].cast(sa.Integer), 0)).label("flag"), + ).filter(Message.deleted == sa.false(), Message.emojis.is_not(None)) + + if reference_time: + qry = qry.filter(Message.created_date >= reference_time) + + qry = qry.group_by(Message.user_id) + return qry + + def query_spam_prompts_per_user(self, reference_time: Optional[datetime] = None): + qry = ( + self.session.query(Message.user_id, func.count().label("spam_prompts")) + .select_from(MessageTreeState) + .join(Message, MessageTreeState.message_tree_id == Message.id) + .filter(MessageTreeState.state == TreeState.ABORTED_LOW_GRADE) + ) + + if reference_time: + qry = qry.filter(Message.created_date >= reference_time) + + qry = qry.group_by(Message.user_id) + return qry + + def query_labels_per_user(self, reference_time: Optional[datetime] = None): + qry = ( + self.session.query( + Message.user_id, + func.sum(coalesce(TextLabels.labels[TextLabel.spam].cast(sa.Integer), 0)).label("spam"), + func.sum(coalesce(TextLabels.labels[TextLabel.lang_mismatch].cast(sa.Integer), 0)).label( + "lang_mismach" + ), + func.sum(coalesce(TextLabels.labels[TextLabel.not_appropriate].cast(sa.Integer), 0)).label( + "not_appropriate" + ), + func.sum(coalesce(TextLabels.labels[TextLabel.pii].cast(sa.Integer), 0)).label("pii"), + func.sum(coalesce(TextLabels.labels[TextLabel.hate_speech].cast(sa.Integer), 0)).label("hate_speech"), + func.sum(coalesce(TextLabels.labels[TextLabel.sexual_content].cast(sa.Integer), 0)).label( + "sexual_content" + ), + func.sum(coalesce(TextLabels.labels[TextLabel.political_content].cast(sa.Integer), 0)).label( + "political_content" + ), + func.avg(TextLabels.labels[TextLabel.quality].cast(sa.Float)).label("quality"), + func.avg(TextLabels.labels[TextLabel.humor].cast(sa.Float)).label("humor"), + func.avg(TextLabels.labels[TextLabel.toxicity].cast(sa.Float)).label("toxicity"), + func.avg(TextLabels.labels[TextLabel.violence].cast(sa.Float)).label("violence"), + func.avg(TextLabels.labels[TextLabel.helpfulness].cast(sa.Float)).label("helpfulness"), + ) + .select_from(TextLabels) + .join(Message, TextLabels.message_id == Message.id) + .filter(Message.deleted == sa.false(), Message.emojis.is_not(None)) + ) + + if reference_time: + qry = qry.filter(Message.created_date >= reference_time) + + qry = qry.group_by(Message.user_id) + return qry + + def _update_troll_stats_internal(self, time_frame: UserStatsTimeFrame, base_date: Optional[datetime] = None): + # gather user data + + time_frame_key = time_frame.value + + stats_by_user: dict[UUID, TrollStats] = dict() + now = utcnow() + + def get_stats(id: UUID) -> TrollStats: + us = stats_by_user.get(id) + if not us: + us = TrollStats(user_id=id, time_frame=time_frame_key, modified_date=now, base_date=base_date) + stats_by_user[id] = us + return us + + # emoji counts of user's messages + qry = self.query_message_emoji_counts_per_user(reference_time=base_date) + for r in qry: + uid = r["user_id"] + s = get_stats(uid) + s.upvotes = r["up"] + s.downvotes = r["down"] + s.red_flags = r["flag"] + + # num spam prompts + qry = self.query_spam_prompts_per_user(reference_time=base_date) + for r in qry: + uid, count = r + s = get_stats(uid).spam_prompts = count + + label_field_names = ( + "quality", + "humor", + "toxicity", + "violence", + "helpfulness", + "spam", + "lang_mismach", + "not_appropriate", + "pii", + "hate_speech", + "sexual_content", + "political_content", + ) + + # label counts / mean values + qry = self.query_labels_per_user(reference_time=base_date) + for r in qry: + uid = r["user_id"] + s = get_stats(uid) + for fn in label_field_names: + setattr(s, fn, r[fn]) + + # delete all existing stast for time frame + d = delete(TrollStats).where(TrollStats.time_frame == time_frame_key) + self.session.execute(d) + + if None in stats_by_user: + logger.warning("Some messages in DB have NULL values in user_id column.") + del stats_by_user[None] + + # compute magic leader score + for v in stats_by_user.values(): + v.troll_score = v.compute_troll_score() + + # insert user objects + self.session.add_all(stats_by_user.values()) + self.session.flush() + + self.update_troll_ranks(time_frame=time_frame) @log_timing(log_kwargs=True) - def update_ranks(self, time_frame: UserStatsTimeFrame = None): + def update_leader_ranks(self, time_frame: UserStatsTimeFrame = None): """ Update user_stats ranks. The persisted rank values allow to quickly the rank of a single user and to query nearby users. @@ -329,10 +526,41 @@ WHERE r = self.session.execute( text(sql_update_rank), {"time_frame": time_frame.value if time_frame is not None else None} ) - logger.debug(f"pre_compute_ranks updated({time_frame=}) {r.rowcount} rows.") + logger.debug(f"pre_compute_ranks leader updated({time_frame=}) {r.rowcount} rows.") - def update_stats_time_frame(self, time_frame: UserStatsTimeFrame, reference_time: Optional[datetime] = None): - self._update_stats_internal(time_frame, reference_time) + @log_timing(log_kwargs=True) + def update_troll_ranks(self, time_frame: UserStatsTimeFrame = None): + sql_update_troll_rank = """ +-- update rank +UPDATE troll_stats ts +SET "rank" = r."rank" +FROM + (SELECT + ROW_NUMBER () OVER( + PARTITION BY time_frame + ORDER BY troll_score DESC, user_id + ) AS "rank", user_id, time_frame + FROM troll_stats ts2 + WHERE (:time_frame IS NULL OR time_frame = :time_frame)) AS r +WHERE + ts.user_id = r.user_id + AND ts.time_frame = r.time_frame;""" + r = self.session.execute( + text(sql_update_troll_rank), {"time_frame": time_frame.value if time_frame is not None else None} + ) + logger.debug(f"pre_compute_ranks troll updated({time_frame=}) {r.rowcount} rows.") + + def update_stats_time_frame( + self, + time_frame: UserStatsTimeFrame, + reference_time: Optional[datetime] = None, + leader_stats: bool = True, + troll_stats: bool = True, + ): + if leader_stats: + self._update_stats_internal(time_frame, reference_time) + if troll_stats: + self._update_troll_stats_internal(time_frame, reference_time) self.session.commit() @log_timing(log_kwargs=True, level="INFO") diff --git a/oasst-shared/oasst_shared/schemas/protocol.py b/oasst-shared/oasst_shared/schemas/protocol.py index 3570d3fd..e0dde366 100644 --- a/oasst-shared/oasst_shared/schemas/protocol.py +++ b/oasst-shared/oasst_shared/schemas/protocol.py @@ -469,6 +469,47 @@ class LeaderboardStats(BaseModel): leaderboard: List[UserScore] +class TrollScore(BaseModel): + rank: Optional[int] + user_id: UUID + highlighted: bool = False + username: str + auth_method: str + display_name: str + last_activity_date: Optional[datetime] + + troll_score: int = 0 + + base_date: Optional[datetime] + modified_date: Optional[datetime] + + red_flags: int = 0 # num reported messages of user + upvotes: int = 0 # num up-voted messages of user + downvotes: int = 0 # num down-voted messages of user + + spam_prompts: int = 0 + + quality: Optional[float] = None + humor: Optional[float] = None + toxicity: Optional[float] = None + violence: Optional[float] = None + helpfulness: Optional[float] = None + + spam: int = 0 + lang_mismach: int = 0 + not_appropriate: int = 0 + pii: int = 0 + hate_speech: int = 0 + sexual_content: int = 0 + political_content: int = 0 + + +class TrollboardStats(BaseModel): + time_frame: str + last_updated: datetime + trollboard: List[TrollScore] + + class OasstErrorResponse(BaseModel): """The format of an error response from the OASST API.""" From dfd2c352764440bbc4f5877d0c26b1a29d107afa Mon Sep 17 00:00:00 2001 From: Alex Ott <66271487+AlexanderHOtt@users.noreply.github.com> Date: Thu, 2 Feb 2023 08:28:00 -0800 Subject: [PATCH 020/152] Feat/task handler (#1056) * move task logic to task handlers * rename command * remove test code * rename classes and add missing handler creations * switch task back to random and fetch log_channel_id from db --- discord-bot/.env.example | 2 +- discord-bot/bot/extensions/work.py | 779 ++++++++++++------------ discord-bot/bot/messages.py | 198 +++--- oasst-shared/oasst_shared/api_client.py | 12 +- 4 files changed, 526 insertions(+), 465 deletions(-) diff --git a/discord-bot/.env.example b/discord-bot/.env.example index 8474ee90..33262896 100644 --- a/discord-bot/.env.example +++ b/discord-bot/.env.example @@ -4,4 +4,4 @@ OWNER_IDS=[, ] PREFIX="/" # DO NOT LEAVE EMPTY, slash command prefix in DMs OASST_API_URL="http://localhost:8080" # No trailing '/' -OASST_API_KEY="" +OASST_API_KEY="1234" diff --git a/discord-bot/bot/extensions/work.py b/discord-bot/bot/extensions/work.py index 51daca3b..7a57265f 100644 --- a/discord-bot/bot/extensions/work.py +++ b/discord-bot/bot/extensions/work.py @@ -9,27 +9,25 @@ import lightbulb.decorators import miru from aiosqlite import Connection from bot.messages import ( - assistant_reply_message, + assistant_reply_messages, confirm_label_response_message, confirm_ranking_response_message, confirm_text_response_message, - initial_prompt_message, - invalid_user_input_embed, - label_assistant_reply_message, - label_initial_prompt_message, - label_prompter_reply_message, + initial_prompt_messages, + label_assistant_reply_messages, + label_prompter_reply_messages, plain_embed, - prompter_reply_message, + prompter_reply_messages, rank_assistant_reply_message, - rank_initial_prompts_message, - rank_prompter_reply_message, + rank_conversation_reply_messages, + rank_initial_prompts_messages, + rank_prompter_reply_messages, task_complete_embed, ) from bot.settings import Settings from loguru import logger -from oasst_shared.api_client import OasstApiClient, TaskType +from oasst_shared.api_client import OasstApiClient from oasst_shared.schemas import protocol as protocol_schema -from oasst_shared.schemas.protocol import TaskRequestType plugin = lightbulb.Plugin("WorkPlugin") @@ -38,30 +36,337 @@ MAX_TASK_ACCEPT_TIME = 60 * 10 # seconds settings = Settings() +_Task_contra = t.TypeVar("_Task_contra", bound=protocol_schema.Task, contravariant=True) + + +class _TaskHandler(t.Generic[_Task_contra]): + """Handle user interaction for a task.""" + + def __init__(self, ctx: lightbulb.Context, task: _Task_contra) -> None: + """Create a new `TaskHandler`. + + Args: + ctx (lightbulb.Context): The context of the command that started the task. + task (_Task_contra): The task to handle. + """ + self.ctx = ctx + self.task = task + self.task_messages = self.get_task_messages(task) + self.sent_messages: list[hikari.Message] = [] + + @staticmethod + def get_task_messages(task: _Task_contra) -> list[str]: + """Get the messages to send to the user for the task.""" + raise NotImplementedError + + async def send(self) -> t.Literal["accept", "next", "cancel"] | None: + """Send the task and wait for the user to accept/skip/cancel it.""" + # Send all but the last message because we need to attach buttons to the last one + logger.debug(f"Sending {len(self.task_messages)} messages\n{self.task_messages!r}") + for task_msg in self.task_messages[:-1]: + if len(task_msg) > 2000: + logger.warning(f"Attempting to send a message <2000 characters in length. Task id: {self.task.id}") + task_msg = task_msg[:1999] + self.sent_messages.append(await self.ctx.author.send(task_msg)) + + # Send the last message with buttons + task_accept_view = TaskAcceptView(timeout=MAX_TASK_ACCEPT_TIME) + logger.debug(f"TH Message length {len(self.task_messages[-1])}") + last_msg = await self.ctx.author.send(self.task_messages[-1][:1999], components=task_accept_view) + + await task_accept_view.start(last_msg) + await task_accept_view.wait() + + return task_accept_view.choice + + async def handle(self) -> None: + """Handle the user's response to the task. + + This method should be called after `send` has been called.""" + # Ack task to the backend + oasst_api: OasstApiClient = self.ctx.bot.d.oasst_api + await oasst_api.ack_task(self.task.id, message_id=f"{self.sent_messages[0].id}") + + # Loop until the user's input is accepted + while True: + try: + # Wait for user to send a message + event = await self.ctx.bot.wait_for( + hikari.DMMessageCreateEvent, + predicate=lambda e: ( + e.author_id == self.ctx.author.id + and e.message.content is not None + and not e.message.content.startswith(settings.prefix) + ), + timeout=MAX_TASK_TIME, + ) + + # Validate the message + if event.content is None or not self.check_user_input(event.content): + await self.ctx.author.send("Invalid input") + continue + + # Confirm user input + if not (await self.confirm_user_input(event.content)): + continue + + # Message is valid and confirmed by user + break + + except asyncio.TimeoutError: + return + + next_task = await self.notify(event.content, event) + if not isinstance(next_task, protocol_schema.TaskDone): + raise TypeError(f"Unknown task type: {next_task!r}") + + return + + async def notify(self, content: str, event: hikari.DMMessageCreateEvent) -> protocol_schema.Task: + """Notify the backend that the user completed the task.""" + raise NotImplementedError + + async def confirm_user_input(self, content: str) -> bool: + """Send the user's response back to the user and ask them to confirm it. Returns True if the user confirms.""" + raise NotImplementedError + + def check_user_input(self, content: str) -> bool: + """Check the user's response to the task. Returns True if the response is valid.""" + raise NotImplementedError + + async def cancel(self, reason: str = "not specified") -> None: + """Cancel the task.""" + oasst_api: OasstApiClient = self.ctx.bot.d.oasst_api + await oasst_api.nack_task(self.task.id, reason) + + +_Ranking_contra = t.TypeVar( + "_Ranking_contra", + bound=protocol_schema.RankAssistantRepliesTask + | protocol_schema.RankInitialPromptsTask + | protocol_schema.RankPrompterRepliesTask + | protocol_schema.RankConversationRepliesTask, + contravariant=True, +) + + +class _RankingTaskHandler(_TaskHandler[_Ranking_contra]): + """This should not be used directly. Use its subclasses instead.""" + + async def notify(self, content: str, event: hikari.DMMessageCreateEvent) -> protocol_schema.Task: + oasst_api: OasstApiClient = self.ctx.bot.d.oasst_api + + task = await oasst_api.post_interaction( + protocol_schema.MessageRanking( + user=protocol_schema.User( + id=f"{self.ctx.author.id}", auth_method="discord", display_name=self.ctx.author.username + ), + ranking=[int(r) - 1 for r in content.split(",")], + message_id=f"{self.sent_messages[0].id}", + ) + ) + + db: Connection = self.ctx.bot.d.db + async with db.cursor() as cursor: + row = await ( + await cursor.execute("SELECT log_channel_id FROM guilds WHERE guild_id = ?", (self.ctx.guild_id,)) + ).fetchone() + log_channel = row[0] if row else None + log_messages: list[hikari.Message] = [] + + if log_channel is not None: + for message in self.task_messages[:-1]: + msg = await self.ctx.bot.rest.create_message(log_channel, message) + log_messages.append(msg) + await self.ctx.bot.rest.create_message(log_channel, task_complete_embed(self.task, self.ctx.author.mention)) + + return task + + +class RankAssistantRepliesHandler(_RankingTaskHandler[protocol_schema.RankAssistantRepliesTask]): + @staticmethod + def get_task_messages(task: protocol_schema.RankAssistantRepliesTask) -> list[str]: + return rank_assistant_reply_message(task) + + def check_user_input(self, content: str) -> bool: + return len(content.split(",")) == len(self.task.reply_messages) and all( + [r.isdigit() and int(r) in range(1, len(self.task.reply_messages) + 1) for r in content.split(",")] + ) + + async def confirm_user_input(self, content: str) -> bool: + confirm_input_view = YesNoView() + msg = await self.ctx.author.send( + confirm_ranking_response_message(content, self.task.reply_messages), components=confirm_input_view + ) + await confirm_input_view.start(msg) + await confirm_input_view.wait() + + return bool(confirm_input_view.choice) + + +class RankInitialPromptHandler(_RankingTaskHandler[protocol_schema.RankInitialPromptsTask]): + def __init__(self, ctx: lightbulb.Context, task: protocol_schema.RankInitialPromptsTask) -> None: + super().__init__(ctx, task) + + @staticmethod + def get_task_messages(task: protocol_schema.RankInitialPromptsTask) -> list[str]: + return rank_initial_prompts_messages(task) + + def check_user_input(self, content: str) -> bool: + return len(content.split(",")) == len(self.task.prompt_messages) and all( + [r.isdigit() and int(r) in range(1, len(self.task.prompt_messages) + 1) for r in content.split(",")] + ) + + async def confirm_user_input(self, content: str) -> bool: + confirm_input_view = YesNoView() + msg = await self.ctx.author.send( + confirm_ranking_response_message(content, self.task.prompt_messages), components=confirm_input_view + ) + await confirm_input_view.start(msg) + await confirm_input_view.wait() + + return bool(confirm_input_view.choice) + + +class RankPrompterReplyHandler(_RankingTaskHandler[protocol_schema.RankPrompterRepliesTask]): + @staticmethod + def get_task_messages(task: protocol_schema.RankPrompterRepliesTask) -> list[str]: + return rank_prompter_reply_messages(task) + + def check_user_input(self, content: str) -> bool: + return len(content.split(",")) == len(self.task.reply_messages) and all( + [r.isdigit() and int(r) in range(1, len(self.task.reply_messages) + 1) for r in content.split(",")] + ) + + async def confirm_user_input(self, content: str) -> bool: + confirm_input_view = YesNoView() + msg = await self.ctx.author.send( + confirm_ranking_response_message(content, self.task.reply_messages), components=confirm_input_view + ) + await confirm_input_view.start(msg) + await confirm_input_view.wait() + + return bool(confirm_input_view.choice) + + +class RankConversationReplyHandler(_RankingTaskHandler[protocol_schema.RankConversationRepliesTask]): + @staticmethod + def get_task_messages(task: protocol_schema.RankConversationRepliesTask) -> list[str]: + return rank_conversation_reply_messages(task) + + def check_user_input(self, content: str) -> bool: + return len(content.split(",")) == len(self.task.reply_messages) and all( + [r.isdigit() and int(r) in range(1, len(self.task.reply_messages) + 1) for r in content.split(",")] + ) + + async def confirm_user_input(self, content: str) -> bool: + confirm_input_view = YesNoView() + msg = await self.ctx.author.send( + confirm_ranking_response_message(content, self.task.reply_messages), components=confirm_input_view + ) + await confirm_input_view.start(msg) + await confirm_input_view.wait() + + return bool(confirm_input_view.choice) + + +class InitialPromptHandler(_TaskHandler[protocol_schema.InitialPromptTask]): + @staticmethod + def get_task_messages(task: protocol_schema.InitialPromptTask) -> list[str]: + return initial_prompt_messages(task) + + def check_user_input(self, content: str) -> bool: + return len(content) > 0 + + async def confirm_user_input(self, content: str) -> bool: + confirm_input_view = YesNoView() + msg = await self.ctx.author.send(confirm_text_response_message(content), components=confirm_input_view) + await confirm_input_view.start(msg) + await confirm_input_view.wait() + + return bool(confirm_input_view.choice) + + +class PrompterReplyHandler(_TaskHandler[protocol_schema.PrompterReplyTask]): + @staticmethod + def get_task_messages(task: protocol_schema.PrompterReplyTask) -> list[str]: + return prompter_reply_messages(task) + + def check_user_input(self, content: str) -> bool: + return len(content) > 0 + + async def confirm_user_input(self, content: str) -> bool: + confirm_input_view = YesNoView() + msg = await self.ctx.author.send(confirm_text_response_message(content), components=confirm_input_view) + await confirm_input_view.start(msg) + await confirm_input_view.wait() + + return bool(confirm_input_view.choice) + + +class AssistantReplyHandler(_TaskHandler[protocol_schema.AssistantReplyTask]): + @staticmethod + def get_task_messages(task: protocol_schema.AssistantReplyTask) -> list[str]: + return assistant_reply_messages(task) + + def check_user_input(self, content: str) -> bool: + return len(content) > 0 + + async def confirm_user_input(self, content: str) -> bool: + confirm_input_view = YesNoView() + msg = await self.ctx.author.send(confirm_text_response_message(content), components=confirm_input_view) + await confirm_input_view.start(msg) + await confirm_input_view.wait() + + return bool(confirm_input_view.choice) + + +_Label_contra = t.TypeVar("_Label_contra", bound=protocol_schema.LabelConversationReplyTask, contravariant=True) + + +class _LabelConversationReplyHandler(_TaskHandler[_Label_contra]): + def check_user_input(self, content: str) -> bool: + user_labels = content.split(",") + return ( + all([l in self.task.valid_labels for l in user_labels]) + and self.task.mandatory_labels is not None + and all([m in user_labels for m in self.task.mandatory_labels]) + ) + + async def confirm_user_input(self, content: str) -> bool: + confirm_input_view = YesNoView() + msg = await self.ctx.author.send(confirm_label_response_message(content), components=confirm_input_view) + await confirm_input_view.start(msg) + await confirm_input_view.wait() + + return bool(confirm_input_view.choice) + + +class LabelAssistantReplyHandler(_LabelConversationReplyHandler[protocol_schema.LabelAssistantReplyTask]): + @staticmethod + def get_task_messages(task: protocol_schema.LabelAssistantReplyTask) -> list[str]: + return label_assistant_reply_messages(task) + + +class LabelPrompterReplyHandler(_LabelConversationReplyHandler[protocol_schema.LabelPrompterReplyTask]): + @staticmethod + def get_task_messages(task: protocol_schema.LabelPrompterReplyTask) -> list[str]: + return label_prompter_reply_messages(task) + + +summarize_story = "summarize_story" +rate_summary = "rate_summary" + @plugin.command -@lightbulb.option( - "type", - "The type of task to request.", - choices=[hikari.CommandChoice(name=task.value, value=task) for task in TaskRequestType], - required=False, - default=str(TaskRequestType.random), - type=str, -) @lightbulb.command("work", "Complete a task.") @lightbulb.implements(lightbulb.SlashCommand, lightbulb.PrefixCommand) -async def work(ctx: lightbulb.Context): - """Create and handle a task.""" - # Only send this message if started from a server - if ctx.guild_id is not None: - await ctx.respond(embed=plain_embed("Sending you a task, check your DMs"), flags=hikari.MessageFlag.EPHEMERAL) - - # make sure the user isn't currently doing a task, and if they are, ask if they want to cancel it - currently_working: dict[ - hikari.Snowflakeish, tuple[hikari.Message | None, UUID | None] - ] = ctx.bot.d.currently_working - +async def work2(ctx: lightbulb.Context) -> None: + """Complete a task.""" oasst_api: OasstApiClient = ctx.bot.d.oasst_api + currently_working: dict[hikari.Snowflake, UUID] = ctx.bot.d.currently_working + + # Check if the user is already working on a task if ctx.author.id in currently_working: yn_view = YesNoView(timeout=MAX_TASK_ACCEPT_TIME) msg = await ctx.author.send( @@ -76,374 +381,66 @@ async def work(ctx: lightbulb.Context): case False | None: return case True: - old_msg, task_id = currently_working[ctx.author.id] - if old_msg is not None: - logger.info(f"User {ctx.author.id} cancelled task {task_id}, deleting message {old_msg.id}") - map(lambda c: c, old_msg.components) - await old_msg.delete() - if task_id is not None: - await oasst_api.nack_task(task_id, reason="user cancelled") + task_id = currently_working[ctx.author.id] + await oasst_api.nack_task(task_id, reason="user cancelled") - await msg.delete() + if ctx.guild_id: + await ctx.respond("check DMs", flags=hikari.MessageFlag.EPHEMERAL) - currently_working[ctx.author.id] = (None, None) - - # Create a TaskRequestType from the stringified enum value - task_type: TaskRequestType = TaskRequestType(ctx.options.type.split(".")[-1]) - - logger.debug(f"Starting task_type: {task_type!r}") + # Keep sending tasks until the user doesn't want more try: - await _handle_task(ctx, task_type) + while True: + task = await oasst_api.fetch_random_task( + user=protocol_schema.User( + id=f"{ctx.author.id}", display_name=ctx.author.username, auth_method="discord" + ), + ) + + # Ranking tasks + if isinstance(task, protocol_schema.RankAssistantRepliesTask): + task_handler = RankAssistantRepliesHandler(ctx, task) + elif isinstance(task, protocol_schema.RankInitialPromptsTask): + task_handler = RankInitialPromptHandler(ctx, task) + elif isinstance(task, protocol_schema.RankPrompterRepliesTask): + task_handler = RankPrompterReplyHandler(ctx, task) + elif isinstance(task, protocol_schema.RankConversationRepliesTask): + task_handler = RankConversationReplyHandler(ctx, task) + + # Text input tasks + elif isinstance(task, protocol_schema.InitialPromptTask): + task_handler = InitialPromptHandler(ctx, task) + elif isinstance(task, protocol_schema.PrompterReplyTask): + task_handler = PrompterReplyHandler(ctx, task) + elif isinstance(task, protocol_schema.AssistantReplyTask): + task_handler = AssistantReplyHandler(ctx, task) + + # Label tasks + elif isinstance(task, protocol_schema.LabelAssistantReplyTask): + task_handler = LabelAssistantReplyHandler(ctx, task) + elif isinstance(task, protocol_schema.LabelPrompterReplyTask): + task_handler = LabelPrompterReplyHandler(ctx, task) + + else: + raise ValueError(f"Unknown task type: {type(task)}") + + resp = await task_handler.send() + + match resp: + case "accept": + currently_working[ctx.author.id] = task.id + await task_handler.handle() + case "next": + await task_handler.cancel("user skipped task") + case "cancel": + await task_handler.cancel("user canceled work") + break + case None: + await task_handler.cancel("select timed out") + break finally: del currently_working[ctx.author.id] -async def _handle_task(ctx: lightbulb.Context, task_type: TaskRequestType) -> None: - """Handle creating and collecting user input for a task. - - Continually present tasks to the user until they select one, cancel, or time out. - If they select one, present the task steps until a `task_done` task is received. - Finally, ask the user if they want to perform another task (of the same type). - """ - oasst_api: OasstApiClient = ctx.bot.d.oasst_api - - # Continue to complete tasks until the user doesn't want to do another - done = False - while not done: - - # Loop until the user accepts a task - task, msg_id = await _select_task(ctx, task_type) - - if task is None: - # User cancelled - return - - # Task action loop - completed = False - while not completed: - await ctx.author.send(embed=plain_embed("Please type your response below:")) - try: - event = await ctx.bot.wait_for( - hikari.DMMessageCreateEvent, - timeout=MAX_TASK_TIME, - predicate=lambda e: e.author.id == ctx.author.id - and not (e.message.content or "").startswith(settings.prefix), - ) - except asyncio.TimeoutError: - await ctx.author.send(embed=plain_embed("Task timed out. Exiting")) - await oasst_api.nack_task(task.id, reason="timed out") - logger.info(f"Task {task.id} timed out") - return - - # Invalid response - valid, err_msg = _validate_user_input(event.content, task) - if not valid or event.content is None: - - await ctx.author.send(embed=invalid_user_input_embed(err_msg)) - continue - - logger.debug(f"Successful user input received: {event.content}") - - # Confirm user input - if isinstance(task, protocol_schema.RankConversationRepliesTask): - content = confirm_ranking_response_message(event.content, task.replies) - elif isinstance(task, protocol_schema.RankInitialPromptsTask): - content = confirm_ranking_response_message(event.content, task.prompts) - elif isinstance(task, protocol_schema.LabelConversationReplyTask | protocol_schema.LabelInitialPromptTask): - content = confirm_label_response_message(event.content) - elif isinstance(task, protocol_schema.ReplyToConversationTask | protocol_schema.InitialPromptTask): - content = confirm_text_response_message(event.content) - else: - logger.critical(f"Unknown task type: {task.type}") - raise ValueError(f"Unknown task type: {task.type}") - - confirm_resp_view = YesNoView(timeout=MAX_TASK_TIME) - msg = await ctx.author.send(content, components=confirm_resp_view) - await confirm_resp_view.start(msg) - await confirm_resp_view.wait() - - match confirm_resp_view.choice: - case False | None: - continue - case True: - await msg.delete() # buttons are already gone - - # Send the response to the backend - if isinstance(task, protocol_schema.RankConversationRepliesTask | protocol_schema.RankInitialPromptsTask): - reply = protocol_schema.MessageRanking( - message_id=str(msg_id), - ranking=[int(r) - 1 for r in event.content.replace(" ", "").split(",")], - user=protocol_schema.User( - auth_method="discord", id=str(ctx.author.id), display_name=ctx.author.username - ), - ) - elif isinstance(task, protocol_schema.LabelConversationReplyTask | protocol_schema.LabelInitialPromptTask): - labels = event.content.replace(" ", "").split(",") - labels_dict = {label: 1 if label in labels else 0 for label in task.valid_labels} - - reply = protocol_schema.TextLabels( - message_id=task.message_id, - labels=labels_dict, - user=protocol_schema.User( - auth_method="discord", id=str(ctx.author.id), display_name=ctx.author.username - ), - ) - elif isinstance(task, protocol_schema.ReplyToConversationTask | protocol_schema.InitialPromptTask): - reply = protocol_schema.TextReplyToMessage( - message_id=str(msg_id), - user_message_id=str(event.message_id), - user=protocol_schema.User( - auth_method="discord", id=str(ctx.author.id), display_name=ctx.author.username - ), - text=event.content, - ) - else: - logger.critical(f"Unexpected task type received: {task.type}") - raise ValueError(f"Unexpected task type received: {task.type}") - - logger.debug(f"Sending reply to backend: {reply!r}") - - # Get next task - new_task = await oasst_api.post_interaction(reply) - logger.info(f"New task {new_task}") - - if new_task.type == TaskType.done: - await ctx.author.send(embed=plain_embed("Task completed")) - completed = True - continue - else: - logger.critical(f"Unexpected task type received: {new_task.type}") - - # Send a message in all the log channels that the task is complete - conn: Connection = ctx.bot.d.db - async with conn.cursor() as cursor: - await cursor.execute("SELECT log_channel_id FROM guild_settings") - log_channel_ids = await cursor.fetchall() - - channels = [ - ctx.bot.cache.get_guild_channel(id[0]) or await ctx.bot.rest.fetch_channel(id[0]) - for id in log_channel_ids - ] - - done_embed = task_complete_embed(task, ctx.author.mention) - # This will definitely get the bot rate limited, but that's a future problem - asyncio.gather(*(ch.send(embed=done_embed) for ch in channels if isinstance(ch, hikari.TextableChannel))) - - # ask the user if they want to do another task - another_task_view = YesNoView(timeout=MAX_TASK_ACCEPT_TIME) - msg = await ctx.author.send(embed=plain_embed("Would you like another task?"), components=another_task_view) - await another_task_view.start(msg) - await another_task_view.wait() - - match another_task_view.choice: - case False | None: - done = True - await msg.edit(embed=plain_embed("Exiting, goodbye!")) - case True: - pass - - -async def _select_task( - ctx: lightbulb.Context, task_type: TaskRequestType, user: protocol_schema.User | None = None -) -> tuple[protocol_schema.Task | None, str]: - """Present tasks to the user until they accept one, cancel, or time out.""" - oasst_api: OasstApiClient = ctx.bot.d.oasst_api - logger.debug(f"Starting task selection for {task_type}") - - # Loop until the user accepts a task, cancels, or times out - msg: hikari.UndefinedOr[hikari.Message] = hikari.UNDEFINED - while True: - logger.debug(f"Requesting task of type {task_type}") - task = await oasst_api.fetch_task(task_type, user) - resp, msg = await _send_task(ctx, task, msg) - msg_id = str(msg.id) - - logger.debug(f"User choice: {resp}") - match resp: - case "accept": - logger.info(f"Task {task.id} accepted, sending ACK") - await oasst_api.ack_task(task.id, msg_id) - return task, msg_id - - case "next": - logger.info(f"Task {task.id} rejected, sending NACK") - await oasst_api.nack_task(task.id, "rejected") - continue - - case "cancel": - logger.info(f"Task {task.id} canceled, sending NACK") - await oasst_api.nack_task(task.id, "canceled") - await ctx.author.send(embed=plain_embed("Task canceled. Exiting")) - return None, msg_id - - case None: - logger.info(f"Task {task.id} timed out, sending NACK") - await oasst_api.nack_task(task.id, "timed out") - await ctx.author.send(embed=plain_embed("Task timed out. Exiting")) - return None, msg_id - - -async def _send_task( - ctx: lightbulb.Context, task: protocol_schema.Task, msg: hikari.UndefinedOr[hikari.Message] -) -> tuple[t.Literal["accept", "next", "cancel"] | None, hikari.Message]: - """Send a task to the user. - - Returns the user's choice and the message ID of the task message. - """ - # The clean way to do this would be to attach a `to_embed` method to the task classes - # but the tasks aren't discord specific so that doesn't really make sense. - - embed: hikari.UndefinedOr[hikari.Embed] = hikari.UNDEFINED - content: hikari.UndefinedOr[str] = hikari.UNDEFINED - - # Create an embed based on the task's type - if task.type == TaskRequestType.initial_prompt: - assert isinstance(task, protocol_schema.InitialPromptTask) - logger.debug("sending initial prompt task") - content = initial_prompt_message(task) - - elif task.type == TaskRequestType.rank_initial_prompts: - assert isinstance(task, protocol_schema.RankInitialPromptsTask) - logger.debug("sending rank initial prompt task") - content = rank_initial_prompts_message(task) - - elif task.type == TaskRequestType.rank_prompter_replies: - assert isinstance(task, protocol_schema.RankPrompterRepliesTask) - logger.debug("sending rank user reply task") - content = rank_prompter_reply_message(task) - - elif task.type == TaskRequestType.rank_assistant_replies: - assert isinstance(task, protocol_schema.RankAssistantRepliesTask) - logger.debug("sending rank assistant reply task") - content = rank_assistant_reply_message(task) - - elif task.type == TaskRequestType.label_initial_prompt: - assert isinstance(task, protocol_schema.LabelInitialPromptTask) - logger.debug("sending label initial prompt task") - content = label_initial_prompt_message(task) - - elif task.type == TaskRequestType.label_prompter_reply: - assert isinstance(task, protocol_schema.LabelPrompterReplyTask) - logger.debug("sending label prompter reply task") - content = label_prompter_reply_message(task) - - elif task.type == TaskRequestType.label_assistant_reply: - assert isinstance(task, protocol_schema.LabelAssistantReplyTask) - logger.debug("sending label assistant reply task") - content = label_assistant_reply_message(task) - - elif task.type == TaskRequestType.prompter_reply: - assert isinstance(task, protocol_schema.PrompterReplyTask) - logger.debug("sending user reply task") - content = prompter_reply_message(task) - - elif task.type == TaskRequestType.assistant_reply: - assert isinstance(task, protocol_schema.AssistantReplyTask) - logger.debug("sending assistant reply task") - content = assistant_reply_message(task) - - elif task.type == TaskRequestType.summarize_story: - raise NotImplementedError - elif task.type == TaskRequestType.rate_summary: - raise NotImplementedError - - else: - logger.critical(f"unknown task type {task.type}") - raise ValueError(f"unknown task type {task.type}") - - view = TaskAcceptView(timeout=MAX_TASK_ACCEPT_TIME) - if not msg: - msg = await ctx.author.send( - content, - embed=embed, - components=view, - ) - else: - await msg.edit( - content, - embed=embed, - components=view, - ) - - assert msg is not None - - # Set the choice id as the current msg id - ctx.bot.d.currently_working[ctx.author.id] = (msg, task.id) - - await view.start(msg) - await view.wait() - - return view.choice, msg - - -def _validate_user_input(content: str | None, task: protocol_schema.Task) -> tuple[bool, str]: - """Returns whether the user's input is valid for the task type and an error message.""" - if content is None: - return False, "No input provided" - - # User message input - if ( - task.type == TaskRequestType.initial_prompt - or task.type == TaskRequestType.prompter_reply - or task.type == TaskRequestType.assistant_reply - ): - assert isinstance( - task, - protocol_schema.InitialPromptTask | protocol_schema.PrompterReplyTask | protocol_schema.AssistantReplyTask, - ) - return len(content) > 0, "Message must be at least one character long." - - # Ranking tasks - elif task.type == TaskRequestType.rank_prompter_replies or task.type == TaskRequestType.rank_assistant_replies: - assert isinstance(task, protocol_schema.RankPrompterRepliesTask | protocol_schema.RankAssistantRepliesTask) - num_replies = len(task.replies) - - rankings = content.replace(" ", "").split(",") - return ( - set(rankings) == {str(i) for i in range(1, num_replies + 1)} and len(rankings) == num_replies, - "Message must contain numbers for all replies.", - ) - - elif task.type == TaskRequestType.rank_initial_prompts: - assert isinstance(task, protocol_schema.RankInitialPromptsTask) - num_prompts = len(task.prompts) - - rankings = content.replace(" ", "").split(",") - return ( - set(rankings) == {str(i) for i in range(1, num_prompts + 1)} and len(rankings) == num_prompts, - "Message must contain numbers for all prompts.", - ) - - # Labels tasks - elif task.type in ( - TaskRequestType.label_initial_prompt, - TaskRequestType.label_prompter_reply, - TaskRequestType.label_assistant_reply, - ): - assert isinstance( - task, - protocol_schema.LabelInitialPromptTask - | protocol_schema.LabelPrompterReplyTask - | protocol_schema.LabelAssistantReplyTask, - ) - - labels = content.replace(" ", "").split(",") - valid_labels = set(task.valid_labels) - return ( - set(labels).issubset(valid_labels), - "Message must only contain labels from predefined set of labels.", - ) - - elif task.type == TaskRequestType.summarize_story: - raise NotImplementedError - elif task.type == TaskRequestType.rate_summary: - raise NotImplementedError - - else: - logger.critical(f"Unknown task type {task.type}") - raise ValueError(f"Unknown task type {task.type}") - - class TaskAcceptView(miru.View): """View with three buttons: accept, next, and cancel. diff --git a/discord-bot/bot/messages.py b/discord-bot/bot/messages.py index 7bd57bb9..26ad9158 100644 --- a/discord-bot/bot/messages.py +++ b/discord-bot/bot/messages.py @@ -1,4 +1,11 @@ -"""All user-facing messages and embeds.""" +"""All user-facing messages and embeds. + +When sending a conversation +- The function will return a list of strings + - use asyncio.gather to send all messages + +- +""" from datetime import datetime @@ -33,8 +40,11 @@ def _ranking_prompt(text: str) -> str: return f":trophy: _{text}_" -def _label_prompt(text: str) -> str: - return f":question: _{text}" +def _label_prompt(text: str, mandatory_label: list[str] | None, valid_labels: list[str]) -> str: + return f""":question: _{text}_ +Mandatory labels: {", ".join(mandatory_label) if mandatory_label is not None else "None"} +Valid labels: {", ".join(valid_labels)} +""" def _response_prompt(text: str) -> str: @@ -57,20 +67,29 @@ def _assistant(text: str | None) -> str: """ -def _make_ordered_list(items: list[str]) -> list[str]: - return [f"{num} {item}" for num, item in zip(NUMBER_EMOJIS, items)] +def _make_ordered_list(items: list[protocol_schema.ConversationMessage]) -> list[str]: + return [f"{num} {item.text}" for num, item in zip(NUMBER_EMOJIS, items)] -def _ordered_list(items: list[str]) -> str: +def _ordered_list(items: list[protocol_schema.ConversationMessage]) -> str: return "\n\n".join(_make_ordered_list(items)) -def _conversation(conv: protocol_schema.Conversation) -> str: - return "\n".join([_assistant(msg.text) if msg.is_assistant else _user(msg.text) for msg in conv.messages]) - - -def _hint(hint: str | None) -> str: - return f"{NL}Hint: {hint}" if hint else "" +def _conversation(conv: protocol_schema.Conversation) -> list[str]: + # return "\n".join([_assistant(msg.text) if msg.is_assistant else _user(msg.text) for msg in conv.messages]) + messages = map( + lambda m: f"""\ +:robot: __Assistant__: +{m.text} +""" + if m.is_assistant + else f"""\ +:person_red_hair: __User__: +{m.text} +""", + conv.messages, + ) + return list(messages) def _li(text: str) -> str: @@ -82,59 +101,80 @@ def _li(text: str) -> str: ### -def initial_prompt_message(task: protocol_schema.InitialPromptTask) -> str: +def initial_prompt_messages(task: protocol_schema.InitialPromptTask) -> list[str]: """Creates the message that gets sent to users when they request an `initial_prompt` task.""" - return f"""\ + return [ + f"""\ -{_h1("INITIAL PROMPT")} +:small_blue_diamond: __**INITIAL PROMPT**__ :small_blue_diamond: -{_writing_prompt("Please provide an initial prompt to the assistant.")} -{_hint(task.hint)} +:pencil: _Please provide an initial prompt to the assistant._{f"{NL}Hint: {task.hint}" if task.hint else ""} """ + ] -def rank_initial_prompts_message(task: protocol_schema.RankInitialPromptsTask) -> str: +def rank_initial_prompts_messages(task: protocol_schema.RankInitialPromptsTask) -> list[str]: """Creates the message that gets sent to users when they request a `rank_initial_prompts` task.""" - return f"""\ + return [ + f"""\ -{_h1("RANK INITIAL PROMPTS")} +:small_blue_diamond: __**RANK INITIAL PROMPTS**__ :small_blue_diamond: -{_ordered_list(task.prompts)} +{_ordered_list(task.prompt_messages)} -{_ranking_prompt("Reply with the numbers of best to worst prompts separated by commas (example: '4,1,3,2')")} +:trophy: _Reply with the numbers of best to worst prompts separated by commas (example: '4,1,3,2')_ """ + ] -def rank_prompter_reply_message(task: protocol_schema.RankPrompterRepliesTask) -> str: +def rank_prompter_reply_messages(task: protocol_schema.RankPrompterRepliesTask) -> list[str]: """Creates the message that gets sent to users when they request a `rank_prompter_replies` task.""" - return f"""\ + return [ + """\ -{_h1("RANK PROMPTER REPLIES")} +:small_blue_diamond: __**RANK PROMPTER REPLIES**__ :small_blue_diamond: + +""", + *_conversation(task.conversation), + f""":person_red_hair: __User__: +{_ordered_list(task.reply_messages)} + +:trophy: _Reply with the numbers of best to worst replies separated by commas (example: '4,1,3,2')_ +""", + ] -{_conversation(task.conversation)} -{_user(None)} -{_ordered_list(task.replies)} - -{_ranking_prompt("Reply with the numbers of best to worst replies separated by commas (example: '4,1,3,2')")} -""" - - -def rank_assistant_reply_message(task: protocol_schema.RankAssistantRepliesTask) -> str: +def rank_assistant_reply_message(task: protocol_schema.RankAssistantRepliesTask) -> list[str]: """Creates the message that gets sent to users when they request a `rank_assistant_replies` task.""" - return f"""\ + return [ + """\ -{_h1("RANK ASSISTANT REPLIES")} +:small_blue_diamond: __**RANK ASSISTANT REPLIES**__ :small_blue_diamond: + +""", + *_conversation(task.conversation), + f""":robot: __Assistant__:, +{_ordered_list(task.reply_messages)} +:trophy: _Reply with the numbers of best to worst replies separated by commas (example: '4,1,3,2')_ +""", + ] -{_conversation(task.conversation)} -{_assistant(None)} -{_ordered_list(task.replies)} +def rank_conversation_reply_messages(task: protocol_schema.RankConversationRepliesTask) -> list[str]: + """Creates the message that gets sent to users when they request a `rank_conversation_replies` task.""" + return [ + """\ -{_ranking_prompt("Reply with the numbers of best to worst replies separated by commas (example: '4,1,3,2')")} -""" +:small_blue_diamond: __**RANK CONVERSATION REPLIES**__ :small_blue_diamond: + +""", + *_conversation(task.conversation), + f""":person_red_hair: __User__: +{_ordered_list(task.reply_messages)} +""", + ] def label_initial_prompt_message(task: protocol_schema.LabelInitialPromptTask) -> str: @@ -146,64 +186,84 @@ def label_initial_prompt_message(task: protocol_schema.LabelInitialPromptTask) - {task.prompt} -{_label_prompt("Reply with labels for the prompt separated by commas (example: 'profanity,misleading')")} +{_label_prompt("Reply with labels for the prompt separated by commas (example: 'profanity,misleading')", task.mandatory_labels, task.valid_labels)} """ -def label_prompter_reply_message(task: protocol_schema.LabelPrompterReplyTask) -> str: +def label_prompter_reply_messages(task: protocol_schema.LabelPrompterReplyTask) -> list[str]: """Creates the message that gets sent to users when they request a `label_prompter_reply` task.""" - return f"""\ + return [ + f"""\ {_h1("LABEL PROMPTER REPLY")} -{_conversation(task.conversation)} -{_user(None)} +""", + *_conversation(task.conversation), + f"""{_user(None)} {task.reply} -{_label_prompt("Reply with labels for the reply separated by commas (example: 'profanity,misleading')")} -""" +{_label_prompt("Reply with labels for the reply separated by commas (example: 'profanity,misleading')", task.mandatory_labels, task.valid_labels)} +""", + ] -def label_assistant_reply_message(task: protocol_schema.LabelAssistantReplyTask) -> str: +def label_assistant_reply_messages(task: protocol_schema.LabelAssistantReplyTask) -> list[str]: """Creates the message that gets sent to users when they request a `label_assistant_reply` task.""" - return f"""\ + return [ + f"""\ {_h1("LABEL ASSISTANT REPLY")} -{_conversation(task.conversation)} +""", + *_conversation(task.conversation), + f""" {_assistant(None)} {task.reply} -{_label_prompt("Reply with labels for the reply separated by commas (example: 'profanity,misleading')")} -""" +{_label_prompt("Reply with labels for the reply separated by commas (example: 'profanity,misleading')", task.mandatory_labels, task.valid_labels)} +""", + ] -def prompter_reply_message(task: protocol_schema.PrompterReplyTask) -> str: +def prompter_reply_messages(task: protocol_schema.PrompterReplyTask) -> list[str]: """Creates the message that gets sent to users when they request a `prompter_reply` task.""" - return f"""\ + return [ + """\ +:small_blue_diamond: __**PROMPTER REPLY**__ :small_blue_diamond: -{_h1("PROMPTER REPLY")} +""", + *_conversation(task.conversation), + f"""{f"{NL}Hint: {task.hint}" if task.hint else ""} + +:speech_balloon: _Please provide a reply to the assistant._ +""", + ] -{_conversation(task.conversation)} -{_hint(task.hint)} - -{_response_prompt("Please provide a reply to the assistant.")} -""" +# def prompter_reply_messages2(task: protocol_schema.PrompterReplyTask) -> list[str]: +# """Creates the message that gets sent to users when they request a `prompter_reply` task.""" +# return [ +# message_templates.render("title.msg", "PROMPTER REPLY"), +# *[message_templates.render("conversation_message.msg", conv) for conv in task.conversation], +# message_templates.render("prompter_reply_task.msg", task.hint), +# ] -def assistant_reply_message(task: protocol_schema.AssistantReplyTask) -> str: +def assistant_reply_messages(task: protocol_schema.AssistantReplyTask) -> list[str]: """Creates the message that gets sent to users when they request a `assistant_reply` task.""" - return f"""\ -{_h1("ASSISTANT REPLY")} + return [ + """\ +:small_blue_diamond: __**ASSISTANT REPLY**__ :small_blue_diamond: +""", + *_conversation(task.conversation), + """\ -{_conversation(task.conversation)} - -{_response_prompt("Please provide an assistant reply to the prompter.")} -""" +:speech_balloon: _Please provide a reply to the user as the assistant._ +""", + ] def confirm_text_response_message(content: str) -> str: @@ -214,7 +274,7 @@ def confirm_text_response_message(content: str) -> str: """ -def confirm_ranking_response_message(content: str, items: list[str]) -> str: +def confirm_ranking_response_message(content: str, items: list[protocol_schema.ConversationMessage]) -> str: user_rankings = [int(r) for r in content.replace(" ", "").split(",")] original_list = _make_ordered_list(items) user_ranked_list = "\n\n".join([original_list[r - 1] for r in user_rankings]) diff --git a/oasst-shared/oasst_shared/api_client.py b/oasst-shared/oasst_shared/api_client.py index 1ee2865b..26592fb8 100644 --- a/oasst-shared/oasst_shared/api_client.py +++ b/oasst-shared/oasst_shared/api_client.py @@ -68,12 +68,15 @@ class OasstApiClient: async def post(self, path: str, data: dict[str, t.Any]) -> Optional[dict[str, t.Any]]: """Make a POST request to the backend.""" logger.debug(f"POST {self.backend_url}{path} DATA: {data}") - response = await self.session.post(f"{self.backend_url}{path}", json=data, headers={"X-API-Key": self.api_key}) + response = await self.session.post(f"{self.backend_url}{path}", json=data, headers={"x-api-key": self.api_key}) + logger.debug(f"response: {response}") # If the response is not a 2XX, check to see # if the json has the fields to create an # OasstError. if response.status >= 300: + text = await response.text() + logger.debug(f"resp text: {text}") data = await response.json() try: oasst_error = protocol_schema.OasstErrorResponse(**(data or {})) @@ -114,20 +117,21 @@ class OasstApiClient: task_type: protocol_schema.TaskRequestType, user: Optional[protocol_schema.User] = None, collective: bool = False, + lang: Optional[str] = None, ) -> protocol_schema.Task: """Fetch a task from the backend.""" logger.debug(f"Fetching task {task_type} for user {user}") - req = protocol_schema.TaskRequest(type=task_type.value, user=user, collective=collective) + req = protocol_schema.TaskRequest(type=task_type.value, user=user, collective=collective, lang=lang) resp = await self.post("/api/v1/tasks/", data=req.dict()) logger.debug(f"RESP {resp}") return self._parse_task(resp) async def fetch_random_task( - self, user: Optional[protocol_schema.User] = None, collective: bool = False + self, user: Optional[protocol_schema.User] = None, collective: bool = False, lang: Optional[str] = None ) -> protocol_schema.Task: """Fetch a random task from the backend.""" logger.debug(f"Fetching random for user {user}") - return await self.fetch_task(protocol_schema.TaskRequestType.random, user, collective) + return await self.fetch_task(protocol_schema.TaskRequestType.random, user, collective, lang) async def ack_task(self, task_id: str | UUID, message_id: str) -> None: """Send an ACK for a task to the backend.""" From 652b7bff04ec6c4b273d8540eb3b3a55da4de1b1 Mon Sep 17 00:00:00 2001 From: Oliver Stanley Date: Thu, 2 Feb 2023 18:33:21 +0000 Subject: [PATCH 021/152] 857: Implement backend Discord authentication (#943) * Initial code for backend auth * Remove outdated check * Initial separation of AuthenticatedUser * AuthenticatedUser -> Account * Rework for Account * Initial code for Discord OAuth * Remove now redundant methods * Remove incorrect response model, add requests dep for backend * Create Settings fields for Discord values * Cleanup get account from Discord function * Cleanup * Cleanup * Generate alembic upgrade script * Remove unused error codes * Update alembic script to correct down revision * Use aiohttp over requests * Update alembic script to latest down revision --- ..._02_1817-8c8241d1f973_add_account_table.py | 41 +++++++++++ backend/oasst_backend/api/v1/login.py | 73 +++++++++++++++++++ backend/oasst_backend/auth.py | 37 ++++++++++ backend/oasst_backend/config.py | 5 ++ backend/oasst_backend/models/user.py | 17 +++++ backend/requirements.txt | 1 + .../exceptions/oasst_api_error.py | 2 + oasst-shared/oasst_shared/schemas/protocol.py | 11 +++ 8 files changed, 187 insertions(+) create mode 100644 backend/alembic/versions/2023_02_02_1817-8c8241d1f973_add_account_table.py create mode 100644 backend/oasst_backend/api/v1/login.py create mode 100644 backend/oasst_backend/auth.py diff --git a/backend/alembic/versions/2023_02_02_1817-8c8241d1f973_add_account_table.py b/backend/alembic/versions/2023_02_02_1817-8c8241d1f973_add_account_table.py new file mode 100644 index 00000000..3ec2708c --- /dev/null +++ b/backend/alembic/versions/2023_02_02_1817-8c8241d1f973_add_account_table.py @@ -0,0 +1,41 @@ +"""Add Account table + +Revision ID: 8c8241d1f973 +Revises: 4d7e0b0ebe84 +Create Date: 2023-01-30 15:10:58.776315 + +""" +import sqlalchemy as sa +import sqlmodel +from alembic import op +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = "8c8241d1f973" +down_revision = "4d7e0b0ebe84" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "account", + sa.Column("id", postgresql.UUID(as_uuid=True), server_default=sa.text("gen_random_uuid()"), nullable=False), + sa.Column("user_id", sqlmodel.sql.sqltypes.GUID(), nullable=False), + sa.Column("provider", sqlmodel.sql.sqltypes.AutoString(length=128), nullable=False), + sa.Column("provider_account_id", sqlmodel.sql.sqltypes.AutoString(length=128), nullable=False), + sa.ForeignKeyConstraint(["user_id"], ["user.id"]), + sa.PrimaryKeyConstraint("id"), + ) + op.create_index("id", "account", [], unique=True) + op.create_index("provider", "account", ["provider_account_id"], unique=True) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_index("provider", table_name="account") + op.drop_index("id", table_name="account") + op.drop_table("account") + # ### end Alembic commands ### diff --git a/backend/oasst_backend/api/v1/login.py b/backend/oasst_backend/api/v1/login.py new file mode 100644 index 00000000..8aab5328 --- /dev/null +++ b/backend/oasst_backend/api/v1/login.py @@ -0,0 +1,73 @@ +import aiohttp +from fastapi import APIRouter, Depends, HTTPException, Request +from oasst_backend import auth +from oasst_backend.api import deps +from oasst_backend.config import Settings +from oasst_backend.models import Account +from oasst_shared.exceptions.oasst_api_error import OasstError, OasstErrorCode +from oasst_shared.schemas import protocol as protocol_schema +from sqlmodel import Session +from starlette.status import HTTP_401_UNAUTHORIZED + +router = APIRouter() + + +@router.get("/discord") +def login_discord(request: Request): + redirect_uri = f"{get_callback_uri(request)}/discord" + auth_url = f"https://discord.com/api/oauth2/authorize?client_id={Settings.AUTH_DISCORD_CLIENT_ID}&redirect_uri={redirect_uri}&response_type=code&scope=identify" + raise HTTPException(status_code=302, headers={"location": auth_url}) + + +@router.get("/callback/discord", response_model=protocol_schema.Token) +async def callback_discord( + auth_code: str, + request: Request, + db: Session = Depends(deps.get_db), +): + redirect_uri = f"{get_callback_uri(request)}/discord" + + async with aiohttp.ClientSession(raise_for_status=True) as session: + # Exchange the auth code for a Discord access token + async with session.post( + "https://discord.com/api/oauth2/token", + data={ + "client_id": Settings.AUTH_DISCORD_CLIENT_ID, + "client_secret": Settings.AUTH_DISCORD_CLIENT_SECRET, + "grant_type": "authorization_code", + "code": auth_code, + "redirect_uri": redirect_uri, + "scope": "identify", + }, + ) as token_response: + token_response_json = await token_response.json() + access_token = token_response_json["access_token"] + + # Retrieve user's Discord information using access token + async with session.get( + "https://discord.com/api/users/@me", headers={"Authorization": f"Bearer {access_token}"} + ) as user_response: + user_response_json = await user_response.json() + discord_id = user_response_json["id"] + + account: Account = auth.get_account_from_discord_id(db, discord_id) + + if not account: + # Discord account is not linked to an OA account + raise OasstError("Invalid authentication", OasstErrorCode.INVALID_AUTHENTICATION, HTTP_401_UNAUTHORIZED) + + # Discord account is valid and linked to an OA account -> create JWT + access_token = auth.create_access_token(account) + + return protocol_schema.Token(access_token=access_token, token_type="bearer") + + +def get_callback_uri(request: Request): + """ + Gets the URI for the base callback endpoint with no provider name appended. + """ + # This seems ugly, not sure if there is a better way + current_url = str(request.url) + domain = current_url.split("/api/v1/")[0] + redirect_uri = f"{domain}/api/v1/callback" + return redirect_uri diff --git a/backend/oasst_backend/auth.py b/backend/oasst_backend/auth.py new file mode 100644 index 00000000..2c633fa4 --- /dev/null +++ b/backend/oasst_backend/auth.py @@ -0,0 +1,37 @@ +from datetime import datetime, timedelta +from typing import Optional + +from jose import jwt +from oasst_backend.config import Settings +from oasst_backend.models import Account +from sqlmodel import Session + + +def create_access_token(data: dict) -> str: + """ + Create an encoded JSON Web Token (JWT) using the given data. + """ + + expires_delta = timedelta(minutes=Settings.AUTH_ACCESS_TOKEN_EXPIRE_MINUTES) + to_encode = data.copy() + expire = datetime.utcnow() + expires_delta + to_encode.update({"exp": expire}) + encoded_jwt = jwt.encode(to_encode, Settings.AUTH_SECRET, algorithm=Settings.AUTH_ALGORITHM) + return encoded_jwt + + +def get_account_from_discord_id(db: Session, discord_id: str) -> Optional[Account]: + """ + Get the Open-Assistant Account associated with the given Discord ID. + """ + + account: Account = ( + db.query(Account) + .filter( + Account.provider == "discord", + Account.provider_account_id == discord_id, + ) + .first() + ) + + return account diff --git a/backend/oasst_backend/config.py b/backend/oasst_backend/config.py index f40f5637..851f9ace 100644 --- a/backend/oasst_backend/config.py +++ b/backend/oasst_backend/config.py @@ -135,6 +135,11 @@ class Settings(BaseSettings): AUTH_LENGTH: int = 32 AUTH_SECRET: bytes = b"O/M2uIbGj+lDD2oyNa8ax4jEOJqCPJzO53UbWShmq98=" AUTH_COOKIE_NAME: str = "next-auth.session-token" + AUTH_ALGORITHM: str = "HS256" + AUTH_ACCESS_TOKEN_EXPIRE_MINUTES: int = 30 + + AUTH_DISCORD_CLIENT_ID: str = "" + AUTH_DISCORD_CLIENT_SECRET: str = "" POSTGRES_HOST: str = "localhost" POSTGRES_PORT: str = "5432" diff --git a/backend/oasst_backend/models/user.py b/backend/oasst_backend/models/user.py index 6c73089c..69fc3e37 100644 --- a/backend/oasst_backend/models/user.py +++ b/backend/oasst_backend/models/user.py @@ -60,3 +60,20 @@ class User(SQLModel, table=True): last_activity_date=self.last_activity_date, tos_acceptance_date=self.tos_acceptance_date, ) + + +class Account(SQLModel, table=True): + __tablename__ = "account" + __table_args__ = ( + Index("id", unique=True), + Index("provider", "provider_account_id", unique=True), + ) + + id: Optional[UUID] = Field( + sa_column=sa.Column( + pg.UUID(as_uuid=True), primary_key=True, default=uuid4, server_default=sa.text("gen_random_uuid()") + ), + ) + user_id: UUID = Field(foreign_key="user.id") + provider: str = Field(nullable=False, max_length=128, default="email") # discord or email + provider_account_id: str = Field(nullable=False, max_length=128) diff --git a/backend/requirements.txt b/backend/requirements.txt index 4a112bc8..4a0008bb 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -1,3 +1,4 @@ +aiohttp==3.8.3 alembic==1.8.1 cryptography==39.0.0 fastapi==0.88.0 diff --git a/oasst-shared/oasst_shared/exceptions/oasst_api_error.py b/oasst-shared/oasst_shared/exceptions/oasst_api_error.py index a8682a32..58c8aadc 100644 --- a/oasst-shared/oasst_shared/exceptions/oasst_api_error.py +++ b/oasst-shared/oasst_shared/exceptions/oasst_api_error.py @@ -28,6 +28,8 @@ class OasstErrorCode(IntEnum): SERVER_ERROR0 = 500 SERVER_ERROR1 = 501 + INVALID_AUTHENTICATION = 600 + # 1000-2000: tasks endpoint TASK_INVALID_REQUEST_TYPE = 1000 TASK_ACK_FAILED = 1001 diff --git a/oasst-shared/oasst_shared/schemas/protocol.py b/oasst-shared/oasst_shared/schemas/protocol.py index e0dde366..a237b0c9 100644 --- a/oasst-shared/oasst_shared/schemas/protocol.py +++ b/oasst-shared/oasst_shared/schemas/protocol.py @@ -29,6 +29,17 @@ class User(BaseModel): auth_method: Literal["discord", "local", "system"] +class Account(BaseModel): + id: UUID + provider: str + provider_account_id: str + + +class Token(BaseModel): + access_token: str + token_type: str + + class FrontEndUser(User): user_id: UUID enabled: bool From 488662690403e14420a59523795ce48c05b74519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=B6pf?= Date: Thu, 2 Feb 2023 19:41:34 +0100 Subject: [PATCH 022/152] fix alembic migration script --- .../2023_02_02_1817-8c8241d1f973_add_account_table.py | 2 -- backend/oasst_backend/models/user.py | 5 +---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/backend/alembic/versions/2023_02_02_1817-8c8241d1f973_add_account_table.py b/backend/alembic/versions/2023_02_02_1817-8c8241d1f973_add_account_table.py index 3ec2708c..3ab59b08 100644 --- a/backend/alembic/versions/2023_02_02_1817-8c8241d1f973_add_account_table.py +++ b/backend/alembic/versions/2023_02_02_1817-8c8241d1f973_add_account_table.py @@ -28,7 +28,6 @@ def upgrade() -> None: sa.ForeignKeyConstraint(["user_id"], ["user.id"]), sa.PrimaryKeyConstraint("id"), ) - op.create_index("id", "account", [], unique=True) op.create_index("provider", "account", ["provider_account_id"], unique=True) # ### end Alembic commands ### @@ -36,6 +35,5 @@ def upgrade() -> None: def downgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### op.drop_index("provider", table_name="account") - op.drop_index("id", table_name="account") op.drop_table("account") # ### end Alembic commands ### diff --git a/backend/oasst_backend/models/user.py b/backend/oasst_backend/models/user.py index 69fc3e37..59239ccf 100644 --- a/backend/oasst_backend/models/user.py +++ b/backend/oasst_backend/models/user.py @@ -64,10 +64,7 @@ class User(SQLModel, table=True): class Account(SQLModel, table=True): __tablename__ = "account" - __table_args__ = ( - Index("id", unique=True), - Index("provider", "provider_account_id", unique=True), - ) + __table_args__ = (Index("provider", "provider_account_id", unique=True),) id: Optional[UUID] = Field( sa_column=sa.Column( From c95bafc498a323f789a77ed006c4b96f9e062ce9 Mon Sep 17 00:00:00 2001 From: Guillermo Hoardings Date: Tue, 31 Jan 2023 22:34:47 +0100 Subject: [PATCH 023/152] Add Spanish translations for new strings added --- website/public/locales/es/labelling.json | 3 ++- website/public/locales/es/message.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/website/public/locales/es/labelling.json b/website/public/locales/es/labelling.json index 9f7217f6..19ef6e1c 100644 --- a/website/public/locales/es/labelling.json +++ b/website/public/locales/es/labelling.json @@ -12,5 +12,6 @@ "hate_speech": "Incitación al odio", "sexual_content": "Contenido sexual", "moral_judgement": "Juzga moralmente", - "political_content": "Contenido político" + "political_content": "Contenido político", + "lang_mismatch": "Idioma incorrecto" } diff --git a/website/public/locales/es/message.json b/website/public/locales/es/message.json index f6e546df..fc54c7eb 100644 --- a/website/public/locales/es/message.json +++ b/website/public/locales/es/message.json @@ -9,5 +9,6 @@ "report_placeholder": "¿Por qué se debería revisar este mensaje?", "report_title": "Informe", "send_report": "Enviar", - "submit_labels": "Enviar" + "submit_labels": "Enviar", + "view_user": "Ver usuario" } From 80d13bb60eba60a27369712fd4a097fde48b1ac3 Mon Sep 17 00:00:00 2001 From: Guillermo Hoardings Date: Tue, 31 Jan 2023 22:37:44 +0100 Subject: [PATCH 024/152] Fix Spanish translation of 'dashboard' --- website/public/locales/es/common.json | 2 +- website/public/locales/es/dashboard.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/website/public/locales/es/common.json b/website/public/locales/es/common.json index 98d3d0de..28917357 100644 --- a/website/public/locales/es/common.json +++ b/website/public/locales/es/common.json @@ -4,7 +4,7 @@ "admin_dashboard": "Panel de administración", "connect": "Connectar", "conversational": "AI conversacional para todos.", - "dashboard": "Panel de administración", + "dashboard": "Panel principal", "discord": "Discord", "docs": "Documentación", "github": "GitHub", diff --git a/website/public/locales/es/dashboard.json b/website/public/locales/es/dashboard.json index cdd34480..88466b00 100644 --- a/website/public/locales/es/dashboard.json +++ b/website/public/locales/es/dashboard.json @@ -3,6 +3,6 @@ "create": "Crear", "evaluate": "Evaluar", "label": "Etiquetar", - "dashboard": "Panel de administración", + "dashboard": "Panel principal", "go": "Ir" } From 83550b7ac625ed0ac69f279652b8ddd39a3c6b6b Mon Sep 17 00:00:00 2001 From: Guillermo Hoardings Date: Thu, 2 Feb 2023 21:46:35 +0100 Subject: [PATCH 025/152] Update Spanish translation with the new strings added to the website --- website/public/locales/es/labelling.json | 11 +++++++++-- website/public/locales/es/tasks.json | 3 ++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/website/public/locales/es/labelling.json b/website/public/locales/es/labelling.json index 19ef6e1c..03405bf9 100644 --- a/website/public/locales/es/labelling.json +++ b/website/public/locales/es/labelling.json @@ -8,10 +8,17 @@ "spam.question": "¿Es el mensaje spam?", "fails_task.question": "¿Es una mala respuesta, según la tarea pedida?", "not_appropriate": "No apropiada", + "not_appropriate.explanation": "No apropiada para un asistente de cliente.", "pii": "Contiene información de identificación personal (PII)", + "pii.explanation": "Contiene información personal como detalles de contacto personal, números de identificación o detalles bancarios", "hate_speech": "Incitación al odio", + "hate_speech.explanation": "El contenido es ofensivo o amenazante y expresa un prejuicio contra una característica protegida. El prejuicio se refiere a las opiniones preconcebidas que no se basan en la razón. Las características protegidas incluyen género, etnia, religión, orientación sexual y características similares.", "sexual_content": "Contenido sexual", - "moral_judgement": "Juzga moralmente", + "sexual_content.explanation": "Contiene contenido sexual.", + "moral_judgement": "Juicio moral", + "moral_judgement.explanation": "Expresa un juicio moral.", "political_content": "Contenido político", - "lang_mismatch": "Idioma incorrecto" + "political_content.explanation": "Expresa una opinión política.", + "lang_mismatch": "Idioma incorrecto", + "lang_mismatch.explanation": "No está escrito en el idioma seleccionado actualmente." } diff --git a/website/public/locales/es/tasks.json b/website/public/locales/es/tasks.json index 4613f5bd..9b4f6d20 100644 --- a/website/public/locales/es/tasks.json +++ b/website/public/locales/es/tasks.json @@ -77,5 +77,6 @@ "label": "Clasificar respuesta del asistente", "desc": "Proporciona etiquetas para una respuesta del asistente.", "overview": "Lee la siguiente conversación y contesta a continuación la pregunta sobre la última respuesta en la discusión." - } + }, + "available_task_count": "{{count}} tareas disponibles" } From 776584503f6b7d0fd18ddcb48bcea6ded4119543 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=B6pf?= Date: Thu, 2 Feb 2023 22:10:14 +0100 Subject: [PATCH 026/152] add new cfg env vars --- .github/workflows/deploy-to-node.yaml | 9 +++++++++ ansible/deploy-to-node.yaml | 15 +++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/.github/workflows/deploy-to-node.yaml b/.github/workflows/deploy-to-node.yaml index 27aae343..053013d1 100644 --- a/.github/workflows/deploy-to-node.yaml +++ b/.github/workflows/deploy-to-node.yaml @@ -41,11 +41,20 @@ jobs: MAX_TREE_DEPTH: ${{ vars.MAX_TREE_DEPTH }} MAX_CHILDREN_COUNT: ${{ vars.MAX_CHILDREN_COUNT }} GOAL_TREE_SIZE: ${{ vars.GOAL_TREE_SIZE }} + MESSAGE_SIZE_LIMIT: ${{ vars.MESSAGE_SIZE_LIMIT }} SKIP_TOXICITY_CALCULATION: ${{ vars.SKIP_TOXICITY_CALCULATION }} STATS_INTERVAL_DAY: ${{ vars.STATS_INTERVAL_DAY }} STATS_INTERVAL_WEEK: ${{ vars.STATS_INTERVAL_WEEK }} STATS_INTERVAL_MONTH: ${{ vars.STATS_INTERVAL_MONTH }} STATS_INTERVAL_TOTAL: ${{ vars.STATS_INTERVAL_TOTAL }} + WEB_NEXT_PUBLIC_CLOUDFLARE_CAPTCHA_SITE_KEY: + ${{ secrets.WEB_NEXT_PUBLIC_CLOUDFLARE_CAPTCHA_SITE_KEY }} + WEB_CLOUDFLARE_CAPTCHA_SERCERT_KEY: + ${{ secrets.WEB_CLOUDFLARE_CAPTCHA_SERCERT_KEY }} + WEB_NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN_CAPTCHA: + ${{ vars.WEB_NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN_CAPTCHA }} + WEB_NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN: + ${{ vars.WEB_NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN }} steps: - name: Checkout uses: actions/checkout@v2 diff --git a/ansible/deploy-to-node.yaml b/ansible/deploy-to-node.yaml index 87f14261..c109ce15 100644 --- a/ansible/deploy-to-node.yaml +++ b/ansible/deploy-to-node.yaml @@ -122,6 +122,9 @@ TREE_MANAGER__MAX_CHILDREN_COUNT: "{{ lookup('ansible.builtin.env', 'MAX_CHILDREN_COUNT') | default('3', true) }}" + MESSAGE_SIZE_LIMIT: + "{{ lookup('ansible.builtin.env', 'MESSAGE_SIZE_LIMIT') | + default('2000', true) }}" USER_STATS_INTERVAL_DAY: "{{ lookup('ansible.builtin.env', 'STATS_INTERVAL_DAY') | default('5', true) }}" @@ -172,6 +175,18 @@ NEXTAUTH_URL: "{{ 'https://open-assistant.io/' if stack_name == 'production' else ('https://web.' + stack_name + '.open-assistant.io/') }}" + NEXT_PUBLIC_CLOUDFLARE_CAPTCHA_SITE_KEY: + "{{ lookup('ansible.builtin.env', + 'WEB_NEXT_PUBLIC_CLOUDFLARE_CAPTCHA_SITE_KEY') }}" + CLOUDFLARE_CAPTCHA_SERCERT_KEY: + "{{ lookup('ansible.builtin.env', + 'WEB_CLOUDFLARE_CAPTCHA_SERCERT_KEY') }}" + NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN_CAPTCHA: + "{{ lookup('ansible.builtin.env', + 'WEB_NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN_CAPTCHA') }}" + NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN: + "{{ lookup('ansible.builtin.env', + 'WEB_NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN') }}" ports: - "{{ website_port }}:3000" command: bash wait-for-postgres.sh node server.js From d5c0adba5f1089e266dc2144a1a7a1e0b922b67a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=B6pf?= Date: Thu, 2 Feb 2023 22:10:50 +0000 Subject: [PATCH 027/152] fix typo SERCERT -> SECRET --- .github/workflows/deploy-to-node.yaml | 4 ++-- ansible/deploy-to-node.yaml | 4 ++-- docker-compose.yaml | 2 +- website/src/lib/captcha.ts | 2 +- website/types/env.d.ts | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/deploy-to-node.yaml b/.github/workflows/deploy-to-node.yaml index 053013d1..182c357d 100644 --- a/.github/workflows/deploy-to-node.yaml +++ b/.github/workflows/deploy-to-node.yaml @@ -49,8 +49,8 @@ jobs: STATS_INTERVAL_TOTAL: ${{ vars.STATS_INTERVAL_TOTAL }} WEB_NEXT_PUBLIC_CLOUDFLARE_CAPTCHA_SITE_KEY: ${{ secrets.WEB_NEXT_PUBLIC_CLOUDFLARE_CAPTCHA_SITE_KEY }} - WEB_CLOUDFLARE_CAPTCHA_SERCERT_KEY: - ${{ secrets.WEB_CLOUDFLARE_CAPTCHA_SERCERT_KEY }} + WEB_CLOUDFLARE_CAPTCHA_SECRET_KEY: + ${{ secrets.WEB_CLOUDFLARE_CAPTCHA_SECRET_KEY }} WEB_NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN_CAPTCHA: ${{ vars.WEB_NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN_CAPTCHA }} WEB_NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN: diff --git a/ansible/deploy-to-node.yaml b/ansible/deploy-to-node.yaml index c109ce15..81428988 100644 --- a/ansible/deploy-to-node.yaml +++ b/ansible/deploy-to-node.yaml @@ -178,9 +178,9 @@ NEXT_PUBLIC_CLOUDFLARE_CAPTCHA_SITE_KEY: "{{ lookup('ansible.builtin.env', 'WEB_NEXT_PUBLIC_CLOUDFLARE_CAPTCHA_SITE_KEY') }}" - CLOUDFLARE_CAPTCHA_SERCERT_KEY: + CLOUDFLARE_CAPTCHA_SECRET_KEY: "{{ lookup('ansible.builtin.env', - 'WEB_CLOUDFLARE_CAPTCHA_SERCERT_KEY') }}" + 'WEB_CLOUDFLARE_CAPTCHA_SECRET_KEY') }}" NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN_CAPTCHA: "{{ lookup('ansible.builtin.env', 'WEB_NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN_CAPTCHA') }}" diff --git a/docker-compose.yaml b/docker-compose.yaml index 9a0202e7..1ea1e680 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -126,7 +126,7 @@ services: - NEXTAUTH_URL=http://localhost:3000 - DEBUG_LOGIN=true - NEXT_PUBLIC_CLOUDFARE_CAPTCHA_SITE_KEY=1x00000000000000000000AA - - CLOUDFLARE_CAPTCHA_SERCERT_KEY=1x0000000000000000000000000000000AA + - CLOUDFLARE_CAPTCHA_SECRET_KEY=1x0000000000000000000000000000000AA - NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN_CAPTCHA=true depends_on: webdb: diff --git a/website/src/lib/captcha.ts b/website/src/lib/captcha.ts index 384f69dd..aa14dcbe 100644 --- a/website/src/lib/captcha.ts +++ b/website/src/lib/captcha.ts @@ -24,7 +24,7 @@ export const checkCaptcha = async ( ): Promise => { const data = new FormData(); - data.append("secret", process.env.CLOUDFLARE_CAPTCHA_SERCERT_KEY); + data.append("secret", process.env.CLOUDFLARE_CAPTCHA_SECRET_KEY); data.append("response", token); data.append("remoteip", ipAdress); diff --git a/website/types/env.d.ts b/website/types/env.d.ts index b5484154..f81897af 100644 --- a/website/types/env.d.ts +++ b/website/types/env.d.ts @@ -3,7 +3,7 @@ declare global { interface ProcessEnv { NODE_ENV: "development" | "production"; NEXT_PUBLIC_CLOUDFLARE_CAPTCHA_SITE_KEY: string; - CLOUDFLARE_CAPTCHA_SERCERT_KEY: string; + CLOUDFLARE_CAPTCHA_SECRET_KEY: string; NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN_CAPTCHA: boolean; } } From 602799881a728f3ce289eed0e76b7af4ea79a172 Mon Sep 17 00:00:00 2001 From: Guillermo Hoardings Date: Fri, 3 Feb 2023 01:17:25 +0100 Subject: [PATCH 028/152] Translate strings that were not using i18n yet Only English and Spanish translations have been included. --- website/public/locales/en/leaderboard.json | 6 +++++- website/public/locales/en/message.json | 4 +++- website/public/locales/en/side_menu.json | 14 ++++++++++++++ website/public/locales/es/leaderboard.json | 6 +++++- website/public/locales/es/message.json | 4 +++- website/public/locales/es/side_menu.json | 14 ++++++++++++++ .../src/components/Dashboard/LeaderboardWidget.tsx | 6 ++++-- website/src/components/Dashboard/SlimFooter.tsx | 12 +++++++----- website/src/components/DataTable.tsx | 6 ++++-- website/src/components/SideMenu.tsx | 4 +++- website/src/pages/messages/index.tsx | 6 ++++-- website/types/i18next.d.ts | 2 ++ 12 files changed, 68 insertions(+), 16 deletions(-) create mode 100644 website/public/locales/en/side_menu.json create mode 100644 website/public/locales/es/side_menu.json diff --git a/website/public/locales/en/leaderboard.json b/website/public/locales/en/leaderboard.json index 06097642..b2ab4173 100644 --- a/website/public/locales/en/leaderboard.json +++ b/website/public/locales/en/leaderboard.json @@ -10,5 +10,9 @@ "weekly": "Weekly", "prompt": "Prompts", "reply": "Replies", - "label": "Labels" + "label": "Labels", + "view_all": "View all", + "top_5_contributors_today": "Top 5 Contributors Today", + "previous": "Previous", + "next": "Next" } diff --git a/website/public/locales/en/message.json b/website/public/locales/en/message.json index d506ce80..ac9689a2 100644 --- a/website/public/locales/en/message.json +++ b/website/public/locales/en/message.json @@ -10,5 +10,7 @@ "report_title": "Report", "send_report": "Send", "submit_labels": "Submit", - "view_user": "View user" + "view_user": "View user", + "recent_messages": "Recent Messages", + "your_recent_messages": "Your Recent Messages" } diff --git a/website/public/locales/en/side_menu.json b/website/public/locales/en/side_menu.json new file mode 100644 index 00000000..0a2a6209 --- /dev/null +++ b/website/public/locales/en/side_menu.json @@ -0,0 +1,14 @@ +{ + "dashboard": "Dashboard", + "dashboard_home": "Dashboard Home", + "messages": "Messages", + "messages_dashboard": "Messages Dashboard", + "leaderboard": "Leaderboard", + "user_leaderboard": "User Leaderboard", + "users": "Users", + "users_dashboard": "Users Dashboard", + "status": "Status", + "status_dashboard": "Status Dashboard", + "dark_mode": "Dark Mode", + "ligth_mode": "Ligth Mode" +} diff --git a/website/public/locales/es/leaderboard.json b/website/public/locales/es/leaderboard.json index 08f69a4b..f39abb2f 100644 --- a/website/public/locales/es/leaderboard.json +++ b/website/public/locales/es/leaderboard.json @@ -10,5 +10,9 @@ "weekly": "Semanal", "prompt": "Indicaciones", "reply": "Respuestas", - "label": "Etiquetas" + "label": "Etiquetas", + "view_all": "Ver todos", + "top_5_contributors_today": "5 mayores contribuidores hoy", + "previous": "Anterior", + "next": "Siguiente" } diff --git a/website/public/locales/es/message.json b/website/public/locales/es/message.json index fc54c7eb..4fd2e58d 100644 --- a/website/public/locales/es/message.json +++ b/website/public/locales/es/message.json @@ -10,5 +10,7 @@ "report_title": "Informe", "send_report": "Enviar", "submit_labels": "Enviar", - "view_user": "Ver usuario" + "view_user": "Ver usuario", + "recent_messages": "Mensajes recientes", + "your_recent_messages": "Tus mensajes recientes" } diff --git a/website/public/locales/es/side_menu.json b/website/public/locales/es/side_menu.json new file mode 100644 index 00000000..43627532 --- /dev/null +++ b/website/public/locales/es/side_menu.json @@ -0,0 +1,14 @@ +{ + "dashboard": "Panel principal", + "dashboard_home": "Panel principal", + "messages": "Mensajes", + "messages_dashboard": "Tablón de mensajes", + "leaderboard": "Clasificaciones", + "user_leaderboard": "Clasificación de usuarios", + "users": "Usuarios", + "users_dashboard": "Tablón de usuarios", + "status": "Estado", + "status_dashboard": "Tablón de estado", + "dark_mode": "Modo oscuro", + "ligth_mode": "Modo claro" +} diff --git a/website/src/components/Dashboard/LeaderboardWidget.tsx b/website/src/components/Dashboard/LeaderboardWidget.tsx index a47816a2..38fe6207 100644 --- a/website/src/components/Dashboard/LeaderboardWidget.tsx +++ b/website/src/components/Dashboard/LeaderboardWidget.tsx @@ -1,17 +1,19 @@ import { Card, CardBody, Link, Text } from "@chakra-ui/react"; +import { useTranslation } from "next-i18next"; import NextLink from "next/link"; import { LeaderboardTable } from "src/components/LeaderboardTable"; import { LeaderboardTimeFrame } from "src/types/Leaderboard"; export function LeaderboardWidget() { + const { t } = useTranslation(["leaderboard"]); return (
- Top 5 Contributors Today + {t("top_5_contributors_today")} - View All -> + {t("view_all")} ->
diff --git a/website/src/components/Dashboard/SlimFooter.tsx b/website/src/components/Dashboard/SlimFooter.tsx index 1c109eb4..1313bb71 100644 --- a/website/src/components/Dashboard/SlimFooter.tsx +++ b/website/src/components/Dashboard/SlimFooter.tsx @@ -1,9 +1,11 @@ import { Box, Divider } from "@chakra-ui/react"; +import { useTranslation } from "next-i18next"; import Image from "next/image"; import Link from "next/link"; import { useMemo } from "react"; export function SlimFooter() { + const { t } = useTranslation(); return (
@@ -16,11 +18,11 @@ export function SlimFooter() { diff --git a/website/src/components/DataTable.tsx b/website/src/components/DataTable.tsx index 5f222a86..d9161e19 100644 --- a/website/src/components/DataTable.tsx +++ b/website/src/components/DataTable.tsx @@ -22,6 +22,7 @@ import { Tr, useDisclosure, } from "@chakra-ui/react"; +import { useTranslation } from "next-i18next"; import { ColumnDef, flexRender, getCoreRowModel, useReactTable } from "@tanstack/react-table"; import { Filter } from "lucide-react"; import { ChangeEvent, ReactNode } from "react"; @@ -62,6 +63,7 @@ export const DataTable = ({ disablePrevious, disablePagination, }: DataTableProps) => { + const { t } = useTranslation("leaderboard"); const { getHeaderGroups, getRowModel } = useReactTable({ data, columns, @@ -83,11 +85,11 @@ export const DataTable = ({ {!disablePagination && ( )} diff --git a/website/src/components/SideMenu.tsx b/website/src/components/SideMenu.tsx index ecd27bec..ee09226c 100644 --- a/website/src/components/SideMenu.tsx +++ b/website/src/components/SideMenu.tsx @@ -1,4 +1,5 @@ import { Button, Card, Text, Tooltip, useColorMode } from "@chakra-ui/react"; +import { useTranslation } from "next-i18next"; import { LucideIcon, Sun } from "lucide-react"; import Link from "next/link"; import { useRouter } from "next/router"; @@ -16,6 +17,7 @@ export interface SideMenuProps { export function SideMenu(props: SideMenuProps) { const router = useRouter(); const { colorMode, toggleColorMode } = useColorMode(); + const { t } = useTranslation(["side_menu"]); return (
@@ -60,7 +62,7 @@ export function SideMenu(props: SideMenuProps) { diff --git a/website/src/pages/messages/index.tsx b/website/src/pages/messages/index.tsx index 3b6e342e..8d950a2b 100644 --- a/website/src/pages/messages/index.tsx +++ b/website/src/pages/messages/index.tsx @@ -1,5 +1,6 @@ import { Box, CircularProgress, SimpleGrid, Text, useColorModeValue } from "@chakra-ui/react"; import Head from "next/head"; +import { useTranslation } from "next-i18next"; import { getDashboardLayout } from "src/components/Layout"; import { MessageTable } from "src/components/Messages/MessageTable"; import { get } from "src/lib/api"; @@ -7,6 +8,7 @@ import useSWRImmutable from "swr/immutable"; export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props"; const MessagesDashboard = () => { + const { t } = useTranslation(["message"]); const boxBgColor = useColorModeValue("white", "gray.800"); const boxAccentColor = useColorModeValue("gray.200", "gray.900"); @@ -22,7 +24,7 @@ const MessagesDashboard = () => { - Recent Messages + {t("recent_messages")} { - Your Recent Messages + {t("your_recent_messages")} Date: Fri, 3 Feb 2023 13:33:20 +0700 Subject: [PATCH 029/152] fix typo --- website/.env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/.env b/website/.env index 2579036f..50ecb498 100644 --- a/website/.env +++ b/website/.env @@ -19,6 +19,6 @@ EMAIL_SERVER_PORT=1025 EMAIL_FROM=info@example.com NEXT_PUBLIC_CLOUDFLARE_CAPTCHA_SITE_KEY=1x00000000000000000000AA -CLOUDFLARE_CAPTCHA_SERCERT_KEY=1x0000000000000000000000000000000AA +CLOUDFLARE_CAPTCHA_SECRET_KEY=1x0000000000000000000000000000000AA NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN_CAPTCHA=false NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN=true From db5ea7579616868692bef9b6efa608860dfee7fb Mon Sep 17 00:00:00 2001 From: AbdBarho Date: Fri, 3 Feb 2023 08:29:01 +0100 Subject: [PATCH 030/152] Add response types --- website/src/types/TaskResponses.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 website/src/types/TaskResponses.ts diff --git a/website/src/types/TaskResponses.ts b/website/src/types/TaskResponses.ts new file mode 100644 index 00000000..a6a49e89 --- /dev/null +++ b/website/src/types/TaskResponses.ts @@ -0,0 +1,15 @@ +export interface CreateTaskReply { + text: string; +} + +export interface EvaluateTaskReply { + ranking: number[]; +} + +export interface LabelTaskReply { + text: string; + labels: Record; + message_id: string; +} + +export type AllTaskReplies = CreateTaskReply | EvaluateTaskReply | LabelTaskReply; From ae829d0e3d2cd4349a285d1b84532a35d1940928 Mon Sep 17 00:00:00 2001 From: AbdBarho Date: Fri, 3 Feb 2023 08:30:01 +0100 Subject: [PATCH 031/152] update tasks to use types --- website/src/components/Tasks/CreateTask.tsx | 3 ++- website/src/components/Tasks/EvaluateTask.tsx | 3 ++- website/src/components/Tasks/LabelTask/LabelTask.tsx | 3 ++- website/src/components/Tasks/Task/Task.tsx | 4 ++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/website/src/components/Tasks/CreateTask.tsx b/website/src/components/Tasks/CreateTask.tsx index 8d406fd7..448ad287 100644 --- a/website/src/components/Tasks/CreateTask.tsx +++ b/website/src/components/Tasks/CreateTask.tsx @@ -8,6 +8,7 @@ import { TaskSurveyProps } from "src/components/Tasks/Task"; import { TaskHeader } from "src/components/Tasks/TaskHeader"; import { getTypeSafei18nKey } from "src/lib/i18n"; import { TaskType } from "src/types/Task"; +import { CreateTaskReply } from "src/types/TaskResponses"; import { CreateTaskType } from "src/types/Tasks"; export const CreateTask = ({ @@ -17,7 +18,7 @@ export const CreateTask = ({ isDisabled, onReplyChanged, onValidityChanged, -}: TaskSurveyProps) => { +}: TaskSurveyProps) => { const { t, i18n } = useTranslation(["tasks", "common"]); const cardColor = useColorModeValue("gray.50", "gray.800"); const titleColor = useColorModeValue("gray.800", "gray.300"); diff --git a/website/src/components/Tasks/EvaluateTask.tsx b/website/src/components/Tasks/EvaluateTask.tsx index e2f07749..2f24e6f1 100644 --- a/website/src/components/Tasks/EvaluateTask.tsx +++ b/website/src/components/Tasks/EvaluateTask.tsx @@ -6,6 +6,7 @@ import { SurveyCard } from "src/components/Survey/SurveyCard"; import { TaskSurveyProps } from "src/components/Tasks/Task"; import { TaskHeader } from "src/components/Tasks/TaskHeader"; import { TaskType } from "src/types/Task"; +import { EvaluateTaskReply } from "src/types/TaskResponses"; import { RankTaskType } from "src/types/Tasks"; export const EvaluateTask = ({ @@ -15,7 +16,7 @@ export const EvaluateTask = ({ isDisabled, onReplyChanged, onValidityChanged, -}: TaskSurveyProps) => { +}: TaskSurveyProps) => { const cardColor = useColorModeValue("gray.50", "gray.800"); const [ranking, setRanking] = useState(null); diff --git a/website/src/components/Tasks/LabelTask/LabelTask.tsx b/website/src/components/Tasks/LabelTask/LabelTask.tsx index 33369757..9c211d62 100644 --- a/website/src/components/Tasks/LabelTask/LabelTask.tsx +++ b/website/src/components/Tasks/LabelTask/LabelTask.tsx @@ -6,6 +6,7 @@ import { MessageTable } from "src/components/Messages/MessageTable"; import { TwoColumnsWithCards } from "src/components/Survey/TwoColumnsWithCards"; import { TaskSurveyProps } from "src/components/Tasks/Task"; import { TaskHeader } from "src/components/Tasks/TaskHeader"; +import { LabelTaskReply } from "src/types/TaskResponses"; import { LabelTaskType } from "src/types/Tasks"; const isRequired = (labelName: string, requiredLabels?: string[]) => { @@ -18,7 +19,7 @@ export const LabelTask = ({ isEditable, onReplyChanged, onValidityChanged, -}: TaskSurveyProps; message_id: string }>) => { +}: TaskSurveyProps) => { const { t } = useTranslation("labelling"); const [values, setValues] = useState(new Array(task.labels.length).fill(null)); const [userInputMade, setUserInputMade] = useBoolean(false); diff --git a/website/src/components/Tasks/Task/Task.tsx b/website/src/components/Tasks/Task/Task.tsx index c10ab597..54160636 100644 --- a/website/src/components/Tasks/Task/Task.tsx +++ b/website/src/components/Tasks/Task/Task.tsx @@ -53,12 +53,12 @@ interface UpdateValidity { replyValidity: TaskReplyValidity; } -export interface TaskSurveyProps { +export interface TaskSurveyProps { task: TaskType; taskType: TaskInfo; isEditable: boolean; isDisabled?: boolean; - onReplyChanged: (content: T) => void; + onReplyChanged: (content: ReplyContent) => void; onValidityChanged: (validity: TaskReplyValidity) => void; } From e8e3f2866582c24a06d23d21380f909772be43c6 Mon Sep 17 00:00:00 2001 From: AbdBarho Date: Fri, 3 Feb 2023 08:30:19 +0100 Subject: [PATCH 032/152] update hooks --- website/src/hooks/tasks/useCreateReply.ts | 13 ++++++++----- website/src/hooks/tasks/useEvaluateReplies.ts | 13 +++++++++++++ website/src/hooks/tasks/useGenericTaskAPI.tsx | 6 +++--- website/src/hooks/tasks/useLabelingTask.ts | 12 +++++++----- website/src/hooks/tasks/useRankReplies.ts | 12 ------------ website/src/lib/constants.ts | 10 +++++----- website/src/types/Hooks.ts | 1 - 7 files changed, 36 insertions(+), 31 deletions(-) create mode 100644 website/src/hooks/tasks/useEvaluateReplies.ts delete mode 100644 website/src/hooks/tasks/useRankReplies.ts diff --git a/website/src/hooks/tasks/useCreateReply.ts b/website/src/hooks/tasks/useCreateReply.ts index 23bc041d..9bb0c487 100644 --- a/website/src/hooks/tasks/useCreateReply.ts +++ b/website/src/hooks/tasks/useCreateReply.ts @@ -1,8 +1,11 @@ +import { useGenericTaskAPI } from "src/hooks/tasks/useGenericTaskAPI"; import { TaskType } from "src/types/Task"; +import { CreateTaskReply } from "src/types/TaskResponses"; import { CreateAssistantReplyTask, CreateInitialPromptTask, CreatePrompterReplyTask } from "src/types/Tasks"; -import { useGenericTaskAPI } from "./useGenericTaskAPI"; - -export const useCreateAssistantReply = () => useGenericTaskAPI(TaskType.assistant_reply); -export const useCreatePrompterReply = () => useGenericTaskAPI(TaskType.prompter_reply); -export const useCreateInitialPrompt = () => useGenericTaskAPI(TaskType.initial_prompt); +export const useCreateAssistantReply = () => + useGenericTaskAPI(TaskType.assistant_reply); +export const useCreatePrompterReply = () => + useGenericTaskAPI(TaskType.prompter_reply); +export const useCreateInitialPrompt = () => + useGenericTaskAPI(TaskType.initial_prompt); diff --git a/website/src/hooks/tasks/useEvaluateReplies.ts b/website/src/hooks/tasks/useEvaluateReplies.ts new file mode 100644 index 00000000..a2e19a1c --- /dev/null +++ b/website/src/hooks/tasks/useEvaluateReplies.ts @@ -0,0 +1,13 @@ +import { useGenericTaskAPI } from "src/hooks/tasks/useGenericTaskAPI"; +import { TaskType } from "src/types/Task"; +import { EvaluateTaskReply } from "src/types/TaskResponses"; +import { RankAssistantRepliesTask, RankInitialPromptsTask, RankPrompterRepliesTask } from "src/types/Tasks"; + +export const useRankAssistantRepliesTask = () => + useGenericTaskAPI(TaskType.rank_assistant_replies); + +export const useRankPrompterRepliesTask = () => + useGenericTaskAPI(TaskType.rank_prompter_replies); + +export const useRankInitialPromptsTask = () => + useGenericTaskAPI(TaskType.rank_initial_prompts); diff --git a/website/src/hooks/tasks/useGenericTaskAPI.tsx b/website/src/hooks/tasks/useGenericTaskAPI.tsx index 7a7d651b..e7630bdc 100644 --- a/website/src/hooks/tasks/useGenericTaskAPI.tsx +++ b/website/src/hooks/tasks/useGenericTaskAPI.tsx @@ -3,11 +3,11 @@ import { TaskInfos } from "src/components/Tasks/TaskTypes"; import { get, post } from "src/lib/api"; import { TaskApiHook } from "src/types/Hooks"; import { BaseTask, ServerTaskResponse, TaskResponse, TaskType as TaskTypeEnum } from "src/types/Task"; +import { AllTaskReplies } from "src/types/TaskResponses"; import useSWRImmutable from "swr/immutable"; import useSWRMutation from "swr/mutation"; -// TODO: provide type for the content reply, this will be much harder since the replies vary vastly -export const useGenericTaskAPI = ( +export const useGenericTaskAPI = ( taskType: TaskTypeEnum ): TaskApiHook => { const [response, setResponse] = useState>({ taskAvailability: "AWAITING_INITIAL" }); @@ -71,5 +71,5 @@ export const useGenericTaskAPI = - useGenericTaskAPI(TaskType.label_assistant_reply); -export const useLabelInitialPromptTask = () => useGenericTaskAPI(TaskType.label_initial_prompt); -export const useLabelPrompterReplyTask = () => useGenericTaskAPI(TaskType.label_prompter_reply); + useGenericTaskAPI(TaskType.label_assistant_reply); +export const useLabelInitialPromptTask = () => + useGenericTaskAPI(TaskType.label_initial_prompt); +export const useLabelPrompterReplyTask = () => + useGenericTaskAPI(TaskType.label_prompter_reply); diff --git a/website/src/hooks/tasks/useRankReplies.ts b/website/src/hooks/tasks/useRankReplies.ts deleted file mode 100644 index d4accda0..00000000 --- a/website/src/hooks/tasks/useRankReplies.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { TaskType } from "src/types/Task"; -import { RankAssistantRepliesTask, RankInitialPromptsTask, RankPrompterRepliesTask } from "src/types/Tasks"; - -import { useGenericTaskAPI } from "./useGenericTaskAPI"; - -export const useRankAssistantRepliesTask = () => - useGenericTaskAPI(TaskType.rank_assistant_replies); - -export const useRankPrompterRepliesTask = () => - useGenericTaskAPI(TaskType.rank_prompter_replies); - -export const useRankInitialPromptsTask = () => useGenericTaskAPI(TaskType.rank_initial_prompts); diff --git a/website/src/lib/constants.ts b/website/src/lib/constants.ts index a260fa28..9efe3d03 100644 --- a/website/src/lib/constants.ts +++ b/website/src/lib/constants.ts @@ -3,17 +3,17 @@ import { useCreateInitialPrompt, useCreatePrompterReply, } from "src/hooks/tasks/useCreateReply"; +import { + useRankAssistantRepliesTask, + useRankInitialPromptsTask, + useRankPrompterRepliesTask, +} from "src/hooks/tasks/useEvaluateReplies"; import { useGenericTaskAPI } from "src/hooks/tasks/useGenericTaskAPI"; import { useLabelAssistantReplyTask, useLabelInitialPromptTask, useLabelPrompterReplyTask, } from "src/hooks/tasks/useLabelingTask"; -import { - useRankAssistantRepliesTask, - useRankInitialPromptsTask, - useRankPrompterRepliesTask, -} from "src/hooks/tasks/useRankReplies"; import { TaskApiHooks } from "src/types/Hooks"; import { TaskType } from "src/types/Task"; diff --git a/website/src/types/Hooks.ts b/website/src/types/Hooks.ts index acdd0b58..5225c009 100644 --- a/website/src/types/Hooks.ts +++ b/website/src/types/Hooks.ts @@ -4,7 +4,6 @@ export type TaskApiHook = { response: TaskResponse; isLoading: boolean; completeTask: (interaction: ResponseContent) => Promise; - skipTask: () => Promise; rejectTask: (reason: string) => Promise; }; From 715127e60eab4493eea40153d6bcd33922a2a6ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=B6pf?= Date: Fri, 3 Feb 2023 07:47:43 +0000 Subject: [PATCH 033/152] change backend default config --- backend/oasst_backend/config.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/oasst_backend/config.py b/backend/oasst_backend/config.py index 851f9ace..71d74c29 100644 --- a/backend/oasst_backend/config.py +++ b/backend/oasst_backend/config.py @@ -34,10 +34,10 @@ class TreeManagerConfiguration(BaseModel): p_full_labeling_review_prompt: float = 1.0 """Probability of full text-labeling (instead of mandatory only) for initial prompts.""" - p_full_labeling_review_reply_assistant: float = 0.1 + p_full_labeling_review_reply_assistant: float = 0.5 """Probability of full text-labeling (instead of mandatory only) for assistant replies.""" - p_full_labeling_review_reply_prompter: float = 0.1 + p_full_labeling_review_reply_prompter: float = 0.25 """Probability of full text-labeling (instead of mandatory only) for prompter replies.""" acceptance_threshold_initial_prompt: float = 0.6 @@ -112,7 +112,7 @@ class TreeManagerConfiguration(BaseModel): rank_prompter_replies: bool = False - lonely_children_count: int = 3 + lonely_children_count: int = 2 """Number of children below which parents are preferred during sampling for reply tasks.""" p_lonely_child_extension: float = 0.8 From 03321ccc72d45a117cc1f425f0e4a9a19d5395ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=B6pf?= Date: Fri, 3 Feb 2023 09:17:32 +0000 Subject: [PATCH 034/152] add lonely_children_count, p_activate_backlog_tree & min_active_rankings_per_lang to gh workflow config --- .github/workflows/deploy-to-node.yaml | 3 +++ ansible/deploy-to-node.yaml | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/.github/workflows/deploy-to-node.yaml b/.github/workflows/deploy-to-node.yaml index 182c357d..a33966af 100644 --- a/.github/workflows/deploy-to-node.yaml +++ b/.github/workflows/deploy-to-node.yaml @@ -40,6 +40,9 @@ jobs: MAX_ACTIVE_TREES: ${{ vars.MAX_ACTIVE_TREES }} MAX_TREE_DEPTH: ${{ vars.MAX_TREE_DEPTH }} MAX_CHILDREN_COUNT: ${{ vars.MAX_CHILDREN_COUNT }} + LONELY_CHILDREN_COUNT: ${{ vars.LONELY_CHILDREN_COUNT }} + P_ACTIVATE_BACKLOG_TREE: ${{ vars.P_ACTIVATE_BACKLOG_TREE }} + MIN_ACTIVE_RANKINGS_PER_LANG: ${{ vars.MIN_ACTIVE_RANKINGS_PER_LANG }} GOAL_TREE_SIZE: ${{ vars.GOAL_TREE_SIZE }} MESSAGE_SIZE_LIMIT: ${{ vars.MESSAGE_SIZE_LIMIT }} SKIP_TOXICITY_CALCULATION: ${{ vars.SKIP_TOXICITY_CALCULATION }} diff --git a/ansible/deploy-to-node.yaml b/ansible/deploy-to-node.yaml index 81428988..5c518a5c 100644 --- a/ansible/deploy-to-node.yaml +++ b/ansible/deploy-to-node.yaml @@ -122,6 +122,15 @@ TREE_MANAGER__MAX_CHILDREN_COUNT: "{{ lookup('ansible.builtin.env', 'MAX_CHILDREN_COUNT') | default('3', true) }}" + TREE_MANAGER__LONELY_CHILDREN_COUNT: + "{{ lookup('ansible.builtin.env', 'LONELY_CHILDREN_COUNT') | + default('2', true) }}" + TREE_MANAGER__P_ACTIVATE_BACKLOG_TREE: + "{{ lookup('ansible.builtin.env', 'P_ACTIVATE_BACKLOG_TREE') | + default('0.1', true) }}" + TREE_MANAGER__MIN_ACTIVE_RANKINGS_PER_LANG: + "{{ lookup('ansible.builtin.env', 'MIN_ACTIVE_RANKINGS_PER_LANG') | + default('0', true) }}" MESSAGE_SIZE_LIMIT: "{{ lookup('ansible.builtin.env', 'MESSAGE_SIZE_LIMIT') | default('2000', true) }}" From 6681aedd017609e6c5aedfdb85ff0c671174ee58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=B6pf?= Date: Fri, 3 Feb 2023 09:36:44 +0000 Subject: [PATCH 035/152] add P_LONELY_CHILD_EXTENSION to workflow vars --- .github/workflows/deploy-to-node.yaml | 1 + ansible/deploy-to-node.yaml | 3 +++ backend/oasst_backend/config.py | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy-to-node.yaml b/.github/workflows/deploy-to-node.yaml index a33966af..3457293e 100644 --- a/.github/workflows/deploy-to-node.yaml +++ b/.github/workflows/deploy-to-node.yaml @@ -41,6 +41,7 @@ jobs: MAX_TREE_DEPTH: ${{ vars.MAX_TREE_DEPTH }} MAX_CHILDREN_COUNT: ${{ vars.MAX_CHILDREN_COUNT }} LONELY_CHILDREN_COUNT: ${{ vars.LONELY_CHILDREN_COUNT }} + P_LONELY_CHILD_EXTENSION: ${{ vars.P_LONELY_CHILD_EXTENSION }} P_ACTIVATE_BACKLOG_TREE: ${{ vars.P_ACTIVATE_BACKLOG_TREE }} MIN_ACTIVE_RANKINGS_PER_LANG: ${{ vars.MIN_ACTIVE_RANKINGS_PER_LANG }} GOAL_TREE_SIZE: ${{ vars.GOAL_TREE_SIZE }} diff --git a/ansible/deploy-to-node.yaml b/ansible/deploy-to-node.yaml index 5c518a5c..23bc0573 100644 --- a/ansible/deploy-to-node.yaml +++ b/ansible/deploy-to-node.yaml @@ -125,6 +125,9 @@ TREE_MANAGER__LONELY_CHILDREN_COUNT: "{{ lookup('ansible.builtin.env', 'LONELY_CHILDREN_COUNT') | default('2', true) }}" + TREE_MANAGER__P_LONELY_CHILD_EXTENSION: + "{{ lookup('ansible.builtin.env', 'P_LONELY_CHILD_EXTENSION') | + default('0.75', true) }}" TREE_MANAGER__P_ACTIVATE_BACKLOG_TREE: "{{ lookup('ansible.builtin.env', 'P_ACTIVATE_BACKLOG_TREE') | default('0.1', true) }}" diff --git a/backend/oasst_backend/config.py b/backend/oasst_backend/config.py index 71d74c29..f1685221 100644 --- a/backend/oasst_backend/config.py +++ b/backend/oasst_backend/config.py @@ -115,7 +115,7 @@ class TreeManagerConfiguration(BaseModel): lonely_children_count: int = 2 """Number of children below which parents are preferred during sampling for reply tasks.""" - p_lonely_child_extension: float = 0.8 + p_lonely_child_extension: float = 0.75 """Probability to select a prompter message parent with less than lonely_children_count children.""" recent_tasks_span_sec: int = 3 * 60 # 3 min From af3ec08f71076d7ba8f6ce309207dca9a552682e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=B6pf?= Date: Fri, 3 Feb 2023 09:43:19 +0000 Subject: [PATCH 036/152] fix: not timeout for sikpped tasks --- backend/oasst_backend/task_repository.py | 4 +++- backend/oasst_backend/tree_manager.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/oasst_backend/task_repository.py b/backend/oasst_backend/task_repository.py index b721caf5..5fe84b24 100644 --- a/backend/oasst_backend/task_repository.py +++ b/backend/oasst_backend/task_repository.py @@ -205,7 +205,7 @@ class TaskRepository: return task def fetch_recent_reply_tasks( - self, max_age: timedelta = timedelta(minutes=5), done: bool = False, limit: int = 100 + self, max_age: timedelta = timedelta(minutes=5), done: bool = False, skipped: bool = False, limit: int = 100 ) -> list[Task]: qry = self.db.query(Task).filter( func.age(Task.created_date) < max_age, @@ -213,6 +213,8 @@ class TaskRepository: ) if done is not None: qry = qry.filter(Task.done == done) + if skipped is not None: + qry = qry.filter(Task.skipped == skipped) if limit: qry = qry.limit(limit) return qry.all() diff --git a/backend/oasst_backend/tree_manager.py b/backend/oasst_backend/tree_manager.py index e09f22d1..44560e15 100644 --- a/backend/oasst_backend/tree_manager.py +++ b/backend/oasst_backend/tree_manager.py @@ -496,7 +496,7 @@ class TreeManager: case TaskType.REPLY: recent_reply_tasks = self.pr.task_repository.fetch_recent_reply_tasks( - max_age=timedelta(seconds=self.cfg.recent_tasks_span_sec), done=False + max_age=timedelta(seconds=self.cfg.recent_tasks_span_sec), done=False, skipped=False, limit=500 ) recent_reply_task_parents = {t.parent_message_id for t in recent_reply_tasks} From 37d4fac904209c36587287cc3f3a28cf2cc8d805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=B6pf?= Date: Fri, 3 Feb 2023 10:19:04 +0000 Subject: [PATCH 037/152] change formatting --- backend/oasst_backend/tree_manager.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/backend/oasst_backend/tree_manager.py b/backend/oasst_backend/tree_manager.py index 44560e15..fbf9fff7 100644 --- a/backend/oasst_backend/tree_manager.py +++ b/backend/oasst_backend/tree_manager.py @@ -496,7 +496,10 @@ class TreeManager: case TaskType.REPLY: recent_reply_tasks = self.pr.task_repository.fetch_recent_reply_tasks( - max_age=timedelta(seconds=self.cfg.recent_tasks_span_sec), done=False, skipped=False, limit=500 + max_age=timedelta(seconds=self.cfg.recent_tasks_span_sec), + done=False, + skipped=False, + limit=500, ) recent_reply_task_parents = {t.parent_message_id for t in recent_reply_tasks} From 8cd5107601bb3779cf0ac054b08bcbbd86f5c0b0 Mon Sep 17 00:00:00 2001 From: Adrian Cowan Date: Fri, 3 Feb 2023 23:05:41 +1100 Subject: [PATCH 038/152] website: cleanup emoji handling, hide all unknown emojis (#1082) --- .../Messages/MessageEmojiButton.tsx | 28 +++---------------- .../components/Messages/MessageTableEntry.tsx | 9 +++--- website/src/types/Emoji.ts | 10 +++++++ 3 files changed, 19 insertions(+), 28 deletions(-) create mode 100644 website/src/types/Emoji.ts diff --git a/website/src/components/Messages/MessageEmojiButton.tsx b/website/src/components/Messages/MessageEmojiButton.tsx index 8b5c9ff7..88580f8c 100644 --- a/website/src/components/Messages/MessageEmojiButton.tsx +++ b/website/src/components/Messages/MessageEmojiButton.tsx @@ -1,28 +1,6 @@ import { Button } from "@chakra-ui/react"; -import { BoxSelect, Flag, LucideProps, ThumbsDown, ThumbsUp } from "lucide-react"; -import { ReactElement } from "react"; import { MessageEmoji } from "src/types/Conversation"; - -type EmojiIconPurpose = "MINI_BUTTON" | "NORMAL"; - -const defaultIconProps: (purpose: EmojiIconPurpose) => LucideProps = (purpose: EmojiIconPurpose) => { - if (purpose === "MINI_BUTTON") return { height: "1em" }; - return {}; -}; - -export const getEmojiIcon = (name: string, purpose: EmojiIconPurpose): ReactElement => { - switch (name) { - case "+1": - return ; - case "-1": - return ; - case "flag": - case "red_flag": - return ; - default: - return ; - } -}; +import { emojiIcons } from "src/types/Emoji"; interface MessageEmojiButtonProps { emoji: MessageEmoji; @@ -31,6 +9,8 @@ interface MessageEmojiButtonProps { } export const MessageEmojiButton = ({ emoji, checked, onClick }: MessageEmojiButtonProps) => { + const EmojiIcon = emojiIcons[emoji.name]; + if (!EmojiIcon) return <>; return ( ); diff --git a/website/src/components/Messages/MessageTableEntry.tsx b/website/src/components/Messages/MessageTableEntry.tsx index 63b1cf32..b252a525 100644 --- a/website/src/components/Messages/MessageTableEntry.tsx +++ b/website/src/components/Messages/MessageTableEntry.tsx @@ -20,11 +20,12 @@ import { useSession } from "next-auth/react"; import { useTranslation } from "next-i18next"; import { useCallback, useEffect, useMemo, useState } from "react"; import { LabelMessagePopup } from "src/components/Messages/LabelPopup"; -import { getEmojiIcon, MessageEmojiButton } from "src/components/Messages/MessageEmojiButton"; +import { MessageEmojiButton } from "src/components/Messages/MessageEmojiButton"; import { ReportPopup } from "src/components/Messages/ReportPopup"; import { del, post } from "src/lib/api"; import { colors } from "src/styles/Theme/colors"; import { Message, MessageEmojis } from "src/types/Conversation"; +import { emojiIcons, isKnownEmoji } from "src/types/Emoji"; import { mutate } from "swr"; import useSWRMutation from "swr/mutation"; @@ -99,7 +100,7 @@ export function MessageTableEntry({ message, enabled, highlight }: MessageTableE onClick={(e) => e.stopPropagation()} > {Object.entries(emojiState.emojis) - .filter(([k]) => !k.startsWith("_")) + .filter(([emoji]) => isKnownEmoji(emoji)) .map(([emoji, count]) => ( void; }) => { const activeColor = useColorModeValue(colors.light.active, colors.dark.active); - + const EmojiIcon = emojiIcons[emoji]; return ( react(emoji, !checked)} justifyContent="center" color={checked ? activeColor : undefined}> - {getEmojiIcon(emoji, "NORMAL")} + ); }; diff --git a/website/src/types/Emoji.ts b/website/src/types/Emoji.ts new file mode 100644 index 00000000..cf8fc00a --- /dev/null +++ b/website/src/types/Emoji.ts @@ -0,0 +1,10 @@ +import { Flag, LucideIcon, ThumbsDown, ThumbsUp } from "lucide-react"; + +export const emojiIcons: { [emoji: string]: LucideIcon } = { + "+1": ThumbsUp, + "-1": ThumbsDown, + flag: Flag, + red_flag: Flag, +}; + +export const isKnownEmoji = (emoji: string) => !!emojiIcons[emoji]; From f38897614e6fc2e279cf2637cf097970f881277a Mon Sep 17 00:00:00 2001 From: Richard Nagyfi Date: Fri, 3 Feb 2023 13:06:33 +0100 Subject: [PATCH 039/152] Added Hungarian locale for website (#1081) - added localization files - ran pre-commit to ensure the JSONs are correctly formatted - updated next-i18.next.config.js as advised on discord --- website/next-i18next.config.js | 2 +- website/public/locales/hu/common.json | 22 ++++++ website/public/locales/hu/dashboard.json | 8 +++ website/public/locales/hu/index.json | 15 ++++ website/public/locales/hu/labelling.json | 24 +++++++ website/public/locales/hu/leaderboard.json | 14 ++++ website/public/locales/hu/message.json | 14 ++++ website/public/locales/hu/tasks.json | 82 ++++++++++++++++++++++ 8 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 website/public/locales/hu/common.json create mode 100644 website/public/locales/hu/dashboard.json create mode 100644 website/public/locales/hu/index.json create mode 100644 website/public/locales/hu/labelling.json create mode 100644 website/public/locales/hu/leaderboard.json create mode 100644 website/public/locales/hu/message.json create mode 100644 website/public/locales/hu/tasks.json diff --git a/website/next-i18next.config.js b/website/next-i18next.config.js index 8a0ccb38..03ed6e99 100644 --- a/website/next-i18next.config.js +++ b/website/next-i18next.config.js @@ -1,6 +1,6 @@ module.exports = { i18n: { defaultLocale: "en", - locales: ["bn", "de", "en", "es", "fr", "ja", "pt-BR", "ru", "vi", "zh"], + locales: ["bn", "de", "en", "es", "fr", "hu", "ja", "pt-BR", "ru", "vi", "zh"], }, }; diff --git a/website/public/locales/hu/common.json b/website/public/locales/hu/common.json new file mode 100644 index 00000000..fbbb475b --- /dev/null +++ b/website/public/locales/hu/common.json @@ -0,0 +1,22 @@ +{ + "about": "Rólunk", + "account_settings": "Fiókom", + "admin_dashboard": "Admin Felület", + "connect": "Kapcsolat", + "conversational": "Társalgási MI Mindenkinek.", + "dashboard": "Irányítópult", + "discord": "Discord", + "docs": "Leírás", + "github": "GitHub", + "legal": "Jogi", + "loading": "Betöltés...", + "more_information": "További információ", + "no": "Nem", + "privacy_policy": "Adatvédelem", + "report_a_bug": "Hibabejelentés", + "sign_in": "Bejelentkezés", + "sign_out": "Kijelentkezés", + "terms_of_service": "Felhasználási feltételek", + "title": "Open Assistant", + "yes": "Igen" +} diff --git a/website/public/locales/hu/dashboard.json b/website/public/locales/hu/dashboard.json new file mode 100644 index 00000000..eae4dc03 --- /dev/null +++ b/website/public/locales/hu/dashboard.json @@ -0,0 +1,8 @@ +{ + "grab_a_task": "Válassz egy feladatot!", + "create": "Létrehozás", + "evaluate": "Értékelés", + "label": "Címkézés", + "dashboard": "Irányítópult", + "go": "Indítás" +} diff --git a/website/public/locales/hu/index.json b/website/public/locales/hu/index.json new file mode 100644 index 00000000..ce881dfa --- /dev/null +++ b/website/public/locales/hu/index.json @@ -0,0 +1,15 @@ +{ + "blurb": "Hiszük, hogy forradalmat csinálunk.", + "blurb1": "Ahogy a Stable Diffusion bárki számára elérhetővé tette, hogy műveket alkothasson, úgy akarjuk mi is megváltoztatni a világot a társalgási Mesterséges Intelligenciák területén.", + "description": "Társalgási MI Mindenkinek. Egy nyílt forráskódú projekt a LAION és sokak mások által, melynek célja egy chatelésre alkalmas nyelvi modell létrehozása.", + "faq_items": { + "q0": "Hol tart a projekt?", + "a0": "A fejlesztés kezdeti fázisában vagyunk, már létező kutatásokból kiindulva dolgozunk az RLHF nagy nyelvi modelleken történő alkalmazásán.", + "q1": "Kik állnak az Open Assistant mögött?", + "a1": "Az Open Assistant projekt szervezője a LAION és olyan önkéntesek, akik szeretnék mindenki számára elérhetővé tenni a technológiát!" + }, + "faq_title": "Gyakran Ismételt Kérdések", + "join_us_description": "Minden nyílt forráskódú projekt hozzád hasonló emberekkel kezdődik! Az Open Source az abba vetett hit, hogy tudásunkkal és technológiánkkal, közösen jobbá tehetjük a világot! Ha téged is érdekel, itt érhetsz el bennünket:", + "join_us_title": "Csatlakozás", + "subtitle": "Társalgási MI Mindenkinek." +} diff --git a/website/public/locales/hu/labelling.json b/website/public/locales/hu/labelling.json new file mode 100644 index 00000000..9fca2cae --- /dev/null +++ b/website/public/locales/hu/labelling.json @@ -0,0 +1,24 @@ +{ + "label_highlighted_yes_no_instruction": "Válaszold meg a megjelölt üzenetre vonatkozó kérdés(eke)t:", + "label_highlighted_flag_instruction": "Jelöld be, melyek vonatkoznak a megjelölt üzenetre:", + "label_highlighted_likert_instruction": "Értékeld a megjelölt üzenetet:", + "label_message_yes_no_instruction": "Válaszold meg az üzenetre vonatkozó kérdés(eke)t:", + "label_message_flag_instruction": "Jelöld be, melyek vonatkoznak erre az üzenetre:", + "label_message_likert_instruction": "Értékeld ezt az üzenetet:", + "spam.question": "Ez az üzenet SPAM?", + "fails_task.question": "Ez a válasz nem a feladatnak megfelelő?", + "not_appropriate": "Nem Helyénvaló", + "not_appropriate.explanation": "Nem ügyfél-asszisztenshez méltó válasz.", + "pii": "Személyes Adat", + "pii.explanation": "Érzékeny, személyes adatot tartalmaz, például: valakinek az elérhetősége, igazolványszáma, bankkártya adatai.", + "hate_speech": "Gyűlölet Beszéd", + "hate_speech.explanation": "Az üzenet célja valamely társadalmi csoport megalázása, megfélemlítése vagy a csoport tagjai elleni erőszak vagy előítéletes fellépés kiváltása. A gyűlöletbeszéd legtöbbször a nemi, faji, etnikai, nemzeti, vallási, vagy szexualitás szerinti csoportok ellen irányul.", + "sexual_content": "Szexuális Tartalom", + "sexual_content.explanation": "Szexuális töltetű üzenet.", + "moral_judgement": "Morális Bírálat", + "moral_judgement.explanation": "Morális értékrendbeli bírálatot tartalmaz.", + "political_content": "Politikai Töltetű", + "political_content.explanation": "Politikai nézeteket közöl vagy propagandát tartalmaz.", + "lang_mismatch": "Idegen Nyelv", + "lang_mismatch.explanation": "Nem a kiválasztott nyelven íródott." +} diff --git a/website/public/locales/hu/leaderboard.json b/website/public/locales/hu/leaderboard.json new file mode 100644 index 00000000..59d5217b --- /dev/null +++ b/website/public/locales/hu/leaderboard.json @@ -0,0 +1,14 @@ +{ + "daily": "Napi", + "last_updated_at": "Frissítve: {{val, datetime}}", + "leaderboard": "Ranglétra", + "monthly": "Havi", + "overall": "Összesített", + "rank": "Helyezés", + "score": "Pont", + "user": "Felhasználó", + "weekly": "Heti", + "prompt": "Promptok", + "reply": "Válaszok", + "label": "Címkék" +} diff --git a/website/public/locales/hu/message.json b/website/public/locales/hu/message.json new file mode 100644 index 00000000..c27b8fda --- /dev/null +++ b/website/public/locales/hu/message.json @@ -0,0 +1,14 @@ +{ + "label_action": "Címkézés", + "label_title": "Címke", + "message": "Üzenet", + "open_new_tab_action": "Megnyitás új lapon", + "parent": "Szülő", + "reactions": "Reakciók", + "report_action": "Jelentés", + "report_placeholder": "Mi a probléma ezzel az üzenettel?", + "report_title": "Bejelentés", + "send_report": "Beküldés", + "submit_labels": "Küldés", + "view_user": "Felhasználó megtekintése" +} diff --git a/website/public/locales/hu/tasks.json b/website/public/locales/hu/tasks.json new file mode 100644 index 00000000..43fedeef --- /dev/null +++ b/website/public/locales/hu/tasks.json @@ -0,0 +1,82 @@ +{ + "default": { + "unchanged_title": "Nem történt változtatás", + "unchanged_message": "Biztosan tovább szeretnél lépni?" + }, + "random": { + "label": "Jó napom van", + "desc": "Segítsd az Open Assistant fejlesztését egy véletlenül kiválaszott feladattal." + }, + "create_initial_prompt": { + "label": "Hozz Létre Kezdeti Promptokat", + "desc": "Írj egy nyitó üzenetet, hogy az Asszisztens minél több fajta kérdésből tanulhasson.", + "overview": "Kezdj el egy beszélgetést az Asszisztenssel.", + "instruction": "Találj ki Kezdeti Promptokat", + "response_placeholder": "Ide írd a promptot..." + }, + "reply_as_user": { + "label": "Válaszolj a Felhasználó Helyett", + "desc": "Csinálj úgy, mintha chatelnél az Asszisztenssel, hogy fejlődhessen.", + "overview": "Írj egy ideillő választ az eddigi beszélgetésre", + "instruction": "Találj ki Felhasználói Válaszokat", + "response_placeholder": "Ide írd a választ..." + }, + "reply_as_assistant": { + "label": "Válaszolj az Asszisztens Helyett", + "desc": "Mjutasd meg az Asszisztensnek, hogy milyen válaszokat küldjön a felhasználói kérdésekre.", + "overview": "Írj egy ideillő választ az eddigi beszélgetésre", + "response_placeholder": "Ide írd a választ..." + }, + "rank_user_replies": { + "label": "Rangsorold a Felhasználó Válaszait", + "desc": "Értékeld a Felhasználói Válaszok minőségét.", + "overview": "Rangsorold az alábbi Felhasználói Válaszokat: a legjobbat tedd legfelülre, a legrosszabbat legalulra.", + "unchanged_title": "Sorrend nem változott", + "unchanged_message": "Nem változtattál a promptok sorrendjén. Így is tovább akarsz lépni?" + }, + "rank_assistant_replies": { + "label": "Rangsorold az Asszisztens Válaszait", + "desc": "Értékeld az Asszisztens Válaszait pontosságuk és megfogalmazásuk alapján.", + "overview": "Rangsorold az alábbi Asszisztens Válaszokat: a legjobbat tedd legfelülre, a legrosszabbat legalulra.", + "unchanged_title": "Sorrend nem változott", + "unchanged_message": "Nem változtattál a promptok sorrendjén. Így is tovább akarsz lépni?" + }, + "rank_initial_prompts": { + "label": "Rangsorold a Kezdeti Promptokat", + "desc": "Értékeld a Kezdeti Promptokat válaszait pontosságuk és megfogalmazásuk alapján.", + "overview": "Rangsorold az alábbi Kezdeti Promptokat: a legjobbat tedd legfelülre, a legrosszabbat legalulra.", + "unchanged_title": "Sorrend nem változott", + "unchanged_message": "Nem változtattál a promptok sorrendjén. Így is tovább akarsz lépni?" + }, + "label_initial_prompt": { + "label": "Címkézd fel a Kezdeti Promptokat", + "desc": "Találj ki címkéket a megadott Promptra.", + "overview": "Találj ki Címkéket az alábbi Prompthoz." + }, + "label_prompter_reply": { + "label": "Címkézd fel a Promptokra adott Válaszokat", + "desc": "Találj ki címkéket a megadott Promptra.", + "overview": "Az alábbi beszélgetés alapján találj ki Címkéket a záró Promptra." + }, + "label_assistant_reply": { + "label": "Címkézd fel az Asszisztens Válaszait", + "desc": "Találj ki címkéket a megadott Promptra.", + "overview": "Az alábbi beszélgetés alapján találj ki Címkéket a záró Promptra." + }, + "classify_initial_prompt": { + "label": "Osztályozd a Kezdeti Promptokat", + "desc": "Találj ki címkéket a megadott Promptra.", + "overview": "Olvasd el a Promptot és válaszold meg a vele kapcsolatos kérdést." + }, + "classify_prompter_reply": { + "label": "Osztályozd a Promptra adott Válaszokat", + "desc": "Találj ki címkéket a megadott Promptra.", + "overview": "Olvasd végig a beszélgetést és válaszolj a legutolsó üzenetre vonatkozó kérdésre." + }, + "classify_assistant_reply": { + "label": "Osztályozd az Asszisztens Válaszait", + "desc": "Találj ki címkéket a megadott Promptra.", + "overview": "Olvasd végig a beszélgetést és válaszolj a legutolsó üzenetre vonatkozó kérdésre." + }, + "available_task_count": "{{count}} feladat érhető el" +} From 0a9f0aea929a359325c4a805cd69f81ab9ce2666 Mon Sep 17 00:00:00 2001 From: Adrian Cowan Date: Sat, 4 Feb 2023 00:21:13 +1100 Subject: [PATCH 040/152] website: Fix bug introduced into optimised build in recent emoji cleanup (#1085) The issue was the omtimised build was optimising the "+1" object key name to just "1" causing the context menu to try to shown an undefined emoji icon. --- .../components/Messages/MessageEmojiButton.tsx | 2 +- .../components/Messages/MessageTableEntry.tsx | 2 +- website/src/types/Emoji.ts | 16 +++++++++------- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/website/src/components/Messages/MessageEmojiButton.tsx b/website/src/components/Messages/MessageEmojiButton.tsx index 88580f8c..41d256bf 100644 --- a/website/src/components/Messages/MessageEmojiButton.tsx +++ b/website/src/components/Messages/MessageEmojiButton.tsx @@ -9,7 +9,7 @@ interface MessageEmojiButtonProps { } export const MessageEmojiButton = ({ emoji, checked, onClick }: MessageEmojiButtonProps) => { - const EmojiIcon = emojiIcons[emoji.name]; + const EmojiIcon = emojiIcons.get(emoji.name); if (!EmojiIcon) return <>; return ( From 86eac87c19512c1a98821a59ec0a8668e96a8287 Mon Sep 17 00:00:00 2001 From: AbdBarho Date: Fri, 3 Feb 2023 20:53:20 +0100 Subject: [PATCH 043/152] Add ToS/License Agreement to Website (#1080) * add new apis to oasst client * add tos handler * Add ToS to Dashboard * use Provider for ToS * simplify provider * fix error * Inject into JWT * primitive error handling * update comment * address review --- website/public/locales/en/tos.json | 6 + .../PolicyCards/PolicyChapterCard.tsx | 4 +- website/src/components/Survey/SurveyCard.tsx | 22 +- website/src/components/ToSWrapper.tsx | 50 +++ website/src/lib/oasst_api_client.ts | 156 ++++---- website/src/pages/api/auth/[...nextauth].ts | 38 +- website/src/pages/api/tos.ts | 19 + website/src/pages/dashboard.tsx | 10 +- website/src/pages/terms-of-service.tsx | 339 +++++++++--------- website/src/types/Users.ts | 30 ++ website/types/i18next.d.ts | 6 +- website/types/next-auth.d.ts | 4 + 12 files changed, 422 insertions(+), 262 deletions(-) create mode 100644 website/public/locales/en/tos.json create mode 100644 website/src/components/ToSWrapper.tsx create mode 100644 website/src/pages/api/tos.ts diff --git a/website/public/locales/en/tos.json b/website/public/locales/en/tos.json new file mode 100644 index 00000000..c8bb43b2 --- /dev/null +++ b/website/public/locales/en/tos.json @@ -0,0 +1,6 @@ +{ + "title": "Terms of Service for Open Assistant", + "content": "To continue using Open Assistant, you have to accept our Terms of Service first.", + "accept": "Accept", + "decline": "Decline" +} diff --git a/website/src/components/PolicyCards/PolicyChapterCard.tsx b/website/src/components/PolicyCards/PolicyChapterCard.tsx index 91e6202e..e57e0853 100644 --- a/website/src/components/PolicyCards/PolicyChapterCard.tsx +++ b/website/src/components/PolicyCards/PolicyChapterCard.tsx @@ -19,10 +19,10 @@ export const PolicyChapterCard = ({ chapter, children }: ChapterProps) => { - + {chapter.number} - + {chapter.title} diff --git a/website/src/components/Survey/SurveyCard.tsx b/website/src/components/Survey/SurveyCard.tsx index 6101f787..dd465243 100644 --- a/website/src/components/Survey/SurveyCard.tsx +++ b/website/src/components/Survey/SurveyCard.tsx @@ -1,19 +1,23 @@ import { Box, BoxProps, useColorModeValue } from "@chakra-ui/react"; import clsx from "clsx"; -import { PropsWithChildren } from "react"; +import { useMemo } from "react"; -export const SurveyCard = (props: PropsWithChildren<{ className?: string }>) => { +export const SurveyCard = (props: BoxProps) => { const backgroundColor = useColorModeValue("white", "gray.700"); - const BoxClasses: BoxProps = { - gap: "2", - borderRadius: "xl", - shadow: "base", - className: clsx("p-4 sm:p-6", props.className), - }; + const boxProps: BoxProps = useMemo( + () => ({ + gap: "2", + borderRadius: "xl", + shadow: "base", + ...props, + className: clsx("p-4 sm:p-6", props.className), + }), + [props] + ); return ( - + {props.children} ); diff --git a/website/src/components/ToSWrapper.tsx b/website/src/components/ToSWrapper.tsx new file mode 100644 index 00000000..98380ae0 --- /dev/null +++ b/website/src/components/ToSWrapper.tsx @@ -0,0 +1,50 @@ +import { Flex, Text } from "@chakra-ui/react"; +import { useSession } from "next-auth/react"; +import { useTranslation } from "next-i18next"; +import { ReactNode, useMemo } from "react"; +import { SubmitButton } from "src/components/Buttons/Submit"; +import { SurveyCard } from "src/components/Survey/SurveyCard"; +import { post } from "src/lib/api"; +import { TermsOfService } from "src/pages/terms-of-service"; + +const navigateAway = () => { + location.href = "https://laion.ai/"; +}; + +const acceptToS = async () => { + await post("/api/tos", { arg: {} }); + location.reload(); +}; + +export const ToSWrapper = ({ children }: { children?: ReactNode | undefined }) => { + const { t } = useTranslation("tos"); + const { data: session, status } = useSession(); + const hasAcceptedTos = Boolean(session?.user.tosAcceptanceDate); + const isLoading = status === "loading"; + + const contents = useMemo( + () => ( + + + {t("title")} + + {t("content")} + + + + {t("decline")} + + + {t("accept")} + + + + ), + [t] + ); + + if (isLoading || hasAcceptedTos) { + return <>{children}; + } + return contents; +}; diff --git a/website/src/lib/oasst_api_client.ts b/website/src/lib/oasst_api_client.ts index 490e036e..f8307854 100644 --- a/website/src/lib/oasst_api_client.ts +++ b/website/src/lib/oasst_api_client.ts @@ -13,6 +13,10 @@ export class OasstError { this.errorCode = errorCode; this.httpStatusCode = httpStatusCode; } + + toString() { + return JSON.stringify(this); + } } export class OasstApiClient { @@ -30,12 +34,66 @@ export class OasstApiClient { } } - fetch_full_settings() { - return this.get>("/api/v1/admin/backend_settings/full"); + private async request( + method: "GET" | "POST" | "PUT" | "DELETE", + path: string, + init?: RequestInit + ): Promise { + const resp = await fetch(`${this.oasstApiUrl}${path}`, { + method, + ...init, + headers: { + ...init?.headers, + ...this.userHeaders, + "X-API-Key": this.oasstApiKey, + "Content-Type": "application/json", + }, + }); + + if (resp.status === 204) { + return null; + } + + if (resp.status >= 300) { + const errorText = await resp.text(); + let error; + try { + error = JSON.parse(errorText); + } catch (e) { + throw new OasstError(errorText, 0, resp.status); + } + throw new OasstError(error.message ?? error, error.error_code, resp.status); + } + + return resp.json(); } - fetch_public_settings() { - return this.get>("/api/v1/admin/backend_settings/public"); + private async post(path: string, body: unknown) { + return this.request("POST", path, { + body: JSON.stringify(body), + }); + } + + private async put(path: string) { + return this.request("PUT", path); + } + + private async get(path: string, query?: Record) { + if (!query) { + return this.request("GET", path); + } + + const filteredQuery = Object.fromEntries( + Object.entries(query).filter(([, value]) => value !== undefined) + ) as Record; + + const params = new URLSearchParams(filteredQuery).toString(); + + return this.request("GET", `${path}?${params}`); + } + + private async delete(path: string) { + return this.request("DELETE", path); } // TODO return a strongly typed Task? @@ -50,15 +108,11 @@ export class OasstApiClient { } async ackTask(taskId: string, messageId: string): Promise { - return this.post(`/api/v1/tasks/${taskId}/ack`, { - message_id: messageId, - }); + return this.post(`/api/v1/tasks/${taskId}/ack`, { message_id: messageId }); } async nackTask(taskId: string, reason: string): Promise { - return this.post(`/api/v1/tasks/${taskId}/nack`, { - reason, - }); + return this.post(`/api/v1/tasks/${taskId}/nack`, { reason }); } // TODO return a strongly typed Task? @@ -84,6 +138,14 @@ export class OasstApiClient { }); } + fetch_full_settings() { + return this.get>("/api/v1/admin/backend_settings/full"); + } + + fetch_public_settings() { + return this.get>("/api/v1/admin/backend_settings/public"); + } + /** * Returns the tasks availability information for given `user`. */ @@ -208,68 +270,6 @@ export class OasstApiClient { }); } - private async post(path: string, body: unknown) { - return this.request("POST", path, { - body: JSON.stringify(body), - }); - } - - private async put(path: string) { - return this.request("PUT", path); - } - - private async delete(path: string) { - return this.request("DELETE", path); - } - - private async get(path: string, query?: Record) { - if (!query) { - return this.request("GET", path); - } - - const filteredQuery = Object.fromEntries( - Object.entries(query).filter(([, value]) => value !== undefined) - ) as Record; - - const params = new URLSearchParams(filteredQuery).toString(); - - return this.request("GET", `${path}?${params}`); - } - - private async request( - method: "GET" | "POST" | "PUT" | "DELETE", - path: string, - init?: RequestInit - ): Promise { - const resp = await fetch(`${this.oasstApiUrl}${path}`, { - method, - ...init, - headers: { - ...init?.headers, - ...this.userHeaders, - "X-API-Key": this.oasstApiKey, - "Content-Type": "application/json", - }, - }); - - if (resp.status === 204) { - return null; - } - - if (resp.status >= 300) { - const errorText = await resp.text(); - let error; - try { - error = JSON.parse(errorText); - } catch (e) { - throw new OasstError(errorText, 0, resp.status); - } - throw new OasstError(error.message ?? error, error.error_code, resp.status); - } - - return await resp.json(); - } - fetch_my_messages(user: BackendUserCore) { const params = new URLSearchParams({ username: user.id, @@ -289,4 +289,16 @@ export class OasstApiClient { fetch_conversation(messageId: string) { return this.get(`/api/v1/messages/${messageId}/conversation`); } + + async fetch_tos_acceptance(user: BackendUserCore): Promise { + const backendUser = await this.get(`/api/v1/frontend_users/${user.auth_method}/${user.id}`); + return backendUser.tos_acceptance_date; + } + + async set_tos_acceptance(user: BackendUserCore) { + // TODO: it is wasteful having to get the backend user first and then set the tos status + // is there a better way of doing this? + const backendUser = await this.get(`/api/v1/frontend_users/${user.auth_method}/${user.id}`); + await this.put(`/api/v1/users/${backendUser.user_id}?tos_acceptance=true`); + } } diff --git a/website/src/pages/api/auth/[...nextauth].ts b/website/src/pages/api/auth/[...nextauth].ts index 5b763b2c..d56868f8 100644 --- a/website/src/pages/api/auth/[...nextauth].ts +++ b/website/src/pages/api/auth/[...nextauth].ts @@ -8,7 +8,9 @@ import CredentialsProvider from "next-auth/providers/credentials"; import DiscordProvider from "next-auth/providers/discord"; import EmailProvider from "next-auth/providers/email"; import { checkCaptcha } from "src/lib/captcha"; +import { createApiClientFromUser } from "src/lib/oasst_client_factory"; import prisma from "src/lib/prismadb"; +import { BackendUserCore } from "src/types/Users"; import { generateUsername } from "unique-username-generator"; const providers: Provider[] = []; @@ -80,6 +82,9 @@ const authOptions: AuthOptions = { // Ensure we can store user data in a database. adapter: PrismaAdapter(prisma), providers, + session: { + strategy: "jwt", + }, pages: { signIn: "/auth/signin", verifyRequest: "/auth/verify", @@ -94,6 +99,7 @@ const authOptions: AuthOptions = { session.user.role = token.role; session.user.isNew = token.isNew; session.user.name = token.name; + session.user.tosAcceptanceDate = token.tosAcceptanceDate; return session; }, /** @@ -101,13 +107,38 @@ const authOptions: AuthOptions = { * This let's use forward the role to the session object. */ async jwt({ token }) { - const { isNew, name, role } = await prisma.user.findUnique({ + const { isNew, name, role, accounts, id } = await prisma.user.findUnique({ where: { id: token.sub }, - select: { name: true, role: true, isNew: true }, + select: { name: true, role: true, isNew: true, accounts: true, id: true }, }); + + const user: BackendUserCore = { + id, + display_name: name, + auth_method: accounts.length > 0 ? accounts[0].provider : "local", + }; + const oasstApiClient = createApiClientFromUser(user); + + let tosAcceptanceDate = null; + try { + /** + * when first creating a new user, the python backend is not informed about it + * so this call will return a 404 + * + * in the frontend, when the user accepts the tos, we do a full refresh + * which means this function will be called again. + */ + tosAcceptanceDate = await oasstApiClient.fetch_tos_acceptance(user); + } catch (err) { + if (err.httpStatusCode !== 404) { + throw err; + } + } + token.name = name; token.role = role; token.isNew = isNew; + token.tosAcceptanceDate = tosAcceptanceDate; return token; }, }, @@ -150,9 +181,6 @@ const authOptions: AuthOptions = { } }, }, - session: { - strategy: "jwt", - }, }; export default function auth(req: NextApiRequest, res: NextApiResponse) { diff --git a/website/src/pages/api/tos.ts b/website/src/pages/api/tos.ts new file mode 100644 index 00000000..125285a4 --- /dev/null +++ b/website/src/pages/api/tos.ts @@ -0,0 +1,19 @@ +import { withoutRole } from "src/lib/auth"; +import { createApiClientFromUser } from "src/lib/oasst_client_factory"; +import { getBackendUserCore } from "src/lib/users"; + +const handler = withoutRole("banned", async (req, res, token) => { + const user = await getBackendUserCore(token.sub); + const oasstApiClient = createApiClientFromUser(user); + if (req.method === "GET") { + const tos_acceptance_date = await oasstApiClient.fetch_tos_acceptance(user); + return res.status(200).json(tos_acceptance_date); + } else if (req.method === "POST") { + await oasstApiClient.set_tos_acceptance(user); + return res.status(200).end(); + } + + res.status(400).end(); +}); + +export default handler; diff --git a/website/src/pages/dashboard.tsx b/website/src/pages/dashboard.tsx index b34a89a3..fdd562b3 100644 --- a/website/src/pages/dashboard.tsx +++ b/website/src/pages/dashboard.tsx @@ -8,10 +8,12 @@ import { get } from "src/lib/api"; import { AvailableTasks, TaskCategory } from "src/types/Task"; export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props"; import { TaskCategoryItem } from "src/components/Dashboard/TaskOption"; +import { ToSWrapper } from "src/components/ToSWrapper"; import useSWR from "swr"; const Dashboard = () => { // Adding a demonstrative call to the backend that includes the web's JWT. + // TODO: add CORS headers to the python backend useSWR(`${process.env.NEXT_PUBLIC_BACKEND_URL}/api/v1/auth/check`, get); const { @@ -44,9 +46,11 @@ const Dashboard = () => { - - - + + + + + ); diff --git a/website/src/pages/terms-of-service.tsx b/website/src/pages/terms-of-service.tsx index 41269bdf..4d9796ea 100644 --- a/website/src/pages/terms-of-service.tsx +++ b/website/src/pages/terms-of-service.tsx @@ -5,162 +5,174 @@ import { PolicyChapterCard } from "src/components/PolicyCards/PolicyChapterCard" import { PolicySectionCard } from "src/components/PolicyCards/PolicySectionCard"; export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props"; -const TermsOfService = () => { - const TermsData = [ - { - number: "1", - title: "Scope of Application, Amendments", - desc: "", - sections: [ - { - number: "1.1", - title: "", - desc: `LAION (association in formation), Marie-Henning-Weg 143, 21035 Hamburg (hereinafter referred to as: "LAION") operates an online portal for the producing a machine learning model called Open Assistant using crowd-sourced data.`, - }, - { - number: "1.2", - title: "", - desc: "The present terms of use regulate the user relationship between the users of the portal and LAION.", - }, - { - number: "1.3", - title: "", - desc: "LAION reserves the right to amend these Terms of Use at any time, also with regard to persons already registered, if this becomes necessary due to changes in the law, changes in jurisdiction, changes in economic circumstances or gaps in these Terms of Use that subsequently become apparent. The user will be informed of such changes in good time by e-mail The user has the opportunity to object to the changes within 14 days of receipt of this e-mail. If the user does not object to the changes and continues to use the portal after expiry of the objection period, the changes shall be deemed to have been agreed effectively from the expiry of the period. If the user objects to the changes within the two-week period, LAION shall be entitled to exclude the user from using the portal. The user shall be informed of these effects once again in the e-mail.", - }, - ], - }, - { - number: "2", - title: "Subject of Use, Availability of the Service", - desc: "", - sections: [ - { - number: "2.1", - title: "", - desc: "The portal serves as a platform for creating data to train an interactive agent for scientific purposes. All text and prompt generated through the service are used for scientific purposes, in particular for the optimization of the AI.", - }, - { - number: "2.2", - title: "", - desc: "The input of texts on the portal and the subsequent generation of text by the artificial intelligence provided by the portal do not give rise to any works protected by copyright. The user who has entered the text for the generation of the text shall have neither the exclusive rights of use nor any rights of an author to the generated text.", - }, - { - number: "2.3", - title: "", - desc: "LAION shall endeavour to ensure that the portal can be used as uninterruptedly as possible. However, there shall be no legal claim to the use of the portal. LAION reserves the right, at its own discretion, to change the portal at any time and without notice, to discontinue its operation or to exclude individual users from using it. Furthermore, it cannot be ruled out that temporary restrictions or interruptions may occur due to technical faults (such as interruption of the power supply, hardware and software errors, technical problems in the data lines).", - }, - ], - }, - { - number: "3", - title: "User Obligations", - desc: "", - sections: [ - { - number: "3.1", - title: "", - desc: "The user may only use the portal for the intended purposes. In particular, he/she may not misuse the portal. The user undertakes to refrain from generating text that violate criminal law, youth protection regulations or the applicable laws of the following countries: Federal Republic of Germany, United States of America (USA), Great Britain, user's place of residence. In particular it is prohibited to enter texts that lead to the creation of pornographic, violence-glorifying or paedosexual content and/or content that violates the personal rights of third parties. LAION reserves the right to file a criminal complaint with the competent authorities in the event of violations.", - }, - { - number: "3.2", - title: "", - desc: "The user undertakes not to use any programs, algorithms or other software in connection with the use of the portal which could interfere with the functioning of the portal. Furthermore, the user shall not take any measures that may result in an unreasonable or excessive load on the infrastructure of the portal or may interfere with it in a disruptive manner.", - }, - { - number: "3.3", - title: "", - desc: "If a user notices obvious errors in the portal which could lead to misuse of the portal or the contents contained therein, the user shall be obliged to report the error to LAION without delay.", - }, - { - number: "3.4", - title: "", - desc: "The use, distribution, storage, forwarding, editing and/or other use of images that violate these terms of use is prohibited.", - }, - ], - }, - { - number: "4", - title: "Liability", - desc: "", - sections: [ - { - number: "4.1", - title: "", - desc: "LAION accepts no liability for the accuracy, completeness, reliability, up-to-dateness and usability of the content.", - }, - { - number: "4.2", - title: "", - desc: "LAION shall be liable without limitation for intent and gross negligence. In the case of simple negligence, LAION shall only be liable for damage resulting from injury to life, limb or health or an essential contractual obligation (obligation the fulfillment of which makes the proper performance of the contract possible in the first place and on the observance of which the contractual partner regularly trusts and may trust).", - }, - { - number: "4.3", - title: "", - desc: "In the event of a breach of material contractual obligations due to simple negligence, the liability of LAION shall be limited to the amount of the foreseeable, typically occurring damage. In all other respects liability shall be excluded.", - }, - { - number: "4.4", - title: "", - desc: "The above limitations of liability shall also apply in favour of the legal representatives and vicarious agents of LAION.", - }, - { - number: "4.5", - title: "", - desc: "LAION shall not be liable for the loss of data of the user. The user shall be solely responsible for the secure storage of his/her data.", - }, - { - number: "4.6", - title: "", - desc: "LAION shall not be liable for any damages incurred by the user as a result of the violation of these terms of use.", - }, - { - number: "4.7", - title: "", - desc: "LAION shall not be liable for the use of content generated on the portal by text input outside the portal. In particular, LAION shall not be liable for any damages incurred by the user due to the assumption of copyrights or exclusive rights of use.", - }, - ], - }, - { - number: "5", - title: "Data Protection", - desc: "", - sections: [ - { - number: "5.1", - title: "", - desc: "LAION processes the personal data of users in accordance with the provisions of data protection law. Detailed information can be found in the privacy policy, available at: /privacy-policy.", - }, - { - number: "5.2", - title: "", - desc: "The user expressly agrees that communication within the scope of and for the purpose of the user relationship between him/her and LAION may also take place via unencrypted e-mails. The user is aware that unencrypted e-mails only offer limited security and confidentiality.", - }, - ], - }, - { - number: "6", - title: "Final Provisions", - desc: "", - sections: [ - { - number: "6.1", - title: "", - desc: "The contractual relationship shall be governed exclusively by the law of the Federal Republic of Germany to the exclusion of the UN Convention on Contracts for the International Sale of Goods.", - }, - { - number: "6.2", - title: "", - desc: "Should individual provisions of these GTC including this provision be or become invalid in whole or in part, the validity of the remaining provisions shall remain unaffected. The invalid or missing provisions shall be replaced by the respective statutory provisions.", - }, - { - number: "6.3", - title: "", - desc: "If the customer is a merchant, a legal entity under public law or a special fund under public law, the place of jurisdiction for all disputes arising from and in connection with contracts concluded under these terms of use shall be the registered office of LAION.", - }, - ], - }, - ]; +const TermsData = [ + { + number: "1", + title: "Scope of Application, Amendments", + desc: "", + sections: [ + { + number: "1.1", + title: "", + desc: `LAION (association in formation), Marie-Henning-Weg 143, 21035 Hamburg (hereinafter referred to as: "LAION") operates an online portal for the producing a machine learning model called Open Assistant using crowd-sourced data.`, + }, + { + number: "1.2", + title: "", + desc: "The present terms of use regulate the user relationship between the users of the portal and LAION.", + }, + { + number: "1.3", + title: "", + desc: "LAION reserves the right to amend these Terms of Use at any time, also with regard to persons already registered, if this becomes necessary due to changes in the law, changes in jurisdiction, changes in economic circumstances or gaps in these Terms of Use that subsequently become apparent. The user will be informed of such changes in good time by e-mail The user has the opportunity to object to the changes within 14 days of receipt of this e-mail. If the user does not object to the changes and continues to use the portal after expiry of the objection period, the changes shall be deemed to have been agreed effectively from the expiry of the period. If the user objects to the changes within the two-week period, LAION shall be entitled to exclude the user from using the portal. The user shall be informed of these effects once again in the e-mail.", + }, + ], + }, + { + number: "2", + title: "Subject of Use, Availability of the Service", + desc: "", + sections: [ + { + number: "2.1", + title: "", + desc: "The portal serves as a platform for creating data to train an interactive agent for scientific purposes. All text and prompt generated through the service are used for scientific purposes, in particular for the optimization of the AI.", + }, + { + number: "2.2", + title: "", + desc: "The input of texts on the portal and the subsequent generation of text by the artificial intelligence provided by the portal do not give rise to any works protected by copyright. The user who has entered the text for the generation of the text shall have neither the exclusive rights of use nor any rights of an author to the generated text.", + }, + { + number: "2.3", + title: "", + desc: "LAION shall endeavour to ensure that the portal can be used as uninterruptedly as possible. However, there shall be no legal claim to the use of the portal. LAION reserves the right, at its own discretion, to change the portal at any time and without notice, to discontinue its operation or to exclude individual users from using it. Furthermore, it cannot be ruled out that temporary restrictions or interruptions may occur due to technical faults (such as interruption of the power supply, hardware and software errors, technical problems in the data lines).", + }, + ], + }, + { + number: "3", + title: "User Obligations", + desc: "", + sections: [ + { + number: "3.1", + title: "", + desc: "The user may only use the portal for the intended purposes. In particular, he/she may not misuse the portal. The user undertakes to refrain from generating text that violate criminal law, youth protection regulations or the applicable laws of the following countries: Federal Republic of Germany, United States of America (USA), Great Britain, user's place of residence. In particular it is prohibited to enter texts that lead to the creation of pornographic, violence-glorifying or paedosexual content and/or content that violates the personal rights of third parties. LAION reserves the right to file a criminal complaint with the competent authorities in the event of violations.", + }, + { + number: "3.2", + title: "", + desc: "The user undertakes not to use any programs, algorithms or other software in connection with the use of the portal which could interfere with the functioning of the portal. Furthermore, the user shall not take any measures that may result in an unreasonable or excessive load on the infrastructure of the portal or may interfere with it in a disruptive manner.", + }, + { + number: "3.3", + title: "", + desc: "If a user notices obvious errors in the portal which could lead to misuse of the portal or the contents contained therein, the user shall be obliged to report the error to LAION without delay.", + }, + { + number: "3.4", + title: "", + desc: "The use, distribution, storage, forwarding, editing and/or other use of images that violate these terms of use is prohibited.", + }, + ], + }, + { + number: "4", + title: "Liability", + desc: "", + sections: [ + { + number: "4.1", + title: "", + desc: "LAION accepts no liability for the accuracy, completeness, reliability, up-to-dateness and usability of the content.", + }, + { + number: "4.2", + title: "", + desc: "LAION shall be liable without limitation for intent and gross negligence. In the case of simple negligence, LAION shall only be liable for damage resulting from injury to life, limb or health or an essential contractual obligation (obligation the fulfillment of which makes the proper performance of the contract possible in the first place and on the observance of which the contractual partner regularly trusts and may trust).", + }, + { + number: "4.3", + title: "", + desc: "In the event of a breach of material contractual obligations due to simple negligence, the liability of LAION shall be limited to the amount of the foreseeable, typically occurring damage. In all other respects liability shall be excluded.", + }, + { + number: "4.4", + title: "", + desc: "The above limitations of liability shall also apply in favour of the legal representatives and vicarious agents of LAION.", + }, + { + number: "4.5", + title: "", + desc: "LAION shall not be liable for the loss of data of the user. The user shall be solely responsible for the secure storage of his/her data.", + }, + { + number: "4.6", + title: "", + desc: "LAION shall not be liable for any damages incurred by the user as a result of the violation of these terms of use.", + }, + { + number: "4.7", + title: "", + desc: "LAION shall not be liable for the use of content generated on the portal by text input outside the portal. In particular, LAION shall not be liable for any damages incurred by the user due to the assumption of copyrights or exclusive rights of use.", + }, + ], + }, + { + number: "5", + title: "Data Protection", + desc: "", + sections: [ + { + number: "5.1", + title: "", + desc: "LAION processes the personal data of users in accordance with the provisions of data protection law. Detailed information can be found in the privacy policy, available at: /privacy-policy.", + }, + { + number: "5.2", + title: "", + desc: "The user expressly agrees that communication within the scope of and for the purpose of the user relationship between him/her and LAION may also take place via unencrypted e-mails. The user is aware that unencrypted e-mails only offer limited security and confidentiality.", + }, + ], + }, + { + number: "6", + title: "Final Provisions", + desc: "", + sections: [ + { + number: "6.1", + title: "", + desc: "The contractual relationship shall be governed exclusively by the law of the Federal Republic of Germany to the exclusion of the UN Convention on Contracts for the International Sale of Goods.", + }, + { + number: "6.2", + title: "", + desc: "Should individual provisions of these GTC including this provision be or become invalid in whole or in part, the validity of the remaining provisions shall remain unaffected. The invalid or missing provisions shall be replaced by the respective statutory provisions.", + }, + { + number: "6.3", + title: "", + desc: "If the customer is a merchant, a legal entity under public law or a special fund under public law, the place of jurisdiction for all disputes arising from and in connection with contracts concluded under these terms of use shall be the registered office of LAION.", + }, + ], + }, +]; +export const TermsOfService = () => ( + + {TermsData.map((chapter, chapterIndex) => ( + + {chapter.sections && chapter.sections.length + ? chapter.sections.map((section, sectionIndex) => ) + : ""} + + ))} + +); + +const TermsOfServicePage = () => { return ( <> @@ -171,23 +183,12 @@ const TermsOfService = () => { Terms of Service - - - {TermsData.map((chapter, chapterIndex) => ( - - {chapter.sections && chapter.sections.length - ? chapter.sections.map((section, sectionIndex) => ( - - )) - : ""} - - ))} - + ); }; -TermsOfService.getLayout = getTransparentHeaderLayout; +TermsOfServicePage.getLayout = getTransparentHeaderLayout; -export default TermsOfService; +export default TermsOfServicePage; diff --git a/website/src/types/Users.ts b/website/src/types/Users.ts index 52240b5f..5100dec4 100644 --- a/website/src/types/Users.ts +++ b/website/src/types/Users.ts @@ -40,6 +40,36 @@ export interface BackendUser extends BackendUserCore { * True when the user is marked for deletion. False otherwise. */ deleted: boolean; + + /** + * time the user was created + */ + created_date: string; // iso date string + + /** + * if the user is shown on leaderboards + */ + show_on_leaderboard: boolean; + + /** + * streak + */ + streak_days: unknown; + + /** + * last day of latest streak + */ + streak_last_day_date: string | null; // iso date string + + /** + * last time this use made an interaction with the backend + */ + last_activity_date: string | null; // iso date string + + /** + * the date when the user accepted terms of the service + */ + tos_acceptance_date: string | null; // iso date string } /** diff --git a/website/types/i18next.d.ts b/website/types/i18next.d.ts index 67d33aa0..05111279 100644 --- a/website/types/i18next.d.ts +++ b/website/types/i18next.d.ts @@ -1,11 +1,12 @@ import type common from "public/locales/en/common.json"; import type dashboard from "public/locales/en/dashboard.json"; import type index from "public/locales/en/index.json"; +import type labelling from "public/locales/en/labelling.json"; import type leaderboard from "public/locales/en/leaderboard.json"; import type message from "public/locales/en/message.json"; -import type labelling from "public/locales/en/labelling.json"; -import type tasks from "public/locales/en/tasks.json"; import type side_menu from "public/locales/en/side_menu.json"; +import type tasks from "public/locales/en/tasks.json"; +import type tos from "public/locales/en/tos.json"; declare module "i18next" { interface CustomTypeOptions { @@ -18,6 +19,7 @@ declare module "i18next" { message: typeof message; labelling: typeof labelling; side_menu: typeof side_menu; + tos: typeof tos; }; } } diff --git a/website/types/next-auth.d.ts b/website/types/next-auth.d.ts index 738ff8f2..ed126deb 100644 --- a/website/types/next-auth.d.ts +++ b/website/types/next-auth.d.ts @@ -8,6 +8,8 @@ declare module "next-auth" { role: string; /** True when the user is new. */ isNew: boolean; + /** Iso timestamp of the user's acceptance of the terms of service */ + tosAcceptanceDate?: string; } & DefaultSession["user"]; } } @@ -18,5 +20,7 @@ declare module "next-auth/jwt" { role?: string; /** True when the user is new. */ isNew?: boolean; + /** Iso timestamp of the user's acceptance of the terms of service */ + tosAcceptanceDate?: string; } } From 323432c150b1d5fe505c199f9f56784835f741c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=B6pf?= Date: Fri, 3 Feb 2023 22:31:39 +0000 Subject: [PATCH 044/152] update LAION's address --- website/src/pages/privacy-policy.tsx | 2 +- website/src/pages/terms-of-service.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/website/src/pages/privacy-policy.tsx b/website/src/pages/privacy-policy.tsx index f84dc1e8..33d8ca11 100644 --- a/website/src/pages/privacy-policy.tsx +++ b/website/src/pages/privacy-policy.tsx @@ -64,7 +64,7 @@ const PrivacyPolicy = () => { { number: "2", title: "Responsible Controller", - desc: "Responsible controller is: LAION e.V., Marie-Henning-Weg 143, 21035 Hamburg, Germany", + desc: "Responsible controller is: LAION e.V., Herman-Lange-Weg 26, 21035 Hamburg, Germany", sections: [], }, { diff --git a/website/src/pages/terms-of-service.tsx b/website/src/pages/terms-of-service.tsx index 4d9796ea..4a7d71e9 100644 --- a/website/src/pages/terms-of-service.tsx +++ b/website/src/pages/terms-of-service.tsx @@ -14,7 +14,7 @@ const TermsData = [ { number: "1.1", title: "", - desc: `LAION (association in formation), Marie-Henning-Weg 143, 21035 Hamburg (hereinafter referred to as: "LAION") operates an online portal for the producing a machine learning model called Open Assistant using crowd-sourced data.`, + desc: `LAION e.V., Herman-Lange-Weg 26, 21035 Hamburg, Germany (hereinafter referred to as: "LAION") operates an online portal for the producing a machine learning model called Open Assistant using crowd-sourced data.`, }, { number: "1.2", From ad6c39b81ae9e7f8d50350b56f481734c11c3a32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=B6pf?= Date: Fri, 3 Feb 2023 23:48:45 +0100 Subject: [PATCH 045/152] Auto-moderation & remaining v1 fixes (#1089) * add expiry date for tasks and periodic removal, fix purge user messages sibling ranking counts * add auto-moderation feature * fix doc strings * fix bad message query * add debug log on insert message * fix >= comparison --- backend/main.py | 10 ++- backend/oasst_backend/config.py | 19 +++++ backend/oasst_backend/prompt_repository.py | 6 +- backend/oasst_backend/task_repository.py | 24 +++++- backend/oasst_backend/tree_manager.py | 92 +++++++++++++++++++++- 5 files changed, 145 insertions(+), 6 deletions(-) diff --git a/backend/main.py b/backend/main.py index 8e30b78e..dacd8097 100644 --- a/backend/main.py +++ b/backend/main.py @@ -18,7 +18,8 @@ from oasst_backend.api.v1.utils import prepare_conversation from oasst_backend.config import settings from oasst_backend.database import engine from oasst_backend.models import message_tree_state -from oasst_backend.prompt_repository import PromptRepository, TaskRepository, UserRepository +from oasst_backend.prompt_repository import PromptRepository, UserRepository +from oasst_backend.task_repository import TaskRepository, delete_expired_tasks from oasst_backend.tree_manager import TreeManager from oasst_backend.user_repository import User from oasst_backend.user_stats_repository import UserStatsRepository, UserStatsTimeFrame @@ -318,6 +319,13 @@ def update_user_streak(session: Session) -> None: return +@app.on_event("startup") +@repeat_every(seconds=60 * 60) # 1 hour +@managed_tx_function(auto_commit=CommitMode.COMMIT) +def cronjob_delete_expired_tasks(session: Session) -> None: + delete_expired_tasks(session) + + app.include_router(api_router, prefix=settings.API_V1_STR) diff --git a/backend/oasst_backend/config.py b/backend/oasst_backend/config.py index f1685221..1d260764 100644 --- a/backend/oasst_backend/config.py +++ b/backend/oasst_backend/config.py @@ -25,12 +25,29 @@ class TreeManagerConfiguration(BaseModel): goal_tree_size: int = 12 """Total number of messages to gather per tree.""" + random_goal_tree_size: bool = False + """If set to true goal tree sizes will be generated randomly within range [min_goal_tree_size, goal_tree_size].""" + + min_goal_tree_size: int = 5 + """Minimum tree size for random goal sizes.""" + num_reviews_initial_prompt: int = 3 """Number of peer review checks to collect in INITIAL_PROMPT_REVIEW state.""" num_reviews_reply: int = 3 """Number of peer review checks to collect per reply (other than initial_prompt).""" + auto_mod_enabled: bool = True + """Flag to enable/disable auto moderation.""" + + auto_mod_max_skip_reply: int = 25 + """Automatically set tree state to `halted_by_moderator` when more than the specified number + of users skip replying to a message. (auto moderation)""" + + auto_mod_red_flags: int = 3 + """Delete messages that receive more than this number of red flags if it is a reply or + set the tree to `aborted_low_grade` when a prompt is flagged. (auto moderation)""" + p_full_labeling_review_prompt: float = 1.0 """Probability of full text-labeling (instead of mandatory only) for initial prompts.""" @@ -222,6 +239,8 @@ class Settings(BaseSettings): RATE_LIMIT_TASK_API_TIMES: int = 10_000 RATE_LIMIT_TASK_API_MINUTES: int = 1 + TASK_VALIDITY_MINUTES: int = 60 * 24 * 2 # tasks expire after 2 days + class Config: env_file = ".env" env_file_encoding = "utf-8" diff --git a/backend/oasst_backend/prompt_repository.py b/backend/oasst_backend/prompt_repository.py index dacd5f9b..cb1dd2e2 100644 --- a/backend/oasst_backend/prompt_repository.py +++ b/backend/oasst_backend/prompt_repository.py @@ -155,8 +155,6 @@ class PromptRepository: review_result=review_result, ) self.db.add(message) - - # self.db.refresh(message) return message def _validate_task( @@ -288,6 +286,10 @@ class PromptRepository: task.done = True self.db.add(task) self.journal.log_text_reply(task=task, message_id=new_message_id, role=role, length=len(text)) + logger.debug( + f"Inserted message id={user_message.id}, tree={user_message.message_tree_id}, user_id={user_message.user_id}, " + f"text[:100]='{user_message.text[:100]}', role='{user_message.role}', lang='{user_message.lang}'" + ) return user_message @managed_tx_method(CommitMode.FLUSH) diff --git a/backend/oasst_backend/task_repository.py b/backend/oasst_backend/task_repository.py index 5fe84b24..7748840a 100644 --- a/backend/oasst_backend/task_repository.py +++ b/backend/oasst_backend/task_repository.py @@ -1,16 +1,18 @@ -from datetime import timedelta +from datetime import datetime, timedelta from typing import Optional from uuid import UUID import oasst_backend.models.db_payload as db_payload from loguru import logger +from oasst_backend.config import settings from oasst_backend.models import ApiClient, Task from oasst_backend.models.payload_column_type import PayloadContainer from oasst_backend.user_repository import UserRepository from oasst_backend.utils.database_utils import CommitMode, managed_tx_method from oasst_shared.exceptions.oasst_api_error import OasstError, OasstErrorCode from oasst_shared.schemas import protocol as protocol_schema -from sqlmodel import Session, func, or_ +from oasst_shared.utils import utcnow +from sqlmodel import Session, delete, func, or_ from starlette.status import HTTP_404_NOT_FOUND @@ -24,6 +26,13 @@ def validate_frontend_message_id(message_id: str) -> None: raise OasstError("message_id must not be empty", OasstErrorCode.INVALID_FRONTEND_MESSAGE_ID) +def delete_expired_tasks(session: Session) -> int: + stm = delete(Task).where(Task.expiry_date < utcnow()) + result = session.exec(stm) + logger.info(f"Deleted {result.rowcount} expired tasks.") + return result.rowcount + + class TaskRepository: def __init__( self, @@ -118,12 +127,18 @@ class TaskRepository: case _: raise OasstError(f"Invalid task type: {type(task)=}", OasstErrorCode.INVALID_TASK_TYPE) + if not collective and settings.TASK_VALIDITY_MINUTES > 0: + expiry_date = utcnow() + timedelta(minutes=settings.TASK_VALIDITY_MINUTES) + else: + expiry_date = None + task_model = self.insert_task( payload=payload, id=task.id, message_tree_id=message_tree_id, parent_message_id=parent_message_id, collective=collective, + expiry_date=expiry_date, ) assert task_model.id == task.id return task_model @@ -175,6 +190,7 @@ class TaskRepository: message_tree_id: UUID = None, parent_message_id: UUID = None, collective: bool = False, + expiry_date: datetime = None, ) -> Task: c = PayloadContainer(payload=payload) task = Task( @@ -186,6 +202,7 @@ class TaskRepository: message_tree_id=message_tree_id, parent_message_id=parent_message_id, collective=collective, + expiry_date=expiry_date, ) logger.debug(f"inserting {task=}") self.db.add(task) @@ -218,3 +235,6 @@ class TaskRepository: if limit: qry = qry.limit(limit) return qry.all() + + def delete_expired_tasks(self) -> int: + return delete_expired_tasks(self.db) diff --git a/backend/oasst_backend/tree_manager.py b/backend/oasst_backend/tree_manager.py index f24292a4..7d5a37d9 100644 --- a/backend/oasst_backend/tree_manager.py +++ b/backend/oasst_backend/tree_manager.py @@ -9,6 +9,7 @@ from uuid import UUID import numpy as np import pydantic +import sqlalchemy as sa from fastapi.encoders import jsonable_encoder from loguru import logger from oasst_backend.api.v1.utils import prepare_conversation, prepare_conversation_message_list @@ -31,6 +32,7 @@ from oasst_backend.utils.ranking import ranked_pairs from oasst_shared.exceptions.oasst_api_error import OasstError, OasstErrorCode from oasst_shared.schemas import protocol as protocol_schema from oasst_shared.utils import utcnow +from sqlalchemy.sql.functions import coalesce from sqlmodel import Session, and_, func, not_, or_, text, update @@ -269,6 +271,31 @@ class TreeManager: self._enter_state(mts, message_tree_state.State.GROWING) self.db.flush() + def _auto_moderation(self, lang: str) -> None: + if not self.cfg.auto_mod_enabled: + return + + bad_messages = self.query_moderation_bad_messages(lang=lang) + for m in bad_messages: + num_red_flag = m.emojis.get(protocol_schema.EmojiCode.red_flag) + + if num_red_flag is not None and num_red_flag >= self.cfg.auto_mod_red_flags: + if m.parent_id is None: + logger.warning( + f"[AUTO MOD] Halting tree {m.message_tree_id}, inital prompt got too many red flags ({m.emojis})." + ) + self.enter_low_grade_state(m.message_tree_id) + else: + logger.warning(f"[AUTO MOD] Deleting message {m.id=}, it received too many red flags ({m.emojis}).") + self.pr.mark_messages_deleted(m.id, recursive=True) + + num_skip_reply = m.emojis.get(protocol_schema.EmojiCode.skip_reply) + if num_skip_reply is not None and num_skip_reply >= self.cfg.auto_mod_max_skip_reply: + logger.warning( + f"[AUTO MOD] Halting tree {m.message_tree_id} due to high skip-reply count of message {m.id=} ({m.emojis})." + ) + self.halt_tree(m.id, halt=True) + def determine_task_availability(self, lang: str) -> dict[protocol_schema.TaskRequestType, int]: self.pr.ensure_user_is_enabled() @@ -276,6 +303,7 @@ class TreeManager: lang = "en" logger.warning("Task availability request without lang tag received, assuming lang='en'.") + self._auto_moderation(lang=lang) num_missing_prompts = self._prompt_lottery(lang=lang) extendible_parents, _ = self.query_extendible_parents(lang=lang) prompts_need_review = self.query_prompts_need_review(lang=lang) @@ -313,6 +341,7 @@ class TreeManager: lang = "en" logger.warning("Task request without lang tag received, assuming 'en'.") + self._auto_moderation(lang=lang) num_missing_prompts = self._prompt_lottery(lang=lang) prompts_need_review = self.query_prompts_need_review(lang=lang) @@ -1254,6 +1283,37 @@ LEFT JOIN message_reaction mr ON mr.task_id = t.id AND mr.payload_type = 'Rankin ) return qry.all() + def query_moderation_bad_messages(self, lang: str) -> list[Message]: + qry = ( + self.db.query(Message) + .select_from(MessageTreeState) + .join(Message, MessageTreeState.message_tree_id == Message.message_tree_id) + .filter( + MessageTreeState.active, + or_( + MessageTreeState.state == message_tree_state.State.INITIAL_PROMPT_REVIEW, + MessageTreeState.state == message_tree_state.State.GROWING, + ), + or_( + Message.parent_id.is_(None), + Message.review_result, + and_(Message.parent_id.is_not(None), Message.review_count < self.cfg.num_reviews_reply), + ), + not_(Message.deleted), + or_( + coalesce(Message.emojis[protocol_schema.EmojiCode.red_flag].cast(sa.Integer), 0) + >= self.cfg.auto_mod_red_flags, + coalesce(Message.emojis[protocol_schema.EmojiCode.skip_reply].cast(sa.Integer), 0) + >= self.cfg.auto_mod_max_skip_reply, + ), + ) + ) + + if lang is not None: + qry = qry.filter(Message.lang == lang) + + return qry.all() + @managed_tx_method(CommitMode.FLUSH) def _insert_tree_state( self, @@ -1281,10 +1341,17 @@ LEFT JOIN message_reaction mr ON mr.task_id = t.id AND mr.payload_type = 'Rankin self, root_message_id: UUID, state: message_tree_state.State = message_tree_state.State.INITIAL_PROMPT_REVIEW, + *, + goal_tree_size: int = None, ) -> MessageTreeState: + if goal_tree_size is None: + if self.cfg.random_goal_tree_size and self.cfg.min_goal_tree_size < self.cfg.goal_tree_size: + goal_tree_size = random.randint(self.cfg.min_goal_tree_size, self.cfg.goal_tree_size) + else: + goal_tree_size = self.cfg.goal_tree_size return self._insert_tree_state( root_message_id=root_message_id, - goal_tree_size=self.cfg.goal_tree_size, + goal_tree_size=goal_tree_size, max_depth=self.cfg.max_tree_depth, max_children_count=self.cfg.max_children_count, state=state, @@ -1379,9 +1446,32 @@ DELETE FROM task t using message m WHERE t.id = m.task_id AND m.id = :message_id DELETE FROM task t WHERE t.parent_message_id = :message_id; DELETE FROM message WHERE id = :message_id; """ + parent_id = self.pr.fetch_message(message_id=message_id).parent_id r = self.db.execute(text(sql_purge_message), {"message_id": message_id}) logger.debug(f"purge_message({message_id=}): {r.rowcount} rows.") + sql_update_ranking_counts = """ +WITH r AS ( + -- find ranking results and count per child + SELECT c.id, + count(*) FILTER ( + WHERE mr.payload#>'{payload, ranked_message_ids}' ? CAST(c.id AS varchar) + ) AS ranking_count + FROM message c + LEFT JOIN message_reaction mr ON mr.payload_type = 'RankingReactionPayload' + AND mr.message_id = c.parent_id + WHERE c.parent_id = :parent_id + GROUP BY c.id +) +UPDATE message m SET ranking_count = r.ranking_count +FROM r WHERE m.id = r.id AND m.ranking_count != r.ranking_count; +""" + + if parent_id is not None: + # update ranking counts of remaining children + r = self.db.execute(text(sql_update_ranking_counts), {"parent_id": parent_id}) + logger.debug(f"ranking_count updated for {r.rowcount} rows.") + def purge_message_tree(self, message_tree_id: UUID) -> None: sql_purge_message_tree = """ DELETE FROM journal j USING message m WHERE j.message_id = m.Id AND m.message_tree_id = :message_tree_id; From ef5b9d775771afdfc2fcc4830a177a74bcd6e218 Mon Sep 17 00:00:00 2001 From: Keith Stevens Date: Sat, 4 Feb 2023 16:18:19 +0900 Subject: [PATCH 046/152] Fixing the way we generate the backenduser object during jwt creation (#1090) --- website/src/pages/api/auth/[...nextauth].ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/src/pages/api/auth/[...nextauth].ts b/website/src/pages/api/auth/[...nextauth].ts index d56868f8..d75422a4 100644 --- a/website/src/pages/api/auth/[...nextauth].ts +++ b/website/src/pages/api/auth/[...nextauth].ts @@ -112,8 +112,9 @@ const authOptions: AuthOptions = { select: { name: true, role: true, isNew: true, accounts: true, id: true }, }); + // Note: This could be cleaner and merged with src/lib/users.ts const user: BackendUserCore = { - id, + id: accounts.length > 0 ? accounts[0].providerAccountId : id, display_name: name, auth_method: accounts.length > 0 ? accounts[0].provider : "local", }; From f547aa07faecbde9e1de694d48df144413ff0cc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=B6pf?= Date: Sat, 4 Feb 2023 14:02:54 +0100 Subject: [PATCH 047/152] retain completed tasks after expiry --- backend/oasst_backend/task_repository.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/oasst_backend/task_repository.py b/backend/oasst_backend/task_repository.py index 7748840a..38a23e0c 100644 --- a/backend/oasst_backend/task_repository.py +++ b/backend/oasst_backend/task_repository.py @@ -12,7 +12,7 @@ from oasst_backend.utils.database_utils import CommitMode, managed_tx_method from oasst_shared.exceptions.oasst_api_error import OasstError, OasstErrorCode from oasst_shared.schemas import protocol as protocol_schema from oasst_shared.utils import utcnow -from sqlmodel import Session, delete, func, or_ +from sqlmodel import Session, delete, false, func, or_ from starlette.status import HTTP_404_NOT_FOUND @@ -27,7 +27,7 @@ def validate_frontend_message_id(message_id: str) -> None: def delete_expired_tasks(session: Session) -> int: - stm = delete(Task).where(Task.expiry_date < utcnow()) + stm = delete(Task).where(Task.expiry_date < utcnow(), Task.done == false()) result = session.exec(stm) logger.info(f"Deleted {result.rowcount} expired tasks.") return result.rowcount @@ -236,5 +236,5 @@ class TaskRepository: qry = qry.limit(limit) return qry.all() - def delete_expired_tasks(self) -> int: + def delete_expired(self) -> int: return delete_expired_tasks(self.db) From af0711e505dc9ba640bfc7e8a646ec10d7ee1e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=B6pf?= Date: Sat, 4 Feb 2023 14:36:29 +0100 Subject: [PATCH 048/152] include initial prompt review in user stats --- .../oasst_backend/user_stats_repository.py | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/backend/oasst_backend/user_stats_repository.py b/backend/oasst_backend/user_stats_repository.py index 4c28b293..cca0d6bf 100644 --- a/backend/oasst_backend/user_stats_repository.py +++ b/backend/oasst_backend/user_stats_repository.py @@ -18,11 +18,20 @@ from oasst_backend.models import ( ) from oasst_backend.models.db_payload import ( LabelAssistantReplyPayload, + LabelInitialPromptPayload, LabelPrompterReplyPayload, RankingReactionPayload, ) from oasst_backend.models.message_tree_state import State as TreeState -from oasst_shared.schemas.protocol import EmojiCode, LeaderboardStats, TextLabel, TrollboardStats, TrollScore, UserScore +from oasst_shared.schemas.protocol import ( + EmojiCode, + LabelTaskMode, + LeaderboardStats, + TextLabel, + TrollboardStats, + TrollScore, + UserScore, +) from oasst_shared.utils import log_timing, utcnow from sqlalchemy.dialects import postgresql from sqlalchemy.sql.functions import coalesce @@ -310,9 +319,9 @@ class UserStatsRepository: for r in qry: uid, mode, count = r s = get_stats(uid) - if mode == "simple": + if mode == LabelTaskMode.simple: s.labels_simple = count - elif mode == "full": + elif mode == LabelTaskMode.full: s.labels_full = count qry = self.query_labels_by_mode_per_user( @@ -321,9 +330,20 @@ class UserStatsRepository: for r in qry: uid, mode, count = r s = get_stats(uid) - if mode == "simple": + if mode == LabelTaskMode.simple: s.labels_simple += count - elif mode == "full": + elif mode == LabelTaskMode.full: + s.labels_full += count + + qry = self.query_labels_by_mode_per_user( + payload_type=LabelInitialPromptPayload.__name__, reference_time=base_date + ) + for r in qry: + uid, mode, count = r + s = get_stats(uid) + if mode == LabelTaskMode.simple: + s.labels_simple += count + elif mode == LabelTaskMode.full: s.labels_full += count qry = self.query_rankings_per_user(reference_time=base_date) From b724b37d4c100a9f72cbf5be57adf9387030148d Mon Sep 17 00:00:00 2001 From: AbdBarho Date: Sat, 4 Feb 2023 14:39:50 +0100 Subject: [PATCH 049/152] Fix ToS page in dark mode (#1091) --- website/src/pages/terms-of-service.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/website/src/pages/terms-of-service.tsx b/website/src/pages/terms-of-service.tsx index 4a7d71e9..66a01bf1 100644 --- a/website/src/pages/terms-of-service.tsx +++ b/website/src/pages/terms-of-service.tsx @@ -179,11 +179,13 @@ const TermsOfServicePage = () => { Terms of Service - Open Assistant - - - Terms of Service - - + + + + Terms of Service + + + ); From effbde407a8e8d4786ac73cbb52a2cc5825907ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=B6pf?= Date: Sat, 4 Feb 2023 18:28:17 +0100 Subject: [PATCH 050/152] increase db pool size --- backend/oasst_backend/config.py | 3 +++ backend/oasst_backend/database.py | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/backend/oasst_backend/config.py b/backend/oasst_backend/config.py index 1d260764..683133f7 100644 --- a/backend/oasst_backend/config.py +++ b/backend/oasst_backend/config.py @@ -166,6 +166,9 @@ class Settings(BaseSettings): DATABASE_URI: Optional[PostgresDsn] = None DATABASE_MAX_TX_RETRY_COUNT: int = 3 + DATABASE_POOL_SIZE = 128 + DATABASE_MAX_OVERFLOW = 128 + RATE_LIMIT: bool = True MESSAGE_SIZE_LIMIT: int = 2000 REDIS_HOST: str = "localhost" diff --git a/backend/oasst_backend/database.py b/backend/oasst_backend/database.py index 1d0e19b2..a77ca1f5 100644 --- a/backend/oasst_backend/database.py +++ b/backend/oasst_backend/database.py @@ -5,4 +5,10 @@ from sqlmodel import create_engine if settings.DATABASE_URI is None: raise OasstError("DATABASE_URI is not set", error_code=OasstErrorCode.DATABASE_URI_NOT_SET) -engine = create_engine(settings.DATABASE_URI, echo=settings.DEBUG_DATABASE_ECHO, isolation_level="REPEATABLE READ") +engine = create_engine( + settings.DATABASE_URI, + echo=settings.DEBUG_DATABASE_ECHO, + isolation_level="REPEATABLE READ", + pool_size=settings.DATABASE_POOL_SIZE, + max_overflow=settings.DATABASE_MAX_OVERFLOW, +) From f02543b36f6ea2c73091356e287390208889df09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=B6pf?= Date: Sat, 4 Feb 2023 20:26:20 +0100 Subject: [PATCH 051/152] reduce INFO logging --- .github/workflows/deploy-to-node.yaml | 1 + ansible/deploy-to-node.yaml | 3 +++ backend/oasst_backend/api/v1/tasks.py | 3 ++- backend/oasst_backend/config.py | 4 ++-- backend/oasst_backend/tree_manager.py | 15 ++++++++++----- 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/.github/workflows/deploy-to-node.yaml b/.github/workflows/deploy-to-node.yaml index 3457293e..436e7f58 100644 --- a/.github/workflows/deploy-to-node.yaml +++ b/.github/workflows/deploy-to-node.yaml @@ -59,6 +59,7 @@ jobs: ${{ vars.WEB_NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN_CAPTCHA }} WEB_NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN: ${{ vars.WEB_NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN }} + LOGURU_LEVEL: ${{ vars.LOGURU_LEVEL }} steps: - name: Checkout uses: actions/checkout@v2 diff --git a/ansible/deploy-to-node.yaml b/ansible/deploy-to-node.yaml index 23bc0573..639003a4 100644 --- a/ansible/deploy-to-node.yaml +++ b/ansible/deploy-to-node.yaml @@ -149,6 +149,9 @@ USER_STATS_INTERVAL_TOTAL: "{{ lookup('ansible.builtin.env', 'STATS_INTERVAL_TOTAL') | default('240', true) }}" + LOGURU_LEVEL: + "{{ lookup('ansible.builtin.env', 'LOGURU_LEVEL') | default('INFO', + true) }}" ports: - "{{ backend_port }}:8080" diff --git a/backend/oasst_backend/api/v1/tasks.py b/backend/oasst_backend/api/v1/tasks.py index c817ba67..c74dfcf3 100644 --- a/backend/oasst_backend/api/v1/tasks.py +++ b/backend/oasst_backend/api/v1/tasks.py @@ -104,7 +104,8 @@ def tasks_acknowledge( pr = PromptRepository(db, api_client, frontend_user=frontend_user) # here we store the message id in the database for the task - logger.info(f"Frontend acknowledges task {task_id=}, {ack_request=}.") + logger.info(f"Frontend ACK task_id={task_id}") + logger.debug(f"{ack_request=}.") pr.task_repository.bind_frontend_message_id(task_id=task_id, frontend_message_id=ack_request.message_id) except OasstError: diff --git a/backend/oasst_backend/config.py b/backend/oasst_backend/config.py index 683133f7..ff4c5497 100644 --- a/backend/oasst_backend/config.py +++ b/backend/oasst_backend/config.py @@ -166,8 +166,8 @@ class Settings(BaseSettings): DATABASE_URI: Optional[PostgresDsn] = None DATABASE_MAX_TX_RETRY_COUNT: int = 3 - DATABASE_POOL_SIZE = 128 - DATABASE_MAX_OVERFLOW = 128 + DATABASE_POOL_SIZE = 75 + DATABASE_MAX_OVERFLOW = 20 RATE_LIMIT: bool = True MESSAGE_SIZE_LIMIT: int = 2000 diff --git a/backend/oasst_backend/tree_manager.py b/backend/oasst_backend/tree_manager.py index 7d5a37d9..6b4f5236 100644 --- a/backend/oasst_backend/tree_manager.py +++ b/backend/oasst_backend/tree_manager.py @@ -623,7 +623,8 @@ class TreeManager: HTTPStatus.SERVICE_UNAVAILABLE, ) - logger.info(f"Generated {task=}.") + logger.info(f"Generated task (type={task.type}, id={task.id})") + logger.debug(f"Generated {task=}.") return task, message_tree_id, parent_message_id @@ -634,8 +635,9 @@ class TreeManager: match type(interaction): case protocol_schema.TextReplyToMessage: logger.info( - f"Frontend reports text reply to {interaction.message_id=} with {interaction.text=} by {interaction.user=}." + f"Frontend reports text reply to message_id={interaction.message_id} by user={interaction.user}." ) + logger.debug(f"with {interaction.text=}") # here we store the text reply in the database message = pr.store_text_reply( text=interaction.text, @@ -682,23 +684,26 @@ class TreeManager: case protocol_schema.MessageRating: logger.info( - f"Frontend reports rating of {interaction.message_id=} with {interaction.rating=} by {interaction.user=}." + f"Frontend reports rating of message_id={interaction.message_id} by user={interaction.user}." ) + logger.debug(f"with {interaction.rating=}") pr.store_rating(interaction) case protocol_schema.MessageRanking: logger.info( - f"Frontend reports ranking of {interaction.message_id=} with {interaction.ranking=} by {interaction.user=}." + f"Frontend reports ranking of message_id={interaction.message_id} by user={interaction.user}." ) + logger.debug(f"with {interaction.ranking=}") _, task = pr.store_ranking(interaction) self.check_condition_for_scoring_state(task.message_tree_id) case protocol_schema.TextLabels: logger.info( - f"Frontend reports labels of {interaction.message_id=} with {interaction.labels=} by {interaction.user=}." + f"Frontend reports labels of message_id={interaction.message_id} by user={interaction.user}." ) + logger.debug(f"with {interaction.labels=}") _, task, msg = pr.store_text_labels(interaction) From 8e88057206fb40c2cbd290fd4088d0dc78622e73 Mon Sep 17 00:00:00 2001 From: Yannic Kilcher Date: Sat, 4 Feb 2023 20:29:02 +0100 Subject: [PATCH 052/152] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 927314ff..3c708323 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,10 @@
+# Here is our website to collect data: + +[open-assistant.io](https://open-assistant.io) + # Table of Contents - [What is Open Assistant?](#what-is-open-assistant) From 1db8f0554ef4074260fd813e9d69b736c7615654 Mon Sep 17 00:00:00 2001 From: Yannic Kilcher Date: Sat, 4 Feb 2023 20:42:04 +0100 Subject: [PATCH 053/152] added prod2 deploy workflow --- .github/workflows/production2-deploy.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .github/workflows/production2-deploy.yaml diff --git a/.github/workflows/production2-deploy.yaml b/.github/workflows/production2-deploy.yaml new file mode 100644 index 00000000..a496e428 --- /dev/null +++ b/.github/workflows/production2-deploy.yaml @@ -0,0 +1,16 @@ +name: Deploy to prod2 + +on: + push: + branches: + - production2 + +jobs: + deploy-to-prod: + uses: ./.github/workflows/deploy-to-node.yaml + secrets: inherit + with: + stack-name: production2 + image-tag: ${{ vars.PROD_IMAGE_TAG }} + backend-port: 8280 + website-port: 3200 From 66ff38defa136715e9e893eaf962f5e505e21e72 Mon Sep 17 00:00:00 2001 From: Eunkwang Jeon Date: Sun, 5 Feb 2023 04:42:36 +0900 Subject: [PATCH 054/152] add korean localization (#1115) --- website/next-i18next.config.js | 2 +- website/public/locales/ko/common.json | 25 +++++++ website/public/locales/ko/dashboard.json | 8 +++ website/public/locales/ko/index.json | 15 ++++ website/public/locales/ko/labelling.json | 24 +++++++ website/public/locales/ko/leaderboard.json | 18 +++++ website/public/locales/ko/message.json | 16 +++++ website/public/locales/ko/side_menu.json | 12 ++++ website/public/locales/ko/tasks.json | 82 ++++++++++++++++++++++ 9 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 website/public/locales/ko/common.json create mode 100644 website/public/locales/ko/dashboard.json create mode 100644 website/public/locales/ko/index.json create mode 100644 website/public/locales/ko/labelling.json create mode 100644 website/public/locales/ko/leaderboard.json create mode 100644 website/public/locales/ko/message.json create mode 100644 website/public/locales/ko/side_menu.json create mode 100644 website/public/locales/ko/tasks.json diff --git a/website/next-i18next.config.js b/website/next-i18next.config.js index 03ed6e99..efa84ef6 100644 --- a/website/next-i18next.config.js +++ b/website/next-i18next.config.js @@ -1,6 +1,6 @@ module.exports = { i18n: { defaultLocale: "en", - locales: ["bn", "de", "en", "es", "fr", "hu", "ja", "pt-BR", "ru", "vi", "zh"], + locales: ["bn", "de", "en", "es", "fr", "hu", "ja", "ko", "pt-BR", "ru", "vi", "zh"], }, }; diff --git a/website/public/locales/ko/common.json b/website/public/locales/ko/common.json new file mode 100644 index 00000000..679c0af2 --- /dev/null +++ b/website/public/locales/ko/common.json @@ -0,0 +1,25 @@ +{ + "about": "About", + "account_settings": "계정", + "admin_dashboard": "관리자 대시보드", + "connect": "연결", + "conversational": "모두를 위한 대화형 AI.", + "dashboard": "대시보드", + "delete": "삭제", + "discord": "Discord", + "docs": "문서", + "github": "GitHub", + "legal": "Legal", + "loading": "로딩중...", + "more_information": "추가 정보", + "no": "아니오", + "privacy_policy": "개인정보보호 정책", + "report_a_bug": "버그신고", + "sign_in": "Sign In", + "sign_out": "Sign Out", + "terms_of_service": "서비스 약관", + "title": "오픈 어시스턴트", + "yes": "예", + "dark_mode": "다크 모드", + "light_mode": "라이트 모드" +} diff --git a/website/public/locales/ko/dashboard.json b/website/public/locales/ko/dashboard.json new file mode 100644 index 00000000..cc262e7f --- /dev/null +++ b/website/public/locales/ko/dashboard.json @@ -0,0 +1,8 @@ +{ + "grab_a_task": "작업을 선택하세요!", + "create": "만들다", + "evaluate": "평가하다", + "label": "레이블", + "dashboard": "대시보드", + "go": "시작" +} diff --git a/website/public/locales/ko/index.json b/website/public/locales/ko/index.json new file mode 100644 index 00000000..ab1e9df9 --- /dev/null +++ b/website/public/locales/ko/index.json @@ -0,0 +1,15 @@ +{ + "blurb": "우리는 혁명을 일으킬 수 있다고 믿습니다.", + "blurb1": "Stable Diffusion이 세상을 새로운 방식으로 예술과 이미지를 만드는 데 도움을 준 것과 마찬가지로 놀라운 대화형 AI를 제공하여 세상을 개선하고자 합니다.", + "description": "모두를 위한 대화형 AI. LAION 및 전 세계 기여자가 사용하는 채팅 지원 GPT LLM을 만드는 오픈 소스 프로젝트입니다.", + "faq_items": { + "q0": "이 프로젝트는 얼마나 진행되나요?", + "a0": "우리는 RLHF를 대규모 언어 모델에 적용하는 확립된 연구에서 작업하는 개발 초기 단계에 있습니다.", + "q1": "Open Assistant 누구와 함께 합니까?", + "a1": "Open Assistant는 이 기술을 모든 사람에게 제공하는 데 관심이 있는 LAION과 전 세계 개인이 조직한 프로젝트입니다." + }, + "faq_title": "자주 묻는 질문", + "join_us_description": "모든 오픈소스 프로젝트는 여러분과 같은 사람들로부터 시작됩니다. 우리가 협력하면 인류의 이익을 위해 우리의 지식과 기술을 세상에 선물할 수 있다는 믿음입니다. 당신도 함꼐하고 싶습니까? 여기에서 우리를 찾으십시오:", + "join_us_title": "우리와 함께하다", + "subtitle": "모두를 위한 대화형 AI." +} diff --git a/website/public/locales/ko/labelling.json b/website/public/locales/ko/labelling.json new file mode 100644 index 00000000..2aa00c26 --- /dev/null +++ b/website/public/locales/ko/labelling.json @@ -0,0 +1,24 @@ +{ + "label_highlighted_yes_no_instruction": "강조 표시된 메시지에 대한 다음 질문에 답하십시오.:", + "label_highlighted_flag_instruction": "강조 표시된 메시지에 해당하는 항목을 선택하십시오.:", + "label_highlighted_likert_instruction": "강조 표시된 메시지를 평가하십시오:", + "label_message_yes_no_instruction": "메시지에 대한 다음 질문에 답하십시오.:", + "label_message_flag_instruction": "메시지에 해당하는 것을 선택하십시오.:", + "label_message_likert_instruction": "메시지 평가:", + "spam.question": "메시지가 스팸입니까?", + "fails_task.question": "프롬프트 작업에 대해 잘못된 답변입니까?", + "not_appropriate": "알맞지 않은", + "not_appropriate.explanation": "고객 지원에 부적합.", + "pii": "개인식별정보를 포함.", + "pii.explanation": "개인 식별 정보가 포함되어 있습니다. 예를 들면 개인 연락처 세부 정보, 면허증 및 기타 식별 번호, 은행 세부 정보가 포함됩니다.", + "hate_speech": "혐오표현", + "hate_speech.explanation": "콘텐츠는 모욕적이거나 위협적이며 보호되는 특성에 대한 편견을 표현합니다. 편견은 이성에 근거하지 않은 선입견을 말합니다. 보호되는 특성에는 성별, 민족, 종교, 성적 취향 및 유사한 특성이 포함됩니다.", + "sexual_content": "성적인 내용", + "sexual_content.explanation": "성적인 내용이 포함되어 있습니다.", + "moral_judgement": "도덕적 판단", + "moral_judgement.explanation": "도덕적 판단을 표현합니다.", + "political_content": "정치적인", + "political_content.explanation": "정치적 견해를 표현합니다.", + "lang_mismatch": "잘못된 언어", + "lang_mismatch.explanation": "현재 선택한 언어로 작성되지 않았습니다." +} diff --git a/website/public/locales/ko/leaderboard.json b/website/public/locales/ko/leaderboard.json new file mode 100644 index 00000000..254f37ca --- /dev/null +++ b/website/public/locales/ko/leaderboard.json @@ -0,0 +1,18 @@ +{ + "daily": "일일", + "last_updated_at": "최종 업데이트 시간: {{val, datetime}}", + "leaderboard": "리더보드", + "monthly": "월간", + "overall": "종합", + "rank": "순위", + "score": "점수", + "user": "사용자", + "weekly": "주간", + "prompt": "프롬프트", + "reply": "답변", + "label": "레이블", + "view_all": "전체보기", + "top_5_contributors_today": "금일 상위 5명의 기여자", + "previous": "이전", + "next": "다음" +} diff --git a/website/public/locales/ko/message.json b/website/public/locales/ko/message.json new file mode 100644 index 00000000..6574b297 --- /dev/null +++ b/website/public/locales/ko/message.json @@ -0,0 +1,16 @@ +{ + "label_action": "레이블", + "label_title": "레이블", + "message": "메세지", + "open_new_tab_action": "새 탭에서 열기", + "parent": "상위", + "reactions": "반응", + "report_action": "리포트", + "report_placeholder": "이 메시지를 검토해야 하는 이유는 무엇입니까?", + "report_title": "리포트", + "send_report": "보내기", + "submit_labels": "등록", + "view_user": "사용자 보기", + "recent_messages": "최근 메세지", + "your_recent_messages": "최근 메세지들" +} diff --git a/website/public/locales/ko/side_menu.json b/website/public/locales/ko/side_menu.json new file mode 100644 index 00000000..f30f1597 --- /dev/null +++ b/website/public/locales/ko/side_menu.json @@ -0,0 +1,12 @@ +{ + "dashboard": "대시보드", + "dashboard_home": "대시보드 홈", + "messages": "메세지", + "messages_dashboard": "메세지 대시보드", + "leaderboard": "리더보드", + "user_leaderboard": "사용자 리더보드", + "users": "사용자", + "users_dashboard": "사용자 대시보드", + "status": "상태", + "status_dashboard": "상태 대시보드" +} diff --git a/website/public/locales/ko/tasks.json b/website/public/locales/ko/tasks.json new file mode 100644 index 00000000..4f46ffd3 --- /dev/null +++ b/website/public/locales/ko/tasks.json @@ -0,0 +1,82 @@ +{ + "default": { + "unchanged_title": "변경사항 없음", + "unchanged_message": "계속 하시겠습니까?" + }, + "random": { + "label": "행운이 느껴진다!", + "desc": "무작위 작업을 시작하여 Open Assistant를 개선할 수 있도록 도와주세요." + }, + "create_initial_prompt": { + "label": "초기 프롬프트 생성", + "desc": "Open Assistant가 다양한 메시지에 답장할 수 있도록 초기 프롬프트를 작성합니다.", + "overview": "어시스턴트에게 보낼 초기 메시지 작성", + "instruction": "초기 프롬프트 제공", + "response_placeholder": "여기에 프롬프트를 작성하세요..." + }, + "reply_as_user": { + "label": "사용자로 회신", + "desc": "Open Assistant와 채팅하고 상호 작용할 때 응답을 개선하는 데 도움을 줍니다.", + "overview": "다음 대화가 주어지면 적절한 답변을 제공하십시오.", + "instruction": "사용자의 답장 제공", + "response_placeholder": "여기에 답장을 쓰세요..." + }, + "reply_as_assistant": { + "label": "어시스턴트로 답장", + "desc": "Open Assistant가 다른 사용자와의 대화에 대한 응답을 개선하도록 도와주세요.", + "overview": "다음 대화가 주어지면 적절한 답변을 제공하십시오.", + "response_placeholder": "여기에 답장을 쓰세요..." + }, + "rank_user_replies": { + "label": "사용자 답글 순위 지정", + "desc": "Open Assistant가 다른 사용자와의 대화에 대한 응답을 개선하도록 도와주세요.", + "overview": "다음 사용자 응답이 주어지면 가장 좋은 것부터 가장 나쁜 것까지 정렬하세요. 가장 좋은 것이 첫 번째, 가장 나쁜 것이 마지막입니다.", + "unchanged_title": "변경되지 않은 순서", + "unchanged_message": "프롬프트의 순서를 변경하지 않았습니다. 계속하시겠습니까?" + }, + "rank_assistant_replies": { + "label": "순위 보조 답변", + "desc": "정확성과 가독성을 기준으로 Open Assistant에서 제공하는 점수 프롬프트입니다.", + "overview": "다음 어시스턴트 응답이 주어지면 가장 좋은 것부터 가장 나쁜 것까지 정렬하세요. 가장 좋은 것이 첫 번째, 가장 나쁜 것이 마지막입니다.", + "unchanged_title": "변경되지 않은 순서", + "unchanged_message": "프롬프트의 순서를 변경하지 않았습니다. 계속하시겠습니까?" + }, + "rank_initial_prompts": { + "label": "초기 프롬프트 순위지정", + "desc": "정확성과 가독성을 기준으로 Open Assistant에서 제공하는 점수 프롬프트입니다.", + "overview": "다음과 같은 초기 프롬프트가 주어지면 가장 좋은 것부터 가장 나쁜 것까지 정렬하세요. 가장 좋은 것이 첫 번째, 가장 나쁜 것이 마지막입니다.", + "unchanged_title": "변경되지 않은 순서", + "unchanged_message": "프롬프트의 순서를 변경하지 않았습니다. 계속하시겠습니까?" + }, + "label_initial_prompt": { + "label": "초기 프롬프트 레이블링", + "desc": "프롬프트에 레이블을 제공합니다.", + "overview": "다음 프롬프트에 대한 레이블 제공" + }, + "label_prompter_reply": { + "label": "프롬프터 대답에 대한 레이블링", + "desc": "프롬프트에 레이블을 제공합니다.", + "overview": "다음 논의가 주어지면 최종 프롬프트에 대한 레이블을 제공하십시오." + }, + "label_assistant_reply": { + "label": "어시스턴트 답장에 대한 레이블링", + "desc": "프롬프트에 레이블을 제공합니다.", + "overview": "다음 논의가 주어지면 최종 프롬프트에 대한 레이블을 제공하십시오." + }, + "classify_initial_prompt": { + "label": "초기 프롬프트 분류", + "desc": "프롬프트에 레이블을 제공합니다.", + "overview": "다음 프롬프트를 읽고 이에 대한 질문에 답하십시오." + }, + "classify_prompter_reply": { + "label": "프롬프터 대답 분류", + "desc": "프롬프트에 레이블을 제공합니다.", + "overview": "다음 대화를 읽고 토론의 마지막 답변에 대한 질문에 답하십시오." + }, + "classify_assistant_reply": { + "label": "어시스턴트 대답 분류", + "desc": "프롬프트에 레이블을 제공합니다.", + "overview": "다음 대화를 읽고 토론의 마지막 답변에 대한 질문에 답하십시오." + }, + "available_task_count": "{{count}} 작업 가능" +} From 0fc1109034807085afc0b3023b63f595c0011210 Mon Sep 17 00:00:00 2001 From: Saifeddine ALOUI Date: Sat, 4 Feb 2023 20:49:52 +0100 Subject: [PATCH 055/152] Added French Locale (#1112) --- website/public/locales/fr/common.json | 25 +++++++ website/public/locales/fr/dashboard.json | 8 +++ website/public/locales/fr/index.json | 15 ++++ website/public/locales/fr/labelling.json | 24 +++++++ website/public/locales/fr/leaderboard.json | 18 +++++ website/public/locales/fr/message.json | 16 +++++ website/public/locales/fr/side_menu.json | 12 ++++ website/public/locales/fr/tasks.json | 82 ++++++++++++++++++++++ website/public/locales/fr/tos.json | 6 ++ 9 files changed, 206 insertions(+) create mode 100644 website/public/locales/fr/common.json create mode 100644 website/public/locales/fr/dashboard.json create mode 100644 website/public/locales/fr/index.json create mode 100644 website/public/locales/fr/labelling.json create mode 100644 website/public/locales/fr/leaderboard.json create mode 100644 website/public/locales/fr/message.json create mode 100644 website/public/locales/fr/side_menu.json create mode 100644 website/public/locales/fr/tasks.json create mode 100644 website/public/locales/fr/tos.json diff --git a/website/public/locales/fr/common.json b/website/public/locales/fr/common.json new file mode 100644 index 00000000..6bfc17f7 --- /dev/null +++ b/website/public/locales/fr/common.json @@ -0,0 +1,25 @@ +{ + "about": "À propos", + "account_settings": "Compte", + "admin_dashboard": "Tableau de bord d'administration", + "connect": "Se connecter", + "conversational": "IA conversationnelle pour tout le monde.", + "dashboard": "Tableau de bord", + "delete": "Supprimer", + "discord": "Discord", + "docs": "Docs", + "github": "GitHub", + "legal": "Légal", + "loading": "Chargement en cours...", + "more_information": "Plus d'informations", + "no": "Non", + "privacy_policy": "Politique de confidentialité", + "report_a_bug": "Signaler un bug", + "sign_in": "Se connecter", + "sign_out": "Se déconnecter", + "terms_of_service": "Conditions d'utilisation", + "title": "Open Assistant", + "yes": "Oui", + "dark_mode": "Mode sombre", + "light_mode": "Mode clair" +} diff --git a/website/public/locales/fr/dashboard.json b/website/public/locales/fr/dashboard.json new file mode 100644 index 00000000..9ca767b8 --- /dev/null +++ b/website/public/locales/fr/dashboard.json @@ -0,0 +1,8 @@ +{ + "grab_a_task": "Attrape une tâche!", + "create": "Créer", + "evaluate": "Évaluer", + "label": "Étiquette", + "dashboard": "Tableau de bord", + "go": "Aller" +} diff --git a/website/public/locales/fr/index.json b/website/public/locales/fr/index.json new file mode 100644 index 00000000..80f3e46a --- /dev/null +++ b/website/public/locales/fr/index.json @@ -0,0 +1,15 @@ +{ + "blurb": "Nous croyons que nous pouvons créer une révolution.", + "blurb1": "De la même manière que Stable Diffusion a aidé le monde à faire de l'art et des images de nouvelles manières, nous voulons améliorer le monde en fournissant une incroyable IA conversationnelle.", + "description": "IA conversationnelle pour tout le monde. Un projet open source pour créer un GPT LLM activé par chat dirigé par LAION et des contributeurs du monde entier.", + "faq_items": { + "q0": "À quel stade est ce projet?", + "a0": "Nous sommes aux premiers stades du développement, travaillant à partir de recherches établies dans l'application de RLHF à de grands modèles linguistiques.", + "q1": "Qui se trouve derrière Open Assistant?", + "a1": "Open Assistant est un projet organisé par LAION et des individus du monde entier intéressés à apporter cette technologie à tout le monde." + }, + "faq_title": "Questions fréquentes", + "join_us_description": "Tous les projets open source commencent avec des personnes comme vous. L'open source est la croyance que si nous collaborons, nous pouvons ensemble offrir notre connaissance et notre technologie au monde pour le bénéfice de l'humanité. Êtes-vous dedans? Trouvez-nous ici :", + "join_us_title": "Rejoignez-nous", + "subtitle": "IA conversationnelle pour tout le monde." +} diff --git a/website/public/locales/fr/labelling.json b/website/public/locales/fr/labelling.json new file mode 100644 index 00000000..387b5353 --- /dev/null +++ b/website/public/locales/fr/labelling.json @@ -0,0 +1,24 @@ +{ + "label_highlighted_yes_no_instruction": "Répondez à la question suivante (s) concernant le message surligné:", + "label_highlighted_flag_instruction": "Sélectionnez tout ce qui s'applique au message surligné:", + "label_highlighted_likert_instruction": "Notez le message surligné:", + "label_message_yes_no_instruction": "Répondez à la question suivante (s) concernant le message:", + "label_message_flag_instruction": "Sélectionnez tout ce qui s'applique au message:", + "label_message_likert_instruction": "Notez le message:", + "spam.question": "Est-ce que le message est un spam?", + "fails_task.question": "Est-ce une mauvaise réponse en réponse à la tâche?", + "not_appropriate": "Inapproprié", + "not_appropriate.explanation": "Inapproprié pour un assistant client.", + "pii": "Contient des RII", + "pii.explanation": "Contient des informations personnellement identifiables. Exemples : coordonnées personnelles, numéros de permis de conduire et d'identité et coordonnées bancaires.", + "hate_speech": "Discours de haine", + "hate_speech.explanation": "Le contenu est abusif ou menaçant et exprime un préjugé contre une caractéristique protégée. Le préjugé se réfère aux opinions préconçues non fondées sur la raison. Les caractéristiques protégées incluent le genre, l'ethnicité, la religion, l'orientation sexuelle et des caractéristiques similaires.", + "sexual_content": "Contenu sexuel", + "sexual_content.explanation": "Contient du contenu sexuel.", + "moral_judgement": "Juge la morale", + "moral_judgement.explanation": "Exprime un jugement moral.", + "political_content": "Politique", + "political_content.explanation": "Exprime des opinions politiques.", + "lang_mismatch": "Langue incorrecte", + "lang_mismatch.explanation": "N'est pas écrit dans la langue actuellement sélectionnée." +} diff --git a/website/public/locales/fr/leaderboard.json b/website/public/locales/fr/leaderboard.json new file mode 100644 index 00000000..9f2c443d --- /dev/null +++ b/website/public/locales/fr/leaderboard.json @@ -0,0 +1,18 @@ +{ + "daily": "Journalier", + "last_updated_at": "Dernière mise à jour à: {{val, datetime}}", + "leaderboard": "Classement", + "monthly": "Mensuel", + "overall": "Global", + "rank": "Rang", + "score": "Score", + "user": "Utilisateur", + "weekly": "Hebdomadaire", + "prompt": "Invitations", + "reply": "Réponses", + "label": "Étiquettes", + "view_all": "Voir tout", + "top_5_contributors_today": "Les 5 meilleurs contributeurs aujourd'hui", + "previous": "Précédent", + "next": "Suivant" +} diff --git a/website/public/locales/fr/message.json b/website/public/locales/fr/message.json new file mode 100644 index 00000000..1f31faa6 --- /dev/null +++ b/website/public/locales/fr/message.json @@ -0,0 +1,16 @@ +{ + "label_action": "Étiqueter", + "label_title": "Étiquette", + "message": "Message", + "open_new_tab_action": "Ouvrir dans un nouvel onglet", + "parent": "Parent", + "reactions": "Réactions", + "report_action": "Signaler", + "report_placeholder": "Pourquoi ce message devrait-il être examiné?", + "report_title": "Signaler", + "send_report": "Envoyer", + "submit_labels": "Soumettre", + "view_user": "Voir l'utilisateur", + "recent_messages": "Messages récents", + "your_recent_messages": "Vos messages récents" +} diff --git a/website/public/locales/fr/side_menu.json b/website/public/locales/fr/side_menu.json new file mode 100644 index 00000000..a3c5065b --- /dev/null +++ b/website/public/locales/fr/side_menu.json @@ -0,0 +1,12 @@ +{ + "dashboard": "Tableau de bord", + "dashboard_home": "Accueil du tableau de bord", + "messages": "Messages", + "messages_dashboard": "Tableau de bord des messages", + "leaderboard": "Classement", + "user_leaderboard": "Classement des utilisateurs", + "users": "Utilisateurs", + "users_dashboard": "Tableau de bord des utilisateurs", + "status": "Statut", + "status_dashboard": "Tableau de bord de statut" +} diff --git a/website/public/locales/fr/tasks.json b/website/public/locales/fr/tasks.json new file mode 100644 index 00000000..c5cf0064 --- /dev/null +++ b/website/public/locales/fr/tasks.json @@ -0,0 +1,82 @@ +{ + "default": { + "unchanged_title": "Aucun changement", + "unchanged_message": "Êtes-vous sûr de vouloir continuer?" + }, + "random": { + "label": "Je me sens chanceux", + "desc": "Aidez-nous à améliorer Open Assistant en démarrant une tâche aléatoire." + }, + "create_initial_prompt": { + "label": "Créer des prompts initiaux", + "desc": "Écrivez des prompts initiaux pour aider Open Assistant à essayer de répondre à des messages divers.", + "overview": "Créez un message initial à envoyer à l'assistant", + "instruction": "Fournir les prompts initiaux", + "response_placeholder": "Écrivez votre prompt ici..." + }, + "reply_as_user": { + "label": "Répondre en tant qu'utilisateur", + "desc": "Discutez avec Open Assistant et aidez-le à améliorer ses réponses en interagissant avec lui.", + "overview": "Compte tenu de la conversation suivante, fournir une réponse adéquate", + "instruction": "Fournir la réponse de l'utilisateur", + "response_placeholder": "Ecrivez votre réponse ici..." + }, + "reply_as_assistant": { + "label": "Répondre en tant qu'assistant", + "desc": "Aidez Open Assistant à améliorer ses réponses aux conversations avec d'autres utilisateurs.", + "overview": "Compte tenu de la conversation suivante, fournir une réponse adéquate", + "response_placeholder": "Ecrivez votre réponse ici..." + }, + "rank_user_replies": { + "label": "Classer les réponses d'utilisateur", + "desc": "Aidez Open Assistant à améliorer ses réponses aux conversations avec d'autres utilisateurs.", + "overview": "Compte tenu des réponses d'utilisateur suivantes, classez-les du meilleur au pire, le meilleur étant en premier, le pire en dernier.", + "unchanged_title": "Ordre inchangé", + "unchanged_message": "Vous n'avez pas modifié l'ordre des prompts. Etes-vous sûr de vouloir continuer?" + }, + "rank_assistant_replies": { + "label": "Classer les réponses de l'assistant", + "desc": "Scorez les prompts fournis par Open Assistant en fonction de leur exactitude et lisibilité.", + "overview": "Compte tenu des réponses d'assistant suivantes, classez-les du meilleur au pire, le meilleur étant en premier, le pire en dernier.", + "unchanged_title": "Ordre inchangé", + "unchanged_message": "Vous n'avez pas modifié l'ordre des prompts. Etes-vous sûr de vouloir continuer?" + }, + "rank_initial_prompts": { + "label": "Classer les invitations initiales", + "desc": "Classez les invitations données par Open Assistant en fonction de leur précision et lisibilité.", + "overview": "En fonction des invitations initiales suivantes, classez-les du meilleur au pire, le meilleur en premier et le pire en dernier.", + "unchanged_title": "Ordre inchangé", + "unchanged_message": "Vous n'avez pas modifié l'ordre des invitations. Êtes-vous sûr de vouloir continuer?" + }, + "label_initial_prompt": { + "label": "Etiqueter l'invitation initiale", + "desc": "Fournir des étiquettes pour une invitation.", + "overview": "Fournir des étiquettes pour l'invitation suivante" + }, + "label_prompter_reply": { + "label": "Etiqueter la réponse du demandeur", + "desc": "Fournir des étiquettes pour une invitation.", + "overview": "En fonction de la discussion suivante, fournir des étiquettes pour la dernière invitation." + }, + "label_assistant_reply": { + "label": "Etiqueter la réponse de l'assistant", + "desc": "Fournir des étiquettes pour une invitation.", + "overview": "En fonction de la discussion suivante, fournir des étiquettes pour la dernière invitation." + }, + "classify_initial_prompt": { + "label": "Classer l'invitation initiale", + "desc": "Fournir des étiquettes pour une invitation.", + "overview": "Lisez l'invitation suivante et répondez à la question à ce sujet." + }, + "classify_prompter_reply": { + "label": "Classer la réponse du demandeur", + "desc": "Fournir des étiquettes pour une invitation.", + "overview": "Lisez la conversation suivante et répondez à la question sur la dernière réponse de la discussion." + }, + "classify_assistant_reply": { + "label": "Classer la réponse de l'assistant", + "desc": "Fournir des étiquettes pour une invitation.", + "overview": "Lisez la conversation suivante et répondez à la question sur la dernière réponse de la discussion." + }, + "available_task_count": "{{count}} tâches disponibles" +} diff --git a/website/public/locales/fr/tos.json b/website/public/locales/fr/tos.json new file mode 100644 index 00000000..ee50480e --- /dev/null +++ b/website/public/locales/fr/tos.json @@ -0,0 +1,6 @@ +{ + "title": "Conditions d'utilisation d'Open Assistant", + "content": "Pour continuer à utiliser Open Assistant, vous devez d'abord accepter nos conditions d'utilisation.", + "accept": "Accepter", + "decline": "Refuser" +} From 2de9bccfba97779ebcdb97e075cad2754396720f Mon Sep 17 00:00:00 2001 From: Anthony Chiu Date: Sun, 5 Feb 2023 04:53:02 +0800 Subject: [PATCH 056/152] Add modal padding bottom and tooltip (#1116) --- website/src/components/CollapsableText.tsx | 39 ++++++++++++++-------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/website/src/components/CollapsableText.tsx b/website/src/components/CollapsableText.tsx index 9be43c4b..1629b4bb 100644 --- a/website/src/components/CollapsableText.tsx +++ b/website/src/components/CollapsableText.tsx @@ -1,5 +1,6 @@ import { Button, + Tooltip, Modal, ModalBody, ModalCloseButton, @@ -23,6 +24,7 @@ export const CollapsableText = ({ isDisabled?: boolean; }) => { const { isOpen, onOpen, onClose } = useDisclosure(); + const finalRef = React.useRef(null); const moreButtonColor = useColorModeValue("gray.600", "gray.400"); @@ -31,24 +33,33 @@ export const CollapsableText = ({ } else { return ( <> - + {text.substring(0, maxLength - 3)}  - + + + - + {/* we kill the event here to disable drag and drop, since it is in the same container */} - + Full Text {text} From 63b2102d395c23abb3f4c51c2c4303861725a477 Mon Sep 17 00:00:00 2001 From: Richard Nagyfi Date: Sat, 4 Feb 2023 22:34:11 +0100 Subject: [PATCH 057/152] The fails_task.question was ambigous (#1128) - the translation for fails_task.question was confusing as the question would require a different answer than yes or no (the buttons available on the dashboard) --- website/public/locales/hu/labelling.json | 2 +- website/public/locales/hu/tasks.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/website/public/locales/hu/labelling.json b/website/public/locales/hu/labelling.json index 9fca2cae..b7c05fbb 100644 --- a/website/public/locales/hu/labelling.json +++ b/website/public/locales/hu/labelling.json @@ -6,7 +6,7 @@ "label_message_flag_instruction": "Jelöld be, melyek vonatkoznak erre az üzenetre:", "label_message_likert_instruction": "Értékeld ezt az üzenetet:", "spam.question": "Ez az üzenet SPAM?", - "fails_task.question": "Ez a válasz nem a feladatnak megfelelő?", + "fails_task.question": "Baj van ezzel az üzenettel, amiért nem a kérdésre válaszol?", "not_appropriate": "Nem Helyénvaló", "not_appropriate.explanation": "Nem ügyfél-asszisztenshez méltó válasz.", "pii": "Személyes Adat", diff --git a/website/public/locales/hu/tasks.json b/website/public/locales/hu/tasks.json index 43fedeef..da9cf254 100644 --- a/website/public/locales/hu/tasks.json +++ b/website/public/locales/hu/tasks.json @@ -17,14 +17,14 @@ "reply_as_user": { "label": "Válaszolj a Felhasználó Helyett", "desc": "Csinálj úgy, mintha chatelnél az Asszisztenssel, hogy fejlődhessen.", - "overview": "Írj egy ideillő választ az eddigi beszélgetésre", + "overview": "Írj egy ideillő üzenetet az eddigi beszélgetésre, mint Felhasználó", "instruction": "Találj ki Felhasználói Válaszokat", "response_placeholder": "Ide írd a választ..." }, "reply_as_assistant": { "label": "Válaszolj az Asszisztens Helyett", "desc": "Mjutasd meg az Asszisztensnek, hogy milyen válaszokat küldjön a felhasználói kérdésekre.", - "overview": "Írj egy ideillő választ az eddigi beszélgetésre", + "overview": "Írj egy ideillő választ az eddigi beszélgetésre, mintha te lennél az Asszisztens", "response_placeholder": "Ide írd a választ..." }, "rank_user_replies": { From d1b0fab3e171c2ebc47717ffe3d39901d1b20576 Mon Sep 17 00:00:00 2001 From: Klotske <30481105+Klotske@users.noreply.github.com> Date: Sun, 5 Feb 2023 00:34:34 +0300 Subject: [PATCH 058/152] website: Add RU locale (#1125) --- website/public/locales/ru/common.json | 25 ++++++++++++++++++++++ website/public/locales/ru/dashboard.json | 8 +++++++ website/public/locales/ru/labelling.json | 24 +++++++++++++++++++++ website/public/locales/ru/leaderboard.json | 18 ++++++++++++++++ website/public/locales/ru/message.json | 16 ++++++++++++++ website/public/locales/ru/side_menu.json | 12 +++++++++++ website/public/locales/ru/tos.json | 6 ++++++ 7 files changed, 109 insertions(+) create mode 100644 website/public/locales/ru/common.json create mode 100644 website/public/locales/ru/dashboard.json create mode 100644 website/public/locales/ru/labelling.json create mode 100644 website/public/locales/ru/leaderboard.json create mode 100644 website/public/locales/ru/message.json create mode 100644 website/public/locales/ru/side_menu.json create mode 100644 website/public/locales/ru/tos.json diff --git a/website/public/locales/ru/common.json b/website/public/locales/ru/common.json new file mode 100644 index 00000000..5b33294d --- /dev/null +++ b/website/public/locales/ru/common.json @@ -0,0 +1,25 @@ +{ + "about": "About", + "account_settings": "Аккаунт", + "admin_dashboard": "Панель администратора", + "connect": "Connect", + "conversational": "Conversational AI for everyone.", + "dashboard": "Главная", + "delete": "Удалить", + "discord": "Discord", + "docs": "Документация", + "github": "GitHub", + "legal": "Legal", + "loading": "Загрузка...", + "more_information": "Больше...", + "no": "Нет", + "privacy_policy": "Политика конфиденциальности", + "report_a_bug": "Сообщить об ошибке", + "sign_in": "Вход", + "sign_out": "Выйти из аккаунта", + "terms_of_service": "Пользовательское Соглашение", + "title": "Open Assistant", + "yes": "Да", + "dark_mode": "Темная тема", + "light_mode": "Светлая тема" +} diff --git a/website/public/locales/ru/dashboard.json b/website/public/locales/ru/dashboard.json new file mode 100644 index 00000000..09a53b10 --- /dev/null +++ b/website/public/locales/ru/dashboard.json @@ -0,0 +1,8 @@ +{ + "grab_a_task": "Взять задание!", + "create": "Создать", + "evaluate": "Ранжировать", + "label": "Классифицировать", + "dashboard": "Главная", + "go": "Начать" +} diff --git a/website/public/locales/ru/labelling.json b/website/public/locales/ru/labelling.json new file mode 100644 index 00000000..c43cb989 --- /dev/null +++ b/website/public/locales/ru/labelling.json @@ -0,0 +1,24 @@ +{ + "label_highlighted_yes_no_instruction": "Ответьте на следующий вопрос (вопросы) о выделенном сообщении:", + "label_highlighted_flag_instruction": "Выберите все, что относится к выделенному сообщению:", + "label_highlighted_likert_instruction": "Оцените выделенное сообщение:", + "label_message_yes_no_instruction": "Ответьте на следующий вопрос (вопросы) о сообщении:", + "label_message_flag_instruction": "Выберите все, что относится к сообщению:", + "label_message_likert_instruction": "Оцените сообщение:", + "spam.question": "Является ли сообщение спамом?", + "fails_task.question": "Плохой ли это ответ, по отношению к поставленной задачу?", + "not_appropriate": "Неуместный ответ", + "not_appropriate.explanation": "Не подходит для помощника.", + "pii": "Содержит персональные данные", + "pii.explanation": "Содержит личную идентифицирующую информацию. Примеры включают личные контактные данные, номер паспорта и/или других удостоверений личности, или же банковские реквизиты.", + "hate_speech": "Разжигание ненависти", + "hate_speech.explanation": "Содержание является оскорбительным или угрожающим и выражает предубеждение против некоторых характеристик. Предрассудки - это предвзятые мнения, не основанные на разуме. К характеристикам относятся пол, этническая принадлежность, религия, сексуальная ориентация и подобные.", + "sexual_content": "Контент сексуального характера", + "sexual_content.explanation": "Содержит материалы сексуального характера.", + "moral_judgement": "Оценивает мораль", + "moral_judgement.explanation": "Выражает моральную оценку.", + "political_content": "Политика", + "political_content.explanation": "Выражает политические взгляды.", + "lang_mismatch": "Неправильный язык", + "lang_mismatch.explanation": "Не написано на текущем выбранном языке." +} diff --git a/website/public/locales/ru/leaderboard.json b/website/public/locales/ru/leaderboard.json new file mode 100644 index 00000000..3023c557 --- /dev/null +++ b/website/public/locales/ru/leaderboard.json @@ -0,0 +1,18 @@ +{ + "daily": "За день", + "last_updated_at": "Последний раз обновлено: {{val, datetime}}", + "leaderboard": "Таблица лидеров", + "monthly": "За месяц", + "overall": "Всего", + "rank": "Позиция", + "score": "Счет", + "user": "Пользователь", + "weekly": "За неделю", + "prompt": "Prompts", + "reply": "Replies", + "label": "Labels", + "view_all": "Посмотреть все", + "top_5_contributors_today": "Топ 5 Пользователей за Сегодня", + "previous": "Назад", + "next": "Вперед" +} diff --git a/website/public/locales/ru/message.json b/website/public/locales/ru/message.json new file mode 100644 index 00000000..e0ba592b --- /dev/null +++ b/website/public/locales/ru/message.json @@ -0,0 +1,16 @@ +{ + "label_action": "Классифицировать", + "label_title": "Классифицировать", + "message": "Сообщение", + "open_new_tab_action": "Открыть в новой вкладке", + "parent": "Родитель", + "reactions": "Реакции", + "report_action": "Пожаловаться", + "report_placeholder": "Почему это сообщение должно быть рассмотрено?", + "report_title": "Пожаловаться", + "send_report": "Отправить", + "submit_labels": "Отправить", + "view_user": "О пользователе", + "recent_messages": "Последние Сообщения", + "your_recent_messages": "Ваши Последние сообщения" +} diff --git a/website/public/locales/ru/side_menu.json b/website/public/locales/ru/side_menu.json new file mode 100644 index 00000000..36596ed2 --- /dev/null +++ b/website/public/locales/ru/side_menu.json @@ -0,0 +1,12 @@ +{ + "dashboard": "Главная", + "dashboard_home": "Главная страница", + "messages": "Сообщения", + "messages_dashboard": "Панель просмотра сообщений", + "leaderboard": "Рейтинг", + "user_leaderboard": "Таблица лидеров", + "users": "Пользователи", + "users_dashboard": "Панель управления пользователями", + "status": "Статус", + "status_dashboard": "Панель состояния системы" +} diff --git a/website/public/locales/ru/tos.json b/website/public/locales/ru/tos.json new file mode 100644 index 00000000..a97cf7a0 --- /dev/null +++ b/website/public/locales/ru/tos.json @@ -0,0 +1,6 @@ +{ + "title": "Пользовательское Соглашение Open Assistant", + "content": "Чтобы продолжить работу с Open Assistant, вам необходимо принять наше Пользовательское Соглашение.", + "accept": "Принять", + "decline": "Отклонить" +} From 280979c7b044069a8d2338798543f87633ad851f Mon Sep 17 00:00:00 2001 From: Yannic Kilcher Date: Sat, 4 Feb 2023 22:37:48 +0100 Subject: [PATCH 059/152] added mainenance mode (#1130) --- website/next.config.js | 27 +++++++++++++++++++++++++++ website/src/pages/brb.tsx | 29 +++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 website/src/pages/brb.tsx diff --git a/website/next.config.js b/website/next.config.js index 19ec09b2..705c3b5d 100644 --- a/website/next.config.js +++ b/website/next.config.js @@ -22,6 +22,33 @@ const nextConfig = { eslint: { ignoreDuringBuilds: true, }, + async redirects() { + if (process.env.MAINTENANCE_MODE !== "true") { + return []; + } + return [ + { + source: "/", + destination: "/brb", + permanent: false, + }, + { + source: "/dashboard", + destination: "/brb", + permanent: false, + }, + { + source: `/tasks/:task`, + destination: "/brb", + permanent: false, + }, + { + source: "/leaderboard", + destination: "/brb", + permanent: false, + }, + ]; + }, }; const withBundleAnalyzer = require("@next/bundle-analyzer")({ diff --git a/website/src/pages/brb.tsx b/website/src/pages/brb.tsx new file mode 100644 index 00000000..a62bdcb4 --- /dev/null +++ b/website/src/pages/brb.tsx @@ -0,0 +1,29 @@ +import Image from "next/image"; +import { CallToAction } from "src/components/CallToAction"; +import { Container } from "src/components/Container"; +import Roadmap from "src/components/Roadmap"; +import Services from "src/components/Services"; +import Vision from "src/components/Vision"; +export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props"; + +const BrbPage = () => { + return ( +
+ +
+
+ temp-image +
+
+
+

Down for maintenance

+
+

{"We are improving the service, we'll be back in very few minutes."}

+
+
+
+
+ ); +}; + +export default BrbPage; From 100ecbe2d53c35c00279b2d1d9aa31754ec265e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=B6pf?= Date: Sat, 4 Feb 2023 23:23:16 +0100 Subject: [PATCH 060/152] Limit initial prompts, ensure max_active_trees = growing trees --- .github/workflows/deploy-to-node.yaml | 1 + ansible/deploy-to-node.yaml | 3 + backend/oasst_backend/config.py | 3 + backend/oasst_backend/tree_manager.py | 88 ++++++++++++++++++++++----- website/public/locales/en/tasks.json | 2 +- 5 files changed, 82 insertions(+), 15 deletions(-) diff --git a/.github/workflows/deploy-to-node.yaml b/.github/workflows/deploy-to-node.yaml index 436e7f58..d710eca6 100644 --- a/.github/workflows/deploy-to-node.yaml +++ b/.github/workflows/deploy-to-node.yaml @@ -38,6 +38,7 @@ jobs: AWS_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }} AWS_SECRET_KEY: ${{ secrets.AWS_SECRET_KEY }} MAX_ACTIVE_TREES: ${{ vars.MAX_ACTIVE_TREES }} + MAX_INITIAL_PROMPT_REVIEW: ${{ vars.MAX_INITIAL_PROMPT_REVIEW }} MAX_TREE_DEPTH: ${{ vars.MAX_TREE_DEPTH }} MAX_CHILDREN_COUNT: ${{ vars.MAX_CHILDREN_COUNT }} LONELY_CHILDREN_COUNT: ${{ vars.LONELY_CHILDREN_COUNT }} diff --git a/ansible/deploy-to-node.yaml b/ansible/deploy-to-node.yaml index 639003a4..958e5172 100644 --- a/ansible/deploy-to-node.yaml +++ b/ansible/deploy-to-node.yaml @@ -113,6 +113,9 @@ TREE_MANAGER__MAX_ACTIVE_TREES: "{{ lookup('ansible.builtin.env', 'MAX_ACTIVE_TREES') | default('10', true) }}" + TREE_MANAGER__MAX_INITIAL_PROMPT_REVIEW: + "{{ lookup('ansible.builtin.env', 'MAX_INITIAL_PROMPT_REVIEW') | + default('100', true) }}" TREE_MANAGER__MAX_TREE_DEPTH: "{{ lookup('ansible.builtin.env', 'MAX_TREE_DEPTH') | default('5', true) }}" diff --git a/backend/oasst_backend/config.py b/backend/oasst_backend/config.py index ff4c5497..4d6dea30 100644 --- a/backend/oasst_backend/config.py +++ b/backend/oasst_backend/config.py @@ -13,6 +13,9 @@ class TreeManagerConfiguration(BaseModel): No new initial prompt tasks are handed out to users if this number is reached.""" + max_initial_prompt_review: int = 100 + """Maximum number of initial prompts under review before no more inital prompt tasks will be handed out.""" + max_tree_depth: int = 3 """Maximum depth of message tree.""" diff --git a/backend/oasst_backend/tree_manager.py b/backend/oasst_backend/tree_manager.py index 6b4f5236..a6c803be 100644 --- a/backend/oasst_backend/tree_manager.py +++ b/backend/oasst_backend/tree_manager.py @@ -51,6 +51,19 @@ class TaskRole(Enum): ASSISTANT = 2 +class TreeStateStats(pydantic.BaseModel): + initial_prompt_review: int + growing: int + ranking: int + ready_for_scoring: int + scoring_failed: int + ready_for_export: int + aborted_low_grade: int + halted_by_moderator: int + backlog_ranking: int + prompt_lottery_waiting: int + + class ActiveTreeSizeRow(pydantic.BaseModel): message_tree_id: UUID goal_tree_size: int @@ -173,7 +186,7 @@ class TreeManager: ) -> dict[protocol_schema.TaskRequestType, int]: task_count_by_type: dict[protocol_schema.TaskRequestType, int] = {t: 0 for t in protocol_schema.TaskRequestType} - task_count_by_type[protocol_schema.TaskRequestType.initial_prompt] = max(1, num_missing_prompts) + task_count_by_type[protocol_schema.TaskRequestType.initial_prompt] = num_missing_prompts task_count_by_type[protocol_schema.TaskRequestType.prompter_reply] = len( list(filter(lambda x: x.parent_role == "assistant", extendible_parents)) @@ -209,10 +222,15 @@ class TreeManager: MAX_RETRIES = 5 retry = 0 while True: - num_active_trees = self.query_num_active_trees(lang=lang, exclude_ranking=True) - num_missing_prompts = self.cfg.max_active_trees - num_active_trees - if num_missing_prompts <= 0: - return 0 + + stats = self.tree_counts_by_state_stats(lang=lang, only_active=True) + + remaining_prompt_review = max(0, self.cfg.max_initial_prompt_review - stats.initial_prompt_review) + num_missing_growing = max(0, self.cfg.max_active_trees - stats.growing) + logger.debug(f"_prompt_lottery {remaining_prompt_review=}, {num_missing_growing=}") + + if num_missing_growing == 0: + return remaining_prompt_review # select among distinct users authors_qry = ( @@ -231,9 +249,9 @@ class TreeManager: author_ids = authors_qry.all() if len(author_ids) == 0: logger.info( - f"No prompts for prompt lottery available ({num_missing_prompts} trees missing for {lang=})." + f"No prompts for prompt lottery available ({num_missing_growing=}, trees missing for {lang=})." ) - return num_missing_prompts + return num_missing_growing + remaining_prompt_review # first select an authour prompt_author_id: UUID = random.choice(author_ids)["user_id"] @@ -261,7 +279,7 @@ class TreeManager: continue else: logger.warning("Max retries in prompt lottery reached.") - return num_missing_prompts + return num_missing_growing + remaining_prompt_review winner_prompt = random.choice(prompt_candidates) message: Message = winner_prompt.Message @@ -1268,8 +1286,23 @@ LEFT JOIN message_reaction mr ON mr.task_id = t.id AND mr.payload_type = 'Rankin for t in ranking_trees: self.check_condition_for_scoring_state(t.message_tree_id) - def query_num_active_trees(self, lang: str, exclude_ranking: bool = True) -> int: - """Count all active trees (optionally exclude those in ranking state).""" + def query_num_growing_trees(self, lang: str) -> int: + """Count all active trees in growing state.""" + query = ( + self.db.query(func.count(MessageTreeState.message_tree_id)) + .join(Message, MessageTreeState.message_tree_id == Message.id) + .filter( + MessageTreeState.active, + MessageTreeState.state == message_tree_state.State.GROWING, + Message.lang == lang, + ) + ) + return query.scalar() + + def query_num_active_trees( + self, lang: str, exclude_ranking: bool = True, exclude_prompt_review: bool = True + ) -> int: + """Count all active trees (optionally exclude those in ranking and initial prompt review states).""" query = ( self.db.query(func.count(MessageTreeState.message_tree_id)) .join(Message, MessageTreeState.message_tree_id == Message.id) @@ -1277,6 +1310,8 @@ LEFT JOIN message_reaction mr ON mr.task_id = t.id AND mr.payload_type = 'Rankin ) if exclude_ranking: query = query.filter(MessageTreeState.state != message_tree_state.State.RANKING) + if exclude_prompt_review: + query = query.filter(MessageTreeState.state != message_tree_state.State.INITIAL_PROMPT_REVIEW) return query.scalar() def query_reviews_for_message(self, message_id: UUID) -> list[TextLabels]: @@ -1363,12 +1398,37 @@ LEFT JOIN message_reaction mr ON mr.task_id = t.id AND mr.payload_type = 'Rankin active=True, ) - def tree_counts_by_state(self) -> dict[str, int]: - qry = self.db.query( - MessageTreeState.state, func.count(MessageTreeState.message_tree_id).label("count") - ).group_by(MessageTreeState.state) + def tree_counts_by_state(self, lang: str = None, only_active: bool = False) -> dict[str, int]: + qry = self.db.query(MessageTreeState.state, func.count(MessageTreeState.message_tree_id).label("count")) + + if lang is not None: + qry = ( + qry.select_from(MessageTreeState) + .join(Message, MessageTreeState.message_tree_id == Message.id) + .filter(Message.lang == lang) + ) + if only_active: + qry = qry.filter(MessageTreeState.active) + + qry = qry.group_by(MessageTreeState.state) return {x["state"]: x["count"] for x in qry} + def tree_counts_by_state_stats(self, lang: str = None, only_active: bool = False) -> TreeStateStats: + count_by_state = self.tree_counts_by_state(lang=lang, only_active=only_active) + r = TreeStateStats( + initial_prompt_review=count_by_state.get(message_tree_state.State.INITIAL_PROMPT_REVIEW) or 0, + growing=count_by_state.get(message_tree_state.State.GROWING) or 0, + ranking=count_by_state.get(message_tree_state.State.RANKING) or 0, + ready_for_scoring=count_by_state.get(message_tree_state.State.READY_FOR_SCORING) or 0, + ready_for_export=count_by_state.get(message_tree_state.State.READY_FOR_EXPORT) or 0, + scoring_failed=count_by_state.get(message_tree_state.State.SCORING_FAILED) or 0, + halted_by_moderator=count_by_state.get(message_tree_state.State.HALTED_BY_MODERATOR) or 0, + backlog_ranking=count_by_state.get(message_tree_state.State.BACKLOG_RANKING) or 0, + prompt_lottery_waiting=count_by_state.get(message_tree_state.State.PROMPT_LOTTERY_WAITING) or 0, + aborted_low_grade=count_by_state.get(message_tree_state.State.ABORTED_LOW_GRADE) or 0, + ) + return r + def tree_message_count_stats(self, only_active: bool = True) -> list[TreeMessageCountStats]: qry = ( self.db.query( diff --git a/website/public/locales/en/tasks.json b/website/public/locales/en/tasks.json index 7fa7c452..ee3da48c 100644 --- a/website/public/locales/en/tasks.json +++ b/website/public/locales/en/tasks.json @@ -9,7 +9,7 @@ }, "create_initial_prompt": { "label": "Create Initial Prompts", - "desc": "Write initial prompts to help Open Assistant to try replying to diverse messages.", + "desc": "Write initial prompts to help Open Assistant to try replying to diverse messages. (enter into lottery)", "overview": "Create an initial message to send to the assistant", "instruction": "Provide the initial prompts", "response_placeholder": "Write your prompt here..." From c90c55c731b1c3d15298802fd0279afca4a12126 Mon Sep 17 00:00:00 2001 From: Niklas Muennighoff Date: Sun, 5 Feb 2023 02:43:24 +0400 Subject: [PATCH 061/152] add link (#1109) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3c708323..73e99dc6 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ interact with the website. ## The Plan -##### We want to get to an initial MVP as fast as possible, by following the 3-steps outlined in the InstructGPT paper. +##### We want to get to an initial MVP as fast as possible, by following the 3-steps outlined in the [InstructGPT paper](https://arxiv.org/abs/2203.02155). 1. Collect high-quality human generated Instruction-Fulfillment samples (prompt + response), goal >50k. We design a crowdsourced process to collect From 59e325219011eacb9d598b7f5d73d12d9157772f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=B6pf?= Date: Sun, 5 Feb 2023 00:18:05 +0100 Subject: [PATCH 062/152] limit number of trees activated during _prompt_lottery() calls --- backend/oasst_backend/tree_manager.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/backend/oasst_backend/tree_manager.py b/backend/oasst_backend/tree_manager.py index a6c803be..cdf61d3f 100644 --- a/backend/oasst_backend/tree_manager.py +++ b/backend/oasst_backend/tree_manager.py @@ -220,7 +220,17 @@ class TreeManager: def _prompt_lottery(self, lang: str) -> int: MAX_RETRIES = 5 + + # Under high load the DB runs into deadlocks when many trees are released + # simultaneously (happens whens the max_active_trees setting is increased). + # To reduce the chance of write conflicts during updates of rows in the + # message_tree_state table we limit the number of trees that are activated + # per _prompt_lottery() call to MAX_ACTIVATE. + MAX_ACTIVATE = 2 + retry = 0 + activated = 0 + while True: stats = self.tree_counts_by_state_stats(lang=lang, only_active=True) @@ -229,8 +239,8 @@ class TreeManager: num_missing_growing = max(0, self.cfg.max_active_trees - stats.growing) logger.debug(f"_prompt_lottery {remaining_prompt_review=}, {num_missing_growing=}") - if num_missing_growing == 0: - return remaining_prompt_review + if num_missing_growing == 0 or activated >= MAX_ACTIVATE: + return num_missing_growing + remaining_prompt_review # select among distinct users authors_qry = ( @@ -288,6 +298,7 @@ class TreeManager: mts: MessageTreeState = winner_prompt.MessageTreeState self._enter_state(mts, message_tree_state.State.GROWING) self.db.flush() + activated += 1 def _auto_moderation(self, lang: str) -> None: if not self.cfg.auto_mod_enabled: From 926adcd710918314783fb84a55612ac40a51cf34 Mon Sep 17 00:00:00 2001 From: Saurav Maheshkar Date: Sat, 4 Feb 2023 23:50:51 +0000 Subject: [PATCH 063/152] feat(ci): enable pip caching in CI (#1129) --- .github/workflows/pre-commit.yaml | 2 ++ .github/workflows/test-api-contract.yaml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml index 3f587f28..0a13c666 100644 --- a/.github/workflows/pre-commit.yaml +++ b/.github/workflows/pre-commit.yaml @@ -21,6 +21,8 @@ jobs: - uses: actions/setup-python@v4 with: python-version: "3.10" + cache: "pip" + cache-dependency-path: "**/requirements*.txt" - uses: pre-commit/action@v3.0.0 - name: Post PR comment on failure if: failure() && github.event_name == 'pull_request_target' diff --git a/.github/workflows/test-api-contract.yaml b/.github/workflows/test-api-contract.yaml index bee2f357..a2f3b68b 100644 --- a/.github/workflows/test-api-contract.yaml +++ b/.github/workflows/test-api-contract.yaml @@ -23,6 +23,8 @@ jobs: - uses: actions/setup-python@v4 with: python-version: "3.10" + cache: "pip" + cache-dependency-path: "**/requirements*.txt" - uses: actions/setup-node@v3 with: node-version: 16 From ae8b9ea09e02590a32aaf61afe439b65bac4847b Mon Sep 17 00:00:00 2001 From: Oliver Stanley Date: Sat, 4 Feb 2023 23:51:26 +0000 Subject: [PATCH 064/152] Update README with quick howto for data collection (#1104) * Update README with quick howto for data collection --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 73e99dc6..7dccafec 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,15 @@ improving language itself. ## Do you want to try it out? +### Contributing to Data Collection + +The data collection frontend is now live [here](https://open-assistant.io/). Log +in and start taking on tasks! We want to collect a high volume of quality data. +By submitting, ranking, and labelling model prompts and responses you will be +directly helping to improve the capabilities of Open Assistant. + +### Running Locally + If you are interested in taking a look at the current state of the project, you can set up an entire stack needed to run **Open-Assistant**, including the website, backend, and associated dependent services. From 263edbaefdc4cc3b7f6978684747a5849437af4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=B6pf?= Date: Sun, 5 Feb 2023 01:16:34 +0100 Subject: [PATCH 065/152] move prompt lottery tree activation into separate transaction scope --- backend/oasst_backend/config.py | 2 +- backend/oasst_backend/tree_manager.py | 135 ++++++++++++++------------ 2 files changed, 73 insertions(+), 64 deletions(-) diff --git a/backend/oasst_backend/config.py b/backend/oasst_backend/config.py index 4d6dea30..6ff727de 100644 --- a/backend/oasst_backend/config.py +++ b/backend/oasst_backend/config.py @@ -47,7 +47,7 @@ class TreeManagerConfiguration(BaseModel): """Automatically set tree state to `halted_by_moderator` when more than the specified number of users skip replying to a message. (auto moderation)""" - auto_mod_red_flags: int = 3 + auto_mod_red_flags: int = 4 """Delete messages that receive more than this number of red flags if it is a reply or set the tree to `aborted_low_grade` when a prompt is flagged. (auto moderation)""" diff --git a/backend/oasst_backend/tree_manager.py b/backend/oasst_backend/tree_manager.py index cdf61d3f..940e08ea 100644 --- a/backend/oasst_backend/tree_manager.py +++ b/backend/oasst_backend/tree_manager.py @@ -26,7 +26,12 @@ from oasst_backend.models import ( ) from oasst_backend.prompt_repository import PromptRepository from oasst_backend.utils import tree_export -from oasst_backend.utils.database_utils import CommitMode, async_managed_tx_method, managed_tx_method +from oasst_backend.utils.database_utils import ( + CommitMode, + async_managed_tx_method, + managed_tx_function, + managed_tx_method, +) from oasst_backend.utils.hugging_face import HfClassificationModel, HfEmbeddingModel, HfUrl, HuggingFaceAPI from oasst_backend.utils.ranking import ranked_pairs from oasst_shared.exceptions.oasst_api_error import OasstError, OasstErrorCode @@ -218,17 +223,12 @@ class TreeManager: return task_count_by_type - def _prompt_lottery(self, lang: str) -> int: - MAX_RETRIES = 5 - + def _prompt_lottery(self, lang: str, max_activate: int = 1) -> int: # Under high load the DB runs into deadlocks when many trees are released # simultaneously (happens whens the max_active_trees setting is increased). # To reduce the chance of write conflicts during updates of rows in the # message_tree_state table we limit the number of trees that are activated - # per _prompt_lottery() call to MAX_ACTIVATE. - MAX_ACTIVATE = 2 - - retry = 0 + # per _prompt_lottery() call to max_activate. activated = 0 while True: @@ -237,67 +237,76 @@ class TreeManager: remaining_prompt_review = max(0, self.cfg.max_initial_prompt_review - stats.initial_prompt_review) num_missing_growing = max(0, self.cfg.max_active_trees - stats.growing) - logger.debug(f"_prompt_lottery {remaining_prompt_review=}, {num_missing_growing=}") + logger.info(f"_prompt_lottery {remaining_prompt_review=}, {num_missing_growing=}") - if num_missing_growing == 0 or activated >= MAX_ACTIVATE: + if num_missing_growing == 0 or activated >= max_activate: return num_missing_growing + remaining_prompt_review - # select among distinct users - authors_qry = ( - self.db.query(Message.user_id) - .select_from(MessageTreeState) - .join(Message, MessageTreeState.message_tree_id == Message.id) - .filter( - MessageTreeState.state == message_tree_state.State.PROMPT_LOTTERY_WAITING, - Message.lang == lang, - not_(Message.deleted), - Message.review_result, + @managed_tx_function(CommitMode.COMMIT) + def activate_one(db: Session) -> int: + # select among distinct users + authors_qry = ( + db.query(Message.user_id) + .select_from(MessageTreeState) + .join(Message, MessageTreeState.message_tree_id == Message.id) + .filter( + MessageTreeState.state == message_tree_state.State.PROMPT_LOTTERY_WAITING, + Message.lang == lang, + not_(Message.deleted), + Message.review_result, + ) + .distinct(Message.user_id) ) - .distinct(Message.user_id) - ) - author_ids = authors_qry.all() - if len(author_ids) == 0: - logger.info( - f"No prompts for prompt lottery available ({num_missing_growing=}, trees missing for {lang=})." + author_ids = authors_qry.all() + if len(author_ids) == 0: + logger.info( + f"No prompts for prompt lottery available ({num_missing_growing=}, trees missing for {lang=})." + ) + return False + + # first select an authour + prompt_author_id: UUID = random.choice(author_ids)["user_id"] + logger.info(f"Selected random prompt author {prompt_author_id} among {len(author_ids)} candidates.") + + # select random prompt of author + qry = ( + db.query(MessageTreeState, Message) + .select_from(MessageTreeState) + .join(Message, MessageTreeState.message_tree_id == Message.id) + .filter( + MessageTreeState.state == message_tree_state.State.PROMPT_LOTTERY_WAITING, + Message.user_id == prompt_author_id, + Message.lang == lang, + not_(Message.deleted), + Message.review_result, + ) + .limit(100) ) + + prompt_candidates = qry.all() + if len(prompt_candidates) == 0: + logger.warning("No prompt candidates of selected author found.") + return False + + winner_prompt = random.choice(prompt_candidates) + message: Message = winner_prompt.Message + logger.info(f"Prompt lottery winner: {message.id=}") + + mts: MessageTreeState = winner_prompt.MessageTreeState + mts.state = message_tree_state.State.GROWING + mts.active = True + db.add(mts) + + if mts.won_prompt_lottery_date is None: + mts.won_prompt_lottery_date = utcnow() + logger.info(f"Tree entered '{mts.state}' state ({mts.message_tree_id=})") + + return True + + if not activate_one(): return num_missing_growing + remaining_prompt_review - # first select an authour - prompt_author_id: UUID = random.choice(author_ids)["user_id"] - logger.info(f"Selected random prompt author {prompt_author_id} among {len(author_ids)} candidates.") - - # select random prompt of author - qry = ( - self.db.query(MessageTreeState, Message) - .select_from(MessageTreeState) - .join(Message, MessageTreeState.message_tree_id == Message.id) - .filter( - MessageTreeState.state == message_tree_state.State.PROMPT_LOTTERY_WAITING, - Message.user_id == prompt_author_id, - Message.lang == lang, - not_(Message.deleted), - Message.review_result, - ) - .limit(100) - ) - - prompt_candidates = qry.all() - if len(prompt_candidates) == 0: - retry += 1 # not sure if this can happen with repeatable read isolation level, just in case we retry - if retry < MAX_RETRIES: - continue - else: - logger.warning("Max retries in prompt lottery reached.") - return num_missing_growing + remaining_prompt_review - - winner_prompt = random.choice(prompt_candidates) - message: Message = winner_prompt.Message - logger.info(f"Prompt lottery winner: {message.id=}") - - mts: MessageTreeState = winner_prompt.MessageTreeState - self._enter_state(mts, message_tree_state.State.GROWING) - self.db.flush() activated += 1 def _auto_moderation(self, lang: str) -> None: @@ -333,7 +342,7 @@ class TreeManager: logger.warning("Task availability request without lang tag received, assuming lang='en'.") self._auto_moderation(lang=lang) - num_missing_prompts = self._prompt_lottery(lang=lang) + num_missing_prompts = self._prompt_lottery(lang=lang, max_activate=1) extendible_parents, _ = self.query_extendible_parents(lang=lang) prompts_need_review = self.query_prompts_need_review(lang=lang) replies_need_review = self.query_replies_need_review(lang=lang) @@ -371,7 +380,7 @@ class TreeManager: logger.warning("Task request without lang tag received, assuming 'en'.") self._auto_moderation(lang=lang) - num_missing_prompts = self._prompt_lottery(lang=lang) + num_missing_prompts = self._prompt_lottery(lang=lang, max_activate=2) prompts_need_review = self.query_prompts_need_review(lang=lang) replies_need_review = self.query_replies_need_review(lang=lang) From 26f3fd4453b5156d1f87d7ce9fd8a1c26f8cf748 Mon Sep 17 00:00:00 2001 From: Yannic Kilcher Date: Sun, 5 Feb 2023 01:34:34 +0100 Subject: [PATCH 066/152] added maintenance mode variable --- .github/workflows/deploy-to-node.yaml | 1 + ansible/deploy-to-node.yaml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.github/workflows/deploy-to-node.yaml b/.github/workflows/deploy-to-node.yaml index d710eca6..ce77de2f 100644 --- a/.github/workflows/deploy-to-node.yaml +++ b/.github/workflows/deploy-to-node.yaml @@ -61,6 +61,7 @@ jobs: WEB_NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN: ${{ vars.WEB_NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN }} LOGURU_LEVEL: ${{ vars.LOGURU_LEVEL }} + MAINTENANCE_MODE: ${{ vars.MAINTENANCE_MODE }} steps: - name: Checkout uses: actions/checkout@v2 diff --git a/ansible/deploy-to-node.yaml b/ansible/deploy-to-node.yaml index 958e5172..595fdb47 100644 --- a/ansible/deploy-to-node.yaml +++ b/ansible/deploy-to-node.yaml @@ -205,6 +205,8 @@ NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN: "{{ lookup('ansible.builtin.env', 'WEB_NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN') }}" + MAINTENANCE_MODE: + "{{ lookup('ansible.builtin.env', 'MAINTENANCE_MODE') }}" ports: - "{{ website_port }}:3000" command: bash wait-for-postgres.sh node server.js From c878d12069a2e8c822ffc12844978e9af7154189 Mon Sep 17 00:00:00 2001 From: Yannic Kilcher Date: Sun, 5 Feb 2023 01:50:30 +0100 Subject: [PATCH 067/152] added backend url --- .github/workflows/deploy-to-node.yaml | 1 + ansible/deploy-to-node.yaml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy-to-node.yaml b/.github/workflows/deploy-to-node.yaml index ce77de2f..522a7da7 100644 --- a/.github/workflows/deploy-to-node.yaml +++ b/.github/workflows/deploy-to-node.yaml @@ -62,6 +62,7 @@ jobs: ${{ vars.WEB_NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN }} LOGURU_LEVEL: ${{ vars.LOGURU_LEVEL }} MAINTENANCE_MODE: ${{ vars.MAINTENANCE_MODE }} + BACKEND_URL: ${{ vars.BACKEND_URL }} steps: - name: Checkout uses: actions/checkout@v2 diff --git a/ansible/deploy-to-node.yaml b/ansible/deploy-to-node.yaml index 595fdb47..2111e1fc 100644 --- a/ansible/deploy-to-node.yaml +++ b/ansible/deploy-to-node.yaml @@ -186,7 +186,7 @@ "{{ lookup('ansible.builtin.env', 'WEB_EMAIL_SERVER_PORT') }}" EMAIL_SERVER_USER: "{{ lookup('ansible.builtin.env', 'WEB_EMAIL_SERVER_USER') }}" - FASTAPI_URL: "http://oasst-{{ stack_name }}-backend:8080" + FASTAPI_URL: "{{ lookup('ansible.builtin.env', 'BACKEND_URL') }}" FASTAPI_KEY: "{{ web_api_key }}" NEXTAUTH_SECRET: "{{ lookup('ansible.builtin.env', 'WEB_NEXTAUTH_SECRET') }}" From dc6dd6a6bfb6a4350575f7545d09f98dfd5d39af Mon Sep 17 00:00:00 2001 From: Richard Macarthy Date: Sun, 5 Feb 2023 05:44:10 +0000 Subject: [PATCH 068/152] Add instructions for adding and editing translations using i18n (#1120) update markdown Remove ignore_keys --- .../find-missing-locales.py | 49 +++++++++++++++++++ website/docs/add_edit_translations.md | 38 ++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 scripts/frontend-development/find-missing-locales.py create mode 100644 website/docs/add_edit_translations.md diff --git a/scripts/frontend-development/find-missing-locales.py b/scripts/frontend-development/find-missing-locales.py new file mode 100644 index 00000000..6be52e58 --- /dev/null +++ b/scripts/frontend-development/find-missing-locales.py @@ -0,0 +1,49 @@ +from glob import glob +from json import load +from os import path + +ALL_PATH = "../../website/public/locales/**/*.json" +DIR = path.dirname(__file__) +EN_PATH = "../../website/public/locales/en/*.json" + + +def get_not_translated(en_json, translation_json, parent_key=None): + not_translated = [] + for key in en_json.keys(): + if key in translation_json and translation_json[key] == en_json[key]: + not_translated.append(("{0}.{1}".format(parent_key, key) if parent_key else key)) + elif isinstance(en_json[key], dict): + not_translated.extend(get_not_translated(en_json[key], translation_json[key], key)) + return not_translated + + +def get_missing(en_json, translation_json): + return [key for key in en_json.keys() if key not in translation_json] + + +def print_result(missing, not_translated, file): + if len(missing): + print("[{0}] - missing: {1} {2}".format(path.basename(path.dirname(file)), path.basename(file), missing)) + if len(not_translated): + print( + "[{0}] - potentially untranslated: {1} {2}".format( + path.basename(path.dirname(file)), path.basename(file), not_translated + ) + ) + + +def audit(file, en_file): + en_json = load(open(en_file)) + translation_json = load(open(file)) + print_result(get_missing(en_json, translation_json), get_not_translated(en_json, translation_json), file) + + +def main(): + for en_file in glob(path.join(DIR, EN_PATH)): + for file in glob(path.join(DIR, ALL_PATH)): + if path.basename(en_file) == path.basename(file) and file != en_file: + audit(file, en_file) + + +if __name__ == "__main__": + main() diff --git a/website/docs/add_edit_translations.md b/website/docs/add_edit_translations.md new file mode 100644 index 00000000..63aff32c --- /dev/null +++ b/website/docs/add_edit_translations.md @@ -0,0 +1,38 @@ +## Adding new locales to i18n + +This guide will help you add a new locale to the `i18n` setup. + +### Prerequisites + +- An up-to-date branch with the `main` branch. +- Familiarity with `i18n`, `react-i18next`, and `next-i18next` libraries is beneficial. + +### Adding a new language + +1. Determine the language and country codes using `ISO 639-1`. For example, `en` for English. +1. Create a new directory within the `public/locales` directory using the language and country codes as the name, for + example `en`. +1. Copy all the files from the `en` directory into the newly created directory. +1. Edit the copied the text in the copied files with the desired language. +1. Add the new language to the list in `next-i18next.config.js` if it does not already exist. +1. Follow the instructions in [Website README](<[README.md](../../../website/README.md)>) to run and test the new + language by changing the active locale in the application and verifying that all translated keys are properly + displayed. +1. Commit your changes and open a pull request against the `main` branch for review. + +### Editing existing translation files + +When editing existing translations, follow these rules: + +1. English translations are required, and other locales fall back to them. +1. Keep translation keys in alphabetical order. +1. Add all translations for higher-level components (e.g. `Layout.ts`) in `common.json` to prevent hydration issues. +1. Add reused translation keys in `common.json`. +1. Split translation files into separate files by feature or route. + +### Finding missing translations + +A script can be used to find missing and potentially untranslated locale files. Run the script from the root dir using +`python scripts/frontend-development/find-missing-locales.py`. + +If you have any questions or need further assistance, please reach out. From d10971341fcb5009e09e58ee11d1bc0ad84e08da Mon Sep 17 00:00:00 2001 From: CactiStaccingCrane <121211419+CactiStaccingCrane@users.noreply.github.com> Date: Sun, 5 Feb 2023 12:49:42 +0700 Subject: [PATCH 069/152] Create Vietnamese translation (#1150) Complete translation of UI for Vietnamese --- website/public/locales/vi/common.json | 33 +++++---- website/public/locales/vi/dashboard.json | 8 +++ website/public/locales/vi/index.json | 15 ++++ website/public/locales/vi/labelling.json | 24 +++++++ website/public/locales/vi/leaderboard.json | 18 +++-- website/public/locales/vi/message.json | 19 ++--- website/public/locales/vi/side_menu.json | 12 ++++ website/public/locales/vi/tasks.json | 82 ++++++++++++++++++++++ website/public/locales/vi/tos.json | 6 ++ 9 files changed, 187 insertions(+), 30 deletions(-) create mode 100644 website/public/locales/vi/dashboard.json create mode 100644 website/public/locales/vi/index.json create mode 100644 website/public/locales/vi/labelling.json create mode 100644 website/public/locales/vi/side_menu.json create mode 100644 website/public/locales/vi/tasks.json create mode 100644 website/public/locales/vi/tos.json diff --git a/website/public/locales/vi/common.json b/website/public/locales/vi/common.json index a28addef..2239f392 100644 --- a/website/public/locales/vi/common.json +++ b/website/public/locales/vi/common.json @@ -1,22 +1,25 @@ { - "about": "About", - "account_settings": "Account", - "admin_dashboard": "Admin Dashboard", - "connect": "Connect", - "conversational": "Conversational AI for everyone.", - "dashboard": "Dashboard", + "about": "Thông tin", + "account_settings": "Tài khoản", + "admin_dashboard": "Trang cho admin", + "connect": "Liên hệ", + "conversational": "Chatbot AI cho tất cả mọi người", + "dashboard": "Trang chính", + "delete": "Xoá", "discord": "Discord", - "docs": "Docs", + "docs": "Hướng dẫn", "github": "GitHub", - "legal": "Legal", - "loading": "Loading...", - "more_information": "More Information", - "no": "No", - "privacy_policy": "Privacy Policy", - "report_a_bug": "Report a Bug", + "legal": "Luật lệ", + "loading": "Đang tải...", + "more_information": "Xem thêm", + "no": "Không", + "privacy_policy": "Chính sách bảo mật", + "report_a_bug": "Báo lỗi", "sign_in": "Đăng nhập", "sign_out": "Đăng xuất", - "terms_of_service": "Terms of Service", + "terms_of_service": "Điều khoản sử dụng", "title": "Open Assistant", - "yes": "Yes" + "yes": "Có", + "dark_mode": "Giao diện tối", + "light_mode": "Giao diện sáng" } diff --git a/website/public/locales/vi/dashboard.json b/website/public/locales/vi/dashboard.json new file mode 100644 index 00000000..1bd2e880 --- /dev/null +++ b/website/public/locales/vi/dashboard.json @@ -0,0 +1,8 @@ +{ + "grab_a_task": "Danh sách việc", + "create": "Tạo", + "evaluate": "Kiểm tra", + "label": "Nhãn", + "dashboard": "Trang chính", + "go": "Xem" +} diff --git a/website/public/locales/vi/index.json b/website/public/locales/vi/index.json new file mode 100644 index 00000000..43022145 --- /dev/null +++ b/website/public/locales/vi/index.json @@ -0,0 +1,15 @@ +{ + "blurb": "Đây sẽ là cuộc cách mạng công nghệ mới.", + "blurb1": "Giống như cách Stable Diffusion đã cho mọi người công cụ để làm tranh ảnh bằng AI, Open Assistant sẽ làm như vậy với con chatbot mã nguồn mở mạnh nhất thế giới.", + "description": "Chatbot trí tuệ nhân tạo mã nguồn mở, dựa trên mô hình ngôn ngữ lớn của LAION và các tình nguyện viên trên toàn thế giới.", + "faq_items": { + "q0": "Open Assistant bây giờ thế nào rồi?", + "a0": "Dự án này đang trong giai đoạn phát triển, từ những nghiên cứu về sử dụng RLHF (học từ phản hồi con người) trong các mô hình ngôn ngữ lớn.", + "q1": "Open Assistant được phát triển bởi ai?", + "a1": "Open Assistant là dự ản được phát triển bởi LAION and các tình nguyện viên trên toàn thế giới." + }, + "faq_title": "Câu hỏi", + "join_us_description": "Các dự án mã nguồn mở được phát triển bởi những người như bạn. Triết lý mã nguồn mở là hợp tác để tạo và phát triển công nghệ mới mà làm giàu thế giới quanh ta. Bạn có muốn tham gia không? Liên hệ chúng tôi ở đây:", + "join_us_title": "Tham gia", + "subtitle": "Chatbot AI cho tất cả mọi người" +} diff --git a/website/public/locales/vi/labelling.json b/website/public/locales/vi/labelling.json new file mode 100644 index 00000000..3169cc6b --- /dev/null +++ b/website/public/locales/vi/labelling.json @@ -0,0 +1,24 @@ +{ + "label_highlighted_yes_no_instruction": "Trả lời các câu hỏi sau:", + "label_highlighted_flag_instruction": "Chọn tất cả các mục mà áp dụng với tin nhắn:", + "label_highlighted_likert_instruction": "Đánh giá tin nhắn:", + "label_message_yes_no_instruction": "Trả lời các câu hỏi sau:", + "label_message_flag_instruction": "Chọn tất cả các mục mà áp dụng với tin nhắn:", + "label_message_likert_instruction": "Đánh giá tin nhắn:", + "spam.question": "Tin nhắn có phải là spam không?", + "fails_task.question": "Tin nhắn có lạc đề và không trả lời câu hỏi ở trên không?", + "not_appropriate": "Không phù hợp", + "not_appropriate.explanation": "Tin nhắn không phù hợp và chuyên nghiệp.", + "pii": "Chứa thông tin cá nhân", + "pii.explanation": "Tin nhắn chứa thông tin cá nhân như số điện thoại, email, địa chỉ nhà, số thẻ tín dụng, vân vân.", + "hate_speech": "Gây kích động", + "hate_speech.explanation": "Tin nhắn gây kích động và có định kiến dựa trên giới tính, dân tộc, tôn giáo, vân vân.", + "sexual_content": "Nội dung khiêu dâm", + "sexual_content.explanation": "Tin nhắn chứa nội dung khiêu dâm như nude.", + "moral_judgement": "Phán xét đạo đức", + "moral_judgement.explanation": "Tin nhắn phán xét đạo đức.", + "political_content": "Liên quan tới chính trị", + "political_content.explanation": "Tin nhắn đưa ra quan điểm chính trị.", + "lang_mismatch": "Sai ngôn ngữ", + "lang_mismatch.explanation": "Tin nhắn không được viết trong ngôn ngữ được chọn." +} diff --git a/website/public/locales/vi/leaderboard.json b/website/public/locales/vi/leaderboard.json index 7ceeb732..2eb3bde3 100644 --- a/website/public/locales/vi/leaderboard.json +++ b/website/public/locales/vi/leaderboard.json @@ -1,14 +1,18 @@ { "daily": "Ngày", - "last_updated_at": "Cập nhật lúc: {{val, datetime}}", + "last_updated_at": "Cập nhật lần cuối: {{val, datetime}}", "leaderboard": "Bảng xếp hạng", "monthly": "Tháng", - "overall": "Overall", - "rank": "Hạng", + "overall": "Tổng quan", + "rank": "Xếp hạng", "score": "Điểm", - "user": "User", + "user": "Tên người dùng", "weekly": "Tuần", - "prompt": "Prompts", - "reply": "Replies", - "label": "Labels" + "prompt": "Câu đầu tiên", + "reply": "Câu trả lời", + "label": "Nhãn", + "view_all": "Nhìn tất cả", + "top_5_contributors_today": "Top 5 người đóng góp", + "previous": "Trước", + "next": "Tiếp" } diff --git a/website/public/locales/vi/message.json b/website/public/locales/vi/message.json index 91f3b5f1..b90339e8 100644 --- a/website/public/locales/vi/message.json +++ b/website/public/locales/vi/message.json @@ -1,13 +1,16 @@ { - "label_action": "Label", - "label_title": "Label", - "message": "Message", - "open_new_tab_action": "Mở trong trang mới", - "parent": "Parent", - "reactions": "Reactions", + "label_action": "Nhãn", + "label_title": "Nhãn", + "message": "Tin nhắn", + "open_new_tab_action": "Mở ở trang mới", + "parent": "Tin nhắn gốc", + "reactions": "Bình luận", "report_action": "Báo cáo", - "report_placeholder": "Why should this message be reviewed?", + "report_placeholder": "Tại sao tin nhắn này cần được báo cáo?", "report_title": "Báo cáo", "send_report": "Gửi", - "submit_labels": "Submit" + "submit_labels": "Gửi", + "view_user": "Xem người dùng", + "recent_messages": "Tin nhắn gần đây", + "your_recent_messages": "Tin nhắn gần đây của bạn" } diff --git a/website/public/locales/vi/side_menu.json b/website/public/locales/vi/side_menu.json new file mode 100644 index 00000000..da9ae2c9 --- /dev/null +++ b/website/public/locales/vi/side_menu.json @@ -0,0 +1,12 @@ +{ + "dashboard": "Trang chính", + "dashboard_home": "Trang chính", + "messages": "Tin nhắn", + "messages_dashboard": "Bảng xếp hạng tin nhắn", + "leaderboard": "Bảng xếp hạng", + "user_leaderboard": "Bảng xếp hạng người dùng", + "users": "Người dùng", + "users_dashboard": "Trang về người dùng", + "status": "Tình trạng", + "status_dashboard": "Trang hiện tình trạng" +} diff --git a/website/public/locales/vi/tasks.json b/website/public/locales/vi/tasks.json new file mode 100644 index 00000000..4a33f7ee --- /dev/null +++ b/website/public/locales/vi/tasks.json @@ -0,0 +1,82 @@ +{ + "default": { + "unchanged_title": "Chưa thay đổi", + "unchanged_message": "Are you sure you would like to continue?" + }, + "random": { + "label": "Chọn ngẫu nhiên", + "desc": "Giúp cải thiện Open Assistant bằng cách làm một việc ngẫu nhiên." + }, + "create_initial_prompt": { + "label": "Tạo tin nhắn đầu", + "desc": "Viết tin nhắn đầu tiên để làm bộ dữ liệu cho Open Assistant.", + "overview": "Viết tin nhắn đầu tiên để Open Assistant trả lời", + "instruction": "Viết tin nhắn đầu", + "response_placeholder": "Viết vào đây..." + }, + "reply_as_user": { + "label": "Đóng vai người dùng", + "desc": "Trò chuyện với Open Assistant và cải thiện con bot.", + "overview": "Tạo câu trả lời phù hợp cho cuộc trò truyện dưới đây", + "instruction": "Viết tin nhắn trả lời", + "response_placeholder": "Viết vào đây..." + }, + "reply_as_assistant": { + "label": "Đóng vai Open Assistant", + "desc": "Giúp cải thiện câu trả lời của Open Assistant.", + "overview": "Tạo câu trả lời phù hợp cho cuộc trò truyện dưới đây", + "response_placeholder": "Viết vào đây..." + }, + "rank_user_replies": { + "label": "Xếp hạng câu trả lời của người dùng", + "desc": "Giúp cải thiện câu trả lời của Open Assistant.", + "overview": "Từ những câu trả lời của người dùng, xếp hạng chúng theo chất lượng, tốt nhât ở trên, tệ nhất ở dưới.", + "unchanged_title": "Chưa thay đổi thứ tự", + "unchanged_message": "Bạn chưa thay đổi thứ tự tin nhắn. Bạn có chắc muốn lưu không?" + }, + "rank_assistant_replies": { + "label": "Xếp hạng câu trả lời của Open Assistant", + "desc": "Đánh giá độ chính xác và dễ đọc của các câu trả lời mà Open Assistant đưa ra.", + "overview": "Từ những câu trả lời của Open Assistant, xếp hạng chúng theo chất lượng, tốt nhât ở trên, tệ nhất ở dưới.", + "unchanged_title": "Chưa thay đổi thứ tự", + "unchanged_message": "Bạn chưa thay đổi thứ tự tin nhắn. Bạn có chắc muốn lưu không?" + }, + "rank_initial_prompts": { + "label": "Xếp hạng tin nhắn đầu tiên", + "desc": "Đánh giá độ chính xác và dễ đọc của các câu trả lời của tin nhắn đầu tiên.", + "overview": "Từ những tin nhắn đầu sau, xếp hạng chúng theo chất lượng, tốt nhât ở trên, tệ nhất ở dưới.", + "unchanged_title": "Chưa thay đổi thứ tự", + "unchanged_message": "Bạn chưa thay đổi thứ tự tin nhắn. Bạn có chắc muốn lưu không?" + }, + "label_initial_prompt": { + "label": "Tạo nhãn cho tin nhắn đầu", + "desc": "Tạo nhãn dữ liệu đánh giá tin nhắn đầu.", + "overview": "Tạo nhãn dữ liệu cho tin nhắn sau." + }, + "label_prompter_reply": { + "label": "Tạo nhãn cho tin nhắn người dùng", + "desc": "Tạo nhãn dữ liệu đánh giá tin nhắn của người dùng.", + "overview": "Từ cuộc trò truyện ở dưới, tạo nhãn dữ liệu cho tin nhắn sau." + }, + "label_assistant_reply": { + "label": "Tạo nhãn cho tin nhắn của Open Assistant", + "desc": "Tạo nhãn dữ liệu đánh giá tin nhắn của Open Assistant.", + "overview": "Từ cuộc trò truyện ở dưới, tạo nhãn dữ liệu cho tin nhắn sau." + }, + "classify_initial_prompt": { + "label": "Phân loại tin nhắn đầu", + "desc": "Tạo nhãn dữ liệu đánh giá tin nhắn.", + "overview": "Đọc tin nhắn đầu và trả lời các câu hỏi." + }, + "classify_prompter_reply": { + "label": "Phân loại tin nhắn người dùng", + "desc": "Tạo nhãn dữ liệu đánh giá tin nhắn.", + "overview": "Từ cuộc trò truyện ở dưới, trả lời các câu hỏi về câu trả lời cuối trong cuộc trò truyện." + }, + "classify_assistant_reply": { + "label": "Phân loại tin nhắn của Open Assistant", + "desc": "Tạo nhãn dữ liệu đánh giá tin nhắn.", + "overview": "Từ cuộc trò truyện ở dưới, trả lời các câu hỏi về câu trả lời cuối trong cuộc trò truyện." + }, + "available_task_count": "{{count}} việc" +} diff --git a/website/public/locales/vi/tos.json b/website/public/locales/vi/tos.json new file mode 100644 index 00000000..d32a012b --- /dev/null +++ b/website/public/locales/vi/tos.json @@ -0,0 +1,6 @@ +{ + "title": "Điều khoản sử dụng của Open Assistant", + "content": "Để tiếp tục sử dụng Open Assistant, bản phải chấp nhận điều khoản sử dụng.", + "accept": "Chấp nhận", + "decline": "Không chấp nhận" +} From 3b61a26c9cb5ee05344a6763df2767a524bfa796 Mon Sep 17 00:00:00 2001 From: Richard Macarthy Date: Sun, 5 Feb 2023 06:09:39 +0000 Subject: [PATCH 070/152] Add halt tree, and copy message id features (#1088) --- website/public/locales/en/common.json | 8 +-- website/public/locales/en/message.json | 6 ++- .../components/Messages/MessageTableEntry.tsx | 54 ++++++++++++++++--- website/src/lib/api.ts | 2 + website/src/lib/oasst_api_client.ts | 7 +++ website/src/pages/api/admin/stop_tree/[id].ts | 15 ++++++ 6 files changed, 81 insertions(+), 11 deletions(-) create mode 100644 website/src/pages/api/admin/stop_tree/[id].ts diff --git a/website/public/locales/en/common.json b/website/public/locales/en/common.json index f1783669..abc9fb21 100644 --- a/website/public/locales/en/common.json +++ b/website/public/locales/en/common.json @@ -2,14 +2,17 @@ "about": "About", "account_settings": "Account", "admin_dashboard": "Admin Dashboard", + "copied": "Copied", "connect": "Connect", "conversational": "Conversational AI for everyone.", + "dark_mode": "Dark Mode", "dashboard": "Dashboard", "delete": "Delete", "discord": "Discord", "docs": "Docs", "github": "GitHub", "legal": "Legal", + "light_mode": "Light Mode", "loading": "Loading...", "more_information": "More Information", "no": "No", @@ -17,9 +20,8 @@ "report_a_bug": "Report a Bug", "sign_in": "Sign In", "sign_out": "Sign Out", + "success": "Success", "terms_of_service": "Terms of Service", "title": "Open Assistant", - "yes": "Yes", - "dark_mode": "Dark Mode", - "light_mode": "Light Mode" + "yes": "Yes" } diff --git a/website/public/locales/en/message.json b/website/public/locales/en/message.json index ac9689a2..c65b1cfa 100644 --- a/website/public/locales/en/message.json +++ b/website/public/locales/en/message.json @@ -1,16 +1,20 @@ { + "copy_message_id": "Copy message ID", "label_action": "Label", "label_title": "Label", + "message_deleted": "Message deleted", "message": "Message", "open_new_tab_action": "Open in new tab", "parent": "Parent", "reactions": "Reactions", + "recent_messages": "Recent Messages", "report_action": "Report", "report_placeholder": "Why should this message be reviewed?", "report_title": "Report", "send_report": "Send", + "stop_tree": "Stop tree", "submit_labels": "Submit", + "tree_stopped": "Tree stopped {{id}}", "view_user": "View user", - "recent_messages": "Recent Messages", "your_recent_messages": "Your Recent Messages" } diff --git a/website/src/components/Messages/MessageTableEntry.tsx b/website/src/components/Messages/MessageTableEntry.tsx index cec724e5..3fb8d59a 100644 --- a/website/src/components/Messages/MessageTableEntry.tsx +++ b/website/src/components/Messages/MessageTableEntry.tsx @@ -12,9 +12,10 @@ import { useBreakpointValue, useColorModeValue, useDisclosure, + useToast, } from "@chakra-ui/react"; import { boolean } from "boolean"; -import { ClipboardList, Flag, MessageSquare, MoreHorizontal, Trash, User } from "lucide-react"; +import { ClipboardList, Copy, Flag, MessageSquare, MoreHorizontal, Slash, Trash, User } from "lucide-react"; import { useRouter } from "next/router"; import { useSession } from "next-auth/react"; import { useTranslation } from "next-i18next"; @@ -22,7 +23,7 @@ import { useCallback, useEffect, useMemo, useState } from "react"; import { LabelMessagePopup } from "src/components/Messages/LabelPopup"; import { MessageEmojiButton } from "src/components/Messages/MessageEmojiButton"; import { ReportPopup } from "src/components/Messages/ReportPopup"; -import { del, post } from "src/lib/api"; +import { del, post, put } from "src/lib/api"; import { colors } from "src/styles/Theme/colors"; import { Message, MessageEmojis } from "src/types/Conversation"; import { emojiIcons, isKnownEmoji } from "src/types/Emoji"; @@ -142,6 +143,8 @@ const EmojiMenuItem = ({ ); }; +const CHAR_COUNT = 10; + const MessageActions = ({ react, userEmoji, @@ -155,16 +158,47 @@ const MessageActions = ({ onReport: () => void; message: Message; }) => { + const toast = useToast(); const { t } = useTranslation(["message", "common"]); - const { trigger } = useSWRMutation(`/api/admin/delete_message/${message.id}`, del); - const { data } = useSession() || {}; - const role = data?.user?.role; + const id = message.id; + const displayId = id.slice(0, CHAR_COUNT) + "..." + id.slice(-CHAR_COUNT); + const { trigger: deleteMessage } = useSWRMutation(`/api/admin/delete_message/${message.id}`, del); + + const { trigger: stopTree } = useSWRMutation(`/api/admin/stop_tree/${message.id}`, put, { + onSuccess: () => { + toast({ + title: t("common:success"), + description: t("tree_stopped", { id: displayId }), + status: "success", + duration: 5000, + isClosable: true, + }); + }, + }); + + const { data: session } = useSession(); + const isAdmin = session?.user?.role === "admin"; const handleDelete = async () => { - await trigger(); + await deleteMessage(); mutate((key) => typeof key === "string" && key.startsWith("/api/messages"), undefined, { revalidate: true }); }; + const handleStop = () => { + stopTree(); + }; + + const handleCopyId = () => { + navigator.clipboard.writeText(message.id); + toast({ + title: t("common:copied"), + description: displayId, + status: "info", + duration: 5000, + isClosable: true, + }); + }; + return ( @@ -189,15 +223,21 @@ const MessageActions = ({ }> {t("open_new_tab_action")} - {role === "admin" && ( + {!!isAdmin && ( <> + }> + {t("copy_message_id")} + }> {t("view_user")} }> {t("common:delete")} + }> + {t("stop_tree")} + )} diff --git a/website/src/lib/api.ts b/website/src/lib/api.ts index 6c3bd900..27b1b811 100644 --- a/website/src/lib/api.ts +++ b/website/src/lib/api.ts @@ -19,6 +19,8 @@ export const post = (url: string, { arg: data }) => api.post(url, data).then((re export const del = (url: string) => api.delete(url).then((res) => res.data); +export const put = (url: string, { arg: data }) => api.put(url, data).then((res) => res.data); + api.interceptors.response.use( (response) => response, (error) => { diff --git a/website/src/lib/oasst_api_client.ts b/website/src/lib/oasst_api_client.ts index f8307854..30fb9885 100644 --- a/website/src/lib/oasst_api_client.ts +++ b/website/src/lib/oasst_api_client.ts @@ -167,6 +167,13 @@ export class OasstApiClient { return this.delete(`/api/v1/messages/${message_id}`); } + /** + * Stop message tree + */ + async stop_tree(message_id: string): Promise { + return this.put(`/api/v1/messages/${message_id}/tree/state?halt=true`); + } + /** * Send a report about a message */ diff --git a/website/src/pages/api/admin/stop_tree/[id].ts b/website/src/pages/api/admin/stop_tree/[id].ts new file mode 100644 index 00000000..ade751b3 --- /dev/null +++ b/website/src/pages/api/admin/stop_tree/[id].ts @@ -0,0 +1,15 @@ +import { withRole } from "src/lib/auth"; +import { createApiClient } from "src/lib/oasst_client_factory"; + +const handler = withRole("admin", async (req, res, token) => { + const { id } = req.query; + try { + const client = await createApiClient(token); + await client.stop_tree(id as string); + res.status(200).json({ message: `Tree ${id} stopped`, id }); + } catch (e) { + res.status(500).json(e); + } +}); + +export default handler; From 7fac0d70c85c3115bd7cf6cecbbc03dfe1e76de9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Korbinian=20P=C3=B6ppel?= <37810656+kpoeppel@users.noreply.github.com> Date: Sun, 5 Feb 2023 07:10:53 +0100 Subject: [PATCH 071/152] Live language feedback (#1071) * Add live language detection using 'lande' in TrackedTextarea. * Remove 'Disable Language Detection'. * Re-run linter. --- website/package-lock.json | 27 +++ website/package.json | 1 + .../src/components/Survey/TrackedTextarea.tsx | 70 ++++++- website/src/lib/iso6393.ts | 187 ++++++++++++++++++ 4 files changed, 282 insertions(+), 3 deletions(-) create mode 100644 website/src/lib/iso6393.ts diff --git a/website/package-lock.json b/website/package-lock.json index fe03e145..3b8220e5 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -32,6 +32,7 @@ "eslint-plugin-simple-import-sort": "^8.0.0", "focus-visible": "^5.2.0", "framer-motion": "^6.5.1", + "lande": "^1.0.10", "lucide-react": "^0.105.0", "next": "13.0.6", "next-auth": "^4.18.6", @@ -26611,6 +26612,14 @@ "node": ">= 8" } }, + "node_modules/lande": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/lande/-/lande-1.0.10.tgz", + "integrity": "sha512-yT52DQh+UV2pEp08jOYrA4drDv0DbjpiRyZYgl25ak9G2cVR2AimzrqkYQWrD9a7Ud+qkAcaiDDoNH9DXfHPmw==", + "dependencies": { + "toygrad": "^2.6.0" + } + }, "node_modules/language-subtag-registry": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", @@ -36420,6 +36429,11 @@ "node": ">=0.8" } }, + "node_modules/toygrad": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/toygrad/-/toygrad-2.6.0.tgz", + "integrity": "sha512-g4zBmlSbvzOE5FOILxYkAybTSxijKLkj1WoNqVGnbMcWDyj4wWQ+eYSr3ik7XOpIgMq/7eBcPRTJX3DM2E0YMg==" + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -58708,6 +58722,14 @@ "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", "dev": true }, + "lande": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/lande/-/lande-1.0.10.tgz", + "integrity": "sha512-yT52DQh+UV2pEp08jOYrA4drDv0DbjpiRyZYgl25ak9G2cVR2AimzrqkYQWrD9a7Ud+qkAcaiDDoNH9DXfHPmw==", + "requires": { + "toygrad": "^2.6.0" + } + }, "language-subtag-registry": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", @@ -65936,6 +65958,11 @@ "punycode": "^2.1.1" } }, + "toygrad": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/toygrad/-/toygrad-2.6.0.tgz", + "integrity": "sha512-g4zBmlSbvzOE5FOILxYkAybTSxijKLkj1WoNqVGnbMcWDyj4wWQ+eYSr3ik7XOpIgMq/7eBcPRTJX3DM2E0YMg==" + }, "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", diff --git a/website/package.json b/website/package.json index c68b1537..7ab3f3d8 100644 --- a/website/package.json +++ b/website/package.json @@ -50,6 +50,7 @@ "eslint-plugin-simple-import-sort": "^8.0.0", "focus-visible": "^5.2.0", "framer-motion": "^6.5.1", + "lande": "^1.0.10", "lucide-react": "^0.105.0", "next": "13.0.6", "next-auth": "^4.18.6", diff --git a/website/src/components/Survey/TrackedTextarea.tsx b/website/src/components/Survey/TrackedTextarea.tsx index f408e168..196d2f1a 100644 --- a/website/src/components/Survey/TrackedTextarea.tsx +++ b/website/src/components/Survey/TrackedTextarea.tsx @@ -1,4 +1,23 @@ -import { Progress, Stack, Textarea, TextareaProps, useColorModeValue } from "@chakra-ui/react"; +import {} from "@chakra-ui/react"; +import lande from "lande"; +import { LanguageAbbreviations } from "src/lib/iso6393"; +import { useCookies } from "react-cookie"; +import React from "react"; +import { + Progress, + Stack, + Textarea, + TextareaProps, + useColorModeValue, + Button, + Modal, + ModalBody, + ModalCloseButton, + ModalContent, + ModalHeader, + ModalOverlay, + useDisclosure, +} from "@chakra-ui/react"; interface TrackedTextboxProps { text: string; @@ -11,10 +30,55 @@ interface TrackedTextboxProps { onTextChange: (event: React.ChangeEvent) => void; } -export const TrackedTextarea = (props: TrackedTextboxProps) => { - const backgroundColor = useColorModeValue("gray.100", "gray.900"); +const killEvent = (e) => e.stopPropagation(); +export const TrackedTextarea = (props: TrackedTextboxProps) => { + const [wordLimitForLangDetection, setWordLimitForLangDetection] = React.useState(10); + const backgroundColor = useColorModeValue("gray.100", "gray.900"); + const [cookies] = useCookies(["NEXT_LOCALE"]); const wordCount = (props.text.match(/\w+/g) || []).length; + const { isOpen, onOpen, onClose } = useDisclosure(); + const currentLanguage = cookies["NEXT_LOCALE"]; + + const closeTemporaryIgnoreLanguageDetection = () => { + setWordLimitForLangDetection(2 * wordCount); + onClose(); + }; + + console.log("", wordCount, wordLimitForLangDetection); + if (wordCount > wordLimitForLangDetection) { + let mostProbableLanguage; + try { + mostProbableLanguage = LanguageAbbreviations[lande(props.text)[0][0]]; + } catch (error) { + mostProbableLanguage = ""; + } + + /*const mostProbableLanguage = lande(props.text);*/ + if (mostProbableLanguage !== currentLanguage) { + setTimeout(() => { + onOpen(); + }, 200); + + return ( + <> + + {/* we kill the event here to disable drag and drop, since it is in the same container */} + + + Switch Language? + + + Do you want to switch language? The detected language is {mostProbableLanguage}, whereas your + chosen language is {currentLanguage}. The language can be changed on the top right. + + + + + + ); + } + } let progressColor: string; switch (true) { diff --git a/website/src/lib/iso6393.ts b/website/src/lib/iso6393.ts new file mode 100644 index 00000000..3720150a --- /dev/null +++ b/website/src/lib/iso6393.ts @@ -0,0 +1,187 @@ +export const LanguageAbbreviations = { + aar: "aa", + abk: "ab", + afr: "af", + aka: "ak", + alb: "sq", + amh: "am", + ara: "ar", + arg: "an", + hye: "hy", + asm: "as", + ava: "av", + ave: "ae", + aym: "ay", + aze: "az", + bak: "ba", + bam: "bm", + eus: "eu", + bel: "be", + ben: "bn", + bih: "bh", + bis: "bi", + tib: "bo", + bos: "bs", + bre: "br", + bul: "bg", + mya: "my", + cat: "ca", + cze: "cs", + cha: "ch", + che: "ce", + zho: "zh", + chu: "cu", + chv: "cv", + cor: "kw", + cos: "co", + cre: "cr", + wel: "cy", + dan: "da", + ger: "de", + deu: "de", + div: "dv", + dut: "nl", + dzo: "dz", + gre: "el", + eng: "en", + epo: "eo", + est: "et", + ewe: "ee", + fao: "fo", + per: "fa", + fij: "fj", + fin: "fi", + fra: "fr", + fry: "fy", + ful: "ff", + geo: "ka", + gla: "gd", + gle: "ga", + glg: "gl", + glv: "gv", + grn: "gn", + guj: "gu", + hat: "ht", + hau: "ha", + heb: "he", + her: "hz", + hin: "hi", + hmo: "ho", + hrv: "hr", + hun: "hu", + ibo: "ig", + ice: "is", + ido: "io", + iii: "ii", + iku: "iu", + ile: "ie", + ina: "ia", + ind: "id", + ipk: "ik", + ita: "it", + jav: "jv", + jpn: "ja", + kal: "kl", + kan: "kn", + kas: "ks", + kau: "kr", + kaz: "kk", + khm: "km", + kik: "ki", + kin: "rw", + kir: "ky", + kom: "kv", + kon: "kg", + kor: "ko", + kua: "kj", + kur: "ku", + lao: "lo", + lat: "la", + lav: "lv", + lim: "li", + lin: "ln", + lit: "lt", + ltz: "lb", + lub: "lu", + lug: "lg", + mkd: "mk", + mah: "mh", + mal: "ml", + mri: "mi", + mar: "mr", + may: "ms", + mlg: "mg", + mlt: "mt", + mon: "mn", + nau: "na", + nav: "nv", + nbl: "nr", + nde: "nd", + ndo: "ng", + nep: "ne", + nno: "nn", + nob: "nb", + nor: "no", + nya: "ny", + oci: "oc", + oji: "oj", + ori: "or", + orm: "om", + oss: "os", + pan: "pa", + pli: "pi", + pol: "pl", + por: "pt", + pus: "ps", + que: "qu", + roh: "rm", + ron: "ro", + run: "rn", + rus: "ru", + sag: "sg", + san: "sa", + sin: "si", + slk: "sk", + slv: "sl", + sme: "se", + smo: "sm", + sna: "sn", + snd: "sd", + som: "so", + sot: "st", + spa: "es", + srd: "sc", + srp: "sr", + ssw: "ss", + sun: "su", + swa: "sw", + swe: "sv", + tah: "ty", + tam: "ta", + tat: "tt", + tel: "te", + tgk: "tg", + tgl: "tl", + tha: "th", + tir: "ti", + ton: "to", + tsn: "tn", + tso: "ts", + tuk: "tk", + tur: "tr", + twi: "tw", + uig: "ug", + ukr: "uk", + urd: "ur", + uzb: "uz", + ven: "ve", + vie: "vi", + vol: "vo", + wln: "wa", + wol: "wo", + xho: "xh", + yid: "yi", + yor: "yo", + zha: "za", + zul: "zu", +}; From 692d178a24b6951d226b06f6ae3bd44a843ff84f Mon Sep 17 00:00:00 2001 From: AbdBarho Date: Sun, 5 Feb 2023 07:16:12 +0100 Subject: [PATCH 072/152] Fix localization in for labelling (#1132) --- .../components/Messages/LabelInputGroup.tsx | 14 +++++---- .../src/components/Messages/LabelPopup.tsx | 8 ++--- website/src/pages/messages/[id]/index.tsx | 30 +++++++++---------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/website/src/components/Messages/LabelInputGroup.tsx b/website/src/components/Messages/LabelInputGroup.tsx index 2193a9f2..7cdb8828 100644 --- a/website/src/components/Messages/LabelInputGroup.tsx +++ b/website/src/components/Messages/LabelInputGroup.tsx @@ -1,9 +1,9 @@ -import { Text, VStack } from "@chakra-ui/react"; +import { Box, Text, VStack } from "@chakra-ui/react"; import { useTranslation } from "next-i18next"; import { Explain } from "src/components/Explain"; import { LabelFlagGroup } from "src/components/Messages/LabelFlagGroup"; -import { LabelLikertGroup } from "src/components/Survey/LabelLikertGroup"; import { LabelYesNoGroup } from "src/components/Messages/LabelYesNoGroup"; +import { LabelLikertGroup } from "src/components/Survey/LabelLikertGroup"; import { getTypeSafei18nKey } from "src/lib/i18n"; import { Label } from "src/types/Tasks"; @@ -55,8 +55,10 @@ export const LabelInputGroup = ({ )} {flagIndexes.length > 0 && ( - - {instructions.flagInstruction} + + + {instructions.flagInstruction} + @@ -64,8 +66,8 @@ export const LabelInputGroup = ({ getTypeSafei18nKey(`${labels[idx].name}.explanation`) )}` )} - />{" "} - + /> + values[idx])} labelNames={flagIndexes.map((idx) => labels[idx].name)} diff --git a/website/src/components/Messages/LabelPopup.tsx b/website/src/components/Messages/LabelPopup.tsx index 38eae7b0..67bae3cc 100644 --- a/website/src/components/Messages/LabelPopup.tsx +++ b/website/src/components/Messages/LabelPopup.tsx @@ -9,7 +9,7 @@ import { ModalOverlay, } from "@chakra-ui/react"; import { useTranslation } from "next-i18next"; -import { useEffect, useState } from "react"; +import { useCallback, useEffect, useMemo, useState } from "react"; import { LabelInputGroup } from "src/components/Messages/LabelInputGroup"; import { get, post } from "src/lib/api"; import { Label } from "src/types/Tasks"; @@ -29,7 +29,7 @@ interface ValidLabelsResponse { export const LabelMessagePopup = ({ messageId, show, onClose }: LabelMessagePopupProps) => { const { t } = useTranslation(); const { data: response } = useSWRImmutable(`/api/valid_labels?message_id=${messageId}`, get); - const valid_labels = response?.valid_labels ?? []; + const valid_labels = useMemo(() => response?.valid_labels ?? [], [response]); const [values, setValues] = useState(new Array(valid_labels.length).fill(null)); useEffect(() => { @@ -38,7 +38,7 @@ export const LabelMessagePopup = ({ messageId, show, onClose }: LabelMessagePopu const { trigger: setLabels } = useSWRMutation("/api/set_label", post); - const submit = () => { + const submit = useCallback(() => { const label_map: Map = new Map(); console.assert(valid_labels.length === values.length); values.forEach((value, idx) => { @@ -53,7 +53,7 @@ export const LabelMessagePopup = ({ messageId, show, onClose }: LabelMessagePopu setValues(new Array(values.length).fill(null)); onClose(); - }; + }, [messageId, onClose, setLabels, valid_labels, values]); return ( diff --git a/website/src/pages/messages/[id]/index.tsx b/website/src/pages/messages/[id]/index.tsx index 2c58c367..0092a843 100644 --- a/website/src/pages/messages/[id]/index.tsx +++ b/website/src/pages/messages/[id]/index.tsx @@ -14,7 +14,9 @@ const MessageDetail = ({ id }: { id: string }) => { const { t } = useTranslation(["message", "common"]); const backgroundColor = useColorModeValue("white", "gray.800"); - const { isLoading: isLoadingParent, data: parent } = useSWRImmutable(`/api/messages/${id}/parent`, get); + const { isLoading: isLoadingParent, data: parent } = useSWRImmutable(`/api/messages/${id}/parent`, get, { + refreshInterval: 30 * 1000, // 30 seconds + }); if (isLoadingParent) { return ; @@ -29,20 +31,16 @@ const MessageDetail = ({ id }: { id: string }) => { /> - - {parent && ( - <> - - - {t("parent")} - - - - - - - )} - + {parent && ( + + + {t("parent")} + + + + + + )} @@ -56,7 +54,7 @@ MessageDetail.getLayout = (page) => getDashboardLayout(page); export const getServerSideProps = async ({ locale, query }) => ({ props: { id: query.id, - ...(await serverSideTranslations(locale, ["common", "message"])), + ...(await serverSideTranslations(locale, ["common", "message", "labelling"])), }, }); From e6fe4773089a6d54b2e74e189c12984ffa654d71 Mon Sep 17 00:00:00 2001 From: AbdBarho Date: Sun, 5 Feb 2023 11:58:20 +0100 Subject: [PATCH 073/152] Show ToS on all pages (#1111) Closes #1047 --- website/cypress/support/commands.ts | 5 + website/src/components/Layout.tsx | 55 ++++---- website/src/components/ToS.tsx | 170 ++++++++++++++++++++++++ website/src/components/ToSWrapper.tsx | 39 +++--- website/src/pages/api/tos.ts | 1 - website/src/pages/dashboard.tsx | 8 +- website/src/pages/terms-of-service.tsx | 172 +------------------------ 7 files changed, 230 insertions(+), 220 deletions(-) create mode 100644 website/src/components/ToS.tsx diff --git a/website/cypress/support/commands.ts b/website/cypress/support/commands.ts index b2ce81f6..4eecf146 100644 --- a/website/cypress/support/commands.ts +++ b/website/cypress/support/commands.ts @@ -47,6 +47,11 @@ Cypress.Commands.add("signInUsingEmailedLink", (emailAddress) => { const loginLink = emails.pop().html.match(/href="[^"]+(\/api\/auth\/callback\/[^"]+?)"/)[1]; cy.visit(loginLink); cy.url().should("include", "/dashboard"); + + // we do a GET to this url to force the python backend to add an entry for our user + // in the database, otherwise the tos acceptance will error with 404 user not found + // then we accept the tos + cy.request("GET", "/api/available_tasks").then(() => cy.request("POST", "/api/tos", {})); }); }); diff --git a/website/src/components/Layout.tsx b/website/src/components/Layout.tsx index 2f89ae47..00a98a71 100644 --- a/website/src/components/Layout.tsx +++ b/website/src/components/Layout.tsx @@ -8,6 +8,7 @@ import { Header } from "src/components/Header"; import { SlimFooter } from "./Dashboard/SlimFooter"; import { Footer } from "./Footer"; import { SideMenuLayout } from "./SideMenuLayout"; +import { ToSWrapper } from "./ToSWrapper"; export type NextPageWithLayout

= NextPage & { getLayout?: (page: React.ReactElement) => React.ReactNode; @@ -32,32 +33,34 @@ export const getTransparentHeaderLayout = (page: React.ReactElement) => ( export const getDashboardLayout = (page: React.ReactElement) => (

- - - {page} - - - - - + + + + {page} + + + + + + ); diff --git a/website/src/components/ToS.tsx b/website/src/components/ToS.tsx new file mode 100644 index 00000000..53bd9682 --- /dev/null +++ b/website/src/components/ToS.tsx @@ -0,0 +1,170 @@ +import { Stack } from "@chakra-ui/react"; +import { PolicyChapterCard } from "src/components/PolicyCards/PolicyChapterCard"; +import { PolicySectionCard } from "src/components/PolicyCards/PolicySectionCard"; + +const TermsData = [ + { + number: "1", + title: "Scope of Application, Amendments", + desc: "", + sections: [ + { + number: "1.1", + title: "", + desc: `LAION e.V., Herman-Lange-Weg 26, 21035 Hamburg, Germany (hereinafter referred to as: "LAION") operates an online portal for the producing a machine learning model called Open Assistant using crowd-sourced data.`, + }, + { + number: "1.2", + title: "", + desc: "The present terms of use regulate the user relationship between the users of the portal and LAION.", + }, + { + number: "1.3", + title: "", + desc: "LAION reserves the right to amend these Terms of Use at any time, also with regard to persons already registered, if this becomes necessary due to changes in the law, changes in jurisdiction, changes in economic circumstances or gaps in these Terms of Use that subsequently become apparent. The user will be informed of such changes in good time by e-mail The user has the opportunity to object to the changes within 14 days of receipt of this e-mail. If the user does not object to the changes and continues to use the portal after expiry of the objection period, the changes shall be deemed to have been agreed effectively from the expiry of the period. If the user objects to the changes within the two-week period, LAION shall be entitled to exclude the user from using the portal. The user shall be informed of these effects once again in the e-mail.", + }, + ], + }, + { + number: "2", + title: "Subject of Use, Availability of the Service", + desc: "", + sections: [ + { + number: "2.1", + title: "", + desc: "The portal serves as a platform for creating data to train an interactive agent for scientific purposes. All text and prompt generated through the service are used for scientific purposes, in particular for the optimization of the AI.", + }, + { + number: "2.2", + title: "", + desc: "The input of texts on the portal and the subsequent generation of text by the artificial intelligence provided by the portal do not give rise to any works protected by copyright. The user who has entered the text for the generation of the text shall have neither the exclusive rights of use nor any rights of an author to the generated text.", + }, + { + number: "2.3", + title: "", + desc: "LAION shall endeavour to ensure that the portal can be used as uninterruptedly as possible. However, there shall be no legal claim to the use of the portal. LAION reserves the right, at its own discretion, to change the portal at any time and without notice, to discontinue its operation or to exclude individual users from using it. Furthermore, it cannot be ruled out that temporary restrictions or interruptions may occur due to technical faults (such as interruption of the power supply, hardware and software errors, technical problems in the data lines).", + }, + ], + }, + { + number: "3", + title: "User Obligations", + desc: "", + sections: [ + { + number: "3.1", + title: "", + desc: "The user may only use the portal for the intended purposes. In particular, he/she may not misuse the portal. The user undertakes to refrain from generating text that violate criminal law, youth protection regulations or the applicable laws of the following countries: Federal Republic of Germany, United States of America (USA), Great Britain, user's place of residence. In particular it is prohibited to enter texts that lead to the creation of pornographic, violence-glorifying or paedosexual content and/or content that violates the personal rights of third parties. LAION reserves the right to file a criminal complaint with the competent authorities in the event of violations.", + }, + { + number: "3.2", + title: "", + desc: "The user undertakes not to use any programs, algorithms or other software in connection with the use of the portal which could interfere with the functioning of the portal. Furthermore, the user shall not take any measures that may result in an unreasonable or excessive load on the infrastructure of the portal or may interfere with it in a disruptive manner.", + }, + { + number: "3.3", + title: "", + desc: "If a user notices obvious errors in the portal which could lead to misuse of the portal or the contents contained therein, the user shall be obliged to report the error to LAION without delay.", + }, + { + number: "3.4", + title: "", + desc: "The use, distribution, storage, forwarding, editing and/or other use of images that violate these terms of use is prohibited.", + }, + ], + }, + { + number: "4", + title: "Liability", + desc: "", + sections: [ + { + number: "4.1", + title: "", + desc: "LAION accepts no liability for the accuracy, completeness, reliability, up-to-dateness and usability of the content.", + }, + { + number: "4.2", + title: "", + desc: "LAION shall be liable without limitation for intent and gross negligence. In the case of simple negligence, LAION shall only be liable for damage resulting from injury to life, limb or health or an essential contractual obligation (obligation the fulfillment of which makes the proper performance of the contract possible in the first place and on the observance of which the contractual partner regularly trusts and may trust).", + }, + { + number: "4.3", + title: "", + desc: "In the event of a breach of material contractual obligations due to simple negligence, the liability of LAION shall be limited to the amount of the foreseeable, typically occurring damage. In all other respects liability shall be excluded.", + }, + { + number: "4.4", + title: "", + desc: "The above limitations of liability shall also apply in favour of the legal representatives and vicarious agents of LAION.", + }, + { + number: "4.5", + title: "", + desc: "LAION shall not be liable for the loss of data of the user. The user shall be solely responsible for the secure storage of his/her data.", + }, + { + number: "4.6", + title: "", + desc: "LAION shall not be liable for any damages incurred by the user as a result of the violation of these terms of use.", + }, + { + number: "4.7", + title: "", + desc: "LAION shall not be liable for the use of content generated on the portal by text input outside the portal. In particular, LAION shall not be liable for any damages incurred by the user due to the assumption of copyrights or exclusive rights of use.", + }, + ], + }, + { + number: "5", + title: "Data Protection", + desc: "", + sections: [ + { + number: "5.1", + title: "", + desc: "LAION processes the personal data of users in accordance with the provisions of data protection law. Detailed information can be found in the privacy policy, available at: /privacy-policy.", + }, + { + number: "5.2", + title: "", + desc: "The user expressly agrees that communication within the scope of and for the purpose of the user relationship between him/her and LAION may also take place via unencrypted e-mails. The user is aware that unencrypted e-mails only offer limited security and confidentiality.", + }, + ], + }, + { + number: "6", + title: "Final Provisions", + desc: "", + sections: [ + { + number: "6.1", + title: "", + desc: "The contractual relationship shall be governed exclusively by the law of the Federal Republic of Germany to the exclusion of the UN Convention on Contracts for the International Sale of Goods.", + }, + { + number: "6.2", + title: "", + desc: "Should individual provisions of these GTC including this provision be or become invalid in whole or in part, the validity of the remaining provisions shall remain unaffected. The invalid or missing provisions shall be replaced by the respective statutory provisions.", + }, + { + number: "6.3", + title: "", + desc: "If the customer is a merchant, a legal entity under public law or a special fund under public law, the place of jurisdiction for all disputes arising from and in connection with contracts concluded under these terms of use shall be the registered office of LAION.", + }, + ], + }, +]; + +export const TermsOfService = () => ( + + {TermsData.map((chapter, chapterIndex) => ( + + {chapter.sections && chapter.sections.length + ? chapter.sections.map((section, sectionIndex) => ) + : ""} + + ))} + +); diff --git a/website/src/components/ToSWrapper.tsx b/website/src/components/ToSWrapper.tsx index 98380ae0..e32509af 100644 --- a/website/src/components/ToSWrapper.tsx +++ b/website/src/components/ToSWrapper.tsx @@ -1,11 +1,11 @@ -import { Flex, Text } from "@chakra-ui/react"; +import { Box, Flex, Text } from "@chakra-ui/react"; import { useSession } from "next-auth/react"; import { useTranslation } from "next-i18next"; import { ReactNode, useMemo } from "react"; import { SubmitButton } from "src/components/Buttons/Submit"; import { SurveyCard } from "src/components/Survey/SurveyCard"; +import { TermsOfService } from "src/components/ToS"; import { post } from "src/lib/api"; -import { TermsOfService } from "src/pages/terms-of-service"; const navigateAway = () => { location.href = "https://laion.ai/"; @@ -21,29 +21,32 @@ export const ToSWrapper = ({ children }: { children?: ReactNode | undefined }) = const { data: session, status } = useSession(); const hasAcceptedTos = Boolean(session?.user.tosAcceptanceDate); const isLoading = status === "loading"; + const notLoggedIn = status === "unauthenticated"; const contents = useMemo( () => ( - - - {t("title")} - - {t("content")} - - - - {t("decline")} - - - {t("accept")} - - - + + + + {t("title")} + + {t("content")} + + + + {t("decline")} + + + {t("accept")} + + + + ), [t] ); - if (isLoading || hasAcceptedTos) { + if (notLoggedIn || isLoading || hasAcceptedTos) { return <>{children}; } return contents; diff --git a/website/src/pages/api/tos.ts b/website/src/pages/api/tos.ts index 125285a4..de6137f8 100644 --- a/website/src/pages/api/tos.ts +++ b/website/src/pages/api/tos.ts @@ -12,7 +12,6 @@ const handler = withoutRole("banned", async (req, res, token) => { await oasstApiClient.set_tos_acceptance(user); return res.status(200).end(); } - res.status(400).end(); }); diff --git a/website/src/pages/dashboard.tsx b/website/src/pages/dashboard.tsx index fdd562b3..44edae12 100644 --- a/website/src/pages/dashboard.tsx +++ b/website/src/pages/dashboard.tsx @@ -46,11 +46,9 @@ const Dashboard = () => { - - - - - + + + ); diff --git a/website/src/pages/terms-of-service.tsx b/website/src/pages/terms-of-service.tsx index 66a01bf1..a1e20fe2 100644 --- a/website/src/pages/terms-of-service.tsx +++ b/website/src/pages/terms-of-service.tsx @@ -1,177 +1,9 @@ -import { Box, Heading, Stack } from "@chakra-ui/react"; +import { Box, Heading } from "@chakra-ui/react"; import Head from "next/head"; import { getTransparentHeaderLayout } from "src/components/Layout"; -import { PolicyChapterCard } from "src/components/PolicyCards/PolicyChapterCard"; -import { PolicySectionCard } from "src/components/PolicyCards/PolicySectionCard"; +import { TermsOfService } from "src/components/ToS"; export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props"; -const TermsData = [ - { - number: "1", - title: "Scope of Application, Amendments", - desc: "", - sections: [ - { - number: "1.1", - title: "", - desc: `LAION e.V., Herman-Lange-Weg 26, 21035 Hamburg, Germany (hereinafter referred to as: "LAION") operates an online portal for the producing a machine learning model called Open Assistant using crowd-sourced data.`, - }, - { - number: "1.2", - title: "", - desc: "The present terms of use regulate the user relationship between the users of the portal and LAION.", - }, - { - number: "1.3", - title: "", - desc: "LAION reserves the right to amend these Terms of Use at any time, also with regard to persons already registered, if this becomes necessary due to changes in the law, changes in jurisdiction, changes in economic circumstances or gaps in these Terms of Use that subsequently become apparent. The user will be informed of such changes in good time by e-mail The user has the opportunity to object to the changes within 14 days of receipt of this e-mail. If the user does not object to the changes and continues to use the portal after expiry of the objection period, the changes shall be deemed to have been agreed effectively from the expiry of the period. If the user objects to the changes within the two-week period, LAION shall be entitled to exclude the user from using the portal. The user shall be informed of these effects once again in the e-mail.", - }, - ], - }, - { - number: "2", - title: "Subject of Use, Availability of the Service", - desc: "", - sections: [ - { - number: "2.1", - title: "", - desc: "The portal serves as a platform for creating data to train an interactive agent for scientific purposes. All text and prompt generated through the service are used for scientific purposes, in particular for the optimization of the AI.", - }, - { - number: "2.2", - title: "", - desc: "The input of texts on the portal and the subsequent generation of text by the artificial intelligence provided by the portal do not give rise to any works protected by copyright. The user who has entered the text for the generation of the text shall have neither the exclusive rights of use nor any rights of an author to the generated text.", - }, - { - number: "2.3", - title: "", - desc: "LAION shall endeavour to ensure that the portal can be used as uninterruptedly as possible. However, there shall be no legal claim to the use of the portal. LAION reserves the right, at its own discretion, to change the portal at any time and without notice, to discontinue its operation or to exclude individual users from using it. Furthermore, it cannot be ruled out that temporary restrictions or interruptions may occur due to technical faults (such as interruption of the power supply, hardware and software errors, technical problems in the data lines).", - }, - ], - }, - { - number: "3", - title: "User Obligations", - desc: "", - sections: [ - { - number: "3.1", - title: "", - desc: "The user may only use the portal for the intended purposes. In particular, he/she may not misuse the portal. The user undertakes to refrain from generating text that violate criminal law, youth protection regulations or the applicable laws of the following countries: Federal Republic of Germany, United States of America (USA), Great Britain, user's place of residence. In particular it is prohibited to enter texts that lead to the creation of pornographic, violence-glorifying or paedosexual content and/or content that violates the personal rights of third parties. LAION reserves the right to file a criminal complaint with the competent authorities in the event of violations.", - }, - { - number: "3.2", - title: "", - desc: "The user undertakes not to use any programs, algorithms or other software in connection with the use of the portal which could interfere with the functioning of the portal. Furthermore, the user shall not take any measures that may result in an unreasonable or excessive load on the infrastructure of the portal or may interfere with it in a disruptive manner.", - }, - { - number: "3.3", - title: "", - desc: "If a user notices obvious errors in the portal which could lead to misuse of the portal or the contents contained therein, the user shall be obliged to report the error to LAION without delay.", - }, - { - number: "3.4", - title: "", - desc: "The use, distribution, storage, forwarding, editing and/or other use of images that violate these terms of use is prohibited.", - }, - ], - }, - { - number: "4", - title: "Liability", - desc: "", - sections: [ - { - number: "4.1", - title: "", - desc: "LAION accepts no liability for the accuracy, completeness, reliability, up-to-dateness and usability of the content.", - }, - { - number: "4.2", - title: "", - desc: "LAION shall be liable without limitation for intent and gross negligence. In the case of simple negligence, LAION shall only be liable for damage resulting from injury to life, limb or health or an essential contractual obligation (obligation the fulfillment of which makes the proper performance of the contract possible in the first place and on the observance of which the contractual partner regularly trusts and may trust).", - }, - { - number: "4.3", - title: "", - desc: "In the event of a breach of material contractual obligations due to simple negligence, the liability of LAION shall be limited to the amount of the foreseeable, typically occurring damage. In all other respects liability shall be excluded.", - }, - { - number: "4.4", - title: "", - desc: "The above limitations of liability shall also apply in favour of the legal representatives and vicarious agents of LAION.", - }, - { - number: "4.5", - title: "", - desc: "LAION shall not be liable for the loss of data of the user. The user shall be solely responsible for the secure storage of his/her data.", - }, - { - number: "4.6", - title: "", - desc: "LAION shall not be liable for any damages incurred by the user as a result of the violation of these terms of use.", - }, - { - number: "4.7", - title: "", - desc: "LAION shall not be liable for the use of content generated on the portal by text input outside the portal. In particular, LAION shall not be liable for any damages incurred by the user due to the assumption of copyrights or exclusive rights of use.", - }, - ], - }, - { - number: "5", - title: "Data Protection", - desc: "", - sections: [ - { - number: "5.1", - title: "", - desc: "LAION processes the personal data of users in accordance with the provisions of data protection law. Detailed information can be found in the privacy policy, available at: /privacy-policy.", - }, - { - number: "5.2", - title: "", - desc: "The user expressly agrees that communication within the scope of and for the purpose of the user relationship between him/her and LAION may also take place via unencrypted e-mails. The user is aware that unencrypted e-mails only offer limited security and confidentiality.", - }, - ], - }, - { - number: "6", - title: "Final Provisions", - desc: "", - sections: [ - { - number: "6.1", - title: "", - desc: "The contractual relationship shall be governed exclusively by the law of the Federal Republic of Germany to the exclusion of the UN Convention on Contracts for the International Sale of Goods.", - }, - { - number: "6.2", - title: "", - desc: "Should individual provisions of these GTC including this provision be or become invalid in whole or in part, the validity of the remaining provisions shall remain unaffected. The invalid or missing provisions shall be replaced by the respective statutory provisions.", - }, - { - number: "6.3", - title: "", - desc: "If the customer is a merchant, a legal entity under public law or a special fund under public law, the place of jurisdiction for all disputes arising from and in connection with contracts concluded under these terms of use shall be the registered office of LAION.", - }, - ], - }, -]; - -export const TermsOfService = () => ( - - {TermsData.map((chapter, chapterIndex) => ( - - {chapter.sections && chapter.sections.length - ? chapter.sections.map((section, sectionIndex) => ) - : ""} - - ))} - -); - const TermsOfServicePage = () => { return ( <> From 0a6622179c59201d0d11bd155b1745dec006056a Mon Sep 17 00:00:00 2001 From: GuilleHoardings Date: Sun, 5 Feb 2023 14:17:46 +0100 Subject: [PATCH 074/152] Update Spanish locale for website (#1169) --- website/public/locales/es/common.json | 9 ++++++--- website/public/locales/es/message.json | 6 +++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/website/public/locales/es/common.json b/website/public/locales/es/common.json index 88d30517..7c7b60f5 100644 --- a/website/public/locales/es/common.json +++ b/website/public/locales/es/common.json @@ -2,13 +2,17 @@ "about": "Acerca de", "account_settings": "Cuenta", "admin_dashboard": "Panel de administración", + "copied": "Copiado", "connect": "Connectar", "conversational": "AI conversacional para todos.", + "dark_mode": "Modo oscuro", "dashboard": "Panel principal", + "delete": "Borrar", "discord": "Discord", "docs": "Documentación", "github": "GitHub", "legal": "Legal", + "light_mode": "Modo claro", "loading": "Cargando...", "more_information": "Más información", "no": "No", @@ -16,9 +20,8 @@ "report_a_bug": "Informar de un error", "sign_in": "Iniciar sesión", "sign_out": "Cerrar sesión", + "success": "Éxito", "terms_of_service": "Términos de servicio", "title": "Open Assistant", - "yes": "Sí", - "dark_mode": "Modo oscuro", - "light_mode": "Modo claro" + "yes": "Sí" } diff --git a/website/public/locales/es/message.json b/website/public/locales/es/message.json index 4fd2e58d..4d455034 100644 --- a/website/public/locales/es/message.json +++ b/website/public/locales/es/message.json @@ -1,16 +1,20 @@ { + "copy_message_id": "Copiar ID del mensaje", "label_action": "Etiquetar", "label_title": "Etiqueta", + "message_deleted": "Mensaje borrado", "message": "Mensaje", "open_new_tab_action": "Abrir en una pestaña nueva", "parent": "Padre", "reactions": "Reacciones", + "recent_messages": "Mensajes recientes", "report_action": "Reportar", "report_placeholder": "¿Por qué se debería revisar este mensaje?", "report_title": "Informe", "send_report": "Enviar", + "stop_tree": "Parar árbol", "submit_labels": "Enviar", + "tree_stopped": "Árbol parado {{id}}", "view_user": "Ver usuario", - "recent_messages": "Mensajes recientes", "your_recent_messages": "Tus mensajes recientes" } From 6fcc3176e4030d4885d193d2307a53833d312398 Mon Sep 17 00:00:00 2001 From: GuilleHoardings Date: Sun, 5 Feb 2023 14:22:58 +0100 Subject: [PATCH 075/152] Add to the FAQ questions that are asked in Discord frequently (#1165) --- docs/docs/faq/faq.md | 47 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/docs/docs/faq/faq.md b/docs/docs/faq/faq.md index 4b1d16eb..f2052102 100644 --- a/docs/docs/faq/faq.md +++ b/docs/docs/faq/faq.md @@ -104,3 +104,50 @@ ones excluding `5433`, like: 5. Add `- POSTGRES_PORT=5432` to `backend.environment` 6. Change `web.environment.DATABASE_URL` to `postgres://postgres:postgres@webdb:5432/oasst_web` + +### Can I use ChatGPT to help in training Open Assistant, for instance, by generating answers? + +No, it is against their terms of service to use it to help train other models. +See +[this issue](https://github.com/LAION-AI/Open-Assistant/issues/471#issuecomment-1374392299). + +### How can I see my score? + +If you are not in the top 100 positions and cannot find yourself in the +leaderboard, it's not possible at the moment. + +### Can we see how many data points have been collected? + +Not right now. + +### Can I install Open Assistant locally and chat with it? + +The project is not at that stage yet. + +### Is the model open? + +The model is not ready yet, but there are some demo models. You can follow the +discussion in the Discord channel +[#ml-models-demo](https://discord.com/channels/1055935572465700980/1067096888530178048). + +### Which base model will be used? + +It's still being discussed. You can follow the discussion in the Discord channel +[#data-discussion](https://discord.com/channels/1055935572465700980/1058348535612985394). + +### What should I do if I don't know how to complete the task as an assistant? + +Skip it. + +### Should I fact check the answers by the assistant? + +Yes, you should try. If you are not sure, skip the task. + +### How can I contribute? + +If you want to help in the data collection, go to the website +[https://open-assistant.io/](https://open-assistant.io/). If you want to +contribute code, take a look at the +[issues in GitHub](https://github.com/LAION-AI/Open-Assistant/issues) and grab +one. Take a look at this +[contributing guide](https://github.com/GuilleHoardings/Open-Assistant/blob/main/CONTRIBUTING.md). From 14b41b4a2d8c341886a0fab067b40dc2dcd42b0b Mon Sep 17 00:00:00 2001 From: Theodor Peifer Date: Sun, 5 Feb 2023 15:34:47 +0100 Subject: [PATCH 076/152] Putting a button for toggling the light/dark color mode right into the navigation bar (#1122) * added button for toggling color mode in nav bar * removed border from color-theme toggle button * removed padding around sun icon and made header title slighty responsive * lower gap between navigation buttons for mobile --- website/src/components/Header/ColorModeToggler.jsx | 14 ++++++++++++++ website/src/components/Header/Header.tsx | 7 ++++--- 2 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 website/src/components/Header/ColorModeToggler.jsx diff --git a/website/src/components/Header/ColorModeToggler.jsx b/website/src/components/Header/ColorModeToggler.jsx new file mode 100644 index 00000000..69ede901 --- /dev/null +++ b/website/src/components/Header/ColorModeToggler.jsx @@ -0,0 +1,14 @@ +import { Button, useColorMode } from "@chakra-ui/react"; +import { Sun } from "lucide-react"; + +const ColorModeToggler = () => { + const { colorMode, toggleColorMode } = useColorMode(); + + return ( + + ); +}; + +export { ColorModeToggler }; diff --git a/website/src/components/Header/Header.tsx b/website/src/components/Header/Header.tsx index 0d70a442..c1c88655 100644 --- a/website/src/components/Header/Header.tsx +++ b/website/src/components/Header/Header.tsx @@ -6,7 +6,7 @@ import { useSession } from "next-auth/react"; import { useTranslation } from "next-i18next"; import { Flags } from "react-feature-flags"; import { LanguageSelector } from "src/components/LanguageSelector"; - +import { ColorModeToggler } from "./ColorModeToggler"; import { UserMenu } from "./UserMenu"; function AccountButton() { @@ -36,19 +36,20 @@ export function Header() { logo - + {t("title")} - + FlagTest + From 9c7ced59bb718eb9d521133c853d526d9b15869a Mon Sep 17 00:00:00 2001 From: Oliver Stanley Date: Sun, 5 Feb 2023 15:29:46 +0000 Subject: [PATCH 077/152] Update get user stats to include necessary fields (#1177) --- backend/oasst_backend/user_stats_repository.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/backend/oasst_backend/user_stats_repository.py b/backend/oasst_backend/user_stats_repository.py index cca0d6bf..b5646d5a 100644 --- a/backend/oasst_backend/user_stats_repository.py +++ b/backend/oasst_backend/user_stats_repository.py @@ -158,7 +158,16 @@ class UserStatsRepository: def get_user_stats_all_time_frames(self, user_id: UUID) -> dict[str, UserScore | None]: qry = ( - self.session.query(User.id.label("user_id"), User.username, User.auth_method, User.display_name, UserStats) + self.session.query( + User.id.label("user_id"), + User.username, + User.auth_method, + User.display_name, + User.streak_days, + User.streak_last_day_date, + User.last_activity_date, + UserStats, + ) .outerjoin(UserStats, User.id == UserStats.user_id) .filter(User.id == user_id) ) From dfda94f178acfc5dca2870db7032fe7412431a92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=B6pf?= Date: Sun, 5 Feb 2023 17:54:27 +0100 Subject: [PATCH 078/152] add some sql snippets for db state inspection --- backend/sql_snippets.md | 142 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 backend/sql_snippets.md diff --git a/backend/sql_snippets.md b/backend/sql_snippets.md new file mode 100644 index 00000000..fac9d7f2 --- /dev/null +++ b/backend/sql_snippets.md @@ -0,0 +1,142 @@ +# Collection of SQL Snippets + +Here are find some SQL queries to inspect the current OA postgres DB. + +# Baics Stats + +```sql +-- tables row counts +(select 'user' as "table", count(*) from "user") union +(select 'task', count(*) from task) union +(select 'message_tree_state', count(*) from message_tree_state) union +(select 'message_reaction', count(*) from message_reaction) union +(select 'text_labels', count(*) from text_labels) union +(select 'message', count(*) from message) union +(select 'journal', count(*) from journal); +``` + +# Messages + +```sql +-- only human by role +select role, count(*) +from message +where not deleted and review_result and not synthetic +group by role; +``` + +```sql +-- language distribution of messages (incl. synthetic) +select lang, count(*), synthetic from message where not deleted and review_result +group by lang, synthetic; +``` + +```sql +-- only human generated messages by lang +select lang, count(*) +from message +where not deleted and review_result and not synthetic +group by lang; +``` + +## Message Trees + +```sql +-- total count of message trees +select count(*) from message_tree_state; +``` + +```sql +-- message tree counts by state +select state, count(*) from message_tree_state group by state; +``` + +```sql +-- count of waiting initial prompts by language +select m.lang, count(*) from message_tree_state mts join message m on mts.message_tree_id = m.id where mts.state = 'prompt_lottery_waiting' group by m.lang; +``` + +```sql +-- select message tree counts +select mts.message_tree_id, count(m.id), max(m.depth), count(m.id) filter (where m.role='prompter') as prompter, count(m.id) filter (where m.role='assistant') as assistant +from message_tree_state mts + join message m on mts.message_tree_id = m.message_tree_id +where mts.state='growing' + and not m.deleted + and m.review_result=true + and m.lang='en' + and mts.active +group by mts.message_tree_id +order by count(m.id) desc; +``` + +```sql +-- show top 100 largest trees +select mts.message_tree_id, mts.goal_tree_size, mts.state, count(m.id) as message_count +from message_tree_state mts + join message m on mts.message_tree_id = m.message_tree_id +where not m.deleted and m.review_result=true +group by mts.message_tree_id, mts.state +order by count(m.id) desc +limit 100; +``` + +```sql +-- active trees, current & goal_size +select mts.message_tree_id, mts.state, mts.goal_tree_size, count(m.id) AS tree_size, max(m.depth) AS max_depth +from message_tree_state mts + join message m ON mts.message_tree_id = m.message_tree_id +WHERE mts.active + and not m.deleted + and m.review_result +group by mts.message_tree_id, mts.goal_tree_size; +``` + +## Users + +```sql +-- count users that accepted tos +select count(*) from "user" where tos_acceptance_date is not null; +``` + +```sql +-- last 25 active users +select u.id, u.username, u.auth_method, u.display_name, u.last_activity_date, age(current_timestamp, last_activity_date) from "user" u WHERE u.last_activity_date is not null order by u.last_activity_date desc limit 25; + +select id, display_name, username, auth_method, last_activity_date from "user" where age(last_activity_date) < interval '1 minutes' order by last_activity_date desc limit 25; +``` + +```sql +-- count active users in last 5 mins +select count(*) from "user" u where age(current_timestamp, last_activity_date) < interval '5 mins'; + +``` + +```sql +-- total count of non-deleted messages (human + synth) +select count(*) from message where deleted=false and review_result=true; +``` + +```sql +-- count max, mean message counts per tree for a given language +with t(message_tree_id, tree_size, state) as (select mts.message_tree_id, count(m.id), mts.state +from message_tree_state mts + join message m on mts.message_tree_id = m.message_tree_id +where + not m.deleted + and m.review_result=true + and m.lang = 'en' +group by mts.message_tree_id) +select state, count(t.*) as trees, sum(t.tree_size) as total_msgs, max(t.tree_size), avg(t.tree_size) from t group by t.state; +``` + +## Connections + +```sql +-- from https://dba.stackexchange.com/questions/161760/number-of-active-connections-and-remaining-connections +select max_conn,used,res_for_super,max_conn-used-res_for_super res_for_normal +from + (select count(*) used from pg_stat_activity) t1, + (select setting::int res_for_super from pg_settings where name=$$superuser_reserved_connections$$) t2, + (select setting::int max_conn from pg_settings where name=$$max_connections$$) t3; +``` From 45637dfd51cd6088e4f590521c99edcbc0213c2f Mon Sep 17 00:00:00 2001 From: swaptr <83858160+swaptr@users.noreply.github.com> Date: Mon, 6 Feb 2023 00:27:35 +0530 Subject: [PATCH 079/152] remove theme button from sidebar (#1181) * remove theme button from sidebar Now that the theme switch button is moved to navbar, we can remove this button. * fix responsiveness --- website/src/components/SideMenu.tsx | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/website/src/components/SideMenu.tsx b/website/src/components/SideMenu.tsx index 1c5bac38..45ae0933 100644 --- a/website/src/components/SideMenu.tsx +++ b/website/src/components/SideMenu.tsx @@ -24,7 +24,7 @@ export function SideMenu(props: SideMenuProps) { -
- - - -
); From 45444d9c6226238450dbbeb4bbbab069ec10f83e Mon Sep 17 00:00:00 2001 From: Eren Akbulut Date: Sun, 5 Feb 2023 20:04:50 +0100 Subject: [PATCH 080/152] Turkish Language support (#1195) * Turkish Language support * Turkish Language keycode --- website/next-i18next.config.js | 2 +- website/public/locales/tr/common.json | 27 +++++++ website/public/locales/tr/dashboard.json | 8 +++ website/public/locales/tr/index.json | 15 ++++ website/public/locales/tr/labelling.json | 24 +++++++ website/public/locales/tr/leaderboard.json | 18 +++++ website/public/locales/tr/message.json | 20 ++++++ website/public/locales/tr/side_menu.json | 12 ++++ website/public/locales/tr/tasks.json | 82 ++++++++++++++++++++++ website/public/locales/tr/tos.json | 6 ++ 10 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 website/public/locales/tr/common.json create mode 100644 website/public/locales/tr/dashboard.json create mode 100644 website/public/locales/tr/index.json create mode 100644 website/public/locales/tr/labelling.json create mode 100644 website/public/locales/tr/leaderboard.json create mode 100644 website/public/locales/tr/message.json create mode 100644 website/public/locales/tr/side_menu.json create mode 100644 website/public/locales/tr/tasks.json create mode 100644 website/public/locales/tr/tos.json diff --git a/website/next-i18next.config.js b/website/next-i18next.config.js index efa84ef6..38c0ad0a 100644 --- a/website/next-i18next.config.js +++ b/website/next-i18next.config.js @@ -1,6 +1,6 @@ module.exports = { i18n: { defaultLocale: "en", - locales: ["bn", "de", "en", "es", "fr", "hu", "ja", "ko", "pt-BR", "ru", "vi", "zh"], + locales: ["bn", "de", "en", "es", "fr", "hu", "ja", "ko", "pt-BR", "ru", "vi", "zh", "tr"], }, }; diff --git a/website/public/locales/tr/common.json b/website/public/locales/tr/common.json new file mode 100644 index 00000000..6eefd3a3 --- /dev/null +++ b/website/public/locales/tr/common.json @@ -0,0 +1,27 @@ +{ + "about": "Hakkında", + "account_settings": "Hesap", + "admin_dashboard": "Yönetici Paneli", + "copied": "Kopyalandı", + "connect": "Bağlan", + "conversational": "Herkes için etkileşimli AI", + "dark_mode": "Karanlık Mod", + "dashboard": "Kontrol Paneli", + "delete": "Sil", + "discord": "Discord", + "docs": "Dokümantasyon", + "github": "GitHub", + "legal": "Yasal", + "light_mode": "Açık Mod", + "loading": "Yükleniyor...", + "more_information": "Daha Fazla Bilgi", + "no": "No", + "privacy_policy": "Gizlilik Politikası", + "report_a_bug": "Hata Bildir", + "sign_in": "Giriş Yap", + "sign_out": "Çıkış Yap", + "success": "Başarılı", + "terms_of_service": "Kullanım Şartları", + "title": "Open Assistant", + "yes": "Evet" +} diff --git a/website/public/locales/tr/dashboard.json b/website/public/locales/tr/dashboard.json new file mode 100644 index 00000000..01ce0d2b --- /dev/null +++ b/website/public/locales/tr/dashboard.json @@ -0,0 +1,8 @@ +{ + "grab_a_task": "Bir görev al!", + "create": "Oluştur", + "evaluate": "Değerlendir", + "label": "Etiketle", + "dashboard": "Kontrol Paneli", + "go": "Başlat" +} diff --git a/website/public/locales/tr/index.json b/website/public/locales/tr/index.json new file mode 100644 index 00000000..a3d83b48 --- /dev/null +++ b/website/public/locales/tr/index.json @@ -0,0 +1,15 @@ +{ + "blurb": "Bir devrim yaratabileceğimize inanıyoruz.", + "blurb1": "Stable Diffusion Dünyaya sanat ve görsel oluşturmak için nasıl yardımcı olduysa, biz de Dünyayı inanılmaz etkileşimli AI sunarak ileri götürmeyi istiyoruz.", + "description": "Herkes için etkileşimli AI. LAION ve dünyanın her yerinden insanlar tarafından geliştirilen, sohbete olanak sağlanayan GPT LLM oluşturmak için başlanmış açık kaynak bir proje.", + "faq_items": { + "q0": "Proje ne kadar ilerledi?", + "a0": "Geliştirmenin erken aşamalarındayız, RLHF tekniklerini büyük dil modellerine uygulama konusunda yer edinmiş araştırmaları temel alıyoruz.", + "q1": "Open Assistant'ın arkasında kim var?", + "a1": "Open Assistant LAION ve dünyanın her yerinden bu teknolojiyi herkese ulaştırmakla ilgilenen bireyler tarafından organize edilmiş bir proje" + }, + "faq_title": "Sıkça Sorulan Sorular", + "join_us_description": "Bütün açık kaynak projeler senin gibi insanlarla başlar. Açık kaynak, eğer iş birliğinde bulunursak birlikte insanlığın iyiliği için Dünyaya bilgi ve teknoloji hediye edebileceğimize dair inançtır. Bizimle misin? Buradan iletişime geç:", + "join_us_title": "Bize katıl", + "subtitle": "Herkes için etkileşimli AI." +} diff --git a/website/public/locales/tr/labelling.json b/website/public/locales/tr/labelling.json new file mode 100644 index 00000000..6bf5db0e --- /dev/null +++ b/website/public/locales/tr/labelling.json @@ -0,0 +1,24 @@ +{ + "label_highlighted_yes_no_instruction": "Vurgulanan mesaj hakkındaki soruları cevaplayın:", + "label_highlighted_flag_instruction": "Vurgulanan mesajla uyuşanları seçin:", + "label_highlighted_likert_instruction": "Vurgulanan mesajı değerlendirin:", + "label_message_yes_no_instruction": "Mesaj hakkındaki soruları cevaplayın:", + "label_message_flag_instruction": "Mesajla uyuşanları seçin:", + "label_message_likert_instruction": "Mesajı değerlendirin:", + "spam.question": "Bu mesaj spam mı?", + "fails_task.question": "Sorulan soruya göre kötü bir cevap mı?", + "not_appropriate": "Uygunsuz", + "not_appropriate.explanation": "Bir tüketici asistanı için uygunsuz", + "pii": "PII İçeriyor", + "pii.explanation": "Kişilik özelliklerini ortaya çıkaran bilgi (PII) içeriyor. Kişisel iletişim bilgileri, kimlik bilgileri ve diğer kişisel bilgiler ve bancakılık bilgileri buna örnek olabilir.", + "hate_speech": "Nefret Söylemi", + "hate_speech.explanation": "İçerik taciz veya tehdit edici ve korunan bir özelliğe karşı önyargı ifade ediyor. Önyargı, nedenselliğe dayanmayan önyargılı görüşleri ifade eder. Korunan karakteristikler cinsiyet, etnik köken, din, cinsel yönelim ve benzeri özellikleri içerir.", + "sexual_content": "Cinsel İçerik", + "sexual_content.explanation": "Cinsel içerik içeriyor.", + "moral_judgement": "Ahlaki Yargı", + "moral_judgement.explanation": "Ahlaki yargı içeriyor.", + "political_content": "Politik İçerik", + "political_content.explanation": "Politik görüş içeriyor.", + "lang_mismatch": "Yanlış Dil", + "lang_mismatch.explanation": "Seçilen dilde yazılmamış." +} diff --git a/website/public/locales/tr/leaderboard.json b/website/public/locales/tr/leaderboard.json new file mode 100644 index 00000000..ad59e068 --- /dev/null +++ b/website/public/locales/tr/leaderboard.json @@ -0,0 +1,18 @@ +{ + "daily": "Günlük", + "last_updated_at": "Son güncelleme: {{val, datetime}}", + "leaderboard": "Skor Tablosu", + "monthly": "Aylık", + "overall": "Genel", + "rank": "Sıralama", + "score": "Skor", + "user": "Kullanıcı", + "weekly": "Haftalık", + "prompt": "Promptlar", + "reply": "Cevaplar", + "label": "Etiketler", + "view_all": "Tümünü Gör", + "top_5_contributors_today": "Bugünün En İyi 5 Katkıda Bulunanı", + "previous": "İleri", + "next": "Geri" +} diff --git a/website/public/locales/tr/message.json b/website/public/locales/tr/message.json new file mode 100644 index 00000000..a8db8bcf --- /dev/null +++ b/website/public/locales/tr/message.json @@ -0,0 +1,20 @@ +{ + "copy_message_id": "Mesaj ID'sini kopyala", + "label_action": "Etiket", + "label_title": "Etiket", + "message_deleted": "Mesaj silindi", + "message": "Mesaj", + "open_new_tab_action": "Yeni sekmede aç", + "parent": "Üst", + "reactions": "Reaksiyonlar", + "recent_messages": "Son Mesajlar", + "report_action": "Raporla", + "report_placeholder": "Bu mesaj neden incelenmeli?", + "report_title": "Mesajı raporla", + "send_report": "Gönder", + "stop_tree": "Ağacı durdur", + "submit_labels": "Gönder", + "tree_stopped": "Ağaç durduruldu {{id}}", + "view_user": "Kullanıcıyı görüntüle", + "your_recent_messages": "Son mesajlarınız" +} diff --git a/website/public/locales/tr/side_menu.json b/website/public/locales/tr/side_menu.json new file mode 100644 index 00000000..e963ff61 --- /dev/null +++ b/website/public/locales/tr/side_menu.json @@ -0,0 +1,12 @@ +{ + "dashboard": "Kontrol Paneli", + "dashboard_home": "Kontrol Paneli Ana Sayfa", + "messages": "Mesajlar", + "messages_dashboard": "Mesaj Kontrol Paneli", + "leaderboard": "Lider Tablosu", + "user_leaderboard": "Kullanıcı Lider Tablosu", + "users": "Kullanıcılar", + "users_dashboard": "Kullanıcı Kontrol Paneli", + "status": "Durum", + "status_dashboard": "Durum Kontrol Paneli" +} diff --git a/website/public/locales/tr/tasks.json b/website/public/locales/tr/tasks.json new file mode 100644 index 00000000..0e7a53d4 --- /dev/null +++ b/website/public/locales/tr/tasks.json @@ -0,0 +1,82 @@ +{ + "default": { + "unchanged_title": "Değişiklik yok", + "unchanged_message": "Devam etmek istediğinizden emin misiniz?" + }, + "random": { + "label": "Şanslı hissediyorum", + "desc": "Open Assistant'ı geliştirmemize yardımcı olmak için rastgele bir göreve başlayın." + }, + "create_initial_prompt": { + "label": "Başlangıc Promptlarını Oluştur", + "desc": "Open Assistant'a çeşitli mesajlara yanıt vermek için başlangıç ​​promptlarını yazın. (çekilişe katılın)", + "overview": "Asistan'a gönderilecek başlangıç ​​mesajını oluşturun", + "instruction": "Başlangıç ​​promptlarını sağlayın", + "response_placeholder": "Promptunuzu buraya yazın..." + }, + "reply_as_user": { + "label": "Kullanıcı Olarak Yanıtla", + "desc": "Open Assistant ile sohbet edin ve onunla etkileşimde bulunurken yanıtlarını geliştirmeye yardımcı olun.", + "overview": "Aşağıdaki konuşmaya göre uygun bir yanıt verin", + "instruction": "Kullanıcının yanıtını paylaşın", + "response_placeholder": "Yanıtınızı buraya yazın..." + }, + "reply_as_assistant": { + "label": "Asistan Olarak Yanıtla", + "desc": "Open Asistant'a kullanıcılar ile iletişim kurmasını geliştirmesinde yardımcı olun.", + "overview": "Aşağıdaki konuşmaya göre uygun bir yanıt verin", + "response_placeholder": "Yanıtınızı buraya yazın..." + }, + "rank_user_replies": { + "label": "Kullanıcı Yanıtlarını Değerlendir", + "desc": "Open Asistant'a kullanıcılar ile iletişim kurmasını geliştirmesinde yardımcı olun..", + "overview": "Aşağıdaki kullanıcı yanıtlarını en iyiden en kötüye doğru sıralayın, en iyi ilk, en kötü son.", + "unchanged_title": "Sıralama Değişmedi", + "unchanged_message": "Yanıtların sırasını değiştirmediniz. Devam etmek istediğinizden emin misiniz?" + }, + "rank_assistant_replies": { + "label": "Asistant Yanıtlarını Değerlendir", + "desc": "Open Asistant tarafından verilen promptları okunabilirlik ve doğruluk hassasiyeti açısından değerlendirin", + "overview": "Aşağıdaki asistan yanıtlarını en iyiden en kötüye doğru sıralayın, en iyi ilk, en kötü son.", + "unchanged_title": "Sıralama Değişmedi", + "unchanged_message": "Yanıtların sırasını değiştirmediniz. Devam etmek istediğinizden emin misiniz?" + }, + "rank_initial_prompts": { + "label": "Başlangıç Promptlarını Değerlendir", + "desc": "Open Asistant tarafından verilen promptları okunabilirlik ve doğruluk hassasiyeti açısından değerlendirin", + "overview": "Aşağıdaki başlangıç promptlarını en iyiden en kötüye doğru sıralayın, en iyi ilk, en kötü son.", + "unchanged_title": "Sıralama Değişmedi", + "unchanged_message": "Yanıtların sırasını değiştirmediniz. Devam etmek istediğinizden emin misiniz?" + }, + "label_initial_prompt": { + "label": "Başlangıç Promptlarını Etiketle", + "desc": "Prompt için etiketler sağlayın", + "overview": "Aşağıdaki prompt için etiketler sağlayın" + }, + "label_prompter_reply": { + "label": "Promptçu Yanıtını Etiketle", + "desc": "Prompt için etiketler sağlayın", + "overview": "Takip eden konuşmalar göz önünde bulundurularak son prompt için etiket sağlayın." + }, + "label_assistant_reply": { + "label": "Asistan Yanıtını Etiketle", + "desc": "Prompt için etiketler sağlayın.", + "overview": "Takip eden konuşmalar göz önünde bulundurularak son prompt için etiket sağlayın." + }, + "classify_initial_prompt": { + "label": "Başlangıç Promptlarını Sınıflandır", + "desc": "Prompt için etiketler sağlayın", + "overview": "Aşağıdaki promptu oku ve sonraki soruya cevap ver." + }, + "classify_prompter_reply": { + "label": "Promptçu Yanıtını Sınıflandır", + "desc": "Prompt için etiketler sağlayın", + "overview": "Aşağıdaki konuşmayı oku ve tartışma kısmındaki son soruya cevap ver." + }, + "classify_assistant_reply": { + "label": "Asistan Yanıtını Sınıflandır", + "desc": "Prompt için etiketler sağlayın", + "overview": "Aşağıdaki konuşmayı oku ve tartışma kısmındaki son soruya cevap ver." + }, + "available_task_count": "{{count}} görev mevcut" +} diff --git a/website/public/locales/tr/tos.json b/website/public/locales/tr/tos.json new file mode 100644 index 00000000..8d0a0797 --- /dev/null +++ b/website/public/locales/tr/tos.json @@ -0,0 +1,6 @@ +{ + "title": "Open Assistant için Kullanım Şartları", + "content": "Open Assistant'ı kullanmaya devam etmek için ilk önce Kullanım Şartları'nı kabul etmeniz gerekmektedir.", + "accept": "Kabul Et", + "decline": "Reddet" +} From 364a4f5aa3e12ae5dd3720cb856c5d39d7db4b1c Mon Sep 17 00:00:00 2001 From: notmd <33456881+notmd@users.noreply.github.com> Date: Mon, 6 Feb 2023 02:17:28 +0700 Subject: [PATCH 081/152] Highlight current user in leaderboard (#1194) * Highlight current user in leaderboard * use first of type for ssr safety --- website/src/components/DataTable.tsx | 26 +++++++++----- .../LeaderboardTable/LeaderboardTable.tsx | 35 +++++++++++++++++-- website/src/types/Leaderboard.ts | 1 + 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/website/src/components/DataTable.tsx b/website/src/components/DataTable.tsx index d9161e19..c724ada5 100644 --- a/website/src/components/DataTable.tsx +++ b/website/src/components/DataTable.tsx @@ -15,6 +15,7 @@ import { Table, TableCaption, TableContainer, + TableRowProps, Tbody, Td, Th, @@ -22,9 +23,9 @@ import { Tr, useDisclosure, } from "@chakra-ui/react"; -import { useTranslation } from "next-i18next"; -import { ColumnDef, flexRender, getCoreRowModel, useReactTable } from "@tanstack/react-table"; +import { ColumnDef, flexRender, getCoreRowModel, Row, useReactTable } from "@tanstack/react-table"; import { Filter } from "lucide-react"; +import { useTranslation } from "next-i18next"; import { ChangeEvent, ReactNode } from "react"; import { useDebouncedCallback } from "use-debounce"; @@ -38,6 +39,8 @@ export type FilterItem = { value: string; }; +export type DataTableRowPropsCallback = (row: Row) => TableRowProps; + export type DataTableProps = { data: T[]; columns: DataTableColumnDef[]; @@ -49,6 +52,7 @@ export type DataTableProps = { disableNext?: boolean; disablePrevious?: boolean; disablePagination?: boolean; + rowProps?: TableRowProps | DataTableRowPropsCallback; }; export const DataTable = ({ @@ -62,6 +66,7 @@ export const DataTable = ({ disableNext, disablePrevious, disablePagination, + rowProps, }: DataTableProps) => { const { t } = useTranslation("leaderboard"); const { getHeaderGroups, getRowModel } = useReactTable({ @@ -117,13 +122,16 @@ export const DataTable = ({ ))} - {getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - {flexRender(cell.column.columnDef.cell, cell.getContext())} - ))} - - ))} + {getRowModel().rows.map((row) => { + const props = typeof rowProps === "function" ? rowProps(row) : rowProps; + return ( + + {row.getVisibleCells().map((cell) => ( + {flexRender(cell.column.columnDef.cell, cell.getContext())} + ))} + + ); + })} diff --git a/website/src/components/LeaderboardTable/LeaderboardTable.tsx b/website/src/components/LeaderboardTable/LeaderboardTable.tsx index 3b6aafcd..6314080c 100644 --- a/website/src/components/LeaderboardTable/LeaderboardTable.tsx +++ b/website/src/components/LeaderboardTable/LeaderboardTable.tsx @@ -1,12 +1,13 @@ -import { CircularProgress } from "@chakra-ui/react"; +import { CircularProgress, useColorModeValue, useToken } from "@chakra-ui/react"; import { createColumnHelper } from "@tanstack/react-table"; import { useTranslation } from "next-i18next"; -import React, { useMemo, useState } from "react"; +import React, { useCallback, useMemo, useState } from "react"; import { get } from "src/lib/api"; +import { colors } from "src/styles/Theme/colors"; import { LeaderboardEntity, LeaderboardReply, LeaderboardTimeFrame } from "src/types/Leaderboard"; import useSWRImmutable from "swr/immutable"; -import { DataTable } from "../DataTable"; +import { DataTable, DataTableRowPropsCallback } from "../DataTable"; const columnHelper = createColumnHelper(); @@ -23,6 +24,7 @@ export const LeaderboardTable = ({ rowPerPage: number; }) => { const { t } = useTranslation("leaderboard"); + const { data: reply, isLoading, @@ -66,6 +68,32 @@ export const LeaderboardTable = ({ return reply?.leaderboard.slice(start, start + rowPerPage) || []; }, [rowPerPage, page, reply?.leaderboard]); + const borderColor = useToken("colors", useColorModeValue(colors.light.active, colors.dark.active)); + const rowProps = useCallback>( + (row) => { + return row.original.highlighted + ? { + sx: { + // https://stackoverflow.com/questions/37963524/how-to-apply-border-radius-to-tr-in-bootstrap + position: "relative", + "td:first-of-type:before": { + borderLeft: `6px solid ${borderColor}`, + content: `""`, + display: "block", + width: "10px", + height: "100%", + left: 0, + top: 0, + borderRadius: "6px 0 0 6px", + position: "absolute", + }, + }, + } + : {}; + }, + [borderColor] + ); + if (isLoading) { return ; } @@ -86,6 +114,7 @@ export const LeaderboardTable = ({ disablePrevious={page === 1} onNextClick={() => setPage((p) => p + 1)} onPreviousClick={() => setPage((p) => p - 1)} + rowProps={rowProps} > ); }; diff --git a/website/src/types/Leaderboard.ts b/website/src/types/Leaderboard.ts index 5c0acfc3..b806ac95 100644 --- a/website/src/types/Leaderboard.ts +++ b/website/src/types/Leaderboard.ts @@ -40,4 +40,5 @@ export interface LeaderboardEntity { reply_ranked_3: number; streak_last_day_date: number | null; streak_days: number | null; + highlighted: boolean; } From 1e321a6fca8e88524d93849f853e9cdcff0f11d0 Mon Sep 17 00:00:00 2001 From: Kian-Meng Ang Date: Mon, 6 Feb 2023 03:18:03 +0800 Subject: [PATCH 082/152] Fix typos (#1143) Found via `codespell -S .mypy_cache,yarn.lock,*.json,*.ipynb -L rouge,nam,vie` --- ansible/README.md | 2 +- backend/oasst_backend/api/v1/hugging_face.py | 2 +- backend/oasst_backend/config.py | 4 ++-- backend/oasst_backend/models/message_tree_state.py | 6 +++--- backend/oasst_backend/prompt_repository.py | 2 +- backend/oasst_backend/task_repository.py | 2 +- backend/oasst_backend/tree_manager.py | 12 ++++++------ backend/oasst_backend/utils/ranking.py | 2 +- copilot/README.md | 2 +- docs/docs/data/schemas.mdx | 2 +- docs/docs/data/supervised-datasets.md | 10 +++++----- model/reward/instructor/TODO.md | 2 +- model/reward/instructor/rank_datasets.py | 2 +- .../supervised_finetuning/custom_datasets/README.md | 2 +- .../custom_datasets/qa_datasets.py | 2 +- .../closed-book-qa/T5_closed_book_QA_generators.py | 4 ++-- .../stackexchange-builder/README.md | 2 +- notebooks/detoxify-evaluation/README.md | 2 +- notebooks/example/README.md | 2 +- .../oasst_shared/exceptions/oasst_api_error.py | 2 +- scripts/data-collection/twitter/README.md | 4 ++-- .../data-collection/twitter/twitter_process_json.py | 2 +- scripts/data_augment/data_augment.py | 4 ++-- scripts/postprocessing/rankings.py | 2 +- scripts/postprocessing/scoring.py | 6 +++--- scripts/postprocessing/task_schedule.py | 2 +- text-frontend/auto_main.py | 4 ++-- website/cypress/README.md | 2 +- website/src/components/Survey/LabelLikertGroup.tsx | 2 +- website/src/hooks/tasks/useGenericTaskAPI.tsx | 2 +- website/src/pages/api/update_task.ts | 2 +- website/src/test_pages/README.md | 2 +- 32 files changed, 50 insertions(+), 50 deletions(-) diff --git a/ansible/README.md b/ansible/README.md index 2ab1943e..e4b7536e 100644 --- a/ansible/README.md +++ b/ansible/README.md @@ -1,6 +1,6 @@ To test the ansible playbook on localhost run `ansible-playbook -i test.inventory.ini dev.yaml`.\ -In case you're missing the ansible docker depencency install it with `ansible-galaxy collection install community.docker`.\ +In case you're missing the ansible docker dependency install it with `ansible-galaxy collection install community.docker`.\ Point Redis Insights to the Redis database by visiting localhost:8001 in a browser and select "I already have a database" followed by "Connect to a Redis Database".\ diff --git a/backend/oasst_backend/api/v1/hugging_face.py b/backend/oasst_backend/api/v1/hugging_face.py index a6715574..8837e0df 100644 --- a/backend/oasst_backend/api/v1/hugging_face.py +++ b/backend/oasst_backend/api/v1/hugging_face.py @@ -18,7 +18,7 @@ async def get_text_toxicity( Args: msg (str): the message that we want to analyze. - api_client (ApiClient, optional): authentification of the user of the request. + api_client (ApiClient, optional): authentication of the user of the request. Defaults to Depends(deps.get_trusted_api_client). Returns: diff --git a/backend/oasst_backend/config.py b/backend/oasst_backend/config.py index 6ff727de..2a21b3ec 100644 --- a/backend/oasst_backend/config.py +++ b/backend/oasst_backend/config.py @@ -14,7 +14,7 @@ class TreeManagerConfiguration(BaseModel): number is reached.""" max_initial_prompt_review: int = 100 - """Maximum number of initial prompts under review before no more inital prompt tasks will be handed out.""" + """Maximum number of initial prompts under review before no more initial prompt tasks will be handed out.""" max_tree_depth: int = 3 """Maximum depth of message tree.""" @@ -75,7 +75,7 @@ class TreeManagerConfiguration(BaseModel): min_active_rankings_per_lang: int = 0 """When the number of active ranking tasks is below this value when a tree enters a terminal - state an available trees in BACKLOG_RANKING will be actived (i.e. enters the RANKING state).""" + state an available trees in BACKLOG_RANKING will be activated (i.e. enters the RANKING state).""" labels_initial_prompt: list[TextLabel] = [ TextLabel.spam, diff --git a/backend/oasst_backend/models/message_tree_state.py b/backend/oasst_backend/models/message_tree_state.py index 199f475b..4f69acfd 100644 --- a/backend/oasst_backend/models/message_tree_state.py +++ b/backend/oasst_backend/models/message_tree_state.py @@ -12,7 +12,7 @@ class State(str, Enum): """States of the Open-Assistant message tree state machine.""" INITIAL_PROMPT_REVIEW = "initial_prompt_review" - """In this state the message tree consists only of a single inital prompt root node. + """In this state the message tree consists only of a single initial prompt root node. Initial prompt labeling tasks will determine if the tree goes into `growing` or `aborted_low_grade` state.""" @@ -33,11 +33,11 @@ class State(str, Enum): compute the aggergated ranking scores that will appear in the dataset.""" READY_FOR_EXPORT = "ready_for_export" - """The Scoring algorithm computed rankings scores for all childern. The message tree can be + """The Scoring algorithm computed rankings scores for all children. The message tree can be exported as part of an Open-Assistant message tree dataset.""" SCORING_FAILED = "scoring_failed" - """An exception occured in the scoring algorithm.""" + """An exception occurred in the scoring algorithm.""" ABORTED_LOW_GRADE = "aborted_low_grade" """The system received too many bad reviews and stopped handing out tasks for this message tree.""" diff --git a/backend/oasst_backend/prompt_repository.py b/backend/oasst_backend/prompt_repository.py index cb1dd2e2..5ac9d85d 100644 --- a/backend/oasst_backend/prompt_repository.py +++ b/backend/oasst_backend/prompt_repository.py @@ -484,7 +484,7 @@ class PromptRepository: OasstErrorCode.TASK_PAYLOAD_TYPE_MISMATCH, ) - logger.debug(f"text_labels relpy: {valid_labels=}, {mandatory_labels=}") + logger.debug(f"text_labels reply: {valid_labels=}, {mandatory_labels=}") if valid_labels: if not all([label in valid_labels for label in text_labels.labels.keys()]): diff --git a/backend/oasst_backend/task_repository.py b/backend/oasst_backend/task_repository.py index 38a23e0c..99bb07bb 100644 --- a/backend/oasst_backend/task_repository.py +++ b/backend/oasst_backend/task_repository.py @@ -177,7 +177,7 @@ class TaskRepository: if not allow_personal_tasks and not task.collective: raise OasstError("This is not a collective task", OasstErrorCode.TASK_NOT_COLLECTIVE) if task.done: - raise OasstError("Allready closed", OasstErrorCode.TASK_ALREADY_DONE) + raise OasstError("Already closed", OasstErrorCode.TASK_ALREADY_DONE) task.done = True self.db.add(task) diff --git a/backend/oasst_backend/tree_manager.py b/backend/oasst_backend/tree_manager.py index 940e08ea..72a4c31f 100644 --- a/backend/oasst_backend/tree_manager.py +++ b/backend/oasst_backend/tree_manager.py @@ -320,7 +320,7 @@ class TreeManager: if num_red_flag is not None and num_red_flag >= self.cfg.auto_mod_red_flags: if m.parent_id is None: logger.warning( - f"[AUTO MOD] Halting tree {m.message_tree_id}, inital prompt got too many red flags ({m.emojis})." + f"[AUTO MOD] Halting tree {m.message_tree_id}, initial prompt got too many red flags ({m.emojis})." ) self.enter_low_grade_state(m.message_tree_id) else: @@ -895,7 +895,7 @@ class TreeManager: logger.warning("The intersection of ranking results ID sets has less than two elements. Skipping.") continue - # keep only elements in commond set + # keep only elements in command set ordered_ids_list = [list(filter(lambda x: x in common_set, ids)) for ids in ordered_ids_list] assert all(len(x) == len(common_set) for x in ordered_ids_list) @@ -1069,7 +1069,7 @@ HAVING(COUNT(mr.message_id) FILTER (WHERE mr.user_id = :user_id) = 0) """ def query_incomplete_rankings(self, lang: str) -> list[IncompleteRankingsRow]: - """Query parents which have childern that need further rankings""" + """Query parents which have children that need further rankings""" user_id = self.pr.user_id if not settings.DEBUG_ALLOW_DUPLICATE_TASKS else None r = self.db.execute( @@ -1256,7 +1256,7 @@ LEFT JOIN message_reaction mr ON mr.task_id = t.id AND mr.payload_type = 'Rankin @managed_tx_method(CommitMode.COMMIT) def ensure_tree_states(self) -> None: - """Add message tree state rows for all root nodes (inital prompt messages).""" + """Add message tree state rows for all root nodes (initial prompt messages).""" missing_tree_ids = self.query_misssing_tree_states() for id in missing_tree_ids: @@ -1598,7 +1598,7 @@ DELETE FROM message WHERE message_tree_id = :message_tree_id; total_messages = sum(len(x) for x in replies_by_tree.values()) logger.debug(f"found: {len(replies_by_tree)} trees; {len(prompts)} prompts; {total_messages} messages;") - # remove all trees based on inital prompts of the user + # remove all trees based on initial prompts of the user if purge_initial_prompts: for p in prompts: self.purge_message_tree(p.message_tree_id) @@ -1636,7 +1636,7 @@ DELETE FROM message WHERE message_tree_id = :message_tree_id; logger.debug(f"purging message: {m.id}") self._purge_message_internal(m.id) - # update childern counts + # update children counts self.pr.update_children_counts(m.message_tree_id) # reactivate tree diff --git a/backend/oasst_backend/utils/ranking.py b/backend/oasst_backend/utils/ranking.py index 0bb94fe8..17863545 100644 --- a/backend/oasst_backend/utils/ranking.py +++ b/backend/oasst_backend/utils/ranking.py @@ -66,7 +66,7 @@ def get_winner(pairs): def get_ranking(pairs): """ - Abuses concordance property to get a (not necessarily unqiue) ranking. + Abuses concordance property to get a (not necessarily unique) ranking. The lack of uniqueness is due to the potential existence of multiple equally ranked winners. We have to pick one, which is where the non-uniqueness comes from diff --git a/copilot/README.md b/copilot/README.md index 16d4dec8..7b07f0db 100644 --- a/copilot/README.md +++ b/copilot/README.md @@ -29,7 +29,7 @@ This will create a variety of aws roles and services needed for deployment. copilot deploy ``` -This will depoy the services but it won't be 100% ready for usage. Before being +This will deploy the services but it won't be 100% ready for usage. Before being ready, we have to inspect the AWS Secrets manager and extract out the database credentials. Read those credentials then put them, and a few other secrets, in a `secrets.yml` file like the following: diff --git a/docs/docs/data/schemas.mdx b/docs/docs/data/schemas.mdx index f614b610..f16c4fa7 100644 --- a/docs/docs/data/schemas.mdx +++ b/docs/docs/data/schemas.mdx @@ -182,7 +182,7 @@ message GenerationExample { class RankingExample: thread: Thread # The conversation thread before the message to be ranked - messages: list[Message] # The messages to be ranked, in oder of decreasing preference + messages: list[Message] # The messages to be ranked, in order of decreasing preference ``` diff --git a/docs/docs/data/supervised-datasets.md b/docs/docs/data/supervised-datasets.md index 79f8b652..f74ead26 100644 --- a/docs/docs/data/supervised-datasets.md +++ b/docs/docs/data/supervised-datasets.md @@ -14,16 +14,16 @@ help. There are two large-scale projects in the area of instruction-following / multitask learning: Promptsource and Natural Instructions - these projects crowdsourced templates and turned existing NLP datasets into -instruction-following seq2seq form in natural langauge. They include both +instruction-following seq2seq form in natural language. They include both long-output training examples like generating a sentence that is a likely consequence of sentence in the prompt, and short-output, like rating prediction from review. (Pre-)training on such datasets should help model understand and -follow instructions and teach it many abilities neccessary to perform a large -set of tasks correctly. However, these data are not dialog-like - they do not -look like a normal conversation. +follow instructions and teach it many abilities necessary to perform a large set +of tasks correctly. However, these data are not dialog-like - they do not look +like a normal conversation. There are also supervised dialog datasets such as Blended Skill Talk or SODA. In -constrast to instruction-following datasets, dialog data is not as focused on +contrast to instruction-following datasets, dialog data is not as focused on "academic tasks" or correctness, but encourage the model to respond naturally like a person would. diff --git a/model/reward/instructor/TODO.md b/model/reward/instructor/TODO.md index c0745fa9..7c82851c 100644 --- a/model/reward/instructor/TODO.md +++ b/model/reward/instructor/TODO.md @@ -1,6 +1,6 @@ Some other reward features we can use -0. Finish classifcation feature +0. Finish classification feature 1. Summaries from human feedback diff --git a/model/reward/instructor/rank_datasets.py b/model/reward/instructor/rank_datasets.py index 330c0a9f..545f6269 100644 --- a/model/reward/instructor/rank_datasets.py +++ b/model/reward/instructor/rank_datasets.py @@ -14,7 +14,7 @@ [] support additional negative samples generated from other models. For example we can use galactica-125m to generate a TLDR and assume it was - inferior than the human perference one + inferior than the human preference one """ diff --git a/model/supervised_finetuning/custom_datasets/README.md b/model/supervised_finetuning/custom_datasets/README.md index 56a28574..b938ec0f 100644 --- a/model/supervised_finetuning/custom_datasets/README.md +++ b/model/supervised_finetuning/custom_datasets/README.md @@ -23,5 +23,5 @@ Issues and TODO: - ideally we can update the config yaml and new dataset will be download from hub - - one possible idea is we upload the trasform format of these dataset to the + - one possible idea is we upload the transform format of these dataset to the OA hub diff --git a/model/supervised_finetuning/custom_datasets/qa_datasets.py b/model/supervised_finetuning/custom_datasets/qa_datasets.py index 2c5c7ee2..5faa22e6 100644 --- a/model/supervised_finetuning/custom_datasets/qa_datasets.py +++ b/model/supervised_finetuning/custom_datasets/qa_datasets.py @@ -314,7 +314,7 @@ class JokeExplaination(Dataset): for line in f: data = json.loads(line) joke = data["joke"] - explanation = data["explaination"] + explanation = data["explanation"] self.pairs.append((joke, explanation)) if len(question) > 0 and len(answer) > 0: diff --git a/notebooks/closed-book-qa/T5_closed_book_QA_generators.py b/notebooks/closed-book-qa/T5_closed_book_QA_generators.py index d6bcac19..3d847f26 100644 --- a/notebooks/closed-book-qa/T5_closed_book_QA_generators.py +++ b/notebooks/closed-book-qa/T5_closed_book_QA_generators.py @@ -83,7 +83,7 @@ with (open("paragraphs.pkl", "rb")) as openfile: try: objects.append(pickle.load(openfile)) except EOFError: - print("Problem laoding your pickle file, using the default array") + print("Problem loading your pickle file, using the default array") pickle_fail = True break @@ -92,7 +92,7 @@ if pickle_fail: paragraphs = [ "Like for me, this thing is like a little side hobby, but it's also one that's deeply fulfilling. So not just from a business perspective, which is not the way I think about it. I just think from a life human perspective, it's I probably wouldn't have this kind of conversation with you off mic, like this long, this deep, this attentive. There's something really fulfilling about these conversations. So what advice would you have for me? What advice do you have for yourself? Oh, have you not introspected this that deeply? Oh, I have advice. I think the first advice I would give to you is I think you should have me on more often. Yeah. Yeah. That's first and foremost. And second is go on your podcast and have a conversation. Well, I would say you come on my podcast when you're ready. Yeah. When you feel like the product that I'm putting out would benefit from your presence and vice versa, not as a favor to a bro, but at the right time.", "Well, we really are looking through a two dimensional screen until it's what we intuit to be a three dimensional world and also inferring dynamic stuff, making it 4D. Anyway, is it possible to visualize some pretty pictures that give us a deeper sense of the truth of reality? I think that we will incrementally be able to do that. I think that, for example, the picture that we have of electrons and photons interacting and scattering, it may have not been possible until Faraday did all of his experiments and then Maxwell wrote down his equations. And we were then sort of forced by his equations to think in a new way. And then when Planck in 1900, desperate to try to solve the problem of black body radiation, what they call the ultraviolet catastrophe where Newton was predicting infinite energies where there weren't infinite energies in black body radiation. And he in desperation proposed packets of energy. Then once you've done that, and then you have an Einstein come along five years later and show how that explains the photoelectric effect.", - "But man, I don't know how I would feel about just bacteria everywhere. Well, it would be depressing if it was true. I suppose depressing, I don't think, I don't. I don't know what's more depressing, bacteria everywhere or nothing everywhere. Yes, either of them are chilling. Yeah. But whether it's chilling or not, I don't think should force us to change our view about whether it's real or not. Yes. And what I'm saying may or may not be true. So how would you feel if we discovered life on Mars? Absolutely. It sounds like you would be less excited than some others because you're like, well. What I would be most interested in is how similar to life on Earth it would be. It would actually turn into quite a subtle problem because the likelihood of life having gone to and fro between Mars and the Earth is quite, I wouldn't say high, but it's not low, it's quite feasible. And so if we found life on Mars and it had very similar genetic code, but it was slightly different, most people would interpret that immediately as evidence that they've been transit one way or the other and that it was a common origin of life on Mars or on the Earth and it went one way or the other way.", + "But man, I don't know how I would feel about just bacteria everywhere. Well, it would be depressing if it was true. I suppose depressing, I don't think, I don't. I don't know what's more depressing, bacteria everywhere or nothing everywhere. Yes, either of them are chilling. Yeah. But whether it's chilling or not, I don't think should force us to change our view about whether it's real or not. Yes. And what I'm saying may or may not be true. So how would you feel if we discovered life on Mars? Absolutely. It sounds like you would be less excited than some others because you're like, well. What I would be most interested in is how similar to life on Earth it would be. It would actually turn into quite a subtle problem because the likelihood of life having gone to and from between Mars and the Earth is quite, I wouldn't say high, but it's not low, it's quite feasible. And so if we found life on Mars and it had very similar genetic code, but it was slightly different, most people would interpret that immediately as evidence that they've been transit one way or the other and that it was a common origin of life on Mars or on the Earth and it went one way or the other way.", ] # Make sure no paragraphs are too long for T5. It handles up to 512 tokens context length. diff --git a/notebooks/data-augmentation/stackexchange-builder/README.md b/notebooks/data-augmentation/stackexchange-builder/README.md index 74a49872..7140bdb7 100644 --- a/notebooks/data-augmentation/stackexchange-builder/README.md +++ b/notebooks/data-augmentation/stackexchange-builder/README.md @@ -86,7 +86,7 @@ Each question and all related answers are on a single line in JSONL format. #### Table/CSV/Parquet Format There are a lot more columns left over in the table format. `_q` and `_a` are -suffixes indiciating if the column came from the question or answer table as +suffixes indicating if the column came from the question or answer table as leftover from a join statement. ``` diff --git a/notebooks/detoxify-evaluation/README.md b/notebooks/detoxify-evaluation/README.md index 84931726..7aa2f357 100644 --- a/notebooks/detoxify-evaluation/README.md +++ b/notebooks/detoxify-evaluation/README.md @@ -15,7 +15,7 @@ trained on | multilingual | xlm-roberta-base | Multilingual Toxic Comment Classification | Unbiased and original models also have a 'small' version - but since normal -models are not memory heavy, and small models perform noticably worse, they are +models are not memory heavy, and small models perform noticeably worse, they are only described in the notebook ## All tests below were ran on a 3090TI diff --git a/notebooks/example/README.md b/notebooks/example/README.md index 763b4812..be886964 100644 --- a/notebooks/example/README.md +++ b/notebooks/example/README.md @@ -7,7 +7,7 @@ this project. Please try and follow this structure as closely as possible. While things will not exactly be the same for each notebook some principles we would like to try ensure are: -1. Each notebook or collection of related or dependant notebooks should live in +1. Each notebook or collection of related or dependent notebooks should live in its own folder. 1. Each notebook should have a markdown file with the same name as the notebook (or README.md if it's a single notebook folder) that explains what the diff --git a/oasst-shared/oasst_shared/exceptions/oasst_api_error.py b/oasst-shared/oasst_shared/exceptions/oasst_api_error.py index 58c8aadc..ed04fc4c 100644 --- a/oasst-shared/oasst_shared/exceptions/oasst_api_error.py +++ b/oasst-shared/oasst_shared/exceptions/oasst_api_error.py @@ -95,7 +95,7 @@ class OasstError(Exception): http_status_code: HTTPStatus def __init__(self, message: str, error_code: OasstErrorCode, http_status_code: HTTPStatus = HTTPStatus.BAD_REQUEST): - super().__init__(message, error_code, http_status_code) # make excetpion picklable (fill args member) + super().__init__(message, error_code, http_status_code) # make exception picklable (fill args member) self.message = message self.error_code = error_code self.http_status_code = http_status_code diff --git a/scripts/data-collection/twitter/README.md b/scripts/data-collection/twitter/README.md index b8c7bfc9..c0d98388 100644 --- a/scripts/data-collection/twitter/README.md +++ b/scripts/data-collection/twitter/README.md @@ -57,7 +57,7 @@ conversation, or at least as a prompt with replies. guarantee of the quality of the tweets. - The tweet quality is the other major issue. We can get conversations through the currently made scripts, but they most likely don't match a useful - instruction -> fulfilment. We are trying to filter the tweets through various + instruction -> fulfillment. We are trying to filter the tweets through various means such as matching useful hashtags, or by using cosine similarity against known instructions. - The modern Twitter API has conversation_id as a field which can be a way to @@ -68,7 +68,7 @@ conversation, or at least as a prompt with replies. ## TODO - Write scripts to filter existing conversations into useful instructions -> - fulfilment with hashtags or cosine similarity. + fulfillment with hashtags or cosine similarity. - Train model to detect if text is a suitable instruction. This could then be run through the conversations (or full tweet dump) to simplify the process. Related to issue #143. diff --git a/scripts/data-collection/twitter/twitter_process_json.py b/scripts/data-collection/twitter/twitter_process_json.py index a1e47d7d..9d1ea2e5 100644 --- a/scripts/data-collection/twitter/twitter_process_json.py +++ b/scripts/data-collection/twitter/twitter_process_json.py @@ -9,7 +9,7 @@ # This assumes data downloaded from https://archive.org/details/twitterstream # and that the internal .tar files are extracted locally. -# They are large files so using something like 7Zip or WinRar migth be easier +# They are large files so using something like 7Zip or WinRar might be easier # than putting all of it in scripts, but it is a possibility. # I often work in notebooks. If you encounter any issue, please reach out to let me know. diff --git a/scripts/data_augment/data_augment.py b/scripts/data_augment/data_augment.py index 0a8d3611..79072006 100644 --- a/scripts/data_augment/data_augment.py +++ b/scripts/data_augment/data_augment.py @@ -94,7 +94,7 @@ class EssayReviser(DataAugmenter): def parse_single(self, essay): instructions = [] - # Make stucture error (shuffle one paragraph with another) + # Make structure error (shuffle one paragraph with another) essay_paragraphs = essay.split("\n\n") # Splitting a String by newline character (\n) rand1 = random.randint(0, len(essay_paragraphs) - 1) @@ -424,7 +424,7 @@ class CodeInstructor(DataAugmenter): def recognize_entities(text, model, n=4, person="ignore"): - """Given a text and a model for entity recognition, return the most occuring entites in the text as a string""" + """Given a text and a model for entity recognition, return the most occurring entities in the text as a string""" doc = model(text) if person == "ignore": ents = Counter([ent.text.strip() for ent in list(doc.ents) if len(ent.text.strip()) >= 5]) diff --git a/scripts/postprocessing/rankings.py b/scripts/postprocessing/rankings.py index 1df6df36..01d092ff 100644 --- a/scripts/postprocessing/rankings.py +++ b/scripts/postprocessing/rankings.py @@ -66,7 +66,7 @@ def get_winner(pairs): def get_ranking(pairs): """ - Abuses concordance property to get a (not necessarily unqiue) ranking. + Abuses concordance property to get a (not necessarily unique) ranking. The lack of uniqueness is due to the potential existence of multiple equally ranked winners. We have to pick one, which is where the non-uniqueness comes from diff --git a/scripts/postprocessing/scoring.py b/scripts/postprocessing/scoring.py index 5e76d19c..bd867d80 100644 --- a/scripts/postprocessing/scoring.py +++ b/scripts/postprocessing/scoring.py @@ -58,7 +58,7 @@ def score_update_votes(new_vote: int, consensus: npt.ArrayLike, voter_data: Vote after that voter cast a vote on a question. This function is only to be run when archiving a question - i.e. the question has had sufficiently many votes, or we cann't get more than "K" bits of information + i.e. the question has had sufficiently many votes, or we can't get more than "K" bits of information The consensus is the array of all votes cast by all voters for that question We then update the voter data using the new information @@ -88,7 +88,7 @@ def score_update_prompts(consensus: npt.ArrayLike, voter_data: Voter) -> Voter: This function returns the gain of points for a given prompt's votes In contrast to the other score updating functions, we can run this online as new votes come in. - i.e. the question has had sufficiently many votes, or we cann't get more than "K" bits of information. + i.e. the question has had sufficiently many votes, or we can't get more than "K" bits of information. Parameters: @@ -122,7 +122,7 @@ def score_update_ranking(user_ranking: npt.ArrayLike, consensus_ranking: npt.Arr This function returns the gain of points for a given ranking's votes This function is only to be run when archiving a question - i.e. the question has had sufficiently many votes, or we cann't get more than "K" bits of information + i.e. the question has had sufficiently many votes, or we can't get more than "K" bits of information we use the bubble-sort distance (or "kendall-tau" distance) to compare the two rankings we use this over spearman correlation since: diff --git a/scripts/postprocessing/task_schedule.py b/scripts/postprocessing/task_schedule.py index deb302b2..ae717dc8 100644 --- a/scripts/postprocessing/task_schedule.py +++ b/scripts/postprocessing/task_schedule.py @@ -56,7 +56,7 @@ def next_answer_task(possible_prompts, answers_per_prompt): This helps to not have too much close-to-finished prompts in the active set. Parameters: - possible_prompts (dict[prompt_id, num_answers]): a dictonary containing all open prompts and the number of answers these prompts currently have. + possible_prompts (dict[prompt_id, num_answers]): a dictionary containing all open prompts and the number of answers these prompts currently have. answers_per_prompt (int): number of answers we per prompt to target Returns: prompt_id (int): the prompt_id corresponding to the next prompt that should get a new answer diff --git a/text-frontend/auto_main.py b/text-frontend/auto_main.py index 2775d98c..e951a28e 100644 --- a/text-frontend/auto_main.py +++ b/text-frontend/auto_main.py @@ -247,7 +247,7 @@ def main(backend_url: str = "http://127.0.0.1:8080", api_key: str = "1234"): tasks.append(new_task) case "task_done": typer.echo("Task done!") - # rerun with new task slected from above cases + # rerun with new task selected from above cases # add a new task q += 1 if q == 10: @@ -257,7 +257,7 @@ def main(backend_url: str = "http://127.0.0.1:8080", api_key: str = "1234"): # case _: typer.echo(f"Unknown task type {task['type']}") - # rerun with new task slected from above cases + # rerun with new task selected from above cases if __name__ == "__main__": diff --git a/website/cypress/README.md b/website/cypress/README.md index d6a2b383..493dc24f 100644 --- a/website/cypress/README.md +++ b/website/cypress/README.md @@ -4,7 +4,7 @@ the context of this site. To learn more, the [Cypress documentation](https://docs.cypress.io/guides/getting-started/opening-the-app) has it all. -Don't get scared by the commercial offerings they offer. Their core is open source, the cloud offering is not necesarry +Don't get scared by the commercial offerings they offer. Their core is open source, the cloud offering is not necessary at all and can be replaced by CI tooling and [community efforts](https://sorry-cypress.dev/). # Component testing diff --git a/website/src/components/Survey/LabelLikertGroup.tsx b/website/src/components/Survey/LabelLikertGroup.tsx index 734c6c10..d80d6cb4 100644 --- a/website/src/components/Survey/LabelLikertGroup.tsx +++ b/website/src/components/Survey/LabelLikertGroup.tsx @@ -156,7 +156,7 @@ const getLabelInfo = (label: string): LabelInfo => { zeroText: "Clean", zeroDescription: [], oneText: "Contains PII", - oneDescription: ["Contains personally identifing information"], + oneDescription: ["Contains personally identifying information"], inverted: false, }; case "quality": diff --git a/website/src/hooks/tasks/useGenericTaskAPI.tsx b/website/src/hooks/tasks/useGenericTaskAPI.tsx index e7630bdc..78749733 100644 --- a/website/src/hooks/tasks/useGenericTaskAPI.tsx +++ b/website/src/hooks/tasks/useGenericTaskAPI.tsx @@ -12,7 +12,7 @@ export const useGenericTaskAPI = => { const [response, setResponse] = useState>({ taskAvailability: "AWAITING_INITIAL" }); - // Note: We use isValidating to indiate we are loading beause it signals eash load, not just the first one. + // Note: We use isValidating to indicate we are loading because it signals eash load, not just the first one. const { isValidating: isLoading, mutate: requestNewTask } = useSWRImmutable>( "/api/new_task/" + taskType, get, diff --git a/website/src/pages/api/update_task.ts b/website/src/pages/api/update_task.ts index 1b4f2eda..59920b13 100644 --- a/website/src/pages/api/update_task.ts +++ b/website/src/pages/api/update_task.ts @@ -7,7 +7,7 @@ import { getBackendUserCore, getUserLanguage } from "src/lib/users"; /** * Stores the task interaction with the Task Backend and then returns the next task generated. * - * This implicity does a few things: + * This implicitly does a few things: * 1) Records the users answer in our local database. * 2) Accepts the task. * 3) Sends the users answer to the Task Backend. diff --git a/website/src/test_pages/README.md b/website/src/test_pages/README.md index 5e3e27a7..42782930 100644 --- a/website/src/test_pages/README.md +++ b/website/src/test_pages/README.md @@ -1,4 +1,4 @@ # Page Tests -Put all page tests in this directory with the patter `MyPage.test.jsx`. We can't place them in `src/pages` due to how +Put all page tests in this directory with the pattern `MyPage.test.jsx`. We can't place them in `src/pages` due to how NextJS generates page routes. From 8bc7d083e04cddb65a2527814ec7645581d6301d Mon Sep 17 00:00:00 2001 From: Zigfrid Zvezdin Date: Sun, 5 Feb 2023 16:18:58 -0300 Subject: [PATCH 083/152] Portuguese (#1188) Co-authored-by: Zigfrid --- website/public/locales/pt-BR/common.json | 27 ++++++ website/public/locales/pt-BR/dashboard.json | 8 ++ website/public/locales/pt-BR/index.json | 15 ++++ website/public/locales/pt-BR/labelling.json | 24 ++++++ website/public/locales/pt-BR/leaderboard.json | 18 ++++ website/public/locales/pt-BR/message.json | 20 +++++ website/public/locales/pt-BR/side_menu.json | 12 +++ website/public/locales/pt-BR/tasks.json | 82 +++++++++++++++++++ website/public/locales/pt-BR/tos.json | 6 ++ 9 files changed, 212 insertions(+) create mode 100644 website/public/locales/pt-BR/common.json create mode 100644 website/public/locales/pt-BR/dashboard.json create mode 100644 website/public/locales/pt-BR/index.json create mode 100644 website/public/locales/pt-BR/labelling.json create mode 100644 website/public/locales/pt-BR/leaderboard.json create mode 100644 website/public/locales/pt-BR/message.json create mode 100644 website/public/locales/pt-BR/side_menu.json create mode 100644 website/public/locales/pt-BR/tasks.json create mode 100644 website/public/locales/pt-BR/tos.json diff --git a/website/public/locales/pt-BR/common.json b/website/public/locales/pt-BR/common.json new file mode 100644 index 00000000..a827c2aa --- /dev/null +++ b/website/public/locales/pt-BR/common.json @@ -0,0 +1,27 @@ +{ + "about": "Sobre", + "account_settings": "Conta", + "admin_dashboard": "Painel de configurações", + "copied": "Copiado", + "connect": "Conectar", + "conversational": "IA conversacional para todos.", + "dark_mode": "Tema Escuro", + "dashboard": "Painel", + "delete": "Deletar", + "discord": "Discord", + "docs": "Documentação", + "github": "GitHub", + "legal": "Legal", + "light_mode": "Tema Claro", + "loading": "Carregando...", + "more_information": "Mais informações...", + "no": "Não", + "privacy_policy": "Política de Privacidade", + "report_a_bug": "Reportar um erro", + "sign_in": "Entrar", + "sign_out": "Sair", + "success": "Sucesso", + "terms_of_service": "Termos de serviço", + "title": "Open Assistant", + "yes": "Sim" +} diff --git a/website/public/locales/pt-BR/dashboard.json b/website/public/locales/pt-BR/dashboard.json new file mode 100644 index 00000000..51ae298c --- /dev/null +++ b/website/public/locales/pt-BR/dashboard.json @@ -0,0 +1,8 @@ +{ + "grab_a_task": "Escolha uma tarefa!", + "create": "Criar", + "evaluate": "Avaliar", + "label": "Classificar", + "dashboard": "Painel", + "go": "Iniciar" +} diff --git a/website/public/locales/pt-BR/index.json b/website/public/locales/pt-BR/index.json new file mode 100644 index 00000000..05fdb925 --- /dev/null +++ b/website/public/locales/pt-BR/index.json @@ -0,0 +1,15 @@ +{ + "blurb": "Acreditamos que podemos criar uma revolução.", + "blurb1": "Da mesma forma que o Stable Diffusion ajudou o mundo a fazer arte e imagens de novas maneiras, nós queremos melhorar o mundo fornecendo uma IA de conversação incrível.", + "description": "IA conversacional para todos. Um projeto open source para criar um chat habilitado por GPT LLM administrado por LAION e colaboradores de todo o mundo.", + "faq_items": { + "q0": "Qual é o estágio do projeto?", + "a0": "Estamos no estágio inicial de desenvolvimento, com base em pesquisas estabelecidas para aplicar o RLHF a grandes modelos linguísticos.", + "q1": "Quem está por trás do Open Assistant?", + "a1": "O Open Assistant é um projeto organizado por LAION e pessoas de todo o mundo interessadas em levar esta tecnologia a todos." + }, + "faq_title": "Perguntas frequentes", + "join_us_description": "Todos os projetos open source começam com pessoas como você. Open source é a crença de que se colaborarmos juntos, podemos compartilhar nosso conhecimento e tecnologia com o mundo em benefício da humanidade. Você está dentro? Encontre-nos aqui:", + "join_us_title": "Junte-se a nós", + "subtitle": "IA conversacional para todos." +} diff --git a/website/public/locales/pt-BR/labelling.json b/website/public/locales/pt-BR/labelling.json new file mode 100644 index 00000000..329a2314 --- /dev/null +++ b/website/public/locales/pt-BR/labelling.json @@ -0,0 +1,24 @@ +{ + "label_highlighted_yes_no_instruction": "Responda a(s) pergunta(s) a seguir sobre a mensagem em destaque:", + "label_highlighted_flag_instruction": "Selecione qualquer um que se aplique à mensagem em destaque:", + "label_highlighted_likert_instruction": "Avalie a mensagem em destaque:", + "label_message_yes_no_instruction": "Responda a(s) pergunta(s) a seguir sobre a mensagem:", + "label_message_flag_instruction": "Selecione o que se aplique à mensagem:", + "label_message_likert_instruction": "Classifique a mensagem:", + "spam.question": "A mensagem é spam?", + "fails_task.question": "É uma má resposta segundo a tarefa pedida?", + "not_appropriate": "Não apropriada", + "not_appropriate.explanation": "Não apropriada para um assistente.", + "pii": "Contém informações que permitem identificação pessoal (PII)", + "pii.explanation": "Contém informações que permitem identificação pessoal tais como informações de contato, números de identificação ou dados bancários", + "hate_speech": "Discurso de ódio", + "hate_speech.explanation": "O conteúdo é ofensivo ou ameaçador e expressa preconceito contra uma característica pessoal. Preconceito refere-se a opiniões preconcebidas que não são baseadas na razão. As características pessoais incluem gênero, etnia, religião, orientação sexual e características similares.", + "sexual_content": "Conteúdo sexual", + "sexual_content.explanation": "Contém conteúdo sexual.", + "moral_judgement": "Julgamento moral", + "moral_judgement.explanation": "Tem julgamento moral", + "political_content": "Conteúdo político", + "political_content.explanation": "Expressa uma opinião política.", + "lang_mismatch": "Idioma incorreto", + "lang_mismatch.explanation": "Não está escrito no idioma selecionado atualmente." +} diff --git a/website/public/locales/pt-BR/leaderboard.json b/website/public/locales/pt-BR/leaderboard.json new file mode 100644 index 00000000..da9820b2 --- /dev/null +++ b/website/public/locales/pt-BR/leaderboard.json @@ -0,0 +1,18 @@ +{ + "daily": "Diário", + "last_updated_at": "Última atualização em: {{val, datetime}}", + "leaderboard": "Leaderboard", + "monthly": "Mensal", + "overall": "Geral", + "rank": "Classificação", + "score": "Pontuação", + "user": "Usuário", + "weekly": "Semanal", + "prompt": "Prompts", + "reply": "Respostas", + "label": "Etiquetas", + "view_all": "Ver tudo", + "top_5_contributors_today": "Top 5 Colaboradores de Hoje", + "previous": "Voltar", + "next": "Seguinte" +} diff --git a/website/public/locales/pt-BR/message.json b/website/public/locales/pt-BR/message.json new file mode 100644 index 00000000..848a77b1 --- /dev/null +++ b/website/public/locales/pt-BR/message.json @@ -0,0 +1,20 @@ +{ + "copy_message_id": "Copiar ID de mensagem", + "label_action": "Classificar", + "label_title": "Classificar", + "message_deleted": "Mensagem apagada", + "message": "Mensagem", + "open_new_tab_action": "Abrir em nova aba", + "parent": "Raiz", + "reactions": "Reações", + "recent_messages": "Mensagens recentes", + "report_action": "Relatar", + "report_placeholder": "Por que devemos rever essa mensagem?", + "report_title": "Relatar", + "send_report": "Enviar", + "stop_tree": "Parar árvore", + "submit_labels": "Enviar", + "tree_stopped": "Árvore parada {{id}}", + "view_user": "Ver usuário", + "your_recent_messages": "Suas Mensagens Recentes" +} diff --git a/website/public/locales/pt-BR/side_menu.json b/website/public/locales/pt-BR/side_menu.json new file mode 100644 index 00000000..c001d838 --- /dev/null +++ b/website/public/locales/pt-BR/side_menu.json @@ -0,0 +1,12 @@ +{ + "dashboard": "Painel", + "dashboard_home": "Página principal", + "messages": "Mensagens", + "messages_dashboard": "Painel de mensagens", + "leaderboard": "Leaderboard", + "user_leaderboard": "Leaderboard dos usuários", + "users": "Usuários", + "users_dashboard": "Painel de controle de usuários", + "status": "Status", + "status_dashboard": "Painel de status" +} diff --git a/website/public/locales/pt-BR/tasks.json b/website/public/locales/pt-BR/tasks.json new file mode 100644 index 00000000..fdc75d14 --- /dev/null +++ b/website/public/locales/pt-BR/tasks.json @@ -0,0 +1,82 @@ +{ + "default": { + "unchanged_title": "Sem alterações", + "unchanged_message": "Tem certeza que quer continuar?" + }, + "random": { + "label": "Estou me sentindo com sorte", + "desc": "Ajude-nos a melhorar o Open Assistant, inicie uma tarefa aleatória." + }, + "create_initial_prompt": { + "label": "Criar prompts iniciais", + "desc": "Escreva prompts iniciais para ajudar o Open Assistant a tentar responder a uma variedade de mensagens.", + "overview": "Criar uma mensagem inicial para enviar ao assistente", + "instruction": "Forneça os prompts iniciais", + "response_placeholder": "Escreva aqui seu prompt..." + }, + "reply_as_user": { + "label": "Responder como usuário", + "desc": "Fale com o Open Assistant e tente melhorar suas respostas à medida que você interage com ele.", + "overview": "Dada a seguinte conversa, dê uma resposta apropriada", + "instruction": "Forneça feedback do usuário", + "response_placeholder": "Escreva aqui sua resposta..." + }, + "reply_as_assistant": { + "label": "Responder como assistente", + "desc": "Ajude o Open Assistant a melhorar suas respostas às conversas com outros usuários.", + "overview": "Dada a seguinte conversa, dê uma resposta apropriada", + "response_placeholder": "Escreva aqui sua resposta..." + }, + "rank_user_replies": { + "label": "Ordenar as respostas dos usuários", + "desc": "Ajude o Open Assistant a melhorar suas respostas às conversas com outros usuários.", + "overview": "Dadas as seguintes respostas dos usuários, ordene-as em ordem da melhor para a pior, sendo a primeira a melhor e a última a pior.", + "unchanged_title": "Ordem inalterada", + "unchanged_message": "Você não mudou a ordem dos prompts - você tem certeza de que quer continuar?" + }, + "rank_assistant_replies": { + "label": "Ordenar as respostas do assistente", + "desc": "Avalie as respostas dadas pelo Open Assistant com base em sua precisão e legibilidade.", + "overview": "Dadas as seguintes respostas do assistente, ordene-as da melhor para a pior, sendo a primeira a melhor e a última a pior.", + "unchanged_title": "Ordem inalterada", + "unchanged_message": "Você não mudou a ordem dos prompts - você tem certeza de que quer continuar?" + }, + "rank_initial_prompts": { + "label": "Ordenar prompts iniciais", + "desc": "Avalie as respostas dadas pelo Open Assistant com base em sua precisão e legibilidade.", + "overview": "Dados os seguintes prompts iniciais, ordene-os do melhor para o pior, sendo o primeiro o melhor e o último o pior.", + "unchanged_title": "Ordem inalterada", + "unchanged_message": "Você não mudou a ordem dos prompts - você tem certeza de que quer continuar?" + }, + "label_initial_prompt": { + "label": "Etiquetar o prompt inicial", + "desc": "Forneça etiquetas para o prompt inicial.", + "overview": "Forneça etiquetas para o prompt a seguir" + }, + "label_prompter_reply": { + "label": "Etiquetar resposta do prompter", + "desc": "Forneça etiquetas para o prompt inicial.", + "overview": "Dada a discussão a seguir, forneça etiquetas para o último prompt." + }, + "label_assistant_reply": { + "label": "Etiquetar resposta do assistente", + "desc": "Forneça etiquetas para o prompt inicial.", + "overview": "Dada a discussão a seguir, forneça etiquetas para o último prompt." + }, + "classify_initial_prompt": { + "label": "Classificar o prompt inicial", + "desc": "Forneça etiquetas para o prompt inicial.", + "overview": "Leia o seguinte prompt e responda à pergunta sobre o assunto." + }, + "classify_prompter_reply": { + "label": "Classificar a resposta do prompter", + "desc": "Forneça etiquetas para o prompt inicial.", + "overview": "Leia a conversa a seguir e depois responda à pergunta sobre a última resposta na discussão." + }, + "classify_assistant_reply": { + "label": "Classificar respuesta del asistente", + "desc": "Forneça etiquetas para o prompt inicial.", + "overview": "Leia a conversa a seguir e depois responda à pergunta sobre a última resposta na discussão." + }, + "available_task_count": "{{count}} tarefas disponiveis" +} diff --git a/website/public/locales/pt-BR/tos.json b/website/public/locales/pt-BR/tos.json new file mode 100644 index 00000000..ee842d3b --- /dev/null +++ b/website/public/locales/pt-BR/tos.json @@ -0,0 +1,6 @@ +{ + "title": "Termos de Serviço para o Open Assistant", + "content": "Para continuar usando o Open Assistant, você precisa aceitar os nossos Termos de Serviço primeiro.", + "accept": "Aceitar", + "decline": "Recusar" +} From 2434d44c01ae4aa0f1d548384aa8a706d5e5fad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=B6pf?= Date: Sun, 5 Feb 2023 20:22:45 +0100 Subject: [PATCH 084/152] Exclude extendible parents with young reply tasks (#1196) * exclude extendible parents with young reply tasks * fix typos --- backend/oasst_backend/config.py | 2 +- backend/oasst_backend/task_repository.py | 2 +- backend/oasst_backend/tree_manager.py | 33 +++++++++++------------- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/backend/oasst_backend/config.py b/backend/oasst_backend/config.py index 2a21b3ec..87b14c6c 100644 --- a/backend/oasst_backend/config.py +++ b/backend/oasst_backend/config.py @@ -138,7 +138,7 @@ class TreeManagerConfiguration(BaseModel): p_lonely_child_extension: float = 0.75 """Probability to select a prompter message parent with less than lonely_children_count children.""" - recent_tasks_span_sec: int = 3 * 60 # 3 min + recent_tasks_span_sec: int = 5 * 60 # 5 min """Time in seconds of recent tasks to consider for exclusion during task selection.""" diff --git a/backend/oasst_backend/task_repository.py b/backend/oasst_backend/task_repository.py index 99bb07bb..2df9efa4 100644 --- a/backend/oasst_backend/task_repository.py +++ b/backend/oasst_backend/task_repository.py @@ -225,7 +225,7 @@ class TaskRepository: self, max_age: timedelta = timedelta(minutes=5), done: bool = False, skipped: bool = False, limit: int = 100 ) -> list[Task]: qry = self.db.query(Task).filter( - func.age(Task.created_date) < max_age, + func.age(func.current_timestamp(), Task.created_date) < max_age, or_(Task.payload_type == "AssistantReplyPayload", Task.payload_type == "PrompterReplyPayload"), ) if done is not None: diff --git a/backend/oasst_backend/tree_manager.py b/backend/oasst_backend/tree_manager.py index 72a4c31f..9556b832 100644 --- a/backend/oasst_backend/tree_manager.py +++ b/backend/oasst_backend/tree_manager.py @@ -562,14 +562,6 @@ class TreeManager: case TaskType.REPLY: - recent_reply_tasks = self.pr.task_repository.fetch_recent_reply_tasks( - max_age=timedelta(seconds=self.cfg.recent_tasks_span_sec), - done=False, - skipped=False, - limit=500, - ) - recent_reply_task_parents = {t.parent_message_id for t in recent_reply_tasks} - if task_role == TaskRole.PROMPTER: extendible_parents = list(filter(lambda x: x.parent_role == "assistant", extendible_parents)) elif task_role == TaskRole.ASSISTANT: @@ -580,24 +572,17 @@ class TreeManager: random_parent: ExtendibleParentRow = None if self.cfg.p_lonely_child_extension > 0 and self.cfg.lonely_children_count > 1: # check if we have extendible prompter parents with a small number of replies - lonely_children_parents = [ p for p in extendible_parents if 0 < p.active_children_count < self.cfg.lonely_children_count and p.parent_role == "prompter" - and p.parent_id not in recent_reply_task_parents ] if len(lonely_children_parents) > 0 and random.random() < self.cfg.p_lonely_child_extension: random_parent = random.choice(lonely_children_parents) if random_parent is None: - # try to exclude parents for which tasks were recently handed out - fresh_parents = [p for p in extendible_parents if p.parent_id not in recent_reply_task_parents] - if len(fresh_parents) > 0: - random_parent = random.choice(fresh_parents) - else: - random_parent = random.choice(extendible_parents) + random_parent = random.choice(extendible_parents) # fetch random conversation to extend logger.debug(f"selected {random_parent=}") @@ -895,7 +880,7 @@ class TreeManager: logger.warning("The intersection of ranking results ID sets has less than two elements. Skipping.") continue - # keep only elements in command set + # keep only elements in common set ordered_ids_list = [list(filter(lambda x: x in common_set, ids)) for ids in ordered_ids_list] assert all(len(x) == len(common_set) for x in ordered_ids_list) @@ -1087,14 +1072,23 @@ HAVING(COUNT(mr.message_id) FILTER (WHERE mr.user_id = :user_id) = 0) _sql_find_extendible_parents = """ -- find all extendible parent nodes +WITH recent_reply_tasks (parent_message_id) AS ( + -- recent incomplete tasks to exclude + SELECT parent_message_id FROM task + WHERE not done + AND not skipped + AND created_date > (CURRENT_TIMESTAMP - :recent_tasks_interval) + AND (payload_type = 'AssistantReplyPayload' OR payload_type = 'PrompterReplyPayload') +) SELECT m.id as parent_id, m.role as parent_role, m.depth, m.message_tree_id, COUNT(c.id) active_children_count FROM message_tree_state mts - INNER JOIN message m ON mts.message_tree_id = m.message_tree_id -- all elements of message tree + INNER JOIN message m ON mts.message_tree_id = m.message_tree_id -- all elements of message tree LEFT JOIN message_emoji me ON (m.id = me.message_id AND :skip_user_id IS NOT NULL AND me.user_id = :skip_user_id AND me.emoji = :skip_reply) + LEFT JOIN recent_reply_tasks rrt ON m.id = rrt.parent_message_id -- recent tasks LEFT JOIN message c ON m.id = c.parent_id -- child nodes WHERE mts.active -- only consider active trees AND mts.state = :growing_state -- message tree must be growing @@ -1103,6 +1097,7 @@ WHERE mts.active -- only consider active trees AND m.review_result -- parent node must have positive review AND m.lang = :lang -- parent matches lang AND me.message_id IS NULL -- no skip reply emoji for user + AND rrt.parent_message_id IS NULL -- no recent reply task found AND NOT coalesce(c.deleted, FALSE) -- don't count deleted children AND (c.review_result OR coalesce(c.review_count, 0) < :num_reviews_reply) -- don't count children with negative review but count elements under review GROUP BY m.id, m.role, m.depth, m.message_tree_id, mts.max_children_count @@ -1125,6 +1120,7 @@ HAVING COUNT(c.id) < mts.max_children_count -- below maximum number of children "user_id": user_id, "skip_user_id": self.pr.user_id, "skip_reply": protocol_schema.EmojiCode.skip_reply, + "recent_tasks_interval": timedelta(seconds=self.cfg.recent_tasks_span_sec), }, ) @@ -1165,6 +1161,7 @@ HAVING COUNT(m.id) < mts.goal_tree_size "user_id": user_id, "skip_user_id": self.pr.user_id, "skip_reply": protocol_schema.EmojiCode.skip_reply, + "recent_tasks_interval": timedelta(seconds=self.cfg.recent_tasks_span_sec), }, ) return [ActiveTreeSizeRow.from_orm(x) for x in r.all()] From dcb9dfe952fb0fa6fc11c719c6fc2881de19b29b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro?= <80827005+AGraciaSipan@users.noreply.github.com> Date: Sun, 5 Feb 2023 20:24:28 +0100 Subject: [PATCH 085/152] fix a typo in esp version of index.json (#1199) --- website/public/locales/es/index.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/public/locales/es/index.json b/website/public/locales/es/index.json index 012a2085..b47c08ab 100644 --- a/website/public/locales/es/index.json +++ b/website/public/locales/es/index.json @@ -1,7 +1,7 @@ { - "blurb": "Creemos que podemos crear una revoluciónn.", + "blurb": "Creemos que podemos crear una revolución.", "blurb1": "De la misma manera que Stable Diffusion ayudó al mundo a crear arte e imágenes de maneras nuevas, queremos mejorar el mundo proporcionando una IA conversacional asombrosa", - "description": "IA conversacional para todos. Un proyecto de código abierto para crear un GPT LLM preparado para chat administrado por LAION y colaboradores de todo el mundo.", + "description": "IA conversacional para todos. Un proyecto de código abierto para crear un GPT LLM preparado para chatear administrado por LAION y colaboradores de todo el mundo.", "faq_items": { "q0": "¿Cómo de avanzado está el proyecto?", "a0": "Estamos en las primeras etapas de desarrollo, trabajando a partir de la investigación establecida para aplicar RLHF (aprendizaje por refuerzo con realimentación humana) a modelos de lenguaje de gran tamaño.", From edfc40ddf3d2ac0d3f3b504e59d569ed4201e625 Mon Sep 17 00:00:00 2001 From: letier3110 <38981658+letier3110@users.noreply.github.com> Date: Mon, 6 Feb 2023 00:44:16 +0400 Subject: [PATCH 086/152] Ukrainian Translation (#1201) * Ukranian * feat: added ukranian to locales array * fix: rename to valid locale --- website/next-i18next.config.js | 2 +- website/public/locales/uk-UA/common.json | 27 ++++++ website/public/locales/uk-UA/dashboard.json | 8 ++ website/public/locales/uk-UA/index.json | 15 ++++ website/public/locales/uk-UA/labelling.json | 24 ++++++ website/public/locales/uk-UA/leaderboard.json | 18 ++++ website/public/locales/uk-UA/message.json | 20 +++++ website/public/locales/uk-UA/side_menu.json | 12 +++ website/public/locales/uk-UA/tasks.json | 82 +++++++++++++++++++ website/public/locales/uk-UA/tos.json | 6 ++ 10 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 website/public/locales/uk-UA/common.json create mode 100644 website/public/locales/uk-UA/dashboard.json create mode 100644 website/public/locales/uk-UA/index.json create mode 100644 website/public/locales/uk-UA/labelling.json create mode 100644 website/public/locales/uk-UA/leaderboard.json create mode 100644 website/public/locales/uk-UA/message.json create mode 100644 website/public/locales/uk-UA/side_menu.json create mode 100644 website/public/locales/uk-UA/tasks.json create mode 100644 website/public/locales/uk-UA/tos.json diff --git a/website/next-i18next.config.js b/website/next-i18next.config.js index 38c0ad0a..385efc53 100644 --- a/website/next-i18next.config.js +++ b/website/next-i18next.config.js @@ -1,6 +1,6 @@ module.exports = { i18n: { defaultLocale: "en", - locales: ["bn", "de", "en", "es", "fr", "hu", "ja", "ko", "pt-BR", "ru", "vi", "zh", "tr"], + locales: ["bn", "de", "en", "es", "fr", "hu", "ja", "ko", "pt-BR", "ru", "uk-UA", "vi", "zh", "tr"], }, }; diff --git a/website/public/locales/uk-UA/common.json b/website/public/locales/uk-UA/common.json new file mode 100644 index 00000000..d5216cce --- /dev/null +++ b/website/public/locales/uk-UA/common.json @@ -0,0 +1,27 @@ +{ + "about": "Про проект", + "account_settings": "Аккаунт", + "admin_dashboard": "Панель адміністратора", + "copied": "Скопійовано", + "connect": "Приєднати", + "conversational": "Розмовний ШІ для кожного.", + "dark_mode": "Темний режим", + "dashboard": "Головна панель", + "delete": "Видалити", + "discord": "Discord", + "docs": "Документація", + "github": "GitHub", + "legal": "Юридична інформація", + "light_mode": "Світлий режим", + "loading": "Завантаження...", + "more_information": "Більше інформації", + "no": "Ні", + "privacy_policy": "Політика конфіденційності", + "report_a_bug": "Сповістити про помилку", + "sign_in": "Війти", + "sign_out": "Вийти", + "success": "Успіх", + "terms_of_service": "Умови використання", + "title": "Open Assistant", + "yes": "Так" +} diff --git a/website/public/locales/uk-UA/dashboard.json b/website/public/locales/uk-UA/dashboard.json new file mode 100644 index 00000000..5309fff5 --- /dev/null +++ b/website/public/locales/uk-UA/dashboard.json @@ -0,0 +1,8 @@ +{ + "grab_a_task": "Взяти задачу!", + "create": "Створити", + "evaluate": "Оцінити", + "label": "Класифікувати", + "dashboard": "Головна панель", + "go": "Go" +} diff --git a/website/public/locales/uk-UA/index.json b/website/public/locales/uk-UA/index.json new file mode 100644 index 00000000..9ffcc8f9 --- /dev/null +++ b/website/public/locales/uk-UA/index.json @@ -0,0 +1,15 @@ +{ + "blurb": "Ми віримо, що можемо створити революцію.", + "blurb1": "Подібно до того, як Stable Diffusion допомогла світу створювати мистецтво та образи новими способами, ми хочемо покращити світ, створюючи дивовижний розмовний ШІ.", + "description": "Розмовний ШІ для всіх. Проект з відкритим вихідним кодом для створення готового до чату GPT LLM, яким керує LAION та партнери по всьому світу.", + "faq_items": { + "q0": "На якому етапі знаходиться проект?", + "a0": "Ми перебуваємо на ранніх стадіях розробки, спираючись на вже проведені дослідження, щоб застосувати RLHF (навчання з підкріпленням і зворотним зв'язком) до великих мовних моделей.", + "q1": "Хто стоїть за Open Assistant?", + "a1": "Open Assistant - це проект, організований LAION та людьми з усього світу, зацікавленими в тому, щоб зробити цю технологію доступною для всіх." + }, + "faq_title": "Поширені запитання", + "join_us_description": "Усі проекти з відкритим кодом починаються з таких людей, як ви. Відкритий код - це віра в те, що якщо ми будемо співпрацювати разом, ми зможемо поділитися своїми знаннями та технологіями зі світом на благо людства. Ви з нами? Знайди нас тут:", + "join_us_title": "Приєднуйтесь до нас", + "subtitle": "Розмовний ШІ для всіх." +} diff --git a/website/public/locales/uk-UA/labelling.json b/website/public/locales/uk-UA/labelling.json new file mode 100644 index 00000000..200664c7 --- /dev/null +++ b/website/public/locales/uk-UA/labelling.json @@ -0,0 +1,24 @@ +{ + "label_highlighted_yes_no_instruction": "Дайте відповідь на наступне (наступні) запитання щодо виділеного повідомлення:", + "label_highlighted_flag_instruction": "Виберіть те, що підходить для виділеного повідомлення:", + "label_highlighted_likert_instruction": "Оцініть виділене повідомлення:", + "label_message_yes_no_instruction": "Дайте відповідь на наступне (наступні) запитання щодо повідомлення:", + "label_message_flag_instruction": "Виберіть ті, що відповідають повідомленню:", + "label_message_likert_instruction": "Оцініть повідомлення:", + "spam.question": "Це повідомлення є спамом?", + "fails_task.question": "Чи є це поганою відповіддю, у відповідності до поставленого завдання?", + "not_appropriate": "Недоречно", + "not_appropriate.explanation": "Недоречно для асистента.", + "pii": "Містить особисті дані", + "pii.explanation": "Містить інформацію, що ідентифікує особу. Приклади включають особисті контактні дані, номери ліцензій та інших документів, що посвідчують особу, а також банківські реквізити.", + "hate_speech": "Розпалювання ворожнечі", + "hate_speech.explanation": "Контент є образливим або погрозливим і виражає упередження щодо захищеної ознаки. Упередження - це упереджені погляди, що не ґрунтуються на розумінні. До захищених ознак належать стать, етнічна приналежність, релігія, сексуальна орієнтація та подібні характеристики.", + "sexual_content": "Зміст сексуального характеру", + "sexual_content.explanation": "Містить матеріали сексуального характеру.", + "moral_judgement": "Моральне судження", + "moral_judgement.explanation": "Висловлює моральне судження.", + "political_content": "Політичне", + "political_content.explanation": "Висловлює політичні погляди.", + "lang_mismatch": "Некоретна мова", + "lang_mismatch.explanation": "Не написано вибраною мовою." +} diff --git a/website/public/locales/uk-UA/leaderboard.json b/website/public/locales/uk-UA/leaderboard.json new file mode 100644 index 00000000..c3c160f8 --- /dev/null +++ b/website/public/locales/uk-UA/leaderboard.json @@ -0,0 +1,18 @@ +{ + "daily": "За день", + "last_updated_at": "Останній раз оновлено: {{val, datetime}}", + "leaderboard": "Рейтинг лідерів", + "monthly": "За місяць", + "overall": "Всього", + "rank": "Рейтинг", + "score": "Бали", + "user": "Користувач", + "weekly": "За тиждень", + "prompt": "Текстів", + "reply": "Відповідей", + "label": "Маркувань", + "view_all": "Подивись усіх", + "top_5_contributors_today": "Топ-5 учасників сьогодні", + "previous": "Попередня", + "next": "Наступна" +} diff --git a/website/public/locales/uk-UA/message.json b/website/public/locales/uk-UA/message.json new file mode 100644 index 00000000..f3b82e3c --- /dev/null +++ b/website/public/locales/uk-UA/message.json @@ -0,0 +1,20 @@ +{ + "copy_message_id": "Скопіювати ID повідомлення", + "label_action": "Маркувати", + "label_title": "Маркування", + "message_deleted": "Повідомлення видалено", + "message": "Повідомлення", + "open_new_tab_action": "Відкрити в новій вкладці", + "parent": "Parent", + "reactions": "Реакції", + "recent_messages": "Останні повідомлення", + "report_action": "Report", + "report_placeholder": "Чому це повідомлення слід переглянути?", + "report_title": "Report", + "send_report": "Відправити", + "stop_tree": "Зупинити дерево", + "submit_labels": "Надіслати", + "tree_stopped": "Дерево зупинено {{id}}", + "view_user": "Профіль користувача", + "your_recent_messages": "Ваші останні повідомлення" +} diff --git a/website/public/locales/uk-UA/side_menu.json b/website/public/locales/uk-UA/side_menu.json new file mode 100644 index 00000000..b27d0890 --- /dev/null +++ b/website/public/locales/uk-UA/side_menu.json @@ -0,0 +1,12 @@ +{ + "dashboard": "Головна", + "dashboard_home": "Головна панель", + "messages": "Повідомлення", + "messages_dashboard": "Панель повідомлень", + "leaderboard": "Рейтинг лідерів", + "user_leaderboard": "User Leaderboard", + "users": "Користувачі", + "users_dashboard": "Панель користувачів", + "status": "Статус", + "status_dashboard": "Панель статусів" +} diff --git a/website/public/locales/uk-UA/tasks.json b/website/public/locales/uk-UA/tasks.json new file mode 100644 index 00000000..91745d3e --- /dev/null +++ b/website/public/locales/uk-UA/tasks.json @@ -0,0 +1,82 @@ +{ + "default": { + "unchanged_title": "Без змін", + "unchanged_message": "Ви впевнені, що хочете продовжити?" + }, + "random": { + "label": "Нехай мені пощастить", + "desc": "Допоможіть нам покращити Open Assistant, запустивши випадкове завдання." + }, + "create_initial_prompt": { + "label": "Створіть початкові тексти", + "desc": "Напишіть початкові тексти, які допоможуть Open Assistant спробувати відповісти на різні повідомлення. (взяти участь у лотереї)", + "overview": "Створіть початкове повідомлення для відправки асистенту", + "instruction": "Надайте початкові тексти", + "response_placeholder": "Напишіть своє запитання тут..." + }, + "reply_as_user": { + "label": "Відповісти як користувач", + "desc": "Спілкуйтеся з Open Assistant і допомагайте покращувати його відповіді, взаємодіючи з ним.", + "overview": "З огляду на наступну розмову, надайте адекватну відповідь", + "instruction": "Надати відповідь користувача", + "response_placeholder": "Напишіть свою відповідь тут..." + }, + "reply_as_assistant": { + "label": "Відповісти як асистент", + "desc": "Допоможіть Open Assistant покращити його реакцію на розмови з іншими користувачами.", + "overview": "З огляду на наступну розмову, надайте адекватну відповідь", + "response_placeholder": "Напишіть свою відповідь тут..." + }, + "rank_user_replies": { + "label": "Ранжування відповідей користувачів", + "desc": "Допоможіть Open Assistant покращити його реакцію на розмови з іншими користувачами.", + "overview": "Отримавши відповіді користувачів, відсортуйте їх від найкращого до найгіршого, де найкращий - на першому місці, найгірший - на останньому.", + "unchanged_title": "Порядок не змінено", + "unchanged_message": "Ви не змінили порядок текстів. Ви впевнені, що хочете продовжити?" + }, + "rank_assistant_replies": { + "label": "Ранжування відповідей асистента", + "desc": "Оцініть тексти, надані Open Assistant, на основі їх точності та читабельності.", + "overview": "Отримавши відповіді асистента, відсортуйте їх у порядку від найкращого до найгіршого, де найкращий - на першому місці, найгірший - на останньому.", + "unchanged_title": "Порядок не змінено", + "unchanged_message": "Ви не змінили порядок текстів. Ви впевнені, що хочете продовжити?" + }, + "rank_initial_prompts": { + "label": "Ранжування початкового тексту", + "desc": "Оцініть тексти, надані Open Assistant, на основі їх точності та читабельності.", + "overview": "Отримавши наступні початкові тексти, відсортуйте їх від найкращого до найгіршого, де найкращий - на першому місці, найгірший - на останньому.", + "unchanged_title": "Порядок не змінено", + "unchanged_message": "You have not changed the order of the prompts. Are you sure you would like to continue?" + }, + "label_initial_prompt": { + "label": "Промаркуйте початковий текст", + "desc": "Надайте мітки для тексту.", + "overview": "Надайте мітки для вказаного тексту." + }, + "label_prompter_reply": { + "label": "Промаркуйте відповідь до запиту", + "desc": "Надайте мітки для тексту.", + "overview": "Враховуючи наступну дискусію, промаркуйте останній текст." + }, + "label_assistant_reply": { + "label": "Промаркуйте відповідь асистента", + "desc": "Надайте мітки для тексту.", + "overview": "Враховуючи наступну дискусію, промаркуйте останній текст." + }, + "classify_initial_prompt": { + "label": "Класифікувати початковий текст", + "desc": "Надайте мітки для тексту.", + "overview": "Прочитайте наступний текст, а потім дайте відповідь на запитання до нього." + }, + "classify_prompter_reply": { + "label": "Класифікувати відповідь до запиту", + "desc": "Надайте мітки для тексту.", + "overview": "Прочитайте наступну розмову, а потім дайте відповідь на запитання щодо останньої відповіді в дискусії." + }, + "classify_assistant_reply": { + "label": "Класифікувати відповідь асистента", + "desc": "Надайте мітки для тексту.", + "overview": "Прочитайте наступну розмову, а потім дайте відповідь на запитання щодо останньої відповіді в дискусії." + }, + "available_task_count": "{{count}} задач доступно" +} diff --git a/website/public/locales/uk-UA/tos.json b/website/public/locales/uk-UA/tos.json new file mode 100644 index 00000000..70856379 --- /dev/null +++ b/website/public/locales/uk-UA/tos.json @@ -0,0 +1,6 @@ +{ + "title": "Умови надання послуг для Open Assistant", + "content": "Щоб продовжити користуватися Open Assistant, ви повинні спочатку прийняти наші Умови надання послуг.", + "accept": "Прийняти", + "decline": "Відхилити" +} From 9467b21d538fb7a5dc191e0246d348f08ce153e5 Mon Sep 17 00:00:00 2001 From: AbdBarho Date: Sun, 5 Feb 2023 21:51:13 +0100 Subject: [PATCH 087/152] Update ToS Endpoint (#1207) --- website/src/lib/oasst_api_client.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/website/src/lib/oasst_api_client.ts b/website/src/lib/oasst_api_client.ts index 30fb9885..3f730b72 100644 --- a/website/src/lib/oasst_api_client.ts +++ b/website/src/lib/oasst_api_client.ts @@ -303,9 +303,8 @@ export class OasstApiClient { } async set_tos_acceptance(user: BackendUserCore) { - // TODO: it is wasteful having to get the backend user first and then set the tos status - // is there a better way of doing this? - const backendUser = await this.get(`/api/v1/frontend_users/${user.auth_method}/${user.id}`); + // NOTE: we do a post here to force create the user if it does not exist + const backendUser = await this.post(`/api/v1/frontend_users/`, user); await this.put(`/api/v1/users/${backendUser.user_id}?tos_acceptance=true`); } } From f05d6abcb7001d67ec795cdcf5f2640eaaed053d Mon Sep 17 00:00:00 2001 From: Andrew Maguire Date: Sun, 5 Feb 2023 21:19:37 +0000 Subject: [PATCH 088/152] Add blog (#1203) * add blog and update docusaurus --- docs/blog/2023-02-05-we-need-your-help.mdx | 25 ++ docs/blog/authors.yml | 5 + docs/docusaurus.config.js | 18 +- docs/package.json | 7 +- docs/yarn.lock | 442 ++++++++++++++++++++- 5 files changed, 491 insertions(+), 6 deletions(-) create mode 100644 docs/blog/2023-02-05-we-need-your-help.mdx create mode 100644 docs/blog/authors.yml diff --git a/docs/blog/2023-02-05-we-need-your-help.mdx b/docs/blog/2023-02-05-we-need-your-help.mdx new file mode 100644 index 00000000..ec11b01a --- /dev/null +++ b/docs/blog/2023-02-05-we-need-your-help.mdx @@ -0,0 +1,25 @@ +--- +title: We Need Your Help! +description: We Need Your Help! +slug: we-need-your-help +authors: yk +tags: [open-assistant] +image: https://img.youtube.com/vi/64Izfm24FKA/0.jpg +--- + +import ReactPlayer from "react-player"; + +We Need Your Help! + +Help us collect data for OpenAssistant, the largest and most open alternative to +ChatGPT. + +https://open-assistant.io + + + + diff --git a/docs/blog/authors.yml b/docs/blog/authors.yml new file mode 100644 index 00000000..fb435bfd --- /dev/null +++ b/docs/blog/authors.yml @@ -0,0 +1,5 @@ +yk: + name: Yannic Kilcher + title: Project Lead + url: https://www.ykilcher.com/ + image_url: https://www.ykilcher.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fheadshot.ff3a7ee3.webp&w=3840&q=75 diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index c3327c77..2102105c 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -41,7 +41,22 @@ const config = { api: { path: "docs/api/openapi.json", }, - blog: false, + blog: { + routeBasePath: "/blog", + showReadingTime: true, + blogTitle: "OpenAssistant Blog", + blogDescription: "Home of the OpenAssistant blog.", + blogSidebarTitle: "Blog Posts", + blogSidebarCount: "ALL", + postsPerPage: "ALL", + feedOptions: { + type: "all", + title: "OpenAssistant Blog", + description: "Home of the OpenAssistant blog.", + language: "en", + copyright: `Copyright © ${new Date().getFullYear()} OpenAssistant.`, + }, + }, theme: { customCss: require.resolve("./src/css/custom.css"), }, @@ -65,6 +80,7 @@ const config = { position: "left", label: "Docs", }, + { to: "/blog", label: "Blog", position: "left" }, { to: "/api", label: "API", position: "left" }, { href: "https://github.com/LAION-AI/Open-Assistant", diff --git a/docs/package.json b/docs/package.json index de35a1a1..92d0c43a 100644 --- a/docs/package.json +++ b/docs/package.json @@ -15,18 +15,19 @@ "typecheck": "tsc" }, "dependencies": { - "@docusaurus/core": "2.2.0", - "@docusaurus/preset-classic": "2.2.0", + "@docusaurus/core": "^2.3.1", + "@docusaurus/preset-classic": "^2.3.1", "@mdx-js/react": "^1.6.22", "clsx": "^1.2.1", "docusaurus-preset-openapi": "^0.6.3", "prism-react-renderer": "^1.3.5", "react": "^17.0.2", "react-dom": "^17.0.2", + "react-player": "^2.11.0", "url": "^0.11.0" }, "devDependencies": { - "@docusaurus/module-type-aliases": "2.2.0", + "@docusaurus/module-type-aliases": "^2.3.1", "@tsconfig/docusaurus": "^1.0.5", "typescript": "^4.7.4" }, diff --git a/docs/yarn.lock b/docs/yarn.lock index da04c19f..7964f6df 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -1275,6 +1275,83 @@ webpack-merge "^5.8.0" webpackbar "^5.0.2" +"@docusaurus/core@2.3.1", "@docusaurus/core@^2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-2.3.1.tgz#32849f2ffd2f086a4e55739af8c4195c5eb386f2" + integrity sha512-0Jd4jtizqnRAr7svWaBbbrCCN8mzBNd2xFLoT/IM7bGfFie5y58oz97KzXliwiLY3zWjqMXjQcuP1a5VgCv2JA== + dependencies: + "@babel/core" "^7.18.6" + "@babel/generator" "^7.18.7" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-transform-runtime" "^7.18.6" + "@babel/preset-env" "^7.18.6" + "@babel/preset-react" "^7.18.6" + "@babel/preset-typescript" "^7.18.6" + "@babel/runtime" "^7.18.6" + "@babel/runtime-corejs3" "^7.18.6" + "@babel/traverse" "^7.18.8" + "@docusaurus/cssnano-preset" "2.3.1" + "@docusaurus/logger" "2.3.1" + "@docusaurus/mdx-loader" "2.3.1" + "@docusaurus/react-loadable" "5.5.2" + "@docusaurus/utils" "2.3.1" + "@docusaurus/utils-common" "2.3.1" + "@docusaurus/utils-validation" "2.3.1" + "@slorber/static-site-generator-webpack-plugin" "^4.0.7" + "@svgr/webpack" "^6.2.1" + autoprefixer "^10.4.7" + babel-loader "^8.2.5" + babel-plugin-dynamic-import-node "^2.3.3" + boxen "^6.2.1" + chalk "^4.1.2" + chokidar "^3.5.3" + clean-css "^5.3.0" + cli-table3 "^0.6.2" + combine-promises "^1.1.0" + commander "^5.1.0" + copy-webpack-plugin "^11.0.0" + core-js "^3.23.3" + css-loader "^6.7.1" + css-minimizer-webpack-plugin "^4.0.0" + cssnano "^5.1.12" + del "^6.1.1" + detect-port "^1.3.0" + escape-html "^1.0.3" + eta "^2.0.0" + file-loader "^6.2.0" + fs-extra "^10.1.0" + html-minifier-terser "^6.1.0" + html-tags "^3.2.0" + html-webpack-plugin "^5.5.0" + import-fresh "^3.3.0" + leven "^3.1.0" + lodash "^4.17.21" + mini-css-extract-plugin "^2.6.1" + postcss "^8.4.14" + postcss-loader "^7.0.0" + prompts "^2.4.2" + react-dev-utils "^12.0.1" + react-helmet-async "^1.3.0" + react-loadable "npm:@docusaurus/react-loadable@5.5.2" + react-loadable-ssr-addon-v5-slorber "^1.0.1" + react-router "^5.3.3" + react-router-config "^5.1.1" + react-router-dom "^5.3.3" + rtl-detect "^1.0.4" + semver "^7.3.7" + serve-handler "^6.1.3" + shelljs "^0.8.5" + terser-webpack-plugin "^5.3.3" + tslib "^2.4.0" + update-notifier "^5.1.0" + url-loader "^4.1.1" + wait-on "^6.0.1" + webpack "^5.73.0" + webpack-bundle-analyzer "^4.5.0" + webpack-dev-server "^4.9.3" + webpack-merge "^5.8.0" + webpackbar "^5.0.2" + "@docusaurus/cssnano-preset@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-2.2.0.tgz#fc05044659051ae74ab4482afcf4a9936e81d523" @@ -1285,6 +1362,16 @@ postcss-sort-media-queries "^4.2.1" tslib "^2.4.0" +"@docusaurus/cssnano-preset@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-2.3.1.tgz#e042487655e3e062417855e12edb3f6eee8f5ecb" + integrity sha512-7mIhAROES6CY1GmCjR4CZkUfjTL6B3u6rKHK0ChQl2d1IevYXq/k/vFgvOrJfcKxiObpMnE9+X6R2Wt1KqxC6w== + dependencies: + cssnano-preset-advanced "^5.3.8" + postcss "^8.4.14" + postcss-sort-media-queries "^4.2.1" + tslib "^2.4.0" + "@docusaurus/logger@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-2.2.0.tgz#ea2f7feda7b8675485933b87f06d9c976d17423f" @@ -1293,6 +1380,14 @@ chalk "^4.1.2" tslib "^2.4.0" +"@docusaurus/logger@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-2.3.1.tgz#d76aefb452e3734b4e0e645efc6cbfc0aae52869" + integrity sha512-2lAV/olKKVr9qJhfHFCaqBIl8FgYjbUFwgUnX76+cULwQYss+42ZQ3grHGFvI0ocN2X55WcYe64ellQXz7suqg== + dependencies: + chalk "^4.1.2" + tslib "^2.4.0" + "@docusaurus/mdx-loader@2.2.0", "@docusaurus/mdx-loader@^2.0.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-2.2.0.tgz#fd558f429e5d9403d284bd4214e54d9768b041a0" @@ -1316,6 +1411,29 @@ url-loader "^4.1.1" webpack "^5.73.0" +"@docusaurus/mdx-loader@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-2.3.1.tgz#7ec6acee5eff0a280e1b399ea4dd690b15a793f7" + integrity sha512-Gzga7OsxQRpt3392K9lv/bW4jGppdLFJh3luKRknCKSAaZrmVkOQv2gvCn8LAOSZ3uRg5No7AgYs/vpL8K94lA== + dependencies: + "@babel/parser" "^7.18.8" + "@babel/traverse" "^7.18.8" + "@docusaurus/logger" "2.3.1" + "@docusaurus/utils" "2.3.1" + "@mdx-js/mdx" "^1.6.22" + escape-html "^1.0.3" + file-loader "^6.2.0" + fs-extra "^10.1.0" + image-size "^1.0.1" + mdast-util-to-string "^2.0.0" + remark-emoji "^2.2.0" + stringify-object "^3.3.0" + tslib "^2.4.0" + unified "^9.2.2" + unist-util-visit "^2.0.3" + url-loader "^4.1.1" + webpack "^5.73.0" + "@docusaurus/module-type-aliases@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-2.2.0.tgz#1e23e54a1bbb6fde1961e4fa395b1b69f4803ba5" @@ -1330,6 +1448,20 @@ react-helmet-async "*" react-loadable "npm:@docusaurus/react-loadable@5.5.2" +"@docusaurus/module-type-aliases@2.3.1", "@docusaurus/module-type-aliases@^2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-2.3.1.tgz#986186200818fed999be2e18d6c698eaf4683a33" + integrity sha512-6KkxfAVOJqIUynTRb/tphYCl+co3cP0PlHiMDbi+SzmYxMdgIrwYqH9yAnGSDoN6Jk2ZE/JY/Azs/8LPgKP48A== + dependencies: + "@docusaurus/react-loadable" "5.5.2" + "@docusaurus/types" "2.3.1" + "@types/history" "^4.7.11" + "@types/react" "*" + "@types/react-router-config" "*" + "@types/react-router-dom" "*" + react-helmet-async "*" + react-loadable "npm:@docusaurus/react-loadable@5.5.2" + "@docusaurus/plugin-content-blog@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.2.0.tgz#dc55982e76771f4e678ac10e26d10e1da2011dc1" @@ -1352,6 +1484,28 @@ utility-types "^3.10.0" webpack "^5.73.0" +"@docusaurus/plugin-content-blog@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.3.1.tgz#236b8ee4f20f7047aa9c285ae77ae36683ad48a3" + integrity sha512-f5LjqX+9WkiLyGiQ41x/KGSJ/9bOjSD8lsVhPvYeUYHCtYpuiDKfhZE07O4EqpHkBx4NQdtQDbp+aptgHSTuiw== + dependencies: + "@docusaurus/core" "2.3.1" + "@docusaurus/logger" "2.3.1" + "@docusaurus/mdx-loader" "2.3.1" + "@docusaurus/types" "2.3.1" + "@docusaurus/utils" "2.3.1" + "@docusaurus/utils-common" "2.3.1" + "@docusaurus/utils-validation" "2.3.1" + cheerio "^1.0.0-rc.12" + feed "^4.2.2" + fs-extra "^10.1.0" + lodash "^4.17.21" + reading-time "^1.5.0" + tslib "^2.4.0" + unist-util-visit "^2.0.3" + utility-types "^3.10.0" + webpack "^5.73.0" + "@docusaurus/plugin-content-docs@2.2.0", "@docusaurus/plugin-content-docs@^2.0.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.2.0.tgz#0fcb85226fcdb80dc1e2d4a36ef442a650dcc84d" @@ -1374,6 +1528,28 @@ utility-types "^3.10.0" webpack "^5.73.0" +"@docusaurus/plugin-content-docs@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.3.1.tgz#feae1555479558a55182f22f8a07acc5e0d7444d" + integrity sha512-DxztTOBEruv7qFxqUtbsqXeNcHqcVEIEe+NQoI1oi2DBmKBhW/o0MIal8lt+9gvmpx3oYtlwmLOOGepxZgJGkw== + dependencies: + "@docusaurus/core" "2.3.1" + "@docusaurus/logger" "2.3.1" + "@docusaurus/mdx-loader" "2.3.1" + "@docusaurus/module-type-aliases" "2.3.1" + "@docusaurus/types" "2.3.1" + "@docusaurus/utils" "2.3.1" + "@docusaurus/utils-validation" "2.3.1" + "@types/react-router-config" "^5.0.6" + combine-promises "^1.1.0" + fs-extra "^10.1.0" + import-fresh "^3.3.0" + js-yaml "^4.1.0" + lodash "^4.17.21" + tslib "^2.4.0" + utility-types "^3.10.0" + webpack "^5.73.0" + "@docusaurus/plugin-content-pages@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.2.0.tgz#e3f40408787bbe229545dd50595f87e1393bc3ae" @@ -1388,6 +1564,20 @@ tslib "^2.4.0" webpack "^5.73.0" +"@docusaurus/plugin-content-pages@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.3.1.tgz#f534a37862be5b3f2ba5b150458d7527646b6f39" + integrity sha512-E80UL6hvKm5VVw8Ka8YaVDtO6kWWDVUK4fffGvkpQ/AJQDOg99LwOXKujPoICC22nUFTsZ2Hp70XvpezCsFQaA== + dependencies: + "@docusaurus/core" "2.3.1" + "@docusaurus/mdx-loader" "2.3.1" + "@docusaurus/types" "2.3.1" + "@docusaurus/utils" "2.3.1" + "@docusaurus/utils-validation" "2.3.1" + fs-extra "^10.1.0" + tslib "^2.4.0" + webpack "^5.73.0" + "@docusaurus/plugin-debug@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-2.2.0.tgz#b38741d2c492f405fee01ee0ef2e0029cedb689a" @@ -1400,6 +1590,18 @@ react-json-view "^1.21.3" tslib "^2.4.0" +"@docusaurus/plugin-debug@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-2.3.1.tgz#26fef904713e148f6dee44957506280f8b7853bb" + integrity sha512-Ujpml1Ppg4geB/2hyu2diWnO49az9U2bxM9Shen7b6qVcyFisNJTkVG2ocvLC7wM1efTJcUhBO6zAku2vKJGMw== + dependencies: + "@docusaurus/core" "2.3.1" + "@docusaurus/types" "2.3.1" + "@docusaurus/utils" "2.3.1" + fs-extra "^10.1.0" + react-json-view "^1.21.3" + tslib "^2.4.0" + "@docusaurus/plugin-google-analytics@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.2.0.tgz#63c7137eff5a1208d2059fea04b5207c037d7954" @@ -1410,6 +1612,16 @@ "@docusaurus/utils-validation" "2.2.0" tslib "^2.4.0" +"@docusaurus/plugin-google-analytics@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.3.1.tgz#e2e7db4cf6a7063e8ba5e128d4e413f4d6a0c862" + integrity sha512-OHip0GQxKOFU8n7gkt3TM4HOYTXPCFDjqKbMClDD3KaDnyTuMp/Zvd9HSr770lLEscgPWIvzhJByRAClqsUWiQ== + dependencies: + "@docusaurus/core" "2.3.1" + "@docusaurus/types" "2.3.1" + "@docusaurus/utils-validation" "2.3.1" + tslib "^2.4.0" + "@docusaurus/plugin-google-gtag@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.2.0.tgz#7b086d169ac5fe9a88aca10ab0fd2bf00c6c6b12" @@ -1420,6 +1632,26 @@ "@docusaurus/utils-validation" "2.2.0" tslib "^2.4.0" +"@docusaurus/plugin-google-gtag@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.3.1.tgz#b8da54a60c0a50aca609c3643faef78cb4f247a0" + integrity sha512-uXtDhfu4+Hm+oqWUySr3DNI5cWC/rmP6XJyAk83Heor3dFjZqDwCbkX8yWPywkRiWev3Dk/rVF8lEn0vIGVocA== + dependencies: + "@docusaurus/core" "2.3.1" + "@docusaurus/types" "2.3.1" + "@docusaurus/utils-validation" "2.3.1" + tslib "^2.4.0" + +"@docusaurus/plugin-google-tag-manager@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-2.3.1.tgz#f19bc01cc784fa4734187c5bc637f0574857e15d" + integrity sha512-Ww2BPEYSqg8q8tJdLYPFFM3FMDBCVhEM4UUqKzJaiRMx3NEoly3qqDRAoRDGdIhlC//Rf0iJV9cWAoq2m6k3sw== + dependencies: + "@docusaurus/core" "2.3.1" + "@docusaurus/types" "2.3.1" + "@docusaurus/utils-validation" "2.3.1" + tslib "^2.4.0" + "@docusaurus/plugin-sitemap@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.2.0.tgz#876da60937886032d63143253d420db6a4b34773" @@ -1435,7 +1667,22 @@ sitemap "^7.1.1" tslib "^2.4.0" -"@docusaurus/preset-classic@2.2.0", "@docusaurus/preset-classic@^2.0.0": +"@docusaurus/plugin-sitemap@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.3.1.tgz#f526ab517ca63b7a3460d585876f5952cb908aa0" + integrity sha512-8Yxile/v6QGYV9vgFiYL+8d2N4z4Er3pSHsrD08c5XI8bUXxTppMwjarDUTH/TRTfgAWotRbhJ6WZLyajLpozA== + dependencies: + "@docusaurus/core" "2.3.1" + "@docusaurus/logger" "2.3.1" + "@docusaurus/types" "2.3.1" + "@docusaurus/utils" "2.3.1" + "@docusaurus/utils-common" "2.3.1" + "@docusaurus/utils-validation" "2.3.1" + fs-extra "^10.1.0" + sitemap "^7.1.1" + tslib "^2.4.0" + +"@docusaurus/preset-classic@^2.0.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-2.2.0.tgz#bece5a043eeb74430f7c6c7510000b9c43669eb7" integrity sha512-yKIWPGNx7BT8v2wjFIWvYrS+nvN04W+UameSFf8lEiJk6pss0kL6SG2MRvyULiI3BDxH+tj6qe02ncpSPGwumg== @@ -1453,6 +1700,25 @@ "@docusaurus/theme-search-algolia" "2.2.0" "@docusaurus/types" "2.2.0" +"@docusaurus/preset-classic@^2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-2.3.1.tgz#f0193f06093eb55cafef66bd1ad9e0d33198bf95" + integrity sha512-OQ5W0AHyfdUk0IldwJ3BlnZ1EqoJuu2L2BMhqLbqwNWdkmzmSUvlFLH1Pe7CZSQgB2YUUC/DnmjbPKk/qQD0lQ== + dependencies: + "@docusaurus/core" "2.3.1" + "@docusaurus/plugin-content-blog" "2.3.1" + "@docusaurus/plugin-content-docs" "2.3.1" + "@docusaurus/plugin-content-pages" "2.3.1" + "@docusaurus/plugin-debug" "2.3.1" + "@docusaurus/plugin-google-analytics" "2.3.1" + "@docusaurus/plugin-google-gtag" "2.3.1" + "@docusaurus/plugin-google-tag-manager" "2.3.1" + "@docusaurus/plugin-sitemap" "2.3.1" + "@docusaurus/theme-classic" "2.3.1" + "@docusaurus/theme-common" "2.3.1" + "@docusaurus/theme-search-algolia" "2.3.1" + "@docusaurus/types" "2.3.1" + "@docusaurus/react-loadable@5.5.2", "react-loadable@npm:@docusaurus/react-loadable@5.5.2": version "5.5.2" resolved "https://registry.yarnpkg.com/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz#81aae0db81ecafbdaee3651f12804580868fa6ce" @@ -1492,6 +1758,37 @@ tslib "^2.4.0" utility-types "^3.10.0" +"@docusaurus/theme-classic@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-2.3.1.tgz#8e6e194236e702c0d4e8d7b7cbb6886ae456e598" + integrity sha512-SelSIDvyttb7ZYHj8vEUhqykhAqfOPKk+uP0z85jH72IMC58e7O8DIlcAeBv+CWsLbNIl9/Hcg71X0jazuxJug== + dependencies: + "@docusaurus/core" "2.3.1" + "@docusaurus/mdx-loader" "2.3.1" + "@docusaurus/module-type-aliases" "2.3.1" + "@docusaurus/plugin-content-blog" "2.3.1" + "@docusaurus/plugin-content-docs" "2.3.1" + "@docusaurus/plugin-content-pages" "2.3.1" + "@docusaurus/theme-common" "2.3.1" + "@docusaurus/theme-translations" "2.3.1" + "@docusaurus/types" "2.3.1" + "@docusaurus/utils" "2.3.1" + "@docusaurus/utils-common" "2.3.1" + "@docusaurus/utils-validation" "2.3.1" + "@mdx-js/react" "^1.6.22" + clsx "^1.2.1" + copy-text-to-clipboard "^3.0.1" + infima "0.2.0-alpha.42" + lodash "^4.17.21" + nprogress "^0.2.0" + postcss "^8.4.14" + prism-react-renderer "^1.3.5" + prismjs "^1.28.0" + react-router-dom "^5.3.3" + rtlcss "^3.5.0" + tslib "^2.4.0" + utility-types "^3.10.0" + "@docusaurus/theme-common@2.2.0", "@docusaurus/theme-common@^2.0.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-2.2.0.tgz#2303498d80448aafdd588b597ce9d6f4cfa930e4" @@ -1512,6 +1809,27 @@ tslib "^2.4.0" utility-types "^3.10.0" +"@docusaurus/theme-common@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-2.3.1.tgz#82f52d80226efef8c4418c4eacfc5051aa215f7f" + integrity sha512-RYmYl2OR2biO+yhmW1aS5FyEvnrItPINa+0U2dMxcHpah8reSCjQ9eJGRmAgkZFchV1+aIQzXOI1K7LCW38O0g== + dependencies: + "@docusaurus/mdx-loader" "2.3.1" + "@docusaurus/module-type-aliases" "2.3.1" + "@docusaurus/plugin-content-blog" "2.3.1" + "@docusaurus/plugin-content-docs" "2.3.1" + "@docusaurus/plugin-content-pages" "2.3.1" + "@docusaurus/utils" "2.3.1" + "@types/history" "^4.7.11" + "@types/react" "*" + "@types/react-router-config" "*" + clsx "^1.2.1" + parse-numeric-range "^1.3.0" + prism-react-renderer "^1.3.5" + tslib "^2.4.0" + use-sync-external-store "^1.2.0" + utility-types "^3.10.0" + "@docusaurus/theme-search-algolia@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.2.0.tgz#77fd9f7a600917e6024fe3ac7fb6cfdf2ce84737" @@ -1534,6 +1852,28 @@ tslib "^2.4.0" utility-types "^3.10.0" +"@docusaurus/theme-search-algolia@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.3.1.tgz#d587b40913119e9287d14670e277b933d8f453f0" + integrity sha512-JdHaRqRuH1X++g5fEMLnq7OtULSGQdrs9AbhcWRQ428ZB8/HOiaN6mj3hzHvcD3DFgu7koIVtWPQnvnN7iwzHA== + dependencies: + "@docsearch/react" "^3.1.1" + "@docusaurus/core" "2.3.1" + "@docusaurus/logger" "2.3.1" + "@docusaurus/plugin-content-docs" "2.3.1" + "@docusaurus/theme-common" "2.3.1" + "@docusaurus/theme-translations" "2.3.1" + "@docusaurus/utils" "2.3.1" + "@docusaurus/utils-validation" "2.3.1" + algoliasearch "^4.13.1" + algoliasearch-helper "^3.10.0" + clsx "^1.2.1" + eta "^2.0.0" + fs-extra "^10.1.0" + lodash "^4.17.21" + tslib "^2.4.0" + utility-types "^3.10.0" + "@docusaurus/theme-translations@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-2.2.0.tgz#5fbd4693679806f80c26eeae1381e1f2c23d83e7" @@ -1542,6 +1882,14 @@ fs-extra "^10.1.0" tslib "^2.4.0" +"@docusaurus/theme-translations@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-2.3.1.tgz#b2b1ecc00a737881b5bfabc19f90b20f0fe02bb3" + integrity sha512-BsBZzAewJabVhoGG1Ij2u4pMS3MPW6gZ6sS4pc+Y7czevRpzxoFNJXRtQDVGe7mOpv/MmRmqg4owDK+lcOTCVQ== + dependencies: + fs-extra "^10.1.0" + tslib "^2.4.0" + "@docusaurus/types@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-2.2.0.tgz#02c577a4041ab7d058a3c214ccb13647e21a9857" @@ -1556,6 +1904,20 @@ webpack "^5.73.0" webpack-merge "^5.8.0" +"@docusaurus/types@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-2.3.1.tgz#785ade2e0f4e35e1eb7fb0d04c27d11c3991a2e8" + integrity sha512-PREbIRhTaNNY042qmfSE372Jb7djZt+oVTZkoqHJ8eff8vOIc2zqqDqBVc5BhOfpZGPTrE078yy/torUEZy08A== + dependencies: + "@types/history" "^4.7.11" + "@types/react" "*" + commander "^5.1.0" + joi "^17.6.0" + react-helmet-async "^1.3.0" + utility-types "^3.10.0" + webpack "^5.73.0" + webpack-merge "^5.8.0" + "@docusaurus/utils-common@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-2.2.0.tgz#a401c1b93a8697dd566baf6ac64f0fdff1641a78" @@ -1563,6 +1925,13 @@ dependencies: tslib "^2.4.0" +"@docusaurus/utils-common@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-2.3.1.tgz#1abe66846eb641547e4964d44f3011938e58e50b" + integrity sha512-pVlRpXkdNcxmKNxAaB1ya2hfCEvVsLDp2joeM6K6uv55Oc5nVIqgyYSgSNKZyMdw66NnvMfsu0RBylcwZQKo9A== + dependencies: + tslib "^2.4.0" + "@docusaurus/utils-validation@2.2.0", "@docusaurus/utils-validation@^2.0.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-2.2.0.tgz#04d4d103137ad0145883971d3aa497f4a1315f25" @@ -1574,6 +1943,17 @@ js-yaml "^4.1.0" tslib "^2.4.0" +"@docusaurus/utils-validation@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-2.3.1.tgz#b65c718ba9b84b7a891bccf5ac6d19b57ee7d887" + integrity sha512-7n0208IG3k1HVTByMHlZoIDjjOFC8sbViHVXJx0r3Q+3Ezrx+VQ1RZ/zjNn6lT+QBCRCXlnlaoJ8ug4HIVgQ3w== + dependencies: + "@docusaurus/logger" "2.3.1" + "@docusaurus/utils" "2.3.1" + joi "^17.6.0" + js-yaml "^4.1.0" + tslib "^2.4.0" + "@docusaurus/utils@2.2.0", "@docusaurus/utils@^2.0.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-2.2.0.tgz#3d6f9b7a69168d5c92d371bf21c556a4f50d1da6" @@ -1595,6 +1975,28 @@ url-loader "^4.1.1" webpack "^5.73.0" +"@docusaurus/utils@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-2.3.1.tgz#24b9cae3a23b1e6dc88f95c45722c7e82727b032" + integrity sha512-9WcQROCV0MmrpOQDXDGhtGMd52DHpSFbKLfkyaYumzbTstrbA5pPOtiGtxK1nqUHkiIv8UwexS54p0Vod2I1lg== + dependencies: + "@docusaurus/logger" "2.3.1" + "@svgr/webpack" "^6.2.1" + escape-string-regexp "^4.0.0" + file-loader "^6.2.0" + fs-extra "^10.1.0" + github-slugger "^1.4.0" + globby "^11.1.0" + gray-matter "^4.0.3" + js-yaml "^4.1.0" + lodash "^4.17.21" + micromatch "^4.0.5" + resolve-pathname "^3.0.0" + shelljs "^0.8.5" + tslib "^2.4.0" + url-loader "^4.1.1" + webpack "^5.73.0" + "@faker-js/faker@5.5.3": version "5.5.3" resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-5.5.3.tgz#18e3af6b8eae7984072bbeb0c0858474d7c4cefe" @@ -3456,6 +3858,11 @@ deep-extend@^0.6.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== +deepmerge@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.0.tgz#65491893ec47756d44719ae520e0e2609233b59b" + integrity sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og== + deepmerge@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" @@ -3899,6 +4306,11 @@ eta@^1.12.3: resolved "https://registry.yarnpkg.com/eta/-/eta-1.12.3.tgz#2982d08adfbef39f9fa50e2fbd42d7337e7338b1" integrity sha512-qHixwbDLtekO/d51Yr4glcaUJCIjGVJyTzuqV4GPlgZo1YpgOKG+avQynErZIYrfM6JIJdtiG2Kox8tbb+DoGg== +eta@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/eta/-/eta-2.0.0.tgz#376865fadebc899e5b6dfce82fae64cbbe47e594" + integrity sha512-NqE7S2VmVwgMS8yBxsH4VgNQjNjLq1gfGU0u9I6Cjh468nPRMoDfGdK9n1p/3Dvsw3ebklDkZsFAnKJ9sefjBA== + etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" @@ -5254,6 +5666,11 @@ liquid-json@0.3.1: resolved "https://registry.yarnpkg.com/liquid-json/-/liquid-json-0.3.1.tgz#9155a18136d8a6b2615e5f16f9a2448ab6b50eea" integrity sha512-wUayTU8MS827Dam6MxgD72Ui+KOSF+u/eIqpatOtjnvgJ0+mnDq33uC2M7J0tPK+upe/DpUAuK4JUU89iBoNKQ== +load-script@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/load-script/-/load-script-1.0.0.tgz#0491939e0bee5643ee494a7e3da3d2bac70c6ca4" + integrity sha512-kPEjMFtZvwL9TaZo0uZ2ml+Ye9HUMmPwbYRJ324qF9tqMejwykJ5ggTyvzmrbBeapCAbk98BSbTeovHEEP1uCA== + loader-runner@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" @@ -5470,6 +5887,11 @@ memfs@^3.1.2, memfs@^3.4.3: dependencies: fs-monkey "^1.0.3" +memoize-one@^5.1.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" + integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== + merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -6715,7 +7137,7 @@ react-error-overlay@^6.0.11: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb" integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg== -react-fast-compare@^3.2.0: +react-fast-compare@^3.0.1, react-fast-compare@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== @@ -6768,6 +7190,17 @@ react-magic-dropzone@^1.0.1: resolved "https://registry.yarnpkg.com/react-magic-dropzone/-/react-magic-dropzone-1.0.1.tgz#bfd25b77b57e7a04aaef0a28910563b707ee54df" integrity sha512-0BIROPARmXHpk4AS3eWBOsewxoM5ndk2psYP/JmbCq8tz3uR2LIV1XiroZ9PKrmDRMctpW+TvsBCtWasuS8vFA== +react-player@^2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/react-player/-/react-player-2.11.0.tgz#9afc75314eb915238e8d6615b2891fbe7170aeaa" + integrity sha512-fIrwpuXOBXdEg1FiyV9isKevZOaaIsAAtZy5fcjkQK9Nhmk1I2NXzY/hkPos8V0zb/ZX416LFy8gv7l/1k3a5w== + dependencies: + deepmerge "^4.0.0" + load-script "^1.0.0" + memoize-one "^5.1.1" + prop-types "^15.7.2" + react-fast-compare "^3.0.1" + react-redux@^7.2.0: version "7.2.9" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.9.tgz#09488fbb9416a4efe3735b7235055442b042481d" @@ -8091,6 +8524,11 @@ use-latest@^1.2.1: dependencies: use-isomorphic-layout-effect "^1.1.1" +use-sync-external-store@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" + integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== + util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" From 204f45b150cec6ac05544682506b3119288377f9 Mon Sep 17 00:00:00 2001 From: Desmond Grealy <111158332+k-nearest-neighbor@users.noreply.github.com> Date: Sun, 5 Feb 2023 13:28:54 -0800 Subject: [PATCH 089/152] Update FAQ to address common questions we are seeing (#1193) * First draft of new FAQ copy * update answers for data license and hardware --- website/public/locales/en/index.json | 10 +++++++++- website/src/components/Faq.tsx | 4 ++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/website/public/locales/en/index.json b/website/public/locales/en/index.json index 7d8c9152..a6e89b9c 100644 --- a/website/public/locales/en/index.json +++ b/website/public/locales/en/index.json @@ -6,7 +6,15 @@ "q0": "How far along is this project?", "a0": "We are in the early stages of development, working from established research in applying RLHF to large language models.", "q1": "Who is behind Open Assistant?", - "a1": "Open Assistant is a project organized by LAION and individuals around the world interested in bringing this technology to everyone." + "a1": "Open Assistant is a project organized by LAION and individuals around the world interested in bringing this technology to everyone.", + "q2": "What license does Open Assistant use?", + "a2": "The code and models are licensed under the Apache 2.0 license.", + "q3": "Will the training data also be released?", + "a3": "Yes, under CC BY 4.0.", + "q4": "Will Open Assistant be free?", + "a4": "Yes, Open Assistant will be free to use and modify.", + "q5": "What hardware will be required to run the models?", + "a5": "There will be versions which will be runnable on consumer hardware." }, "faq_title": "Frequently Asked Questions", "join_us_description": "All open source projects begin with people like you. Open source is the belief that if we collaborate we can together gift our knowledge and technology to the world for the benefit of humanity. Are you in? Find us here:", diff --git a/website/src/components/Faq.tsx b/website/src/components/Faq.tsx index 46d5d19c..04b02729 100644 --- a/website/src/components/Faq.tsx +++ b/website/src/components/Faq.tsx @@ -3,7 +3,7 @@ import { useTranslation } from "next-i18next"; import { Container } from "./Container"; -const FAQS = Array.from({ length: 2 }); +const FAQS = Array.from({ length: 6 }); export function Faq() { const { colorMode } = useColorMode(); @@ -21,7 +21,7 @@ export function Faq() { {FAQS.map((_, index) => { return ( From f6e7bc72fa26cfa854025384eb91c6a8ee08b2c5 Mon Sep 17 00:00:00 2001 From: Andrew Maguire Date: Sun, 5 Feb 2023 21:40:52 +0000 Subject: [PATCH 090/152] add link to app in docs site (#1211) --- docs/docusaurus.config.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 2102105c..6e3ffa78 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -74,6 +74,11 @@ const config = { src: "img/logo.svg", }, items: [ + { + href: "https://open-assistant.io/", + label: "App", + position: "left", + }, { type: "doc", docId: "intro", From 196cc0c58e657537719b4409a425a3ddc9ba8cc8 Mon Sep 17 00:00:00 2001 From: Oliver Stanley Date: Sun, 5 Feb 2023 23:30:30 +0000 Subject: [PATCH 091/152] 1216: Add quickstart data collection guide (#1219) * Create data_collection.md --- docs/docs/guides/data_collection.md | 83 +++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 docs/docs/guides/data_collection.md diff --git a/docs/docs/guides/data_collection.md b/docs/docs/guides/data_collection.md new file mode 100644 index 00000000..4dce205c --- /dev/null +++ b/docs/docs/guides/data_collection.md @@ -0,0 +1,83 @@ +# Data Collection Guide + +## Writing Prompts (Initial Prompts or Prompter Replies) + +Attempt to post a **diverse range** of prompts. When posting a prompt, consider +whether it is likely to be original. Collecting the same prompt many times is +usually not useful. + +Prompts can be on any topic but should not be obscene or hateful. Prompts go +through a moderation process just like answers, so spammy or inappropriate +prompts will be removed. + +Do **not** include personally identifiable information (PII) in prompts. This +will be moderated out. + +Prompts should not include links which the assistant must open to effectively +answer the prompt. + +### Prompts: Spelling and Grammar + +For prompts, grammar and spelling is significantly less important than answers. +If the grammar of a prompt makes it **ambiguous or unreadable** it should be +considered low quality, but if it simply contains common typos this is not a +problem. + +## Writing Answers (Assistant Replies) + +Answers should aim to match the tone of the prompt. Prompts which are to the +point should receive answers which are to the point. Answers should not be +unnecessarily formal and should be **conversational** in a manner a human may +write. Avoid jargon if possible. + +Attempt to answer in a way which accurately fulfils the request in the prompt. +Low quality answers will be moderated. Longer answers tend to be preferable +_unless_ the prompt is sufficiently simple to justify a shorter one. + +Where possible, **avoid bias** or expressing subjective preferences in answers. +Do **not** write answers which encourage illegal activities or activities likely +to be harmful to the user or others around them. + +### Answers: ChatGPT + +**Do not copy answers from ChatGPT** or other OpenAI services. It is prohibited +according to the OpenAI Terms of Service. Obvious ChatGPT-generated answers +should be reported in moderation and rated low quality. Other AI systems may +allow such usage, but answers should still **not** be copied and pasted. + +### Answers: Spelling and Grammar + +Answers should be held to a high standard of grammar and spelling. It **is** +permissible for answers to contain sources or references provided they are +relevant and from reputable websites. However, this is **not** required. + +## Ranking and Classifying Prompts + +Largely the criteria for "quality" can be derived by how well the prompt follows +the guidance +[above](https://github.com/LAION-AI/Open-Assistant/blob/main/docs/docs/guides#writing-prompts-initial-prompts-or-prompter-replies). +The other labels are largely self-explanatory. + +Spam should be reserved for intentionally low effort or low quality prompts. + +It is usually fine to go closer to "Ordinary" than "Creative" unless there is +obvious creativity shown. The same goes for "Serious" compared to "Humorous". + +## Ranking and Classifying Answers + +Your rankings and classification will help decide which answers are the best and +therefore which ones are prioritised in the final dataset. That means the answer +classification is a crucial task, serving as community moderation. + +Largely the criteria for "quality" can be derived by how well the prompt follows +the guidance +[above](https://github.com/LAION-AI/Open-Assistant/blob/main/docs/docs/guides#writing-answers-assistant-replies). +The other labels are largely self-explanatory. + +Spam should be reserved for intentionally low effort or low quality answers. + +The bad answer label should be given when the answer does not respond to the +prompt at all or is irrelevant. + +It is usually fine to go closer to "Ordinary" than "Creative" unless there is +obvious creativity shown. The same goes for "Serious" compared to "Humorous". From 7be3ca4b9ce24bbf2cc11d97ed9129bff957ab91 Mon Sep 17 00:00:00 2001 From: AbdBarho Date: Mon, 6 Feb 2023 03:20:28 +0100 Subject: [PATCH 092/152] Update german locale (#1166) also: sort keys in json alphabetically change the way files are printed to be grouped by language. This will be spicy since we have many german speakers here. --- .../find-missing-locales.py | 15 ++++++++---- website/public/locales/de/common.json | 7 +++++- website/public/locales/de/labelling.json | 24 ++++++++++++------- website/public/locales/de/leaderboard.json | 14 +++++++---- website/public/locales/en/common.json | 2 +- website/public/locales/en/labelling.json | 24 +++++++++---------- website/public/locales/en/leaderboard.json | 20 ++++++++-------- 7 files changed, 64 insertions(+), 42 deletions(-) diff --git a/scripts/frontend-development/find-missing-locales.py b/scripts/frontend-development/find-missing-locales.py index 6be52e58..09e3d761 100644 --- a/scripts/frontend-development/find-missing-locales.py +++ b/scripts/frontend-development/find-missing-locales.py @@ -1,3 +1,4 @@ +from collections import defaultdict from glob import glob from json import load from os import path @@ -23,10 +24,10 @@ def get_missing(en_json, translation_json): def print_result(missing, not_translated, file): if len(missing): - print("[{0}] - missing: {1} {2}".format(path.basename(path.dirname(file)), path.basename(file), missing)) + print("[{0}] - {1}\tmissing: {2}".format(path.basename(path.dirname(file)), path.basename(file), missing)) if len(not_translated): print( - "[{0}] - potentially untranslated: {1} {2}".format( + "[{0}] - {1}\tpotentially untranslated: {2}".format( path.basename(path.dirname(file)), path.basename(file), not_translated ) ) @@ -35,14 +36,20 @@ def print_result(missing, not_translated, file): def audit(file, en_file): en_json = load(open(en_file)) translation_json = load(open(file)) - print_result(get_missing(en_json, translation_json), get_not_translated(en_json, translation_json), file) + return (get_missing(en_json, translation_json), get_not_translated(en_json, translation_json), file) def main(): + per_language_dict = defaultdict(list) for en_file in glob(path.join(DIR, EN_PATH)): for file in glob(path.join(DIR, ALL_PATH)): if path.basename(en_file) == path.basename(file) and file != en_file: - audit(file, en_file) + file_info = audit(file, en_file) + lang = path.basename(path.dirname(file)) + per_language_dict[lang].append(file_info) + for results in per_language_dict.values(): + list(map(lambda args: print_result(*args), results)) + print() if __name__ == "__main__": diff --git a/website/public/locales/de/common.json b/website/public/locales/de/common.json index 279d48ae..d401f4cb 100644 --- a/website/public/locales/de/common.json +++ b/website/public/locales/de/common.json @@ -4,18 +4,23 @@ "admin_dashboard": "Admin-Bereich", "connect": "Kontakt aufnehmen", "conversational": "Konversations-KI für alle.", + "copied": "Kopiert", + "dark_mode": "Dunkler Modus", "dashboard": "Dashboard", + "delete": "Löschen", "discord": "Discord", "docs": "Doku", "github": "GitHub", "legal": "Rechtliches", + "light_mode": "Heller Modus", "loading": "Wird geladen...", - "more_information": "Weiter Informationen", + "more_information": "Weitere Informationen", "no": "Nein", "privacy_policy": "Datenschutz-Bestimmungen", "report_a_bug": "Einen Fehler melden", "sign_in": "Anmelden", "sign_out": "Abmelden", + "success": "Erfolg", "terms_of_service": "Nutzungsbedingungen", "title": "Open Assistant", "yes": "Ja" diff --git a/website/public/locales/de/labelling.json b/website/public/locales/de/labelling.json index 659a2f62..98f2ef00 100644 --- a/website/public/locales/de/labelling.json +++ b/website/public/locales/de/labelling.json @@ -1,17 +1,23 @@ { - "label_highlighted_yes_no_instruction": "Beantworten Sie die folgende(n) Frage(n) zu der markierten Nachricht:", + "fails_task.question": "Ist es eine schlechte Antwort, wenn man die Aufgabe sieht?", + "hate_speech": "Hassrede", + "hate_speech.explanation": "Inhalt ist beleidigend oder bedrohlich und drückt Vorurteile gegen eine geschützte Eigenschaft aus. Vorurteil bezieht sich auf vorgefasste Meinungen, die nicht auf Vernunft beruhen. Zu den geschützten Merkmalen gehören Geschlecht, ethnische Zugehörigkeit, Religion, sexuelle Orientierung, und ähnliche Merkmale.", "label_highlighted_flag_instruction": "Wählen Sie aus, was auf die markierte Nachricht zutrifft:", "label_highlighted_likert_instruction": "Bewerten Sie die markierte Nachricht:", - "label_message_yes_no_instruction": "Beantworten Sie die folgende(n) Frage(n) zur Nachricht:", + "label_highlighted_yes_no_instruction": "Beantworten Sie die folgende(n) Frage(n) zu der markierten Nachricht:", "label_message_flag_instruction": "Wählen Sie aus, was auf die Nachricht zutrifft:", "label_message_likert_instruction": "Nachricht bewerten:", - "spam.question": "Ist die Nachricht Spam?", - "fails_task.question": "Ist es eine schlechte Antwort, wenn man die Aufgabe sieht?", - "not_appropriate": "Nicht angemessen", - "pii": "Personenbezogene Daten", - "hate_speech": "Hassrede", - "sexual_content": "Sexueller Inhalt", + "label_message_yes_no_instruction": "Beantworten Sie die folgende(n) Frage(n) zur Nachricht:", + "lang_mismatch": "Sprachkonflikt", + "lang_mismatch.explanation": "Nicht in der aktuell ausgewählten Sprache geschrieben.", "moral_judgement": "Moralisches Urteil", + "moral_judgement.explanation": "Drückt ein moralisches Urteil aus.", + "not_appropriate": "Nicht angemessen", + "not_appropriate.explanation": "Nicht angemessen für einen Assistenten.", + "pii": "Personenbezogene Daten", + "pii.explanation": "Enthält personenbezogene Daten. Beispiele hierfür sind persönliche Kontaktdaten, Lizenz- und andere Identitätsnummern, sowie Bankdaten.", "political_content": "Politisch", - "lang_mismatch": "Sprachkonflikt" + "political_content.explanation": "Enthält politische Meinungen.", + "sexual_content": "Sexueller Inhalt", + "spam.question": "Ist die Nachricht Spam?" } diff --git a/website/public/locales/de/leaderboard.json b/website/public/locales/de/leaderboard.json index 3d716f26..2692e3a7 100644 --- a/website/public/locales/de/leaderboard.json +++ b/website/public/locales/de/leaderboard.json @@ -1,14 +1,18 @@ { "daily": "Täglich", + "label": "Labels", "last_updated_at": "Zuletzt aktualisiert: {{val, datetime}}", "leaderboard": "Bestenliste", "monthly": "Monatlich", + "next": "Nächste", "overall": "Gesamt", - "rank": "Rang", - "score": "Punktzahl", - "user": "Benutzer", - "weekly": "Wöchentlich", + "previous": "Vorherige", "prompt": "Prompts", + "rank": "Rang", "reply": "Antworten", - "label": "Labels" + "score": "Punktzahl", + "top_5_contributors_today": "Top 5 Benutzer heute", + "user": "Benutzer", + "view_all": "Alle anzeigen", + "weekly": "Wöchentlich" } diff --git a/website/public/locales/en/common.json b/website/public/locales/en/common.json index abc9fb21..b964b26a 100644 --- a/website/public/locales/en/common.json +++ b/website/public/locales/en/common.json @@ -2,9 +2,9 @@ "about": "About", "account_settings": "Account", "admin_dashboard": "Admin Dashboard", - "copied": "Copied", "connect": "Connect", "conversational": "Conversational AI for everyone.", + "copied": "Copied", "dark_mode": "Dark Mode", "dashboard": "Dashboard", "delete": "Delete", diff --git a/website/public/locales/en/labelling.json b/website/public/locales/en/labelling.json index 624de963..3eb7fb89 100644 --- a/website/public/locales/en/labelling.json +++ b/website/public/locales/en/labelling.json @@ -1,24 +1,24 @@ { - "label_highlighted_yes_no_instruction": "Answer the following question(s) about the highlighted message:", + "fails_task.question": "Is it a bad reply, as an answer to the prompt task?", + "hate_speech": "Hate Speech", + "hate_speech.explanation": "Content is abusive or threatening and expresses prejudice against a protected characteristic. Prejudice refers to preconceived views not based on reason. Protected characteristics include gender, ethnicity, religion, sexual orientation, and similar characteristics.", "label_highlighted_flag_instruction": "Select any that apply to the highlighted message:", "label_highlighted_likert_instruction": "Rate the highlighted message:", - "label_message_yes_no_instruction": "Answer the following question(s) about the message:", + "label_highlighted_yes_no_instruction": "Answer the following question(s) about the highlighted message:", "label_message_flag_instruction": "Select any that apply to the message:", "label_message_likert_instruction": "Rate the message:", - "spam.question": "Is the message spam?", - "fails_task.question": "Is it a bad reply, as an answer to the prompt task?", + "label_message_yes_no_instruction": "Answer the following question(s) about the message:", + "lang_mismatch": "Wrong Language", + "lang_mismatch.explanation": "Not written in the currently selected language.", + "moral_judgement": "Judges Morality", + "moral_judgement.explanation": "Expresses moral judgement.", "not_appropriate": "Not Appropriate", "not_appropriate.explanation": "Inappropriate for a customer assistant.", "pii": "Contains PII", "pii.explanation": "Contains personally identifying information. Examples include personal contact details, license and other identity numbers and banking details.", - "hate_speech": "Hate Speech", - "hate_speech.explanation": "Content is abusive or threatening and expresses prejudice against a protected characteristic. Prejudice refers to preconceived views not based on reason. Protected characteristics include gender, ethnicity, religion, sexual orientation, and similar characteristics.", - "sexual_content": "Sexual Content", - "sexual_content.explanation": "Contains sexual content.", - "moral_judgement": "Judges Morality", - "moral_judgement.explanation": "Expresses moral judgement.", "political_content": "Political", "political_content.explanation": "Expresses political views.", - "lang_mismatch": "Wrong Language", - "lang_mismatch.explanation": "Not written in the currently selected language." + "sexual_content": "Sexual Content", + "sexual_content.explanation": "Contains sexual content.", + "spam.question": "Is the message spam?" } diff --git a/website/public/locales/en/leaderboard.json b/website/public/locales/en/leaderboard.json index b2ab4173..cebe281d 100644 --- a/website/public/locales/en/leaderboard.json +++ b/website/public/locales/en/leaderboard.json @@ -1,18 +1,18 @@ { "daily": "Daily", + "label": "Labels", "last_updated_at": "Last updated at: {{val, datetime}}", "leaderboard": "Leaderboard", "monthly": "Monthly", + "next": "Next", "overall": "Overall", - "rank": "Rank", - "score": "Score", - "user": "User", - "weekly": "Weekly", - "prompt": "Prompts", - "reply": "Replies", - "label": "Labels", - "view_all": "View all", - "top_5_contributors_today": "Top 5 Contributors Today", "previous": "Previous", - "next": "Next" + "prompt": "Prompts", + "rank": "Rank", + "reply": "Replies", + "score": "Score", + "top_5_contributors_today": "Top 5 Contributors Today", + "user": "User", + "view_all": "View all", + "weekly": "Weekly" } From 852a2b73a97d61a793922a04d172db16e542935c Mon Sep 17 00:00:00 2001 From: AbdBarho Date: Mon, 6 Feb 2023 03:23:13 +0100 Subject: [PATCH 093/152] Use more screen realestate for tooltips (#1210) --- website/src/components/CollapsableText.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/src/components/CollapsableText.tsx b/website/src/components/CollapsableText.tsx index 1629b4bb..07382787 100644 --- a/website/src/components/CollapsableText.tsx +++ b/website/src/components/CollapsableText.tsx @@ -1,12 +1,12 @@ import { Button, - Tooltip, Modal, ModalBody, ModalCloseButton, ModalContent, ModalHeader, ModalOverlay, + Tooltip, useColorModeValue, useDisclosure, } from "@chakra-ui/react"; @@ -35,7 +35,7 @@ export const CollapsableText = ({ <> {text.substring(0, maxLength - 3)}  - + ); }; diff --git a/website/src/components/Messages/MessageTableEntry.tsx b/website/src/components/Messages/MessageTableEntry.tsx index 3fb8d59a..236602e3 100644 --- a/website/src/components/Messages/MessageTableEntry.tsx +++ b/website/src/components/Messages/MessageTableEntry.tsx @@ -40,8 +40,11 @@ export function MessageTableEntry({ message, enabled, highlight }: MessageTableE const router = useRouter(); const [emojiState, setEmojis] = useState({ emojis: {}, user_emojis: [] }); useEffect(() => { + const emojis = { ...message.emojis }; + emojis["+1"] = emojis["+1"] || 0; + emojis["-1"] = emojis["-1"] || 0; setEmojis({ - emojis: message?.emojis || {}, + emojis: emojis, user_emojis: message?.user_emojis || [], }); }, [message.emojis, message.user_emojis]); @@ -72,7 +75,11 @@ export function MessageTableEntry({ message, enabled, highlight }: MessageTableE const highlightColor = useColorModeValue(colors.light.active, colors.dark.active); const { trigger: sendEmojiChange } = useSWRMutation(`/api/messages/${message.id}/emoji`, post, { - onSuccess: setEmojis, + onSuccess: (data) => { + data.emojis["+1"] = data.emojis["+1"] || 0; + data.emojis["-1"] = data.emojis["-1"] || 0; + setEmojis(data); + }, }); const react = (emoji: string, state: boolean) => { sendEmojiChange({ op: state ? "add" : "remove", emoji }); @@ -102,14 +109,17 @@ export function MessageTableEntry({ message, enabled, highlight }: MessageTableE > {Object.entries(emojiState.emojis) .filter(([emoji]) => isKnownEmoji(emoji)) - .map(([emoji, count]) => ( - react(emoji, !emojiState.user_emojis.includes(emoji))} - /> - ))} + .sort(([emoji]) => -emoji) + .map(([emoji, count]) => { + return ( + react(emoji, !emojiState.user_emojis.includes(emoji))} + /> + ); + })} Date: Mon, 6 Feb 2023 21:29:30 +0000 Subject: [PATCH 105/152] 1184: Add dedicated export.py (#1270) * Add export script --- backend/export.py | 143 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 backend/export.py diff --git a/backend/export.py b/backend/export.py new file mode 100644 index 00000000..ef3fde49 --- /dev/null +++ b/backend/export.py @@ -0,0 +1,143 @@ +import argparse +import json +import sys +from pathlib import Path +from typing import List, Optional +from uuid import UUID + +from fastapi.encoders import jsonable_encoder +from loguru import logger +from oasst_backend.database import engine +from oasst_backend.models import Message, MessageTreeState, message_tree_state +from oasst_backend.utils import tree_export +from sqlmodel import Session, not_ + + +def fetch_tree_ids(db: Session, ready_only: bool = False): + tree_qry = db.query(MessageTreeState) + + if ready_only: + tree_qry = tree_qry.filter(MessageTreeState.state == message_tree_state.State.READY_FOR_EXPORT) + + message_trees = tree_qry.all() + + message_tree_ids = [tree.message_tree_id for tree in message_trees] + return message_tree_ids + + +def fetch_message_ids( + db: Session, + message_tree_id: Optional[UUID] = None, + user_id: Optional[UUID] = None, + include_deleted: bool = False, + deleted_only: bool = False, +) -> List[Message]: + qry = db.query(Message) + + if message_tree_id: + qry = qry.filter(Message.message_tree_id == message_tree_id) + if user_id: + qry = qry.filter(Message.user_id == user_id) + if not include_deleted: + qry = qry.filter(not_(Message.deleted)) + if deleted_only: + qry = qry.filter(Message.deleted) + + return qry.all() + + +def export_trees( + db: Session, + export_file: Optional[Path] = None, + use_compression: bool = False, + ready_only: bool = False, + include_deleted: bool = False, + deleted_only: bool = False, + user_id: Optional[UUID] = None, +): + trees_to_export: List[tree_export.ExportMessageTree] = [] + + if user_id: + messages = fetch_message_ids(db, user_id=user_id, include_deleted=include_deleted, deleted_only=deleted_only) + message_tree_ids = [msg.message_tree_id for msg in messages] + else: + message_tree_ids = fetch_tree_ids(db, ready_only) + + message_trees = [ + fetch_message_ids(db, message_tree_id=tree_id, include_deleted=include_deleted, deleted_only=deleted_only) + for tree_id in message_tree_ids + ] + + for message_tree_id, message_tree in zip(message_tree_ids, message_trees): + trees_to_export.append(tree_export.build_export_tree(message_tree_id, message_tree)) + + if export_file: + tree_export.write_trees_to_file(export_file, trees_to_export, use_compression) + else: + sys.stdout.write(json.dumps(jsonable_encoder(trees_to_export), indent=2)) + + +def validate_args(args): + if args.deleted_only: + args.include_deleted = True + + args.use_compression = args.export_file is not None and ".gz" in args.export_file + + if args.ready_only and args.user_id is not None: + raise ValueError("Cannot use --ready-only when specifying a user ID") + + if args.export_file is None: + logger.warning("No export file provided, output will be sent to STDOUT") + + +def parse_args(): + parser = argparse.ArgumentParser() + + parser.add_argument( + "--export-file", + type=str, + help="Name of file to export trees to. If not provided, output will be sent to STDOUT", + ) + parser.add_argument( + "--ready-only", + action="store_true", + help="Only export trees which are ready for use", + ) + parser.add_argument( + "--include-deleted", + action="store_true", + help="Include deleted messages in export", + ) + parser.add_argument( + "--deleted-only", + action="store_true", + help="Export only deleted messages (implies --include-deleted)", + ) + parser.add_argument( + "--user", + type=str, + help="Only export trees involving the user with the specified ID. Incompatible with --ready-only.", + ) + + args = parser.parse_args() + return args + + +def main(): + args = parse_args() + validate_args(args) + + with Session(engine) as db: + export_trees( + db, + Path(args.export_file) if args.export_file is not None else None, + args.use_compression, + args.ready_only, + args.include_deleted, + args.deleted_only, + UUID(args.user) if args.user is not None else None, + ) + + +if __name__ == "__main__": + main() From 0ef36e81be657fdb144057600ae1cdf5fbec27ee Mon Sep 17 00:00:00 2001 From: AbdBarho Date: Tue, 7 Feb 2023 00:10:35 +0100 Subject: [PATCH 106/152] Basic user stats in the accounts page (#1158) Closes #747 Blocked by #1156 #1166 Very simplistic, not much styling --- website/public/locales/en/leaderboard.json | 17 ++++- website/src/lib/oasst_api_client.ts | 5 ++ website/src/pages/account/index.tsx | 82 ++++++++++++++++++++-- website/src/pages/api/user_stats.ts | 12 ++++ 4 files changed, 108 insertions(+), 8 deletions(-) create mode 100644 website/src/pages/api/user_stats.ts diff --git a/website/public/locales/en/leaderboard.json b/website/public/locales/en/leaderboard.json index cebe281d..2339a05d 100644 --- a/website/public/locales/en/leaderboard.json +++ b/website/public/locales/en/leaderboard.json @@ -1,18 +1,33 @@ { + "accepted": "↪ Accepted", + "accepted_prompts": "Accepted prompts", "daily": "Daily", + "day": "Day", + "good_rankings": "Good rankings", "label": "Labels", + "labels_full": "Labels (full)", + "labels_simple": "Labels (simple)", "last_updated_at": "Last updated at: {{val, datetime}}", "leaderboard": "Leaderboard", + "month": "Month", "monthly": "Monthly", "next": "Next", "overall": "Overall", "previous": "Previous", "prompt": "Prompts", "rank": "Rank", + "rankings": "Rankings", + "replies_assistant": "Replies as Assistant", + "replies_prompter": "Replies as Prompter", "reply": "Replies", + "reply_ranked_1": "Replies ranked first", "score": "Score", "top_5_contributors_today": "Top 5 Contributors Today", + "total": "Total", "user": "User", "view_all": "View all", - "weekly": "Weekly" + "week": "Week", + "weekly": "Weekly", + "your_account": "Your account", + "your_stats": "Your statistics" } diff --git a/website/src/lib/oasst_api_client.ts b/website/src/lib/oasst_api_client.ts index 3f730b72..2aafab37 100644 --- a/website/src/lib/oasst_api_client.ts +++ b/website/src/lib/oasst_api_client.ts @@ -307,4 +307,9 @@ export class OasstApiClient { const backendUser = await this.post(`/api/v1/frontend_users/`, user); await this.put(`/api/v1/users/${backendUser.user_id}?tos_acceptance=true`); } + + async fetch_user_stats(user: BackendUserCore) { + const backendUser = await this.get(`/api/v1/frontend_users/${user.auth_method}/${user.id}`); + return this.get(`/api/v1/users/${backendUser.user_id}/stats`); + } } diff --git a/website/src/pages/account/index.tsx b/website/src/pages/account/index.tsx index 25d28bd0..8a7753e1 100644 --- a/website/src/pages/account/index.tsx +++ b/website/src/pages/account/index.tsx @@ -1,18 +1,27 @@ -import { Divider, Flex, Grid, Icon, Text } from "@chakra-ui/react"; +import { Box, Divider, Flex, Grid, Icon, Text } from "@chakra-ui/react"; import Head from "next/head"; import Link from "next/link"; import { useSession } from "next-auth/react"; import React from "react"; export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props"; import { Pencil } from "lucide-react"; +import { useTranslation } from "react-i18next"; import { SurveyCard } from "src/components/Survey/SurveyCard"; +import { get } from "src/lib/api"; +import { getTypeSafei18nKey } from "src/lib/i18n"; +import { LeaderboardEntity, LeaderboardTimeFrame } from "src/types/Leaderboard"; +import uswSWRImmutable from "swr/immutable"; export default function Account() { + const { t } = useTranslation("leaderboard"); const { data: session } = useSession(); - + const { data } = uswSWRImmutable<{ [time in LeaderboardTimeFrame]: LeaderboardEntity }>("/api/user_stats", get); if (!session) { return; } + + console.log(data); + return ( <> @@ -23,11 +32,9 @@ export default function Account() { />
- + - - Your Account - + {t("your_account")} Username @@ -40,10 +47,71 @@ export default function Account() { Email {session.user.email ?? "(No Email)"} -

+
+ + {t("your_stats")} + {[ + LeaderboardTimeFrame.total, + LeaderboardTimeFrame.day, + LeaderboardTimeFrame.week, + LeaderboardTimeFrame.month, + ].map((key) => { + const values = data[key]; + if (!values) { + return null; + } + return ( + + {t(getTypeSafei18nKey(key))} + + + + + + + + + + + + + + + + + + + + + + ); + })}
); } + +const Title = ({ children }) => ( + + {children} + +); + +const TableColumn = ({ children }) => { + return ( + + {children} + + ); +}; + +const Entry = ({ title, value }) => { + return ( + <> + {title} + {value} + + ); +}; diff --git a/website/src/pages/api/user_stats.ts b/website/src/pages/api/user_stats.ts new file mode 100644 index 00000000..cb508e8c --- /dev/null +++ b/website/src/pages/api/user_stats.ts @@ -0,0 +1,12 @@ +import { withoutRole } from "src/lib/auth"; +import { createApiClientFromUser } from "src/lib/oasst_client_factory"; +import { getBackendUserCore } from "src/lib/users"; + +const handler = withoutRole("banned", async (req, res, token) => { + const user = await getBackendUserCore(token.sub); + const oasstApiClient = createApiClientFromUser(user); + const stats = await oasstApiClient.fetch_user_stats(user); + res.status(200).json(stats); +}); + +export default handler; From 8ed1451b73e247f55b738827377cc31c0eccbc97 Mon Sep 17 00:00:00 2001 From: Yichao 'Peak' Ji Date: Tue, 7 Feb 2023 10:48:35 +0800 Subject: [PATCH 107/152] Add Chinese translation (#1245) --- website/public/locales/zh/common.json | 27 +++++++ website/public/locales/zh/dashboard.json | 8 +++ website/public/locales/zh/index.json | 23 ++++++ website/public/locales/zh/labelling.json | 24 +++++++ website/public/locales/zh/leaderboard.json | 18 +++++ website/public/locales/zh/message.json | 20 ++++++ website/public/locales/zh/side_menu.json | 12 ++++ website/public/locales/zh/tasks.json | 82 ++++++++++++++++++++++ website/public/locales/zh/tos.json | 6 ++ 9 files changed, 220 insertions(+) create mode 100644 website/public/locales/zh/common.json create mode 100644 website/public/locales/zh/dashboard.json create mode 100644 website/public/locales/zh/index.json create mode 100644 website/public/locales/zh/labelling.json create mode 100644 website/public/locales/zh/leaderboard.json create mode 100644 website/public/locales/zh/message.json create mode 100644 website/public/locales/zh/side_menu.json create mode 100644 website/public/locales/zh/tasks.json create mode 100644 website/public/locales/zh/tos.json diff --git a/website/public/locales/zh/common.json b/website/public/locales/zh/common.json new file mode 100644 index 00000000..bba05485 --- /dev/null +++ b/website/public/locales/zh/common.json @@ -0,0 +1,27 @@ +{ + "about": "关于", + "account_settings": "帐号", + "admin_dashboard": "管理面板", + "connect": "连接", + "conversational": "每个人的对话式人工智能。", + "copied": "已复制", + "dark_mode": "深色模式", + "dashboard": "概览", + "delete": "删除", + "discord": "Discord", + "docs": "文档", + "github": "GitHub", + "legal": "法律信息", + "light_mode": "浅色模式", + "loading": "载入中...", + "more_information": "更多信息", + "no": "否", + "privacy_policy": "隐私政策", + "report_a_bug": "报告问题", + "sign_in": "登入", + "sign_out": "登出", + "success": "成功", + "terms_of_service": "服务条款", + "title": "Open Assistant", + "yes": "是" +} diff --git a/website/public/locales/zh/dashboard.json b/website/public/locales/zh/dashboard.json new file mode 100644 index 00000000..2e240956 --- /dev/null +++ b/website/public/locales/zh/dashboard.json @@ -0,0 +1,8 @@ +{ + "grab_a_task": "选择任务!", + "create": "新建", + "evaluate": "评估", + "label": "标注", + "dashboard": "概览", + "go": "开始" +} diff --git a/website/public/locales/zh/index.json b/website/public/locales/zh/index.json new file mode 100644 index 00000000..4e6db31c --- /dev/null +++ b/website/public/locales/zh/index.json @@ -0,0 +1,23 @@ +{ + "blurb": "我们可以创造一场革命。", + "blurb1": "正如 Stable Diffusion 为世界带来了艺术创作的全新途径,我们想用令人惊叹的对话式人工智能让世界再进一步。", + "description": "每个人的对话式人工智能。由 LAION 和全世界的贡献者们一同运作的开源项目,致力于创造一个对话式的 GPT 大模型。", + "faq_items": { + "q0": "项目进展到什么阶段了?", + "a0": "我们处于研发的初期阶段,正在参照现有研究将 RLHF 应用在大型语言模型中。", + "q1": "谁在支持 Open Assistant?", + "a1": "Open Assistant 是一个由 LAION 和全世界致力于将该技术带给每个人的志愿者们共同组织的项目。", + "q2": "Open Assistant 使用什么开源协议?", + "a2": "代码和模型均基于 Apache 2.0 license 分发。", + "q3": "训练数据也会公开吗?", + "a3": "是的,将基于 CC BY 4.0 协议公开。", + "q4": "Open Assistant 会是免费的么?", + "a4": "是的,Open Assistant 可被免费使用和修改。", + "q5": "什么样的硬件能够运行这些模型?", + "a5": "将会提供可在消费级硬件上运行的模型版本。" + }, + "faq_title": "常见问题", + "join_us_description": "所有开源项目都始于像你一样的人。开源是一种信念,我们相信在合作中将知识和技术赠予世界将会造福人类。想一起来吗?我们在这里:", + "join_us_title": "加入我们", + "subtitle": "每个人的对话式人工智能。" +} diff --git a/website/public/locales/zh/labelling.json b/website/public/locales/zh/labelling.json new file mode 100644 index 00000000..6e33b8d5 --- /dev/null +++ b/website/public/locales/zh/labelling.json @@ -0,0 +1,24 @@ +{ + "fails_task.question": "对于该提示任务来说这不是个好的回复?", + "hate_speech": "仇恨言论", + "hate_speech.explanation": "内容涉及辱骂或威胁,表达了对受保护特征的偏见。偏见是指非理性的先入为主的观点。受保护的特征包括性别、种族、宗教、性取向和类似特征。", + "label_highlighted_flag_instruction": "选择适用于高亮信息的选项:", + "label_highlighted_likert_instruction": "评价高亮信息:", + "label_highlighted_yes_no_instruction": "回答关于高亮信息的以下问题:", + "label_message_flag_instruction": "选择适用于该信息的选项:", + "label_message_likert_instruction": "评价该信息:", + "label_message_yes_no_instruction": "回答关于该信息的以下问题:", + "lang_mismatch": "语言错误", + "lang_mismatch.explanation": "并非以当前选择的语言书写。", + "moral_judgement": "道德判断", + "moral_judgement.explanation": "表达了道德判断。", + "not_appropriate": "不合时宜", + "not_appropriate.explanation": "对于用户助理来说是不合适的。", + "pii": "个人信息", + "pii.explanation": "含有个人信息。例如个人联系方式、证件执照、银行资料和其他身份信息。", + "political_content": "政治内容", + "political_content.explanation": "表达了政治观点或倾向。", + "sexual_content": "色情内容", + "sexual_content.explanation": "包含色情内容。", + "spam.question": "是否为垃圾信息?" +} diff --git a/website/public/locales/zh/leaderboard.json b/website/public/locales/zh/leaderboard.json new file mode 100644 index 00000000..edeb8e81 --- /dev/null +++ b/website/public/locales/zh/leaderboard.json @@ -0,0 +1,18 @@ +{ + "daily": "每日", + "label": "标注数", + "last_updated_at": "最后更新于:{{val, datetime}}", + "leaderboard": "排行榜", + "monthly": "每月", + "next": "下一页", + "overall": "总体", + "previous": "上一页", + "prompt": "提示数", + "rank": "排名", + "reply": "回复数", + "score": "积分", + "top_5_contributors_today": "本日五大贡献者", + "user": "用户", + "view_all": "查看全部", + "weekly": "每周" +} diff --git a/website/public/locales/zh/message.json b/website/public/locales/zh/message.json new file mode 100644 index 00000000..6a975798 --- /dev/null +++ b/website/public/locales/zh/message.json @@ -0,0 +1,20 @@ +{ + "copy_message_id": "复制信息 ID", + "label_action": "标注", + "label_title": "标注", + "message_deleted": "信息已删除", + "message": "信息", + "open_new_tab_action": "在新标签页中打开", + "parent": "上级", + "reactions": "反馈", + "recent_messages": "最新信息", + "report_action": "报告", + "report_placeholder": "为什么该信息需要被检查?", + "report_title": "报告", + "send_report": "发送", + "stop_tree": "终止树", + "submit_labels": "提交", + "tree_stopped": "树终止于 {{id}}", + "view_user": "查看用户", + "your_recent_messages": "你的最新信息" +} diff --git a/website/public/locales/zh/side_menu.json b/website/public/locales/zh/side_menu.json new file mode 100644 index 00000000..fbb69bd1 --- /dev/null +++ b/website/public/locales/zh/side_menu.json @@ -0,0 +1,12 @@ +{ + "dashboard": "概览", + "dashboard_home": "概览首页", + "messages": "信息", + "messages_dashboard": "信息概览", + "leaderboard": "排行榜", + "user_leaderboard": "用户排行榜", + "users": "用户", + "users_dashboard": "用户概览", + "status": "状态", + "status_dashboard": "状态概览" +} diff --git a/website/public/locales/zh/tasks.json b/website/public/locales/zh/tasks.json new file mode 100644 index 00000000..788dcdd6 --- /dev/null +++ b/website/public/locales/zh/tasks.json @@ -0,0 +1,82 @@ +{ + "default": { + "unchanged_title": "无变化", + "unchanged_message": "确定要继续吗?" + }, + "random": { + "label": "手气不错", + "desc": "通过开始一个随机任务来改进 Open Assistant。" + }, + "create_initial_prompt": { + "label": "创建初始提示", + "desc": "编写初始提示来让 Open Assistant 尝试回复各种不同的信息。", + "overview": "创建发送给助理的第一条信息", + "instruction": "提供初始提示", + "response_placeholder": "在这里输入你的提示..." + }, + "reply_as_user": { + "label": "作为用户回复", + "desc": "通过与 Open Assistant 聊天来帮助改进它的回复。", + "overview": "基于如下的对话提供一个合适的回复", + "instruction": "提供作为用户的回复", + "response_placeholder": "在这里输入你的回复..." + }, + "reply_as_assistant": { + "label": "作为助理回复", + "desc": "帮助 Open Assistant 改进它与其他用户对话的响应。", + "overview": "基于如下的对话提供一个合适的回复", + "response_placeholder": "在这里输入你的回复..." + }, + "rank_user_replies": { + "label": "用户回复排序", + "desc": "帮助 Open Assistant 改进它与其他用户对话的响应。", + "overview": "将给出的用户回复按照从优到劣排序。", + "unchanged_title": "排序未改变", + "unchanged_message": "你并未改变提示的排序。确定要继续吗?" + }, + "rank_assistant_replies": { + "label": "助理回复排序", + "desc": "根据准确性和可读性为 Open Assistant 的提示进行评价。", + "overview": "将给出的助理回复按照从优到劣排序。", + "unchanged_title": "排序未改变", + "unchanged_message": "你并未改变提示的排序。确定要继续吗?" + }, + "rank_initial_prompts": { + "label": "初始提示排序", + "desc": "根据准确性和可读性为 Open Assistant 的提示进行评价。", + "overview": "将给出的初始提示按照从优到劣排序。", + "unchanged_title": "排序未改变", + "unchanged_message": "你并未改变提示的排序。确定要继续吗?" + }, + "label_initial_prompt": { + "label": "标注初始提示", + "desc": "为提示提供标注", + "overview": "对以下提示进行标注" + }, + "label_prompter_reply": { + "label": "标注提示者回复", + "desc": "为提示提供标注", + "overview": "基于以下讨论,对最后的提示进行标注。" + }, + "label_assistant_reply": { + "label": "标注助理回复", + "desc": "为提示提供标注", + "overview": "基于以下讨论,对最后的提示进行标注。" + }, + "classify_initial_prompt": { + "label": "分类初始提示", + "desc": "为提示提供标注", + "overview": "阅读以下的提示并回答其中的问题。" + }, + "classify_prompter_reply": { + "label": "分类提示者回复", + "desc": "为提示提供标注", + "overview": "阅读以下对话并回答最后一个回复中的问题。" + }, + "classify_assistant_reply": { + "label": "分类助理回复", + "desc": "为提示提供标注", + "overview": "阅读以下对话并回答最后一个回复中的问题。" + }, + "available_task_count": "{{count}} 个可用任务" +} diff --git a/website/public/locales/zh/tos.json b/website/public/locales/zh/tos.json new file mode 100644 index 00000000..612fe535 --- /dev/null +++ b/website/public/locales/zh/tos.json @@ -0,0 +1,6 @@ +{ + "title": "Open Assistant 服务条款", + "content": "你需要接受服务条款以继续使用 Open Assistant。", + "accept": "接受", + "decline": "拒绝" +} From 931e12f31e1ab518b4c9903a9941183bd2298ad3 Mon Sep 17 00:00:00 2001 From: KyattPL Date: Tue, 7 Feb 2023 06:46:20 +0100 Subject: [PATCH 108/152] Added Polish language locale (#1250) --- website/next-i18next.config.js | 1 + website/public/locales/pl/common.json | 27 +++++++ website/public/locales/pl/dashboard.json | 8 +++ website/public/locales/pl/index.json | 23 ++++++ website/public/locales/pl/labelling.json | 24 +++++++ website/public/locales/pl/leaderboard.json | 18 +++++ website/public/locales/pl/message.json | 20 ++++++ website/public/locales/pl/side_menu.json | 12 ++++ website/public/locales/pl/tasks.json | 82 ++++++++++++++++++++++ website/public/locales/pl/tos.json | 6 ++ 10 files changed, 221 insertions(+) create mode 100644 website/public/locales/pl/common.json create mode 100644 website/public/locales/pl/dashboard.json create mode 100644 website/public/locales/pl/index.json create mode 100644 website/public/locales/pl/labelling.json create mode 100644 website/public/locales/pl/leaderboard.json create mode 100644 website/public/locales/pl/message.json create mode 100644 website/public/locales/pl/side_menu.json create mode 100644 website/public/locales/pl/tasks.json create mode 100644 website/public/locales/pl/tos.json diff --git a/website/next-i18next.config.js b/website/next-i18next.config.js index 22b6b477..8ae0b222 100644 --- a/website/next-i18next.config.js +++ b/website/next-i18next.config.js @@ -13,6 +13,7 @@ module.exports = { "it", "ja", "ko", + "pl", "pt-BR", "ru", "uk-UA", diff --git a/website/public/locales/pl/common.json b/website/public/locales/pl/common.json new file mode 100644 index 00000000..01bca692 --- /dev/null +++ b/website/public/locales/pl/common.json @@ -0,0 +1,27 @@ +{ + "about": "O nas", + "account_settings": "Konto", + "admin_dashboard": "Panel Administratora", + "connect": "Dołącz", + "conversational": "Konwersacyjna SI dla każdego.", + "copied": "Skopiowano", + "dark_mode": "Tryb ciemny", + "dashboard": "Panel", + "delete": "Usuń", + "discord": "Discord", + "docs": "Dokumentacja", + "github": "GitHub", + "legal": "Prawa", + "light_mode": "Tryb jasny", + "loading": "Wczytywanie...", + "more_information": "Więcej Informacji", + "no": "Nie", + "privacy_policy": "Polityka Prywatności", + "report_a_bug": "Zgłoś Błąd", + "sign_in": "Zaloguj Się", + "sign_out": "Wyloguj Się", + "success": "Sukces", + "terms_of_service": "Warunki Usługi", + "title": "Open Assistant", + "yes": "Tak" +} diff --git a/website/public/locales/pl/dashboard.json b/website/public/locales/pl/dashboard.json new file mode 100644 index 00000000..8a8e788c --- /dev/null +++ b/website/public/locales/pl/dashboard.json @@ -0,0 +1,8 @@ +{ + "grab_a_task": "Wybierz zadanie!", + "create": "Stwórz", + "evaluate": "Oceń", + "label": "Sklasyfikuj", + "dashboard": "Panel", + "go": "Przejdź" +} diff --git a/website/public/locales/pl/index.json b/website/public/locales/pl/index.json new file mode 100644 index 00000000..91a4fa93 --- /dev/null +++ b/website/public/locales/pl/index.json @@ -0,0 +1,23 @@ +{ + "blurb": "Wierzymy, że możemy stworzyć rewolucję.", + "blurb1": "Tak jak Stable Diffusion pomaga światu tworzyć sztukę i obrazy na inne sposoby, chcemy wzbogacić świat poprzez dostarczenie niesamowitej konwersacyjnej SI.", + "description": "Konwersacyjna SI dla każdego. Projekt w formie otwartego oprogramowania mający na celu utworzenie czatu wspomaganego przez GPT LLM kierowany przez LAION i uczestników z całego świata.", + "faq_items": { + "q0": "W jakim stopniu zaawansowania jest projekt?", + "a0": "Jesteśmy w początkowych fazach rozwoju, pracujemy na bazie potwierdzonych badań w aplikowaniu RLHF (uczenie ze wzmocnieniem na podstawie ludzkiej informacji zwrotnej) do wielkich modeli językowych.", + "q1": "Kto stoi za Open Assistant?", + "a1": "Open Assistant to projekt zorganizowany przez LAION i osoby z całego świata chętne dostarczenia tej technologii dla każdego.", + "q2": "Jakiej licencji używa Open Assistant?", + "a2": "Kod i modele podlegają pod licencję Apache 2.0", + "q3": "Czy dane treningowe zostaną opublikowane?", + "a3": "Tak, na bazie CC BY 4.0 (uznanie autorstwa).", + "q4": "Czy Open Assistant będzie darmowy?", + "a4": "Tak, Open Assistant będzie darmowy w obsłudze i modyfikacji.", + "q5": "Jaki sprzęt będzie wymagany do uruchomienia modeli?", + "a5": "Będą dostępne wersje przygotowane do uruchomienia na sprzęcie konsumenckim." + }, + "faq_title": "Najczęściej Zadawane Pytania", + "join_us_description": "Wszystkie projekty wolnego oprogramowania zaczynają się od ludzi takich jak ty. Otwarte oprogramowanie to przekonanie, że współpracując możemy podarować naszą wiedzę i technologię światu dla dobra ludzkości. Wchodzisz w to? Znajdź nas tutaj:", + "join_us_title": "Dołącz do nas", + "subtitle": "Konwersacyjna SI dla każdego." +} diff --git a/website/public/locales/pl/labelling.json b/website/public/locales/pl/labelling.json new file mode 100644 index 00000000..aa5d828f --- /dev/null +++ b/website/public/locales/pl/labelling.json @@ -0,0 +1,24 @@ +{ + "fails_task.question": "Czy jest to zła reakcja, jako odpowiedź na zadanie z polecenia?", + "hate_speech": "Mowa nienawiści", + "hate_speech.explanation": "Treść jest obraźliwa lub grożąca i wyraża uprzedzenie wobec chronionej cechy. Uprzedzenie odnosi się do przyjętych z góry poglądów nieopartych na wnioskowaniu. Chronione charakterystyki zawierają płeć, pochodzenie, religię, orientację seksualną i podobne cechy.", + "label_highlighted_flag_instruction": "Wybierz jakiekolwiek, które pasują do zaznaczonej wiadomości:", + "label_highlighted_likert_instruction": "Oceń zaznaczoną wiadomość:", + "label_highlighted_yes_no_instruction": "Odpowiedz na następujące pytania dotyczące zaznaczonej wiadomości:", + "label_message_flag_instruction": "Wybierz jakiekolwiek, które pasują do wiadomości:", + "label_message_likert_instruction": "Oceń wiadomość:", + "label_message_yes_no_instruction": "Odpowiedz na następujące pytania dotyczące wiadomości:", + "lang_mismatch": "Zły Język", + "lang_mismatch.explanation": "Nienapisane w aktualnie wybranym języku.", + "moral_judgement": "Osądza Moralność", + "moral_judgement.explanation": "Wyraża osąd moralny.", + "not_appropriate": "Niewłaściwa", + "not_appropriate.explanation": "Niewłaściwa dla asystenta konsumenta.", + "pii": "Zawiera dane osobowe", + "pii.explanation": "Zawiera osobiście identyfikujące informacje. Przykłady zawierają osobiste dane kontaktowe, licencje oraz inne numery identyfikacyjne czy szczegóły bankowe.", + "political_content": "Polityczna", + "political_content.explanation": "Wyraża poglądy polityczne.", + "sexual_content": "Treść erotyczna", + "sexual_content.explanation": "Zawiera treść erotyczną.", + "spam.question": "Czy ta wiadomość to spam?" +} diff --git a/website/public/locales/pl/leaderboard.json b/website/public/locales/pl/leaderboard.json new file mode 100644 index 00000000..720457c0 --- /dev/null +++ b/website/public/locales/pl/leaderboard.json @@ -0,0 +1,18 @@ +{ + "daily": "Dzienny", + "label": "Etykiety", + "last_updated_at": "Ostatnia aktualizacja: {{val, datetime}}", + "leaderboard": "Ranking", + "monthly": "Miesięczny", + "next": "Następna", + "overall": "Ogólny", + "previous": "Poprzednia", + "prompt": "Polecenia", + "rank": "Pozycja", + "reply": "Odpowiedzi", + "score": "Wynik", + "top_5_contributors_today": "Top 5 Dzisiejszych Uczestników", + "user": "Użytkownik", + "view_all": "Wyświetl wszystkich", + "weekly": "Tygodniowy" +} diff --git a/website/public/locales/pl/message.json b/website/public/locales/pl/message.json new file mode 100644 index 00000000..e3417c23 --- /dev/null +++ b/website/public/locales/pl/message.json @@ -0,0 +1,20 @@ +{ + "copy_message_id": "Skopiuj ID wiadomości", + "label_action": "Sklasyfikuj", + "label_title": "Sklasyfikuj", + "message_deleted": "Wiadomość usunięta", + "message": "Wiadomość", + "open_new_tab_action": "Otwórz w nowej karcie", + "parent": "Rodzic", + "reactions": "Reakcje", + "recent_messages": "Ostatnie Wiadomości", + "report_action": "Zgłoś", + "report_placeholder": "Dlaczego ta wiadomość powinna zostać przejrzana?", + "report_title": "Zgłoś", + "send_report": "Wyślij", + "stop_tree": "Zatrzymaj drzewo", + "submit_labels": "Wyślij", + "tree_stopped": "Drzewo zatrzymane {{id}}", + "view_user": "Wyświetl użytkownika", + "your_recent_messages": "Twoje ostatnie wiadomości" +} diff --git a/website/public/locales/pl/side_menu.json b/website/public/locales/pl/side_menu.json new file mode 100644 index 00000000..f352bd9f --- /dev/null +++ b/website/public/locales/pl/side_menu.json @@ -0,0 +1,12 @@ +{ + "dashboard": "Panel", + "dashboard_home": "Strona Główna Panelu", + "messages": "Wiadomości", + "messages_dashboard": "Strona Główna Wiadomości", + "leaderboard": "Ranking", + "user_leaderboard": "Ranking Użytkowników", + "users": "Użytkownicy", + "users_dashboard": "Panel Użytkownika", + "status": "Status", + "status_dashboard": "Panel Statusu" +} diff --git a/website/public/locales/pl/tasks.json b/website/public/locales/pl/tasks.json new file mode 100644 index 00000000..a0ecb45c --- /dev/null +++ b/website/public/locales/pl/tasks.json @@ -0,0 +1,82 @@ +{ + "default": { + "unchanged_title": "Brak zmian", + "unchanged_message": "Czy na pewno chcesz kontynuować?" + }, + "random": { + "label": "Losowe zadanie", + "desc": "Pomóż nam udoskonalić Open Assistant poprzez wypełnienie losowego zadania." + }, + "create_initial_prompt": { + "label": "Utwórz Początkowe Polecenia", + "desc": "Napisz początkowe polecenia by pomóc Open Assistant w odpowiadaniu na różnorodne wiadomości. (dołącz do loterii)", + "overview": "Utwórz początkową wiadomość do wysłania asystentowi", + "instruction": "Dostarcz początkowe polecenia", + "response_placeholder": "Napisz tutaj swoje polecenie..." + }, + "reply_as_user": { + "label": "Odpowiedz Jako Użytkownik", + "desc": "Czatuj z Open Assistant i pomóż mu poprawić jego odpowiedzi w ramach postępującej rozmowy.", + "overview": "Mając daną konwersację, dostarcz odpowiednią odpowiedź", + "instruction": "Dostarcz odpowiedź użytkownika", + "response_placeholder": "Napisz tutaj swoją odpowiedź..." + }, + "reply_as_assistant": { + "label": "Odpowiedz Jako Asystent", + "desc": "Pomóż Open Assistant udoskonalić jego odpowiedzi na konwersacje z innymi użytkownikami.", + "overview": "Mając daną konwersację, dostarcz odpowiednią odpowiedź", + "response_placeholder": "Napisz tutaj swoją odpowiedź..." + }, + "rank_user_replies": { + "label": "Oceń Odpowiedzi Użytkownika", + "desc": "Pomóż Open Assistant udoskonalić jego odpowiedzi na konwersacje z innymi użytkownikami.", + "overview": "Mając dane odpowiedzi użytkownika, uporządkuj je od najlepszej do najgorszej, najlepsza będąca pierwszą, a najgorsza ostatnią.", + "unchanged_title": "Porządek niezmieniony", + "unchanged_message": "Nie zmieniłeś porządku poleceń. Czy na pewno chcesz kontynuować?" + }, + "rank_assistant_replies": { + "label": "Oceń Odpowiedzi Asystenta", + "desc": "Oceń polecenia wydane przez Open Assistant na podstawie ich precyzji i czytelności.", + "overview": "Mając dane odpowiedzi asystenta, uporządkuj je od najlepszej do najgorszej, najlepsza będąca pierwszą, a najgorsza ostatnią.", + "unchanged_title": "Porządek niezmieniony", + "unchanged_message": "Nie zmieniłeś porządku poleceń. Czy na pewno chcesz kontynuować?" + }, + "rank_initial_prompts": { + "label": "Oceń Początkowe Polecenia", + "desc": "Oceń polecenia wydane przez Open Assistant na podstawie ich precyzji i czytelności.", + "overview": "Mając dane początkowe polecenia, uporządkuj je od najlepszej do najgorszej, najlepsza będąca pierwszą, a najgorsza ostatnią.", + "unchanged_title": "Porządek niezmieniony", + "unchanged_message": "Nie zmieniłeś porządku poleceń. Czy na pewno chcesz kontynuować?" + }, + "label_initial_prompt": { + "label": "Nadaj Etykiety Początkowemu Poleceniu", + "desc": "Określ etykiety dla polecenia.", + "overview": "Dostarcz etykiety dla następującego polecenia" + }, + "label_prompter_reply": { + "label": "Nadaj Etykiety Odpowiedzi Wydającego Polecenie", + "desc": "Określ etykiety dla polecenia.", + "overview": "Mając daną dyskusję, określ etykiety dla ostatniego polecenia." + }, + "label_assistant_reply": { + "label": "Nadaj Etykiety Odpowiedzi Asystenta", + "desc": "Określ etykiety dla polecenia.", + "overview": "Mając daną dyskusję, określ etykiety dla ostatniego polecenia." + }, + "classify_initial_prompt": { + "label": "Sklasyfikuj Początkowe Polecenie", + "desc": "Określ etykiety dla polecenia.", + "overview": "Przeczytaj dane polecenie i odpowiedz na nie." + }, + "classify_prompter_reply": { + "label": "Sklasyfikuj Odpowiedź Wydającego Polecenie", + "desc": "Określ etykiety dla polecenia.", + "overview": "Przeczytaj daną konwersację i odpowiedz na ostatnią wiadomość w dyskusji." + }, + "classify_assistant_reply": { + "label": "Sklasyfikuj Odpowiedź Asystenta", + "desc": "Określ etykiety dla polecenia.", + "overview": "Przeczytaj daną konwersację i odpowiedz na ostatnią wiadomość w dyskusji." + }, + "available_task_count": "{{count}} dostępnych zadań" +} diff --git a/website/public/locales/pl/tos.json b/website/public/locales/pl/tos.json new file mode 100644 index 00000000..9416b8ed --- /dev/null +++ b/website/public/locales/pl/tos.json @@ -0,0 +1,6 @@ +{ + "title": "Warunki świadczenia usług przez Open Assistant", + "content": "Aby móc korzystać z Open Assistant, musisz najpierw zaakceptować nasze warunki świadczenia usług.", + "accept": "Akceptuj", + "decline": "Odrzuć" +} From 952e021c88c387e2578c43a05183cd46d64b5967 Mon Sep 17 00:00:00 2001 From: notmd <33456881+notmd@users.noreply.github.com> Date: Tue, 7 Feb 2023 12:49:50 +0700 Subject: [PATCH 109/152] Show current user rank in leaderboard (#1263) close #1000 maybe #1178 too * Show current user rank in the leaderboard with +-1 user (only on leaderboard * Extend auto_main script to use random user. * Support colSpan in the DataTable component (I haven't verified colSpan in header yet, leave that until we need it) * Refactor OasstError to include the path and request method. --- text-frontend/auto_main.py | 403 +++++++++--------- text-frontend/requirements.txt | 1 + .../Dashboard/LeaderboardWidget.tsx | 4 +- website/src/components/DataTable.tsx | 37 +- .../LeaderboardTable/LeaderboardTable.tsx | 122 ++++-- website/src/lib/api.ts | 8 +- website/src/lib/oasst_api_client.ts | 50 ++- website/src/pages/api/leaderboard.ts | 25 +- 8 files changed, 396 insertions(+), 254 deletions(-) diff --git a/text-frontend/auto_main.py b/text-frontend/auto_main.py index e951a28e..31c74d9d 100644 --- a/text-frontend/auto_main.py +++ b/text-frontend/auto_main.py @@ -6,12 +6,10 @@ from uuid import uuid4 import requests import typer +from faker import Faker app = typer.Typer() - - -# debug constants -USER = {"id": "1234", "display_name": "John Doe", "auth_method": "local"} +fake = Faker() def _random_message_id(): @@ -26,19 +24,11 @@ def _render_message(message: dict) -> str: @app.command() -def main(backend_url: str = "http://127.0.0.1:8080", api_key: str = "1234"): +def main( + backend_url: str = "http://127.0.0.1:8080", api_key: str = "1234", random_users: int = 1, task_per_user: int = 10 +): """automates tasks""" - # make sure dummy user has accepted the terms of service - create_user_request = dict(USER) - create_user_request["tos_acceptance"] = True - response = requests.post( - f"{backend_url}/api/v1/frontend_users/", json=create_user_request, headers={"X-API-Key": api_key} - ) - response.raise_for_status() - user = response.json() - typer.echo(f"user: {user}") - def _post(path: str, json: dict) -> dict: response = requests.post(f"{backend_url}{path}", json=json, headers={"X-API-Key": api_key}) response.raise_for_status() @@ -60,204 +50,219 @@ def main(backend_url: str = "http://127.0.0.1:8080", api_key: str = "1234"): print(shuffled) return ranks - tasks = [_post("/api/v1/tasks/", {"type": "random", "user": USER})] - q = 0 - while tasks: - task = tasks.pop(0) - print(task) + for i in range(int(random_users)): + name = fake.name() + USER = {"id": name, "display_name": name, "auth_method": "local"} - match (task["type"]): - case "initial_prompt": - typer.echo("Please provide an initial prompt to the assistant.") - if task["hint"]: - typer.echo(f"Hint: {task['hint']}") - # acknowledge task - message_id = _random_message_id() - _post(f"/api/v1/tasks/{task['id']}/ack", {"message_id": message_id}) + create_user_request = dict(USER) + # make sure dummy user has accepted the terms of service + create_user_request["tos_acceptance"] = True + response = requests.post( + f"{backend_url}/api/v1/frontend_users/", json=create_user_request, headers={"X-API-Key": api_key} + ) + response.raise_for_status() + user = response.json() + typer.echo(f"user: {user}") + q = 0 - prompt = gen_random_text() - user_message_id = _random_message_id() - # send interaction - new_task = _post( - "/api/v1/tasks/interaction", - { - "type": "text_reply_to_message", - "message_id": message_id, - "task_id": task["id"], - "user_message_id": user_message_id, - "text": prompt, - "user": USER, - }, - ) - tasks.append(new_task) + tasks = [_post("/api/v1/tasks/", {"type": "random", "user": USER})] - case "label_initial_prompt": - typer.echo("Label the following prompt:") - typer.echo(task["prompt"]) - # acknowledge task - message_id = _random_message_id() - _post(f"/api/v1/tasks/{task['id']}/ack", {"message_id": message_id}) + while tasks: + task = tasks.pop(0) + print(task) - valid_labels = task["valid_labels"] - mandatory_labels = task["mandatory_labels"] + match (task["type"]): + case "initial_prompt": + typer.echo("Please provide an initial prompt to the assistant.") + if task["hint"]: + typer.echo(f"Hint: {task['hint']}") + # acknowledge task + message_id = _random_message_id() + _post(f"/api/v1/tasks/{task['id']}/ack", {"message_id": message_id}) - labels_dict = None - if task["mode"] == "simple" and len(valid_labels) == 1: - answer = random.choice([True, False]) - labels_dict = {valid_labels[0]: 1 if answer else 0} - else: - labels = random.sample(valid_labels, random.randint(1, len(valid_labels))) - for l in mandatory_labels: - if l not in labels: - labels.append(l) - labels_dict = {label: random.random() for label in valid_labels} - if random.random() < 0.9: - labels_dict["spam"] = 0 - labels_dict["lang_mismatch"] = 0 + prompt = gen_random_text() + user_message_id = _random_message_id() + # send interaction + new_task = _post( + "/api/v1/tasks/interaction", + { + "type": "text_reply_to_message", + "message_id": message_id, + "task_id": task["id"], + "user_message_id": user_message_id, + "text": prompt, + "user": USER, + }, + ) + tasks.append(new_task) - # send labels - new_task = _post( - "/api/v1/tasks/interaction", - { - "type": "text_labels", - "message_id": task["message_id"], - "task_id": task["id"], - "text": task["prompt"], - "labels": labels_dict, - "user": USER, - }, - ) - tasks.append(new_task) - case "prompter_reply": - # acknowledge task - message_id = _random_message_id() - user_message_id = _random_message_id() - _post(f"/api/v1/tasks/{task['id']}/ack", {"message_id": message_id}) - # send interaction - new_task = _post( - "/api/v1/tasks/interaction", - { - "type": "text_reply_to_message", - "message_id": message_id, - "task_id": task["id"], - "user_message_id": user_message_id, - "text": gen_random_text(), - "user": USER, - }, - ) - tasks.append(new_task) + case "label_initial_prompt": + typer.echo("Label the following prompt:") + typer.echo(task["prompt"]) + # acknowledge task + message_id = _random_message_id() + _post(f"/api/v1/tasks/{task['id']}/ack", {"message_id": message_id}) - case "assistant_reply": - # acknowledge task - message_id = _random_message_id() - user_message_id = _random_message_id() - _post(f"/api/v1/tasks/{task['id']}/ack", {"message_id": message_id}) - # send interaction - new_task = _post( - "/api/v1/tasks/interaction", - { - "type": "text_reply_to_message", - "message_id": message_id, - "task_id": task["id"], - "user_message_id": user_message_id, - "text": gen_random_text(), - "user": USER, - }, - ) - tasks.append(new_task) + valid_labels = task["valid_labels"] + mandatory_labels = task["mandatory_labels"] - case "rank_prompter_replies" | "rank_assistant_replies": - # acknowledge task - message_id = _random_message_id() - user_message_id = _random_message_id() - _post(f"/api/v1/tasks/{task['id']}/ack", {"message_id": message_id}) - # send interaction - ranking = gen_random_ranking(task["replies"]) - print(ranking) - new_task = _post( - "/api/v1/tasks/interaction", - { - "type": "message_ranking", - "message_id": message_id, - "task_id": task["id"], - "ranking": ranking, - "user": USER, - }, - ) - tasks.append(new_task) + labels_dict = None + if task["mode"] == "simple" and len(valid_labels) == 1: + answer = random.choice([True, False]) + labels_dict = {valid_labels[0]: 1 if answer else 0} + else: + labels = random.sample(valid_labels, random.randint(1, len(valid_labels))) + for l in mandatory_labels: + if l not in labels: + labels.append(l) + labels_dict = {label: random.random() for label in valid_labels} + if random.random() < 0.9: + labels_dict["spam"] = 0 + labels_dict["lang_mismatch"] = 0 - case "rank_initial_prompts": - # acknowledge task - message_id = _random_message_id() - user_message_id = _random_message_id() - _post(f"/api/v1/tasks/{task['id']}/ack", {"message_id": message_id}) - # send interaction - ranking = gen_random_ranking(task["prompots"]) - new_task = _post( - "/api/v1/tasks/interaction", - { - "type": "message_ranking", - "message_id": message_id, - "ranking": ranking, - "user": USER, - }, - ) - tasks.append(new_task) + # send labels + new_task = _post( + "/api/v1/tasks/interaction", + { + "type": "text_labels", + "message_id": task["message_id"], + "task_id": task["id"], + "text": task["prompt"], + "labels": labels_dict, + "user": USER, + }, + ) + tasks.append(new_task) + case "prompter_reply": + # acknowledge task + message_id = _random_message_id() + user_message_id = _random_message_id() + _post(f"/api/v1/tasks/{task['id']}/ack", {"message_id": message_id}) + # send interaction + new_task = _post( + "/api/v1/tasks/interaction", + { + "type": "text_reply_to_message", + "message_id": message_id, + "task_id": task["id"], + "user_message_id": user_message_id, + "text": gen_random_text(), + "user": USER, + }, + ) + tasks.append(new_task) - case "label_prompter_reply" | "label_assistant_reply": - # acknowledge task - typer.echo("Here is the conversation so far:") - for message in task["conversation"]["messages"]: - typer.echo(_render_message(message)) + case "assistant_reply": + # acknowledge task + message_id = _random_message_id() + user_message_id = _random_message_id() + _post(f"/api/v1/tasks/{task['id']}/ack", {"message_id": message_id}) + # send interaction + new_task = _post( + "/api/v1/tasks/interaction", + { + "type": "text_reply_to_message", + "message_id": message_id, + "task_id": task["id"], + "user_message_id": user_message_id, + "text": gen_random_text(), + "user": USER, + }, + ) + tasks.append(new_task) - typer.echo("Label the following reply:") - typer.echo(task["reply"]) - message_id = _random_message_id() - user_message_id = _random_message_id() - _post(f"/api/v1/tasks/{task['id']}/ack", {"message_id": message_id}) - valid_labels = task["valid_labels"] - mandatory_labels = task["mandatory_labels"] + case "rank_prompter_replies" | "rank_assistant_replies": + # acknowledge task + message_id = _random_message_id() + user_message_id = _random_message_id() + _post(f"/api/v1/tasks/{task['id']}/ack", {"message_id": message_id}) + # send interaction + ranking = gen_random_ranking(task["replies"]) + print(ranking) + new_task = _post( + "/api/v1/tasks/interaction", + { + "type": "message_ranking", + "message_id": message_id, + "task_id": task["id"], + "ranking": ranking, + "user": USER, + }, + ) + tasks.append(new_task) - labels_dict = None - if task["mode"] == "simple" and len(valid_labels) == 1: - answer = random.choice([True, False]) - labels_dict = {valid_labels[0]: 1 if answer else 0} - else: - labels = random.sample(valid_labels, random.randint(1, len(valid_labels))) - for l in mandatory_labels: - if l not in labels: - labels.append(l) - labels_dict = {label: random.random() for label in valid_labels} - if random.random() < 0.9: - labels_dict["spam"] = 0 - labels_dict["lang_mismatch"] = 0 + case "rank_initial_prompts": + # acknowledge task + message_id = _random_message_id() + user_message_id = _random_message_id() + _post(f"/api/v1/tasks/{task['id']}/ack", {"message_id": message_id}) + # send interaction + ranking = gen_random_ranking(task["prompots"]) + new_task = _post( + "/api/v1/tasks/interaction", + { + "type": "message_ranking", + "message_id": message_id, + "ranking": ranking, + "user": USER, + }, + ) + tasks.append(new_task) - # send interaction - new_task = _post( - "/api/v1/tasks/interaction", - { - "type": "text_labels", - "message_id": task["message_id"], - "task_id": task["id"], - "text": task["reply"], - "labels": labels_dict, - "user": USER, - }, - ) - tasks.append(new_task) - case "task_done": - typer.echo("Task done!") - # rerun with new task selected from above cases - # add a new task - q += 1 - if q == 10: + case "label_prompter_reply" | "label_assistant_reply": + # acknowledge task + typer.echo("Here is the conversation so far:") + for message in task["conversation"]["messages"]: + typer.echo(_render_message(message)) + + typer.echo("Label the following reply:") + typer.echo(task["reply"]) + message_id = _random_message_id() + user_message_id = _random_message_id() + _post(f"/api/v1/tasks/{task['id']}/ack", {"message_id": message_id}) + valid_labels = task["valid_labels"] + mandatory_labels = task["mandatory_labels"] + + labels_dict = None + if task["mode"] == "simple" and len(valid_labels) == 1: + answer = random.choice([True, False]) + labels_dict = {valid_labels[0]: 1 if answer else 0} + else: + labels = random.sample(valid_labels, random.randint(1, len(valid_labels))) + for l in mandatory_labels: + if l not in labels: + labels.append(l) + labels_dict = {label: random.random() for label in valid_labels} + if random.random() < 0.9: + labels_dict["spam"] = 0 + labels_dict["lang_mismatch"] = 0 + + # send interaction + new_task = _post( + "/api/v1/tasks/interaction", + { + "type": "text_labels", + "message_id": task["message_id"], + "task_id": task["id"], + "text": task["reply"], + "labels": labels_dict, + "user": USER, + }, + ) + tasks.append(new_task) + case "task_done": typer.echo("Task done!") - break - tasks = [_post("/api/v1/tasks/", {"type": "random", "user": USER})] - # - case _: - typer.echo(f"Unknown task type {task['type']}") - # rerun with new task selected from above cases + # rerun with new task selected from above cases + # add a new task + q += 1 + if q == task_per_user: + typer.echo("Task done!") + break + tasks = [_post("/api/v1/tasks/", {"type": "random", "user": USER})] + # + case _: + typer.echo(f"Unknown task type {task['type']}") + # rerun with new task selected from above cases if __name__ == "__main__": diff --git a/text-frontend/requirements.txt b/text-frontend/requirements.txt index 3904ecb5..fe1ce30a 100644 --- a/text-frontend/requirements.txt +++ b/text-frontend/requirements.txt @@ -1,2 +1,3 @@ +faker==16.6.1 requests==2.28.1 typer==0.7.0 diff --git a/website/src/components/Dashboard/LeaderboardWidget.tsx b/website/src/components/Dashboard/LeaderboardWidget.tsx index 38fe6207..3e40e5ee 100644 --- a/website/src/components/Dashboard/LeaderboardWidget.tsx +++ b/website/src/components/Dashboard/LeaderboardWidget.tsx @@ -1,6 +1,6 @@ import { Card, CardBody, Link, Text } from "@chakra-ui/react"; -import { useTranslation } from "next-i18next"; import NextLink from "next/link"; +import { useTranslation } from "next-i18next"; import { LeaderboardTable } from "src/components/LeaderboardTable"; import { LeaderboardTimeFrame } from "src/types/Leaderboard"; @@ -19,7 +19,7 @@ export function LeaderboardWidget() { - + diff --git a/website/src/components/DataTable.tsx b/website/src/components/DataTable.tsx index c724ada5..f25f30dd 100644 --- a/website/src/components/DataTable.tsx +++ b/website/src/components/DataTable.tsx @@ -23,7 +23,7 @@ import { Tr, useDisclosure, } from "@chakra-ui/react"; -import { ColumnDef, flexRender, getCoreRowModel, Row, useReactTable } from "@tanstack/react-table"; +import { Cell, ColumnDef, flexRender, getCoreRowModel, Row, useReactTable } from "@tanstack/react-table"; import { Filter } from "lucide-react"; import { useTranslation } from "next-i18next"; import { ChangeEvent, ReactNode } from "react"; @@ -31,6 +31,7 @@ import { useDebouncedCallback } from "use-debounce"; export type DataTableColumnDef = ColumnDef & { filterable?: boolean; + span?: number | ((cell: Cell) => number | undefined); }; // TODO: stricter type @@ -126,9 +127,7 @@ export const DataTable = ({ const props = typeof rowProps === "function" ? rowProps(row) : rowProps; return ( - {row.getVisibleCells().map((cell) => ( - {flexRender(cell.column.columnDef.cell, cell.getContext())} - ))} + ); })} @@ -139,6 +138,36 @@ export const DataTable = ({ ); }; +type WithSpanCell = Cell & { span?: number }; + +const DataTableRow = ({ row }: { row: Row }) => { + const cells: WithSpanCell[] = row.getVisibleCells(); + const renderCells: WithSpanCell[] = []; + + for (let i = 0; i < cells.length; i++) { + const cell = cells[i]; + const span = (cell.column.columnDef as DataTableColumnDef).span; + const spanValue = typeof span === "function" ? span(cell) : span; + if (spanValue && spanValue > 1) { + i += spanValue - 1; // skip next `spanValue - 1` cell + } + cell.span = spanValue; + renderCells.push(cell); + } + + return ( + <> + {renderCells.map((cell) => { + return ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ); + })} + + ); +}; + const FilterModal = ({ label, onChange, diff --git a/website/src/components/LeaderboardTable/LeaderboardTable.tsx b/website/src/components/LeaderboardTable/LeaderboardTable.tsx index 6314080c..b775be8d 100644 --- a/website/src/components/LeaderboardTable/LeaderboardTable.tsx +++ b/website/src/components/LeaderboardTable/LeaderboardTable.tsx @@ -1,5 +1,6 @@ -import { CircularProgress, useColorModeValue, useToken } from "@chakra-ui/react"; +import { Box, CircularProgress, Flex, useColorModeValue, useToken } from "@chakra-ui/react"; import { createColumnHelper } from "@tanstack/react-table"; +import { MoreHorizontal } from "lucide-react"; import { useTranslation } from "next-i18next"; import React, { useCallback, useMemo, useState } from "react"; import { get } from "src/lib/api"; @@ -7,9 +8,11 @@ import { colors } from "src/styles/Theme/colors"; import { LeaderboardEntity, LeaderboardReply, LeaderboardTimeFrame } from "src/types/Leaderboard"; import useSWRImmutable from "swr/immutable"; -import { DataTable, DataTableRowPropsCallback } from "../DataTable"; +import { DataTable, DataTableColumnDef, DataTableRowPropsCallback } from "../DataTable"; -const columnHelper = createColumnHelper(); +type WindowLeaderboardEntity = LeaderboardEntity & { isSpaceRow?: boolean }; + +const columnHelper = createColumnHelper(); /** * Presents a grid of leaderboard entries with more detailed information. @@ -18,10 +21,12 @@ export const LeaderboardTable = ({ timeFrame, limit: limit, rowPerPage, + hideCurrentUserRanking, }: { timeFrame: LeaderboardTimeFrame; limit: number; rowPerPage: number; + hideCurrentUserRanking?: boolean; }) => { const { t } = useTranslation("leaderboard"); @@ -29,15 +34,19 @@ export const LeaderboardTable = ({ data: reply, isLoading, error, - } = useSWRImmutable(`/api/leaderboard?time_frame=${timeFrame}&limit=${limit}`, get, { - revalidateOnMount: true, - }); - - const columns = useMemo( + } = useSWRImmutable( + `/api/leaderboard?time_frame=${timeFrame}&limit=${limit}&includeUserStats=${!hideCurrentUserRanking}`, + get + ); + const columns: DataTableColumnDef[] = useMemo( () => [ - columnHelper.accessor("rank", { - header: t("rank"), - }), + { + ...columnHelper.accessor("rank", { + header: t("rank"), + cell: ({ row, getValue }) => (row.original.isSpaceRow ? : getValue()), + }), + span: (cell) => (cell.row.original.isSpaceRow ? 6 : undefined), + }, columnHelper.accessor("display_name", { header: t("user"), }), @@ -63,15 +72,72 @@ export const LeaderboardTable = ({ }, [t, reply?.last_updated]); const [page, setPage] = useState(1); - const data = useMemo(() => { + const data: WindowLeaderboardEntity[] = useMemo(() => { + if (!reply) { + return []; + } const start = (page - 1) * rowPerPage; - return reply?.leaderboard.slice(start, start + rowPerPage) || []; - }, [rowPerPage, page, reply?.leaderboard]); + const end = start + rowPerPage; + const leaderBoardEntities = reply.leaderboard.slice(start, end); + if (hideCurrentUserRanking) { + return leaderBoardEntities; + } + const userStatsWindow: WindowLeaderboardEntity[] = reply.user_stats_window; + const userStats = userStatsWindow.find((stats) => stats.highlighted); + if (userStats.rank > end) { + leaderBoardEntities.push( + { isSpaceRow: true } as WindowLeaderboardEntity, + ...reply.user_stats_window.filter( + (stats) => + leaderBoardEntities.findIndex((leaderBoardEntity) => leaderBoardEntity.user_id === stats.user_id) === -1 + ) // filter to avoid duplicated row + ); + } + return leaderBoardEntities; + }, [page, rowPerPage, reply, hideCurrentUserRanking]); + const rowProps = useLeaderboardRowProps(); + + if (isLoading) { + return ; + } + + if (error) { + return Unable to load leaderboard; + } + + const maxPage = Math.ceil(reply.leaderboard.length / rowPerPage); + + return ( + = maxPage} + disablePrevious={page === 1} + onNextClick={() => setPage((p) => p + 1)} + onPreviousClick={() => setPage((p) => p - 1)} + rowProps={rowProps} + > + ); +}; + +const SpaceRow = () => { + const color = useColorModeValue("gray.600", "gray.400"); + return ( + + + + ); +}; + +const useLeaderboardRowProps = () => { const borderColor = useToken("colors", useColorModeValue(colors.light.active, colors.dark.active)); - const rowProps = useCallback>( + return useCallback>( (row) => { - return row.original.highlighted + const rowData = row.original; + return rowData.highlighted ? { sx: { // https://stackoverflow.com/questions/37963524/how-to-apply-border-radius-to-tr-in-bootstrap @@ -93,28 +159,4 @@ export const LeaderboardTable = ({ }, [borderColor] ); - - if (isLoading) { - return ; - } - - if (error) { - return Unable to load leaderboard; - } - - const maxPage = Math.ceil(reply.leaderboard.length / rowPerPage); - - return ( - setPage((p) => p + 1)} - onPreviousClick={() => setPage((p) => p - 1)} - rowProps={rowProps} - > - ); }; diff --git a/website/src/lib/api.ts b/website/src/lib/api.ts index 27b1b811..c35ea87f 100644 --- a/website/src/lib/api.ts +++ b/website/src/lib/api.ts @@ -25,7 +25,13 @@ api.interceptors.response.use( (response) => response, (error) => { const err = error?.response?.data; - throw new OasstError(err?.message ?? error, err?.errorCode, error?.response?.httpStatusCode || -1); + throw new OasstError({ + message: err?.message ?? error, + errorCode: err?.errorCode, + httpStatusCode: error?.response?.httpStatusCode || -1, + method: err?.config?.method, + path: err?.config?.url, + }); } ); diff --git a/website/src/lib/oasst_api_client.ts b/website/src/lib/oasst_api_client.ts index 2aafab37..abd1173f 100644 --- a/website/src/lib/oasst_api_client.ts +++ b/website/src/lib/oasst_api_client.ts @@ -7,11 +7,27 @@ export class OasstError { message: string; errorCode: number; httpStatusCode: number; + path: string; + method: string; - constructor(message: string, errorCode: number, httpStatusCode: number) { + constructor({ + errorCode, + httpStatusCode, + message, + path, + method, + }: { + message: string; + errorCode: number; + httpStatusCode: number; + path: string; + method: string; + }) { this.message = message; this.errorCode = errorCode; this.httpStatusCode = httpStatusCode; + this.path = path; + this.method = method; } toString() { @@ -60,9 +76,21 @@ export class OasstApiClient { try { error = JSON.parse(errorText); } catch (e) { - throw new OasstError(errorText, 0, resp.status); + throw new OasstError({ + message: errorText, + errorCode: 0, + httpStatusCode: resp.status, + path, + method, + }); } - throw new OasstError(error.message ?? error, error.error_code, resp.status); + throw new OasstError({ + message: error.message ?? error, + errorCode: error.error_code, + httpStatusCode: resp.status, + path, + method, + }); } return resp.json(); @@ -297,9 +325,9 @@ export class OasstApiClient { return this.get(`/api/v1/messages/${messageId}/conversation`); } - async fetch_tos_acceptance(user: BackendUserCore): Promise { - const backendUser = await this.get(`/api/v1/frontend_users/${user.auth_method}/${user.id}`); - return backendUser.tos_acceptance_date; + async fetch_tos_acceptance(backendUserCore: BackendUserCore): Promise { + const user = await this.fetch_frontend_user(backendUserCore); + return user.tos_acceptance_date; } async set_tos_acceptance(user: BackendUserCore) { @@ -312,4 +340,14 @@ export class OasstApiClient { const backendUser = await this.get(`/api/v1/frontend_users/${user.auth_method}/${user.id}`); return this.get(`/api/v1/users/${backendUser.user_id}/stats`); } + + fetch_user_stats_window(user_id: string, time_frame: LeaderboardTimeFrame, window_size?: number) { + return this.get(`/api/v1/users/${user_id}/stats/${time_frame}/window`, { + window_size, + }); + } + + fetch_frontend_user(user: BackendUserCore) { + return this.get(`/api/v1/frontend_users/${user.auth_method}/${user.id}`); + } } diff --git a/website/src/pages/api/leaderboard.ts b/website/src/pages/api/leaderboard.ts index fad1d8a6..42f74c3d 100644 --- a/website/src/pages/api/leaderboard.ts +++ b/website/src/pages/api/leaderboard.ts @@ -1,5 +1,6 @@ import { withoutRole } from "src/lib/auth"; import { createApiClient } from "src/lib/oasst_client_factory"; +import { getBackendUserCore } from "src/lib/users"; import { LeaderboardTimeFrame } from "src/types/Leaderboard"; /** @@ -7,9 +8,29 @@ import { LeaderboardTimeFrame } from "src/types/Leaderboard"; */ const handler = withoutRole("banned", async (req, res, token) => { const oasstApiClient = await createApiClient(token); + const backendUser = await getBackendUserCore(token.sub); const time_frame = (req.query.time_frame as LeaderboardTimeFrame) ?? LeaderboardTimeFrame.day; - const info = await oasstApiClient.fetch_leaderboard(time_frame, { limit: req.query.limit as unknown as number }); - res.status(200).json(info); + const includeUserStats = req.query.includeUserStats; + + if (includeUserStats !== "true") { + const leaderboard = await oasstApiClient.fetch_leaderboard(time_frame, { + limit: req.query.limit as unknown as number, + }); + return res.status(200).json(leaderboard); + } + const user = await oasstApiClient.fetch_frontend_user(backendUser); + + const [leaderboard, user_stats] = await Promise.all([ + oasstApiClient.fetch_leaderboard(time_frame, { + limit: req.query.limit as unknown as number, + }), + oasstApiClient.fetch_user_stats_window(user.user_id, time_frame, 3), + ]); + + res.status(200).json({ + ...leaderboard, + user_stats_window: user_stats.leaderboard.map((stats) => ({ ...stats, is_window: true })), + }); }); export default handler; From 1938f4d3a7c64649764b5a45d627cfb734cea2e1 Mon Sep 17 00:00:00 2001 From: AbdBarho Date: Tue, 7 Feb 2023 06:51:10 +0100 Subject: [PATCH 110/152] Add missing keys to all locales (#1264) --- website/public/locales/ar/common.json | 8 +- website/public/locales/ar/dashboard.json | 8 +- website/public/locales/ar/labelling.json | 24 ++-- website/public/locales/ar/leaderboard.json | 20 ++-- website/public/locales/ar/message.json | 6 +- website/public/locales/ar/side_menu.json | 8 +- website/public/locales/ar/tasks.json | 104 +++++++++--------- website/public/locales/ar/tos.json | 6 +- website/public/locales/ca/common.json | 2 +- website/public/locales/ca/dashboard.json | 8 +- website/public/locales/ca/labelling.json | 24 ++-- website/public/locales/ca/leaderboard.json | 20 ++-- website/public/locales/ca/message.json | 2 +- website/public/locales/ca/side_menu.json | 8 +- website/public/locales/ca/tasks.json | 104 +++++++++--------- website/public/locales/ca/tos.json | 6 +- website/public/locales/de/dashboard.json | 8 +- website/public/locales/de/labelling.json | 1 + website/public/locales/de/message.json | 9 +- website/public/locales/de/side_menu.json | 12 ++ website/public/locales/de/tasks.json | 101 ++++++++--------- website/public/locales/de/tos.json | 6 + website/public/locales/es/common.json | 2 +- website/public/locales/es/dashboard.json | 8 +- website/public/locales/es/labelling.json | 24 ++-- website/public/locales/es/leaderboard.json | 20 ++-- website/public/locales/es/message.json | 2 +- website/public/locales/es/side_menu.json | 8 +- website/public/locales/es/tasks.json | 104 +++++++++--------- website/public/locales/es/tos.json | 6 + website/public/locales/fr/common.json | 8 +- website/public/locales/fr/dashboard.json | 8 +- website/public/locales/fr/labelling.json | 24 ++-- website/public/locales/fr/leaderboard.json | 20 ++-- website/public/locales/fr/message.json | 6 +- website/public/locales/fr/side_menu.json | 8 +- website/public/locales/fr/tasks.json | 104 +++++++++--------- website/public/locales/fr/tos.json | 6 +- website/public/locales/hu/common.json | 5 + website/public/locales/hu/dashboard.json | 8 +- website/public/locales/hu/labelling.json | 24 ++-- website/public/locales/hu/leaderboard.json | 14 ++- website/public/locales/hu/message.json | 8 +- website/public/locales/hu/side_menu.json | 12 ++ website/public/locales/hu/tasks.json | 104 +++++++++--------- website/public/locales/hu/tos.json | 6 + website/public/locales/it/dashboard.json | 8 +- website/public/locales/it/message.json | 2 +- website/public/locales/it/side_menu.json | 8 +- website/public/locales/it/tasks.json | 104 +++++++++--------- website/public/locales/it/tos.json | 6 +- website/public/locales/ko/common.json | 8 +- website/public/locales/ko/dashboard.json | 8 +- website/public/locales/ko/labelling.json | 24 ++-- website/public/locales/ko/leaderboard.json | 20 ++-- website/public/locales/ko/message.json | 6 +- website/public/locales/ko/side_menu.json | 8 +- website/public/locales/ko/tasks.json | 104 +++++++++--------- website/public/locales/ko/tos.json | 6 + website/public/locales/pt-BR/common.json | 2 +- website/public/locales/pt-BR/dashboard.json | 8 +- website/public/locales/pt-BR/labelling.json | 24 ++-- website/public/locales/pt-BR/leaderboard.json | 20 ++-- website/public/locales/pt-BR/message.json | 2 +- website/public/locales/pt-BR/side_menu.json | 8 +- website/public/locales/pt-BR/tasks.json | 104 +++++++++--------- website/public/locales/pt-BR/tos.json | 6 +- website/public/locales/ru/common.json | 8 +- website/public/locales/ru/dashboard.json | 8 +- website/public/locales/ru/index.json | 23 ++++ website/public/locales/ru/labelling.json | 24 ++-- website/public/locales/ru/leaderboard.json | 20 ++-- website/public/locales/ru/message.json | 6 +- website/public/locales/ru/side_menu.json | 8 +- website/public/locales/ru/tasks.json | 82 ++++++++++++++ website/public/locales/ru/tos.json | 6 +- website/public/locales/tr/common.json | 2 +- website/public/locales/tr/dashboard.json | 8 +- website/public/locales/tr/labelling.json | 24 ++-- website/public/locales/tr/leaderboard.json | 20 ++-- website/public/locales/tr/message.json | 2 +- website/public/locales/tr/side_menu.json | 8 +- website/public/locales/tr/tasks.json | 104 +++++++++--------- website/public/locales/tr/tos.json | 6 +- website/public/locales/uk-UA/common.json | 2 +- website/public/locales/uk-UA/dashboard.json | 8 +- website/public/locales/uk-UA/labelling.json | 24 ++-- website/public/locales/uk-UA/leaderboard.json | 20 ++-- website/public/locales/uk-UA/message.json | 2 +- website/public/locales/uk-UA/side_menu.json | 8 +- website/public/locales/uk-UA/tasks.json | 104 +++++++++--------- website/public/locales/uk-UA/tos.json | 6 +- website/public/locales/vi/common.json | 8 +- website/public/locales/vi/dashboard.json | 8 +- website/public/locales/vi/labelling.json | 24 ++-- website/public/locales/vi/leaderboard.json | 20 ++-- website/public/locales/vi/message.json | 6 +- website/public/locales/vi/side_menu.json | 8 +- website/public/locales/vi/tasks.json | 104 +++++++++--------- website/public/locales/vi/tos.json | 6 +- 100 files changed, 1222 insertions(+), 1015 deletions(-) create mode 100644 website/public/locales/de/side_menu.json create mode 100644 website/public/locales/de/tos.json create mode 100644 website/public/locales/es/tos.json create mode 100644 website/public/locales/hu/side_menu.json create mode 100644 website/public/locales/hu/tos.json create mode 100644 website/public/locales/ko/tos.json create mode 100644 website/public/locales/ru/index.json create mode 100644 website/public/locales/ru/tasks.json diff --git a/website/public/locales/ar/common.json b/website/public/locales/ar/common.json index 88f60ec7..b89cafe8 100644 --- a/website/public/locales/ar/common.json +++ b/website/public/locales/ar/common.json @@ -4,12 +4,15 @@ "admin_dashboard": "لوحة التحكم الإدارية", "connect": "الاتصال", "conversational": "ذكاء تحدثي للجميع.", + "copied": "Copied", + "dark_mode": "الوضع الداكن", "dashboard": "لوحة التحكم", "delete": "حذف", "discord": "ديسكورد", "docs": "وثائق", "github": "جيت هوب (github)", "legal": "قانوني", + "light_mode": "الوضع المضيء", "loading": "جار التحميل...", "more_information": "مزيد من المعلومات", "no": "لا", @@ -17,9 +20,8 @@ "report_a_bug": "إبلاغ عن خطأ", "sign_in": "تسجيل الدخول", "sign_out": "تسجيل الخروج", + "success": "Success", "terms_of_service": "شروط الخدمة", "title": "Open Assistant (المساعد المفتوح)", - "yes": "نعم", - "dark_mode": "الوضع الداكن", - "light_mode": "الوضع المضيء" + "yes": "نعم" } diff --git a/website/public/locales/ar/dashboard.json b/website/public/locales/ar/dashboard.json index 789abb97..d87be0d1 100644 --- a/website/public/locales/ar/dashboard.json +++ b/website/public/locales/ar/dashboard.json @@ -1,8 +1,8 @@ { - "grab_a_task": "التقاط مهمة!", "create": "خلق", - "evaluate": "تقييم", - "label": "تصنيف", "dashboard": "لوحة التحكم", - "go": "ذهاب" + "evaluate": "تقييم", + "go": "ذهاب", + "grab_a_task": "التقاط مهمة!", + "label": "تصنيف" } diff --git a/website/public/locales/ar/labelling.json b/website/public/locales/ar/labelling.json index a2cf6c15..55356e19 100644 --- a/website/public/locales/ar/labelling.json +++ b/website/public/locales/ar/labelling.json @@ -1,24 +1,24 @@ { - "label_highlighted_yes_no_instruction": "أجب على السؤال (الأسئلة) التالي عن الخطاب المميز:", + "fails_task.question": "هل هي رد سيئ، كجواب على مهمة النداء؟", + "hate_speech": "نشاط عدائي", + "hate_speech.explanation": "المحتوى يحمل عبارات تشهير أو تهديد ويعبر عن الطائفية ضد خاصية محمية. الطائفية تعني الآراء المسبقة التي لا تعتمد على العقل. الخصائص المحمية تشمل الجنس والعرق والدين والميول الجنسية ومثل هذه الخصائص.", "label_highlighted_flag_instruction": "حدد أي أن تنطبق على الخطاب المميز:", "label_highlighted_likert_instruction": "تقييم الخطاب المميز:", - "label_message_yes_no_instruction": "أجب على السؤال (الأسئلة) التالي عن الخطاب:", + "label_highlighted_yes_no_instruction": "أجب على السؤال (الأسئلة) التالي عن الخطاب المميز:", "label_message_flag_instruction": "حدد أي أن تنطبق على الخطاب:", "label_message_likert_instruction": "تقييم الخطاب:", - "spam.question": "هل الخطاب هي رسالة غير مرغوب فيها؟", - "fails_task.question": "هل هي رد سيئ، كجواب على مهمة النداء؟", + "label_message_yes_no_instruction": "أجب على السؤال (الأسئلة) التالي عن الخطاب:", + "lang_mismatch": "لغة خاطئة", + "lang_mismatch.explanation": "لم كتب باللغة المحددة حاليا.", + "moral_judgement": "حكم على الأخلاقيات", + "moral_judgement.explanation": "يعبر عن الأخلاقيات.", "not_appropriate": "غير مناسب", "not_appropriate.explanation": "غير مناسب لمساعد العميل.", "pii": "تحتوي على PII", "pii.explanation": "تحتوي على معلومات شخصية يمكن تحديد الهوية بها. مثال يشمل تفاصيل اتصال شخصية، رقم ترخيص وغيرها من أرقام الهوية وتفاصيل الحساب المصرفي.", - "hate_speech": "نشاط عدائي", - "hate_speech.explanation": "المحتوى يحمل عبارات تشهير أو تهديد ويعبر عن الطائفية ضد خاصية محمية. الطائفية تعني الآراء المسبقة التي لا تعتمد على العقل. الخصائص المحمية تشمل الجنس والعرق والدين والميول الجنسية ومثل هذه الخصائص.", - "sexual_content": "المحتوى الجنسي", - "sexual_content.explanation": "يحتوي على محتوى جنسي.", - "moral_judgement": "حكم على الأخلاقيات", - "moral_judgement.explanation": "يعبر عن الأخلاقيات.", "political_content": "سياسي", "political_content.explanation": "يعبر عن الآراء السياسية.", - "lang_mismatch": "لغة خاطئة", - "lang_mismatch.explanation": "لم كتب باللغة المحددة حاليا." + "sexual_content": "المحتوى الجنسي", + "sexual_content.explanation": "يحتوي على محتوى جنسي.", + "spam.question": "هل الخطاب هي رسالة غير مرغوب فيها؟" } diff --git a/website/public/locales/ar/leaderboard.json b/website/public/locales/ar/leaderboard.json index 3e724918..ab37d1a8 100644 --- a/website/public/locales/ar/leaderboard.json +++ b/website/public/locales/ar/leaderboard.json @@ -1,18 +1,18 @@ { "daily": "يومياً", + "label": "العلامات", "last_updated_at": "آخر تحديث في: {{val, datetime}}", "leaderboard": "الجدول الترتيبي", "monthly": "شهرياً", + "next": "التالي", "overall": "إجمالياً", - "rank": "الترتيب", - "score": "النقاط", - "user": "المستخدم", - "weekly": "أسبوعياً", - "prompt": "المقترحات", - "reply": "الردود", - "label": "العلامات", - "view_all": "عرض الكل", - "top_5_contributors_today": "أعلى 5 مساهمين اليوم", "previous": "السابق", - "next": "التالي" + "prompt": "المقترحات", + "rank": "الترتيب", + "reply": "الردود", + "score": "النقاط", + "top_5_contributors_today": "أعلى 5 مساهمين اليوم", + "user": "المستخدم", + "view_all": "عرض الكل", + "weekly": "أسبوعياً" } diff --git a/website/public/locales/ar/message.json b/website/public/locales/ar/message.json index 949dee1c..a007673e 100644 --- a/website/public/locales/ar/message.json +++ b/website/public/locales/ar/message.json @@ -1,16 +1,20 @@ { + "copy_message_id": "Copy message ID", "label_action": "تصنيف", "label_title": "تصنيف", "message": "رسالة", + "message_deleted": "Message deleted", "open_new_tab_action": "فتح في علامة تبويب جديدة", "parent": "الأصل", "reactions": "الردود", + "recent_messages": "أحدث الرسائل", "report_action": "تبليغ", "report_placeholder": "لماذا يجب استعراض هذه الرسالة؟", "report_title": "تبليغ", "send_report": "إرسال", + "stop_tree": "Stop tree", "submit_labels": "إرسال", + "tree_stopped": "Tree stopped {{id}}", "view_user": "عرض المستخدم", - "recent_messages": "أحدث الرسائل", "your_recent_messages": "أحدث رسائلك" } diff --git a/website/public/locales/ar/side_menu.json b/website/public/locales/ar/side_menu.json index 467ed046..4f7edcae 100644 --- a/website/public/locales/ar/side_menu.json +++ b/website/public/locales/ar/side_menu.json @@ -1,12 +1,12 @@ { "dashboard": "لوحة التحكم", "dashboard_home": "الصفحة الرئيسية للإحصائيات", + "leaderboard": "جدول الأوائل", "messages": "رسائل", "messages_dashboard": "لوحة تحكم الرسائل", - "leaderboard": "جدول الأوائل", + "status": "الحالة", + "status_dashboard": "لوحة تحكم الحالة", "user_leaderboard": "جدول الأوائل للمستخدمين", "users": "المستخدمون", - "users_dashboard": "لوحة تحكم المستخدمين", - "status": "الحالة", - "status_dashboard": "لوحة تحكم الحالة" + "users_dashboard": "لوحة تحكم المستخدمين" } diff --git a/website/public/locales/ar/tasks.json b/website/public/locales/ar/tasks.json index cc65d86f..fdfb2d86 100644 --- a/website/public/locales/ar/tasks.json +++ b/website/public/locales/ar/tasks.json @@ -1,11 +1,19 @@ { - "default": { - "unchanged_title": "لا تغير", - "unchanged_message": "هل أنت متأكد من أنك تريد المتابعة؟" + "available_task_count": "{{count}} مهام متاحة", + "classify_assistant_reply": { + "label": "تصنيف رد المساعد", + "desc": "توفير ملصقات للمنادي.", + "overview": "اقرأ المحادثة التالية وثم أجب عن السؤال حول آخر رد في المناقشة." }, - "random": { - "label": "أنا أشعر بالحظ", - "desc": "ساعدنا في تحسين Open Assistant ببدء مهمة عشوائية." + "classify_initial_prompt": { + "label": "صنف بداية النداء", + "desc": "أعط علامات للنداء", + "overview": "اقرأ النداء التالي وأجب عن السؤال عنه." + }, + "classify_prompter_reply": { + "label": "تصنيف رد المنادي", + "desc": "توفير ملصقات للمنادي.", + "overview": "اقرأ المحادثة التالية وثم أجب عن السؤال حول آخر رد في المناقشة." }, "create_initial_prompt": { "label": "إنشاء النداء الأولي", @@ -14,25 +22,28 @@ "instruction": "أعط االندائات الأولية", "response_placeholder": "اكتب نداءك هنا..." }, - "reply_as_user": { - "label": "الرد كمستخدم", - "desc": "تحدث مع Open Assistant وساعده في تحسين ردوده عند التفاعل معه.", - "overview": "بناءً على المحادثة التالية، توفر رد مناسب", - "instruction": "أعط رد المستخدم", - "response_placeholder": "اكتب ردك هنا..." + "default": { + "unchanged_title": "لا تغير", + "unchanged_message": "هل أنت متأكد من أنك تريد المتابعة؟" }, - "reply_as_assistant": { - "label": "كــــالمدراء", - "desc": "مساعدة Open Assistant لتحسين ردوده على محادثات مع مستخدمين آخرين.", - "overview": "بعد الحصول على المحادثة التالية، توفير رد كافي", - "response_placeholder": "اكتب ردك هنا..." + "label_assistant_reply": { + "label": "تصنيف الرد عن طريق المساعد", + "desc": "تقديم تصنيفات للنداء.", + "overview": "بعد النقاش التالي، تقديم تصنيفات للنداء النهائي." }, - "rank_user_replies": { - "label": "تصنيف ردود المستخدم", - "desc": "مساعدة Open Assistant لتحسين ردوده على محادثات مع مستخدمين آخرين.", - "overview": "بعد الحصول على الردود التالية للمستخدم، قم بترتيبها من أفضل إلى أسوأ، أفضل أولاً وأسوأ آخراً.", - "unchanged_title": "لم يتغير الترتيب", - "unchanged_message": "لم تقم بتغيير ترتيب الردود. هل أنت متأكد من أن تود الاستمرار؟" + "label_initial_prompt": { + "label": "تصنيف النداء الأولي", + "desc": "توفير تصنيفات للنداء.", + "overview": "توفير تصنيفات للنداء التالي" + }, + "label_prompter_reply": { + "label": "تصنيف الرد على النداء", + "desc": "أعط تصنيفات للنداء.", + "overview": "أعط تصنيفات للرد النهائي في المناقشة التالية." + }, + "random": { + "label": "أنا أشعر بالحظ", + "desc": "ساعدنا في تحسين Open Assistant ببدء مهمة عشوائية." }, "rank_assistant_replies": { "label": "تصنيف ردود المدراء", @@ -48,35 +59,24 @@ "unchanged_title": "لم يتغير الترتيب", "unchanged_message": "لم تغير ترتيب النداءات. هل أنت متأكد من أنك ترغب في الاستمرار؟" }, - "label_initial_prompt": { - "label": "تصنيف النداء الأولي", - "desc": "توفير تصنيفات للنداء.", - "overview": "توفير تصنيفات للنداء التالي" + "rank_user_replies": { + "label": "تصنيف ردود المستخدم", + "desc": "مساعدة Open Assistant لتحسين ردوده على محادثات مع مستخدمين آخرين.", + "overview": "بعد الحصول على الردود التالية للمستخدم، قم بترتيبها من أفضل إلى أسوأ، أفضل أولاً وأسوأ آخراً.", + "unchanged_title": "لم يتغير الترتيب", + "unchanged_message": "لم تقم بتغيير ترتيب الردود. هل أنت متأكد من أن تود الاستمرار؟" }, - "label_prompter_reply": { - "label": "تصنيف الرد على النداء", - "desc": "أعط تصنيفات للنداء.", - "overview": "أعط تصنيفات للرد النهائي في المناقشة التالية." + "reply_as_assistant": { + "label": "كــــالمدراء", + "desc": "مساعدة Open Assistant لتحسين ردوده على محادثات مع مستخدمين آخرين.", + "overview": "بعد الحصول على المحادثة التالية، توفير رد كافي", + "response_placeholder": "اكتب ردك هنا..." }, - "label_assistant_reply": { - "label": "تصنيف الرد عن طريق المساعد", - "desc": "تقديم تصنيفات للنداء.", - "overview": "بعد النقاش التالي، تقديم تصنيفات للنداء النهائي." - }, - "classify_initial_prompt": { - "label": "صنف بداية النداء", - "desc": "أعط علامات للنداء", - "overview": "اقرأ النداء التالي وأجب عن السؤال عنه." - }, - "classify_prompter_reply": { - "label": "تصنيف رد المنادي", - "desc": "توفير ملصقات للمنادي.", - "overview": "اقرأ المحادثة التالية وثم أجب عن السؤال حول آخر رد في المناقشة." - }, - "classify_assistant_reply": { - "label": "تصنيف رد المساعد", - "desc": "توفير ملصقات للمنادي.", - "overview": "اقرأ المحادثة التالية وثم أجب عن السؤال حول آخر رد في المناقشة." - }, - "available_task_count": "{{count}} مهام متاحة" + "reply_as_user": { + "label": "الرد كمستخدم", + "desc": "تحدث مع Open Assistant وساعده في تحسين ردوده عند التفاعل معه.", + "overview": "بناءً على المحادثة التالية، توفر رد مناسب", + "instruction": "أعط رد المستخدم", + "response_placeholder": "اكتب ردك هنا..." + } } diff --git a/website/public/locales/ar/tos.json b/website/public/locales/ar/tos.json index 9af56319..b4c80dba 100644 --- a/website/public/locales/ar/tos.json +++ b/website/public/locales/ar/tos.json @@ -1,6 +1,6 @@ { - "title": "شروط الخدمة لمساعد مفتوح", - "content": "للاستمرار في استخدام Open Assistant (المساعد المفتوح)، يجب عليك قبول شروط الخدمة الخاصة بنا أولاً.", "accept": "قبول", - "decline": "رفض" + "content": "للاستمرار في استخدام Open Assistant (المساعد المفتوح)، يجب عليك قبول شروط الخدمة الخاصة بنا أولاً.", + "decline": "رفض", + "title": "شروط الخدمة لمساعد مفتوح" } diff --git a/website/public/locales/ca/common.json b/website/public/locales/ca/common.json index 42466441..2e15ac62 100644 --- a/website/public/locales/ca/common.json +++ b/website/public/locales/ca/common.json @@ -2,9 +2,9 @@ "about": "Sobre", "account_settings": "Compte", "admin_dashboard": "Panell d'administració", - "copied": "Copiat", "connect": "Connectar", "conversational": "AI conversacional per a tothom.", + "copied": "Copiat", "dark_mode": "Mode fosc", "dashboard": "Panell principal", "delete": "Esborrar", diff --git a/website/public/locales/ca/dashboard.json b/website/public/locales/ca/dashboard.json index 837e37ec..a67d0390 100644 --- a/website/public/locales/ca/dashboard.json +++ b/website/public/locales/ca/dashboard.json @@ -1,8 +1,8 @@ { - "grab_a_task": "Pren una tasca!", "create": "Crear", - "evaluate": "Avaluar", - "label": "Etiquetar", "dashboard": "Panell principal", - "go": "Anar" + "evaluate": "Avaluar", + "go": "Anar", + "grab_a_task": "Pren una tasca!", + "label": "Etiquetar" } diff --git a/website/public/locales/ca/labelling.json b/website/public/locales/ca/labelling.json index 73e93969..e9bef673 100644 --- a/website/public/locales/ca/labelling.json +++ b/website/public/locales/ca/labelling.json @@ -1,24 +1,24 @@ { - "label_highlighted_yes_no_instruction": "Contesta la/les següent/s pregunta/s sobre el missatge ressaltat:", + "fails_task.question": "És una mala resposta, segons la tasca demanada?", + "hate_speech": "Incitació a l'odi", + "hate_speech.explanation": "El contingut és ofensiu o amenaçador i expressa un prejudici contra una característica protegida. El prejudici fa referència a les opinions preconcebudes que no es basen en la raó. Les característiques protegides inclouen gènere, ètnia, religió, orientació sexual i característiques semblants.", "label_highlighted_flag_instruction": "Selecciona qualsevol que sigui adequat per al missatge ressaltat:", "label_highlighted_likert_instruction": "Qualifica el missatge ressaltat:", - "label_message_yes_no_instruction": "Contesta la/les següent/s pregunta/es sobre el missatge:", + "label_highlighted_yes_no_instruction": "Contesta la/les següent/s pregunta/s sobre el missatge ressaltat:", "label_message_flag_instruction": "Selecciona qualsevol que sigui adequada per al missatge:", "label_message_likert_instruction": "Qualifica el missatge:", - "spam.question": "És el missatge spam?", - "fails_task.question": "És una mala resposta, segons la tasca demanada?", + "label_message_yes_no_instruction": "Contesta la/les següent/s pregunta/es sobre el missatge:", + "lang_mismatch": "Idioma incorrecte", + "lang_mismatch.explanation": "No està escrit a l'idioma seleccionat actualment.", + "moral_judgement": "Judici moral", + "moral_judgement.explanation": "Expressa un judici moral.", "not_appropriate": "No apropiada", "not_appropriate.explanation": "No apropiada per a un assistent de client.", "pii": "Conté informació d'identificació personal (PII)", "pii.explanation": "Conté informació personal com detalls de contacte personal, números d'identificació o detalls bancaris", - "hate_speech": "Incitació a l'odi", - "hate_speech.explanation": "El contingut és ofensiu o amenaçador i expressa un prejudici contra una característica protegida. El prejudici fa referència a les opinions preconcebudes que no es basen en la raó. Les característiques protegides inclouen gènere, ètnia, religió, orientació sexual i característiques semblants.", - "sexual_content": "Contingut sexual", - "sexual_content.explanation": "Conté contingut sexual.", - "moral_judgement": "Judici moral", - "moral_judgement.explanation": "Expressa un judici moral.", "political_content": "Contingut polític", "political_content.explanation": "Expressa una opinió política.", - "lang_mismatch": "Idioma incorrecte", - "lang_mismatch.explanation": "No està escrit a l'idioma seleccionat actualment." + "sexual_content": "Contingut sexual", + "sexual_content.explanation": "Conté contingut sexual.", + "spam.question": "És el missatge spam?" } diff --git a/website/public/locales/ca/leaderboard.json b/website/public/locales/ca/leaderboard.json index e5004696..0f3b01ad 100644 --- a/website/public/locales/ca/leaderboard.json +++ b/website/public/locales/ca/leaderboard.json @@ -1,18 +1,18 @@ { "daily": "Diari", + "label": "Etiquetes", "last_updated_at": "Última actualització: {{val, datetime}}", "leaderboard": "Taula de classificació", "monthly": "Mensual", + "next": "Següent", "overall": "Global", - "rank": "Posició", - "score": "Puntuació", - "user": "Usuari", - "weekly": "Setmanal", - "prompt": "Indicacions", - "reply": "Respostes", - "label": "Etiquetes", - "view_all": "Veure tots", - "top_5_contributors_today": "Top 5 contribuïdors avui", "previous": "Anterior", - "next": "Següent" + "prompt": "Indicacions", + "rank": "Posició", + "reply": "Respostes", + "score": "Puntuació", + "top_5_contributors_today": "Top 5 contribuïdors avui", + "user": "Usuari", + "view_all": "Veure tots", + "weekly": "Setmanal" } diff --git a/website/public/locales/ca/message.json b/website/public/locales/ca/message.json index 28ed2f09..a6d35b16 100644 --- a/website/public/locales/ca/message.json +++ b/website/public/locales/ca/message.json @@ -2,8 +2,8 @@ "copy_message_id": "Copiar ID del missatge", "label_action": "Etiquetar", "label_title": "Etiqueta", - "message_deleted": "Missatge esborrat", "message": "Missatge", + "message_deleted": "Missatge esborrat", "open_new_tab_action": "Obrir en una pestanya nova", "parent": "Pare", "reactions": "Reaccions", diff --git a/website/public/locales/ca/side_menu.json b/website/public/locales/ca/side_menu.json index aece4f4e..84e079d7 100644 --- a/website/public/locales/ca/side_menu.json +++ b/website/public/locales/ca/side_menu.json @@ -1,12 +1,12 @@ { "dashboard": "Panell principal", "dashboard_home": "Panell principal", + "leaderboard": "Classificacions", "messages": "Missatges", "messages_dashboard": "Taulell de missatges", - "leaderboard": "Classificacions", + "status": "Estat", + "status_dashboard": "Taulell d'estat", "user_leaderboard": "Classificació d'usuaris", "users": "Usuaris", - "users_dashboard": "Taulell d'usuaris", - "status": "Estat", - "status_dashboard": "Taulell d'estat" + "users_dashboard": "Taulell d'usuaris" } diff --git a/website/public/locales/ca/tasks.json b/website/public/locales/ca/tasks.json index a4409322..fe89c74c 100644 --- a/website/public/locales/ca/tasks.json +++ b/website/public/locales/ca/tasks.json @@ -1,11 +1,19 @@ { - "default": { - "unchanged_title": "Sense canvis", - "unchanged_message": "Estàs segur que vols continuar?" + "available_task_count": "{{count}} tasques disponibles", + "classify_assistant_reply": { + "label": "Classificar resposta de l'assistent", + "desc": "Proporciona etiquetes per a una resposta de l'assistent.", + "overview": "Llegeix la conversa següent i contesta a continuació la pregunta sobre l'última resposta a la discussió." }, - "random": { - "label": "Tindré sort", - "desc": "Ajuda'ns a millorar Open Assistant començant amb una tasca aleatòria." + "classify_initial_prompt": { + "label": "Classificar instruccions inicials", + "desc": "Proporciona etiquetes per a unes instruccions.", + "overview": "Llegeix la següent entrada i contesta a continuació la pregunta sobre aquesta." + }, + "classify_prompter_reply": { + "label": "Classificar la resposta de l'apuntador", + "desc": "Proporciona etiquetes per a una entrada.", + "overview": "Llegeix la conversa següent i contesta a continuació la pregunta sobre l'última resposta a la discussió." }, "create_initial_prompt": { "label": "Crear instruccions inicials", @@ -14,25 +22,28 @@ "instruction": "Proporciona les instruccions inicials", "response_placeholder": "Escriu les teves instruccions aquí..." }, - "reply_as_user": { - "label": "Contestar com a usuari", - "desc": "Parlar amb Open Assistant i intentar millorar les respostes mentre interacciones amb ell.", - "overview": "Donada la conversa següent, proporciona una resposta adequada", - "instruction": "Proporciona la resposta de l'usuari", - "response_placeholder": "Escriu la teva resposta aquí..." + "default": { + "unchanged_title": "Sense canvis", + "unchanged_message": "Estàs segur que vols continuar?" }, - "reply_as_assistant": { - "label": "Contestar com a assistent", - "desc": "Ajuda Open Assistant a millorar les seves respostes a converses amb altres usuaris.", - "overview": "Donada la conversa següent, proporciona una resposta adequada", - "response_placeholder": "Escriu la teva resposta aquí..." + "label_assistant_reply": { + "label": "Etiquetar resposta de l'assistent", + "desc": "Proporciona etiquetes per a unes instruccions.", + "overview": "Donada la discussió següent, proporciona etiquetes per a la darrera entrada." }, - "rank_user_replies": { - "label": "Ordenar respostes d'usuaris", - "desc": "Ajuda Open Assistant a millorar les seves respostes a converses amb altres usuaris.", - "overview": "Donades les respostes següents d'usuaris, ordeneu-les de millor a pitjor, amb la primera sent la millor i l'última, la pitjor.", - "unchanged_title": "Ordre sense canviar", - "unchanged_message": "No heu canviat l'ordre de les respostes. Segur que vols continuar?" + "label_initial_prompt": { + "label": "Etiquetar instruccions inicials", + "desc": "Proporciona etiquetes per a unes instruccions.", + "overview": "Proporciona etiquetes per a les instruccions següents" + }, + "label_prompter_reply": { + "label": "Etiquetar resposta de l'apuntador", + "desc": "Proporciona etiquetes per a unes instruccions.", + "overview": "Donada la discussió següent, proporciona etiquetes per a la darrera entrada." + }, + "random": { + "label": "Tindré sort", + "desc": "Ajuda'ns a millorar Open Assistant començant amb una tasca aleatòria." }, "rank_assistant_replies": { "label": "Ordenar respostes de l'assistent", @@ -48,35 +59,24 @@ "unchanged_title": "Ordre sense canviar", "unchanged_message": "No heu canviat l'ordre de les entrades. Segur que vols continuar?" }, - "label_initial_prompt": { - "label": "Etiquetar instruccions inicials", - "desc": "Proporciona etiquetes per a unes instruccions.", - "overview": "Proporciona etiquetes per a les instruccions següents" + "rank_user_replies": { + "label": "Ordenar respostes d'usuaris", + "desc": "Ajuda Open Assistant a millorar les seves respostes a converses amb altres usuaris.", + "overview": "Donades les respostes següents d'usuaris, ordeneu-les de millor a pitjor, amb la primera sent la millor i l'última, la pitjor.", + "unchanged_title": "Ordre sense canviar", + "unchanged_message": "No heu canviat l'ordre de les respostes. Segur que vols continuar?" }, - "label_prompter_reply": { - "label": "Etiquetar resposta de l'apuntador", - "desc": "Proporciona etiquetes per a unes instruccions.", - "overview": "Donada la discussió següent, proporciona etiquetes per a la darrera entrada." + "reply_as_assistant": { + "label": "Contestar com a assistent", + "desc": "Ajuda Open Assistant a millorar les seves respostes a converses amb altres usuaris.", + "overview": "Donada la conversa següent, proporciona una resposta adequada", + "response_placeholder": "Escriu la teva resposta aquí..." }, - "label_assistant_reply": { - "label": "Etiquetar resposta de l'assistent", - "desc": "Proporciona etiquetes per a unes instruccions.", - "overview": "Donada la discussió següent, proporciona etiquetes per a la darrera entrada." - }, - "classify_initial_prompt": { - "label": "Classificar instruccions inicials", - "desc": "Proporciona etiquetes per a unes instruccions.", - "overview": "Llegeix la següent entrada i contesta a continuació la pregunta sobre aquesta." - }, - "classify_prompter_reply": { - "label": "Classificar la resposta de l'apuntador", - "desc": "Proporciona etiquetes per a una entrada.", - "overview": "Llegeix la conversa següent i contesta a continuació la pregunta sobre l'última resposta a la discussió." - }, - "classify_assistant_reply": { - "label": "Classificar resposta de l'assistent", - "desc": "Proporciona etiquetes per a una resposta de l'assistent.", - "overview": "Llegeix la conversa següent i contesta a continuació la pregunta sobre l'última resposta a la discussió." - }, - "available_task_count": "{{count}} tasques disponibles" + "reply_as_user": { + "label": "Contestar com a usuari", + "desc": "Parlar amb Open Assistant i intentar millorar les respostes mentre interacciones amb ell.", + "overview": "Donada la conversa següent, proporciona una resposta adequada", + "instruction": "Proporciona la resposta de l'usuari", + "response_placeholder": "Escriu la teva resposta aquí..." + } } diff --git a/website/public/locales/ca/tos.json b/website/public/locales/ca/tos.json index e4723207..62327390 100644 --- a/website/public/locales/ca/tos.json +++ b/website/public/locales/ca/tos.json @@ -1,6 +1,6 @@ { - "title": "Condicions del servei d'Open Assistant", - "content": "Per continuar utilitzant Open Assistant, primer has d'acceptar les nostres Condicions del servei.", "accept": "Acceptar", - "decline": "Rebutjar" + "content": "Per continuar utilitzant Open Assistant, primer has d'acceptar les nostres Condicions del servei.", + "decline": "Rebutjar", + "title": "Condicions del servei d'Open Assistant" } diff --git a/website/public/locales/de/dashboard.json b/website/public/locales/de/dashboard.json index e2e841c4..b418eaaa 100644 --- a/website/public/locales/de/dashboard.json +++ b/website/public/locales/de/dashboard.json @@ -1,8 +1,8 @@ { - "grab_a_task": "Schnapp dir eine Aufgabe!", "create": "Erstellen", - "evaluate": "Auswerten", - "label": "Label", "dashboard": "Dashboard", - "go": "Los" + "evaluate": "Auswerten", + "go": "Los", + "grab_a_task": "Schnapp dir eine Aufgabe!", + "label": "Label" } diff --git a/website/public/locales/de/labelling.json b/website/public/locales/de/labelling.json index 98f2ef00..6569976c 100644 --- a/website/public/locales/de/labelling.json +++ b/website/public/locales/de/labelling.json @@ -19,5 +19,6 @@ "political_content": "Politisch", "political_content.explanation": "Enthält politische Meinungen.", "sexual_content": "Sexueller Inhalt", + "sexual_content.explanation": "Contains sexual content.", "spam.question": "Ist die Nachricht Spam?" } diff --git a/website/public/locales/de/message.json b/website/public/locales/de/message.json index 8cd9345d..6a74a1c3 100644 --- a/website/public/locales/de/message.json +++ b/website/public/locales/de/message.json @@ -1,13 +1,20 @@ { + "copy_message_id": "Copy message ID", "label_action": "Label", "label_title": "Label", "message": "Nachricht", + "message_deleted": "Message deleted", "open_new_tab_action": "In neuem Tab öffnen", "parent": "Vorgänger", "reactions": "Reaktionen", + "recent_messages": "Recent Messages", "report_action": "Melden", "report_placeholder": "Warum sollte diese Nachricht überprüft werden?", "report_title": "Meldung", "send_report": "Senden", - "submit_labels": "Absenden" + "stop_tree": "Stop tree", + "submit_labels": "Absenden", + "tree_stopped": "Tree stopped {{id}}", + "view_user": "View user", + "your_recent_messages": "Your Recent Messages" } diff --git a/website/public/locales/de/side_menu.json b/website/public/locales/de/side_menu.json new file mode 100644 index 00000000..c17b475a --- /dev/null +++ b/website/public/locales/de/side_menu.json @@ -0,0 +1,12 @@ +{ + "dashboard": "Dashboard", + "dashboard_home": "Dashboard Home", + "leaderboard": "Leaderboard", + "messages": "Nachrichten", + "messages_dashboard": "Messages Dashboard", + "status": "Status", + "status_dashboard": "Status Dashboard", + "user_leaderboard": "User Leaderboard", + "users": "Users", + "users_dashboard": "Users Dashboard" +} diff --git a/website/public/locales/de/tasks.json b/website/public/locales/de/tasks.json index 15474ed5..1cd3efca 100644 --- a/website/public/locales/de/tasks.json +++ b/website/public/locales/de/tasks.json @@ -1,11 +1,19 @@ { - "default": { - "unchanged_title": "Keine Änderungen", - "unchanged_message": "Möchten Sie wirklich fortfahren?" + "available_task_count": "{{count}} tasks available", + "classify_assistant_reply": { + "label": "Antwort des Assistenten klassifizieren", + "desc": "Labeln Sie die Antwort.", + "overview": "Lesen Sie das folgende Gespräch und beantworten Sie die Frage zur letzten Antwort in der Diskussion." }, - "random": { - "label": "Auf gut Glück", - "desc": "Helfen Sie uns, Open Assistant zu verbessern, indem Sie eine zufällige Aufgabe starten." + "classify_initial_prompt": { + "label": "Initialen Prompt klassifizieren", + "desc": "Labeln Sie den initialen Prompt.", + "overview": "Lesen Sie den folgenden Prompt und beantworten Sie dann die Frage dazu." + }, + "classify_prompter_reply": { + "label": "Prompter-Antwort klassifizieren", + "desc": "Labeln Sie die Antwort.", + "overview": "Lesen Sie das folgende Gespräch und beantworten Sie die Frage zur letzten Antwort in der Diskussion." }, "create_initial_prompt": { "label": "Initialer Prompt", @@ -14,25 +22,28 @@ "instruction": "Geben Sie den initialen Prompt ein", "response_placeholder": "Schreiben Sie hier Ihren Prompt..." }, - "reply_as_user": { - "label": "Als Benutzer antworten", - "desc": "Chatten Sie mit Open Assistant und helfen Sie, seine Antworten zu verbessern, während Sie damit interagieren.", - "overview": "Geben Sie angesichts des folgenden Gesprächs eine angemessene Antwort.", - "instruction": "Geben Sie die Antwort des Benutzers an", - "response_placeholder": "Schreiben Sie hier Ihre Antwort..." + "default": { + "unchanged_title": "Keine Änderungen", + "unchanged_message": "Möchten Sie wirklich fortfahren?" }, - "reply_as_assistant": { - "label": "Als Assistent antworten", - "desc": "Helfen Sie Open Assistant dabei, seine Antworten auf Gespräche mit anderen Benutzern zu verbessern.", - "overview": "Geben Sie angesichts des folgenden Gesprächs eine angemessene Antwort.", - "response_placeholder": "Schreiben Sie hier Ihre Antwort..." + "label_assistant_reply": { + "label": "Antwort des Assistenten labeln", + "desc": "Labeln Sie die Antwort.", + "overview": "Wählen Sie angesichts der folgenden Diskussion Labels für die letzte Nachticht." }, - "rank_user_replies": { - "label": "Benutzerantworten einstufen", - "desc": "Helfen Sie Open Assistant dabei, seine Antworten auf Gespräche mit anderen Benutzern zu verbessern.", - "overview": "Sortieren Sie die folgenden Benutzerantworten von der Besten zur Schlechtesten, wobei die Beste zuerst und die Schlechteste zuletzt kommt.", - "unchanged_title": "Reihenfolge unverändert", - "unchanged_message": "Sie haben die Reihenfolge nicht geändert. Möchten Sie wirklich fortfahren?" + "label_initial_prompt": { + "label": "Initiale Prompts labeln", + "desc": "Labeln Sie die initialen Prompts.", + "overview": "Wählen Sie Labels für den folgenden Prompt." + }, + "label_prompter_reply": { + "label": "Prompter-Antwort labeln", + "desc": "Labeln Sie die Antwort.", + "overview": "Wählen Sie angesichts der folgenden Diskussion Labels für die letzte Nachticht." + }, + "random": { + "label": "Auf gut Glück", + "desc": "Helfen Sie uns, Open Assistant zu verbessern, indem Sie eine zufällige Aufgabe starten." }, "rank_assistant_replies": { "label": "Assistentenantworten einstufen", @@ -48,34 +59,24 @@ "unchanged_title": "Reihenfolge unverändert", "unchanged_message": "Sie haben die Reihenfolge nicht geändert. Möchten Sie wirklich fortfahren?" }, - "label_initial_prompt": { - "label": "Initiale Prompts labeln", - "desc": "Labeln Sie die initialen Prompts.", - "overview": "Wählen Sie Labels für den folgenden Prompt." + "rank_user_replies": { + "label": "Benutzerantworten einstufen", + "desc": "Helfen Sie Open Assistant dabei, seine Antworten auf Gespräche mit anderen Benutzern zu verbessern.", + "overview": "Sortieren Sie die folgenden Benutzerantworten von der Besten zur Schlechtesten, wobei die Beste zuerst und die Schlechteste zuletzt kommt.", + "unchanged_title": "Reihenfolge unverändert", + "unchanged_message": "Sie haben die Reihenfolge nicht geändert. Möchten Sie wirklich fortfahren?" }, - "label_prompter_reply": { - "label": "Prompter-Antwort labeln", - "desc": "Labeln Sie die Antwort.", - "overview": "Wählen Sie angesichts der folgenden Diskussion Labels für die letzte Nachticht." + "reply_as_assistant": { + "label": "Als Assistent antworten", + "desc": "Helfen Sie Open Assistant dabei, seine Antworten auf Gespräche mit anderen Benutzern zu verbessern.", + "overview": "Geben Sie angesichts des folgenden Gesprächs eine angemessene Antwort.", + "response_placeholder": "Schreiben Sie hier Ihre Antwort..." }, - "label_assistant_reply": { - "label": "Antwort des Assistenten labeln", - "desc": "Labeln Sie die Antwort.", - "overview": "Wählen Sie angesichts der folgenden Diskussion Labels für die letzte Nachticht." - }, - "classify_initial_prompt": { - "label": "Initialen Prompt klassifizieren", - "desc": "Labeln Sie den initialen Prompt.", - "overview": "Lesen Sie den folgenden Prompt und beantworten Sie dann die Frage dazu." - }, - "classify_prompter_reply": { - "label": "Prompter-Antwort klassifizieren", - "desc": "Labeln Sie die Antwort.", - "overview": "Lesen Sie das folgende Gespräch und beantworten Sie die Frage zur letzten Antwort in der Diskussion." - }, - "classify_assistant_reply": { - "label": "Antwort des Assistenten klassifizieren", - "desc": "Labeln Sie die Antwort.", - "overview": "Lesen Sie das folgende Gespräch und beantworten Sie die Frage zur letzten Antwort in der Diskussion." + "reply_as_user": { + "label": "Als Benutzer antworten", + "desc": "Chatten Sie mit Open Assistant und helfen Sie, seine Antworten zu verbessern, während Sie damit interagieren.", + "overview": "Geben Sie angesichts des folgenden Gesprächs eine angemessene Antwort.", + "instruction": "Geben Sie die Antwort des Benutzers an", + "response_placeholder": "Schreiben Sie hier Ihre Antwort..." } } diff --git a/website/public/locales/de/tos.json b/website/public/locales/de/tos.json new file mode 100644 index 00000000..4d3d62b4 --- /dev/null +++ b/website/public/locales/de/tos.json @@ -0,0 +1,6 @@ +{ + "accept": "Accept", + "content": "To continue using Open Assistant, you have to accept our Terms of Service first.", + "decline": "Decline", + "title": "Terms of Service for Open Assistant" +} diff --git a/website/public/locales/es/common.json b/website/public/locales/es/common.json index 7d1a826a..eac24039 100644 --- a/website/public/locales/es/common.json +++ b/website/public/locales/es/common.json @@ -2,9 +2,9 @@ "about": "Acerca de", "account_settings": "Cuenta", "admin_dashboard": "Panel de administración", - "copied": "Copiado", "connect": "Connectar", "conversational": "IA conversacional para todos.", + "copied": "Copiado", "dark_mode": "Modo oscuro", "dashboard": "Panel principal", "delete": "Borrar", diff --git a/website/public/locales/es/dashboard.json b/website/public/locales/es/dashboard.json index 88466b00..3d81cae8 100644 --- a/website/public/locales/es/dashboard.json +++ b/website/public/locales/es/dashboard.json @@ -1,8 +1,8 @@ { - "grab_a_task": "¡Toma una tarea!", "create": "Crear", - "evaluate": "Evaluar", - "label": "Etiquetar", "dashboard": "Panel principal", - "go": "Ir" + "evaluate": "Evaluar", + "go": "Ir", + "grab_a_task": "¡Toma una tarea!", + "label": "Etiquetar" } diff --git a/website/public/locales/es/labelling.json b/website/public/locales/es/labelling.json index 03405bf9..522b827e 100644 --- a/website/public/locales/es/labelling.json +++ b/website/public/locales/es/labelling.json @@ -1,24 +1,24 @@ { - "label_highlighted_yes_no_instruction": "Contesta la(s) siguiente(s) pregunta(s) sobre el mensaje resaltado:", + "fails_task.question": "¿Es una mala respuesta, según la tarea pedida?", + "hate_speech": "Incitación al odio", + "hate_speech.explanation": "El contenido es ofensivo o amenazante y expresa un prejuicio contra una característica protegida. El prejuicio se refiere a las opiniones preconcebidas que no se basan en la razón. Las características protegidas incluyen género, etnia, religión, orientación sexual y características similares.", "label_highlighted_flag_instruction": "Selecciona cualquiera que sea adecuada para el mensaje resaltado:", "label_highlighted_likert_instruction": "Califica el mensaje resaltado:", - "label_message_yes_no_instruction": "Contesta la(s) siguiente(s) pregunta(s) sobre el mensaje:", + "label_highlighted_yes_no_instruction": "Contesta la(s) siguiente(s) pregunta(s) sobre el mensaje resaltado:", "label_message_flag_instruction": "Selecciona cualquiera que sea adecuada para el mensaje:", "label_message_likert_instruction": "Califica el mensaje:", - "spam.question": "¿Es el mensaje spam?", - "fails_task.question": "¿Es una mala respuesta, según la tarea pedida?", + "label_message_yes_no_instruction": "Contesta la(s) siguiente(s) pregunta(s) sobre el mensaje:", + "lang_mismatch": "Idioma incorrecto", + "lang_mismatch.explanation": "No está escrito en el idioma seleccionado actualmente.", + "moral_judgement": "Juicio moral", + "moral_judgement.explanation": "Expresa un juicio moral.", "not_appropriate": "No apropiada", "not_appropriate.explanation": "No apropiada para un asistente de cliente.", "pii": "Contiene información de identificación personal (PII)", "pii.explanation": "Contiene información personal como detalles de contacto personal, números de identificación o detalles bancarios", - "hate_speech": "Incitación al odio", - "hate_speech.explanation": "El contenido es ofensivo o amenazante y expresa un prejuicio contra una característica protegida. El prejuicio se refiere a las opiniones preconcebidas que no se basan en la razón. Las características protegidas incluyen género, etnia, religión, orientación sexual y características similares.", - "sexual_content": "Contenido sexual", - "sexual_content.explanation": "Contiene contenido sexual.", - "moral_judgement": "Juicio moral", - "moral_judgement.explanation": "Expresa un juicio moral.", "political_content": "Contenido político", "political_content.explanation": "Expresa una opinión política.", - "lang_mismatch": "Idioma incorrecto", - "lang_mismatch.explanation": "No está escrito en el idioma seleccionado actualmente." + "sexual_content": "Contenido sexual", + "sexual_content.explanation": "Contiene contenido sexual.", + "spam.question": "¿Es el mensaje spam?" } diff --git a/website/public/locales/es/leaderboard.json b/website/public/locales/es/leaderboard.json index f39abb2f..1972e900 100644 --- a/website/public/locales/es/leaderboard.json +++ b/website/public/locales/es/leaderboard.json @@ -1,18 +1,18 @@ { "daily": "Diario", + "label": "Etiquetas", "last_updated_at": "Última actualización: {{val, datetime}}", "leaderboard": "Tabla de clasificación", "monthly": "Mensual", + "next": "Siguiente", "overall": "Global", - "rank": "Posición", - "score": "Puntuación", - "user": "Usuario", - "weekly": "Semanal", - "prompt": "Indicaciones", - "reply": "Respuestas", - "label": "Etiquetas", - "view_all": "Ver todos", - "top_5_contributors_today": "5 mayores contribuidores hoy", "previous": "Anterior", - "next": "Siguiente" + "prompt": "Indicaciones", + "rank": "Posición", + "reply": "Respuestas", + "score": "Puntuación", + "top_5_contributors_today": "5 mayores contribuidores hoy", + "user": "Usuario", + "view_all": "Ver todos", + "weekly": "Semanal" } diff --git a/website/public/locales/es/message.json b/website/public/locales/es/message.json index 4d455034..081b81f4 100644 --- a/website/public/locales/es/message.json +++ b/website/public/locales/es/message.json @@ -2,8 +2,8 @@ "copy_message_id": "Copiar ID del mensaje", "label_action": "Etiquetar", "label_title": "Etiqueta", - "message_deleted": "Mensaje borrado", "message": "Mensaje", + "message_deleted": "Mensaje borrado", "open_new_tab_action": "Abrir en una pestaña nueva", "parent": "Padre", "reactions": "Reacciones", diff --git a/website/public/locales/es/side_menu.json b/website/public/locales/es/side_menu.json index 0a658520..080fb902 100644 --- a/website/public/locales/es/side_menu.json +++ b/website/public/locales/es/side_menu.json @@ -1,12 +1,12 @@ { "dashboard": "Panel principal", "dashboard_home": "Panel principal", + "leaderboard": "Clasificaciones", "messages": "Mensajes", "messages_dashboard": "Tablón de mensajes", - "leaderboard": "Clasificaciones", + "status": "Estado", + "status_dashboard": "Tablón de estado", "user_leaderboard": "Clasificación de usuarios", "users": "Usuarios", - "users_dashboard": "Tablón de usuarios", - "status": "Estado", - "status_dashboard": "Tablón de estado" + "users_dashboard": "Tablón de usuarios" } diff --git a/website/public/locales/es/tasks.json b/website/public/locales/es/tasks.json index 9b4f6d20..1c6a4cc5 100644 --- a/website/public/locales/es/tasks.json +++ b/website/public/locales/es/tasks.json @@ -1,11 +1,19 @@ { - "default": { - "unchanged_title": "Sin cambios", - "unchanged_message": "¿Estás seguro de que quieres continuar?" + "available_task_count": "{{count}} tareas disponibles", + "classify_assistant_reply": { + "label": "Clasificar respuesta del asistente", + "desc": "Proporciona etiquetas para una respuesta del asistente.", + "overview": "Lee la siguiente conversación y contesta a continuación la pregunta sobre la última respuesta en la discusión." }, - "random": { - "label": "Voy a tener suerte", - "desc": "Ayúdanos a mejorar Open Assistant empezando con una tarea aleatoria." + "classify_initial_prompt": { + "label": "Clasificar instrucciones iniciales", + "desc": "Proporciona etiquetas para unas instrucciones.", + "overview": "Lee la siguiente entrada y contesta a continuación la pregunta sobre ella." + }, + "classify_prompter_reply": { + "label": "Clasificar la respuesta del apuntador", + "desc": "Proporciona etiquetas para una entrada.", + "overview": "Lee la siguiente conversación y contesta a continuación la pregunta sobre la última respuesta en la discusión." }, "create_initial_prompt": { "label": "Crear instrucciones iniciales", @@ -14,25 +22,28 @@ "instruction": "Proporciona las instrucciones iniciales", "response_placeholder": "Escribe tus instrucciones aquí..." }, - "reply_as_user": { - "label": "Contestar como usuario", - "desc": "Hablar con Open Assistant e intentar mejorar sus respuestas mientras interaccionas con él.", - "overview": "Dada la conversación siguiente, proporciona una respuesta adecuada", - "instruction": "Proporciona la respuesta del usuario", - "response_placeholder": "Escribe tu respuesta aquí..." + "default": { + "unchanged_title": "Sin cambios", + "unchanged_message": "¿Estás seguro de que quieres continuar?" }, - "reply_as_assistant": { - "label": "Contestar como asistente", - "desc": "Ayuda a Open Assistant a mejorar sus respuestas a conversaciones con otros usuarios.", - "overview": "Dada la conversación siguiente, proporciona una respuesta adecuada", - "response_placeholder": "Escribe tu respuesta aquí..." + "label_assistant_reply": { + "label": "Etiquetar respuesta del asistente", + "desc": "Proporciona etiquetas para unas instrucciones.", + "overview": "Dada la discusión siguiente, proporciona etiquetas para la última entrada." }, - "rank_user_replies": { - "label": "Ordenar respuestas de usuarios", - "desc": "Ayuda a Open Assistant a mejorar sus respuestas a conversaciones con otros usuarios.", - "overview": "Dadas las siguientes respuestas de usuarios, ordénalas de mejor a peor, con la primera siendo la mejor y la última, la peor.", - "unchanged_title": "Orden sin cambiar", - "unchanged_message": "No has cambiado el orden de las respuestas. ¿Seguro que quieres continuar?" + "label_initial_prompt": { + "label": "Etiquetar instrucciones inciales", + "desc": "Proporciona etiquetas para unas instrucciones.", + "overview": "Proporciona etiquetas para las siguientes instrucciones" + }, + "label_prompter_reply": { + "label": "Etiquetar respuesta del apuntador", + "desc": "Proporciona etiquetas para unas instrucciones.", + "overview": "Dada la discusión siguiente, proporciona etiquetas para la última entrada." + }, + "random": { + "label": "Voy a tener suerte", + "desc": "Ayúdanos a mejorar Open Assistant empezando con una tarea aleatoria." }, "rank_assistant_replies": { "label": "Ordenar respuestas del asistente", @@ -48,35 +59,24 @@ "unchanged_title": "Orden sin cambiar", "unchanged_message": "No has cambiado el orden de las entradas. ¿Seguro que quieres continuar?" }, - "label_initial_prompt": { - "label": "Etiquetar instrucciones inciales", - "desc": "Proporciona etiquetas para unas instrucciones.", - "overview": "Proporciona etiquetas para las siguientes instrucciones" + "rank_user_replies": { + "label": "Ordenar respuestas de usuarios", + "desc": "Ayuda a Open Assistant a mejorar sus respuestas a conversaciones con otros usuarios.", + "overview": "Dadas las siguientes respuestas de usuarios, ordénalas de mejor a peor, con la primera siendo la mejor y la última, la peor.", + "unchanged_title": "Orden sin cambiar", + "unchanged_message": "No has cambiado el orden de las respuestas. ¿Seguro que quieres continuar?" }, - "label_prompter_reply": { - "label": "Etiquetar respuesta del apuntador", - "desc": "Proporciona etiquetas para unas instrucciones.", - "overview": "Dada la discusión siguiente, proporciona etiquetas para la última entrada." + "reply_as_assistant": { + "label": "Contestar como asistente", + "desc": "Ayuda a Open Assistant a mejorar sus respuestas a conversaciones con otros usuarios.", + "overview": "Dada la conversación siguiente, proporciona una respuesta adecuada", + "response_placeholder": "Escribe tu respuesta aquí..." }, - "label_assistant_reply": { - "label": "Etiquetar respuesta del asistente", - "desc": "Proporciona etiquetas para unas instrucciones.", - "overview": "Dada la discusión siguiente, proporciona etiquetas para la última entrada." - }, - "classify_initial_prompt": { - "label": "Clasificar instrucciones iniciales", - "desc": "Proporciona etiquetas para unas instrucciones.", - "overview": "Lee la siguiente entrada y contesta a continuación la pregunta sobre ella." - }, - "classify_prompter_reply": { - "label": "Clasificar la respuesta del apuntador", - "desc": "Proporciona etiquetas para una entrada.", - "overview": "Lee la siguiente conversación y contesta a continuación la pregunta sobre la última respuesta en la discusión." - }, - "classify_assistant_reply": { - "label": "Clasificar respuesta del asistente", - "desc": "Proporciona etiquetas para una respuesta del asistente.", - "overview": "Lee la siguiente conversación y contesta a continuación la pregunta sobre la última respuesta en la discusión." - }, - "available_task_count": "{{count}} tareas disponibles" + "reply_as_user": { + "label": "Contestar como usuario", + "desc": "Hablar con Open Assistant e intentar mejorar sus respuestas mientras interaccionas con él.", + "overview": "Dada la conversación siguiente, proporciona una respuesta adecuada", + "instruction": "Proporciona la respuesta del usuario", + "response_placeholder": "Escribe tu respuesta aquí..." + } } diff --git a/website/public/locales/es/tos.json b/website/public/locales/es/tos.json new file mode 100644 index 00000000..4d3d62b4 --- /dev/null +++ b/website/public/locales/es/tos.json @@ -0,0 +1,6 @@ +{ + "accept": "Accept", + "content": "To continue using Open Assistant, you have to accept our Terms of Service first.", + "decline": "Decline", + "title": "Terms of Service for Open Assistant" +} diff --git a/website/public/locales/fr/common.json b/website/public/locales/fr/common.json index 6bfc17f7..66c882c9 100644 --- a/website/public/locales/fr/common.json +++ b/website/public/locales/fr/common.json @@ -4,12 +4,15 @@ "admin_dashboard": "Tableau de bord d'administration", "connect": "Se connecter", "conversational": "IA conversationnelle pour tout le monde.", + "copied": "Copied", + "dark_mode": "Mode sombre", "dashboard": "Tableau de bord", "delete": "Supprimer", "discord": "Discord", "docs": "Docs", "github": "GitHub", "legal": "Légal", + "light_mode": "Mode clair", "loading": "Chargement en cours...", "more_information": "Plus d'informations", "no": "Non", @@ -17,9 +20,8 @@ "report_a_bug": "Signaler un bug", "sign_in": "Se connecter", "sign_out": "Se déconnecter", + "success": "Success", "terms_of_service": "Conditions d'utilisation", "title": "Open Assistant", - "yes": "Oui", - "dark_mode": "Mode sombre", - "light_mode": "Mode clair" + "yes": "Oui" } diff --git a/website/public/locales/fr/dashboard.json b/website/public/locales/fr/dashboard.json index 9ca767b8..e7d94e87 100644 --- a/website/public/locales/fr/dashboard.json +++ b/website/public/locales/fr/dashboard.json @@ -1,8 +1,8 @@ { - "grab_a_task": "Attrape une tâche!", "create": "Créer", - "evaluate": "Évaluer", - "label": "Étiquette", "dashboard": "Tableau de bord", - "go": "Aller" + "evaluate": "Évaluer", + "go": "Aller", + "grab_a_task": "Attrape une tâche!", + "label": "Étiquette" } diff --git a/website/public/locales/fr/labelling.json b/website/public/locales/fr/labelling.json index 387b5353..a4dca997 100644 --- a/website/public/locales/fr/labelling.json +++ b/website/public/locales/fr/labelling.json @@ -1,24 +1,24 @@ { - "label_highlighted_yes_no_instruction": "Répondez à la question suivante (s) concernant le message surligné:", + "fails_task.question": "Est-ce une mauvaise réponse en réponse à la tâche?", + "hate_speech": "Discours de haine", + "hate_speech.explanation": "Le contenu est abusif ou menaçant et exprime un préjugé contre une caractéristique protégée. Le préjugé se réfère aux opinions préconçues non fondées sur la raison. Les caractéristiques protégées incluent le genre, l'ethnicité, la religion, l'orientation sexuelle et des caractéristiques similaires.", "label_highlighted_flag_instruction": "Sélectionnez tout ce qui s'applique au message surligné:", "label_highlighted_likert_instruction": "Notez le message surligné:", - "label_message_yes_no_instruction": "Répondez à la question suivante (s) concernant le message:", + "label_highlighted_yes_no_instruction": "Répondez à la question suivante (s) concernant le message surligné:", "label_message_flag_instruction": "Sélectionnez tout ce qui s'applique au message:", "label_message_likert_instruction": "Notez le message:", - "spam.question": "Est-ce que le message est un spam?", - "fails_task.question": "Est-ce une mauvaise réponse en réponse à la tâche?", + "label_message_yes_no_instruction": "Répondez à la question suivante (s) concernant le message:", + "lang_mismatch": "Langue incorrecte", + "lang_mismatch.explanation": "N'est pas écrit dans la langue actuellement sélectionnée.", + "moral_judgement": "Juge la morale", + "moral_judgement.explanation": "Exprime un jugement moral.", "not_appropriate": "Inapproprié", "not_appropriate.explanation": "Inapproprié pour un assistant client.", "pii": "Contient des RII", "pii.explanation": "Contient des informations personnellement identifiables. Exemples : coordonnées personnelles, numéros de permis de conduire et d'identité et coordonnées bancaires.", - "hate_speech": "Discours de haine", - "hate_speech.explanation": "Le contenu est abusif ou menaçant et exprime un préjugé contre une caractéristique protégée. Le préjugé se réfère aux opinions préconçues non fondées sur la raison. Les caractéristiques protégées incluent le genre, l'ethnicité, la religion, l'orientation sexuelle et des caractéristiques similaires.", - "sexual_content": "Contenu sexuel", - "sexual_content.explanation": "Contient du contenu sexuel.", - "moral_judgement": "Juge la morale", - "moral_judgement.explanation": "Exprime un jugement moral.", "political_content": "Politique", "political_content.explanation": "Exprime des opinions politiques.", - "lang_mismatch": "Langue incorrecte", - "lang_mismatch.explanation": "N'est pas écrit dans la langue actuellement sélectionnée." + "sexual_content": "Contenu sexuel", + "sexual_content.explanation": "Contient du contenu sexuel.", + "spam.question": "Est-ce que le message est un spam?" } diff --git a/website/public/locales/fr/leaderboard.json b/website/public/locales/fr/leaderboard.json index 9f2c443d..21555e9d 100644 --- a/website/public/locales/fr/leaderboard.json +++ b/website/public/locales/fr/leaderboard.json @@ -1,18 +1,18 @@ { "daily": "Journalier", + "label": "Étiquettes", "last_updated_at": "Dernière mise à jour à: {{val, datetime}}", "leaderboard": "Classement", "monthly": "Mensuel", + "next": "Suivant", "overall": "Global", - "rank": "Rang", - "score": "Score", - "user": "Utilisateur", - "weekly": "Hebdomadaire", - "prompt": "Invitations", - "reply": "Réponses", - "label": "Étiquettes", - "view_all": "Voir tout", - "top_5_contributors_today": "Les 5 meilleurs contributeurs aujourd'hui", "previous": "Précédent", - "next": "Suivant" + "prompt": "Invitations", + "rank": "Rang", + "reply": "Réponses", + "score": "Score", + "top_5_contributors_today": "Les 5 meilleurs contributeurs aujourd'hui", + "user": "Utilisateur", + "view_all": "Voir tout", + "weekly": "Hebdomadaire" } diff --git a/website/public/locales/fr/message.json b/website/public/locales/fr/message.json index 1f31faa6..a93092da 100644 --- a/website/public/locales/fr/message.json +++ b/website/public/locales/fr/message.json @@ -1,16 +1,20 @@ { + "copy_message_id": "Copy message ID", "label_action": "Étiqueter", "label_title": "Étiquette", "message": "Message", + "message_deleted": "Message deleted", "open_new_tab_action": "Ouvrir dans un nouvel onglet", "parent": "Parent", "reactions": "Réactions", + "recent_messages": "Messages récents", "report_action": "Signaler", "report_placeholder": "Pourquoi ce message devrait-il être examiné?", "report_title": "Signaler", "send_report": "Envoyer", + "stop_tree": "Stop tree", "submit_labels": "Soumettre", + "tree_stopped": "Tree stopped {{id}}", "view_user": "Voir l'utilisateur", - "recent_messages": "Messages récents", "your_recent_messages": "Vos messages récents" } diff --git a/website/public/locales/fr/side_menu.json b/website/public/locales/fr/side_menu.json index a3c5065b..87f62a5e 100644 --- a/website/public/locales/fr/side_menu.json +++ b/website/public/locales/fr/side_menu.json @@ -1,12 +1,12 @@ { "dashboard": "Tableau de bord", "dashboard_home": "Accueil du tableau de bord", + "leaderboard": "Classement", "messages": "Messages", "messages_dashboard": "Tableau de bord des messages", - "leaderboard": "Classement", + "status": "Statut", + "status_dashboard": "Tableau de bord de statut", "user_leaderboard": "Classement des utilisateurs", "users": "Utilisateurs", - "users_dashboard": "Tableau de bord des utilisateurs", - "status": "Statut", - "status_dashboard": "Tableau de bord de statut" + "users_dashboard": "Tableau de bord des utilisateurs" } diff --git a/website/public/locales/fr/tasks.json b/website/public/locales/fr/tasks.json index c5cf0064..916a4ab0 100644 --- a/website/public/locales/fr/tasks.json +++ b/website/public/locales/fr/tasks.json @@ -1,11 +1,19 @@ { - "default": { - "unchanged_title": "Aucun changement", - "unchanged_message": "Êtes-vous sûr de vouloir continuer?" + "available_task_count": "{{count}} tâches disponibles", + "classify_assistant_reply": { + "label": "Classer la réponse de l'assistant", + "desc": "Fournir des étiquettes pour une invitation.", + "overview": "Lisez la conversation suivante et répondez à la question sur la dernière réponse de la discussion." }, - "random": { - "label": "Je me sens chanceux", - "desc": "Aidez-nous à améliorer Open Assistant en démarrant une tâche aléatoire." + "classify_initial_prompt": { + "label": "Classer l'invitation initiale", + "desc": "Fournir des étiquettes pour une invitation.", + "overview": "Lisez l'invitation suivante et répondez à la question à ce sujet." + }, + "classify_prompter_reply": { + "label": "Classer la réponse du demandeur", + "desc": "Fournir des étiquettes pour une invitation.", + "overview": "Lisez la conversation suivante et répondez à la question sur la dernière réponse de la discussion." }, "create_initial_prompt": { "label": "Créer des prompts initiaux", @@ -14,25 +22,28 @@ "instruction": "Fournir les prompts initiaux", "response_placeholder": "Écrivez votre prompt ici..." }, - "reply_as_user": { - "label": "Répondre en tant qu'utilisateur", - "desc": "Discutez avec Open Assistant et aidez-le à améliorer ses réponses en interagissant avec lui.", - "overview": "Compte tenu de la conversation suivante, fournir une réponse adéquate", - "instruction": "Fournir la réponse de l'utilisateur", - "response_placeholder": "Ecrivez votre réponse ici..." + "default": { + "unchanged_title": "Aucun changement", + "unchanged_message": "Êtes-vous sûr de vouloir continuer?" }, - "reply_as_assistant": { - "label": "Répondre en tant qu'assistant", - "desc": "Aidez Open Assistant à améliorer ses réponses aux conversations avec d'autres utilisateurs.", - "overview": "Compte tenu de la conversation suivante, fournir une réponse adéquate", - "response_placeholder": "Ecrivez votre réponse ici..." + "label_assistant_reply": { + "label": "Etiqueter la réponse de l'assistant", + "desc": "Fournir des étiquettes pour une invitation.", + "overview": "En fonction de la discussion suivante, fournir des étiquettes pour la dernière invitation." }, - "rank_user_replies": { - "label": "Classer les réponses d'utilisateur", - "desc": "Aidez Open Assistant à améliorer ses réponses aux conversations avec d'autres utilisateurs.", - "overview": "Compte tenu des réponses d'utilisateur suivantes, classez-les du meilleur au pire, le meilleur étant en premier, le pire en dernier.", - "unchanged_title": "Ordre inchangé", - "unchanged_message": "Vous n'avez pas modifié l'ordre des prompts. Etes-vous sûr de vouloir continuer?" + "label_initial_prompt": { + "label": "Etiqueter l'invitation initiale", + "desc": "Fournir des étiquettes pour une invitation.", + "overview": "Fournir des étiquettes pour l'invitation suivante" + }, + "label_prompter_reply": { + "label": "Etiqueter la réponse du demandeur", + "desc": "Fournir des étiquettes pour une invitation.", + "overview": "En fonction de la discussion suivante, fournir des étiquettes pour la dernière invitation." + }, + "random": { + "label": "Je me sens chanceux", + "desc": "Aidez-nous à améliorer Open Assistant en démarrant une tâche aléatoire." }, "rank_assistant_replies": { "label": "Classer les réponses de l'assistant", @@ -48,35 +59,24 @@ "unchanged_title": "Ordre inchangé", "unchanged_message": "Vous n'avez pas modifié l'ordre des invitations. Êtes-vous sûr de vouloir continuer?" }, - "label_initial_prompt": { - "label": "Etiqueter l'invitation initiale", - "desc": "Fournir des étiquettes pour une invitation.", - "overview": "Fournir des étiquettes pour l'invitation suivante" + "rank_user_replies": { + "label": "Classer les réponses d'utilisateur", + "desc": "Aidez Open Assistant à améliorer ses réponses aux conversations avec d'autres utilisateurs.", + "overview": "Compte tenu des réponses d'utilisateur suivantes, classez-les du meilleur au pire, le meilleur étant en premier, le pire en dernier.", + "unchanged_title": "Ordre inchangé", + "unchanged_message": "Vous n'avez pas modifié l'ordre des prompts. Etes-vous sûr de vouloir continuer?" }, - "label_prompter_reply": { - "label": "Etiqueter la réponse du demandeur", - "desc": "Fournir des étiquettes pour une invitation.", - "overview": "En fonction de la discussion suivante, fournir des étiquettes pour la dernière invitation." + "reply_as_assistant": { + "label": "Répondre en tant qu'assistant", + "desc": "Aidez Open Assistant à améliorer ses réponses aux conversations avec d'autres utilisateurs.", + "overview": "Compte tenu de la conversation suivante, fournir une réponse adéquate", + "response_placeholder": "Ecrivez votre réponse ici..." }, - "label_assistant_reply": { - "label": "Etiqueter la réponse de l'assistant", - "desc": "Fournir des étiquettes pour une invitation.", - "overview": "En fonction de la discussion suivante, fournir des étiquettes pour la dernière invitation." - }, - "classify_initial_prompt": { - "label": "Classer l'invitation initiale", - "desc": "Fournir des étiquettes pour une invitation.", - "overview": "Lisez l'invitation suivante et répondez à la question à ce sujet." - }, - "classify_prompter_reply": { - "label": "Classer la réponse du demandeur", - "desc": "Fournir des étiquettes pour une invitation.", - "overview": "Lisez la conversation suivante et répondez à la question sur la dernière réponse de la discussion." - }, - "classify_assistant_reply": { - "label": "Classer la réponse de l'assistant", - "desc": "Fournir des étiquettes pour une invitation.", - "overview": "Lisez la conversation suivante et répondez à la question sur la dernière réponse de la discussion." - }, - "available_task_count": "{{count}} tâches disponibles" + "reply_as_user": { + "label": "Répondre en tant qu'utilisateur", + "desc": "Discutez avec Open Assistant et aidez-le à améliorer ses réponses en interagissant avec lui.", + "overview": "Compte tenu de la conversation suivante, fournir une réponse adéquate", + "instruction": "Fournir la réponse de l'utilisateur", + "response_placeholder": "Ecrivez votre réponse ici..." + } } diff --git a/website/public/locales/fr/tos.json b/website/public/locales/fr/tos.json index ee50480e..d15cdc9e 100644 --- a/website/public/locales/fr/tos.json +++ b/website/public/locales/fr/tos.json @@ -1,6 +1,6 @@ { - "title": "Conditions d'utilisation d'Open Assistant", - "content": "Pour continuer à utiliser Open Assistant, vous devez d'abord accepter nos conditions d'utilisation.", "accept": "Accepter", - "decline": "Refuser" + "content": "Pour continuer à utiliser Open Assistant, vous devez d'abord accepter nos conditions d'utilisation.", + "decline": "Refuser", + "title": "Conditions d'utilisation d'Open Assistant" } diff --git a/website/public/locales/hu/common.json b/website/public/locales/hu/common.json index fbbb475b..f0cb71bb 100644 --- a/website/public/locales/hu/common.json +++ b/website/public/locales/hu/common.json @@ -4,11 +4,15 @@ "admin_dashboard": "Admin Felület", "connect": "Kapcsolat", "conversational": "Társalgási MI Mindenkinek.", + "copied": "Copied", + "dark_mode": "Dark Mode", "dashboard": "Irányítópult", + "delete": "Delete", "discord": "Discord", "docs": "Leírás", "github": "GitHub", "legal": "Jogi", + "light_mode": "Light Mode", "loading": "Betöltés...", "more_information": "További információ", "no": "Nem", @@ -16,6 +20,7 @@ "report_a_bug": "Hibabejelentés", "sign_in": "Bejelentkezés", "sign_out": "Kijelentkezés", + "success": "Success", "terms_of_service": "Felhasználási feltételek", "title": "Open Assistant", "yes": "Igen" diff --git a/website/public/locales/hu/dashboard.json b/website/public/locales/hu/dashboard.json index eae4dc03..c24ef25d 100644 --- a/website/public/locales/hu/dashboard.json +++ b/website/public/locales/hu/dashboard.json @@ -1,8 +1,8 @@ { - "grab_a_task": "Válassz egy feladatot!", "create": "Létrehozás", - "evaluate": "Értékelés", - "label": "Címkézés", "dashboard": "Irányítópult", - "go": "Indítás" + "evaluate": "Értékelés", + "go": "Indítás", + "grab_a_task": "Válassz egy feladatot!", + "label": "Címkézés" } diff --git a/website/public/locales/hu/labelling.json b/website/public/locales/hu/labelling.json index b7c05fbb..a519a028 100644 --- a/website/public/locales/hu/labelling.json +++ b/website/public/locales/hu/labelling.json @@ -1,24 +1,24 @@ { - "label_highlighted_yes_no_instruction": "Válaszold meg a megjelölt üzenetre vonatkozó kérdés(eke)t:", + "fails_task.question": "Baj van ezzel az üzenettel, amiért nem a kérdésre válaszol?", + "hate_speech": "Gyűlölet Beszéd", + "hate_speech.explanation": "Az üzenet célja valamely társadalmi csoport megalázása, megfélemlítése vagy a csoport tagjai elleni erőszak vagy előítéletes fellépés kiváltása. A gyűlöletbeszéd legtöbbször a nemi, faji, etnikai, nemzeti, vallási, vagy szexualitás szerinti csoportok ellen irányul.", "label_highlighted_flag_instruction": "Jelöld be, melyek vonatkoznak a megjelölt üzenetre:", "label_highlighted_likert_instruction": "Értékeld a megjelölt üzenetet:", - "label_message_yes_no_instruction": "Válaszold meg az üzenetre vonatkozó kérdés(eke)t:", + "label_highlighted_yes_no_instruction": "Válaszold meg a megjelölt üzenetre vonatkozó kérdés(eke)t:", "label_message_flag_instruction": "Jelöld be, melyek vonatkoznak erre az üzenetre:", "label_message_likert_instruction": "Értékeld ezt az üzenetet:", - "spam.question": "Ez az üzenet SPAM?", - "fails_task.question": "Baj van ezzel az üzenettel, amiért nem a kérdésre válaszol?", + "label_message_yes_no_instruction": "Válaszold meg az üzenetre vonatkozó kérdés(eke)t:", + "lang_mismatch": "Idegen Nyelv", + "lang_mismatch.explanation": "Nem a kiválasztott nyelven íródott.", + "moral_judgement": "Morális Bírálat", + "moral_judgement.explanation": "Morális értékrendbeli bírálatot tartalmaz.", "not_appropriate": "Nem Helyénvaló", "not_appropriate.explanation": "Nem ügyfél-asszisztenshez méltó válasz.", "pii": "Személyes Adat", "pii.explanation": "Érzékeny, személyes adatot tartalmaz, például: valakinek az elérhetősége, igazolványszáma, bankkártya adatai.", - "hate_speech": "Gyűlölet Beszéd", - "hate_speech.explanation": "Az üzenet célja valamely társadalmi csoport megalázása, megfélemlítése vagy a csoport tagjai elleni erőszak vagy előítéletes fellépés kiváltása. A gyűlöletbeszéd legtöbbször a nemi, faji, etnikai, nemzeti, vallási, vagy szexualitás szerinti csoportok ellen irányul.", - "sexual_content": "Szexuális Tartalom", - "sexual_content.explanation": "Szexuális töltetű üzenet.", - "moral_judgement": "Morális Bírálat", - "moral_judgement.explanation": "Morális értékrendbeli bírálatot tartalmaz.", "political_content": "Politikai Töltetű", "political_content.explanation": "Politikai nézeteket közöl vagy propagandát tartalmaz.", - "lang_mismatch": "Idegen Nyelv", - "lang_mismatch.explanation": "Nem a kiválasztott nyelven íródott." + "sexual_content": "Szexuális Tartalom", + "sexual_content.explanation": "Szexuális töltetű üzenet.", + "spam.question": "Ez az üzenet SPAM?" } diff --git a/website/public/locales/hu/leaderboard.json b/website/public/locales/hu/leaderboard.json index 59d5217b..c1d38742 100644 --- a/website/public/locales/hu/leaderboard.json +++ b/website/public/locales/hu/leaderboard.json @@ -1,14 +1,18 @@ { "daily": "Napi", + "label": "Címkék", "last_updated_at": "Frissítve: {{val, datetime}}", "leaderboard": "Ranglétra", "monthly": "Havi", + "next": "Next", "overall": "Összesített", - "rank": "Helyezés", - "score": "Pont", - "user": "Felhasználó", - "weekly": "Heti", + "previous": "Previous", "prompt": "Promptok", + "rank": "Helyezés", "reply": "Válaszok", - "label": "Címkék" + "score": "Pont", + "top_5_contributors_today": "Top 5 Contributors Today", + "user": "Felhasználó", + "view_all": "View all", + "weekly": "Heti" } diff --git a/website/public/locales/hu/message.json b/website/public/locales/hu/message.json index c27b8fda..ad3c9a0e 100644 --- a/website/public/locales/hu/message.json +++ b/website/public/locales/hu/message.json @@ -1,14 +1,20 @@ { + "copy_message_id": "Copy message ID", "label_action": "Címkézés", "label_title": "Címke", "message": "Üzenet", + "message_deleted": "Message deleted", "open_new_tab_action": "Megnyitás új lapon", "parent": "Szülő", "reactions": "Reakciók", + "recent_messages": "Recent Messages", "report_action": "Jelentés", "report_placeholder": "Mi a probléma ezzel az üzenettel?", "report_title": "Bejelentés", "send_report": "Beküldés", + "stop_tree": "Stop tree", "submit_labels": "Küldés", - "view_user": "Felhasználó megtekintése" + "tree_stopped": "Tree stopped {{id}}", + "view_user": "Felhasználó megtekintése", + "your_recent_messages": "Your Recent Messages" } diff --git a/website/public/locales/hu/side_menu.json b/website/public/locales/hu/side_menu.json new file mode 100644 index 00000000..293112f4 --- /dev/null +++ b/website/public/locales/hu/side_menu.json @@ -0,0 +1,12 @@ +{ + "dashboard": "Dashboard", + "dashboard_home": "Dashboard Home", + "leaderboard": "Leaderboard", + "messages": "Messages", + "messages_dashboard": "Messages Dashboard", + "status": "Status", + "status_dashboard": "Status Dashboard", + "user_leaderboard": "User Leaderboard", + "users": "Users", + "users_dashboard": "Users Dashboard" +} diff --git a/website/public/locales/hu/tasks.json b/website/public/locales/hu/tasks.json index da9cf254..00d10faf 100644 --- a/website/public/locales/hu/tasks.json +++ b/website/public/locales/hu/tasks.json @@ -1,11 +1,19 @@ { - "default": { - "unchanged_title": "Nem történt változtatás", - "unchanged_message": "Biztosan tovább szeretnél lépni?" + "available_task_count": "{{count}} feladat érhető el", + "classify_assistant_reply": { + "label": "Osztályozd az Asszisztens Válaszait", + "desc": "Találj ki címkéket a megadott Promptra.", + "overview": "Olvasd végig a beszélgetést és válaszolj a legutolsó üzenetre vonatkozó kérdésre." }, - "random": { - "label": "Jó napom van", - "desc": "Segítsd az Open Assistant fejlesztését egy véletlenül kiválaszott feladattal." + "classify_initial_prompt": { + "label": "Osztályozd a Kezdeti Promptokat", + "desc": "Találj ki címkéket a megadott Promptra.", + "overview": "Olvasd el a Promptot és válaszold meg a vele kapcsolatos kérdést." + }, + "classify_prompter_reply": { + "label": "Osztályozd a Promptra adott Válaszokat", + "desc": "Találj ki címkéket a megadott Promptra.", + "overview": "Olvasd végig a beszélgetést és válaszolj a legutolsó üzenetre vonatkozó kérdésre." }, "create_initial_prompt": { "label": "Hozz Létre Kezdeti Promptokat", @@ -14,25 +22,28 @@ "instruction": "Találj ki Kezdeti Promptokat", "response_placeholder": "Ide írd a promptot..." }, - "reply_as_user": { - "label": "Válaszolj a Felhasználó Helyett", - "desc": "Csinálj úgy, mintha chatelnél az Asszisztenssel, hogy fejlődhessen.", - "overview": "Írj egy ideillő üzenetet az eddigi beszélgetésre, mint Felhasználó", - "instruction": "Találj ki Felhasználói Válaszokat", - "response_placeholder": "Ide írd a választ..." + "default": { + "unchanged_title": "Nem történt változtatás", + "unchanged_message": "Biztosan tovább szeretnél lépni?" }, - "reply_as_assistant": { - "label": "Válaszolj az Asszisztens Helyett", - "desc": "Mjutasd meg az Asszisztensnek, hogy milyen válaszokat küldjön a felhasználói kérdésekre.", - "overview": "Írj egy ideillő választ az eddigi beszélgetésre, mintha te lennél az Asszisztens", - "response_placeholder": "Ide írd a választ..." + "label_assistant_reply": { + "label": "Címkézd fel az Asszisztens Válaszait", + "desc": "Találj ki címkéket a megadott Promptra.", + "overview": "Az alábbi beszélgetés alapján találj ki Címkéket a záró Promptra." }, - "rank_user_replies": { - "label": "Rangsorold a Felhasználó Válaszait", - "desc": "Értékeld a Felhasználói Válaszok minőségét.", - "overview": "Rangsorold az alábbi Felhasználói Válaszokat: a legjobbat tedd legfelülre, a legrosszabbat legalulra.", - "unchanged_title": "Sorrend nem változott", - "unchanged_message": "Nem változtattál a promptok sorrendjén. Így is tovább akarsz lépni?" + "label_initial_prompt": { + "label": "Címkézd fel a Kezdeti Promptokat", + "desc": "Találj ki címkéket a megadott Promptra.", + "overview": "Találj ki Címkéket az alábbi Prompthoz." + }, + "label_prompter_reply": { + "label": "Címkézd fel a Promptokra adott Válaszokat", + "desc": "Találj ki címkéket a megadott Promptra.", + "overview": "Az alábbi beszélgetés alapján találj ki Címkéket a záró Promptra." + }, + "random": { + "label": "Jó napom van", + "desc": "Segítsd az Open Assistant fejlesztését egy véletlenül kiválaszott feladattal." }, "rank_assistant_replies": { "label": "Rangsorold az Asszisztens Válaszait", @@ -48,35 +59,24 @@ "unchanged_title": "Sorrend nem változott", "unchanged_message": "Nem változtattál a promptok sorrendjén. Így is tovább akarsz lépni?" }, - "label_initial_prompt": { - "label": "Címkézd fel a Kezdeti Promptokat", - "desc": "Találj ki címkéket a megadott Promptra.", - "overview": "Találj ki Címkéket az alábbi Prompthoz." + "rank_user_replies": { + "label": "Rangsorold a Felhasználó Válaszait", + "desc": "Értékeld a Felhasználói Válaszok minőségét.", + "overview": "Rangsorold az alábbi Felhasználói Válaszokat: a legjobbat tedd legfelülre, a legrosszabbat legalulra.", + "unchanged_title": "Sorrend nem változott", + "unchanged_message": "Nem változtattál a promptok sorrendjén. Így is tovább akarsz lépni?" }, - "label_prompter_reply": { - "label": "Címkézd fel a Promptokra adott Válaszokat", - "desc": "Találj ki címkéket a megadott Promptra.", - "overview": "Az alábbi beszélgetés alapján találj ki Címkéket a záró Promptra." + "reply_as_assistant": { + "label": "Válaszolj az Asszisztens Helyett", + "desc": "Mjutasd meg az Asszisztensnek, hogy milyen válaszokat küldjön a felhasználói kérdésekre.", + "overview": "Írj egy ideillő választ az eddigi beszélgetésre, mintha te lennél az Asszisztens", + "response_placeholder": "Ide írd a választ..." }, - "label_assistant_reply": { - "label": "Címkézd fel az Asszisztens Válaszait", - "desc": "Találj ki címkéket a megadott Promptra.", - "overview": "Az alábbi beszélgetés alapján találj ki Címkéket a záró Promptra." - }, - "classify_initial_prompt": { - "label": "Osztályozd a Kezdeti Promptokat", - "desc": "Találj ki címkéket a megadott Promptra.", - "overview": "Olvasd el a Promptot és válaszold meg a vele kapcsolatos kérdést." - }, - "classify_prompter_reply": { - "label": "Osztályozd a Promptra adott Válaszokat", - "desc": "Találj ki címkéket a megadott Promptra.", - "overview": "Olvasd végig a beszélgetést és válaszolj a legutolsó üzenetre vonatkozó kérdésre." - }, - "classify_assistant_reply": { - "label": "Osztályozd az Asszisztens Válaszait", - "desc": "Találj ki címkéket a megadott Promptra.", - "overview": "Olvasd végig a beszélgetést és válaszolj a legutolsó üzenetre vonatkozó kérdésre." - }, - "available_task_count": "{{count}} feladat érhető el" + "reply_as_user": { + "label": "Válaszolj a Felhasználó Helyett", + "desc": "Csinálj úgy, mintha chatelnél az Asszisztenssel, hogy fejlődhessen.", + "overview": "Írj egy ideillő üzenetet az eddigi beszélgetésre, mint Felhasználó", + "instruction": "Találj ki Felhasználói Válaszokat", + "response_placeholder": "Ide írd a választ..." + } } diff --git a/website/public/locales/hu/tos.json b/website/public/locales/hu/tos.json new file mode 100644 index 00000000..4d3d62b4 --- /dev/null +++ b/website/public/locales/hu/tos.json @@ -0,0 +1,6 @@ +{ + "accept": "Accept", + "content": "To continue using Open Assistant, you have to accept our Terms of Service first.", + "decline": "Decline", + "title": "Terms of Service for Open Assistant" +} diff --git a/website/public/locales/it/dashboard.json b/website/public/locales/it/dashboard.json index e730e13c..3f888567 100644 --- a/website/public/locales/it/dashboard.json +++ b/website/public/locales/it/dashboard.json @@ -1,8 +1,8 @@ { - "grab_a_task": "Scegli un compito!", "create": "Crea", - "evaluate": "Valuta", - "label": "Etichetta", "dashboard": "Pannello di controllo", - "go": "Vai" + "evaluate": "Valuta", + "go": "Vai", + "grab_a_task": "Scegli un compito!", + "label": "Etichetta" } diff --git a/website/public/locales/it/message.json b/website/public/locales/it/message.json index a98810c7..1040f5ff 100644 --- a/website/public/locales/it/message.json +++ b/website/public/locales/it/message.json @@ -2,8 +2,8 @@ "copy_message_id": "Copia l'ID del messaggio", "label_action": "Etichetta", "label_title": "Etichetta", - "message_deleted": "Messaggio eliminato", "message": "Messaggio", + "message_deleted": "Messaggio eliminato", "open_new_tab_action": "Apri in una nuova finestra", "parent": "Genitore", "reactions": "Reazioni", diff --git a/website/public/locales/it/side_menu.json b/website/public/locales/it/side_menu.json index 79a7f83f..9bb8b7fb 100644 --- a/website/public/locales/it/side_menu.json +++ b/website/public/locales/it/side_menu.json @@ -1,12 +1,12 @@ { "dashboard": "Pannello di controllo", "dashboard_home": "Schermata iniziale", + "leaderboard": "Classifica", "messages": "Messaggi", "messages_dashboard": "Pannello di controllo dei messaggi", - "leaderboard": "Classifica", + "status": "Stato", + "status_dashboard": "Pannello di controllo dello stato", "user_leaderboard": "Classifica dell'utente", "users": "Utenti", - "users_dashboard": "Pannello di controllo degli utenti", - "status": "Stato", - "status_dashboard": "Pannello di controllo dello stato" + "users_dashboard": "Pannello di controllo degli utenti" } diff --git a/website/public/locales/it/tasks.json b/website/public/locales/it/tasks.json index e37d159b..e293189c 100644 --- a/website/public/locales/it/tasks.json +++ b/website/public/locales/it/tasks.json @@ -1,11 +1,19 @@ { - "default": { - "unchanged_title": "Non sono presenti modifiche", - "unchanged_message": "Sei sicuro di voler continuare?" + "available_task_count": "{{count}} compiti disponibili", + "classify_assistant_reply": { + "label": "Classifica la risposta dell'assistente", + "desc": "Fornisci etichette per una richiesta.", + "overview": "Leggi la seguente conversazione e rispondi alla domanda riguardante l'ultima risposta della discussione." }, - "random": { - "label": "Mi sento fortunato", - "desc": "Aiutaci a migliorare Open Assistant iniziando un compito a caso." + "classify_initial_prompt": { + "label": "Classifica la richiesta iniziale", + "desc": "Fornisci etichette per una richiesta.", + "overview": "Leggi la seguente richiesta e rispondi alla domanda che la riguarda." + }, + "classify_prompter_reply": { + "label": "Classifica la risposta dell'utente", + "desc": "Fornisci etichette per una richiesta.", + "overview": "Leggi la seguente conversazione e rispondi alla domanda riguardante l'ultima risposta della discussione." }, "create_initial_prompt": { "label": "Crea richiesta iniziale", @@ -14,25 +22,28 @@ "instruction": "Fornisci una richiesta iniziale", "response_placeholder": "Scrivi qui la tua richiesta..." }, - "reply_as_user": { - "label": "Rispondi come un utente", - "desc": "Parla con Open Assistant e aiuta a migliorare le sue risposte mentre ci interagisci.", - "overview": "Date le seguenti conversazioni fornisci una risposta adeguata", - "instruction": "Fornisci la risposta dell'utente", - "response_placeholder": "Scrivi qui la tua risposta..." + "default": { + "unchanged_title": "Non sono presenti modifiche", + "unchanged_message": "Sei sicuro di voler continuare?" }, - "reply_as_assistant": { - "label": "Rispondi come assistente", - "desc": "Aiuta Open Assistant a migliorare le sue risposte a conversazioni con altri utenti.", - "overview": "Date le seguenti conversazioni, fornisci una risposta adeguata", - "response_placeholder": "Scrivi qui la tua risposta..." + "label_assistant_reply": { + "label": "Etichetta la risposta dell'assistente", + "desc": "Fornisci etichette per una richiesta.", + "overview": "Data la seguente conversazione, fornisci etichette per la richiesta finale." }, - "rank_user_replies": { - "label": "Classifica le risposte degli utenti", - "desc": "Aiuta Open Assistant a migliorare le sue risposte a conversazioni con altri utenti.", - "overview": "Date le seguenti risposte degli utenti, ordinale dalla migliore alla peggiore, la migliore come prima e la peggiore come ultima.", - "unchanged_title": "L'ordine non è cambiato", - "unchanged_message": "Non hai cambiato l'ordine delle richieste . Sei sicuro di voler continuare?" + "label_initial_prompt": { + "label": "Etichetta le richieste iniziali", + "desc": "Fornisci delle etichette per le richieste.", + "overview": "Fornisci etichette per la seguente richiesta" + }, + "label_prompter_reply": { + "label": "Etichetta la risposta dell'utente", + "desc": "Fornisci etichette per una richiesta.", + "overview": "Data la seguente conversazione, fornisci etichette per la richiesta finale." + }, + "random": { + "label": "Mi sento fortunato", + "desc": "Aiutaci a migliorare Open Assistant iniziando un compito a caso." }, "rank_assistant_replies": { "label": "Classifica le risposte dell'assistente", @@ -48,35 +59,24 @@ "unchanged_title": "L'ordine non è cambiato", "unchanged_message": "Non hai cambiato l'ordine delle richieste . Sei sicuro di voler continuare?" }, - "label_initial_prompt": { - "label": "Etichetta le richieste iniziali", - "desc": "Fornisci delle etichette per le richieste.", - "overview": "Fornisci etichette per la seguente richiesta" + "rank_user_replies": { + "label": "Classifica le risposte degli utenti", + "desc": "Aiuta Open Assistant a migliorare le sue risposte a conversazioni con altri utenti.", + "overview": "Date le seguenti risposte degli utenti, ordinale dalla migliore alla peggiore, la migliore come prima e la peggiore come ultima.", + "unchanged_title": "L'ordine non è cambiato", + "unchanged_message": "Non hai cambiato l'ordine delle richieste . Sei sicuro di voler continuare?" }, - "label_prompter_reply": { - "label": "Etichetta la risposta dell'utente", - "desc": "Fornisci etichette per una richiesta.", - "overview": "Data la seguente conversazione, fornisci etichette per la richiesta finale." + "reply_as_assistant": { + "label": "Rispondi come assistente", + "desc": "Aiuta Open Assistant a migliorare le sue risposte a conversazioni con altri utenti.", + "overview": "Date le seguenti conversazioni, fornisci una risposta adeguata", + "response_placeholder": "Scrivi qui la tua risposta..." }, - "label_assistant_reply": { - "label": "Etichetta la risposta dell'assistente", - "desc": "Fornisci etichette per una richiesta.", - "overview": "Data la seguente conversazione, fornisci etichette per la richiesta finale." - }, - "classify_initial_prompt": { - "label": "Classifica la richiesta iniziale", - "desc": "Fornisci etichette per una richiesta.", - "overview": "Leggi la seguente richiesta e rispondi alla domanda che la riguarda." - }, - "classify_prompter_reply": { - "label": "Classifica la risposta dell'utente", - "desc": "Fornisci etichette per una richiesta.", - "overview": "Leggi la seguente conversazione e rispondi alla domanda riguardante l'ultima risposta della discussione." - }, - "classify_assistant_reply": { - "label": "Classifica la risposta dell'assistente", - "desc": "Fornisci etichette per una richiesta.", - "overview": "Leggi la seguente conversazione e rispondi alla domanda riguardante l'ultima risposta della discussione." - }, - "available_task_count": "{{count}} compiti disponibili" + "reply_as_user": { + "label": "Rispondi come un utente", + "desc": "Parla con Open Assistant e aiuta a migliorare le sue risposte mentre ci interagisci.", + "overview": "Date le seguenti conversazioni fornisci una risposta adeguata", + "instruction": "Fornisci la risposta dell'utente", + "response_placeholder": "Scrivi qui la tua risposta..." + } } diff --git a/website/public/locales/it/tos.json b/website/public/locales/it/tos.json index b2f7e11b..9ee498fc 100644 --- a/website/public/locales/it/tos.json +++ b/website/public/locales/it/tos.json @@ -1,6 +1,6 @@ { - "title": "Termini di Servizio per Open Assistant", - "content": "Per continuare ad usare Open Assistant, accettai i nostri Termini di Servizio.", "accept": "Accetta", - "decline": "Rifiuta" + "content": "Per continuare ad usare Open Assistant, accettai i nostri Termini di Servizio.", + "decline": "Rifiuta", + "title": "Termini di Servizio per Open Assistant" } diff --git a/website/public/locales/ko/common.json b/website/public/locales/ko/common.json index 679c0af2..b7029019 100644 --- a/website/public/locales/ko/common.json +++ b/website/public/locales/ko/common.json @@ -4,12 +4,15 @@ "admin_dashboard": "관리자 대시보드", "connect": "연결", "conversational": "모두를 위한 대화형 AI.", + "copied": "Copied", + "dark_mode": "다크 모드", "dashboard": "대시보드", "delete": "삭제", "discord": "Discord", "docs": "문서", "github": "GitHub", "legal": "Legal", + "light_mode": "라이트 모드", "loading": "로딩중...", "more_information": "추가 정보", "no": "아니오", @@ -17,9 +20,8 @@ "report_a_bug": "버그신고", "sign_in": "Sign In", "sign_out": "Sign Out", + "success": "Success", "terms_of_service": "서비스 약관", "title": "오픈 어시스턴트", - "yes": "예", - "dark_mode": "다크 모드", - "light_mode": "라이트 모드" + "yes": "예" } diff --git a/website/public/locales/ko/dashboard.json b/website/public/locales/ko/dashboard.json index cc262e7f..a116ed92 100644 --- a/website/public/locales/ko/dashboard.json +++ b/website/public/locales/ko/dashboard.json @@ -1,8 +1,8 @@ { - "grab_a_task": "작업을 선택하세요!", "create": "만들다", - "evaluate": "평가하다", - "label": "레이블", "dashboard": "대시보드", - "go": "시작" + "evaluate": "평가하다", + "go": "시작", + "grab_a_task": "작업을 선택하세요!", + "label": "레이블" } diff --git a/website/public/locales/ko/labelling.json b/website/public/locales/ko/labelling.json index 2aa00c26..64685922 100644 --- a/website/public/locales/ko/labelling.json +++ b/website/public/locales/ko/labelling.json @@ -1,24 +1,24 @@ { - "label_highlighted_yes_no_instruction": "강조 표시된 메시지에 대한 다음 질문에 답하십시오.:", + "fails_task.question": "프롬프트 작업에 대해 잘못된 답변입니까?", + "hate_speech": "혐오표현", + "hate_speech.explanation": "콘텐츠는 모욕적이거나 위협적이며 보호되는 특성에 대한 편견을 표현합니다. 편견은 이성에 근거하지 않은 선입견을 말합니다. 보호되는 특성에는 성별, 민족, 종교, 성적 취향 및 유사한 특성이 포함됩니다.", "label_highlighted_flag_instruction": "강조 표시된 메시지에 해당하는 항목을 선택하십시오.:", "label_highlighted_likert_instruction": "강조 표시된 메시지를 평가하십시오:", - "label_message_yes_no_instruction": "메시지에 대한 다음 질문에 답하십시오.:", + "label_highlighted_yes_no_instruction": "강조 표시된 메시지에 대한 다음 질문에 답하십시오.:", "label_message_flag_instruction": "메시지에 해당하는 것을 선택하십시오.:", "label_message_likert_instruction": "메시지 평가:", - "spam.question": "메시지가 스팸입니까?", - "fails_task.question": "프롬프트 작업에 대해 잘못된 답변입니까?", + "label_message_yes_no_instruction": "메시지에 대한 다음 질문에 답하십시오.:", + "lang_mismatch": "잘못된 언어", + "lang_mismatch.explanation": "현재 선택한 언어로 작성되지 않았습니다.", + "moral_judgement": "도덕적 판단", + "moral_judgement.explanation": "도덕적 판단을 표현합니다.", "not_appropriate": "알맞지 않은", "not_appropriate.explanation": "고객 지원에 부적합.", "pii": "개인식별정보를 포함.", "pii.explanation": "개인 식별 정보가 포함되어 있습니다. 예를 들면 개인 연락처 세부 정보, 면허증 및 기타 식별 번호, 은행 세부 정보가 포함됩니다.", - "hate_speech": "혐오표현", - "hate_speech.explanation": "콘텐츠는 모욕적이거나 위협적이며 보호되는 특성에 대한 편견을 표현합니다. 편견은 이성에 근거하지 않은 선입견을 말합니다. 보호되는 특성에는 성별, 민족, 종교, 성적 취향 및 유사한 특성이 포함됩니다.", - "sexual_content": "성적인 내용", - "sexual_content.explanation": "성적인 내용이 포함되어 있습니다.", - "moral_judgement": "도덕적 판단", - "moral_judgement.explanation": "도덕적 판단을 표현합니다.", "political_content": "정치적인", "political_content.explanation": "정치적 견해를 표현합니다.", - "lang_mismatch": "잘못된 언어", - "lang_mismatch.explanation": "현재 선택한 언어로 작성되지 않았습니다." + "sexual_content": "성적인 내용", + "sexual_content.explanation": "성적인 내용이 포함되어 있습니다.", + "spam.question": "메시지가 스팸입니까?" } diff --git a/website/public/locales/ko/leaderboard.json b/website/public/locales/ko/leaderboard.json index 254f37ca..e58de665 100644 --- a/website/public/locales/ko/leaderboard.json +++ b/website/public/locales/ko/leaderboard.json @@ -1,18 +1,18 @@ { "daily": "일일", + "label": "레이블", "last_updated_at": "최종 업데이트 시간: {{val, datetime}}", "leaderboard": "리더보드", "monthly": "월간", + "next": "다음", "overall": "종합", - "rank": "순위", - "score": "점수", - "user": "사용자", - "weekly": "주간", - "prompt": "프롬프트", - "reply": "답변", - "label": "레이블", - "view_all": "전체보기", - "top_5_contributors_today": "금일 상위 5명의 기여자", "previous": "이전", - "next": "다음" + "prompt": "프롬프트", + "rank": "순위", + "reply": "답변", + "score": "점수", + "top_5_contributors_today": "금일 상위 5명의 기여자", + "user": "사용자", + "view_all": "전체보기", + "weekly": "주간" } diff --git a/website/public/locales/ko/message.json b/website/public/locales/ko/message.json index 6574b297..1b3455dc 100644 --- a/website/public/locales/ko/message.json +++ b/website/public/locales/ko/message.json @@ -1,16 +1,20 @@ { + "copy_message_id": "Copy message ID", "label_action": "레이블", "label_title": "레이블", "message": "메세지", + "message_deleted": "Message deleted", "open_new_tab_action": "새 탭에서 열기", "parent": "상위", "reactions": "반응", + "recent_messages": "최근 메세지", "report_action": "리포트", "report_placeholder": "이 메시지를 검토해야 하는 이유는 무엇입니까?", "report_title": "리포트", "send_report": "보내기", + "stop_tree": "Stop tree", "submit_labels": "등록", + "tree_stopped": "Tree stopped {{id}}", "view_user": "사용자 보기", - "recent_messages": "최근 메세지", "your_recent_messages": "최근 메세지들" } diff --git a/website/public/locales/ko/side_menu.json b/website/public/locales/ko/side_menu.json index f30f1597..99b43380 100644 --- a/website/public/locales/ko/side_menu.json +++ b/website/public/locales/ko/side_menu.json @@ -1,12 +1,12 @@ { "dashboard": "대시보드", "dashboard_home": "대시보드 홈", + "leaderboard": "리더보드", "messages": "메세지", "messages_dashboard": "메세지 대시보드", - "leaderboard": "리더보드", + "status": "상태", + "status_dashboard": "상태 대시보드", "user_leaderboard": "사용자 리더보드", "users": "사용자", - "users_dashboard": "사용자 대시보드", - "status": "상태", - "status_dashboard": "상태 대시보드" + "users_dashboard": "사용자 대시보드" } diff --git a/website/public/locales/ko/tasks.json b/website/public/locales/ko/tasks.json index 4f46ffd3..8ec6246d 100644 --- a/website/public/locales/ko/tasks.json +++ b/website/public/locales/ko/tasks.json @@ -1,11 +1,19 @@ { - "default": { - "unchanged_title": "변경사항 없음", - "unchanged_message": "계속 하시겠습니까?" + "available_task_count": "{{count}} 작업 가능", + "classify_assistant_reply": { + "label": "어시스턴트 대답 분류", + "desc": "프롬프트에 레이블을 제공합니다.", + "overview": "다음 대화를 읽고 토론의 마지막 답변에 대한 질문에 답하십시오." }, - "random": { - "label": "행운이 느껴진다!", - "desc": "무작위 작업을 시작하여 Open Assistant를 개선할 수 있도록 도와주세요." + "classify_initial_prompt": { + "label": "초기 프롬프트 분류", + "desc": "프롬프트에 레이블을 제공합니다.", + "overview": "다음 프롬프트를 읽고 이에 대한 질문에 답하십시오." + }, + "classify_prompter_reply": { + "label": "프롬프터 대답 분류", + "desc": "프롬프트에 레이블을 제공합니다.", + "overview": "다음 대화를 읽고 토론의 마지막 답변에 대한 질문에 답하십시오." }, "create_initial_prompt": { "label": "초기 프롬프트 생성", @@ -14,25 +22,28 @@ "instruction": "초기 프롬프트 제공", "response_placeholder": "여기에 프롬프트를 작성하세요..." }, - "reply_as_user": { - "label": "사용자로 회신", - "desc": "Open Assistant와 채팅하고 상호 작용할 때 응답을 개선하는 데 도움을 줍니다.", - "overview": "다음 대화가 주어지면 적절한 답변을 제공하십시오.", - "instruction": "사용자의 답장 제공", - "response_placeholder": "여기에 답장을 쓰세요..." + "default": { + "unchanged_title": "변경사항 없음", + "unchanged_message": "계속 하시겠습니까?" }, - "reply_as_assistant": { - "label": "어시스턴트로 답장", - "desc": "Open Assistant가 다른 사용자와의 대화에 대한 응답을 개선하도록 도와주세요.", - "overview": "다음 대화가 주어지면 적절한 답변을 제공하십시오.", - "response_placeholder": "여기에 답장을 쓰세요..." + "label_assistant_reply": { + "label": "어시스턴트 답장에 대한 레이블링", + "desc": "프롬프트에 레이블을 제공합니다.", + "overview": "다음 논의가 주어지면 최종 프롬프트에 대한 레이블을 제공하십시오." }, - "rank_user_replies": { - "label": "사용자 답글 순위 지정", - "desc": "Open Assistant가 다른 사용자와의 대화에 대한 응답을 개선하도록 도와주세요.", - "overview": "다음 사용자 응답이 주어지면 가장 좋은 것부터 가장 나쁜 것까지 정렬하세요. 가장 좋은 것이 첫 번째, 가장 나쁜 것이 마지막입니다.", - "unchanged_title": "변경되지 않은 순서", - "unchanged_message": "프롬프트의 순서를 변경하지 않았습니다. 계속하시겠습니까?" + "label_initial_prompt": { + "label": "초기 프롬프트 레이블링", + "desc": "프롬프트에 레이블을 제공합니다.", + "overview": "다음 프롬프트에 대한 레이블 제공" + }, + "label_prompter_reply": { + "label": "프롬프터 대답에 대한 레이블링", + "desc": "프롬프트에 레이블을 제공합니다.", + "overview": "다음 논의가 주어지면 최종 프롬프트에 대한 레이블을 제공하십시오." + }, + "random": { + "label": "행운이 느껴진다!", + "desc": "무작위 작업을 시작하여 Open Assistant를 개선할 수 있도록 도와주세요." }, "rank_assistant_replies": { "label": "순위 보조 답변", @@ -48,35 +59,24 @@ "unchanged_title": "변경되지 않은 순서", "unchanged_message": "프롬프트의 순서를 변경하지 않았습니다. 계속하시겠습니까?" }, - "label_initial_prompt": { - "label": "초기 프롬프트 레이블링", - "desc": "프롬프트에 레이블을 제공합니다.", - "overview": "다음 프롬프트에 대한 레이블 제공" + "rank_user_replies": { + "label": "사용자 답글 순위 지정", + "desc": "Open Assistant가 다른 사용자와의 대화에 대한 응답을 개선하도록 도와주세요.", + "overview": "다음 사용자 응답이 주어지면 가장 좋은 것부터 가장 나쁜 것까지 정렬하세요. 가장 좋은 것이 첫 번째, 가장 나쁜 것이 마지막입니다.", + "unchanged_title": "변경되지 않은 순서", + "unchanged_message": "프롬프트의 순서를 변경하지 않았습니다. 계속하시겠습니까?" }, - "label_prompter_reply": { - "label": "프롬프터 대답에 대한 레이블링", - "desc": "프롬프트에 레이블을 제공합니다.", - "overview": "다음 논의가 주어지면 최종 프롬프트에 대한 레이블을 제공하십시오." + "reply_as_assistant": { + "label": "어시스턴트로 답장", + "desc": "Open Assistant가 다른 사용자와의 대화에 대한 응답을 개선하도록 도와주세요.", + "overview": "다음 대화가 주어지면 적절한 답변을 제공하십시오.", + "response_placeholder": "여기에 답장을 쓰세요..." }, - "label_assistant_reply": { - "label": "어시스턴트 답장에 대한 레이블링", - "desc": "프롬프트에 레이블을 제공합니다.", - "overview": "다음 논의가 주어지면 최종 프롬프트에 대한 레이블을 제공하십시오." - }, - "classify_initial_prompt": { - "label": "초기 프롬프트 분류", - "desc": "프롬프트에 레이블을 제공합니다.", - "overview": "다음 프롬프트를 읽고 이에 대한 질문에 답하십시오." - }, - "classify_prompter_reply": { - "label": "프롬프터 대답 분류", - "desc": "프롬프트에 레이블을 제공합니다.", - "overview": "다음 대화를 읽고 토론의 마지막 답변에 대한 질문에 답하십시오." - }, - "classify_assistant_reply": { - "label": "어시스턴트 대답 분류", - "desc": "프롬프트에 레이블을 제공합니다.", - "overview": "다음 대화를 읽고 토론의 마지막 답변에 대한 질문에 답하십시오." - }, - "available_task_count": "{{count}} 작업 가능" + "reply_as_user": { + "label": "사용자로 회신", + "desc": "Open Assistant와 채팅하고 상호 작용할 때 응답을 개선하는 데 도움을 줍니다.", + "overview": "다음 대화가 주어지면 적절한 답변을 제공하십시오.", + "instruction": "사용자의 답장 제공", + "response_placeholder": "여기에 답장을 쓰세요..." + } } diff --git a/website/public/locales/ko/tos.json b/website/public/locales/ko/tos.json new file mode 100644 index 00000000..4d3d62b4 --- /dev/null +++ b/website/public/locales/ko/tos.json @@ -0,0 +1,6 @@ +{ + "accept": "Accept", + "content": "To continue using Open Assistant, you have to accept our Terms of Service first.", + "decline": "Decline", + "title": "Terms of Service for Open Assistant" +} diff --git a/website/public/locales/pt-BR/common.json b/website/public/locales/pt-BR/common.json index a827c2aa..0e33ed21 100644 --- a/website/public/locales/pt-BR/common.json +++ b/website/public/locales/pt-BR/common.json @@ -2,9 +2,9 @@ "about": "Sobre", "account_settings": "Conta", "admin_dashboard": "Painel de configurações", - "copied": "Copiado", "connect": "Conectar", "conversational": "IA conversacional para todos.", + "copied": "Copiado", "dark_mode": "Tema Escuro", "dashboard": "Painel", "delete": "Deletar", diff --git a/website/public/locales/pt-BR/dashboard.json b/website/public/locales/pt-BR/dashboard.json index 51ae298c..78c2106e 100644 --- a/website/public/locales/pt-BR/dashboard.json +++ b/website/public/locales/pt-BR/dashboard.json @@ -1,8 +1,8 @@ { - "grab_a_task": "Escolha uma tarefa!", "create": "Criar", - "evaluate": "Avaliar", - "label": "Classificar", "dashboard": "Painel", - "go": "Iniciar" + "evaluate": "Avaliar", + "go": "Iniciar", + "grab_a_task": "Escolha uma tarefa!", + "label": "Classificar" } diff --git a/website/public/locales/pt-BR/labelling.json b/website/public/locales/pt-BR/labelling.json index 329a2314..bf036ddd 100644 --- a/website/public/locales/pt-BR/labelling.json +++ b/website/public/locales/pt-BR/labelling.json @@ -1,24 +1,24 @@ { - "label_highlighted_yes_no_instruction": "Responda a(s) pergunta(s) a seguir sobre a mensagem em destaque:", + "fails_task.question": "É uma má resposta segundo a tarefa pedida?", + "hate_speech": "Discurso de ódio", + "hate_speech.explanation": "O conteúdo é ofensivo ou ameaçador e expressa preconceito contra uma característica pessoal. Preconceito refere-se a opiniões preconcebidas que não são baseadas na razão. As características pessoais incluem gênero, etnia, religião, orientação sexual e características similares.", "label_highlighted_flag_instruction": "Selecione qualquer um que se aplique à mensagem em destaque:", "label_highlighted_likert_instruction": "Avalie a mensagem em destaque:", - "label_message_yes_no_instruction": "Responda a(s) pergunta(s) a seguir sobre a mensagem:", + "label_highlighted_yes_no_instruction": "Responda a(s) pergunta(s) a seguir sobre a mensagem em destaque:", "label_message_flag_instruction": "Selecione o que se aplique à mensagem:", "label_message_likert_instruction": "Classifique a mensagem:", - "spam.question": "A mensagem é spam?", - "fails_task.question": "É uma má resposta segundo a tarefa pedida?", + "label_message_yes_no_instruction": "Responda a(s) pergunta(s) a seguir sobre a mensagem:", + "lang_mismatch": "Idioma incorreto", + "lang_mismatch.explanation": "Não está escrito no idioma selecionado atualmente.", + "moral_judgement": "Julgamento moral", + "moral_judgement.explanation": "Tem julgamento moral", "not_appropriate": "Não apropriada", "not_appropriate.explanation": "Não apropriada para um assistente.", "pii": "Contém informações que permitem identificação pessoal (PII)", "pii.explanation": "Contém informações que permitem identificação pessoal tais como informações de contato, números de identificação ou dados bancários", - "hate_speech": "Discurso de ódio", - "hate_speech.explanation": "O conteúdo é ofensivo ou ameaçador e expressa preconceito contra uma característica pessoal. Preconceito refere-se a opiniões preconcebidas que não são baseadas na razão. As características pessoais incluem gênero, etnia, religião, orientação sexual e características similares.", - "sexual_content": "Conteúdo sexual", - "sexual_content.explanation": "Contém conteúdo sexual.", - "moral_judgement": "Julgamento moral", - "moral_judgement.explanation": "Tem julgamento moral", "political_content": "Conteúdo político", "political_content.explanation": "Expressa uma opinião política.", - "lang_mismatch": "Idioma incorreto", - "lang_mismatch.explanation": "Não está escrito no idioma selecionado atualmente." + "sexual_content": "Conteúdo sexual", + "sexual_content.explanation": "Contém conteúdo sexual.", + "spam.question": "A mensagem é spam?" } diff --git a/website/public/locales/pt-BR/leaderboard.json b/website/public/locales/pt-BR/leaderboard.json index da9820b2..94c4a1eb 100644 --- a/website/public/locales/pt-BR/leaderboard.json +++ b/website/public/locales/pt-BR/leaderboard.json @@ -1,18 +1,18 @@ { "daily": "Diário", + "label": "Etiquetas", "last_updated_at": "Última atualização em: {{val, datetime}}", "leaderboard": "Leaderboard", "monthly": "Mensal", + "next": "Seguinte", "overall": "Geral", - "rank": "Classificação", - "score": "Pontuação", - "user": "Usuário", - "weekly": "Semanal", - "prompt": "Prompts", - "reply": "Respostas", - "label": "Etiquetas", - "view_all": "Ver tudo", - "top_5_contributors_today": "Top 5 Colaboradores de Hoje", "previous": "Voltar", - "next": "Seguinte" + "prompt": "Prompts", + "rank": "Classificação", + "reply": "Respostas", + "score": "Pontuação", + "top_5_contributors_today": "Top 5 Colaboradores de Hoje", + "user": "Usuário", + "view_all": "Ver tudo", + "weekly": "Semanal" } diff --git a/website/public/locales/pt-BR/message.json b/website/public/locales/pt-BR/message.json index 848a77b1..2ea52026 100644 --- a/website/public/locales/pt-BR/message.json +++ b/website/public/locales/pt-BR/message.json @@ -2,8 +2,8 @@ "copy_message_id": "Copiar ID de mensagem", "label_action": "Classificar", "label_title": "Classificar", - "message_deleted": "Mensagem apagada", "message": "Mensagem", + "message_deleted": "Mensagem apagada", "open_new_tab_action": "Abrir em nova aba", "parent": "Raiz", "reactions": "Reações", diff --git a/website/public/locales/pt-BR/side_menu.json b/website/public/locales/pt-BR/side_menu.json index c001d838..78b01d57 100644 --- a/website/public/locales/pt-BR/side_menu.json +++ b/website/public/locales/pt-BR/side_menu.json @@ -1,12 +1,12 @@ { "dashboard": "Painel", "dashboard_home": "Página principal", + "leaderboard": "Leaderboard", "messages": "Mensagens", "messages_dashboard": "Painel de mensagens", - "leaderboard": "Leaderboard", + "status": "Status", + "status_dashboard": "Painel de status", "user_leaderboard": "Leaderboard dos usuários", "users": "Usuários", - "users_dashboard": "Painel de controle de usuários", - "status": "Status", - "status_dashboard": "Painel de status" + "users_dashboard": "Painel de controle de usuários" } diff --git a/website/public/locales/pt-BR/tasks.json b/website/public/locales/pt-BR/tasks.json index fd7243ad..25bc7dc2 100644 --- a/website/public/locales/pt-BR/tasks.json +++ b/website/public/locales/pt-BR/tasks.json @@ -1,11 +1,19 @@ { - "default": { - "unchanged_title": "Sem alterações", - "unchanged_message": "Tem certeza que quer continuar?" + "available_task_count": "{{count}} tarefas disponiveis", + "classify_assistant_reply": { + "label": "Classificar a resposta do assistente", + "desc": "Forneça etiquetas para o prompt inicial.", + "overview": "Leia a conversa a seguir e depois responda à pergunta sobre a última resposta na discussão." }, - "random": { - "label": "Estou me sentindo com sorte", - "desc": "Ajude-nos a melhorar o Open Assistant, inicie uma tarefa aleatória." + "classify_initial_prompt": { + "label": "Classificar o prompt inicial", + "desc": "Forneça etiquetas para o prompt inicial.", + "overview": "Leia o seguinte prompt e responda à pergunta sobre o assunto." + }, + "classify_prompter_reply": { + "label": "Classificar a resposta do prompter", + "desc": "Forneça etiquetas para o prompt inicial.", + "overview": "Leia a conversa a seguir e depois responda à pergunta sobre a última resposta na discussão." }, "create_initial_prompt": { "label": "Criar prompts iniciais", @@ -14,25 +22,28 @@ "instruction": "Forneça os prompts iniciais", "response_placeholder": "Escreva aqui seu prompt..." }, - "reply_as_user": { - "label": "Responder como usuário", - "desc": "Fale com o Open Assistant e tente melhorar suas respostas à medida que você interage com ele.", - "overview": "Dada a seguinte conversa, dê uma resposta apropriada", - "instruction": "Forneça feedback do usuário", - "response_placeholder": "Escreva aqui sua resposta..." + "default": { + "unchanged_title": "Sem alterações", + "unchanged_message": "Tem certeza que quer continuar?" }, - "reply_as_assistant": { - "label": "Responder como assistente", - "desc": "Ajude o Open Assistant a melhorar suas respostas às conversas com outros usuários.", - "overview": "Dada a seguinte conversa, dê uma resposta apropriada", - "response_placeholder": "Escreva aqui sua resposta..." + "label_assistant_reply": { + "label": "Etiquetar resposta do assistente", + "desc": "Forneça etiquetas para o prompt inicial.", + "overview": "Dada a discussão a seguir, forneça etiquetas para o último prompt." }, - "rank_user_replies": { - "label": "Ordenar as respostas dos usuários", - "desc": "Ajude o Open Assistant a melhorar suas respostas às conversas com outros usuários.", - "overview": "Dadas as seguintes respostas dos usuários, ordene-as em ordem da melhor para a pior, sendo a primeira a melhor e a última a pior.", - "unchanged_title": "Ordem inalterada", - "unchanged_message": "Você não mudou a ordem dos prompts - você tem certeza de que quer continuar?" + "label_initial_prompt": { + "label": "Etiquetar o prompt inicial", + "desc": "Forneça etiquetas para o prompt inicial.", + "overview": "Forneça etiquetas para o prompt a seguir" + }, + "label_prompter_reply": { + "label": "Etiquetar resposta do prompter", + "desc": "Forneça etiquetas para o prompt inicial.", + "overview": "Dada a discussão a seguir, forneça etiquetas para o último prompt." + }, + "random": { + "label": "Estou me sentindo com sorte", + "desc": "Ajude-nos a melhorar o Open Assistant, inicie uma tarefa aleatória." }, "rank_assistant_replies": { "label": "Ordenar as respostas do assistente", @@ -48,35 +59,24 @@ "unchanged_title": "Ordem inalterada", "unchanged_message": "Você não mudou a ordem dos prompts - você tem certeza de que quer continuar?" }, - "label_initial_prompt": { - "label": "Etiquetar o prompt inicial", - "desc": "Forneça etiquetas para o prompt inicial.", - "overview": "Forneça etiquetas para o prompt a seguir" + "rank_user_replies": { + "label": "Ordenar as respostas dos usuários", + "desc": "Ajude o Open Assistant a melhorar suas respostas às conversas com outros usuários.", + "overview": "Dadas as seguintes respostas dos usuários, ordene-as em ordem da melhor para a pior, sendo a primeira a melhor e a última a pior.", + "unchanged_title": "Ordem inalterada", + "unchanged_message": "Você não mudou a ordem dos prompts - você tem certeza de que quer continuar?" }, - "label_prompter_reply": { - "label": "Etiquetar resposta do prompter", - "desc": "Forneça etiquetas para o prompt inicial.", - "overview": "Dada a discussão a seguir, forneça etiquetas para o último prompt." + "reply_as_assistant": { + "label": "Responder como assistente", + "desc": "Ajude o Open Assistant a melhorar suas respostas às conversas com outros usuários.", + "overview": "Dada a seguinte conversa, dê uma resposta apropriada", + "response_placeholder": "Escreva aqui sua resposta..." }, - "label_assistant_reply": { - "label": "Etiquetar resposta do assistente", - "desc": "Forneça etiquetas para o prompt inicial.", - "overview": "Dada a discussão a seguir, forneça etiquetas para o último prompt." - }, - "classify_initial_prompt": { - "label": "Classificar o prompt inicial", - "desc": "Forneça etiquetas para o prompt inicial.", - "overview": "Leia o seguinte prompt e responda à pergunta sobre o assunto." - }, - "classify_prompter_reply": { - "label": "Classificar a resposta do prompter", - "desc": "Forneça etiquetas para o prompt inicial.", - "overview": "Leia a conversa a seguir e depois responda à pergunta sobre a última resposta na discussão." - }, - "classify_assistant_reply": { - "label": "Classificar a resposta do assistente", - "desc": "Forneça etiquetas para o prompt inicial.", - "overview": "Leia a conversa a seguir e depois responda à pergunta sobre a última resposta na discussão." - }, - "available_task_count": "{{count}} tarefas disponiveis" + "reply_as_user": { + "label": "Responder como usuário", + "desc": "Fale com o Open Assistant e tente melhorar suas respostas à medida que você interage com ele.", + "overview": "Dada a seguinte conversa, dê uma resposta apropriada", + "instruction": "Forneça feedback do usuário", + "response_placeholder": "Escreva aqui sua resposta..." + } } diff --git a/website/public/locales/pt-BR/tos.json b/website/public/locales/pt-BR/tos.json index ee842d3b..8e4a549a 100644 --- a/website/public/locales/pt-BR/tos.json +++ b/website/public/locales/pt-BR/tos.json @@ -1,6 +1,6 @@ { - "title": "Termos de Serviço para o Open Assistant", - "content": "Para continuar usando o Open Assistant, você precisa aceitar os nossos Termos de Serviço primeiro.", "accept": "Aceitar", - "decline": "Recusar" + "content": "Para continuar usando o Open Assistant, você precisa aceitar os nossos Termos de Serviço primeiro.", + "decline": "Recusar", + "title": "Termos de Serviço para o Open Assistant" } diff --git a/website/public/locales/ru/common.json b/website/public/locales/ru/common.json index 5b33294d..7ab53c51 100644 --- a/website/public/locales/ru/common.json +++ b/website/public/locales/ru/common.json @@ -4,12 +4,15 @@ "admin_dashboard": "Панель администратора", "connect": "Connect", "conversational": "Conversational AI for everyone.", + "copied": "Copied", + "dark_mode": "Темная тема", "dashboard": "Главная", "delete": "Удалить", "discord": "Discord", "docs": "Документация", "github": "GitHub", "legal": "Legal", + "light_mode": "Светлая тема", "loading": "Загрузка...", "more_information": "Больше...", "no": "Нет", @@ -17,9 +20,8 @@ "report_a_bug": "Сообщить об ошибке", "sign_in": "Вход", "sign_out": "Выйти из аккаунта", + "success": "Success", "terms_of_service": "Пользовательское Соглашение", "title": "Open Assistant", - "yes": "Да", - "dark_mode": "Темная тема", - "light_mode": "Светлая тема" + "yes": "Да" } diff --git a/website/public/locales/ru/dashboard.json b/website/public/locales/ru/dashboard.json index 09a53b10..b3c38e36 100644 --- a/website/public/locales/ru/dashboard.json +++ b/website/public/locales/ru/dashboard.json @@ -1,8 +1,8 @@ { - "grab_a_task": "Взять задание!", "create": "Создать", - "evaluate": "Ранжировать", - "label": "Классифицировать", "dashboard": "Главная", - "go": "Начать" + "evaluate": "Ранжировать", + "go": "Начать", + "grab_a_task": "Взять задание!", + "label": "Классифицировать" } diff --git a/website/public/locales/ru/index.json b/website/public/locales/ru/index.json new file mode 100644 index 00000000..a6e89b9c --- /dev/null +++ b/website/public/locales/ru/index.json @@ -0,0 +1,23 @@ +{ + "blurb": "We believe we can create a revolution.", + "blurb1": "In the same way that Stable Diffusion helped the world make art and images in new ways, we want to improve the world by providing amazing conversational AI.", + "description": "Conversational AI for everyone. An open source project to create a chat enabled GPT LLM run by LAION and contributors around the world.", + "faq_items": { + "q0": "How far along is this project?", + "a0": "We are in the early stages of development, working from established research in applying RLHF to large language models.", + "q1": "Who is behind Open Assistant?", + "a1": "Open Assistant is a project organized by LAION and individuals around the world interested in bringing this technology to everyone.", + "q2": "What license does Open Assistant use?", + "a2": "The code and models are licensed under the Apache 2.0 license.", + "q3": "Will the training data also be released?", + "a3": "Yes, under CC BY 4.0.", + "q4": "Will Open Assistant be free?", + "a4": "Yes, Open Assistant will be free to use and modify.", + "q5": "What hardware will be required to run the models?", + "a5": "There will be versions which will be runnable on consumer hardware." + }, + "faq_title": "Frequently Asked Questions", + "join_us_description": "All open source projects begin with people like you. Open source is the belief that if we collaborate we can together gift our knowledge and technology to the world for the benefit of humanity. Are you in? Find us here:", + "join_us_title": "Join us", + "subtitle": "Conversational AI for everyone." +} diff --git a/website/public/locales/ru/labelling.json b/website/public/locales/ru/labelling.json index c43cb989..7bd47dc7 100644 --- a/website/public/locales/ru/labelling.json +++ b/website/public/locales/ru/labelling.json @@ -1,24 +1,24 @@ { - "label_highlighted_yes_no_instruction": "Ответьте на следующий вопрос (вопросы) о выделенном сообщении:", + "fails_task.question": "Плохой ли это ответ, по отношению к поставленной задачу?", + "hate_speech": "Разжигание ненависти", + "hate_speech.explanation": "Содержание является оскорбительным или угрожающим и выражает предубеждение против некоторых характеристик. Предрассудки - это предвзятые мнения, не основанные на разуме. К характеристикам относятся пол, этническая принадлежность, религия, сексуальная ориентация и подобные.", "label_highlighted_flag_instruction": "Выберите все, что относится к выделенному сообщению:", "label_highlighted_likert_instruction": "Оцените выделенное сообщение:", - "label_message_yes_no_instruction": "Ответьте на следующий вопрос (вопросы) о сообщении:", + "label_highlighted_yes_no_instruction": "Ответьте на следующий вопрос (вопросы) о выделенном сообщении:", "label_message_flag_instruction": "Выберите все, что относится к сообщению:", "label_message_likert_instruction": "Оцените сообщение:", - "spam.question": "Является ли сообщение спамом?", - "fails_task.question": "Плохой ли это ответ, по отношению к поставленной задачу?", + "label_message_yes_no_instruction": "Ответьте на следующий вопрос (вопросы) о сообщении:", + "lang_mismatch": "Неправильный язык", + "lang_mismatch.explanation": "Не написано на текущем выбранном языке.", + "moral_judgement": "Оценивает мораль", + "moral_judgement.explanation": "Выражает моральную оценку.", "not_appropriate": "Неуместный ответ", "not_appropriate.explanation": "Не подходит для помощника.", "pii": "Содержит персональные данные", "pii.explanation": "Содержит личную идентифицирующую информацию. Примеры включают личные контактные данные, номер паспорта и/или других удостоверений личности, или же банковские реквизиты.", - "hate_speech": "Разжигание ненависти", - "hate_speech.explanation": "Содержание является оскорбительным или угрожающим и выражает предубеждение против некоторых характеристик. Предрассудки - это предвзятые мнения, не основанные на разуме. К характеристикам относятся пол, этническая принадлежность, религия, сексуальная ориентация и подобные.", - "sexual_content": "Контент сексуального характера", - "sexual_content.explanation": "Содержит материалы сексуального характера.", - "moral_judgement": "Оценивает мораль", - "moral_judgement.explanation": "Выражает моральную оценку.", "political_content": "Политика", "political_content.explanation": "Выражает политические взгляды.", - "lang_mismatch": "Неправильный язык", - "lang_mismatch.explanation": "Не написано на текущем выбранном языке." + "sexual_content": "Контент сексуального характера", + "sexual_content.explanation": "Содержит материалы сексуального характера.", + "spam.question": "Является ли сообщение спамом?" } diff --git a/website/public/locales/ru/leaderboard.json b/website/public/locales/ru/leaderboard.json index 3023c557..37b7850b 100644 --- a/website/public/locales/ru/leaderboard.json +++ b/website/public/locales/ru/leaderboard.json @@ -1,18 +1,18 @@ { "daily": "За день", + "label": "Labels", "last_updated_at": "Последний раз обновлено: {{val, datetime}}", "leaderboard": "Таблица лидеров", "monthly": "За месяц", + "next": "Вперед", "overall": "Всего", - "rank": "Позиция", - "score": "Счет", - "user": "Пользователь", - "weekly": "За неделю", - "prompt": "Prompts", - "reply": "Replies", - "label": "Labels", - "view_all": "Посмотреть все", - "top_5_contributors_today": "Топ 5 Пользователей за Сегодня", "previous": "Назад", - "next": "Вперед" + "prompt": "Prompts", + "rank": "Позиция", + "reply": "Replies", + "score": "Счет", + "top_5_contributors_today": "Топ 5 Пользователей за Сегодня", + "user": "Пользователь", + "view_all": "Посмотреть все", + "weekly": "За неделю" } diff --git a/website/public/locales/ru/message.json b/website/public/locales/ru/message.json index e0ba592b..269215a4 100644 --- a/website/public/locales/ru/message.json +++ b/website/public/locales/ru/message.json @@ -1,16 +1,20 @@ { + "copy_message_id": "Copy message ID", "label_action": "Классифицировать", "label_title": "Классифицировать", "message": "Сообщение", + "message_deleted": "Message deleted", "open_new_tab_action": "Открыть в новой вкладке", "parent": "Родитель", "reactions": "Реакции", + "recent_messages": "Последние Сообщения", "report_action": "Пожаловаться", "report_placeholder": "Почему это сообщение должно быть рассмотрено?", "report_title": "Пожаловаться", "send_report": "Отправить", + "stop_tree": "Stop tree", "submit_labels": "Отправить", + "tree_stopped": "Tree stopped {{id}}", "view_user": "О пользователе", - "recent_messages": "Последние Сообщения", "your_recent_messages": "Ваши Последние сообщения" } diff --git a/website/public/locales/ru/side_menu.json b/website/public/locales/ru/side_menu.json index 36596ed2..e72ef732 100644 --- a/website/public/locales/ru/side_menu.json +++ b/website/public/locales/ru/side_menu.json @@ -1,12 +1,12 @@ { "dashboard": "Главная", "dashboard_home": "Главная страница", + "leaderboard": "Рейтинг", "messages": "Сообщения", "messages_dashboard": "Панель просмотра сообщений", - "leaderboard": "Рейтинг", + "status": "Статус", + "status_dashboard": "Панель состояния системы", "user_leaderboard": "Таблица лидеров", "users": "Пользователи", - "users_dashboard": "Панель управления пользователями", - "status": "Статус", - "status_dashboard": "Панель состояния системы" + "users_dashboard": "Панель управления пользователями" } diff --git a/website/public/locales/ru/tasks.json b/website/public/locales/ru/tasks.json new file mode 100644 index 00000000..d658baf1 --- /dev/null +++ b/website/public/locales/ru/tasks.json @@ -0,0 +1,82 @@ +{ + "available_task_count": "{{count}} tasks available", + "classify_assistant_reply": { + "label": "Classify Assistant Reply", + "desc": "Provide labels for a prompt.", + "overview": "Read the following conversation and then answer the question about the last reply in the discussion." + }, + "classify_initial_prompt": { + "label": "Classify Initial Prompt", + "desc": "Provide labels for a prompt.", + "overview": "Read the following prompt and then answer the question about it." + }, + "classify_prompter_reply": { + "label": "Classify Prompter Reply", + "desc": "Provide labels for a prompt.", + "overview": "Read the following conversation and then answer the question about the last reply in the discussion." + }, + "create_initial_prompt": { + "label": "Create Initial Prompts", + "desc": "Write initial prompts to help Open Assistant to try replying to diverse messages. (enter into lottery)", + "overview": "Create an initial message to send to the assistant", + "instruction": "Provide the initial prompts", + "response_placeholder": "Write your prompt here..." + }, + "default": { + "unchanged_title": "No changes", + "unchanged_message": "Are you sure you would like to continue?" + }, + "label_assistant_reply": { + "label": "Label Assistant Reply", + "desc": "Provide labels for a prompt.", + "overview": "Given the following discussion, provide labels for the final prompt." + }, + "label_initial_prompt": { + "label": "Label Initial Prompt", + "desc": "Provide labels for a prompt.", + "overview": "Provide labels for the following prompt" + }, + "label_prompter_reply": { + "label": "Label Prompter Reply", + "desc": "Provide labels for a prompt.", + "overview": "Given the following discussion, provide labels for the final prompt." + }, + "random": { + "label": "I'm feeling lucky", + "desc": "Help us improve Open Assistant by starting a random task." + }, + "rank_assistant_replies": { + "label": "Rank Assistant Replies", + "desc": "Score prompts given by Open Assistant based on their accuracy and readability.", + "overview": "Given the following Assistant replies, sort them from best to worst, best being first, worst being last.", + "unchanged_title": "Order Unchanged", + "unchanged_message": "You have not changed the order of the prompts. Are you sure you would like to continue?" + }, + "rank_initial_prompts": { + "label": "Rank Initial Prompts", + "desc": "Score prompts given by Open Assistant based on their accuracy and readability.", + "overview": "Given the following initial prompts, sort them from best to worst, best being first, worst being last.", + "unchanged_title": "Order Unchanged", + "unchanged_message": "You have not changed the order of the prompts. Are you sure you would like to continue?" + }, + "rank_user_replies": { + "label": "Rank User Replies", + "desc": "Help Open Assistant improve its responses to conversations with other users.", + "overview": "Given the following User replies, sort them from best to worst, best being first, worst being last.", + "unchanged_title": "Order Unchanged", + "unchanged_message": "You have not changed the order of the prompts. Are you sure you would like to continue?" + }, + "reply_as_assistant": { + "label": "Reply as Assistant", + "desc": "Help Open Assistant improve its responses to conversations with other users.", + "overview": "Given the following conversation, provide an adequate reply", + "response_placeholder": "Write your reply here..." + }, + "reply_as_user": { + "label": "Reply as User", + "desc": "Chat with Open Assistant and help improve it's responses as you interact with it.", + "overview": "Given the following conversation, provide an adequate reply", + "instruction": "Provide the user's reply", + "response_placeholder": "Write your reply here..." + } +} diff --git a/website/public/locales/ru/tos.json b/website/public/locales/ru/tos.json index a97cf7a0..3c04e9dd 100644 --- a/website/public/locales/ru/tos.json +++ b/website/public/locales/ru/tos.json @@ -1,6 +1,6 @@ { - "title": "Пользовательское Соглашение Open Assistant", - "content": "Чтобы продолжить работу с Open Assistant, вам необходимо принять наше Пользовательское Соглашение.", "accept": "Принять", - "decline": "Отклонить" + "content": "Чтобы продолжить работу с Open Assistant, вам необходимо принять наше Пользовательское Соглашение.", + "decline": "Отклонить", + "title": "Пользовательское Соглашение Open Assistant" } diff --git a/website/public/locales/tr/common.json b/website/public/locales/tr/common.json index 6eefd3a3..bd220d7c 100644 --- a/website/public/locales/tr/common.json +++ b/website/public/locales/tr/common.json @@ -2,9 +2,9 @@ "about": "Hakkında", "account_settings": "Hesap", "admin_dashboard": "Yönetici Paneli", - "copied": "Kopyalandı", "connect": "Bağlan", "conversational": "Herkes için etkileşimli AI", + "copied": "Kopyalandı", "dark_mode": "Karanlık Mod", "dashboard": "Kontrol Paneli", "delete": "Sil", diff --git a/website/public/locales/tr/dashboard.json b/website/public/locales/tr/dashboard.json index 01ce0d2b..89e614b7 100644 --- a/website/public/locales/tr/dashboard.json +++ b/website/public/locales/tr/dashboard.json @@ -1,8 +1,8 @@ { - "grab_a_task": "Bir görev al!", "create": "Oluştur", - "evaluate": "Değerlendir", - "label": "Etiketle", "dashboard": "Kontrol Paneli", - "go": "Başlat" + "evaluate": "Değerlendir", + "go": "Başlat", + "grab_a_task": "Bir görev al!", + "label": "Etiketle" } diff --git a/website/public/locales/tr/labelling.json b/website/public/locales/tr/labelling.json index 6bf5db0e..d37eef0b 100644 --- a/website/public/locales/tr/labelling.json +++ b/website/public/locales/tr/labelling.json @@ -1,24 +1,24 @@ { - "label_highlighted_yes_no_instruction": "Vurgulanan mesaj hakkındaki soruları cevaplayın:", + "fails_task.question": "Sorulan soruya göre kötü bir cevap mı?", + "hate_speech": "Nefret Söylemi", + "hate_speech.explanation": "İçerik taciz veya tehdit edici ve korunan bir özelliğe karşı önyargı ifade ediyor. Önyargı, nedenselliğe dayanmayan önyargılı görüşleri ifade eder. Korunan karakteristikler cinsiyet, etnik köken, din, cinsel yönelim ve benzeri özellikleri içerir.", "label_highlighted_flag_instruction": "Vurgulanan mesajla uyuşanları seçin:", "label_highlighted_likert_instruction": "Vurgulanan mesajı değerlendirin:", - "label_message_yes_no_instruction": "Mesaj hakkındaki soruları cevaplayın:", + "label_highlighted_yes_no_instruction": "Vurgulanan mesaj hakkındaki soruları cevaplayın:", "label_message_flag_instruction": "Mesajla uyuşanları seçin:", "label_message_likert_instruction": "Mesajı değerlendirin:", - "spam.question": "Bu mesaj spam mı?", - "fails_task.question": "Sorulan soruya göre kötü bir cevap mı?", + "label_message_yes_no_instruction": "Mesaj hakkındaki soruları cevaplayın:", + "lang_mismatch": "Yanlış Dil", + "lang_mismatch.explanation": "Seçilen dilde yazılmamış.", + "moral_judgement": "Ahlaki Yargı", + "moral_judgement.explanation": "Ahlaki yargı içeriyor.", "not_appropriate": "Uygunsuz", "not_appropriate.explanation": "Bir tüketici asistanı için uygunsuz", "pii": "PII İçeriyor", "pii.explanation": "Kişilik özelliklerini ortaya çıkaran bilgi (PII) içeriyor. Kişisel iletişim bilgileri, kimlik bilgileri ve diğer kişisel bilgiler ve bancakılık bilgileri buna örnek olabilir.", - "hate_speech": "Nefret Söylemi", - "hate_speech.explanation": "İçerik taciz veya tehdit edici ve korunan bir özelliğe karşı önyargı ifade ediyor. Önyargı, nedenselliğe dayanmayan önyargılı görüşleri ifade eder. Korunan karakteristikler cinsiyet, etnik köken, din, cinsel yönelim ve benzeri özellikleri içerir.", - "sexual_content": "Cinsel İçerik", - "sexual_content.explanation": "Cinsel içerik içeriyor.", - "moral_judgement": "Ahlaki Yargı", - "moral_judgement.explanation": "Ahlaki yargı içeriyor.", "political_content": "Politik İçerik", "political_content.explanation": "Politik görüş içeriyor.", - "lang_mismatch": "Yanlış Dil", - "lang_mismatch.explanation": "Seçilen dilde yazılmamış." + "sexual_content": "Cinsel İçerik", + "sexual_content.explanation": "Cinsel içerik içeriyor.", + "spam.question": "Bu mesaj spam mı?" } diff --git a/website/public/locales/tr/leaderboard.json b/website/public/locales/tr/leaderboard.json index ad59e068..f6e1bbde 100644 --- a/website/public/locales/tr/leaderboard.json +++ b/website/public/locales/tr/leaderboard.json @@ -1,18 +1,18 @@ { "daily": "Günlük", + "label": "Etiketler", "last_updated_at": "Son güncelleme: {{val, datetime}}", "leaderboard": "Skor Tablosu", "monthly": "Aylık", + "next": "Geri", "overall": "Genel", - "rank": "Sıralama", - "score": "Skor", - "user": "Kullanıcı", - "weekly": "Haftalık", - "prompt": "Promptlar", - "reply": "Cevaplar", - "label": "Etiketler", - "view_all": "Tümünü Gör", - "top_5_contributors_today": "Bugünün En İyi 5 Katkıda Bulunanı", "previous": "İleri", - "next": "Geri" + "prompt": "Promptlar", + "rank": "Sıralama", + "reply": "Cevaplar", + "score": "Skor", + "top_5_contributors_today": "Bugünün En İyi 5 Katkıda Bulunanı", + "user": "Kullanıcı", + "view_all": "Tümünü Gör", + "weekly": "Haftalık" } diff --git a/website/public/locales/tr/message.json b/website/public/locales/tr/message.json index a8db8bcf..3420ecf3 100644 --- a/website/public/locales/tr/message.json +++ b/website/public/locales/tr/message.json @@ -2,8 +2,8 @@ "copy_message_id": "Mesaj ID'sini kopyala", "label_action": "Etiket", "label_title": "Etiket", - "message_deleted": "Mesaj silindi", "message": "Mesaj", + "message_deleted": "Mesaj silindi", "open_new_tab_action": "Yeni sekmede aç", "parent": "Üst", "reactions": "Reaksiyonlar", diff --git a/website/public/locales/tr/side_menu.json b/website/public/locales/tr/side_menu.json index e963ff61..8add2136 100644 --- a/website/public/locales/tr/side_menu.json +++ b/website/public/locales/tr/side_menu.json @@ -1,12 +1,12 @@ { "dashboard": "Kontrol Paneli", "dashboard_home": "Kontrol Paneli Ana Sayfa", + "leaderboard": "Lider Tablosu", "messages": "Mesajlar", "messages_dashboard": "Mesaj Kontrol Paneli", - "leaderboard": "Lider Tablosu", + "status": "Durum", + "status_dashboard": "Durum Kontrol Paneli", "user_leaderboard": "Kullanıcı Lider Tablosu", "users": "Kullanıcılar", - "users_dashboard": "Kullanıcı Kontrol Paneli", - "status": "Durum", - "status_dashboard": "Durum Kontrol Paneli" + "users_dashboard": "Kullanıcı Kontrol Paneli" } diff --git a/website/public/locales/tr/tasks.json b/website/public/locales/tr/tasks.json index 0e7a53d4..5b18df3a 100644 --- a/website/public/locales/tr/tasks.json +++ b/website/public/locales/tr/tasks.json @@ -1,11 +1,19 @@ { - "default": { - "unchanged_title": "Değişiklik yok", - "unchanged_message": "Devam etmek istediğinizden emin misiniz?" + "available_task_count": "{{count}} görev mevcut", + "classify_assistant_reply": { + "label": "Asistan Yanıtını Sınıflandır", + "desc": "Prompt için etiketler sağlayın", + "overview": "Aşağıdaki konuşmayı oku ve tartışma kısmındaki son soruya cevap ver." }, - "random": { - "label": "Şanslı hissediyorum", - "desc": "Open Assistant'ı geliştirmemize yardımcı olmak için rastgele bir göreve başlayın." + "classify_initial_prompt": { + "label": "Başlangıç Promptlarını Sınıflandır", + "desc": "Prompt için etiketler sağlayın", + "overview": "Aşağıdaki promptu oku ve sonraki soruya cevap ver." + }, + "classify_prompter_reply": { + "label": "Promptçu Yanıtını Sınıflandır", + "desc": "Prompt için etiketler sağlayın", + "overview": "Aşağıdaki konuşmayı oku ve tartışma kısmındaki son soruya cevap ver." }, "create_initial_prompt": { "label": "Başlangıc Promptlarını Oluştur", @@ -14,25 +22,28 @@ "instruction": "Başlangıç ​​promptlarını sağlayın", "response_placeholder": "Promptunuzu buraya yazın..." }, - "reply_as_user": { - "label": "Kullanıcı Olarak Yanıtla", - "desc": "Open Assistant ile sohbet edin ve onunla etkileşimde bulunurken yanıtlarını geliştirmeye yardımcı olun.", - "overview": "Aşağıdaki konuşmaya göre uygun bir yanıt verin", - "instruction": "Kullanıcının yanıtını paylaşın", - "response_placeholder": "Yanıtınızı buraya yazın..." + "default": { + "unchanged_title": "Değişiklik yok", + "unchanged_message": "Devam etmek istediğinizden emin misiniz?" }, - "reply_as_assistant": { - "label": "Asistan Olarak Yanıtla", - "desc": "Open Asistant'a kullanıcılar ile iletişim kurmasını geliştirmesinde yardımcı olun.", - "overview": "Aşağıdaki konuşmaya göre uygun bir yanıt verin", - "response_placeholder": "Yanıtınızı buraya yazın..." + "label_assistant_reply": { + "label": "Asistan Yanıtını Etiketle", + "desc": "Prompt için etiketler sağlayın.", + "overview": "Takip eden konuşmalar göz önünde bulundurularak son prompt için etiket sağlayın." }, - "rank_user_replies": { - "label": "Kullanıcı Yanıtlarını Değerlendir", - "desc": "Open Asistant'a kullanıcılar ile iletişim kurmasını geliştirmesinde yardımcı olun..", - "overview": "Aşağıdaki kullanıcı yanıtlarını en iyiden en kötüye doğru sıralayın, en iyi ilk, en kötü son.", - "unchanged_title": "Sıralama Değişmedi", - "unchanged_message": "Yanıtların sırasını değiştirmediniz. Devam etmek istediğinizden emin misiniz?" + "label_initial_prompt": { + "label": "Başlangıç Promptlarını Etiketle", + "desc": "Prompt için etiketler sağlayın", + "overview": "Aşağıdaki prompt için etiketler sağlayın" + }, + "label_prompter_reply": { + "label": "Promptçu Yanıtını Etiketle", + "desc": "Prompt için etiketler sağlayın", + "overview": "Takip eden konuşmalar göz önünde bulundurularak son prompt için etiket sağlayın." + }, + "random": { + "label": "Şanslı hissediyorum", + "desc": "Open Assistant'ı geliştirmemize yardımcı olmak için rastgele bir göreve başlayın." }, "rank_assistant_replies": { "label": "Asistant Yanıtlarını Değerlendir", @@ -48,35 +59,24 @@ "unchanged_title": "Sıralama Değişmedi", "unchanged_message": "Yanıtların sırasını değiştirmediniz. Devam etmek istediğinizden emin misiniz?" }, - "label_initial_prompt": { - "label": "Başlangıç Promptlarını Etiketle", - "desc": "Prompt için etiketler sağlayın", - "overview": "Aşağıdaki prompt için etiketler sağlayın" + "rank_user_replies": { + "label": "Kullanıcı Yanıtlarını Değerlendir", + "desc": "Open Asistant'a kullanıcılar ile iletişim kurmasını geliştirmesinde yardımcı olun..", + "overview": "Aşağıdaki kullanıcı yanıtlarını en iyiden en kötüye doğru sıralayın, en iyi ilk, en kötü son.", + "unchanged_title": "Sıralama Değişmedi", + "unchanged_message": "Yanıtların sırasını değiştirmediniz. Devam etmek istediğinizden emin misiniz?" }, - "label_prompter_reply": { - "label": "Promptçu Yanıtını Etiketle", - "desc": "Prompt için etiketler sağlayın", - "overview": "Takip eden konuşmalar göz önünde bulundurularak son prompt için etiket sağlayın." + "reply_as_assistant": { + "label": "Asistan Olarak Yanıtla", + "desc": "Open Asistant'a kullanıcılar ile iletişim kurmasını geliştirmesinde yardımcı olun.", + "overview": "Aşağıdaki konuşmaya göre uygun bir yanıt verin", + "response_placeholder": "Yanıtınızı buraya yazın..." }, - "label_assistant_reply": { - "label": "Asistan Yanıtını Etiketle", - "desc": "Prompt için etiketler sağlayın.", - "overview": "Takip eden konuşmalar göz önünde bulundurularak son prompt için etiket sağlayın." - }, - "classify_initial_prompt": { - "label": "Başlangıç Promptlarını Sınıflandır", - "desc": "Prompt için etiketler sağlayın", - "overview": "Aşağıdaki promptu oku ve sonraki soruya cevap ver." - }, - "classify_prompter_reply": { - "label": "Promptçu Yanıtını Sınıflandır", - "desc": "Prompt için etiketler sağlayın", - "overview": "Aşağıdaki konuşmayı oku ve tartışma kısmındaki son soruya cevap ver." - }, - "classify_assistant_reply": { - "label": "Asistan Yanıtını Sınıflandır", - "desc": "Prompt için etiketler sağlayın", - "overview": "Aşağıdaki konuşmayı oku ve tartışma kısmındaki son soruya cevap ver." - }, - "available_task_count": "{{count}} görev mevcut" + "reply_as_user": { + "label": "Kullanıcı Olarak Yanıtla", + "desc": "Open Assistant ile sohbet edin ve onunla etkileşimde bulunurken yanıtlarını geliştirmeye yardımcı olun.", + "overview": "Aşağıdaki konuşmaya göre uygun bir yanıt verin", + "instruction": "Kullanıcının yanıtını paylaşın", + "response_placeholder": "Yanıtınızı buraya yazın..." + } } diff --git a/website/public/locales/tr/tos.json b/website/public/locales/tr/tos.json index 8d0a0797..47882fd3 100644 --- a/website/public/locales/tr/tos.json +++ b/website/public/locales/tr/tos.json @@ -1,6 +1,6 @@ { - "title": "Open Assistant için Kullanım Şartları", - "content": "Open Assistant'ı kullanmaya devam etmek için ilk önce Kullanım Şartları'nı kabul etmeniz gerekmektedir.", "accept": "Kabul Et", - "decline": "Reddet" + "content": "Open Assistant'ı kullanmaya devam etmek için ilk önce Kullanım Şartları'nı kabul etmeniz gerekmektedir.", + "decline": "Reddet", + "title": "Open Assistant için Kullanım Şartları" } diff --git a/website/public/locales/uk-UA/common.json b/website/public/locales/uk-UA/common.json index 0abd4f17..8f8829ea 100644 --- a/website/public/locales/uk-UA/common.json +++ b/website/public/locales/uk-UA/common.json @@ -2,9 +2,9 @@ "about": "Про проєкт", "account_settings": "Аккаунт", "admin_dashboard": "Панель адміністратора", - "copied": "Скопійовано", "connect": "Приєднати", "conversational": "Розмовний ШІ для кожного.", + "copied": "Скопійовано", "dark_mode": "Темний режим", "dashboard": "Головна панель", "delete": "Видалити", diff --git a/website/public/locales/uk-UA/dashboard.json b/website/public/locales/uk-UA/dashboard.json index 5309fff5..1f323748 100644 --- a/website/public/locales/uk-UA/dashboard.json +++ b/website/public/locales/uk-UA/dashboard.json @@ -1,8 +1,8 @@ { - "grab_a_task": "Взяти задачу!", "create": "Створити", - "evaluate": "Оцінити", - "label": "Класифікувати", "dashboard": "Головна панель", - "go": "Go" + "evaluate": "Оцінити", + "go": "Go", + "grab_a_task": "Взяти задачу!", + "label": "Класифікувати" } diff --git a/website/public/locales/uk-UA/labelling.json b/website/public/locales/uk-UA/labelling.json index 610f2ae0..beea5bbd 100644 --- a/website/public/locales/uk-UA/labelling.json +++ b/website/public/locales/uk-UA/labelling.json @@ -1,24 +1,24 @@ { - "label_highlighted_yes_no_instruction": "Дайте відповідь на наступне (наступні) запитання щодо виділеного повідомлення:", + "fails_task.question": "Чи є це поганою відповіддю, у відповідності до поставленого завдання?", + "hate_speech": "Розпалювання ворожнечі", + "hate_speech.explanation": "Контент є образливим або погрозливим і виражає упередження щодо захищеної ознаки. Упередження - це упереджені погляди, що не ґрунтуються на розумінні. До захищених ознак належать стать, етнічна приналежність, релігія, сексуальна орієнтація та подібні характеристики.", "label_highlighted_flag_instruction": "Виберіть те, що підходить для виділеного повідомлення:", "label_highlighted_likert_instruction": "Оцініть виділене повідомлення:", - "label_message_yes_no_instruction": "Дайте відповідь на наступне (наступні) запитання щодо повідомлення:", + "label_highlighted_yes_no_instruction": "Дайте відповідь на наступне (наступні) запитання щодо виділеного повідомлення:", "label_message_flag_instruction": "Виберіть ті, що відповідають повідомленню:", "label_message_likert_instruction": "Оцініть повідомлення:", - "spam.question": "Це повідомлення є спамом?", - "fails_task.question": "Чи є це поганою відповіддю, у відповідності до поставленого завдання?", + "label_message_yes_no_instruction": "Дайте відповідь на наступне (наступні) запитання щодо повідомлення:", + "lang_mismatch": "Некоретна мова", + "lang_mismatch.explanation": "Не написано вибраною мовою.", + "moral_judgement": "Моральне судження", + "moral_judgement.explanation": "Висловлює моральне судження.", "not_appropriate": "Недоречно", "not_appropriate.explanation": "Недоречно для асистента.", "pii": "Містить особисті дані", "pii.explanation": "Містить інформацію, що ідентифікує особу. Приклади включають особисті контактні дані, деталі паспорта та інших документів, що посвідчують особу, а також банківські реквізити.", - "hate_speech": "Розпалювання ворожнечі", - "hate_speech.explanation": "Контент є образливим або погрозливим і виражає упередження щодо захищеної ознаки. Упередження - це упереджені погляди, що не ґрунтуються на розумінні. До захищених ознак належать стать, етнічна приналежність, релігія, сексуальна орієнтація та подібні характеристики.", - "sexual_content": "Зміст сексуального характеру", - "sexual_content.explanation": "Містить матеріали сексуального характеру.", - "moral_judgement": "Моральне судження", - "moral_judgement.explanation": "Висловлює моральне судження.", "political_content": "Політичне", "political_content.explanation": "Висловлює політичні погляди.", - "lang_mismatch": "Некоретна мова", - "lang_mismatch.explanation": "Не написано вибраною мовою." + "sexual_content": "Зміст сексуального характеру", + "sexual_content.explanation": "Містить матеріали сексуального характеру.", + "spam.question": "Це повідомлення є спамом?" } diff --git a/website/public/locales/uk-UA/leaderboard.json b/website/public/locales/uk-UA/leaderboard.json index c3c160f8..2f7523d5 100644 --- a/website/public/locales/uk-UA/leaderboard.json +++ b/website/public/locales/uk-UA/leaderboard.json @@ -1,18 +1,18 @@ { "daily": "За день", + "label": "Маркувань", "last_updated_at": "Останній раз оновлено: {{val, datetime}}", "leaderboard": "Рейтинг лідерів", "monthly": "За місяць", + "next": "Наступна", "overall": "Всього", - "rank": "Рейтинг", - "score": "Бали", - "user": "Користувач", - "weekly": "За тиждень", - "prompt": "Текстів", - "reply": "Відповідей", - "label": "Маркувань", - "view_all": "Подивись усіх", - "top_5_contributors_today": "Топ-5 учасників сьогодні", "previous": "Попередня", - "next": "Наступна" + "prompt": "Текстів", + "rank": "Рейтинг", + "reply": "Відповідей", + "score": "Бали", + "top_5_contributors_today": "Топ-5 учасників сьогодні", + "user": "Користувач", + "view_all": "Подивись усіх", + "weekly": "За тиждень" } diff --git a/website/public/locales/uk-UA/message.json b/website/public/locales/uk-UA/message.json index f3b82e3c..34b30def 100644 --- a/website/public/locales/uk-UA/message.json +++ b/website/public/locales/uk-UA/message.json @@ -2,8 +2,8 @@ "copy_message_id": "Скопіювати ID повідомлення", "label_action": "Маркувати", "label_title": "Маркування", - "message_deleted": "Повідомлення видалено", "message": "Повідомлення", + "message_deleted": "Повідомлення видалено", "open_new_tab_action": "Відкрити в новій вкладці", "parent": "Parent", "reactions": "Реакції", diff --git a/website/public/locales/uk-UA/side_menu.json b/website/public/locales/uk-UA/side_menu.json index b27d0890..4111a0c7 100644 --- a/website/public/locales/uk-UA/side_menu.json +++ b/website/public/locales/uk-UA/side_menu.json @@ -1,12 +1,12 @@ { "dashboard": "Головна", "dashboard_home": "Головна панель", + "leaderboard": "Рейтинг лідерів", "messages": "Повідомлення", "messages_dashboard": "Панель повідомлень", - "leaderboard": "Рейтинг лідерів", + "status": "Статус", + "status_dashboard": "Панель статусів", "user_leaderboard": "User Leaderboard", "users": "Користувачі", - "users_dashboard": "Панель користувачів", - "status": "Статус", - "status_dashboard": "Панель статусів" + "users_dashboard": "Панель користувачів" } diff --git a/website/public/locales/uk-UA/tasks.json b/website/public/locales/uk-UA/tasks.json index bc2122d3..ab1a72f7 100644 --- a/website/public/locales/uk-UA/tasks.json +++ b/website/public/locales/uk-UA/tasks.json @@ -1,11 +1,19 @@ { - "default": { - "unchanged_title": "Без змін", - "unchanged_message": "Ви впевнені, що хочете продовжити?" + "available_task_count": "{{count}} задач доступно", + "classify_assistant_reply": { + "label": "Класифікувати відповідь асистента", + "desc": "Надайте мітки для тексту.", + "overview": "Прочитайте наступну розмову, а потім дайте відповідь на запитання щодо останньої відповіді в дискусії." }, - "random": { - "label": "Нехай мені пощастить", - "desc": "Допоможіть нам покращити Open Assistant, запустивши випадкове завдання." + "classify_initial_prompt": { + "label": "Класифікувати початковий текст", + "desc": "Надайте мітки для тексту.", + "overview": "Прочитайте наступний текст, а потім дайте відповідь на запитання до нього." + }, + "classify_prompter_reply": { + "label": "Класифікувати відповідь до запиту", + "desc": "Надайте мітки для тексту.", + "overview": "Прочитайте наступну розмову, а потім дайте відповідь на запитання щодо останньої відповіді в дискусії." }, "create_initial_prompt": { "label": "Створіть початкові тексти", @@ -14,25 +22,28 @@ "instruction": "Надайте початкові тексти", "response_placeholder": "Напишіть своє запитання тут..." }, - "reply_as_user": { - "label": "Відповісти як користувач", - "desc": "Спілкуйтеся з Open Assistant і допомагайте покращувати його відповіді, взаємодіючи з ним.", - "overview": "З огляду на наступну розмову, надайте адекватну відповідь", - "instruction": "Надати відповідь користувача", - "response_placeholder": "Напишіть свою відповідь тут..." + "default": { + "unchanged_title": "Без змін", + "unchanged_message": "Ви впевнені, що хочете продовжити?" }, - "reply_as_assistant": { - "label": "Відповісти як асистент", - "desc": "Допоможіть Open Assistant покращити його реакцію на розмови з іншими користувачами.", - "overview": "З огляду на наступну розмову, надайте адекватну відповідь", - "response_placeholder": "Напишіть свою відповідь тут..." + "label_assistant_reply": { + "label": "Промаркуйте відповідь асистента", + "desc": "Надайте мітки для тексту.", + "overview": "Враховуючи наступну дискусію, промаркуйте останній текст." }, - "rank_user_replies": { - "label": "Ранжування відповідей користувачів", - "desc": "Допоможіть Open Assistant покращити його реакцію на розмови з іншими користувачами.", - "overview": "Отримавши відповіді користувачів, відсортуйте їх від найкращого до найгіршого, де найкращий - на першому місці, найгірший - на останньому.", - "unchanged_title": "Порядок не змінено", - "unchanged_message": "Ви не змінили порядок текстів. Ви впевнені, що хочете продовжити?" + "label_initial_prompt": { + "label": "Промаркуйте початковий текст", + "desc": "Надайте мітки для тексту.", + "overview": "Надайте мітки для вказаного тексту." + }, + "label_prompter_reply": { + "label": "Промаркуйте відповідь до запиту", + "desc": "Надайте мітки для тексту.", + "overview": "Враховуючи наступну дискусію, промаркуйте останній текст." + }, + "random": { + "label": "Нехай мені пощастить", + "desc": "Допоможіть нам покращити Open Assistant, запустивши випадкове завдання." }, "rank_assistant_replies": { "label": "Ранжування відповідей асистента", @@ -48,35 +59,24 @@ "unchanged_title": "Порядок не змінено", "unchanged_message": "Ви не змінили порядок текстів. Ви впевнені, що хочете продовжити?" }, - "label_initial_prompt": { - "label": "Промаркуйте початковий текст", - "desc": "Надайте мітки для тексту.", - "overview": "Надайте мітки для вказаного тексту." + "rank_user_replies": { + "label": "Ранжування відповідей користувачів", + "desc": "Допоможіть Open Assistant покращити його реакцію на розмови з іншими користувачами.", + "overview": "Отримавши відповіді користувачів, відсортуйте їх від найкращого до найгіршого, де найкращий - на першому місці, найгірший - на останньому.", + "unchanged_title": "Порядок не змінено", + "unchanged_message": "Ви не змінили порядок текстів. Ви впевнені, що хочете продовжити?" }, - "label_prompter_reply": { - "label": "Промаркуйте відповідь до запиту", - "desc": "Надайте мітки для тексту.", - "overview": "Враховуючи наступну дискусію, промаркуйте останній текст." + "reply_as_assistant": { + "label": "Відповісти як асистент", + "desc": "Допоможіть Open Assistant покращити його реакцію на розмови з іншими користувачами.", + "overview": "З огляду на наступну розмову, надайте адекватну відповідь", + "response_placeholder": "Напишіть свою відповідь тут..." }, - "label_assistant_reply": { - "label": "Промаркуйте відповідь асистента", - "desc": "Надайте мітки для тексту.", - "overview": "Враховуючи наступну дискусію, промаркуйте останній текст." - }, - "classify_initial_prompt": { - "label": "Класифікувати початковий текст", - "desc": "Надайте мітки для тексту.", - "overview": "Прочитайте наступний текст, а потім дайте відповідь на запитання до нього." - }, - "classify_prompter_reply": { - "label": "Класифікувати відповідь до запиту", - "desc": "Надайте мітки для тексту.", - "overview": "Прочитайте наступну розмову, а потім дайте відповідь на запитання щодо останньої відповіді в дискусії." - }, - "classify_assistant_reply": { - "label": "Класифікувати відповідь асистента", - "desc": "Надайте мітки для тексту.", - "overview": "Прочитайте наступну розмову, а потім дайте відповідь на запитання щодо останньої відповіді в дискусії." - }, - "available_task_count": "{{count}} задач доступно" + "reply_as_user": { + "label": "Відповісти як користувач", + "desc": "Спілкуйтеся з Open Assistant і допомагайте покращувати його відповіді, взаємодіючи з ним.", + "overview": "З огляду на наступну розмову, надайте адекватну відповідь", + "instruction": "Надати відповідь користувача", + "response_placeholder": "Напишіть свою відповідь тут..." + } } diff --git a/website/public/locales/uk-UA/tos.json b/website/public/locales/uk-UA/tos.json index 70856379..eed89b9d 100644 --- a/website/public/locales/uk-UA/tos.json +++ b/website/public/locales/uk-UA/tos.json @@ -1,6 +1,6 @@ { - "title": "Умови надання послуг для Open Assistant", - "content": "Щоб продовжити користуватися Open Assistant, ви повинні спочатку прийняти наші Умови надання послуг.", "accept": "Прийняти", - "decline": "Відхилити" + "content": "Щоб продовжити користуватися Open Assistant, ви повинні спочатку прийняти наші Умови надання послуг.", + "decline": "Відхилити", + "title": "Умови надання послуг для Open Assistant" } diff --git a/website/public/locales/vi/common.json b/website/public/locales/vi/common.json index 2239f392..9896e4c2 100644 --- a/website/public/locales/vi/common.json +++ b/website/public/locales/vi/common.json @@ -4,12 +4,15 @@ "admin_dashboard": "Trang cho admin", "connect": "Liên hệ", "conversational": "Chatbot AI cho tất cả mọi người", + "copied": "Copied", + "dark_mode": "Giao diện tối", "dashboard": "Trang chính", "delete": "Xoá", "discord": "Discord", "docs": "Hướng dẫn", "github": "GitHub", "legal": "Luật lệ", + "light_mode": "Giao diện sáng", "loading": "Đang tải...", "more_information": "Xem thêm", "no": "Không", @@ -17,9 +20,8 @@ "report_a_bug": "Báo lỗi", "sign_in": "Đăng nhập", "sign_out": "Đăng xuất", + "success": "Success", "terms_of_service": "Điều khoản sử dụng", "title": "Open Assistant", - "yes": "Có", - "dark_mode": "Giao diện tối", - "light_mode": "Giao diện sáng" + "yes": "Có" } diff --git a/website/public/locales/vi/dashboard.json b/website/public/locales/vi/dashboard.json index 1bd2e880..a4cb4e2f 100644 --- a/website/public/locales/vi/dashboard.json +++ b/website/public/locales/vi/dashboard.json @@ -1,8 +1,8 @@ { - "grab_a_task": "Danh sách việc", "create": "Tạo", - "evaluate": "Kiểm tra", - "label": "Nhãn", "dashboard": "Trang chính", - "go": "Xem" + "evaluate": "Kiểm tra", + "go": "Xem", + "grab_a_task": "Danh sách việc", + "label": "Nhãn" } diff --git a/website/public/locales/vi/labelling.json b/website/public/locales/vi/labelling.json index 3169cc6b..4bb6d01d 100644 --- a/website/public/locales/vi/labelling.json +++ b/website/public/locales/vi/labelling.json @@ -1,24 +1,24 @@ { - "label_highlighted_yes_no_instruction": "Trả lời các câu hỏi sau:", + "fails_task.question": "Tin nhắn có lạc đề và không trả lời câu hỏi ở trên không?", + "hate_speech": "Gây kích động", + "hate_speech.explanation": "Tin nhắn gây kích động và có định kiến dựa trên giới tính, dân tộc, tôn giáo, vân vân.", "label_highlighted_flag_instruction": "Chọn tất cả các mục mà áp dụng với tin nhắn:", "label_highlighted_likert_instruction": "Đánh giá tin nhắn:", - "label_message_yes_no_instruction": "Trả lời các câu hỏi sau:", + "label_highlighted_yes_no_instruction": "Trả lời các câu hỏi sau:", "label_message_flag_instruction": "Chọn tất cả các mục mà áp dụng với tin nhắn:", "label_message_likert_instruction": "Đánh giá tin nhắn:", - "spam.question": "Tin nhắn có phải là spam không?", - "fails_task.question": "Tin nhắn có lạc đề và không trả lời câu hỏi ở trên không?", + "label_message_yes_no_instruction": "Trả lời các câu hỏi sau:", + "lang_mismatch": "Sai ngôn ngữ", + "lang_mismatch.explanation": "Tin nhắn không được viết trong ngôn ngữ được chọn.", + "moral_judgement": "Phán xét đạo đức", + "moral_judgement.explanation": "Tin nhắn phán xét đạo đức.", "not_appropriate": "Không phù hợp", "not_appropriate.explanation": "Tin nhắn không phù hợp và chuyên nghiệp.", "pii": "Chứa thông tin cá nhân", "pii.explanation": "Tin nhắn chứa thông tin cá nhân như số điện thoại, email, địa chỉ nhà, số thẻ tín dụng, vân vân.", - "hate_speech": "Gây kích động", - "hate_speech.explanation": "Tin nhắn gây kích động và có định kiến dựa trên giới tính, dân tộc, tôn giáo, vân vân.", - "sexual_content": "Nội dung khiêu dâm", - "sexual_content.explanation": "Tin nhắn chứa nội dung khiêu dâm như nude.", - "moral_judgement": "Phán xét đạo đức", - "moral_judgement.explanation": "Tin nhắn phán xét đạo đức.", "political_content": "Liên quan tới chính trị", "political_content.explanation": "Tin nhắn đưa ra quan điểm chính trị.", - "lang_mismatch": "Sai ngôn ngữ", - "lang_mismatch.explanation": "Tin nhắn không được viết trong ngôn ngữ được chọn." + "sexual_content": "Nội dung khiêu dâm", + "sexual_content.explanation": "Tin nhắn chứa nội dung khiêu dâm như nude.", + "spam.question": "Tin nhắn có phải là spam không?" } diff --git a/website/public/locales/vi/leaderboard.json b/website/public/locales/vi/leaderboard.json index 2eb3bde3..ebe25dda 100644 --- a/website/public/locales/vi/leaderboard.json +++ b/website/public/locales/vi/leaderboard.json @@ -1,18 +1,18 @@ { "daily": "Ngày", + "label": "Nhãn", "last_updated_at": "Cập nhật lần cuối: {{val, datetime}}", "leaderboard": "Bảng xếp hạng", "monthly": "Tháng", + "next": "Tiếp", "overall": "Tổng quan", - "rank": "Xếp hạng", - "score": "Điểm", - "user": "Tên người dùng", - "weekly": "Tuần", - "prompt": "Câu đầu tiên", - "reply": "Câu trả lời", - "label": "Nhãn", - "view_all": "Nhìn tất cả", - "top_5_contributors_today": "Top 5 người đóng góp", "previous": "Trước", - "next": "Tiếp" + "prompt": "Câu đầu tiên", + "rank": "Xếp hạng", + "reply": "Câu trả lời", + "score": "Điểm", + "top_5_contributors_today": "Top 5 người đóng góp", + "user": "Tên người dùng", + "view_all": "Nhìn tất cả", + "weekly": "Tuần" } diff --git a/website/public/locales/vi/message.json b/website/public/locales/vi/message.json index b90339e8..baabe4b6 100644 --- a/website/public/locales/vi/message.json +++ b/website/public/locales/vi/message.json @@ -1,16 +1,20 @@ { + "copy_message_id": "Copy message ID", "label_action": "Nhãn", "label_title": "Nhãn", "message": "Tin nhắn", + "message_deleted": "Message deleted", "open_new_tab_action": "Mở ở trang mới", "parent": "Tin nhắn gốc", "reactions": "Bình luận", + "recent_messages": "Tin nhắn gần đây", "report_action": "Báo cáo", "report_placeholder": "Tại sao tin nhắn này cần được báo cáo?", "report_title": "Báo cáo", "send_report": "Gửi", + "stop_tree": "Stop tree", "submit_labels": "Gửi", + "tree_stopped": "Tree stopped {{id}}", "view_user": "Xem người dùng", - "recent_messages": "Tin nhắn gần đây", "your_recent_messages": "Tin nhắn gần đây của bạn" } diff --git a/website/public/locales/vi/side_menu.json b/website/public/locales/vi/side_menu.json index da9ae2c9..6b06846f 100644 --- a/website/public/locales/vi/side_menu.json +++ b/website/public/locales/vi/side_menu.json @@ -1,12 +1,12 @@ { "dashboard": "Trang chính", "dashboard_home": "Trang chính", + "leaderboard": "Bảng xếp hạng", "messages": "Tin nhắn", "messages_dashboard": "Bảng xếp hạng tin nhắn", - "leaderboard": "Bảng xếp hạng", + "status": "Tình trạng", + "status_dashboard": "Trang hiện tình trạng", "user_leaderboard": "Bảng xếp hạng người dùng", "users": "Người dùng", - "users_dashboard": "Trang về người dùng", - "status": "Tình trạng", - "status_dashboard": "Trang hiện tình trạng" + "users_dashboard": "Trang về người dùng" } diff --git a/website/public/locales/vi/tasks.json b/website/public/locales/vi/tasks.json index 4a33f7ee..e197c410 100644 --- a/website/public/locales/vi/tasks.json +++ b/website/public/locales/vi/tasks.json @@ -1,11 +1,19 @@ { - "default": { - "unchanged_title": "Chưa thay đổi", - "unchanged_message": "Are you sure you would like to continue?" + "available_task_count": "{{count}} việc", + "classify_assistant_reply": { + "label": "Phân loại tin nhắn của Open Assistant", + "desc": "Tạo nhãn dữ liệu đánh giá tin nhắn.", + "overview": "Từ cuộc trò truyện ở dưới, trả lời các câu hỏi về câu trả lời cuối trong cuộc trò truyện." }, - "random": { - "label": "Chọn ngẫu nhiên", - "desc": "Giúp cải thiện Open Assistant bằng cách làm một việc ngẫu nhiên." + "classify_initial_prompt": { + "label": "Phân loại tin nhắn đầu", + "desc": "Tạo nhãn dữ liệu đánh giá tin nhắn.", + "overview": "Đọc tin nhắn đầu và trả lời các câu hỏi." + }, + "classify_prompter_reply": { + "label": "Phân loại tin nhắn người dùng", + "desc": "Tạo nhãn dữ liệu đánh giá tin nhắn.", + "overview": "Từ cuộc trò truyện ở dưới, trả lời các câu hỏi về câu trả lời cuối trong cuộc trò truyện." }, "create_initial_prompt": { "label": "Tạo tin nhắn đầu", @@ -14,25 +22,28 @@ "instruction": "Viết tin nhắn đầu", "response_placeholder": "Viết vào đây..." }, - "reply_as_user": { - "label": "Đóng vai người dùng", - "desc": "Trò chuyện với Open Assistant và cải thiện con bot.", - "overview": "Tạo câu trả lời phù hợp cho cuộc trò truyện dưới đây", - "instruction": "Viết tin nhắn trả lời", - "response_placeholder": "Viết vào đây..." + "default": { + "unchanged_title": "Chưa thay đổi", + "unchanged_message": "Are you sure you would like to continue?" }, - "reply_as_assistant": { - "label": "Đóng vai Open Assistant", - "desc": "Giúp cải thiện câu trả lời của Open Assistant.", - "overview": "Tạo câu trả lời phù hợp cho cuộc trò truyện dưới đây", - "response_placeholder": "Viết vào đây..." + "label_assistant_reply": { + "label": "Tạo nhãn cho tin nhắn của Open Assistant", + "desc": "Tạo nhãn dữ liệu đánh giá tin nhắn của Open Assistant.", + "overview": "Từ cuộc trò truyện ở dưới, tạo nhãn dữ liệu cho tin nhắn sau." }, - "rank_user_replies": { - "label": "Xếp hạng câu trả lời của người dùng", - "desc": "Giúp cải thiện câu trả lời của Open Assistant.", - "overview": "Từ những câu trả lời của người dùng, xếp hạng chúng theo chất lượng, tốt nhât ở trên, tệ nhất ở dưới.", - "unchanged_title": "Chưa thay đổi thứ tự", - "unchanged_message": "Bạn chưa thay đổi thứ tự tin nhắn. Bạn có chắc muốn lưu không?" + "label_initial_prompt": { + "label": "Tạo nhãn cho tin nhắn đầu", + "desc": "Tạo nhãn dữ liệu đánh giá tin nhắn đầu.", + "overview": "Tạo nhãn dữ liệu cho tin nhắn sau." + }, + "label_prompter_reply": { + "label": "Tạo nhãn cho tin nhắn người dùng", + "desc": "Tạo nhãn dữ liệu đánh giá tin nhắn của người dùng.", + "overview": "Từ cuộc trò truyện ở dưới, tạo nhãn dữ liệu cho tin nhắn sau." + }, + "random": { + "label": "Chọn ngẫu nhiên", + "desc": "Giúp cải thiện Open Assistant bằng cách làm một việc ngẫu nhiên." }, "rank_assistant_replies": { "label": "Xếp hạng câu trả lời của Open Assistant", @@ -48,35 +59,24 @@ "unchanged_title": "Chưa thay đổi thứ tự", "unchanged_message": "Bạn chưa thay đổi thứ tự tin nhắn. Bạn có chắc muốn lưu không?" }, - "label_initial_prompt": { - "label": "Tạo nhãn cho tin nhắn đầu", - "desc": "Tạo nhãn dữ liệu đánh giá tin nhắn đầu.", - "overview": "Tạo nhãn dữ liệu cho tin nhắn sau." + "rank_user_replies": { + "label": "Xếp hạng câu trả lời của người dùng", + "desc": "Giúp cải thiện câu trả lời của Open Assistant.", + "overview": "Từ những câu trả lời của người dùng, xếp hạng chúng theo chất lượng, tốt nhât ở trên, tệ nhất ở dưới.", + "unchanged_title": "Chưa thay đổi thứ tự", + "unchanged_message": "Bạn chưa thay đổi thứ tự tin nhắn. Bạn có chắc muốn lưu không?" }, - "label_prompter_reply": { - "label": "Tạo nhãn cho tin nhắn người dùng", - "desc": "Tạo nhãn dữ liệu đánh giá tin nhắn của người dùng.", - "overview": "Từ cuộc trò truyện ở dưới, tạo nhãn dữ liệu cho tin nhắn sau." + "reply_as_assistant": { + "label": "Đóng vai Open Assistant", + "desc": "Giúp cải thiện câu trả lời của Open Assistant.", + "overview": "Tạo câu trả lời phù hợp cho cuộc trò truyện dưới đây", + "response_placeholder": "Viết vào đây..." }, - "label_assistant_reply": { - "label": "Tạo nhãn cho tin nhắn của Open Assistant", - "desc": "Tạo nhãn dữ liệu đánh giá tin nhắn của Open Assistant.", - "overview": "Từ cuộc trò truyện ở dưới, tạo nhãn dữ liệu cho tin nhắn sau." - }, - "classify_initial_prompt": { - "label": "Phân loại tin nhắn đầu", - "desc": "Tạo nhãn dữ liệu đánh giá tin nhắn.", - "overview": "Đọc tin nhắn đầu và trả lời các câu hỏi." - }, - "classify_prompter_reply": { - "label": "Phân loại tin nhắn người dùng", - "desc": "Tạo nhãn dữ liệu đánh giá tin nhắn.", - "overview": "Từ cuộc trò truyện ở dưới, trả lời các câu hỏi về câu trả lời cuối trong cuộc trò truyện." - }, - "classify_assistant_reply": { - "label": "Phân loại tin nhắn của Open Assistant", - "desc": "Tạo nhãn dữ liệu đánh giá tin nhắn.", - "overview": "Từ cuộc trò truyện ở dưới, trả lời các câu hỏi về câu trả lời cuối trong cuộc trò truyện." - }, - "available_task_count": "{{count}} việc" + "reply_as_user": { + "label": "Đóng vai người dùng", + "desc": "Trò chuyện với Open Assistant và cải thiện con bot.", + "overview": "Tạo câu trả lời phù hợp cho cuộc trò truyện dưới đây", + "instruction": "Viết tin nhắn trả lời", + "response_placeholder": "Viết vào đây..." + } } diff --git a/website/public/locales/vi/tos.json b/website/public/locales/vi/tos.json index d32a012b..46e60035 100644 --- a/website/public/locales/vi/tos.json +++ b/website/public/locales/vi/tos.json @@ -1,6 +1,6 @@ { - "title": "Điều khoản sử dụng của Open Assistant", - "content": "Để tiếp tục sử dụng Open Assistant, bản phải chấp nhận điều khoản sử dụng.", "accept": "Chấp nhận", - "decline": "Không chấp nhận" + "content": "Để tiếp tục sử dụng Open Assistant, bản phải chấp nhận điều khoản sử dụng.", + "decline": "Không chấp nhận", + "title": "Điều khoản sử dụng của Open Assistant" } From 201a9669e0546139a12628e7fd9a1659c44acc7d Mon Sep 17 00:00:00 2001 From: AbdBarho Date: Tue, 7 Feb 2023 06:51:52 +0100 Subject: [PATCH 111/152] Localize the dashboard (#1265) --- website/src/components/Layout.tsx | 12 ++--- website/src/components/SideMenu.tsx | 69 +++++++++++++++-------------- 2 files changed, 42 insertions(+), 39 deletions(-) diff --git a/website/src/components/Layout.tsx b/website/src/components/Layout.tsx index 00a98a71..70e2abdb 100644 --- a/website/src/components/Layout.tsx +++ b/website/src/components/Layout.tsx @@ -37,17 +37,17 @@ export const getDashboardLayout = (page: React.ReactElement) => ( ( From 5d10b28b20f2c55fd06866f802f69babf4a7e729 Mon Sep 17 00:00:00 2001 From: notmd <33456881+notmd@users.noreply.github.com> Date: Tue, 7 Feb 2023 14:17:21 +0700 Subject: [PATCH 112/152] fix leaderboard when current user doesn't have stats (#1289) --- website/src/components/LeaderboardTable/LeaderboardTable.tsx | 4 ++-- website/src/pages/api/leaderboard.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/website/src/components/LeaderboardTable/LeaderboardTable.tsx b/website/src/components/LeaderboardTable/LeaderboardTable.tsx index b775be8d..8451be9e 100644 --- a/website/src/components/LeaderboardTable/LeaderboardTable.tsx +++ b/website/src/components/LeaderboardTable/LeaderboardTable.tsx @@ -34,7 +34,7 @@ export const LeaderboardTable = ({ data: reply, isLoading, error, - } = useSWRImmutable( + } = useSWRImmutable( `/api/leaderboard?time_frame=${timeFrame}&limit=${limit}&includeUserStats=${!hideCurrentUserRanking}`, get ); @@ -79,7 +79,7 @@ export const LeaderboardTable = ({ const start = (page - 1) * rowPerPage; const end = start + rowPerPage; const leaderBoardEntities = reply.leaderboard.slice(start, end); - if (hideCurrentUserRanking) { + if (hideCurrentUserRanking || !reply.user_stats_window) { return leaderBoardEntities; } const userStatsWindow: WindowLeaderboardEntity[] = reply.user_stats_window; diff --git a/website/src/pages/api/leaderboard.ts b/website/src/pages/api/leaderboard.ts index 42f74c3d..8a38a82f 100644 --- a/website/src/pages/api/leaderboard.ts +++ b/website/src/pages/api/leaderboard.ts @@ -29,7 +29,7 @@ const handler = withoutRole("banned", async (req, res, token) => { res.status(200).json({ ...leaderboard, - user_stats_window: user_stats.leaderboard.map((stats) => ({ ...stats, is_window: true })), + user_stats_window: user_stats?.leaderboard.map((stats) => ({ ...stats, is_window: true })), }); }); From eb1c4ada2acb98941820a4c44dd43d10992ef574 Mon Sep 17 00:00:00 2001 From: "jack.butler" Date: Tue, 7 Feb 2023 09:19:24 +0000 Subject: [PATCH 113/152] rename arg name to model_name --- model/supervised_finetuning/utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/model/supervised_finetuning/utils.py b/model/supervised_finetuning/utils.py index 9aba63c7..c3b8264f 100644 --- a/model/supervised_finetuning/utils.py +++ b/model/supervised_finetuning/utils.py @@ -35,13 +35,13 @@ TOKENIZER_CONFIGS = { } -def match_tokenizer_name(name: str) -> TokenizerConfig: +def match_tokenizer_name(model_name: str) -> TokenizerConfig: """Match a partial model name to a tokenizer configuration""" - tokenizer_config_matches = [config for name, config in TOKENIZER_CONFIGS.items() if name in name] + tokenizer_config_matches = [config for name, config in TOKENIZER_CONFIGS.items() if name in model_name] if not tokenizer_config_matches: - raise ValueError(f"Cannot find any tokeniser configuration to match {name=}") + raise ValueError(f"Cannot find any tokeniser configuration to match {model_name=}") elif 1 < len(tokenizer_config_matches): - raise ValueError(f"Found multiple tokeniser configuration matches for {name=}") + raise ValueError(f"Found multiple tokeniser configuration matches for {model_name=}") else: return tokenizer_config_matches[0] From b7d0c4331c2cdb85844534931026789a81a6828e Mon Sep 17 00:00:00 2001 From: notmd <33456881+notmd@users.noreply.github.com> Date: Tue, 7 Feb 2023 17:56:59 +0700 Subject: [PATCH 114/152] Ts strict mode (#1288) part of #879 --- website/package-lock.json | 13 +++++++++++++ website/package.json | 1 + website/src/components/DataTable.tsx | 2 +- website/src/components/UserTable.tsx | 4 ++-- website/src/lib/users.ts | 17 +++++++++++------ website/src/pages/auth/signin.tsx | 11 ++++++----- website/src/pages/auth/verify.tsx | 5 +++-- website/src/pages/messages/[id]/index.tsx | 13 +++++++++---- website/src/pages/tasks/all.tsx | 2 +- website/types/next-auth.d.ts | 7 ++++--- 10 files changed, 51 insertions(+), 24 deletions(-) diff --git a/website/package-lock.json b/website/package-lock.json index 3b8220e5..a785fe29 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -68,6 +68,7 @@ "@storybook/testing-library": "^0.0.13", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", + "@types/accept-language-parser": "^1.5.3", "@types/node": "^18.11.17", "@types/react": "18.0.26", "@typescript-eslint/eslint-plugin": "^5.47.1", @@ -12619,6 +12620,12 @@ "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", "devOptional": true }, + "node_modules/@types/accept-language-parser": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@types/accept-language-parser/-/accept-language-parser-1.5.3.tgz", + "integrity": "sha512-S8oM29O6nnRC3/+rwYV7GBYIIgNIZ52PCxqBG7OuItq9oATnYWy8FfeLKwvq5F7pIYjeeBSCI7y+l+Z9UEQpVQ==", + "dev": true + }, "node_modules/@types/aria-query": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", @@ -47865,6 +47872,12 @@ "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", "devOptional": true }, + "@types/accept-language-parser": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@types/accept-language-parser/-/accept-language-parser-1.5.3.tgz", + "integrity": "sha512-S8oM29O6nnRC3/+rwYV7GBYIIgNIZ52PCxqBG7OuItq9oATnYWy8FfeLKwvq5F7pIYjeeBSCI7y+l+Z9UEQpVQ==", + "dev": true + }, "@types/aria-query": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", diff --git a/website/package.json b/website/package.json index 7ab3f3d8..551a20c6 100644 --- a/website/package.json +++ b/website/package.json @@ -86,6 +86,7 @@ "@storybook/testing-library": "^0.0.13", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", + "@types/accept-language-parser": "^1.5.3", "@types/node": "^18.11.17", "@types/react": "18.0.26", "@typescript-eslint/eslint-plugin": "^5.47.1", diff --git a/website/src/components/DataTable.tsx b/website/src/components/DataTable.tsx index f25f30dd..35246bf7 100644 --- a/website/src/components/DataTable.tsx +++ b/website/src/components/DataTable.tsx @@ -84,7 +84,7 @@ export const DataTable = ({ } else { newValues = filterValues.map((oldValue) => (oldValue.id === value.id ? value : oldValue)); } - onFilterChange(newValues); + onFilterChange && onFilterChange(newValues); }; return ( <> diff --git a/website/src/components/UserTable.tsx b/website/src/components/UserTable.tsx index 57a96c95..ab05d065 100644 --- a/website/src/components/UserTable.tsx +++ b/website/src/components/UserTable.tsx @@ -76,14 +76,14 @@ export const UserTable = memo(function UserTable() { const toPreviousPage = () => { setPagination({ - cursor: data.prev, + cursor: data?.prev || "", direction: "back", }); }; const toNextPage = () => { setPagination({ - cursor: data.next, + cursor: data?.next || "", direction: "forward", }); }; diff --git a/website/src/lib/users.ts b/website/src/lib/users.ts index d9e32937..d17dda37 100644 --- a/website/src/lib/users.ts +++ b/website/src/lib/users.ts @@ -32,9 +32,8 @@ const getUserLanguage = (req: NextApiRequest): string => { * * @param {string} id The user's web auth id. * - * @return {BackendUserCore} The most specific auth type and id for the user. */ -const getBackendUserCore = async (id: string) => { +const getBackendUserCore = async (id: string): Promise => { const user = await prisma.user.findUnique({ where: { id }, select: { @@ -44,21 +43,27 @@ const getBackendUserCore = async (id: string) => { }, }); + if (!user) { + return null; + } + // If there are no linked accounts, just use what we have locally. if (user.accounts.length === 0) { return { id: user.id, - display_name: user.name, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + display_name: user.name!, auth_method: "local", - } as BackendUserCore; + }; } // Otherwise, use the first linked account that the user created. return { id: user.accounts[0].providerAccountId, - display_name: user.name, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + display_name: user.name!, auth_method: user.accounts[0].provider, - } as BackendUserCore; + }; }; export { getBackendUserCore, getUserLanguage }; diff --git a/website/src/pages/auth/signin.tsx b/website/src/pages/auth/signin.tsx index 62cd93f7..d66ff60c 100644 --- a/website/src/pages/auth/signin.tsx +++ b/website/src/pages/auth/signin.tsx @@ -7,9 +7,10 @@ import { GetServerSideProps } from "next"; import Head from "next/head"; import Link from "next/link"; import { useRouter } from "next/router"; -import { getProviders, signIn } from "next-auth/react"; +import { BuiltInProviderType } from "next-auth/providers"; +import { ClientSafeProvider, getProviders, signIn } from "next-auth/react"; import { serverSideTranslations } from "next-i18next/serverSideTranslations"; -import React, { useEffect, useRef, useState } from "react"; +import React, { ReactNode, useEffect, useRef, useState } from "react"; import { useForm } from "react-hook-form"; import { AuthLayout } from "src/components/AuthLayout"; import { CloudFlareCaptcha } from "src/components/CloudflareCaptcha"; @@ -48,7 +49,7 @@ const errorMessages: Record = { }; interface SigninProps { - providers: Awaited>; + providers: Record; } function Signin({ providers }: SigninProps) { @@ -137,7 +138,7 @@ function Signin({ providers }: SigninProps) { ); } -Signin.getLayout = (page) => ( +Signin.getLayout = (page: ReactNode) => (
{page} @@ -151,7 +152,7 @@ const emailSigninCaptcha = boolean(process.env.NEXT_PUBLIC_ENABLE_EMAIL_SIGNIN_C const EmailSignInForm = ({ providerId }: { providerId: string }) => { const { register, handleSubmit } = useForm<{ email: string }>(); - const captcha = useRef(); + const captcha = useRef(null); const [captchaSuccess, setCaptchaSuccess] = useState(false); const signinWithEmail = (data: { email: string }) => { signIn(providerId, { diff --git a/website/src/pages/auth/verify.tsx b/website/src/pages/auth/verify.tsx index d7a64a63..0e4ce1f9 100644 --- a/website/src/pages/auth/verify.tsx +++ b/website/src/pages/auth/verify.tsx @@ -1,4 +1,5 @@ import { useColorMode } from "@chakra-ui/react"; +import { GetServerSideProps } from "next"; import Head from "next/head"; import { getCsrfToken, getProviders } from "next-auth/react"; import { serverSideTranslations } from "next-i18next/serverSideTranslations"; @@ -22,7 +23,7 @@ export default function Verify() { ); } -export async function getServerSideProps({ locale }) { +export const getServerSideProps: GetServerSideProps = async ({ locale = "en" }) => { const csrfToken = await getCsrfToken(); const providers = await getProviders(); return { @@ -32,4 +33,4 @@ export async function getServerSideProps({ locale }) { ...(await serverSideTranslations(locale, ["common"])), }, }; -} +}; diff --git a/website/src/pages/messages/[id]/index.tsx b/website/src/pages/messages/[id]/index.tsx index 0092a843..e50e60cf 100644 --- a/website/src/pages/messages/[id]/index.tsx +++ b/website/src/pages/messages/[id]/index.tsx @@ -1,4 +1,5 @@ import { Box, Card, Text, useColorModeValue } from "@chakra-ui/react"; +import { GetServerSideProps, InferGetServerSidePropsType } from "next"; import Head from "next/head"; import { useTranslation } from "next-i18next"; import { serverSideTranslations } from "next-i18next/serverSideTranslations"; @@ -10,7 +11,7 @@ import { get } from "src/lib/api"; import { Message } from "src/types/Conversation"; import useSWRImmutable from "swr/immutable"; -const MessageDetail = ({ id }: { id: string }) => { +const MessageDetail = ({ id }: InferGetServerSidePropsType) => { const { t } = useTranslation(["message", "common"]); const backgroundColor = useColorModeValue("white", "gray.800"); @@ -49,11 +50,15 @@ const MessageDetail = ({ id }: { id: string }) => { ); }; -MessageDetail.getLayout = (page) => getDashboardLayout(page); +MessageDetail.getLayout = getDashboardLayout; -export const getServerSideProps = async ({ locale, query }) => ({ +export const getServerSideProps: GetServerSideProps<{ id: string }, { id: string }> = async ({ + locale = "en", + params, +}) => ({ props: { - id: query.id, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + id: params!.id, ...(await serverSideTranslations(locale, ["common", "message", "labelling"])), }, }); diff --git a/website/src/pages/tasks/all.tsx b/website/src/pages/tasks/all.tsx index 01954c2f..d71096ee 100644 --- a/website/src/pages/tasks/all.tsx +++ b/website/src/pages/tasks/all.tsx @@ -16,6 +16,6 @@ const AllTasks = () => { ); }; -AllTasks.getLayout = (page) => getDashboardLayout(page); +AllTasks.getLayout = getDashboardLayout; export default AllTasks; diff --git a/website/types/next-auth.d.ts b/website/types/next-auth.d.ts index ed126deb..f0f381d4 100644 --- a/website/types/next-auth.d.ts +++ b/website/types/next-auth.d.ts @@ -1,5 +1,4 @@ -import NextAuth, { DefaultSession } from "next-auth"; -import { JWT } from "next-auth/jwt"; +import { DefaultSession } from "next-auth"; declare module "next-auth" { interface Session { @@ -17,9 +16,11 @@ declare module "next-auth" { declare module "next-auth/jwt" { interface JWT { /** The user's role. */ - role?: string; + role: string; /** True when the user is new. */ isNew?: boolean; + + sub: string; /** Iso timestamp of the user's acceptance of the terms of service */ tosAcceptanceDate?: string; } From e2327295aff8a6b1d7b7b265b32a82ac2a8aacd2 Mon Sep 17 00:00:00 2001 From: AbdBarho Date: Tue, 7 Feb 2023 11:57:35 +0100 Subject: [PATCH 115/152] Fix error in user stats when loading (#1290) there was no check for waiting the data to be fetched, worked locally, not when deployed. --- website/src/pages/account/index.tsx | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/website/src/pages/account/index.tsx b/website/src/pages/account/index.tsx index 8a7753e1..27cc29fd 100644 --- a/website/src/pages/account/index.tsx +++ b/website/src/pages/account/index.tsx @@ -15,13 +15,17 @@ import uswSWRImmutable from "swr/immutable"; export default function Account() { const { t } = useTranslation("leaderboard"); const { data: session } = useSession(); - const { data } = uswSWRImmutable<{ [time in LeaderboardTimeFrame]: LeaderboardEntity }>("/api/user_stats", get); + const { data: entries } = uswSWRImmutable>( + "/api/user_stats", + get, + { + fallbackData: {}, + } + ); if (!session) { return; } - console.log(data); - return ( <> @@ -55,12 +59,10 @@ export default function Account() { LeaderboardTimeFrame.day, LeaderboardTimeFrame.week, LeaderboardTimeFrame.month, - ].map((key) => { - const values = data[key]; - if (!values) { - return null; - } - return ( + ] + .map((key) => ({ key, values: entries[key] })) + .filter(({ values }) => values) + .map(({ key, values }) => ( {t(getTypeSafei18nKey(key))} @@ -84,8 +86,7 @@ export default function Account() { - ); - })} + ))} From 801b47949c028e65d9c32add6f5d745946521a9d Mon Sep 17 00:00:00 2001 From: Pavel Mokin Date: Tue, 7 Feb 2023 14:06:43 +0300 Subject: [PATCH 116/152] Scroll to the top every time we get a new task (#1293) --- website/src/components/Tasks/Task/Task.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/components/Tasks/Task/Task.tsx b/website/src/components/Tasks/Task/Task.tsx index 54160636..84d1a980 100644 --- a/website/src/components/Tasks/Task/Task.tsx +++ b/website/src/components/Tasks/Task/Task.tsx @@ -115,6 +115,7 @@ export const Task = () => { useEffect(() => { taskEvent({ action: "NEW_TASK" }); + scrollToTop(rootEl.current); }, [task.id]); const onReplyChanged = useCallback( @@ -128,7 +129,6 @@ export const Task = () => { if (taskStatus.mode === "REVIEW") { taskEvent({ action: "SET_SUBMITTED" }); await completeTask(replyContent.current); - scrollToTop(rootEl.current); } }, [taskStatus.mode, completeTask]); From ab82da7d74d451209734f8fa4287dd96c364412d Mon Sep 17 00:00:00 2001 From: Saifeddine ALOUI Date: Tue, 7 Feb 2023 12:07:49 +0100 Subject: [PATCH 117/152] Enhanced French and arabic Locales (#1273) I have updated the French and arabic locales by enhancing some expressions as didn't sound good when I read them in the final product. --- website/public/locales/ar/index.json | 20 ++++++++++++++------ website/public/locales/ar/labelling.json | 20 ++++++++++---------- website/public/locales/ar/tos.json | 6 +++--- website/public/locales/fr/index.json | 18 +++++++++++++----- website/public/locales/fr/tasks.json | 16 ++++++++-------- 5 files changed, 48 insertions(+), 32 deletions(-) diff --git a/website/public/locales/ar/index.json b/website/public/locales/ar/index.json index 7b279988..01f1283d 100644 --- a/website/public/locales/ar/index.json +++ b/website/public/locales/ar/index.json @@ -1,15 +1,23 @@ { "blurb": "نحن نعتقد أنه يمكن أن نخلق ثورة.", - "blurb1": "كما ساعد Stable Diffusion العالم في عمل الفن والصور بطرق جديدة، نحن نريد تحسين العالم عن طريق تقديم ذكاء تحدثي رائع.", - "description": "ذكاء تحدثي للجميع. مشروع مفتوح المصدر لخلق GPT LLM ممتاز مع تفعيل الدردشة بواسطة LAION والمتزعمين حول العالم.", + "blurb1": "كما ساهم Stable Diffusion في تحويل عالم الصناعة الفنية والبصرية بتقديم طرق جديدة، نحرص على تحسين العالم من خلال تقديم ذكاء تحدثي عالي الجودة.", + "description": " هدفنا انشاء ذكاء تحدثي عالي الجودة للجميع. لتحقيق هذا الهدف انشانا هذا المشروع مفتوح المصدر للدردشة الاسطناعية تزعمه ليون LAION باهانة مساهمين من كل أنحاء العالم. ", "faq_items": { - "q0": "إلى أي مدى عند المشروع؟", + "q0": "إلي أي مدى وصل هذا المشروع؟", "a0": "نحن في المراحل الأولى من التطوير، نعمل على أساس أبحاث مؤرخة في تطبيق RLHF على النماذج اللغوية الكبيرة.", - "q1": "من هو وراء Open Assistant؟", - "a1": "Open Assistant هو مشروع منظم من قبل LAION والأفراد حول العالم الذين يهتمون بجلب هذه التكنولوجيا للجميع." + "q1": "من وراء Open Assistant؟", + "a1": "Open Assistant هو مشروع منظم من قبل LAION وأفراد من حول العالم يهتمون بجلب هذه التكنولوجيا للجميع.", + "q2": "ما هي الترخيص الذي يستخدمه Open Assistant؟", + "a2": "يتم ترخيص الشفرة والنماذج بموجب ترخيص Apache 2.0.", + "q3": "هل سيتم إصدار بيانات التدريب أيضًا؟", + "a3": "نعم، بموجب ترخيص CC BY 4.0.", + "q4": "هل سيكون Open Assistant مجانيًا؟", + "a4": "نعم، سيكون Open Assistant مجانيًا للاستخدام والتعديل.", + "q5": "ما هو الجهاز المطلوب لتشغيل النماذج؟", + "a5": "سيكون هناك إصدارات يمكن تشغيلها على الأجهزة المصممة للمستهلكين." }, "faq_title": "أسئلة وأجوبة شائعة", - "join_us_description": "جميع المشاريع المفتوحة المصدر تبدأ مع أشخاص مثلك. المصدر المفتوح هو الإيمان بأنه إذا تعاوننا، يمكن أن نقدم معا علمنا وتكنولوجيانا للعالم لنفع البشرية. هل تريد الانضمام الينا؟ اعثر علينا هنا:", + "join_us_description": "جميع المشاريع المفتوحة المصدر تبدأ بأشخاص مثلك. المصدر المفتوح هو الإيمان بأنه إذا تعاوننا، يمكن أن نقدم معا علمنا وتكنولوجيتنا لنفع البشرية. هل تريد الانضمام الينا؟ اعثر علينا هنا:", "join_us_title": "انضم إلينا", "subtitle": "ذكاء تحدثي للجميع." } diff --git a/website/public/locales/ar/labelling.json b/website/public/locales/ar/labelling.json index 55356e19..34791b2b 100644 --- a/website/public/locales/ar/labelling.json +++ b/website/public/locales/ar/labelling.json @@ -1,24 +1,24 @@ { - "fails_task.question": "هل هي رد سيئ، كجواب على مهمة النداء؟", + "label_highlighted_yes_no_instruction": "أجب على السؤال (الأسئلة) التالي عن الخطاب المميز:", + "label_highlighted_flag_instruction": "حدد أي خيار ينطبق على الخطاب المميز:", + "label_highlighted_likert_instruction": "تقييم الخطاب المميز:", + "label_message_yes_no_instruction": "أجب على السؤال (الأسئلة) التالي عن الخطاب:", + "label_message_flag_instruction": "حدد أي خيار ينطبق على الخطاب:", + "label_message_likert_instruction": "تقييم الخطاب:", + "spam.question": "هل الخطاب هو رسالة غير مرغوب فيها(SPAM)؟", + "fails_task.question": "هل هو رد سيئ، كجواب على النداء؟", "hate_speech": "نشاط عدائي", "hate_speech.explanation": "المحتوى يحمل عبارات تشهير أو تهديد ويعبر عن الطائفية ضد خاصية محمية. الطائفية تعني الآراء المسبقة التي لا تعتمد على العقل. الخصائص المحمية تشمل الجنس والعرق والدين والميول الجنسية ومثل هذه الخصائص.", - "label_highlighted_flag_instruction": "حدد أي أن تنطبق على الخطاب المميز:", - "label_highlighted_likert_instruction": "تقييم الخطاب المميز:", - "label_highlighted_yes_no_instruction": "أجب على السؤال (الأسئلة) التالي عن الخطاب المميز:", - "label_message_flag_instruction": "حدد أي أن تنطبق على الخطاب:", - "label_message_likert_instruction": "تقييم الخطاب:", - "label_message_yes_no_instruction": "أجب على السؤال (الأسئلة) التالي عن الخطاب:", "lang_mismatch": "لغة خاطئة", "lang_mismatch.explanation": "لم كتب باللغة المحددة حاليا.", "moral_judgement": "حكم على الأخلاقيات", "moral_judgement.explanation": "يعبر عن الأخلاقيات.", "not_appropriate": "غير مناسب", - "not_appropriate.explanation": "غير مناسب لمساعد العميل.", + "not_appropriate.explanation": "غير مناسب لمساعد الحريف.", "pii": "تحتوي على PII", "pii.explanation": "تحتوي على معلومات شخصية يمكن تحديد الهوية بها. مثال يشمل تفاصيل اتصال شخصية، رقم ترخيص وغيرها من أرقام الهوية وتفاصيل الحساب المصرفي.", "political_content": "سياسي", "political_content.explanation": "يعبر عن الآراء السياسية.", "sexual_content": "المحتوى الجنسي", - "sexual_content.explanation": "يحتوي على محتوى جنسي.", - "spam.question": "هل الخطاب هي رسالة غير مرغوب فيها؟" + "sexual_content.explanation": "يحتوي على محتوى جنسي." } diff --git a/website/public/locales/ar/tos.json b/website/public/locales/ar/tos.json index b4c80dba..12039a8a 100644 --- a/website/public/locales/ar/tos.json +++ b/website/public/locales/ar/tos.json @@ -1,6 +1,6 @@ { - "accept": "قبول", + "title": "شروط الخدمة ل Open Assistant (المساعد المفتوح)", "content": "للاستمرار في استخدام Open Assistant (المساعد المفتوح)، يجب عليك قبول شروط الخدمة الخاصة بنا أولاً.", - "decline": "رفض", - "title": "شروط الخدمة لمساعد مفتوح" + "accept": "قبول", + "decline": "رفض" } diff --git a/website/public/locales/fr/index.json b/website/public/locales/fr/index.json index 80f3e46a..466cfda3 100644 --- a/website/public/locales/fr/index.json +++ b/website/public/locales/fr/index.json @@ -1,15 +1,23 @@ { "blurb": "Nous croyons que nous pouvons créer une révolution.", - "blurb1": "De la même manière que Stable Diffusion a aidé le monde à faire de l'art et des images de nouvelles manières, nous voulons améliorer le monde en fournissant une incroyable IA conversationnelle.", - "description": "IA conversationnelle pour tout le monde. Un projet open source pour créer un GPT LLM activé par chat dirigé par LAION et des contributeurs du monde entier.", + "blurb1": "Stable Diffusion a révolutionné la création artistique et visuelle en offrant de nouvelles approches. De la même manière, nous aspirons à transformer le monde en proposant une IA conversationnelle d'une qualité exceptionnelle.", + "description": "Notre objectif est de rendre l'IA conversationnelle accessible à tous. Pour atteindre cet objectif, nous lançons un projet open-source pour développer un large modèle de langage LLM pour le chat, dirigé par LAION et soutenu par des contributeurs du monde entier.", "faq_items": { "q0": "À quel stade est ce projet?", - "a0": "Nous sommes aux premiers stades du développement, travaillant à partir de recherches établies dans l'application de RLHF à de grands modèles linguistiques.", + "a0": "Nous sommes aux premiers stades du développement, travaillant à partir de recherches établies dans l'application de RLHF aux modèles de language large (LLM).", "q1": "Qui se trouve derrière Open Assistant?", - "a1": "Open Assistant est un projet organisé par LAION et des individus du monde entier intéressés à apporter cette technologie à tout le monde." + "a1": "Open Assistant est un projet organisé par LAION et des individus du monde entier intéressés à apporter cette technologie à tout le monde.", + "q2": "Quel est le type de licence utilisé par Open Assistant ?", + "a2": "Le code et les modèles sont sous licence Apache 2.0.", + "q3": "Les données d'entraînement seront-elles également publiées ?", + "a3": "Oui, sous CC BY 4.0.", + "q4": "Open Assistant sera-t-il gratuit ?", + "a4": "Oui, Open Assistant sera gratuit pour l'utiliser et le modifier.", + "q5": "Quel matériel sera nécessaire pour faire tourner les modèles ?", + "a5": "Il y aura des versions qui pourront être exécutées sur du matériel grand public." }, "faq_title": "Questions fréquentes", - "join_us_description": "Tous les projets open source commencent avec des personnes comme vous. L'open source est la croyance que si nous collaborons, nous pouvons ensemble offrir notre connaissance et notre technologie au monde pour le bénéfice de l'humanité. Êtes-vous dedans? Trouvez-nous ici :", + "join_us_description": "Tous les projets open source commencent avec des personnes comme vous. L'open source est la croyance que si nous collaborons, nous pouvons ensemble offrir notre connaissance et notre technologie au monde pour le bénéfice de l'humanité. Êtes-vous pret à nous rejoindre? Trouvez-nous ici :", "join_us_title": "Rejoignez-nous", "subtitle": "IA conversationnelle pour tout le monde." } diff --git a/website/public/locales/fr/tasks.json b/website/public/locales/fr/tasks.json index 916a4ab0..6f37d0c1 100644 --- a/website/public/locales/fr/tasks.json +++ b/website/public/locales/fr/tasks.json @@ -1,5 +1,5 @@ { - "available_task_count": "{{count}} tâches disponibles", + "available_task_count": "Il y a {{count}} tâches disponibles", "classify_assistant_reply": { "label": "Classer la réponse de l'assistant", "desc": "Fournir des étiquettes pour une invitation.", @@ -16,11 +16,11 @@ "overview": "Lisez la conversation suivante et répondez à la question sur la dernière réponse de la discussion." }, "create_initial_prompt": { - "label": "Créer des prompts initiaux", - "desc": "Écrivez des prompts initiaux pour aider Open Assistant à essayer de répondre à des messages divers.", + "label": "Créer des invites initiaux", + "desc": "Écrivez des invites initiaux pour aider Open Assistant à essayer de répondre à des messages divers.", "overview": "Créez un message initial à envoyer à l'assistant", - "instruction": "Fournir les prompts initiaux", - "response_placeholder": "Écrivez votre prompt ici..." + "instruction": "Fournir les invites initiaux", + "response_placeholder": "Écrivez votre invite ici..." }, "default": { "unchanged_title": "Aucun changement", @@ -47,10 +47,10 @@ }, "rank_assistant_replies": { "label": "Classer les réponses de l'assistant", - "desc": "Scorez les prompts fournis par Open Assistant en fonction de leur exactitude et lisibilité.", + "desc": "Scorez les invites fournis par Open Assistant en fonction de leur exactitude et lisibilité.", "overview": "Compte tenu des réponses d'assistant suivantes, classez-les du meilleur au pire, le meilleur étant en premier, le pire en dernier.", "unchanged_title": "Ordre inchangé", - "unchanged_message": "Vous n'avez pas modifié l'ordre des prompts. Etes-vous sûr de vouloir continuer?" + "unchanged_message": "Vous n'avez pas modifié l'ordre des invites. Etes-vous sûr de vouloir continuer?" }, "rank_initial_prompts": { "label": "Classer les invitations initiales", @@ -64,7 +64,7 @@ "desc": "Aidez Open Assistant à améliorer ses réponses aux conversations avec d'autres utilisateurs.", "overview": "Compte tenu des réponses d'utilisateur suivantes, classez-les du meilleur au pire, le meilleur étant en premier, le pire en dernier.", "unchanged_title": "Ordre inchangé", - "unchanged_message": "Vous n'avez pas modifié l'ordre des prompts. Etes-vous sûr de vouloir continuer?" + "unchanged_message": "Vous n'avez pas modifié l'ordre des invites. Etes-vous sûr de vouloir continuer?" }, "reply_as_assistant": { "label": "Répondre en tant qu'assistant", From 52af7ba13b5fec03b1b7bfcf2561b4ed0f7f4595 Mon Sep 17 00:00:00 2001 From: Adrian Cowan Date: Tue, 7 Feb 2023 22:17:53 +1100 Subject: [PATCH 118/152] website: show language in text area (#1296) * website: show language in text area When the language hasn't been detected (too little text) the langauge that it will be submitted as is shown. When we detect the language is not what will be submitted we show the detected language in red. The tooltip informs the user that they don't appear to be writing in the correct language. Note: this replaces the modal dialog that we use to popup if the language appeared to differ. * website: Don't suggest the user change the language --- website/public/locales/en/language.json | 22 ++++ .../src/components/Survey/TrackedTextarea.tsx | 120 ++++++++---------- website/src/styles/Theme/colors.ts | 2 + website/types/i18next.d.ts | 2 + 4 files changed, 79 insertions(+), 67 deletions(-) create mode 100644 website/public/locales/en/language.json diff --git a/website/public/locales/en/language.json b/website/public/locales/en/language.json new file mode 100644 index 00000000..b957103d --- /dev/null +++ b/website/public/locales/en/language.json @@ -0,0 +1,22 @@ +{ + "writing_wrong_langauge_a_b": "You appear to be writing in {{detected_lang}} but this will be submitted as {{submit_lang}}.", + "submitted_as": "This will be submitted as {{submit_lang}}", + "lang_ar": "Arabic", + "lang_bn": "Bengali", + "lang_ca": "Catalan", + "lang_de": "German", + "lang_en": "English", + "lang_es": "Spanish", + "lang_fr": "French", + "lang_hu": "Hungarian", + "lang_it": "Italian", + "lang_ja": "Japanese", + "lang_ko": "Korean", + "lang_pl": "Polish", + "lang_pt-BR": "Brazilian Portugese", + "lang_ru": "Russian", + "lang_tr": "Turkish", + "lang_uk-UA": "Ukrainian", + "lang_vi": "Vietnamese", + "lang_zh": "Chinese" +} diff --git a/website/src/components/Survey/TrackedTextarea.tsx b/website/src/components/Survey/TrackedTextarea.tsx index 196d2f1a..29b792df 100644 --- a/website/src/components/Survey/TrackedTextarea.tsx +++ b/website/src/components/Survey/TrackedTextarea.tsx @@ -1,23 +1,12 @@ -import {} from "@chakra-ui/react"; +import { Tooltip } from "@chakra-ui/react"; +import { Progress, Stack, Textarea, TextareaProps, useColorModeValue } from "@chakra-ui/react"; import lande from "lande"; -import { LanguageAbbreviations } from "src/lib/iso6393"; -import { useCookies } from "react-cookie"; +import { useTranslation } from "next-i18next"; import React from "react"; -import { - Progress, - Stack, - Textarea, - TextareaProps, - useColorModeValue, - Button, - Modal, - ModalBody, - ModalCloseButton, - ModalContent, - ModalHeader, - ModalOverlay, - useDisclosure, -} from "@chakra-ui/react"; +import { useCookies } from "react-cookie"; +import { getTypeSafei18nKey } from "src/lib/i18n"; +import { LanguageAbbreviations } from "src/lib/iso6393"; +import { colors } from "src/styles/Theme/colors"; interface TrackedTextboxProps { text: string; @@ -30,55 +19,23 @@ interface TrackedTextboxProps { onTextChange: (event: React.ChangeEvent) => void; } -const killEvent = (e) => e.stopPropagation(); - export const TrackedTextarea = (props: TrackedTextboxProps) => { - const [wordLimitForLangDetection, setWordLimitForLangDetection] = React.useState(10); + const { t } = useTranslation("language"); + const wordLimitForLangDetection = 4; const backgroundColor = useColorModeValue("gray.100", "gray.900"); const [cookies] = useCookies(["NEXT_LOCALE"]); const wordCount = (props.text.match(/\w+/g) || []).length; - const { isOpen, onOpen, onClose } = useDisclosure(); const currentLanguage = cookies["NEXT_LOCALE"]; - const closeTemporaryIgnoreLanguageDetection = () => { - setWordLimitForLangDetection(2 * wordCount); - onClose(); - }; - - console.log("", wordCount, wordLimitForLangDetection); - if (wordCount > wordLimitForLangDetection) { - let mostProbableLanguage; + const detectLang = (text: string) => { try { - mostProbableLanguage = LanguageAbbreviations[lande(props.text)[0][0]]; + return LanguageAbbreviations[lande(text)[0][0]]; } catch (error) { - mostProbableLanguage = ""; + return currentLanguage; } - - /*const mostProbableLanguage = lande(props.text);*/ - if (mostProbableLanguage !== currentLanguage) { - setTimeout(() => { - onOpen(); - }, 200); - - return ( - <> - - {/* we kill the event here to disable drag and drop, since it is in the same container */} - - - Switch Language? - - - Do you want to switch language? The detected language is {mostProbableLanguage}, whereas your - chosen language is {currentLanguage}. The language can be changed on the top right. - - - - - - ); - } - } + }; + const detectedLang = wordCount > wordLimitForLangDetection ? detectLang(props.text) : currentLanguage; + const wrongLanguage = detectedLang !== currentLanguage; let progressColor: string; switch (true) { @@ -92,17 +49,46 @@ export const TrackedTextarea = (props: TrackedTextboxProps) => { progressColor = "green"; } + const problemColor = useColorModeValue(colors.light.problem, colors.dark.problem); + return ( -