feat: ai employees

This commit is contained in:
xilesun 2025-03-30 19:59:05 +08:00
parent 8a82cdec5b
commit c9ed2208ec
101 changed files with 3016 additions and 346 deletions

View File

@ -50,6 +50,17 @@ export function createDetailsWithPaginationUISchema(options: {
'x-read-pretty': true,
'x-use-component-props': 'useDetailsWithPaginationProps',
properties: {
[uid()]: {
type: 'void',
'x-initializer': hideActionInitializer ? undefined : 'aiEmployees:configure',
'x-component': 'ActionBar',
'x-component-props': {
style: {
marginBottom: 16,
},
},
properties: {},
},
[uid()]: {
type: 'void',
'x-initializer': hideActionInitializer ? undefined : 'details:configureActions',

View File

@ -51,6 +51,17 @@ export function createDetailsUISchema(options: {
'x-read-pretty': true,
'x-use-component-props': 'useDetailsProps',
properties: {
[uid()]: {
type: 'void',
'x-initializer': 'aiEmployees:configure',
'x-component': 'ActionBar',
'x-component-props': {
style: {
marginBottom: 16,
},
},
properties: {},
},
[uid()]: {
type: 'void',
'x-initializer': 'details:configureActions',

View File

@ -60,6 +60,18 @@ export function createCreateFormBlockUISchema(options: CreateFormBlockUISchemaOp
'x-initializer': 'form:configureFields',
properties: {},
},
[uid()]: {
type: 'void',
'x-initializer': 'aiEmployees:configure',
'x-component': 'ActionBar',
'x-component-props': {
layout: 'one-column',
style: {
marginBottom: 8,
},
},
properties: {},
},
[uid()]: {
type: 'void',
'x-initializer': 'createForm:configureActions',

View File

@ -53,6 +53,8 @@ export const requestLogger = (appName: string, requestLogger: Logger, options?:
app: appName,
reqId,
});
ctx.res.setHeader('X-Request-Id', reqId);
let error: Error;
try {
await next();
@ -82,8 +84,6 @@ export const requestLogger = (appName: string, requestLogger: Logger, options?:
}
}
ctx.res.setHeader('X-Request-Id', reqId);
if (error) {
throw error;
}

View File

@ -13,8 +13,10 @@
"@nocobase/test": "1.x"
},
"devDependencies": {
"@ant-design/x": "^1.0.5",
"@langchain/core": "^0.3.39",
"@langchain/deepseek": "^0.0.1",
"@langchain/openai": "^0.4.3"
"@langchain/openai": "^0.4.3",
"snowflake-id": "^1.1.0"
}
}

View File

@ -0,0 +1,55 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import React, { useContext } from 'react';
import { createContext } from 'react';
import { ChatBoxProvider } from './chatbox/ChatBoxProvider';
import { useAPIClient, useRequest } from '@nocobase/client';
export type AIEmployee = {
username: string;
nickname?: string;
avatar?: string;
bio?: string;
greeting?: string;
};
export const AIEmployeesContext = createContext<{
aiEmployees: AIEmployee[];
setAIEmployees: (aiEmployees: AIEmployee[]) => void;
}>({} as any);
export const AIEmployeesProvider: React.FC<{
children: React.ReactNode;
}> = (props) => {
const [aiEmployees, setAIEmployees] = React.useState<AIEmployee[]>(null);
return (
<AIEmployeesContext.Provider value={{ aiEmployees, setAIEmployees }}>
<ChatBoxProvider>{props.children}</ChatBoxProvider>
</AIEmployeesContext.Provider>
);
};
export const useAIEmployeesContext = () => {
const { aiEmployees, setAIEmployees } = useContext(AIEmployeesContext);
const api = useAPIClient();
const service = useRequest<AIEmployee[]>(
() =>
api
.resource('aiEmployees')
.list()
.then((res) => res?.data?.data),
{
ready: !aiEmployees,
onSuccess: (aiEmployees) => setAIEmployees(aiEmployees),
},
);
return { aiEmployees, service };
};

View File

@ -0,0 +1,14 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
// @ts-ignore
export const avatars = import.meta.webpackContext('./avatars', {
recursive: false,
regExp: /\.svg$/,
});

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_malayan_skin_01"><path d="M337.2765,222.7712l-.01-.0028A87.9992,87.9992,0,1,0,168,189.0145c0,97.4733,84.7191,216.9171,216.7848,214.9727C384.7846,403.9872,303.728,304.837,337.2765,222.7712Z" style="fill:#071b2b"/><path d="M196.3388,459.2315a11.2273,11.2273,0,0,0,10.795,14.3115h97.7316a11.2268,11.2268,0,0,0,10.795-14.3115l-3.6246-12.6874H199.9643Z" style="fill:#d87761"/><path d="M261.4639,368.543H250.5362a37.5,37.5,0,0,0-36.0571,27.1985l-14.5148,50.8026H312.0358L297.52,395.7415A37.5,37.5,0,0,0,261.4639,368.543Z" style="fill:#0d263e"/><path d="M377.7958,228.13h-10.459A112.4033,112.4033,0,0,0,256,130.775h0A112.4033,112.4033,0,0,0,144.6623,228.13h-10.459a33.7518,33.7518,0,1,0,0,67.5036h10.459A112.4049,112.4049,0,0,0,256,392.9894h0A112.4049,112.4049,0,0,0,367.3368,295.634h10.459a33.7518,33.7518,0,1,0,0-67.5036Z" style="fill:#d87761"/><path d="M256.0014,358.7981a37.2964,37.2964,0,0,1-26.521-10.979,7.5018,7.5018,0,1,1,10.6054-10.6128c8.5108,8.5034,23.3277,8.5,31.8238.0037a7.4992,7.4992,0,1,1,10.6054,10.6054A37.2425,37.2425,0,0,1,256.0014,358.7981Z" style="fill:#8c1813"/><rect height="45" rx="15" style="fill:#bf5e48" width="30" x="240.9998" y="275.8614"/><path d="M380.468,241.8058H366.9694v40.1514H380.468a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#bf5e48"/><path d="M336.1742,244.9414a7.4972,7.4972,0,0,0-10.6054,0L323.231,247.28a20.6842,20.6842,0,1,0,10.605,10.6054l2.3382-2.3382A7.4973,7.4973,0,0,0,336.1742,244.9414Z" style="fill:#0d253d"/><circle cx="319.5723" cy="258.4678" r="7.6845" style="fill:#ffefdc"/><path d="M197.036,245.5274a20.5237,20.5237,0,0,0-8.2681,1.75l-2.3373-2.3364a7.4992,7.4992,0,0,0-10.6055,10.6055l2.3373,2.3364a20.6122,20.6122,0,1,0,18.8736-12.3559Z" style="fill:#0d253d"/><circle cx="201.6467" cy="258.4678" r="7.6845" style="fill:#ffefdc"/><path d="M131.5313,241.8058H145.03v40.1514H131.5313a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#bf5e48"/><path d="M367.1969,227.2079a112.3272,112.3272,0,0,0-222.3944,0c2.4682-8.1481,23.78-68.8348,111.1981-68.8348C343.417,158.3731,364.7286,219.06,367.1969,227.2079Z" style="fill:#0d263e"/></g></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_malayan_skin_06"><path d="M287.4863,352.0415H224.5122A36.0119,36.0119,0,0,0,188.5,388.0533v74.272a11.2178,11.2178,0,0,0,11.2178,11.2177H312.2818A11.2177,11.2177,0,0,0,323.5,462.3253V388.0547A36.0132,36.0132,0,0,0,287.4863,352.0415Z" style="fill:#f4e2ff"/><path d="M371.8266,219.8372H361v.0018a105,105,0,0,0-210,0v-.0018H140.1734a33.7519,33.7519,0,1,0,0,67.5037H151v-.0019a105,105,0,0,0,210,0v.0019h10.8266a33.7519,33.7519,0,1,0,0-67.5037Z" style="fill:#d87761"/><path d="M269.0718,317.668h-93.89A46.8586,46.8586,0,0,0,256,350.0429a46.8586,46.8586,0,0,0,80.8186-32.3749Z" style="fill:#f4e2ff"/><rect height="68.3763" rx="22.7921" style="fill:#bf5e48" width="45.5842" x="233.208" y="263.5237"/><path d="M374.4984,233.5127H361v40.1514h13.4985a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#bf5e48"/><circle cx="314.9627" cy="250.5027" r="20.625" style="fill:#521919"/><circle cx="319.5735" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><circle cx="197.0372" cy="250.5027" r="20.625" style="fill:#521919"/><circle cx="201.6479" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><path d="M137.5014,233.5127H151v40.1514H137.5014a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#bf5e48"/><path d="M392.0876,171.4883a88.8088,88.8088,0,0,1-14.85,48.825,32.7677,32.7677,0,0,0-5.4-.45H360.9624s-27.3-24.15-105-24.15c-77.6248,0-105,24.15-105,24.15h-10.8a31.4438,31.4438,0,0,0-5.4.45,88.8054,88.8054,0,0,1-14.85-48.825c0-59.3994,60.9-107.6258,136.05-107.6258C331.1876,63.8625,392.0876,112.0889,392.0876,171.4883Z" style="fill:#ffc139"/></g></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_caucasian_skin_02"><path d="M256.0005,408.745c119.7876,0,160.1055-45.4174,160.1055-45.4174s-26.12-59.9012-26.12-104.8609H122.0149c0,44.96-26.1209,104.8609-26.1209,104.8609s40.3189,45.4174,160.1065,45.4174Z" style="fill:#521919"/><path d="M304.8657,473.543H207.1344a11.2272,11.2272,0,0,1-10.7953-14.3116l18.14-63.4906a37.5,37.5,0,0,1,36.057-27.1978h10.9277a37.5,37.5,0,0,1,36.0569,27.1978l18.14,63.4906A11.2272,11.2272,0,0,1,304.8657,473.543Z" style="fill:#eb5e59"/><path d="M377.7966,228.13h-10.459a112.3415,112.3415,0,0,0-222.6754,0h-10.459a33.7519,33.7519,0,1,0,0,67.5037h10.459a112.3418,112.3418,0,0,0,222.6754,0h10.459a33.7519,33.7519,0,1,0,0-67.5037Z" style="fill:#f8c4b0"/><path d="M255.9976,358.7975a37.2429,37.2429,0,0,1-26.5137-10.9827,7.4992,7.4992,0,0,1,10.6055-10.6054c8.4961,8.4961,23.313,8.5,31.8237-.0037a7.5018,7.5018,0,1,1,10.6055,10.6128A37.2964,37.2964,0,0,1,255.9976,358.7975Z" style="fill:#ff4d4d"/><rect height="45" rx="15" style="fill:#ef9e8b" width="30" x="241" y="275.8604"/><path d="M380.4683,241.8049H366.97v40.1513h13.4986a20.2465,20.2465,0,0,0,0-40.1513Z" style="fill:#ef9e8b"/><path d="M336.1745,244.94a7.4973,7.4973,0,0,0-10.6055,0l-2.3378,2.3383a20.6845,20.6845,0,1,0,10.605,10.6055l2.3383-2.3383A7.4973,7.4973,0,0,0,336.1745,244.94Z" style="fill:#0167a3"/><circle cx="319.5725" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M197.0363,245.5264a20.5221,20.5221,0,0,0-8.2681,1.7505l-2.3374-2.3365a7.4992,7.4992,0,0,0-10.6054,10.6055l2.3373,2.3364a20.6122,20.6122,0,1,0,18.8736-12.3559Z" style="fill:#0167a3"/><circle cx="201.647" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M131.5316,241.8049H145.03v40.1513H131.5316a20.2464,20.2464,0,0,1,0-40.1513Z" style="fill:#ef9e8b"/><path d="M389.9852,213.269v17.1752a32.8471,32.8471,0,0,0-12.2251-2.3254H367.4852c-.0751,0-.0751-.0751-.15-.0751-33-21.3739-68.475-11.55-112.2747-16.65-43.8753-5.1-57.75-40.199-57.75-40.199s-39.375,9.8236-52.5,55.7995c-.0751.3736-.2253.7489-.3,1.1243H134.16a32.7476,32.7476,0,0,0-12.15,2.3254V213.269a133.9877,133.9877,0,1,1,267.9753,0Z" style="fill:#521919"/></g></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_malayan_skin_06"><path d="M304.8661,473.543H207.1348A11.2272,11.2272,0,0,1,196.34,459.2314l18.14-63.4906a37.5,37.5,0,0,1,36.0569-27.1978h10.9277a37.5,37.5,0,0,1,36.057,27.1978l18.14,63.4906A11.2272,11.2272,0,0,1,304.8661,473.543Z" style="fill:#27b286"/><path d="M214.4791,395.7415l-12.6782,44.3756L221.09,473.543h75.5841L237.4689,370.9691A37.4417,37.4417,0,0,0,214.4791,395.7415Z" style="fill:#ffc139"/><path d="M347.8714,271.6283A52.3519,52.3519,0,0,0,278.59,297.73c-22.1425,48.9155-11.6975,122.4027,55.106,146.259,0,0-19.5151-55.11,21.6173-81.13l-.0945-.08a52.1478,52.1478,0,0,0-7.3473-91.15Z" style="fill:#071b2b"/><path d="M377.7967,228.13h-10.459a112.3416,112.3416,0,0,0-222.6754,0h-10.459a33.7509,33.7509,0,1,0,0,67.5018h10.459a112.3415,112.3415,0,0,0,222.6754,0h10.459a33.7509,33.7509,0,1,0,0-67.5018Z" style="fill:#d87761"/><path d="M255.9968,358.8a37.234,37.234,0,0,1-26.5137-10.9863,7.4992,7.4992,0,1,1,10.6055-10.6055c8.4961,8.5035,23.3276,8.5035,31.8237,0a7.4992,7.4992,0,1,1,10.6055,10.6055A37.2382,37.2382,0,0,1,255.9968,358.8Z" style="fill:#c42020"/><rect height="45" rx="15" style="fill:#bf5e48" width="30" x="241.0001" y="275.8607"/><path d="M380.4683,241.8052H366.97v40.1513h13.4985a20.2464,20.2464,0,0,0,0-40.1513Z" style="fill:#bf5e48"/><path d="M336.1746,244.9407a7.4975,7.4975,0,0,0-10.6055,0l-2.3378,2.3383a20.6845,20.6845,0,1,0,10.605,10.6055l2.3383-2.3383A7.4975,7.4975,0,0,0,336.1746,244.9407Z" style="fill:#0d253d"/><circle cx="319.5726" cy="258.4671" r="7.6845" style="fill:#ffefdc"/><path d="M197.0364,245.5267a20.5225,20.5225,0,0,0-8.2682,1.75l-2.3373-2.3365a7.4992,7.4992,0,0,0-10.6055,10.6055l2.3374,2.3364a20.6122,20.6122,0,1,0,18.8736-12.3559Z" style="fill:#0d253d"/><circle cx="201.6471" cy="258.4671" r="7.6845" style="fill:#ffefdc"/><path d="M131.5317,241.8052H145.03v40.1513H131.5317a20.2464,20.2464,0,0,1,0-40.1513Z" style="fill:#bf5e48"/><circle cx="256" cy="225.2765" r="7.4978" style="fill:#c42020"/><path d="M367.2558,227.6a112.4007,112.4007,0,0,0-111.2567-96.8262h0a112.4015,112.4015,0,0,0-111.2544,96.8134c1.7633-4.4843,15.7429-37.2236,50.8983-44.53a53.81,53.81,0,0,1,29.6882,2.016,89.76,89.76,0,0,0,61.3335,0,53.812,53.812,0,0,1,29.6887-2.016C351.5325,190.3687,365.5085,223.15,367.2558,227.6Z" style="fill:#0d253d"/><path d="M295.1684,182.7551s6.102-26.5015,36.583-29.4094c31.5692-3.01,66.7426,20.4931,61.7055,73.7793-3.8734,40.9819-26.91,43.672-22.9505,79.6163,3.9595,35.9464,5.7667,60.9717-32.0471,82.0844,0,0,22.0326-33.5947,11.2029-62.0735-10.8291-28.4767,7.2868-61.6167-4.8784-93.2742C332.6185,201.8227,310.7629,181.7357,295.1684,182.7551Z" style="fill:#162f44"/></g></svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_mongolian_skin_01"><rect height="175.2136" style="fill:#330f0f" width="225" x="143.5" y="199.2944"/><path d="M304.8655,473.543H207.1342a11.2272,11.2272,0,0,1-10.7953-14.3116l18.14-63.4906a37.5,37.5,0,0,1,36.057-27.1978h10.9277a37.5,37.5,0,0,1,36.0569,27.1978l18.14,63.4906A11.2272,11.2272,0,0,1,304.8655,473.543Z" style="fill:#243f57"/><rect height="262.2149" rx="112.4697" style="fill:#f8c497" width="224.9396" x="143.5301" y="130.7736"/><path d="M255.9962,358.7975a37.2425,37.2425,0,0,1-26.5136-10.9827,7.4992,7.4992,0,0,1,10.6054-10.6054c8.5035,8.5,23.335,8.4924,31.8238,0a7.4992,7.4992,0,0,1,10.6054,10.6054A37.2593,37.2593,0,0,1,255.9962,358.7975Z" style="fill:#f7725c"/><rect height="45" rx="15" style="fill:#ef9e72" width="30" x="240.9999" y="275.8604"/><path d="M297.3634,271.0241a7.5,7.5,0,0,1-1.0913-14.9195l35.1856-5.2185a7.5,7.5,0,0,1,2.1972,14.8389l-35.1855,5.2185A7.57,7.57,0,0,1,297.3634,271.0241Z" style="fill:#0d263e"/><path d="M214.6364,271.0241a7.57,7.57,0,0,1-1.106-.0806l-35.1855-5.2185a7.5,7.5,0,0,1,2.1972-14.8389l35.1856,5.2185a7.5,7.5,0,0,1-1.0913,14.9195Z" style="fill:#0d263e"/><path d="M251.0754,102.0416C177.9211,104.6435,121,166.9891,121,240.1891V364.9938a24.5144,24.5144,0,0,0,24.5151,24.5142h7.4487a11.4788,11.4788,0,0,0,11.478-11.4789V244.45a14.996,14.996,0,0,1,14.9954-14.9963h62.96L256,199.2944l13.602,30.1593h62.96A14.996,14.996,0,0,1,347.5582,244.45V378.0273a11.48,11.48,0,0,0,11.48,11.4807h7.4469A24.5144,24.5144,0,0,0,391,364.9938v-128.04A135.0028,135.0028,0,0,0,251.0754,102.0416Z" style="fill:#521919"/></g></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_malayan_skin_02"><path d="M336.0854,224.2449l-.01-.0027A86.7093,86.7093,0,1,0,169.29,190.983c0,96.0446,83.4773,213.7376,213.6072,211.8217C382.8972,402.8047,303.0287,305.1078,336.0854,224.2449Z" style="fill:#071b2b"/><path d="M304.8656,473.543H207.1343a11.2272,11.2272,0,0,1-10.7953-14.3116l18.14-63.4906a37.5,37.5,0,0,1,36.0569-27.1978h10.9278a37.5,37.5,0,0,1,36.0569,27.1978l18.14,63.4906A11.2272,11.2272,0,0,1,304.8656,473.543Z" style="fill:#ffc139"/><path d="M377.7967,228.13h-10.459a112.3418,112.3418,0,0,0-222.6754,0h-10.459a33.7514,33.7514,0,1,0,0,67.5027h10.459a112.3416,112.3416,0,0,0,222.6754,0h10.459a33.7514,33.7514,0,1,0,0-67.5027Z" style="fill:#d87761"/><path d="M256.0014,358.7992a37.2846,37.2846,0,0,1-26.521-10.9827,7.5018,7.5018,0,0,1,10.6054-10.6128c8.5108,8.5181,23.3277,8.5,31.8238.0037a7.4992,7.4992,0,1,1,10.6054,10.6055A37.2338,37.2338,0,0,1,256.0014,358.7992Z" style="fill:#8c1813"/><rect height="45" rx="15" style="fill:#bf5e48" width="30" x="241.0001" y="275.8604"/><path d="M380.4683,241.8049H366.97v40.1513h13.4985a20.2464,20.2464,0,0,0,0-40.1513Z" style="fill:#bf5e48"/><path d="M336.1745,244.94a7.4972,7.4972,0,0,0-10.6054,0l-2.3378,2.3383a20.6845,20.6845,0,1,0,10.605,10.6055l2.3382-2.3383A7.4973,7.4973,0,0,0,336.1745,244.94Z" style="fill:#0d253d"/><circle cx="319.5726" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M197.0363,245.5264a20.5224,20.5224,0,0,0-8.2681,1.7505l-2.3373-2.3365a7.4992,7.4992,0,0,0-10.6055,10.6055l2.3373,2.3364a20.6122,20.6122,0,1,0,18.8736-12.3559Z" style="fill:#0d253d"/><circle cx="201.647" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M131.5316,241.8049H145.03v40.1513H131.5316a20.2465,20.2465,0,0,1,0-40.1513Z" style="fill:#bf5e48"/><path d="M367.2558,227.5993a112.4007,112.4007,0,0,0-111.2567-96.8262h0a112.4014,112.4014,0,0,0-111.2544,96.8133c1.7633-4.4842,15.7429-37.2235,50.8983-44.5294a53.81,53.81,0,0,1,29.6882,2.016,89.7611,89.7611,0,0,0,61.3335,0,53.8119,53.8119,0,0,1,29.6887-2.016C351.5325,190.3684,365.5085,223.15,367.2558,227.5993Z" style="fill:#0d253d"/><path d="M295.1684,182.7548s6.1019-26.5015,36.583-29.4094c31.5692-3.01,66.7426,20.493,61.7055,73.7793-3.8734,40.9819-26.91,43.672-22.9506,79.6163,3.96,35.9464,5.7668,60.9716-32.0471,82.0844,0,0,22.0327-33.5947,11.203-62.0735-10.8292-28.4767,7.2868-61.6167-4.8785-93.2742C332.6185,201.8224,310.7629,181.7354,295.1684,182.7548Z" style="fill:#162f44"/><path d="M209.3315,181.9032s-5.5472-23.8983-33.2572-26.5419c-28.6993-2.7359-60.6751,18.63-56.0959,67.0721,3.5212,37.2562,24.4637,39.7018,20.8641,72.3784-3.6,32.6786-5.2425,55.4288,29.1337,74.6222,0,0-20.03-30.5406-10.1845-56.4305,9.8447-25.8879-6.6243-56.0151,4.435-84.7946C175.286,199.4313,195.1547,180.9765,209.3315,181.9032Z" style="fill:#162f44"/></g></svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_caucasian_skin_02"><path d="M298.5818,473.543H213.4182a11.2352,11.2352,0,0,1-11.1484-9.8416l-7.4478-59.5825A44.995,44.995,0,0,1,239.47,353.543h33.061a44.995,44.995,0,0,1,44.6475,50.5759L309.73,463.7014A11.2351,11.2351,0,0,1,298.5818,473.543Z" style="fill:#243f57"/><path d="M371.8266,219.8369H361v.0019a105,105,0,0,0-210,0v-.0019H140.1734a33.7519,33.7519,0,1,0,0,67.5037H151v-.0018a105,105,0,0,0,210,0v.0018h10.8266a33.7519,33.7519,0,1,0,0-67.5037Z" style="fill:#f8c4b0"/><path d="M256.0032,358.1493a37.26,37.26,0,0,1-26.521-10.9826,7.4992,7.4992,0,0,1,10.6055-10.6055c8.4961,8.4888,23.32,8.5034,31.8237,0a7.4992,7.4992,0,0,1,10.6055,10.6055A37.243,37.243,0,0,1,256.0032,358.1493Z" style="fill:#ff8080"/><path d="M255.9959,399.8394a111.5038,111.5038,0,0,1-47.6367-10.5579,29.7077,29.7077,0,0,1-16.5015-32.666l2.19-11.2536A34.4269,34.4269,0,0,1,210.073,322.459l8.5767-5.1635a7.5008,7.5008,0,0,1,7.7344,12.854l-8.5767,5.1635a19.4132,19.4132,0,0,0-9.0381,12.909l-2.19,11.2536a14.7363,14.7363,0,0,0,8.1372,16.22,98.1708,98.1708,0,0,0,82.5659,0A14.75,14.75,0,0,0,305.42,359.472l-2.19-11.2464a19.4119,19.4119,0,0,0-9.0381-12.9126L285.615,330.15a7.5008,7.5008,0,0,1,7.7344-12.854l8.5767,5.1635a34.4252,34.4252,0,0,1,16.0253,22.9065l2.19,11.2464a29.717,29.717,0,0,1-16.5015,32.67A111.5125,111.5125,0,0,1,255.9959,399.8394Z" style="fill:#521919"/><rect height="68.3763" rx="22.7921" style="fill:#ef9e8b" width="45.5842" x="233.208" y="263.5237"/><path d="M374.4986,233.5127H361v40.1514h13.4986a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#ef9e8b"/><circle cx="314.9628" cy="250.5027" r="20.625" style="fill:#521919"/><circle cx="319.5735" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><circle cx="197.0372" cy="250.5027" r="20.625" style="fill:#521919"/><circle cx="201.6479" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><path d="M137.5016,233.5127H151v40.1514H137.5016a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#ef9e8b"/><path d="M360.8408,216.6853A104.9274,104.9274,0,0,0,256,114.8384h0a104.9288,104.9288,0,0,0-104.84,101.8451c8.7227-28.9014,29.1971-47.1716,49.7768-58.6157C210.8243,172.28,231.73,182.11,256,182.11s45.1749-9.8309,55.0635-24.0417C331.6437,169.5119,352.119,187.784,360.8408,216.6853Z" style="fill:#521919"/></g></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_aethiopian_skin_01"><path d="M417.8908,179.2019a30.2431,30.2431,0,0,0-16.0236-48.75,30.2069,30.2069,0,0,0-30.3053-41.3394,30.2951,30.2951,0,0,0-41.5682-30.08,30.255,30.255,0,0,0-48.9011-15.6471,30.202,30.202,0,0,0-51.2407.1513,30.1841,30.1841,0,0,0-48.75,15.946,30.293,30.293,0,0,0-41.417,30.3089,30.2185,30.2185,0,0,0-30.08,41.4907,30.3149,30.3149,0,0,0-15.721,48.901,30.2434,30.2434,0,0,0,.0775,51.2406,30.2629,30.2629,0,0,0,15.9461,48.75,30.25,30.25,0,0,0,30.2314,41.4944,30.2186,30.2186,0,0,0,41.4908,30.08,30.2451,30.2451,0,0,0,48.8272,15.7947,30.2269,30.2269,0,0,0,51.3146-.0775,30.2,30.2,0,0,0,48.75-15.8685,30.244,30.244,0,0,0,41.4945-30.1576A30.2206,30.2206,0,0,0,402.17,279.9487a30.28,30.28,0,0,0,15.8723-48.8234A30.2052,30.2052,0,0,0,432.25,205.5031v-.679A30.4,30.4,0,0,0,417.8908,179.2019Z" style="fill:#0d263e"/><path d="M304.8656,473.543H207.1342a11.2273,11.2273,0,0,1-10.7953-14.3116l18.14-63.4906A37.5,37.5,0,0,1,250.536,368.543h10.9278a37.5,37.5,0,0,1,36.0569,27.1978l18.14,63.4906A11.2273,11.2273,0,0,1,304.8656,473.543Z" style="fill:#27b286"/><path d="M377.7965,228.13h-10.459a112.3415,112.3415,0,0,0-222.6754,0H134.204a33.7519,33.7519,0,1,0,0,67.5037h10.4581a112.3418,112.3418,0,0,0,222.6754,0h10.459a33.7519,33.7519,0,1,0,0-67.5037Z" style="fill:#a5442e"/><path d="M256.0021,358.7975a37.2964,37.2964,0,0,1-26.521-10.979,7.5018,7.5018,0,1,1,10.6055-10.6128c8.5107,8.5034,23.3276,8.5,31.8237.0037a7.4992,7.4992,0,0,1,10.6055,10.6054A37.2429,37.2429,0,0,1,256.0021,358.7975Z" style="fill:#8c1813"/><rect height="45" rx="15" style="fill:#8c2b15" width="30" x="241" y="275.8604"/><path d="M380.4682,241.8049H366.97v40.1513h13.4985a20.2464,20.2464,0,0,0,0-40.1513Z" style="fill:#8c2b15"/><path d="M336.1745,244.94a7.4973,7.4973,0,0,0-10.6055,0l-2.3378,2.3383a20.6845,20.6845,0,1,0,10.605,10.6055l2.3383-2.3383A7.4975,7.4975,0,0,0,336.1745,244.94Z" style="fill:#0d253d"/><circle cx="319.5725" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M197.0363,245.5264a20.5225,20.5225,0,0,0-8.2682,1.7505l-2.3373-2.3365a7.4992,7.4992,0,0,0-10.6055,10.6055l2.3374,2.3364a20.6122,20.6122,0,1,0,18.8736-12.3559Z" style="fill:#0d253d"/><circle cx="201.647" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M131.5316,241.8049H145.03v40.1513H131.5316a20.2464,20.2464,0,0,1,0-40.1513Z" style="fill:#8c2b15"/><path d="M377.7964,228.13a121.7965,121.7965,0,1,0-243.5929,0h10.3343c11.9392-.0807,23.96-7.189,27.6286-19.1112,15.9833,11.3741,41.7437.1057,44.083-19.4047,15.7172,7.5521,37.45-3.7945,39.7506-21.3824,2.3008,17.5879,24.0333,28.9345,39.75,21.3824,2.3393,19.51,28.1,30.7788,44.083,19.4047,3.6683,11.9222,15.6894,19.0305,27.6286,19.1112Z" style="fill:#0d263e"/></g></svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_malayan_skin_05"><path d="M317.1627,404.168l-7.4253,59.55a11.1994,11.1994,0,0,1-11.175,9.8254H213.4376a11.1993,11.1993,0,0,1-11.1749-9.8254l-7.4254-59.55a45.0062,45.0062,0,0,1,44.6251-50.625h33.0753A45.0061,45.0061,0,0,1,317.1627,404.168Z" style="fill:#f4e2ff"/><path d="M371.8266,219.8376H361v.0018a105,105,0,0,0-210,0v-.0018H140.1734a33.7514,33.7514,0,1,0,0,67.5027H151v-.0009a105,105,0,1,0,210,0v.0009h10.8266a33.7514,33.7514,0,1,0,0-67.5027Z" style="fill:#d87761"/><path d="M277.3674,376.1274H234.6329a8.6155,8.6155,0,0,0-5.9872,14.8106l21.3673,20.65a8.6157,8.6157,0,0,0,11.9743,0l21.3672-20.65A8.6154,8.6154,0,0,0,277.3674,376.1274Z" style="fill:#0d263e"/><path d="M256,358.15a37.243,37.243,0,0,1-26.5137-10.9826,7.4992,7.4992,0,0,1,10.6055-10.6055c8.4961,8.4961,23.32,8.4961,31.8164,0a7.4992,7.4992,0,1,1,10.6055,10.6055A37.243,37.243,0,0,1,256,358.15Z" style="fill:#8c1813"/><path d="M315.2383,339.0044a7.4637,7.4637,0,0,1-1.9483-.26l-21.7309-5.8227a7.4992,7.4992,0,1,1,3.8818-14.4873l21.731,5.8227a7.5018,7.5018,0,0,1-1.9336,14.7473Z" style="fill:#0d263e"/><path d="M196.7617,339.0044a7.5018,7.5018,0,0,1-1.9336-14.7473l21.731-5.8227a7.4992,7.4992,0,1,1,3.8818,14.4873L198.71,338.7444A7.4637,7.4637,0,0,1,196.7617,339.0044Z" style="fill:#0d263e"/><path d="M374.4984,233.5127H361v40.1514h13.4985a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#bf5e48"/><path d="M137.5015,233.5127H151v40.1514H137.5015a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#bf5e48"/><path d="M314.9627,201.7527a48.717,48.717,0,0,0-41.24,22.8735H238.2777a49.0111,49.0111,0,1,0,6.243,15h22.9587a48.7289,48.7289,0,1,0,47.4833-37.8735Z" style="fill:#8ca4bc"/><circle cx="314.9627" cy="250.5027" r="33.75" style="fill:#0d253d"/><circle cx="305.1318" cy="240.6718" r="11.25" style="fill:#ffefdc"/><circle cx="197.0373" cy="250.5027" r="33.75" style="fill:#0d253d"/><circle cx="187.2064" cy="240.6718" r="11.25" style="fill:#ffefdc"/><rect height="68.3763" rx="22.7921" style="fill:#bf5e48" width="45.5842" x="233.208" y="263.5237"/><path d="M361,219.8377a105,105,0,0,0-210,0c22.3892-84.0876,105-50.9125,105-50.9125S338.6109,135.75,361,219.8377Z" style="fill:#0d263e"/></g></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_mongolian_skin_01"><path d="M298.5816,473.543H213.418a11.2352,11.2352,0,0,1-11.1484-9.8416l-7.4478-59.5825a44.995,44.995,0,0,1,44.6475-50.5759H272.53a44.995,44.995,0,0,1,44.6475,50.5759L309.73,463.7014A11.2351,11.2351,0,0,1,298.5816,473.543Z" style="fill:#eb5e59"/><path d="M371.8266,219.8369H361v.0019a105,105,0,0,0-105-105h0a105,105,0,0,0-105,105v-.0019H140.173a33.7519,33.7519,0,1,0,0,67.5037H151v-.0018a104.9989,104.9989,0,0,0,105,105h0a104.999,104.999,0,0,0,105-105v.0018h10.8266a33.7519,33.7519,0,1,0,0-67.5037Z" style="fill:#f8c497"/><path d="M256.0032,358.1493a37.26,37.26,0,0,1-26.521-10.9826,7.4992,7.4992,0,0,1,10.6055-10.6055c8.4961,8.4888,23.3276,8.5034,31.8237,0a7.4992,7.4992,0,0,1,10.6055,10.6055A37.243,37.243,0,0,1,256.0032,358.1493Z" style="fill:#f7725c"/><rect height="60.0155" rx="16.6061" style="fill:#ef9e72" width="33.2122" x="239.3938" y="262.6054"/><path d="M374.4984,233.5127H361v40.1514h13.4986a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#ef9e72"/><path d="M297.3631,275.6127a7.5,7.5,0,0,1-1.0913-14.9194l35.1855-5.2185a7.5,7.5,0,1,1,2.1973,14.8388l-35.1856,5.2185A7.5541,7.5541,0,0,1,297.3631,275.6127Z" style="fill:#0d263e"/><path d="M214.6433,275.6127a7.5541,7.5541,0,0,1-1.1059-.0806l-35.1929-5.2185a7.5,7.5,0,1,1,2.1973-14.8388l35.1928,5.2185a7.5,7.5,0,0,1-1.0913,14.9194Z" style="fill:#0d263e"/><path d="M137.5014,233.5127H151v40.1514H137.5014a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#ef9e72"/><path d="M361,219.8384h10.8266a33.3821,33.3821,0,0,1,16.6676,4.5758l6.6609-38.2526a45.7583,45.7583,0,0,0-45.0787-53.61l-24.1695-20.9839c-23.9712-20.8117-55.69-30.8276-87.149-26.58-30.36,4.1016-66.6023,14.6705-90.1676,40.2247-61.8118,67.02-4.2086,115.21-4.2086,115.21s13.5543-34.6966,41.64-51.93c0,0,28.4043,30.3186,93.34,33.7408l-5.2427-22.8186s37.288,14.17,86.8808,20.4236Z" style="fill:#0d263e"/></g></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_caucasian_skin_09"><path d="M355.7879,344.1924a324.7,324.7,0,0,0,31.1243,22.95s-57.2242,43.35-130.95-3.2245c-73.65,46.5747-130.8747,3.2245-130.8747,3.2245a334.4056,334.4056,0,0,0,31.1243-22.9495c-44.0991-3.2254-69.2249-30.45-69.2249-30.45a336.8922,336.8922,0,0,0,38.6252-19.2755H386.3876a336.8922,336.8922,0,0,0,38.6252,19.2755S399.887,340.967,355.7879,344.1924Z" style="fill:#521919"/><path d="M304.8623,473.543H207.131a11.2272,11.2272,0,0,1-10.7953-14.3116l18.14-63.4906a37.5,37.5,0,0,1,36.0569-27.1978h10.9277a37.5,37.5,0,0,1,36.0569,27.1978l18.14,63.4906A11.2272,11.2272,0,0,1,304.8623,473.543Z" style="fill:#ffc139"/><path d="M377.7935,228.13h-10.459a112.4041,112.4041,0,0,0-111.3372-97.3563h-.001A112.4055,112.4055,0,0,0,144.6591,228.13H134.2a33.7509,33.7509,0,1,0,0,67.5018h10.459a112.4063,112.4063,0,0,0,111.3372,97.3572h.001a112.405,112.405,0,0,0,111.3372-97.3572h10.459a33.7509,33.7509,0,1,0,0-67.5018Z" style="fill:#f8c4b0"/><path d="M255.9936,358.8A37.234,37.234,0,0,1,229.48,347.8133a7.4992,7.4992,0,1,1,10.6055-10.6055c8.4888,8.5,23.3057,8.5108,31.8237-.0036a7.5018,7.5018,0,0,1,10.6055,10.6127A37.2848,37.2848,0,0,1,255.9936,358.8Z" style="fill:#ff4d4d"/><rect height="45" rx="15" style="fill:#ef9e8b" width="30" x="240.9968" y="275.8604"/><path d="M380.465,241.8049H366.9664v40.1513H380.465a20.2465,20.2465,0,0,0,0-40.1513Z" style="fill:#ef9e8b"/><path d="M336.1712,244.94a7.4973,7.4973,0,0,0-10.6055,0l-2.3378,2.3383a20.684,20.684,0,1,0,10.6051,10.6055l2.3382-2.3383A7.4973,7.4973,0,0,0,336.1712,244.94Z" style="fill:#004b28"/><circle cx="319.5692" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M197.033,245.5264a20.5221,20.5221,0,0,0-8.2681,1.7505l-2.3373-2.3365a7.4992,7.4992,0,0,0-10.6055,10.6055l2.3373,2.3364a20.6122,20.6122,0,1,0,18.8736-12.3559Z" style="fill:#004b28"/><circle cx="201.6437" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M131.5283,241.8049h13.4986v40.1513H131.5283a20.2465,20.2465,0,0,1,0-40.1513Z" style="fill:#ef9e8b"/><path d="M389.9874,213.2427v17.2494a32.7476,32.7476,0,0,0-12.15-2.3245h-10.35c-.0751,0-.0751-.0751-.15-.0751-33-21.45-68.4-11.5494-112.2757-16.7248-43.8739-5.1-57.75-40.2-57.75-40.2s-39.6753,9.9746-52.5751,56.4752c-.075.15-.075.3744-.15.5246H134.2376a33.1425,33.1425,0,0,0-12.226,2.3245V213.2427a133.9879,133.9879,0,0,1,267.9758,0Z" style="fill:#521919"/></g></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_caucasian_skin_09"><path d="M368.3335,287.34H143.6668c5.6762,30.1013-33.3952,63.6232-33.3952,63.6232S139.2987,405.7356,256,370.3551c116.7017,35.38,145.7284-19.3917,145.7284-19.3917S362.6574,317.4415,368.3335,287.34Z" style="fill:#0d263e"/><path d="M272.5306,353.543H239.47a44.9514,44.9514,0,0,0-11.22,1.4612V473.543h55.5V355.0042A44.9457,44.9457,0,0,0,272.5306,353.543Z" style="fill:#8ca4bc"/><path d="M309.73,463.6992l7.4479-59.5825A44.977,44.977,0,0,0,283.75,355.0042V473.543h14.8315A11.237,11.237,0,0,0,309.73,463.6992Z" style="fill:#521919"/><path d="M194.822,404.1167l7.4479,59.5825a11.2361,11.2361,0,0,0,11.1483,9.8438H228.25V355.0042A44.9768,44.9768,0,0,0,194.822,404.1167Z" style="fill:#521919"/><path d="M371.827,219.8372H361a105,105,0,0,0-210,.0018v-.0018H140.1734a33.7519,33.7519,0,1,0,0,67.5037H151v-.0019a105,105,0,0,0,210,.0019h10.827a33.7519,33.7519,0,1,0,0-67.5037Z" style="fill:#f8c4b0"/><path d="M277.3675,376.1274H234.6329a8.6154,8.6154,0,0,0-5.9871,14.8106l21.3673,20.65a8.6156,8.6156,0,0,0,11.9742,0l21.3673-20.65A8.6154,8.6154,0,0,0,277.3675,376.1274Z" style="fill:#0d263e"/><path d="M256.0018,358.1514a37.2851,37.2851,0,0,1-26.521-10.9826,7.5018,7.5018,0,0,1,10.6055-10.6128c8.5181,8.518,23.335,8.5,31.8237.0036a7.4992,7.4992,0,1,1,10.6055,10.6055A37.2338,37.2338,0,0,1,256.0018,358.1514Z" style="fill:#ff8080"/><rect height="68.3763" rx="22.7921" style="fill:#ef9e8b" width="45.5842" x="233.2081" y="263.5237"/><path d="M374.4987,233.5127H361v40.1514h13.4986a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#ef9e8b"/><circle cx="314.9629" cy="250.5027" r="20.625" style="fill:#0d263e"/><circle cx="319.5736" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><circle cx="197.0373" cy="250.5027" r="20.625" style="fill:#0d263e"/><circle cx="201.648" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><path d="M137.5017,233.5127H151v40.1514H137.5017a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#ef9e8b"/><path d="M151.1105,219.8372H140.2839a33.3783,33.3783,0,0,0-16.5939,4.5374h-.298a134.0012,134.0012,0,1,1,265.2319-.108h-.2911a33.3778,33.3778,0,0,0-16.3957-4.4294H361.1105l-.11,0c-33.067-21.4966-62.144-11.6242-106.0468-16.7329-43.9027-5.105-57.7409-40.2136-57.7409-40.2136S163.2137,176.3867,151,219.8376h0" style="fill:#0d263e"/></g></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_mongolian_skin_02"><rect height="251.9144" style="fill:#071b2b" width="225" x="143.4996" y="199.2949"/><path d="M304.8657,473.543H207.1343a11.2273,11.2273,0,0,1-10.7953-14.3116l18.14-63.4906a37.5,37.5,0,0,1,36.0569-27.1978h10.9278a37.5,37.5,0,0,1,36.0569,27.1978l18.14,63.4906A11.2273,11.2273,0,0,1,304.8657,473.543Z" style="fill:#f4e2ff"/><rect height="262.2149" rx="112.4697" style="fill:#f8c497" width="224.9396" x="143.5297" y="130.7736"/><path d="M255.9972,358.7992a37.2338,37.2338,0,0,1-26.5137-10.9863,7.4992,7.4992,0,1,1,10.6055-10.6055c8.4961,8.4961,23.313,8.5144,31.8237-.0037a7.5018,7.5018,0,0,1,10.6055,10.6128A37.2848,37.2848,0,0,1,255.9972,358.7992Z" style="fill:#f7725c"/><rect height="45" rx="15" style="fill:#ef9e72" width="30" x="240.9995" y="275.8604"/><path d="M297.357,271.0221a7.5,7.5,0,0,1-1.0913-14.9194l35.1929-5.2185a7.5,7.5,0,1,1,2.1973,14.8388l-35.1929,5.2185A7.5554,7.5554,0,0,1,297.357,271.0221Z" style="fill:#0d263e"/><path d="M214.6373,271.0221a7.5541,7.5541,0,0,1-1.1059-.0806l-35.1856-5.2185a7.5,7.5,0,1,1,2.1973-14.8388l35.1855,5.2185a7.5,7.5,0,0,1-1.0913,14.9194Z" style="fill:#0d263e"/><path d="M251.0757,102.0422C177.9208,104.6443,121,166.99,121,240.191V454.1591a12.05,12.05,0,0,0,12.05,12.05h19.341a12.05,12.05,0,0,0,12.05-12.05V244.4505a14.9963,14.9963,0,0,1,14.9963-14.9963h62.9593L256,199.2949l13.602,30.1593h62.96A14.9954,14.9954,0,0,1,347.5582,244.45V389.5058c0,.0011.0007,43.0646.0017,64.6575A12.0473,12.0473,0,0,0,359.61,466.21H378.95a12.05,12.05,0,0,0,12.05-12.05V236.9542A135.0028,135.0028,0,0,0,251.0757,102.0422Z" style="fill:#0d263e"/></g></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_mongolian_skin_05"><path d="M349.8016,344.6948l-.1623.0093a69.2839,69.2839,0,1,0-132.9816,7.1951C239.8993,419.1358,316.88,480.338,402.89,442.4525,402.89,442.4525,333.92,407.1951,349.8016,344.6948Z" style="fill:#071b2b"/><path d="M309.4268,43.4034l-46.7143,26.97-46.7148-26.97a21.675,21.675,0,0,0-32.514,18.772v46.8915a21.6756,21.6756,0,0,0,32.514,18.7719l46.7148-26.97,46.7143,26.97a21.6757,21.6757,0,0,0,32.5141-18.772V62.1754A21.6751,21.6751,0,0,0,309.4268,43.4034Z" style="fill:#eb5e59"/><rect height="68.2979" rx="18.1915" style="fill:#dd4747" width="36.383" x="244.5208" y="51.4717"/><path d="M322.3732,459.2315l-18.14-63.49a37.3021,37.3021,0,0,0-5.8567-11.8195l-35.6639,46.7725h-.0009L227.0476,383.922a37.3115,37.3115,0,0,0-5.8562,11.8195l-18.14,63.49a11.2273,11.2273,0,0,0,10.7954,14.3115h97.7312A11.2271,11.2271,0,0,0,322.3732,459.2315Z" style="fill:#f4e2ff"/><path d="M298.3763,383.922a37.6117,37.6117,0,0,0-19.8431-13.85l-15.8208,60.6226Z" style="fill:#3285e2"/><path d="M262.712,430.6945l-15.8213-60.6226a37.61,37.61,0,0,0-19.8431,13.85l35.6639,46.7725Z" style="fill:#3285e2"/><path d="M262.7124,430.6945l15.8208-60.6226a37.0648,37.0648,0,0,0-10.3569-1.5289H257.2486a37.07,37.07,0,0,0-10.3579,1.5289l15.8213,60.6226Z" style="fill:#f8c497"/><path d="M384.5089,228.1322H374.05a112.3415,112.3415,0,0,0-222.6754,0H140.9159a33.7509,33.7509,0,1,0,0,67.5018h10.4586a112.3415,112.3415,0,0,0,222.6754,0h10.459a33.7509,33.7509,0,1,0,0-67.5018Z" style="fill:#f8c497"/><path d="M262.7122,358.8a37.243,37.243,0,0,1-26.5137-10.9826,7.4992,7.4992,0,0,1,10.6055-10.6055c8.4961,8.4961,23.32,8.4961,31.8164,0a7.4992,7.4992,0,0,1,10.6055,10.6055A37.2432,37.2432,0,0,1,262.7122,358.8Z" style="fill:#ff4d4d"/><rect height="45" rx="15" style="fill:#ef9e72" width="30" x="247.7124" y="275.8625"/><path d="M387.1806,241.8069H373.6821v40.1514h13.4985a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#ef9e72"/><path d="M342.8868,244.9425a7.4972,7.4972,0,0,0-10.6054,0l-2.3378,2.3382a20.6845,20.6845,0,1,0,10.605,10.6055l2.3382-2.3383A7.4972,7.4972,0,0,0,342.8868,244.9425Z" style="fill:#0d253d"/><circle cx="326.2849" cy="258.4689" r="7.6845" style="fill:#ffefdc"/><path d="M203.7487,245.5284a20.5242,20.5242,0,0,0-8.2682,1.75l-2.3373-2.3364a7.4992,7.4992,0,0,0-10.6055,10.6054l2.3374,2.3365a20.6122,20.6122,0,1,0,18.8736-12.356Z" style="fill:#0d253d"/><circle cx="208.3593" cy="258.4689" r="7.6845" style="fill:#ffefdc"/><path d="M138.244,241.8069h13.4985v40.1514H138.244a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#ef9e72"/><path d="M262.6719,79.2931c-121.5747,0-168.9748,51.45-168.9748,110.1746,0,26.7,11.85,42.0758,21.75,50.3247a33.49,33.49,0,0,1,12.9721-9.08c3.0555,105.8194,42.2424,162.279,42.2424,162.279V217.7767h-.0124c22.2176-7.3453,46.3161-2.4143,74.6229-6.4087,36.75-5.1,48.3-40.2,48.3-40.2s18.1865,41.8451,64.7186,54.1086H357.9V378.3922s37.3141-53.3862,38.6709-147.9364c.04.0156.0861.02.1264.0366V213.243A134.0025,134.0025,0,0,0,262.6719,79.2931Z" style="fill:#0d253d"/></g></svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_caucasian_skin_05"><path d="M389.9849,278.0225h-267.97s-7.6932,44.8883-37.0551,70.9918c0,0,42.7185,40.1917,171.04,40.1917s171.04-40.1917,171.04-40.1917C397.679,322.9108,389.9849,278.0225,389.9849,278.0225Z" style="fill:#521919"/><path d="M304.866,473.543H207.1347a11.2272,11.2272,0,0,1-10.7953-14.3116l18.14-63.4906a37.5,37.5,0,0,1,36.0569-27.1978h10.9278a37.5,37.5,0,0,1,36.0569,27.1978l18.14,63.4906A11.2272,11.2272,0,0,1,304.866,473.543Z" style="fill:#0d263e"/><path d="M377.7969,228.13h-10.459a112.3416,112.3416,0,0,0-222.6755,0H134.2039a33.7509,33.7509,0,1,0,0,67.5018h10.4585a112.3417,112.3417,0,0,0,222.6755,0h10.459a33.7509,33.7509,0,1,0,0-67.5018Z" style="fill:#f8c4b0"/><path d="M256,358.7981a37.2428,37.2428,0,0,1-26.5136-10.9826A7.4992,7.4992,0,1,1,240.0919,337.21c8.4961,8.4961,23.32,8.4961,31.8164,0a7.4992,7.4992,0,0,1,10.6055,10.6055A37.2428,37.2428,0,0,1,256,358.7981Z" style="fill:#ff4d4d"/><rect height="45" rx="15" style="fill:#ef9e8b" width="30" x="241.0003" y="275.8604"/><path d="M380.4685,241.8049H366.97v40.1513h13.4985a20.2464,20.2464,0,0,0,0-40.1513Z" style="fill:#ef9e8b"/><path d="M336.1748,244.94a7.4973,7.4973,0,0,0-10.6055,0l-2.3378,2.3383a20.6845,20.6845,0,1,0,10.605,10.6055l2.3383-2.3383A7.4973,7.4973,0,0,0,336.1748,244.94Z" style="fill:#004b28"/><circle cx="319.5728" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M197.0366,245.5264a20.5217,20.5217,0,0,0-8.2681,1.7505l-2.3374-2.3365a7.4992,7.4992,0,0,0-10.6054,10.6055l2.3373,2.3364a20.6122,20.6122,0,1,0,18.8736-12.3559Z" style="fill:#004b28"/><circle cx="201.6473" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M131.5319,241.8049H145.03v40.1513H131.5319a20.2464,20.2464,0,0,1,0-40.1513Z" style="fill:#ef9e8b"/><path d="M389.9855,213.2375v17.1744a34.2838,34.2838,0,0,0-12.15-2.2494h-10.35c-.0751,0-.0751-.0751-.15-.0751-33-21.45-68.4-11.5494-112.2748-16.7249-43.8752-5.1-57.75-40.2-57.75-40.2s-39.375,9.9006-52.5,55.8747c-.075.3753-.2252.7507-.3,1.1252h-10.275a34.3868,34.3868,0,0,0-12.225,2.2494V213.2375a133.9877,133.9877,0,0,1,267.9753,0Z" style="fill:#521919"/></g></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_malayan_skin_04"><path d="M317.1629,404.168l-7.4254,59.55a11.1994,11.1994,0,0,1-11.1749,9.8254H213.4377a11.1994,11.1994,0,0,1-11.1749-9.8254l-7.4254-59.55a45.0062,45.0062,0,0,1,44.6251-50.625h33.0753A45.0062,45.0062,0,0,1,317.1629,404.168Z" style="fill:#3285e2"/><polygon points="278.762 441.067 256.038 463.194 233.238 440.394 251.313 353.543 261.138 353.543 278.762 441.067" style="fill:#243f57"/><path d="M371.8266,219.8376H361v.0018a105,105,0,0,0-210,0v-.0018H140.1734a33.7514,33.7514,0,1,0,0,67.5027H151v-.0009a105,105,0,1,0,210,0v.0009h10.8266a33.7514,33.7514,0,1,0,0-67.5027Z" style="fill:#d87761"/><path d="M256.0032,358.15a37.26,37.26,0,0,1-26.521-10.9826,7.4992,7.4992,0,0,1,10.6055-10.6055c8.4887,8.4924,23.32,8.5,31.8237,0a7.4992,7.4992,0,0,1,10.6055,10.6055A37.243,37.243,0,0,1,256.0032,358.15Z" style="fill:#8c1813"/><rect height="68.3763" rx="22.7921" style="fill:#bf5e48" width="45.5842" x="233.208" y="263.5237"/><path d="M374.4985,233.5127H361v40.1514h13.4986a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#bf5e48"/><circle cx="314.9628" cy="250.5027" r="20.625" style="fill:#521919"/><circle cx="319.5735" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><circle cx="197.0373" cy="250.5027" r="20.625" style="fill:#521919"/><circle cx="201.648" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><path d="M137.5015,233.5127H151v40.1514H137.5015a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#bf5e48"/></g></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_caucasian_skin_06"><path d="M317.1625,404.168l-7.4253,59.55a11.1994,11.1994,0,0,1-11.175,9.8254H213.4374a11.1993,11.1993,0,0,1-11.1749-9.8254l-7.4254-59.55a45.0062,45.0062,0,0,1,44.6251-50.625h33.0753A45.0061,45.0061,0,0,1,317.1625,404.168Z" style="fill:#eb5e59"/><path d="M371.8266,219.8376H361v.0018a105,105,0,0,0-105-105h0a105,105,0,0,0-105,105v-.0018H140.1734a33.7514,33.7514,0,1,0,0,67.5027H151v-.0009a105,105,0,0,0,105,105h0a105,105,0,0,0,105-105v.0009h10.8266a33.7514,33.7514,0,1,0,0-67.5027Z" style="fill:#f8c4b0"/><path d="M255.9968,358.15a37.243,37.243,0,0,1-26.5137-10.9826,7.4992,7.4992,0,0,1,10.6055-10.6055c8.4961,8.4961,23.313,8.5,31.8237-.0037a7.5018,7.5018,0,0,1,10.6055,10.6128A37.2966,37.2966,0,0,1,255.9968,358.15Z" style="fill:#ff8080"/><path d="M255.9968,399.8394A111.5042,111.5042,0,0,1,208.36,389.2815a29.7077,29.7077,0,0,1-16.5015-32.666l2.19-11.2536a34.4265,34.4265,0,0,1,16.0253-22.9029l8.5767-5.1635a7.5008,7.5008,0,0,1,7.7344,12.854l-8.5767,5.1635a19.4132,19.4132,0,0,0-9.0381,12.909l-2.19,11.2536a14.7363,14.7363,0,0,0,8.1372,16.22,98.1708,98.1708,0,0,0,82.5659,0,14.75,14.75,0,0,0,8.1372-16.2231l-2.19-11.2464a19.4119,19.4119,0,0,0-9.0381-12.9126l-8.5767-5.1635a7.5008,7.5008,0,0,1,7.7344-12.854l8.5767,5.1635a34.4257,34.4257,0,0,1,16.0254,22.9065l2.19,11.2464a29.717,29.717,0,0,1-16.5015,32.67A111.5122,111.5122,0,0,1,255.9968,399.8394Z" style="fill:#521919"/><rect height="68.3763" rx="22.7921" style="fill:#ef9e8b" width="45.5842" x="233.2078" y="263.5237"/><path d="M374.4984,233.5127H361v40.1514h13.4985a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#ef9e8b"/><circle cx="314.9626" cy="250.5027" r="20.625" style="fill:#521919"/><circle cx="319.5733" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><circle cx="197.0371" cy="250.5027" r="20.625" style="fill:#521919"/><circle cx="201.6478" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><path d="M137.5014,233.5127H151v40.1514H137.5014a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#ef9e8b"/><path d="M321.25,137.62s2.531,20.766-9.3,35.9234c0,0,32.7749,8.7763,49.05,46.2763A104.5351,104.5351,0,0,0,321.25,137.62Z" style="fill:#8ca4bc"/><path d="M321.25,137.62s-30.5406-56.5668-105.2426-28.0481l.0554-.0623c-21.7411,8.26-57.0868,8.9777-57.0868,8.9777a68.6075,68.6075,0,0,0,12.8087,17.4664C130.9668,173.855,151,219.8383,151,219.8383s27.843-29.78,82.765-29.78S311.95,173.5437,311.95,173.5437C323.781,158.3863,321.25,137.62,321.25,137.62Z" style="fill:#521919"/></g></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_caucasian_skin_08"><path d="M272.5305,353.543H239.47a44.9514,44.9514,0,0,0-11.22,1.4612V473.543h55.5V355.0042A44.9451,44.9451,0,0,0,272.5305,353.543Z" style="fill:#f4e2ff"/><polygon points="278.762 441.067 256.038 463.194 233.238 440.394 251.313 353.543 261.137 353.543 278.762 441.067" style="fill:#eb5e59"/><path d="M309.73,463.6992l7.4478-59.5825A44.977,44.977,0,0,0,283.75,355.0042V473.543h14.8315A11.2372,11.2372,0,0,0,309.73,463.6992Z" style="fill:#243f57"/><path d="M194.822,404.1167l7.4478,59.5825a11.2361,11.2361,0,0,0,11.1483,9.8438H228.25V355.0042A44.9766,44.9766,0,0,0,194.822,404.1167Z" style="fill:#243f57"/><path d="M371.8266,219.8357H361v.0037a105,105,0,0,0-210,0v-.0037H140.1734a33.7519,33.7519,0,1,0,0,67.5037H151v-.001a105,105,0,0,0,210,0v.001h10.8266a33.7519,33.7519,0,1,0,0-67.5037Z" style="fill:#f8c4b0"/><path d="M256.0023,358.15a37.2846,37.2846,0,0,1-26.521-10.9827,7.5018,7.5018,0,0,1,10.6055-10.6128c8.518,8.5145,23.3276,8.5035,31.8237.0037a7.4992,7.4992,0,1,1,10.6055,10.6055A37.234,37.234,0,0,1,256.0023,358.15Z" style="fill:#ff8080"/><rect height="90" rx="30" style="fill:#ef9e8b" width="60" x="226" y="245.2107"/><path d="M374.4984,233.5116H361V273.663h13.4985a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#ef9e8b"/><circle cx="314.9628" cy="250.5016" r="20.625" style="fill:#004b28"/><circle cx="319.5735" cy="242.8171" r="7.6845" style="fill:#ffefdc"/><circle cx="197.0372" cy="250.5016" r="20.625" style="fill:#004b28"/><circle cx="201.6479" cy="242.8171" r="7.6845" style="fill:#ffefdc"/><path d="M137.5015,233.5116H151V273.663H137.5015a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#ef9e8b"/><path d="M361.3283,144.3817c0-49.7864-122.3735-112.98-196.9427-40.8508-49.5452,47.9205-45.7908,93.9814-37.5776,119.087a33.559,33.559,0,0,1,13.3649-2.7814H151c12.2136-43.4509,46.2124-56.9465,46.2124-56.9465s13.8382,35.1086,57.7409,40.2136c43.9027,5.1087,72.98-4.7637,106.0468,16.7329h10.8266a33.5545,33.5545,0,0,1,13.6532,2.937C403.6114,164.6851,361.3283,144.3817,361.3283,144.3817Z" style="fill:#521919"/></g></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_mongolian_skin_04"><path d="M298.5818,473.543H213.4182a11.2352,11.2352,0,0,1-11.1484-9.8416l-7.4478-59.5825A44.995,44.995,0,0,1,239.47,353.543h33.061a44.9949,44.9949,0,0,1,44.6475,50.5759L309.73,463.7014A11.2351,11.2351,0,0,1,298.5818,473.543Z" style="fill:#f4e2ff"/><path d="M371.8266,219.8376H361v.0018a105,105,0,0,0-210,0v-.0018H140.1734a33.7514,33.7514,0,1,0,0,67.5027H151v-.0009a105,105,0,1,0,210,0v.0009h10.8266a33.7514,33.7514,0,1,0,0-67.5027Z" style="fill:#f8c497"/><path d="M256,358.15a37.243,37.243,0,0,1-26.5137-10.9826,7.4992,7.4992,0,0,1,10.6055-10.6055c8.4961,8.4961,23.32,8.4961,31.8164,0a7.4992,7.4992,0,1,1,10.6055,10.6055A37.243,37.243,0,0,1,256,358.15Z" style="fill:#f7725c"/><path d="M317.2451,354.1033a7.498,7.498,0,0,1-7.5-7.5V342.22a10.6412,10.6412,0,0,0-8.0347-10.3272l-15.9448-4.0356a7.4982,7.4982,0,1,1,3.6768-14.5386l15.9448,4.0356A25.6227,25.6227,0,0,1,324.7451,342.22v4.3835A7.498,7.498,0,0,1,317.2451,354.1033Z" style="fill:#0d263e"/><path d="M194.7549,354.1033a7.498,7.498,0,0,1-7.5-7.5V342.22a25.6227,25.6227,0,0,1,19.3579-24.8658l15.9448-4.0356a7.4982,7.4982,0,1,1,3.6768,14.5386L210.29,331.8926a10.6412,10.6412,0,0,0-8.0347,10.3272v4.3835A7.498,7.498,0,0,1,194.7549,354.1033Z" style="fill:#0d263e"/><rect height="60.0155" rx="16.6061" style="fill:#ef9e72" width="33.2122" x="239.3939" y="262.6054"/><path d="M374.4985,233.5127H361v40.1514h13.4985a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#ef9e72"/><path d="M297.36,275.6133a7.5,7.5,0,0,1-1.0913-14.9194l35.1928-5.2185a7.5,7.5,0,0,1,2.1973,14.8389l-35.1929,5.2185A7.5677,7.5677,0,0,1,297.36,275.6133Z" style="fill:#0d263e"/><path d="M214.64,275.6133a7.5677,7.5677,0,0,1-1.1059-.08l-35.1929-5.2185a7.5,7.5,0,1,1,2.1973-14.8389l35.1928,5.2185a7.5,7.5,0,0,1-1.0913,14.9194Z" style="fill:#0d263e"/><path d="M137.5015,233.5127H151v40.1514H137.5015a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#ef9e72"/><path d="M256,114.8391c-27.2731-2.9608-48.4168-20.354-48.4168-20.354s-.9677,18.2739,7.4552,28.645c0,0-15.1145-.78-24.6094-8.291,0,0,.1227,13.0078,5.2634,19.1309A104.8047,104.8047,0,0,0,151,219.8373c.0037-.011,9.8172-39.4941,51.6536-53.5016h.02c13.18,13.1634,32.1565,21.4819,53.3267,21.4819s40.1468-8.3185,53.3267-21.4819h.02c36.5144,12.2241,48.63,43.8446,51.1249,51.7016l.5287,1.8A105,105,0,0,0,256,114.8391Z" style="fill:#0d263e"/></g></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_aethiopian_skin_04"><path d="M256,85.278h0a54.025,54.025,0,0,1,54.025,54.025V466.35a0,0,0,0,1,0,0h-108.05a0,0,0,0,1,0,0V139.303A54.025,54.025,0,0,1,256,85.278Z" style="fill:#330f0f"/><path d="M315.6609,459.2315l-18.14-63.49a37.2231,37.2231,0,0,0-7.1219-13.3667,64.4207,64.4207,0,0,1-83.1234,38.5821l-10.936,38.2746a11.2273,11.2273,0,0,0,10.795,14.3115h97.7316A11.2273,11.2273,0,0,0,315.6609,459.2315Z" style="fill:#ffc139"/><path d="M290.3987,382.3748a37.3893,37.3893,0,0,0-28.9352-13.8318H250.5358A37.5,37.5,0,0,0,214.48,395.7415l-7.2043,25.2154a64.4207,64.4207,0,0,0,83.1234-38.5821Z" style="fill:#a5442e"/><path d="M377.7967,228.13h-10.459A112.4041,112.4041,0,0,0,256.0005,130.775h0A112.4057,112.4057,0,0,0,144.6623,228.13H134.2042a33.7518,33.7518,0,1,0,0,67.5036h10.4581a112.4057,112.4057,0,0,0,111.3382,97.3554h0A112.4041,112.4041,0,0,0,367.3377,295.634h10.459a33.7518,33.7518,0,1,0,0-67.5036Z" style="fill:#a5442e"/><path d="M256.0023,358.7981a37.2839,37.2839,0,0,1-26.521-10.979,7.5018,7.5018,0,0,1,10.6055-10.6128c8.4961,8.5034,23.3276,8.5,31.8237.0037a7.4992,7.4992,0,1,1,10.6055,10.6054A37.23,37.23,0,0,1,256.0023,358.7981Z" style="fill:#8c1813"/><rect height="45" rx="15" style="fill:#8c2b15" width="30" x="241.0003" y="275.8616"/><path d="M380.4685,241.806H366.97v40.1514h13.4985a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#8c2b15"/><path d="M336.1748,244.9416a7.4973,7.4973,0,0,0-10.6055,0l-2.3378,2.3383a20.6842,20.6842,0,1,0,10.605,10.6054l2.3383-2.3382A7.4975,7.4975,0,0,0,336.1748,244.9416Z" style="fill:#0d253d"/><circle cx="319.5728" cy="258.468" r="7.6845" style="fill:#ffefdc"/><path d="M197.0366,245.5275a20.5242,20.5242,0,0,0-8.2682,1.75l-2.3373-2.3364a7.4992,7.4992,0,0,0-10.6055,10.6055l2.3374,2.3364a20.6122,20.6122,0,1,0,18.8736-12.356Z" style="fill:#0d253d"/><circle cx="201.6473" cy="258.468" r="7.6845" style="fill:#ffefdc"/><path d="M131.5319,241.806H145.03v40.1514H131.5319a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#8c2b15"/><path d="M367.2561,227.6009a112.4007,112.4007,0,0,0-111.2567-96.8261h-.0005a112.4015,112.4015,0,0,0-111.2544,96.8133c1.7633-4.4842,15.7429-37.2235,50.8983-44.5294a53.81,53.81,0,0,1,29.6882,2.016,89.7611,89.7611,0,0,0,61.3335,0,53.812,53.812,0,0,1,29.6887-2.016C351.5328,190.37,365.5088,223.1515,367.2561,227.6009Z" style="fill:#521919"/></g></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_aethiopian_skin_03"><path d="M333.2359,166.1414a14.4285,14.4285,0,0,0-7.6446-23.2578,14.4112,14.4112,0,0,0-14.4582-19.7224A14.4533,14.4533,0,0,0,291.3016,108.81a14.4342,14.4342,0,0,0-23.33-7.4651,14.409,14.409,0,0,0-24.4462.0722,14.4,14.4,0,0,0-23.2577,7.6077,14.4522,14.4522,0,0,0-19.7594,14.46A14.4168,14.4168,0,0,0,186.1575,143.28a14.4628,14.4628,0,0,0-7.5,23.33,14.4287,14.4287,0,0,0,.0369,24.4461,14.4381,14.4381,0,0,0,7.6077,23.2578A14.4315,14.4315,0,0,0,200.7248,234.11,14.4169,14.4169,0,0,0,220.52,248.4608a14.4295,14.4295,0,0,0,23.2947,7.5354,14.4208,14.4208,0,0,0,24.4814-.0369,14.4079,14.4079,0,0,0,23.2577-7.5707A14.429,14.429,0,0,0,311.35,234.0008a14.4178,14.4178,0,0,0,14.386-19.7946,14.4462,14.4462,0,0,0,7.5724-23.293,14.41,14.41,0,0,0,6.7784-12.2239v-.324A14.503,14.503,0,0,0,333.2359,166.1414Z" style="fill:#071b2b"/><path d="M304.866,473.543H207.1346a11.2273,11.2273,0,0,1-10.7953-14.3116l18.14-63.4906a37.5,37.5,0,0,1,36.0569-27.1978h10.9278a37.5,37.5,0,0,1,36.0569,27.1978l18.14,63.4906A11.2273,11.2273,0,0,1,304.866,473.543Z" style="fill:#f4e2ff"/><path d="M377.7967,228.13h-10.459a112.4033,112.4033,0,0,0-111.3372-97.3553h0A112.4049,112.4049,0,0,0,144.6623,228.13H134.2042a33.7514,33.7514,0,1,0,0,67.5028h10.4581a112.4065,112.4065,0,0,0,111.3382,97.3562h0a112.4049,112.4049,0,0,0,111.3372-97.3562h10.459a33.7514,33.7514,0,1,0,0-67.5028Z" style="fill:#a5442e"/><path d="M256.0023,358.7981a37.2964,37.2964,0,0,1-26.521-10.979,7.5018,7.5018,0,0,1,10.6055-10.6128c8.5107,8.5035,23.3276,8.5,31.8237.0037a7.4992,7.4992,0,0,1,10.6055,10.6055A37.2432,37.2432,0,0,1,256.0023,358.7981Z" style="fill:#8c1813"/><rect height="45" rx="15" style="fill:#8c2b15" width="30" x="241.0003" y="275.8612"/><path d="M380.4685,241.8057H366.97V281.957h13.4985a20.2464,20.2464,0,0,0,0-40.1513Z" style="fill:#8c2b15"/><path d="M336.1748,244.9412a7.4973,7.4973,0,0,0-10.6055,0l-2.3378,2.3383a20.6845,20.6845,0,1,0,10.605,10.6055l2.3383-2.3383A7.4975,7.4975,0,0,0,336.1748,244.9412Z" style="fill:#0d253d"/><circle cx="319.5728" cy="258.4676" r="7.6845" style="fill:#ffefdc"/><path d="M197.0366,245.5272a20.5225,20.5225,0,0,0-8.2682,1.7505l-2.3373-2.3365a7.4992,7.4992,0,0,0-10.6055,10.6055l2.3374,2.3364a20.6122,20.6122,0,1,0,18.8736-12.3559Z" style="fill:#0d253d"/><circle cx="201.6473" cy="258.4676" r="7.6845" style="fill:#ffefdc"/><path d="M131.5319,241.8057H145.03V281.957H131.5319a20.2464,20.2464,0,0,1,0-40.1513Z" style="fill:#8c2b15"/><path d="M367.1974,227.2078a112.3272,112.3272,0,0,0-222.3944,0c2.4683-8.1482,23.78-68.8349,111.1981-68.8349C343.4175,158.3729,364.7291,219.06,367.1974,227.2078Z" style="fill:#0d263e"/><path d="M209.3317,165.3215s-5.8246-23.4326-34.92-26.2083c-30.1342-2.8727-63.7088,19.5615-58.9007,70.4257,3.6973,39.1191,25.6869,41.6869,21.9074,75.9974-3.78,34.3124-5.5046,58.2,30.59,78.3532,0,0-21.0312-32.0676-10.6938-59.2519,10.337-27.1824-6.9555-58.816,4.6568-89.0345C173.5839,185.3867,193.8561,169.6364,209.3317,165.3215Z" style="fill:#162f44"/></g></svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_aethiopian_skin_02"><path d="M417.8908,198.3233a30.2431,30.2431,0,0,0-16.0236-48.75,30.207,30.207,0,0,0-30.3053-41.3394,30.2952,30.2952,0,0,0-41.5682-30.08,30.255,30.255,0,0,0-48.9011-15.6471,30.202,30.202,0,0,0-51.2407.1513,30.1841,30.1841,0,0,0-48.75,15.9461,30.293,30.293,0,0,0-41.417,30.3089,30.2185,30.2185,0,0,0-30.08,41.4907,30.3148,30.3148,0,0,0-15.721,48.9009,30.2434,30.2434,0,0,0,.0775,51.2406,30.2628,30.2628,0,0,0,15.9461,48.75A30.25,30.25,0,0,0,140.1391,340.79,30.2186,30.2186,0,0,0,181.63,370.87a30.2452,30.2452,0,0,0,48.8272,15.7948,30.227,30.227,0,0,0,51.3146-.0775,30.2,30.2,0,0,0,48.75-15.8686,30.244,30.244,0,0,0,41.4945-30.1576A30.2206,30.2206,0,0,0,402.17,299.07a30.28,30.28,0,0,0,15.8723-48.8234A30.2052,30.2052,0,0,0,432.25,224.6245v-.679A30.4,30.4,0,0,0,417.8908,198.3233Z" style="fill:#0d263e"/><path d="M298.5818,473.543H213.4182a11.2351,11.2351,0,0,1-11.1484-9.8416l-7.4478-59.5825A44.995,44.995,0,0,1,239.47,353.543h33.061a44.995,44.995,0,0,1,44.6475,50.5759L309.73,463.7014A11.2351,11.2351,0,0,1,298.5818,473.543Z" style="fill:#27b286"/><path d="M371.8267,219.8368H361v.0037a104.999,104.999,0,0,0-105-105h0A104.9989,104.9989,0,0,0,151,219.8405v-.0037H140.1735a33.7519,33.7519,0,1,0,0,67.5037H151V287.34A105,105,0,0,0,256,392.34h0a105,105,0,0,0,105-105v.0009h10.8266a33.7519,33.7519,0,1,0,0-67.5037Z" style="fill:#a5442e"/><path d="M255.9992,358.151a37.234,37.234,0,0,1-26.5137-10.9863,7.4992,7.4992,0,1,1,10.6055-10.6055c8.4961,8.5034,23.32,8.5034,31.8164,0a7.4992,7.4992,0,1,1,10.6055,10.6055A37.234,37.234,0,0,1,255.9992,358.151Z" style="fill:#8c1813"/><rect height="68.3763" rx="22.7921" style="fill:#8c2b15" width="45.5842" x="233.2079" y="263.5237"/><path d="M374.4985,233.5127H361v40.1514h13.4986a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#8c2b15"/><circle cx="314.9627" cy="250.5027" r="20.625" style="fill:#0d253d"/><circle cx="319.5734" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><circle cx="197.0371" cy="250.5027" r="20.625" style="fill:#0d253d"/><circle cx="201.6479" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><path d="M137.5015,233.5127H151v40.1514H137.5015a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#8c2b15"/><path d="M233.68,216.0589A29.0972,29.0972,0,0,1,209.478,222.56h0a28.7745,28.7745,0,0,1-20.59-15.6055h0a28.8743,28.8743,0,0,1-26.7311.1446h0a28.72,28.72,0,0,1-15.6019-27.1613h0a28.9778,28.9778,0,0,1-25.5035-28.3925h0a28.8116,28.8116,0,0,1,25.07-28.971h0a28.89,28.89,0,0,1,15.4608-27.4506h0a28.8177,28.8177,0,0,1,26.8016,0h0a28.8522,28.8522,0,0,1,20.59-15.676h0a28.841,28.841,0,0,1,24.1983,6.5011h0a28.6549,28.6549,0,0,1,22.3958-10.7622h0A28.8413,28.8413,0,0,1,278.034,85.8783h0a28.7359,28.7359,0,0,1,24.1313-6.5752h0a28.9753,28.9753,0,0,1,20.66,15.5314h0a28.8688,28.8688,0,0,1,26.731-.1447h0a28.9261,28.9261,0,0,1,15.676,27.0909h0a28.83,28.83,0,0,1,25.6446,28.1032h0v.5044h0c0,.1446.0741.3633.0741.5785h0a28.901,28.901,0,0,1-25.3589,28.6817h0a28.74,28.74,0,0,1-15.5313,27.306h0a28.6733,28.6733,0,0,1-26.7311-.0705h0a29.1787,29.1787,0,0,1-20.5862,15.676h0a28.8826,28.8826,0,0,1-24.2018-6.5752h0a28.6958,28.6958,0,0,1-22.47,10.7658h0A28.8149,28.8149,0,0,1,233.68,216.0589Z" style="fill:#0d263e"/></g></svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_mongolian_skin_06"><path d="M304.838,473.543H207.1066a11.2273,11.2273,0,0,1-10.7953-14.3116l18.14-63.4906a37.5,37.5,0,0,1,36.0569-27.1978h10.9278a37.5,37.5,0,0,1,36.0569,27.1978l18.14,63.4906A11.2272,11.2272,0,0,1,304.838,473.543Z" style="fill:#f4e2ff"/><path d="M377.7688,228.13H367.31a112.3416,112.3416,0,0,0-222.6754,0H134.2312a33.7509,33.7509,0,1,0,0,67.5018h10.4032a112.3415,112.3415,0,0,0,222.6754,0h10.459a33.7509,33.7509,0,1,0,0-67.5018Z" style="fill:#f8c497"/><path d="M255.9744,358.8a37.2846,37.2846,0,0,1-26.521-10.9827,7.5018,7.5018,0,0,1,10.6055-10.6127c8.518,8.5144,23.3349,8.5034,31.8237.0036a7.4992,7.4992,0,1,1,10.6055,10.6055A37.234,37.234,0,0,1,255.9744,358.8Z" style="fill:#f7725c"/><rect height="45" rx="15" style="fill:#ef9e72" width="30" x="240.9723" y="275.8604"/><path d="M380.4405,241.8049H366.942v40.1513h13.4985a20.2464,20.2464,0,0,0,0-40.1513Z" style="fill:#ef9e72"/><path d="M297.3342,271.0225a7.5,7.5,0,0,1-1.0913-14.9194l35.1856-5.2185a7.5,7.5,0,1,1,2.1973,14.8388L298.44,270.9419A7.5544,7.5544,0,0,1,297.3342,271.0225Z" style="fill:#0d263e"/><path d="M214.6145,271.0225a7.5541,7.5541,0,0,1-1.1059-.0806l-35.1929-5.2185a7.5,7.5,0,1,1,2.1973-14.8388l35.1928,5.2185a7.5,7.5,0,0,1-1.0913,14.9194Z" style="fill:#0d263e"/><path d="M131.56,241.8049H145.058v40.1513H131.56a20.2464,20.2464,0,0,1,0-40.1513Z" style="fill:#ef9e72"/><circle cx="343.642" cy="161.9467" r="22.117" style="fill:#ffc139"/><path d="M435.0185,198.6533l-.0062-.0008a51.2955,51.2955,0,1,0-100.4-6.4916c7.4931,56.3217,65.6272,118.8258,141.7875,107.55C476.4,299.7109,421.9423,248.6512,435.0185,198.6533Z" style="fill:#0d253d"/><circle cx="168.358" cy="161.9467" r="22.117" style="fill:#ffc139"/><path d="M76.9815,198.6533l.0062-.0008a51.2955,51.2955,0,1,1,100.4-6.4916C169.8943,248.4826,111.76,310.9867,35.6,299.7109,35.6,299.7109,90.0577,248.6512,76.9815,198.6533Z" style="fill:#0d253d"/><path d="M367.228,227.6a112.4007,112.4007,0,0,0-111.2567-96.8262h-.0005A112.4015,112.4015,0,0,0,144.7164,227.587c1.7633-4.4843,15.7429-37.2236,50.8983-44.5295a53.81,53.81,0,0,1,29.6882,2.016,89.76,89.76,0,0,0,61.3335,0,53.8119,53.8119,0,0,1,29.6887-2.016C351.5047,190.3689,365.4807,223.15,367.228,227.6Z" style="fill:#0d253d"/></g></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_malayan_skin_01"><path d="M298.5818,473.543H213.4182a11.2352,11.2352,0,0,1-11.1484-9.8416l-7.4478-59.5825A44.995,44.995,0,0,1,239.47,353.543h33.061a44.9949,44.9949,0,0,1,44.6475,50.5759L309.73,463.7014A11.2351,11.2351,0,0,1,298.5818,473.543Z" style="fill:#8ca4bc"/><path d="M371.8266,219.8369H361v.0019a105,105,0,0,0-210,0v-.0019H140.1734a33.7519,33.7519,0,1,0,0,67.5037H151v-.0018a105,105,0,0,0,210,0v.0018h10.8266a33.7519,33.7519,0,1,0,0-67.5037Z" style="fill:#d87761"/><path d="M256,358.1493a37.243,37.243,0,0,1-26.5137-10.9826,7.4992,7.4992,0,0,1,10.6055-10.6055c8.4961,8.4961,23.32,8.4961,31.8164,0a7.4992,7.4992,0,1,1,10.6055,10.6055A37.243,37.243,0,0,1,256,358.1493Z" style="fill:#8c1813"/><rect height="68.3763" rx="22.7921" style="fill:#bf5e48" width="45.5842" x="233.208" y="263.5237"/><path d="M374.4984,233.5127H361v40.1514h13.4985a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#bf5e48"/><circle cx="314.9628" cy="250.5027" r="20.625" style="fill:#521919"/><circle cx="319.5735" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><circle cx="197.0373" cy="250.5027" r="20.625" style="fill:#521919"/><circle cx="201.648" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><path d="M137.5015,233.5127H151v40.1514H137.5015a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#bf5e48"/><path d="M361,216.8831c-9.75-31.5-33.3751-48.2245-34.95-49.2737,6.6-.6006,13.5-.9009,20.625-.9009A103.6125,103.6125,0,0,1,361,216.8831Z" style="fill:#8ca4bc"/><path d="M151,216.8831c9.75-31.5,33.3751-48.2245,34.95-49.2737-6.6-.6006-13.5-.9009-20.625-.9009A103.6115,103.6115,0,0,0,151,216.8831Z" style="fill:#8ca4bc"/><path d="M346.5761,166.7023C361.181,80.5321,245.5922,80.531,214.0505,80.531s-62.8968-23.9361-62.8968-23.9361c-2.469,30.9574,13.2707,49.468,13.2707,49.468-24.9984-3.1914-46.602-18.83-46.602-18.83-4.787,68.5466,47.6015,79.4691,47.6015,79.4691,50.5018,0,90.5761,15.7968,90.5761,15.7968S296.0743,166.7023,346.5761,166.7023Z" style="fill:#0d263e"/></g></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_caucasian_skin_10"><path d="M411.0018,199.0293A28.9563,28.9563,0,0,0,395.66,152.3541a28.9215,28.9215,0,0,0-29.0157-39.58,29.0059,29.0059,0,0,0-39.7994-28.8,28.9675,28.9675,0,0,0-46.82-14.9813,28.9169,28.9169,0,0,0-49.06.1449,28.9,28.9,0,0,0-46.6753,15.2674,29.0039,29.0039,0,0,0-39.6545,29.0192,28.9326,28.9326,0,0,0-28.8,39.7251,29.025,29.025,0,0,0-15.052,46.82,28.9565,28.9565,0,0,0,.0742,49.06,28.9751,28.9751,0,0,0,15.2676,46.6752,28.9623,28.9623,0,0,0,28.945,39.7287,28.9326,28.9326,0,0,0,39.7252,28.8,28.9581,28.9581,0,0,0,46.7495,15.1226,28.9406,28.9406,0,0,0,49.1309-.0742A28.9148,28.9148,0,0,0,327.35,364.0884a28.957,28.957,0,0,0,39.7287-28.8743A28.9345,28.9345,0,0,0,395.95,295.489a28.9917,28.9917,0,0,0,15.1969-46.7459A28.92,28.92,0,0,0,424.75,224.2113v-.65A29.1063,29.1063,0,0,0,411.0018,199.0293Z" style="fill:#eb5d25"/><path d="M317.1626,404.168l-7.4254,59.55a11.1993,11.1993,0,0,1-11.1749,9.8254H213.4375a11.1993,11.1993,0,0,1-11.1749-9.8254l-7.4254-59.55a45.0062,45.0062,0,0,1,44.6251-50.625h33.0752A45.0061,45.0061,0,0,1,317.1626,404.168Z" style="fill:#ffc139"/><path d="M371.8265,219.425H361v.0018a105,105,0,0,0-210,0v-.0018H140.1734a33.7509,33.7509,0,1,0,0,67.5018H151a105,105,0,0,0,210,0h10.8265a33.7509,33.7509,0,1,0,0-67.5018Z" style="fill:#f8c4b0"/><path d="M256,357.7374a37.2335,37.2335,0,0,1-26.5137-10.9864,7.4992,7.4992,0,1,1,10.6055-10.6054c8.4961,8.5034,23.32,8.5034,31.8164,0a7.4992,7.4992,0,1,1,10.6054,10.6054A37.2333,37.2333,0,0,1,256,357.7374Z" style="fill:#ff8080"/><rect height="68.3763" rx="22.7921" style="fill:#ef9e8b" width="45.5842" x="233.2079" y="263.1105"/><circle cx="334.5781" cy="293.7918" r="5.6257" style="fill:#ea9381"/><circle cx="306.919" cy="305.8157" r="5.6257" style="fill:#ea9381"/><circle cx="205.081" cy="305.8157" r="5.6257" style="fill:#ea9381"/><circle cx="177.4219" cy="293.7918" r="5.6257" style="fill:#ea9381"/><path d="M374.4985,233.1H361v40.1513h13.4986a20.2465,20.2465,0,0,0,0-40.1513Z" style="fill:#ef9e8b"/><circle cx="314.9627" cy="250.0896" r="20.625" style="fill:#0d253d"/><circle cx="319.5734" cy="242.4051" r="7.6845" style="fill:#ffefdc"/><circle cx="197.0371" cy="250.0896" r="20.625" style="fill:#0d253d"/><circle cx="201.6479" cy="242.4051" r="7.6845" style="fill:#ffefdc"/><path d="M137.5015,233.1H151v40.1513H137.5015a20.2465,20.2465,0,0,1,0-40.1513Z" style="fill:#ef9e8b"/><path d="M233.68,215.6457a29.0969,29.0969,0,0,1-24.2018,6.5011h0a28.7743,28.7743,0,0,1-20.59-15.6054h0a28.8746,28.8746,0,0,1-26.7311.1446h0a28.72,28.72,0,0,1-15.6019-27.1614h0a28.9777,28.9777,0,0,1-25.5035-28.3924h0a28.8115,28.8115,0,0,1,25.07-28.971h0a28.8894,28.8894,0,0,1,15.4608-27.4506h0a28.8177,28.8177,0,0,1,26.8016,0h0a28.8522,28.8522,0,0,1,20.59-15.676h0a28.8406,28.8406,0,0,1,24.1983,6.5011h0a28.655,28.655,0,0,1,22.3958-10.7623h0A28.8416,28.8416,0,0,1,278.034,85.4651h0A28.7359,28.7359,0,0,1,302.1653,78.89h0a28.9756,28.9756,0,0,1,20.66,15.5314h0a28.8688,28.8688,0,0,1,26.731-.1446h0a28.9261,28.9261,0,0,1,15.676,27.0908h0a28.83,28.83,0,0,1,25.6446,28.1032h0v.5045h0c0,.1446.0741.3633.0741.5785h0a28.901,28.901,0,0,1-25.3589,28.6817h0a28.74,28.74,0,0,1-15.5313,27.306h0a28.673,28.673,0,0,1-26.7311-.0706h0a29.1782,29.1782,0,0,1-20.5862,15.676h0a28.8826,28.8826,0,0,1-24.2018-6.5751h0a28.696,28.696,0,0,1-22.47,10.7657h0A28.8149,28.8149,0,0,1,233.68,215.6457Z" style="fill:#eb5d25"/></g></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_caucasian_skin_01"><path d="M389.9851,300.3886V278.0228h-267.97v22.3658c0,22.4072-7.3512,43.8082-18.7241,63.1147A45.6505,45.6505,0,0,0,96.5852,386.85c0,45,71.3717,81.4765,159.4143,81.4765S415.4148,431.85,415.4148,386.85a45.6505,45.6505,0,0,0-6.7056-23.3464C397.3363,344.1968,389.9851,322.7958,389.9851,300.3886Z" style="fill:#521919"/><path d="M304.8656,473.543H207.1342a11.2273,11.2273,0,0,1-10.7953-14.3116l18.14-63.4906A37.5,37.5,0,0,1,250.536,368.543h10.9278a37.5,37.5,0,0,1,36.0569,27.1978l18.14,63.4906A11.2273,11.2273,0,0,1,304.8656,473.543Z" style="fill:#f4e2ff"/><path d="M377.7963,228.13H367.3378A112.4057,112.4057,0,0,0,256,130.7726h0A112.4054,112.4054,0,0,0,144.6623,228.13h-10.459a33.7519,33.7519,0,1,0,0,67.5037h10.459A112.4053,112.4053,0,0,0,256,392.9888h0a112.4057,112.4057,0,0,0,111.3377-97.3553h10.4585a33.7519,33.7519,0,1,0,0-67.5037Z" style="fill:#f8c4b0"/><path d="M256,358.7975a37.2429,37.2429,0,0,1-26.5137-10.9827,7.4992,7.4992,0,0,1,10.6055-10.6054c8.4961,8.4961,23.32,8.4961,31.8164,0a7.4992,7.4992,0,0,1,10.6055,10.6054A37.2427,37.2427,0,0,1,256,358.7975Z" style="fill:#ff4d4d"/><rect height="45" rx="15" style="fill:#ef9e8b" width="30" x="241" y="275.8604"/><path d="M380.4682,241.8049H366.97v40.1513h13.4985a20.2464,20.2464,0,0,0,0-40.1513Z" style="fill:#ef9e8b"/><path d="M336.1745,244.94a7.4973,7.4973,0,0,0-10.6055,0l-2.3378,2.3383a20.6845,20.6845,0,1,0,10.605,10.6055l2.3383-2.3383A7.4975,7.4975,0,0,0,336.1745,244.94Z" style="fill:#004b28"/><circle cx="319.5725" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M197.0363,245.5264a20.5225,20.5225,0,0,0-8.2682,1.7505l-2.3373-2.3365a7.4992,7.4992,0,0,0-10.6055,10.6055l2.3374,2.3364a20.6122,20.6122,0,1,0,18.8736-12.3559Z" style="fill:#004b28"/><circle cx="201.647" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M131.5316,241.8049H145.03v40.1513H131.5316a20.2464,20.2464,0,0,1,0-40.1513Z" style="fill:#ef9e8b"/><path d="M389.9851,213.269v17.1752a32.8469,32.8469,0,0,0-12.225-2.3254H367.41a.0736.0736,0,0,1-.0751-.0751c-33.0748-21.3739-68.4-11.55-112.2748-16.65-43.95-5.1-57.75-40.199-57.75-40.199s-39.375,9.8236-52.5,55.7995c-.0751.3736-.2252.7489-.3,1.1243H134.16a32.746,32.746,0,0,0-12.15,2.3254V213.269a133.9874,133.9874,0,1,1,267.9748,0Z" style="fill:#521919"/></g></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_mongolian_skin_02"><path d="M298.5818,473.543H213.4182a11.2352,11.2352,0,0,1-11.1484-9.8416l-7.4478-59.5825A44.995,44.995,0,0,1,239.47,353.543h33.061a44.995,44.995,0,0,1,44.6475,50.5759L309.73,463.7014A11.2351,11.2351,0,0,1,298.5818,473.543Z" style="fill:#ffc139"/><path d="M371.8266,219.8368H361v.0037a105,105,0,1,0-210,0v-.0037H140.1734a33.7519,33.7519,0,1,0,0,67.5037H151V287.34a105,105,0,0,0,210,0v.0009h10.8266a33.7519,33.7519,0,1,0,0-67.5037Z" style="fill:#f8c497"/><path d="M256.0032,358.151a37.2382,37.2382,0,0,1-26.521-10.9863,7.4992,7.4992,0,1,1,10.6055-10.6055c8.4961,8.5034,23.3276,8.5034,31.8237,0a7.4992,7.4992,0,1,1,10.6055,10.6055A37.234,37.234,0,0,1,256.0032,358.151Z" style="fill:#f7725c"/><rect height="60.0155" rx="16.6061" style="fill:#ef9e72" width="33.2122" x="239.394" y="262.6054"/><path d="M374.4986,233.5127H361v40.1514h13.4986a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#ef9e72"/><path d="M297.3631,275.6107a7.5,7.5,0,0,1-1.0913-14.9194l35.1855-5.2185a7.5,7.5,0,0,1,2.1973,14.8389L298.469,275.53A7.5677,7.5677,0,0,1,297.3631,275.6107Z" style="fill:#0d263e"/><path d="M214.6433,275.6107a7.5677,7.5677,0,0,1-1.1059-.0805l-35.1929-5.2185a7.5,7.5,0,0,1,2.1973-14.8389l35.1928,5.2185a7.5,7.5,0,0,1-1.0913,14.9194Z" style="fill:#0d263e"/><path d="M137.5016,233.5127H151v40.1514H137.5016a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#ef9e72"/><path d="M361.0005,219.84v-.0018h.0256c.0664-.0055,2.4861-.15,5.6973,0h5.1036a33.5259,33.5259,0,0,1,7.62.943,211.7254,211.7254,0,0,1,18.1783-31.4026c-52.8332-143.23-180.7839-89.1905-180.7839-89.1905l-.7181-28.8027c-73.3244,14.042-67.58,79.5831-67.58,79.5831s-46.5957,32.7568-13.1028,95.31c0,0,19.8848-23.7767,53.06-35.6594,0,0,27.6227,29.1167,95.6015,26.7231l-9.3351-34.7074S311.277,224.3591,361.0005,219.84Z" style="fill:#0d263e"/></g></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_caucasian_skin_08"><path d="M342.9037,93.9965a14.4285,14.4285,0,0,0-7.6446-23.2577,14.4114,14.4114,0,0,0-14.4582-19.7225,14.4533,14.4533,0,0,0-19.8316-14.3508,14.4342,14.4342,0,0,0-23.33-7.465,14.4089,14.4089,0,0,0-24.4462.0722A14.4,14.4,0,0,0,229.9355,36.88a14.4524,14.4524,0,0,0-19.76,14.46,14.4167,14.4167,0,0,0-14.3507,19.7946,14.4628,14.4628,0,0,0-7.5,23.33,14.4288,14.4288,0,0,0,.037,24.4462,14.4381,14.4381,0,0,0,7.6076,23.2578,14.4316,14.4316,0,0,0,14.423,19.7963,14.4167,14.4167,0,0,0,19.7946,14.3508,14.43,14.43,0,0,0,23.2948,7.5355,14.4206,14.4206,0,0,0,24.4813-.037,14.4079,14.4079,0,0,0,23.2578-7.5706,14.429,14.429,0,0,0,19.7964-14.3878,14.4178,14.4178,0,0,0,14.386-19.7946,14.4463,14.4463,0,0,0,7.5724-23.293,14.41,14.41,0,0,0,6.7784-12.224v-.3239A14.5032,14.5032,0,0,0,342.9037,93.9965Z" style="fill:#330f0f"/><path d="M314.534,473.543H216.8027a11.2272,11.2272,0,0,1-10.7953-14.3116l18.14-63.4906a37.5,37.5,0,0,1,36.0569-27.1978h10.9277a37.5,37.5,0,0,1,36.0569,27.1978l18.14,63.4906A11.2272,11.2272,0,0,1,314.534,473.543Z" style="fill:#0d263e"/><path d="M387.4652,228.13h-10.459a112.4042,112.4042,0,0,0-111.3373-97.3563h-.0009A112.4048,112.4048,0,0,0,154.3307,228.13h-10.459a33.7509,33.7509,0,1,0,0,67.5018h10.459A112.4057,112.4057,0,0,0,265.668,392.9891h.0009a112.4051,112.4051,0,0,0,111.3373-97.3572h10.459a33.7509,33.7509,0,1,0,0-67.5018Z" style="fill:#f8c4b0"/><path d="M265.6689,358.8a37.234,37.234,0,0,1-26.5137-10.9863,7.4992,7.4992,0,1,1,10.6055-10.6055c8.4961,8.5034,23.32,8.5034,31.8164,0a7.4992,7.4992,0,1,1,10.6055,10.6055A37.234,37.234,0,0,1,265.6689,358.8Z" style="fill:#ff4d4d"/><rect height="45" rx="15" style="fill:#ef9e8b" width="30" x="250.6683" y="275.8604"/><path d="M390.1366,241.8049H376.638v40.1513h13.4986a20.2465,20.2465,0,0,0,0-40.1513Z" style="fill:#ef9e8b"/><path d="M345.8428,244.94a7.4973,7.4973,0,0,0-10.6055,0L332.9,247.2787a20.6845,20.6845,0,1,0,10.605,10.6055l2.3383-2.3383A7.4973,7.4973,0,0,0,345.8428,244.94Z" style="fill:#0167a3"/><circle cx="329.2408" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M206.7046,245.5264a20.5221,20.5221,0,0,0-8.2681,1.7505l-2.3373-2.3365a7.4992,7.4992,0,0,0-10.6055,10.6055l2.3373,2.3364a20.6122,20.6122,0,1,0,18.8736-12.3559Z" style="fill:#0167a3"/><circle cx="211.3153" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M141.2,241.8049h13.4986v40.1513H141.2a20.2465,20.2465,0,0,1,0-40.1513Z" style="fill:#ef9e8b"/><path d="M399.6536,213.2427v17.2494a27.3412,27.3412,0,0,0-5.3247-1.65h-.15a22.2247,22.2247,0,0,0-3.2254-.5255,25.9217,25.9217,0,0,0-3.45-.2243H376.629v.0751c-58.05-5.85-80.0254-57-80.0254-57s-11.6244,35.1-48.3755,40.2c-36.5991,5.1754-66.2988-4.7251-93.8992,16.5747l-.15.15h-5.4l.0742.0751h-4.9493a33.75,33.75,0,1,0,0,67.5h10.4251a112.3871,112.3871,0,0,0,35.9994,68.25c-16.5,45.45-62.6239,52.1246-62.6239,52.1246,57.9749-90.6-73.5754-121.2744-26.6254-255.9741.6-1.875,1.1994-3.6,1.875-5.4a4.7875,4.7875,0,0,1,.15-.5255c16.5747-42.5995,66.3-74.85,162.6-74.85A133.9865,133.9865,0,0,1,399.6536,213.2427Z" style="fill:#521919"/></g></svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_malayan_skin_04"><path d="M394.7853,292.8886V270.5228H126.815v22.3658c0,22.4072-7.3512,43.8082-18.724,63.1147a45.65,45.65,0,0,0-6.7057,23.3464c0,45,71.3718,81.4765,159.4144,81.4765S420.215,424.35,420.215,379.35a45.65,45.65,0,0,0-6.7057-23.3464C402.1365,336.6968,394.7853,315.2958,394.7853,292.8886Z" style="fill:#521919"/><path d="M309.6658,473.543H211.9345a11.2272,11.2272,0,0,1-10.7953-14.3116l18.14-63.4906a37.5,37.5,0,0,1,36.0569-27.1978H266.264a37.5,37.5,0,0,1,36.057,27.1978l18.14,63.4906A11.2272,11.2272,0,0,1,309.6658,473.543Z" style="fill:#3285e2"/><path d="M382.5967,228.13h-10.459a112.3416,112.3416,0,0,0-222.6755,0H139.0037a33.7509,33.7509,0,1,0,0,67.5018h10.4585a112.3417,112.3417,0,0,0,222.6755,0h10.459a33.7509,33.7509,0,1,0,0-67.5018Z" style="fill:#d87761"/><path d="M260.8,358.7981a37.2428,37.2428,0,0,1-26.5137-10.9826A7.4992,7.4992,0,1,1,244.8918,337.21c8.4961,8.4961,23.32,8.4961,31.8164,0a7.4992,7.4992,0,0,1,10.6054,10.6055A37.2428,37.2428,0,0,1,260.8,358.7981Z" style="fill:#c42020"/><rect height="45" rx="15" style="fill:#bf5e48" width="30" x="245.8002" y="275.8604"/><path d="M385.2684,241.8049H371.77v40.1513h13.4986a20.2465,20.2465,0,0,0,0-40.1513Z" style="fill:#bf5e48"/><path d="M340.9746,244.94a7.4973,7.4973,0,0,0-10.6055,0l-2.3378,2.3383a20.684,20.684,0,1,0,10.6051,10.6055l2.3382-2.3383A7.4973,7.4973,0,0,0,340.9746,244.94Z" style="fill:#0d253d"/><circle cx="324.3726" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M201.8364,245.5264a20.5221,20.5221,0,0,0-8.2681,1.7505L191.231,244.94a7.4992,7.4992,0,0,0-10.6055,10.6055l2.3373,2.3364a20.6122,20.6122,0,1,0,18.8736-12.3559Z" style="fill:#0d253d"/><circle cx="206.4471" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M136.3317,241.8049H149.83v40.1513H136.3317a20.2465,20.2465,0,0,1,0-40.1513Z" style="fill:#bf5e48"/><path d="M394.7847,213.2476v17.1753a33.1393,33.1393,0,0,0-12.225-2.3254h-10.8c-58.05-5.7752-80.1-56.9248-80.1-56.9248s-11.55,35.1-48.3,40.2c-36.6746,5.1-66.3-4.7241-93.9,16.5747l-.15.15H138.96a33.1518,33.1518,0,0,0-19.65,6.4508c-10.275-9.375-27.5249-29.55-27.5249-60.0751,0-47.3255,47.4-95.1755,168.9748-95.1755A133.9551,133.9551,0,0,1,394.7847,213.2476Z" style="fill:#521919"/></g></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_aethiopian_skin_05"><path d="M228.9376,253.6591a35.2792,35.2792,0,0,1-29.3438,7.8824h0A34.8881,34.8881,0,0,1,174.63,242.62h0a35.0091,35.0091,0,0,1-32.41.1754h0a34.8222,34.8222,0,0,1-18.9167-32.9322h0A35.1344,35.1344,0,0,1,92.38,175.4388h0a34.9328,34.9328,0,0,1,30.396-35.1262h0A35.0272,35.0272,0,0,1,141.522,107.03h0a34.94,34.94,0,0,1,32.4959,0h0a34.9824,34.9824,0,0,1,24.9643-19.0066h0a34.9688,34.9688,0,0,1,29.34,7.8824h0a34.7429,34.7429,0,0,1,27.154-13.0489h0a34.9692,34.9692,0,0,1,27.24,12.9633h0a34.8414,34.8414,0,0,1,29.2583-7.9721h0a35.1317,35.1317,0,0,1,25.05,18.8312h0a35.0023,35.0023,0,0,1,32.41-.1753h0A35.0718,35.0718,0,0,1,388.4405,139.35h0a34.9554,34.9554,0,0,1,31.0931,34.0741h0v.6116h0c0,.1753.09.44.09.7014h0a35.0413,35.0413,0,0,1-30.7466,34.7755h0A34.8461,34.8461,0,0,1,370.0456,242.62h0a34.7649,34.7649,0,0,1-32.41-.0855h0a35.3784,35.3784,0,0,1-24.96,19.0066h0a35.0192,35.0192,0,0,1-29.3439-7.9722h0a34.7925,34.7925,0,0,1-27.2439,13.0531h0A34.9367,34.9367,0,0,1,228.9376,253.6591Z" style="fill:#0d263e"/><path d="M317.1626,404.168l-7.4254,59.55a11.1993,11.1993,0,0,1-11.1749,9.8254H213.4375a11.1993,11.1993,0,0,1-11.1749-9.8254l-7.4254-59.55a45.0062,45.0062,0,0,1,44.6251-50.625h33.0752A45.0061,45.0061,0,0,1,317.1626,404.168Z" style="fill:#f4e2ff"/><polygon points="278.762 441.067 256.037 463.194 233.238 440.394 251.312 353.543 261.137 353.543 278.762 441.067" style="fill:#27b286"/><path d="M371.8266,219.837H361v.0018a105,105,0,0,0-210,0v-.0018H140.1734a33.7518,33.7518,0,1,0,0,67.5036H151V287.34a105,105,0,0,0,210,0v.0009h10.8266a33.7518,33.7518,0,1,0,0-67.5036Z" style="fill:#a5442e"/><path d="M269.0716,317.668h-93.89A46.8586,46.8586,0,0,0,256,350.0429a46.8586,46.8586,0,0,0,80.8186-32.3749Z" style="fill:#0d263e"/><rect height="68.3763" rx="22.7921" style="fill:#8c2b15" width="45.5842" x="233.2079" y="263.5237"/><path d="M374.4985,233.5127H361v40.1514h13.4986a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#8c2b15"/><circle cx="314.9627" cy="250.5027" r="20.625" style="fill:#0d253d"/><circle cx="319.5734" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><circle cx="197.0371" cy="250.5027" r="20.625" style="fill:#0d253d"/><circle cx="201.6479" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><path d="M137.5015,233.5127H151v40.1514H137.5015a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#8c2b15"/></g></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_caucasian_skin_05"><path d="M353.1009,464.5487V412.8422a60.7992,60.7992,0,0,0-60.7992-60.7992H219.6976a60.7987,60.7987,0,0,0-60.7987,60.7987v51.707a8.9943,8.9943,0,0,0,8.9943,8.9943H344.1067A8.9942,8.9942,0,0,0,353.1009,464.5487Z" style="fill:#f4e2ff"/><path d="M371.8266,219.8376H361v.0018a105,105,0,0,0-210,0v-.0018H140.173a33.7514,33.7514,0,1,0,0,67.5027H151v-.0009a105,105,0,1,0,210,0v.0009h10.8266a33.7514,33.7514,0,1,0,0-67.5027Z" style="fill:#f8c4b0"/><path d="M256.0032,358.15a37.26,37.26,0,0,1-26.521-10.9826,7.4992,7.4992,0,0,1,10.6055-10.6055c8.4887,8.4924,23.32,8.5,31.8237,0a7.4992,7.4992,0,0,1,10.6055,10.6055A37.243,37.243,0,0,1,256.0032,358.15Z" style="fill:#ff8080"/><path d="M151,287.34v41.5833a105,105,0,0,0,105,105h0a105,105,0,0,0,105-105V287.34Zm118.5864,86.4533H243.9552c-14.7811,0-28.0288-11.0706-28.8-25.8307a27.297,27.297,0,0,1,27.258-28.7622h26.4579c13.0275,0,24.8579,8.8366,27.4365,21.6064A27.3265,27.3265,0,0,1,269.5863,373.7935Z" style="fill:#521919"/><rect height="68.3763" rx="22.7921" style="fill:#ef9e8b" width="45.5842" x="233.2079" y="263.5243"/><path d="M374.4983,233.5127H361v40.1514h13.4985a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#ef9e8b"/><circle cx="314.9627" cy="250.5027" r="20.625" style="fill:#521919"/><circle cx="319.5734" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><circle cx="197.0372" cy="250.5027" r="20.625" style="fill:#521919"/><circle cx="201.6479" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><path d="M137.5014,233.5127H151v40.1514H137.5014a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#ef9e8b"/><path d="M327.1923,142.5958c.15.15.2248.3.3749.45a63.2989,63.2989,0,0,1,15.3749,41.25v17.4a18.1811,18.1811,0,0,0,18.0748,18.1494H371.892a33.07,33.07,0,0,1,10.275,1.5766,26.05,26.05,0,0,0,1.2753-8.0255c0-28.65-14.025-46.35-28.125-56.8506A85.7224,85.7224,0,0,0,327.1923,142.5958Z" style="fill:#521919"/><path d="M184.8074,142.5958c-.15.15-.2247.3-.3749.45a63.3,63.3,0,0,0-15.3749,41.25v17.4a18.1811,18.1811,0,0,1-18.0748,18.1494H140.1077a33.07,33.07,0,0,0-10.275,1.5766,26.05,26.05,0,0,1-1.2753-8.0255c0-28.65,14.025-46.35,28.125-56.8506A85.7234,85.7234,0,0,1,184.8074,142.5958Z" style="fill:#521919"/></g></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_malayan_skin_02"><path d="M287.4868,352.0415H224.5127a36.0119,36.0119,0,0,0-36.0118,36.0118v74.272a11.2178,11.2178,0,0,0,11.2178,11.2177H312.2823A11.2178,11.2178,0,0,0,323.5,462.3253V388.0547A36.0133,36.0133,0,0,0,287.4868,352.0415Z" style="fill:#f4e2ff"/><path d="M371.8266,219.8357H361v.0037a105,105,0,0,0-210,0v-.0037H140.1734a33.7519,33.7519,0,1,0,0,67.5037H151v-.001a105,105,0,0,0,210,0v.001h10.8266a33.7519,33.7519,0,1,0,0-67.5037Z" style="fill:#d87761"/><path d="M256,358.15a37.234,37.234,0,0,1-26.5137-10.9863,7.4992,7.4992,0,1,1,10.6055-10.6055c8.4961,8.5034,23.32,8.5034,31.8164,0a7.4992,7.4992,0,1,1,10.6055,10.6055A37.234,37.234,0,0,1,256,358.15Z" style="fill:#8c1813"/><rect height="68.3763" rx="22.7921" style="fill:#bf5e48" width="45.5842" x="233.208" y="263.5225"/><path d="M374.4984,233.5116H361V273.663h13.4985a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#bf5e48"/><circle cx="314.9628" cy="250.5016" r="20.625" style="fill:#0d253d"/><circle cx="319.5735" cy="242.8171" r="7.6845" style="fill:#ffefdc"/><circle cx="197.0373" cy="250.5016" r="20.625" style="fill:#0d253d"/><circle cx="201.648" cy="242.8171" r="7.6845" style="fill:#ffefdc"/><path d="M137.5015,233.5116H151V273.663H137.5015a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#bf5e48"/><path d="M361,219.8372a38.5449,38.5449,0,0,1-38.5437-38.5456H353.6A104.559,104.559,0,0,1,361,219.8372Z" style="fill:#8ca4bc"/><path d="M151,219.8372a38.5449,38.5449,0,0,0,38.5437-38.5456H158.4A104.559,104.559,0,0,0,151,219.8372Z" style="fill:#8ca4bc"/><path d="M305.0021,96.5073H206.9984a40.1773,40.1773,0,0,0-39.563,33.1781l-9.13,51.6073h195.39l-9.13-51.6073A40.1773,40.1773,0,0,0,305.0021,96.5073Z" style="fill:#0d263e"/></g></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_aethiopian_skin_05"><path d="M261.4639,368.543H250.5361a37.3721,37.3721,0,0,0-16.9793,4.1125V473.543h44.8883V372.6555A37.38,37.38,0,0,0,261.4639,368.543Z" style="fill:#f4e2ff"/><path d="M315.6613,459.23l-18.14-63.49a37.4468,37.4468,0,0,0-19.0759-23.0841V473.543h26.4276A11.23,11.23,0,0,0,315.6613,459.23Z" style="fill:#0d263e"/><path d="M214.479,395.74l-18.14,63.49a11.2289,11.2289,0,0,0,10.7959,14.3134h26.4222V372.6555A37.4393,37.4393,0,0,0,214.479,395.74Z" style="fill:#0d263e"/><path d="M377.7965,228.1317h-10.459A112.4052,112.4052,0,0,0,256,130.7745h0A112.4058,112.4058,0,0,0,144.662,228.1317H134.2035a33.7509,33.7509,0,1,0,0,67.5018H144.662A112.4059,112.4059,0,0,0,256,392.9907h0a112.4053,112.4053,0,0,0,111.3373-97.3572h10.459a33.7509,33.7509,0,1,0,0-67.5018Z" style="fill:#a5442e"/><path d="M256.0007,358.7994a37.2431,37.2431,0,0,1-26.5137-10.9827,7.4992,7.4992,0,0,1,10.6055-10.6055c8.4961,8.4961,23.32,8.4961,31.8164,0a7.4992,7.4992,0,0,1,10.6055,10.6055A37.2433,37.2433,0,0,1,256.0007,358.7994Z" style="fill:#8c1813"/><rect height="45" rx="15" style="fill:#8c2b15" width="30" x="241.0001" y="275.8619"/><path d="M380.4683,241.8063H366.97v40.1514h13.4985a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#8c2b15"/><path d="M336.1745,244.9419a7.4972,7.4972,0,0,0-10.6054,0l-2.3378,2.3383a20.6842,20.6842,0,1,0,10.605,10.6054l2.3382-2.3382A7.4973,7.4973,0,0,0,336.1745,244.9419Z" style="fill:#0d253d"/><circle cx="319.5726" cy="258.4683" r="7.6845" style="fill:#ffefdc"/><path d="M197.0363,245.5278a20.5241,20.5241,0,0,0-8.2681,1.75l-2.3373-2.3364a7.4992,7.4992,0,0,0-10.6055,10.6055l2.3373,2.3364a20.6122,20.6122,0,1,0,18.8736-12.356Z" style="fill:#0d253d"/><circle cx="201.647" cy="258.4683" r="7.6845" style="fill:#ffefdc"/><path d="M131.5316,241.8063H145.03v40.1514H131.5316a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#8c2b15"/><path d="M367.2559,227.6013a112.4007,112.4007,0,0,0-111.2568-96.8262h0a112.4014,112.4014,0,0,0-111.2544,96.8133c1.7633-4.4842,15.7429-37.2235,50.8983-44.5294a53.81,53.81,0,0,1,29.6882,2.016,89.76,89.76,0,0,0,61.3335,0,53.8119,53.8119,0,0,1,29.6887-2.016C351.5326,190.37,365.5086,223.1518,367.2559,227.6013Z" style="fill:#0d253d"/></g></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_caucasian_skin_07"><path d="M317.1627,404.168l-7.4254,59.55a11.1993,11.1993,0,0,1-11.1749,9.8254H213.4376a11.1993,11.1993,0,0,1-11.1749-9.8254l-7.4254-59.55a45.0061,45.0061,0,0,1,44.6251-50.625h33.0752A45.0061,45.0061,0,0,1,317.1627,404.168Z" style="fill:#f4e2ff"/><polygon points="278.762 441.067 256.038 463.194 233.238 440.394 251.312 353.543 261.137 353.543 278.762 441.067" style="fill:#eb5e59"/><path d="M371.827,219.8376H361v.0018a105,105,0,0,0-105-105h0a105,105,0,0,0-105,105v-.0018H140.1734a33.7514,33.7514,0,1,0,0,67.5027H151v-.0009a105,105,0,0,0,105,105h0a105,105,0,0,0,105-105v.0009h10.827a33.7514,33.7514,0,1,0,0-67.5027Z" style="fill:#f8c4b0"/><path d="M256.0018,358.15a37.2966,37.2966,0,0,1-26.521-10.979,7.5018,7.5018,0,0,1,10.6055-10.6128c8.5107,8.5035,23.3276,8.5,31.8237.0037a7.4992,7.4992,0,1,1,10.6055,10.6055A37.2428,37.2428,0,0,1,256.0018,358.15Z" style="fill:#ff8080"/><rect height="90" rx="30" style="fill:#ef9e8b" width="60" x="226.0002" y="245.2118"/><path d="M374.4986,233.5127H361v40.1514h13.4985a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#ef9e8b"/><circle cx="314.963" cy="250.5027" r="20.625" style="fill:#0167a3"/><circle cx="319.5737" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><circle cx="197.0374" cy="250.5027" r="20.625" style="fill:#0167a3"/><circle cx="201.6481" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><path d="M137.5017,233.5127H151v40.1514H137.5017a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#ef9e8b"/><path d="M256,114.8391c-27.2731-2.9608-48.4168-20.354-48.4168-20.354s-.9677,18.2739,7.4552,28.645c0,0-15.1145-.78-24.6094-8.291,0,0,.1227,13.0078,5.2634,19.1309A104.8047,104.8047,0,0,0,151,219.8373c.0037-.011,9.8172-39.4941,51.6536-53.5016h.02c13.18,13.1634,32.1565,21.4819,53.3267,21.4819s40.1468-8.3185,53.3267-21.4819h.02c36.5144,12.2241,48.63,43.8446,51.1249,51.7016l.5287,1.8A105,105,0,0,0,256,114.8391Z" style="fill:#eb5d25"/></g></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_mongolian_skin_07"><path d="M353.1011,464.5487V412.8422a60.7992,60.7992,0,0,0-60.7992-60.7992H219.6977a60.7987,60.7987,0,0,0-60.7986,60.7987v51.707a8.9943,8.9943,0,0,0,8.9943,8.9943H344.1068A8.9943,8.9943,0,0,0,353.1011,464.5487Z" style="fill:#f4e2ff"/><path d="M371.827,219.837H361a105,105,0,0,0-210,.0018v-.0018H140.1734a33.7518,33.7518,0,1,0,0,67.5036H151V287.34a105,105,0,0,0,210,.0009h10.827a33.7518,33.7518,0,1,0,0-67.5036Z" style="fill:#f8c497"/><path d="M255.9968,358.1512a37.234,37.234,0,0,1-26.5137-10.9863,7.4992,7.4992,0,1,1,10.6055-10.6055c8.4961,8.5034,23.3276,8.5034,31.8237,0a7.4992,7.4992,0,1,1,10.6055,10.6055A37.2382,37.2382,0,0,1,255.9968,358.1512Z" style="fill:#f7725c"/><rect height="60.0155" rx="16.6061" style="fill:#ef9e72" width="33.2122" x="239.3941" y="262.6054"/><path d="M374.4987,233.5127H361v40.1514h13.4986a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#ef9e72"/><circle cx="314.9629" cy="250.5027" r="20.625" style="fill:#0d253d"/><circle cx="319.5736" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><circle cx="197.0373" cy="250.5027" r="20.625" style="fill:#0d253d"/><circle cx="201.648" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><path d="M137.5017,233.5127H151v40.1514H137.5017a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#ef9e72"/><path d="M327.1926,142.5958c.15.15.2248.3.3749.45a63.2989,63.2989,0,0,1,15.3749,41.25v17.4a18.1811,18.1811,0,0,0,18.0748,18.1494h10.8751a33.07,33.07,0,0,1,10.275,1.5766,26.05,26.05,0,0,0,1.2753-8.0255c0-28.65-14.0249-46.35-28.125-56.8506A85.7224,85.7224,0,0,0,327.1926,142.5958Z" style="fill:#8ca4bc"/><path d="M184.8077,142.5958c-.15.15-.2247.3-.3749.45a63.3,63.3,0,0,0-15.3749,41.25v17.4a18.1809,18.1809,0,0,1-18.0748,18.1494H140.108a33.0693,33.0693,0,0,0-10.2749,1.5766,26.0472,26.0472,0,0,1-1.2754-8.0255c0-28.65,14.025-46.35,28.125-56.8506A85.7234,85.7234,0,0,1,184.8077,142.5958Z" style="fill:#8ca4bc"/></g></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_mongolian_skin_04"><circle cx="256.0001" cy="159.2951" r="62.7128" style="fill:#071b2b"/><path d="M304.8656,473.543H207.1343a11.2272,11.2272,0,0,1-10.7953-14.3116l18.14-63.4906a37.5,37.5,0,0,1,36.0569-27.1978h10.9278a37.5,37.5,0,0,1,36.0569,27.1978l18.14,63.4906A11.2272,11.2272,0,0,1,304.8656,473.543Z" style="fill:#eb5e59"/><path d="M377.7967,228.13h-10.459a112.3415,112.3415,0,0,0-222.6754,0h-10.459a33.7509,33.7509,0,1,0,0,67.5018h10.459a112.3416,112.3416,0,0,0,222.6754,0h10.459a33.7509,33.7509,0,1,0,0-67.5018Z" style="fill:#f8c497"/><path d="M256.0014,358.7981a37.2964,37.2964,0,0,1-26.521-10.979,7.5018,7.5018,0,0,1,10.6054-10.6128c8.5108,8.5035,23.3277,8.5,31.8238.0037a7.4992,7.4992,0,1,1,10.6054,10.6055A37.2428,37.2428,0,0,1,256.0014,358.7981Z" style="fill:#f7725c"/><path d="M380.4683,241.8049H366.97v40.1513h13.4985a20.2464,20.2464,0,0,0,0-40.1513Z" style="fill:#ef9e72"/><path d="M297.3612,271.0247a7.5,7.5,0,0,1-1.0913-14.9194l35.1929-5.2185a7.5,7.5,0,1,1,2.1973,14.8388l-35.1929,5.2185A7.5554,7.5554,0,0,1,297.3612,271.0247Z" style="fill:#0d263e"/><path d="M214.6415,271.0247a7.5541,7.5541,0,0,1-1.1059-.0806l-35.1929-5.2185a7.5,7.5,0,0,1,2.1972-14.8388l35.1929,5.2185a7.5,7.5,0,0,1-1.0913,14.9194Z" style="fill:#0d263e"/><path d="M131.5316,241.8049H145.03v40.1513H131.5316a20.2465,20.2465,0,0,1,0-40.1513Z" style="fill:#ef9e72"/><path d="M367.2558,227.6a112.4007,112.4007,0,0,0-111.2567-96.8262h0A112.4014,112.4014,0,0,0,144.7442,227.587c1.7633-4.4843,15.7429-37.2236,50.8983-44.5295a53.81,53.81,0,0,1,29.6882,2.016,89.76,89.76,0,0,0,61.3335,0,53.8119,53.8119,0,0,1,29.6887-2.016C351.5325,190.3689,365.5085,223.15,367.2558,227.6Z" style="fill:#0d253d"/><path d="M355.24,232.7753H271.3223a7.5,7.5,0,0,0-7.5,7.5v7.5H248.1778v-7.5a7.5,7.5,0,0,0-7.5-7.5H156.7606a7.5,7.5,0,0,0-7.5,7.5v61.9556a7.5,7.5,0,0,0,7.5,7.5h83.9172a7.5,7.5,0,0,0,7.5-7.5V262.7753h15.6445v39.4556a7.5,7.5,0,0,0,7.5,7.5H355.24a7.5,7.5,0,0,0,7.5-7.5V240.2753A7.5,7.5,0,0,0,355.24,232.7753ZM233.1778,294.7309H164.2606V247.7753h68.9172Zm114.5618,0H278.8223V247.7753H347.74Z" style="fill:#521919"/><rect height="45" rx="15" style="fill:#ef9e72" width="30" x="241.0001" y="275.8604"/></g></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_caucasian_skin_03"><rect height="175.2129" style="fill:#c94517" width="225" x="143.5001" y="199.2944"/><path d="M304.8658,473.543H207.1344a11.2273,11.2273,0,0,1-10.7953-14.3116l18.14-63.4906a37.5,37.5,0,0,1,36.0569-27.1978H261.464a37.5,37.5,0,0,1,36.0569,27.1978l18.14,63.4906A11.2273,11.2273,0,0,1,304.8658,473.543Z" style="fill:#f4e2ff"/><rect height="262.2149" rx="112.4697" style="fill:#f8c4b0" width="224.9396" x="143.5302" y="130.7736"/><path d="M255.9968,358.7981a37.243,37.243,0,0,1-26.5137-10.9826A7.4992,7.4992,0,0,1,240.0886,337.21c8.4961,8.5,23.3276,8.4924,31.8237,0a7.4992,7.4992,0,0,1,10.6055,10.6055A37.26,37.26,0,0,1,255.9968,358.7981Z" style="fill:#ff4d4d"/><rect height="45" rx="15" style="fill:#ef9e8b" width="30" x="241.0001" y="275.8604"/><path d="M336.1746,244.94a7.4973,7.4973,0,0,0-10.6055,0l-2.3378,2.3383a20.6845,20.6845,0,1,0,10.605,10.6055l2.3383-2.3383A7.4975,7.4975,0,0,0,336.1746,244.94Z" style="fill:#004b28"/><circle cx="319.5726" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M197.0364,245.5264a20.5225,20.5225,0,0,0-8.2682,1.7505l-2.3373-2.3365a7.4992,7.4992,0,0,0-10.6055,10.6055l2.3374,2.3364a20.6122,20.6122,0,1,0,18.8736-12.3559Z" style="fill:#004b28"/><circle cx="201.6471" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M251.0754,102.0416C177.9211,104.6435,121,166.9891,121,240.1891V364.9938a24.5144,24.5144,0,0,0,24.5151,24.5142h7.4487a11.4788,11.4788,0,0,0,11.478-11.4789V244.45a14.996,14.996,0,0,1,14.9954-14.9963h62.96L256,199.2944l13.602,30.1593h62.96A14.996,14.996,0,0,1,347.5582,244.45V378.0273a11.48,11.48,0,0,0,11.48,11.4807h7.4469A24.5144,24.5144,0,0,0,391,364.9938v-128.04A135.0028,135.0028,0,0,0,251.0754,102.0416Z" style="fill:#eb5d25"/></g></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_aethiopian_skin_03"><path d="M359.3344,308.522a19.3042,19.3042,0,0,0-10.2278-31.1168,19.2811,19.2811,0,0,0-19.3438-26.3869,19.3374,19.3374,0,0,0-26.533-19.2,19.3117,19.3117,0,0,0-31.2134-9.9876,19.278,19.278,0,0,0-32.7069.0966,19.2664,19.2664,0,0,0-31.1168,10.1783,19.336,19.336,0,0,0-26.4364,19.3462,19.2885,19.2885,0,0,0-19.2,26.4835,19.35,19.35,0,0,0-10.0346,31.2134,19.3043,19.3043,0,0,0,.0494,32.7068,19.3169,19.3169,0,0,0,10.1784,31.1169,19.3082,19.3082,0,0,0,19.2967,26.4858,19.2884,19.2884,0,0,0,26.4834,19.2A19.3055,19.3055,0,0,0,239.6959,428.74a19.2936,19.2936,0,0,0,32.7539-.05,19.2765,19.2765,0,0,0,31.1169-10.1289,19.3047,19.3047,0,0,0,26.4858-19.25A19.29,19.29,0,0,0,349.3,372.8286a19.3278,19.3278,0,0,0,10.1312-31.164A19.28,19.28,0,0,0,368.5,325.31v-.4334A19.4041,19.4041,0,0,0,359.3344,308.522Z" style="fill:#071b2b"/><path d="M298.5816,473.543H213.418a11.2352,11.2352,0,0,1-11.1484-9.8416l-7.4478-59.5825a44.995,44.995,0,0,1,44.6475-50.5759H272.53a44.995,44.995,0,0,1,44.6475,50.5759L309.73,463.7014A11.2351,11.2351,0,0,1,298.5816,473.543Z" style="fill:#ffc139"/><path d="M371.8266,219.8376H361v.0018a105,105,0,0,0-105-105h0a105,105,0,0,0-105,105v-.0018H140.1734a33.7514,33.7514,0,1,0,0,67.5027H151v-.0009a105,105,0,0,0,105,105h0a105,105,0,0,0,105-105v.0009h10.8266a33.7514,33.7514,0,1,0,0-67.5027Z" style="fill:#a5442e"/><path d="M277.3672,376.1274H234.6326a8.6154,8.6154,0,0,0-5.9871,14.8106l21.3673,20.65a8.6157,8.6157,0,0,0,11.9743,0l21.3672-20.65A8.6154,8.6154,0,0,0,277.3672,376.1274Z" style="fill:#0d263e"/><path d="M255.9991,358.15a37.243,37.243,0,0,1-26.5137-10.9826,7.4992,7.4992,0,0,1,10.6055-10.6055c8.4961,8.4961,23.32,8.4961,31.8164,0a7.4992,7.4992,0,0,1,10.6055,10.6055A37.2432,37.2432,0,0,1,255.9991,358.15Z" style="fill:#8c1813"/><rect height="68.3763" rx="22.7921" style="fill:#8c2b15" width="45.5842" x="233.2078" y="263.5237"/><path d="M374.4984,233.5127H361v40.1514h13.4986a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#8c2b15"/><circle cx="314.9626" cy="250.5027" r="20.625" style="fill:#0d253d"/><circle cx="319.5733" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><circle cx="197.037" cy="250.5027" r="20.625" style="fill:#0d253d"/><circle cx="201.6478" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><path d="M137.5014,233.5127H151v40.1514H137.5014a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#8c2b15"/><path d="M361,219.8373a105,105,0,0,0-210,0c22.3892-84.0876,105-50.9125,105-50.9125S338.6107,135.75,361,219.8373Z" style="fill:#0d263e"/></g></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_mongolian_skin_06"><path d="M272.53,353.543H239.4692a44.952,44.952,0,0,0-11.22,1.4612V473.543h55.5V355.0042A44.9449,44.9449,0,0,0,272.53,353.543Z" style="fill:#f4e2ff"/><path d="M309.73,463.6992l7.4478-59.5825A44.977,44.977,0,0,0,283.75,355.0042V473.543h14.8315A11.2372,11.2372,0,0,0,309.73,463.6992Z" style="fill:#243f57"/><path d="M194.8217,404.1167l7.4478,59.5825a11.2363,11.2363,0,0,0,11.1484,9.8438h14.8315V355.0042A44.9766,44.9766,0,0,0,194.8217,404.1167Z" style="fill:#243f57"/><path d="M371.8266,219.8372H361A104.9994,104.9994,0,0,0,256,114.839h0a105,105,0,0,0-105,105v-.0018H140.173a33.7519,33.7519,0,1,0,0,67.5037H151v-.0019a105,105,0,0,0,105,105h0A104.9994,104.9994,0,0,0,361,287.3409h10.8271a33.7519,33.7519,0,1,0,0-67.5037Z" style="fill:#f8c497"/><path d="M255.9991,358.1514a37.234,37.234,0,0,1-26.5137-10.9863A7.4992,7.4992,0,1,1,240.0909,336.56c8.4961,8.5034,23.32,8.5034,31.8164,0a7.4992,7.4992,0,1,1,10.6055,10.6055A37.234,37.234,0,0,1,255.9991,358.1514Z" style="fill:#f7725c"/><rect height="60.0155" rx="16.6061" style="fill:#ef9e72" width="33.2122" x="239.3937" y="262.6054"/><path d="M374.4983,233.5127H361v40.1514h13.4985a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#ef9e72"/><path d="M297.3589,275.6111a7.5,7.5,0,0,1-1.0913-14.9194l35.1929-5.2185a7.5,7.5,0,0,1,2.1973,14.8389l-35.1929,5.2185A7.568,7.568,0,0,1,297.3589,275.6111Z" style="fill:#0d263e"/><path d="M214.6392,275.6111a7.5677,7.5677,0,0,1-1.1059-.0805L178.34,270.3121a7.5,7.5,0,1,1,2.1973-14.8389l35.1928,5.2185a7.5,7.5,0,0,1-1.0913,14.9194Z" style="fill:#0d263e"/><path d="M137.5013,233.5127H151v40.1514H137.5013a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#ef9e72"/><path d="M256,104.0121A115.8272,115.8272,0,0,0,140.1733,219.8373l23.1647,20.31,23.1642-20.31,23.1647,20.31,23.1642-20.31,23.1647,20.31,23.1642-20.31,23.1647,20.31,23.1642-20.31,23.1646,20.31,23.1643-20.31h.0087A115.8272,115.8272,0,0,0,256,104.0121Z" style="fill:#eb5d25"/></g></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_malayan_skin_05"><path d="M412.0236,413.3344c-.9052-10.3452-4.655-15.2289-8.4057-20.1134s-7.5005-9.769-8.4056-20.115c-.9044-10.3363,1.9412-15.793,4.7867-21.25s5.69-10.9133,4.7867-21.25c-.9051-10.3428-4.655-15.2257-8.4048-20.1077s-7.5-9.765-8.4049-20.1078c-.8291-9.4676,1.49-14.8386,4.07-19.8685H119.9539c2.5805,5.03,4.8991,10.4009,4.0707,19.8685-.9043,10.3428-4.655,15.2257-8.4048,20.1078s-7.5005,9.7649-8.4048,20.1077c-.9044,10.3364,1.9412,15.793,4.7867,21.25s5.691,10.9134,4.7859,21.25c-.9052,10.346-4.655,15.2305-8.4049,20.115s-7.5005,9.7682-8.4056,20.1134c-.0089.1043-.0178.2069-.0267.31a28.2927,28.2927,0,0,0,15.7243,27.2623c19.19,9.6777,64.3164,27.1178,140.326,27.1178s121.1347-17.44,140.3252-27.1178a28.2908,28.2908,0,0,0,15.7235-27.2623C412.0413,413.5413,412.0316,413.4387,412.0236,413.3344Z" style="fill:#0d263e"/><path d="M304.8663,473.543H207.1349A11.2273,11.2273,0,0,1,196.34,459.2314l18.14-63.4906a37.5,37.5,0,0,1,36.0569-27.1978h10.9278a37.5,37.5,0,0,1,36.0569,27.1978l18.14,63.4906A11.2273,11.2273,0,0,1,304.8663,473.543Z" style="fill:#d87761"/><path d="M297.5208,395.7409a37.3919,37.3919,0,0,0-20.3082-23.6151V392.33A21.2127,21.2127,0,0,1,256,413.5424h0A21.2132,21.2132,0,0,1,234.787,392.33V372.1258a37.3916,37.3916,0,0,0-20.3082,23.6151L199.964,446.5435H312.0356Z" style="fill:#3285e2"/><path d="M377.7969,228.13h-10.459a112.4042,112.4042,0,0,0-111.3373-97.3562H256A112.4056,112.4056,0,0,0,144.6624,228.13h-10.459a33.7514,33.7514,0,1,0,0,67.5028h10.459A112.4063,112.4063,0,0,0,256,392.9888h.0009a112.405,112.405,0,0,0,111.3373-97.3562h10.459a33.7514,33.7514,0,1,0,0-67.5028Z" style="fill:#d87761"/><path d="M255.9969,358.7994a37.2335,37.2335,0,0,1-26.5136-10.9864,7.4992,7.4992,0,1,1,10.6054-10.6054c8.4888,8.5,23.3057,8.5107,31.8238-.0037a7.5018,7.5018,0,0,1,10.6054,10.6128A37.285,37.285,0,0,1,255.9969,358.7994Z" style="fill:#c42020"/><rect height="45" rx="15" style="fill:#bf5e48" width="30" x="241.0001" y="275.8604"/><path d="M380.4683,241.8049H366.97v40.1513h13.4985a20.2464,20.2464,0,0,0,0-40.1513Z" style="fill:#bf5e48"/><path d="M336.1746,244.94a7.4973,7.4973,0,0,0-10.6055,0l-2.3378,2.3383a20.6845,20.6845,0,1,0,10.605,10.6055l2.3383-2.3383A7.4975,7.4975,0,0,0,336.1746,244.94Z" style="fill:#0d263e"/><circle cx="319.5726" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M197.0364,245.5264a20.5225,20.5225,0,0,0-8.2682,1.7505l-2.3373-2.3365a7.4992,7.4992,0,0,0-10.6055,10.6055l2.3374,2.3364a20.6122,20.6122,0,1,0,18.8736-12.3559Z" style="fill:#0d263e"/><circle cx="201.6471" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M131.5317,241.8049H145.03v40.1513H131.5317a20.2464,20.2464,0,0,1,0-40.1513Z" style="fill:#bf5e48"/><path d="M389.99,213.2452V230.42a32.7451,32.7451,0,0,0-12.15-2.3246H367.49c-.0751,0-.0751-.075-.15-.075-32.9993-21.3758-68.4-11.55-112.2748-16.65s-57.75-40.2008-57.75-40.2008S157.64,181.145,144.74,227.57c-.0751.15-.0751.3754-.15.5255H134.24a33.1388,33.1388,0,0,0-12.225,2.3246V213.2452a133.9874,133.9874,0,0,1,267.9748,0Z" style="fill:#0d263e"/></g></svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_mongolian_skin_03"><path d="M302.0041,473.543H216.84a11.235,11.235,0,0,1-11.1483-9.8416l-7.4479-59.5825a44.995,44.995,0,0,1,44.6475-50.5759h33.0611A44.995,44.995,0,0,1,320.6,404.1189l-7.4478,59.5825A11.2352,11.2352,0,0,1,302.0041,473.543Z" style="fill:#8ca4bc"/><path d="M375.2488,219.8376H364.4222v.0018a105,105,0,0,0-210,0v-.0018H143.5957a33.7514,33.7514,0,1,0,0,67.5027h10.8265v-.0009a105,105,0,0,0,210,0v.0009h10.8266a33.7514,33.7514,0,1,0,0-67.5027Z" style="fill:#f8c497"/><path d="M259.419,358.15a37.2428,37.2428,0,0,1-26.5136-10.9826,7.4992,7.4992,0,0,1,10.6054-10.6055c8.4961,8.5,23.3277,8.4924,31.8238,0A7.4992,7.4992,0,0,1,285.94,347.1673,37.26,37.26,0,0,1,259.419,358.15Z" style="fill:#f7725c"/><rect height="60.0155" rx="16.6061" style="fill:#ef9e72" width="33.2122" x="242.8161" y="262.6054"/><path d="M377.9207,233.5127H364.4222v40.1514h13.4985a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#ef9e72"/><circle cx="318.3849" cy="250.5027" r="20.625" style="fill:#0d253d"/><circle cx="322.9956" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><circle cx="200.4594" cy="250.5027" r="20.625" style="fill:#0d253d"/><circle cx="205.0701" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><path d="M140.9238,233.5127h13.4985v40.1514H140.9238a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#ef9e72"/><path d="M345.6567,112.0617h-30a35.6394,35.6394,0,0,0-35.64-35.64H124.4222a110.9573,110.9573,0,0,0,5.9336,35.64h-27.399v56.31a51.4656,51.4656,0,0,0,51.4654,51.4655H283.5565a32.1,32.1,0,0,0,32.1-32.1,38.6587,38.6587,0,0,0,37.95,32.1h21.6751l13.95-50.3265A45.2505,45.2505,0,0,0,345.6567,112.0617Z" style="fill:#0d263e"/></g></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_caucasian_skin_07"><path d="M360.7864,353.4034l-.0942.0239a41.4194,41.4194,0,1,0-77.241,19.2989c21.2646,36.8313,73.3884,64.0284,119.5789,32.04C403.03,404.7662,358.55,391.89,360.7864,353.4034Z" style="fill:#c94517"/><path d="M315.6609,459.2315l-18.14-63.49a37.3021,37.3021,0,0,0-5.8567-11.8195l-35.6648,61.7725L220.3353,383.922a37.3115,37.3115,0,0,0-5.8562,11.8195l-18.14,63.49a11.2272,11.2272,0,0,0,10.7954,14.3115h97.7312A11.2271,11.2271,0,0,0,315.6609,459.2315Z" style="fill:#521919"/><path d="M291.664,383.922a37.4464,37.4464,0,0,0-30.2-15.379H250.5363a37.4468,37.4468,0,0,0-30.201,15.379l35.6639,61.7725Z" style="fill:#f4e2ff"/><path d="M377.7965,228.13h-10.459A112.4036,112.4036,0,0,0,256,130.775h0A112.4042,112.4042,0,0,0,144.662,228.13H134.2035a33.7514,33.7514,0,1,0,0,67.5027H144.662A112.4058,112.4058,0,0,0,256,392.9894h0a112.4052,112.4052,0,0,0,111.3373-97.3563h10.459a33.7514,33.7514,0,1,0,0-67.5027Z" style="fill:#f8c4b0"/><path d="M256,358.8a37.2338,37.2338,0,0,1-26.5137-10.9863,7.4992,7.4992,0,1,1,10.6055-10.6055c8.4961,8.5035,23.32,8.5035,31.8164,0a7.4992,7.4992,0,1,1,10.6054,10.6055A37.2338,37.2338,0,0,1,256,358.8Z" style="fill:#ff4d4d"/><rect height="45" rx="15" style="fill:#ef9e8b" width="30" x="241.0001" y="275.8611"/><path d="M380.4683,241.8056H366.97v40.1513h13.4985a20.2464,20.2464,0,0,0,0-40.1513Z" style="fill:#ef9e8b"/><path d="M336.1745,244.9412a7.4972,7.4972,0,0,0-10.6054,0l-2.3378,2.3382a20.6845,20.6845,0,1,0,10.605,10.6055l2.3382-2.3383A7.4972,7.4972,0,0,0,336.1745,244.9412Z" style="fill:#0167a3"/><circle cx="319.5726" cy="258.4675" r="7.6845" style="fill:#ffefdc"/><path d="M197.0363,245.5271a20.5224,20.5224,0,0,0-8.2681,1.7505l-2.3373-2.3364a7.4992,7.4992,0,1,0-10.6055,10.6054l2.3373,2.3364a20.6122,20.6122,0,1,0,18.8736-12.3559Z" style="fill:#0167a3"/><circle cx="201.647" cy="258.4675" r="7.6845" style="fill:#ffefdc"/><path d="M131.5316,241.8056H145.03v40.1513H131.5316a20.2465,20.2465,0,0,1,0-40.1513Z" style="fill:#ef9e8b"/><path d="M367.2558,227.6A112.4007,112.4007,0,0,0,255.999,130.7738h0a112.4014,112.4014,0,0,0-111.2544,96.8134c1.7633-4.4843,15.7429-37.2236,50.8983-44.5295a53.81,53.81,0,0,1,29.6882,2.016,89.76,89.76,0,0,0,61.3335,0,53.8119,53.8119,0,0,1,29.6887-2.016C351.5325,190.3691,365.5085,223.1505,367.2558,227.6Z" style="fill:#eb5d25"/><path d="M209.3315,181.9039s-5.5472-23.8983-33.2572-26.5419c-28.6993-2.7359-60.6751,18.63-56.0959,67.0721,3.5212,37.2563,24.4637,39.7018,20.8641,72.3785-3.6,32.6785-5.2425,55.4287,29.1337,74.6221,0,0-20.03-30.5406-10.1845-56.43,9.8447-25.8879-6.6243-56.0152,4.435-84.7947C175.286,199.432,195.1547,180.9772,209.3315,181.9039Z" style="fill:#ff7443"/></g></svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_caucasian_skin_03"><path d="M317.1627,404.168l-7.4254,59.55a11.1994,11.1994,0,0,1-11.175,9.8254H213.4375a11.1994,11.1994,0,0,1-11.1749-9.8254l-7.4254-59.55a45.0062,45.0062,0,0,1,44.6251-50.625h33.0753A45.0062,45.0062,0,0,1,317.1627,404.168Z" style="fill:#243f57"/><path d="M371.8266,219.8372H361v.0018a105,105,0,0,0-210,0v-.0018H140.1734a33.7519,33.7519,0,1,0,0,67.5037H151v-.0019a105,105,0,0,0,210,0v.0019h10.8266a33.7519,33.7519,0,1,0,0-67.5037Z" style="fill:#f8c4b0"/><path d="M256,358.1514a37.234,37.234,0,0,1-26.5137-10.9863A7.4992,7.4992,0,1,1,240.0918,336.56c8.4961,8.5034,23.32,8.5034,31.8164,0a7.4992,7.4992,0,1,1,10.6055,10.6055A37.234,37.234,0,0,1,256,358.1514Z" style="fill:#ff8080"/><rect height="68.3763" rx="22.7921" style="fill:#ef9e8b" width="45.5842" x="233.2079" y="263.5237"/><path d="M374.4985,233.5127H361v40.1514h13.4985a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#ef9e8b"/><circle cx="314.9627" cy="250.5027" r="20.625" style="fill:#004b28"/><circle cx="319.5734" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><circle cx="197.0372" cy="250.5027" r="20.625" style="fill:#004b28"/><circle cx="201.6479" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><path d="M137.5015,233.5127H151v40.1514H137.5015a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#ef9e8b"/><path d="M235.58,200.8439a26.62,26.62,0,0,1-22.1418,5.9477h0a26.3254,26.3254,0,0,1-18.8371-14.2771h0a26.4169,26.4169,0,0,1-24.4557.1323h0a26.2756,26.2756,0,0,1-14.2739-24.8494h0a26.5112,26.5112,0,0,1-23.3326-25.9757h0a26.359,26.359,0,0,1,22.9357-26.505h0a26.43,26.43,0,0,1,14.1448-25.114h0a26.3645,26.3645,0,0,1,24.52,0h0A26.3963,26.3963,0,0,1,212.9765,75.861h0a26.3859,26.3859,0,0,1,22.1385,5.9477h0a26.2162,26.2162,0,0,1,20.4895-9.8462h0a26.3864,26.3864,0,0,1,20.554,9.7817h0a26.29,26.29,0,0,1,22.0773-6.0155h0A26.509,26.509,0,0,1,317.1375,89.938h0a26.4118,26.4118,0,0,1,24.4557-.1323h0a26.464,26.464,0,0,1,14.3416,24.7849h0a26.3761,26.3761,0,0,1,23.4617,25.7111h0v.4614h0c0,.1324.0678.3324.0678.5293h0a26.4408,26.4408,0,0,1-23.2,26.24h0a26.2936,26.2936,0,0,1-14.2094,24.9818h0a26.2319,26.2319,0,0,1-24.4556-.0646h0a26.6951,26.6951,0,0,1-18.834,14.3417h0a26.4243,26.4243,0,0,1-22.1418-6.0155h0a26.253,26.253,0,0,1-20.5572,9.8494h0A26.3624,26.3624,0,0,1,235.58,200.8439Z" style="fill:#eb5d25"/></g></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_aethiopian_skin_02"><path d="M435.3407,177.9c12.1783-13.526,17.7887-29.057,13.9151-43.5095-6.3144-23.5712-35.8512-37.0441-71.16-35.0226,5.0491-19.2591,2.5516-37.0807-8.768-48.4-7.7948-7.7948-18.6868-11.391-30.99-11.2591l.0339-.0385c-.17,0-.3461.0275-.5173.0275-.9219.0183-1.8613.0952-2.7988.1538C307.6191,40.8,277.6594,53.2566,256,68.599c-21.6587-15.3405-51.6175-27.799-79.054-28.7475-.9375-.0586-1.8787-.1355-2.8006-.1538-.1712,0-.347-.0275-.5173-.0275l.0339.0385c-12.3019-.1319-23.193,3.4643-30.9888,11.2591-11.3205,11.32-13.8162,29.1412-8.768,48.4-35.31-2.0215-64.8449,11.4514-71.16,35.0226-3.8727,14.4525,1.7367,29.9835,13.9141,43.51-26.7022,16.1041-41.9137,39.9866-36.1505,61.496,4.1455,15.4687,18.3435,26.5448,37.56,31.8-12.7066,25.8032-12.9208,51.806,1.9263,66.6522,12.7121,12.713,33.6108,14.3188,55.5533,6.5625,1.3806,29.729,14.2813,53.3862,35.0711,58.9581,14.5413,3.8965,30.1776-1.7926,43.7613-14.1247,10.0836,18.4021,24.9719,30.0989,41.62,30.0989,16.65,0,31.538-11.6968,41.6207-30.0989,13.5837,12.3321,29.2191,18.0212,43.7613,14.1247,20.79-5.5719,33.6914-29.2291,35.07-58.9581,21.9434,7.7563,42.843,6.1505,55.5542-6.5625,14.8471-14.8462,14.6338-40.849,1.9263-66.6522,19.2169-5.2551,33.4131-16.3312,37.5586-31.8C477.2553,217.8868,462.0429,194.0043,435.3407,177.9Z" style="fill:#521919"/><path d="M304.8661,473.543H207.1347A11.2272,11.2272,0,0,1,196.34,459.2314l18.14-63.4906a37.5,37.5,0,0,1,36.0569-27.1978h10.9278a37.5,37.5,0,0,1,36.0569,27.1978l18.14,63.4906A11.2273,11.2273,0,0,1,304.8661,473.543Z" style="fill:#eb5e59"/><path d="M377.7969,228.13H367.338a112.3418,112.3418,0,0,0-222.6755,0H134.2044a33.7514,33.7514,0,1,0,0,67.5027h10.4581a112.3417,112.3417,0,0,0,222.6755,0h10.4589a33.7514,33.7514,0,1,0,0-67.5027Z" style="fill:#a5442e"/><path d="M256.0025,358.7992a37.2848,37.2848,0,0,1-26.521-10.9827,7.5018,7.5018,0,0,1,10.6055-10.6128c8.518,8.5181,23.3349,8.5,31.8237.0037a7.4992,7.4992,0,1,1,10.6055,10.6055A37.234,37.234,0,0,1,256.0025,358.7992Z" style="fill:#8c1813"/><rect height="45" rx="15" style="fill:#8c2b15" width="30" x="241.0004" y="275.8604"/><path d="M380.4686,241.8049H366.97v40.1513h13.4985a20.2464,20.2464,0,0,0,0-40.1513Z" style="fill:#8c2b15"/><path d="M336.1749,244.94a7.4973,7.4973,0,0,0-10.6055,0l-2.3378,2.3383a20.6845,20.6845,0,1,0,10.605,10.6055l2.3383-2.3383A7.4973,7.4973,0,0,0,336.1749,244.94Z" style="fill:#0d253d"/><circle cx="319.5729" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M197.0367,245.5264a20.5217,20.5217,0,0,0-8.2681,1.7505l-2.3374-2.3365a7.4992,7.4992,0,0,0-10.6055,10.6055l2.3374,2.3364a20.6122,20.6122,0,1,0,18.8736-12.3559Z" style="fill:#0d253d"/><circle cx="201.6474" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M131.532,241.8049h13.4985v40.1513H131.532a20.2464,20.2464,0,0,1,0-40.1513Z" style="fill:#8c2b15"/><path d="M256,106.33a121.7984,121.7984,0,0,0-121.7963,121.8h10.827C233.9778,228.13,256,175.4728,256,175.4728S278.022,228.13,366.97,228.13h10.827A121.7986,121.7986,0,0,0,256,106.33Z" style="fill:#521919"/></g></svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_aethiopian_skin_04"><path d="M317.1626,404.168l-7.4254,59.55a11.1993,11.1993,0,0,1-11.1749,9.8254H213.4375a11.1993,11.1993,0,0,1-11.1749-9.8254l-7.4254-59.55a45.0061,45.0061,0,0,1,44.6251-50.625h33.0752A45.0061,45.0061,0,0,1,317.1626,404.168Z" style="fill:#f4e2ff"/><polygon points="278.762 441.067 256.037 463.194 233.238 440.394 251.312 353.543 261.137 353.543 278.762 441.067" style="fill:#3285e2"/><path d="M371.8266,219.8376H361v.0018a105,105,0,0,0-105-105h0a105,105,0,0,0-105,105v-.0018H140.1734a33.7514,33.7514,0,1,0,0,67.5027H151v-.0009a105,105,0,0,0,105,105h0a105,105,0,0,0,105-105v.0009h10.8266a33.7514,33.7514,0,1,0,0-67.5027Z" style="fill:#a5442e"/><path d="M277.3672,376.1274H234.6326a8.6154,8.6154,0,0,0-5.9871,14.8106l21.3673,20.65a8.6157,8.6157,0,0,0,11.9743,0l21.3672-20.65A8.6154,8.6154,0,0,0,277.3672,376.1274Z" style="fill:#0d263e"/><path d="M255.9991,358.15a37.243,37.243,0,0,1-26.5137-10.9826,7.4992,7.4992,0,0,1,10.6055-10.6055c8.4961,8.4961,23.32,8.4961,31.8164,0a7.4992,7.4992,0,0,1,10.6055,10.6055A37.2432,37.2432,0,0,1,255.9991,358.15Z" style="fill:#8c1813"/><rect height="68.3763" rx="22.7921" style="fill:#8c2b15" width="45.5842" x="233.2078" y="263.5237"/><path d="M374.4984,233.5127H361v40.1514h13.4986a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#8c2b15"/><circle cx="314.9626" cy="250.5027" r="20.625" style="fill:#0d253d"/><circle cx="319.5733" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><circle cx="197.037" cy="250.5027" r="20.625" style="fill:#0d253d"/><circle cx="201.6478" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><path d="M137.5014,233.5127H151v40.1514H137.5014a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#8c2b15"/><path d="M235.58,200.8439a26.6205,26.6205,0,0,1-22.1418,5.9477h0a26.3254,26.3254,0,0,1-18.8371-14.2771h0a26.4169,26.4169,0,0,1-24.4557.1323h0a26.2754,26.2754,0,0,1-14.2739-24.8494h0a26.5111,26.5111,0,0,1-23.3326-25.9757h0a26.359,26.359,0,0,1,22.9356-26.505h0a26.43,26.43,0,0,1,14.1448-25.114h0a26.3647,26.3647,0,0,1,24.52,0h0A26.3963,26.3963,0,0,1,212.9763,75.861h0a26.386,26.386,0,0,1,22.1386,5.9477h0a26.2162,26.2162,0,0,1,20.4895-9.8462h0a26.3865,26.3865,0,0,1,20.554,9.7817h0a26.29,26.29,0,0,1,22.0772-6.0155h0A26.5086,26.5086,0,0,1,317.1373,89.938h0a26.4118,26.4118,0,0,1,24.4557-.1323h0a26.4641,26.4641,0,0,1,14.3417,24.7849h0a26.3761,26.3761,0,0,1,23.4617,25.7111h0v.4614h0c0,.1324.0678.3324.0678.5293h0a26.4408,26.4408,0,0,1-23.2,26.24h0a26.2936,26.2936,0,0,1-14.2094,24.9818h0a26.2321,26.2321,0,0,1-24.4557-.0646h0a26.6949,26.6949,0,0,1-18.8339,14.3417h0a26.4242,26.4242,0,0,1-22.1418-6.0155h0a26.253,26.253,0,0,1-20.5572,9.8494h0A26.3622,26.3622,0,0,1,235.58,200.8439Z" style="fill:#0d263e"/></g></svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_aethiopian_skin_01"><path d="M298.5816,473.543H213.418a11.2352,11.2352,0,0,1-11.1484-9.8416l-7.4478-59.5825a44.995,44.995,0,0,1,44.6475-50.5759H272.53a44.995,44.995,0,0,1,44.6475,50.5759L309.73,463.7014A11.2351,11.2351,0,0,1,298.5816,473.543Z" style="fill:#f4e2ff"/><path d="M371.8266,219.8369H361v.0019a105,105,0,0,0-105-105h0a105,105,0,0,0-105,105v-.0019H140.1734a33.7519,33.7519,0,1,0,0,67.5037H151v-.0018a104.9989,104.9989,0,0,0,105,105h0a104.999,104.999,0,0,0,105-105v.0018h10.8266a33.7519,33.7519,0,1,0,0-67.5037Z" style="fill:#a5442e"/><path d="M255.9991,358.1493a37.243,37.243,0,0,1-26.5137-10.9826,7.4992,7.4992,0,0,1,10.6055-10.6055c8.4961,8.4961,23.32,8.4961,31.8164,0a7.4992,7.4992,0,0,1,10.6055,10.6055A37.2432,37.2432,0,0,1,255.9991,358.1493Z" style="fill:#8c1813"/><rect height="68.3763" rx="22.7921" style="fill:#8c2b15" width="45.5842" x="233.2078" y="263.5237"/><path d="M374.4984,233.5127H361v40.1514h13.4986a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#8c2b15"/><circle cx="314.9626" cy="250.5027" r="20.625" style="fill:#0d253d"/><circle cx="319.5733" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><circle cx="197.037" cy="250.5027" r="20.625" style="fill:#0d253d"/><circle cx="201.6478" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><path d="M137.5014,233.5127H151v40.1514H137.5014a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#8c2b15"/></g></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_mongolian_skin_05"><path d="M324.8084,404.168l-7.4253,59.55a11.1994,11.1994,0,0,1-11.175,9.8254H221.0833a11.1993,11.1993,0,0,1-11.1749-9.8254l-7.4254-59.55a45.0062,45.0062,0,0,1,44.6251-50.625h33.0752A45.0061,45.0061,0,0,1,324.8084,404.168Z" style="fill:#27b286"/><path d="M379.4724,219.8372H368.6458v.0018a105,105,0,0,0-210,0v-.0018H147.8192a33.7519,33.7519,0,1,0,0,67.5037h10.8266v-.0019a105,105,0,0,0,210,0v.0019h10.8266a33.7519,33.7519,0,1,0,0-67.5037Z" style="fill:#f8c497"/><path d="M263.649,358.1514a37.2382,37.2382,0,0,1-26.521-10.9863A7.4992,7.4992,0,1,1,247.7335,336.56c8.4961,8.5034,23.3276,8.5034,31.8237,0a7.4992,7.4992,0,1,1,10.6055,10.6055A37.234,37.234,0,0,1,263.649,358.1514Z" style="fill:#f7725c"/><rect height="60.0155" rx="16.6061" style="fill:#ef9e72" width="33.2122" x="247.0397" y="262.6054"/><path d="M382.1443,233.5127H368.6457v40.1514h13.4986a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#ef9e72"/><circle cx="322.6085" cy="250.5027" r="20.625" style="fill:#0d253d"/><circle cx="327.2192" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><circle cx="204.683" cy="250.5027" r="20.625" style="fill:#0d253d"/><circle cx="209.2937" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><path d="M145.1473,233.5127h13.4986v40.1514H145.1473a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#ef9e72"/><path d="M337.3833,121.6616h-3.3751A56.99,56.99,0,0,0,281.283,86.3369H127.533a57.025,57.025,0,0,0,12.3,35.3247h-41.1a63.6335,63.6335,0,0,0,36.6751,57.6745l12.3748,40.5011h10.8751a34.57,34.57,0,0,0,34.5748-34.5007h140.85a34.57,34.57,0,0,0,34.5749,34.5007h10.8l8.925-29.2511A53.3191,53.3191,0,0,0,337.3833,121.6616Z" style="fill:#0d263e"/><path d="M368.3171,208.276H284.4a7.5,7.5,0,0,0-7.5,7.5v8.8514H250.3917V215.776a7.5,7.5,0,0,0-7.5-7.5H158.9745a7.5,7.5,0,0,0-7.5,7.5v69.4556a7.5,7.5,0,0,0,7.5,7.5h83.9172a7.5,7.5,0,0,0,7.5-7.5V239.6274H276.9v45.6042a7.5,7.5,0,0,0,7.5,7.5h83.9172a7.5,7.5,0,0,0,7.5-7.5V215.776A7.5,7.5,0,0,0,368.3171,208.276ZM235.3917,277.7316H166.4745V223.276h68.9172Zm125.4254,0H291.9V223.276h68.9172Z" style="fill:#521919"/></g></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_caucasian_skin_04"><rect height="277.8797" style="fill:#330f0f" width="225" x="143.5005" y="175.446"/><path d="M261.4642,368.543H250.5365a37.3725,37.3725,0,0,0-16.9794,4.1125V473.543h44.8883V372.6555A37.38,37.38,0,0,0,261.4642,368.543Z" style="fill:#f4e2ff"/><path d="M315.6616,459.23l-18.14-63.49a37.4468,37.4468,0,0,0-19.0759-23.0841V473.543H304.873A11.23,11.23,0,0,0,315.6616,459.23Z" style="fill:#0d263e"/><path d="M214.4793,395.74l-18.14,63.49A11.2288,11.2288,0,0,0,207.135,473.543h26.4221V372.6555A37.44,37.44,0,0,0,214.4793,395.74Z" style="fill:#0d263e"/><path d="M341.8529,270.9565h39.9278a0,0,0,0,1,0,0V468.3257a0,0,0,0,1,0,0h-79.234a0,0,0,0,1,0,0V310.2627A39.3062,39.3062,0,0,1,341.8529,270.9565Z" style="fill:#521919" transform="translate(684.3273 739.2822) rotate(180)"/><path d="M130.22,270.9565h79.234a0,0,0,0,1,0,0V468.3257a0,0,0,0,1,0,0H169.5261A39.3062,39.3062,0,0,1,130.22,429.02V270.9565A0,0,0,0,1,130.22,270.9565Z" style="fill:#521919"/><path d="M377.7967,228.1285h-10.459a112.4033,112.4033,0,0,0-111.3372-97.3553h0a112.4033,112.4033,0,0,0-111.3373,97.3553h-10.459a33.7514,33.7514,0,1,0,0,67.5028h10.459a112.405,112.405,0,0,0,111.3373,97.3563h0a112.4049,112.4049,0,0,0,111.3372-97.3563h10.459a33.7514,33.7514,0,1,0,0-67.5028Z" style="fill:#f8c4b0"/><path d="M255.9968,358.7981a37.234,37.234,0,0,1-26.5137-10.9863,7.4992,7.4992,0,1,1,10.6055-10.6055c8.4961,8.5034,23.3276,8.5034,31.8237,0a7.4992,7.4992,0,1,1,10.6055,10.6055A37.2382,37.2382,0,0,1,255.9968,358.7981Z" style="fill:#ff4d4d"/><path d="M380.4686,241.8037H366.97v40.1514h13.4985a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#ef9e8b"/><path d="M131.532,241.8037h13.4985v40.1514H131.532a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#ef9e8b"/><path d="M397.3006,228.92c0,1.8-.0751,3.6-.15,5.4A32.74,32.74,0,0,0,377.8,228.0944H367c-88.9508,0-111-52.6484-111-52.6484S233.95,228.0944,145,228.0944H134.2a32.7421,32.7421,0,0,0-19.3506,6.2255c-.0741-1.8-.1492-3.6-.1492-5.4a141.3,141.3,0,1,1,282.6,0Z" style="fill:#521919"/><path d="M314.9628,217.4a48.7166,48.7166,0,0,0-41.24,22.8735H238.2778a49.0111,49.0111,0,1,0,6.243,15h22.9586A48.729,48.729,0,1,0,314.9628,217.4Z" style="fill:#eb5e59"/><circle cx="314.9628" cy="266.1503" r="33.75" style="fill:#0d263e"/><circle cx="305.1319" cy="256.3194" r="11.25" style="fill:#ffefdc"/><circle cx="197.0374" cy="266.1503" r="33.75" style="fill:#0d263e"/><circle cx="187.2065" cy="256.3194" r="11.25" style="fill:#ffefdc"/><rect height="45" rx="15" style="fill:#ef9e8b" width="30" x="241.0004" y="275.8593"/></g></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_mongolian_skin_07"><path d="M272.69,388.6944a22.4994,22.4994,0,0,1-18.75,10.0489h0a22.4151,22.4151,0,0,1-18.8233-10.1258h0A22.388,22.388,0,0,1,215.6164,398.67H215.54a22.5694,22.5694,0,0,1-19.9475-13.9526h0a22.5173,22.5173,0,0,1-23.9246,4.801h0a22.4982,22.4982,0,0,1-14.2529-19.801h0a22.5027,22.5027,0,0,1-24.1479-3.3H133.19a22.5472,22.5472,0,0,1-6.8995-23.3972h0a22.5475,22.5475,0,0,1-21.676-11.1035h0a22.5568,22.5568,0,0,1,1.1279-24.375h0A22.58,22.58,0,0,1,88.8671,289.92h0a22.5564,22.5564,0,0,1,8.6976-22.2766h0a22.5286,22.5286,0,0,1-10.8729-20.2478h0A22.4669,22.4669,0,0,1,99.967,227.818h0a22.4612,22.4612,0,0,1-6.0022-22.9505h0a22.4853,22.4853,0,0,1,17.7759-15.5969h0a22.4862,22.4862,0,0,1,0-23.7012h0a22.4856,22.4856,0,0,1,21.1487-10.5761h0a22.5156,22.5156,0,0,1,6.0022-22.8736h0a22.3269,22.3269,0,0,1,23.1-4.9512h0a22.46,22.46,0,0,1,11.55-20.6982h0a22.33,22.33,0,0,1,23.6243,1.1243h0a22.4492,22.4492,0,0,1,16.4246-17.1021h0v-.0732h0a22.4833,22.4833,0,0,1,22.5732,7.0495h0a22.6612,22.6612,0,0,1,20.1746-12.3742h0A22.5227,22.5227,0,0,1,276.44,97.5421h0a22.5983,22.5983,0,0,1,22.65-6.8994h0a22.5614,22.5614,0,0,1,16.3513,17.1753h0a22.331,22.331,0,0,1,23.6243-.9742h0A22.4808,22.4808,0,0,1,350.54,127.5421h0A22.6811,22.6811,0,0,1,373.64,132.57h0a22.4584,22.4584,0,0,1,5.852,22.95h0A22.6182,22.6182,0,0,1,400.6408,166.17h0a22.6357,22.6357,0,0,1-.15,23.6975h0a22.5969,22.5969,0,0,1,17.7759,15.6775h0a22.4673,22.4673,0,0,1-6.1524,22.8735h0a22.558,22.558,0,0,1,13.2019,19.6509h0a22.4543,22.4543,0,0,1-10.95,20.1746h0a22.5523,22.5523,0,0,1,8.551,22.35h0a22.3882,22.3882,0,0,1-16.875,17.6258h0a22.55,22.55,0,0,1,.9742,24.375h0a22.4688,22.4688,0,0,1-21.7493,10.95h0a22.461,22.461,0,0,1-7.1265,23.324h0a22.3659,22.3659,0,0,1-24.1516,3.2263h0a22.4647,22.4647,0,0,1-14.3225,19.7241h0a22.5,22.5,0,0,1-23.9246-4.9512h0A22.5214,22.5214,0,0,1,295.6408,398.67h-2.0251c-.7508.0733-1.5015.0733-2.1753.0733h0A22.3058,22.3058,0,0,1,272.69,388.6944Z" style="fill:#0d263e"/><path d="M304.8653,473.543H207.134a11.2273,11.2273,0,0,1-10.7953-14.3116l18.14-63.4906a37.5,37.5,0,0,1,36.0569-27.1978h10.9278a37.5,37.5,0,0,1,36.0569,27.1978l18.14,63.4906A11.2272,11.2272,0,0,1,304.8653,473.543Z" style="fill:#3285e2"/><rect height="262.2152" rx="112.4698" style="fill:#f8c497" width="224.9398" x="143.53" y="130.7735"/><path d="M255.9968,358.7994a37.2335,37.2335,0,0,1-26.5136-10.9864,7.4992,7.4992,0,1,1,10.6054-10.6054c8.4961,8.5,23.313,8.5107,31.8238-.0037a7.5018,7.5018,0,0,1,10.6054,10.6128A37.285,37.285,0,0,1,255.9968,358.7994Z" style="fill:#f7725c"/><rect height="45" rx="15" style="fill:#ef9e72" width="30" x="241" y="275.8604"/><path d="M336.1745,244.94a7.4973,7.4973,0,0,0-10.6055,0l-2.3378,2.3383a20.6845,20.6845,0,1,0,10.605,10.6055l2.3383-2.3383A7.4975,7.4975,0,0,0,336.1745,244.94Z" style="fill:#0d253d"/><circle cx="319.5725" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M197.0363,245.5264a20.5225,20.5225,0,0,0-8.2682,1.7505l-2.3373-2.3365a7.4992,7.4992,0,0,0-10.6055,10.6055l2.3374,2.3364a20.6122,20.6122,0,1,0,18.8736-12.3559Z" style="fill:#0d253d"/><circle cx="201.647" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M373.487,180.7714a129.6465,129.6465,0,0,0-24.375-33.825,131.7315,131.7315,0,0,0-186.2247,0,132.6171,132.6171,0,0,0-38.55,93.1494v43.5754a131.6732,131.6732,0,0,0,5.7752,38.7012,30.032,30.032,0,0,0,24.2248-29.4013,30.3123,30.3123,0,0,0-5.625-17.4737,29.6345,29.6345,0,0,0,13.4253-18.0762,30.0918,30.0918,0,0,0-2.1753-20.7,29.59,29.59,0,0,0,13.575-11.325,30.0216,30.0216,0,0,0,40.35-6.0755A29.9589,29.9589,0,0,0,256,217.7716a29.9589,29.9589,0,0,0,42.1124,1.549,30.0214,30.0214,0,0,0,40.35,6.0755,29.5911,29.5911,0,0,0,13.575,11.325,30.0929,30.0929,0,0,0-2.1753,20.7,29.6353,29.6353,0,0,0,13.4253,18.0762,30.3123,30.3123,0,0,0-5.625,17.4737,30.0322,30.0322,0,0,0,24.2249,29.4013,131.6732,131.6732,0,0,0,5.7751-38.7012V240.0958A130.3512,130.3512,0,0,0,373.487,180.7714Z" style="fill:#0d263e"/></g></svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_caucasian_skin_11"><rect height="194.1704" style="fill:#cab8d8" width="239.7127" x="136.2875" y="219.8376"/><path d="M287.4864,352.0415H224.5123a36.0118,36.0118,0,0,0-36.0118,36.0118v74.272a11.2177,11.2177,0,0,0,11.2177,11.2177H312.2818A11.2177,11.2177,0,0,0,323.5,462.3253V388.0547A36.0132,36.0132,0,0,0,287.4864,352.0415Z" style="fill:#f4e2ff"/><rect height="277.5" rx="104.9999" style="fill:#f8c4b0" width="210" x="151" y="114.8395"/><path d="M277.3674,376.1274H234.6328a8.6154,8.6154,0,0,0-5.9871,14.8106l21.3673,20.65a8.6156,8.6156,0,0,0,11.9742,0l21.3673-20.65A8.6154,8.6154,0,0,0,277.3674,376.1274Z" style="fill:#0d263e"/><path d="M255.9994,358.1512a37.2338,37.2338,0,0,1-26.5136-10.9863,7.4992,7.4992,0,1,1,10.6054-10.6055c8.4961,8.5034,23.32,8.5034,31.8164,0a7.4992,7.4992,0,1,1,10.6055,10.6055A37.2338,37.2338,0,0,1,255.9994,358.1512Z" style="fill:#ff8080"/><rect height="68.3763" rx="22.7921" style="fill:#ef9e8b" width="45.5842" x="233.208" y="263.5237"/><circle cx="314.9628" cy="250.5027" r="20.625" style="fill:#521919"/><circle cx="319.5735" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><circle cx="197.0372" cy="250.5027" r="20.625" style="fill:#521919"/><circle cx="201.6479" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><polygon points="398.212 414.008 343.088 444.008 343.088 212.338 375.712 212.338 398.212 414.008" style="fill:#f4e2ff"/><polygon points="168.912 444.008 113.788 414.008 136.288 212.338 168.912 212.338 168.912 444.008" style="fill:#f4e2ff"/><path d="M256,69.8376a120,120,0,0,0-120,120H376A120.0007,120.0007,0,0,0,256,69.8376Z" style="fill:#f4e2ff"/><rect height="37.5" rx="18.75" style="fill:#0d263e" width="276.9249" x="117.5375" y="182.3376"/></g></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_caucasian_skin_11"><path d="M339.0217,473.543a11.2647,11.2647,0,0,0,11.2647-11.2647V399.3391a40.5458,40.5458,0,0,0-40.5-40.5675H202.2146a40.5463,40.5463,0,0,0-40.5,40.5675v62.9392a11.2646,11.2646,0,0,0,11.2646,11.2647Z" style="fill:#0d263e"/><rect height="262.2149" rx="112.4697" style="fill:#f8c4b0" width="224.9396" x="143.5309" y="130.7745"/><path d="M255.9972,358.7981a37.2428,37.2428,0,0,1-26.5137-10.9826A7.4992,7.4992,0,0,1,240.089,337.21c8.5034,8.5034,23.3349,8.4888,31.8237,0a7.4992,7.4992,0,0,1,10.6055,10.6055A37.26,37.26,0,0,1,255.9972,358.7981Z" style="fill:#ff4d4d"/><rect height="45" rx="15" style="fill:#ef9e8b" width="30" x="241.0008" y="275.8613"/><path d="M336.1752,244.9413a7.4972,7.4972,0,0,0-10.6054,0L323.232,247.28a20.6845,20.6845,0,1,0,10.605,10.6055l2.3382-2.3383A7.4973,7.4973,0,0,0,336.1752,244.9413Z" style="fill:#004b28"/><circle cx="319.5733" cy="258.4677" r="7.6845" style="fill:#ffefdc"/><path d="M197.037,245.5273a20.5221,20.5221,0,0,0-8.2681,1.7505l-2.3373-2.3365a7.4992,7.4992,0,0,0-10.6055,10.6055l2.3373,2.3364a20.6122,20.6122,0,1,0,18.8736-12.3559Z" style="fill:#004b28"/><circle cx="201.6477" cy="258.4677" r="7.6845" style="fill:#ffefdc"/><path d="M144.6154,227.9891H367.3861a112.3741,112.3741,0,0,0-222.7707,0Z" style="fill:#330f0f"/><path d="M250.798,108.374c-73.0394,2.7612-129.7651,65.0954-129.765,138.1869V387.09a59.9366,59.9366,0,0,0,37.4158,55.636c28.4962,11.4867,61.8626,18.1,97.5512,18.1s69.055-6.6136,97.5512-18.1A59.9365,59.9365,0,0,0,390.967,387.09V243.2425C390.967,167.0932,327.581,105.4714,250.798,108.374ZM360.967,280.5191a104.967,104.967,0,1,1-209.934,0V243.2425a104.967,104.967,0,1,1,209.934,0Z" style="fill:#521919"/></g></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_caucasian_skin_06"><path d="M188.3991,459.2315A11.2274,11.2274,0,0,0,199.195,473.543h97.7307a11.2274,11.2274,0,0,0,10.7959-14.3115L304.1327,446.67H191.988Z" style="fill:#f8c4b0"/><polygon points="205.274 400.169 191.988 446.67 304.133 446.67 290.847 400.169 205.274 400.169" style="fill:#eb5e59"/><path d="M289.5814,395.7415a37.5005,37.5005,0,0,0-36.0572-27.1985H242.5965a37.5,37.5,0,0,0-36.0571,27.1985l-1.2653,4.4275h85.5725Z" style="fill:#f8c4b0"/><path d="M248.06,130.9014a112.4036,112.4036,0,0,0-111.3163,97.2143H126.1478a33.7514,33.7514,0,1,0,0,67.5028h10.5533A112.4114,112.4114,0,0,0,360.53,280.6459V243.37A112.469,112.469,0,0,0,248.06,130.9014Z" style="fill:#f8c4b0"/><path d="M248.0576,358.9263A37.2337,37.2337,0,0,1,221.5439,347.94a7.4992,7.4992,0,1,1,10.6055-10.6054c8.4888,8.5,23.3057,8.5107,31.8237-.0037a7.5018,7.5018,0,0,1,10.6055,10.6128A37.285,37.285,0,0,1,248.0576,358.9263Z" style="fill:#ff4d4d"/><rect height="45" rx="15" style="fill:#ef9e8b" width="30" x="233.0605" y="275.9877"/><path d="M328.2349,245.0677a7.4973,7.4973,0,0,0-10.6055,0l-2.3378,2.3382a20.684,20.684,0,1,0,10.6051,10.6055l2.3382-2.3382A7.4973,7.4973,0,0,0,328.2349,245.0677Z" style="fill:#004b28"/><circle cx="311.6329" cy="258.5941" r="7.6845" style="fill:#ffefdc"/><path d="M189.0967,245.6536a20.5237,20.5237,0,0,0-8.2681,1.75l-2.3373-2.3364a7.4992,7.4992,0,0,0-10.6055,10.6055l2.3373,2.3364a20.6122,20.6122,0,1,0,18.8736-12.356Z" style="fill:#004b28"/><circle cx="193.7074" cy="258.5941" r="7.6845" style="fill:#ffefdc"/><path d="M123.4761,241.7911h13.4986v40.1513H123.4761a20.2465,20.2465,0,0,1,0-40.1513Z" style="fill:#ef9e8b"/><path d="M344.1139,398.1914s166.9576-190.4709,4.4254-273.3332c-29.2218-92.35-182.8508-62.9887-223-.4355-25.7,40.0418-20.2694,82.53-8.0654,104.9638a33.2954,33.2954,0,0,1,8.6737-1.2708h10.4682s17.3272-14.0954,68.71-14.0954,91.6022-29.7363,91.6022-29.7363h.0009c0,.0055-1.0016,32.5488,18.6264,64.4311,22.6108,36.731,34.7287,78.9368,30.9695,121.9043Z" style="fill:#521919"/></g></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Female_mongolian_skin_03"><path d="M360.7865,353.4027l-.0942.0239a41.4194,41.4194,0,1,0-77.241,19.2989c21.2646,36.8313,73.3884,64.0284,119.5789,32.04C403.03,404.7655,358.55,391.8892,360.7865,353.4027Z" style="fill:#330f0f"/><path d="M304.8659,473.543H207.1345a11.2273,11.2273,0,0,1-10.7953-14.3116l18.14-63.4906a37.5,37.5,0,0,1,36.0569-27.1978h10.9278a37.5,37.5,0,0,1,36.0569,27.1978l18.14,63.4906A11.2272,11.2272,0,0,1,304.8659,473.543Z" style="fill:#27b286"/><path d="M377.797,228.13H367.338A112.4052,112.4052,0,0,0,256,130.7732h0A112.4057,112.4057,0,0,0,144.6625,228.13h-10.459a33.7509,33.7509,0,1,0,0,67.5018h10.459A112.4048,112.4048,0,0,0,256,392.9885h0A112.4043,112.4043,0,0,0,367.338,295.6322h10.459a33.7509,33.7509,0,1,0,0-67.5018Z" style="fill:#f8c497"/><path d="M255.997,358.7981a37.2428,37.2428,0,0,1-26.5136-10.9826A7.4992,7.4992,0,1,1,240.0888,337.21c8.4961,8.4961,23.313,8.5,31.8238-.0037a7.5018,7.5018,0,0,1,10.6054,10.6128A37.2964,37.2964,0,0,1,255.997,358.7981Z" style="fill:#f7725c"/><rect height="45" rx="15" style="fill:#ef9e72" width="30" x="241.0002" y="275.8604"/><path d="M380.4684,241.8049H366.97v40.1513h13.4985a20.2464,20.2464,0,0,0,0-40.1513Z" style="fill:#ef9e72"/><path d="M336.1746,244.94a7.4972,7.4972,0,0,0-10.6054,0l-2.3378,2.3383a20.6845,20.6845,0,1,0,10.605,10.6055l2.3382-2.3383A7.4973,7.4973,0,0,0,336.1746,244.94Z" style="fill:#521919"/><circle cx="319.5727" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M197.0365,245.5264a20.5225,20.5225,0,0,0-8.2682,1.7505L186.431,244.94a7.4992,7.4992,0,0,0-10.6055,10.6055l2.3374,2.3364a20.6122,20.6122,0,1,0,18.8736-12.3559Z" style="fill:#521919"/><circle cx="201.6471" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M131.5318,241.8049H145.03v40.1513H131.5318a20.2464,20.2464,0,0,1,0-40.1513Z" style="fill:#ef9e72"/><path d="M389.9845,213.2586a133.9847,133.9847,0,1,0-267.9693,0c0,118.006,44.957,179.729,44.957,179.729V227.9437c62.4792,0,89.0222-47.9938,89.0277-48.003.0055.0092,26.5484,48.003,89.0277,48.003V392.9876S389.9845,331.2646,389.9845,213.2586Z" style="fill:#521919"/></g></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_caucasian_skin_01"><path d="M317.1627,404.168l-7.4254,59.55a11.1993,11.1993,0,0,1-11.1749,9.8254H213.4376a11.1993,11.1993,0,0,1-11.1749-9.8254l-7.4254-59.55a45.0062,45.0062,0,0,1,44.6251-50.625h33.0752A45.0061,45.0061,0,0,1,317.1627,404.168Z" style="fill:#f4e2ff"/><polygon points="278.762 441.067 256.038 463.194 233.238 440.394 251.313 353.543 261.137 353.543 278.762 441.067" style="fill:#243f57"/><rect height="79.1689" style="fill:#ffb019" width="25.2644" x="128.0211" y="182.8503"/><path d="M371.8266,219.86H361v.0018a105,105,0,0,0-210,0V219.86H140.1734a33.7519,33.7519,0,1,0,0,67.5037H151v-.0019a105,105,0,0,0,210,0v.0019h10.8266a33.7519,33.7519,0,1,0,0-67.5037Z" style="fill:#f8c4b0"/><path d="M256.0023,358.1719a37.2968,37.2968,0,0,1-26.521-10.979A7.5018,7.5018,0,1,1,240.0868,336.58c8.5107,8.5034,23.3276,8.5,31.8237.0036a7.4992,7.4992,0,0,1,10.6055,10.6055A37.2433,37.2433,0,0,1,256.0023,358.1719Z" style="fill:#ff8080"/><rect height="90" rx="30" style="fill:#ef9e8b" width="60" x="226" y="245.2344"/><path d="M374.4984,233.5353H361v40.1513h13.4985a20.2464,20.2464,0,0,0,0-40.1513Z" style="fill:#ef9e8b"/><circle cx="314.9628" cy="250.5253" r="20.625" style="fill:#0167a3"/><circle cx="319.5735" cy="242.8408" r="7.6845" style="fill:#ffefdc"/><circle cx="197.0372" cy="250.5253" r="20.625" style="fill:#0167a3"/><circle cx="201.6479" cy="242.8408" r="7.6845" style="fill:#ffefdc"/><path d="M137.5015,233.5353H151v40.1513H137.5015a20.2464,20.2464,0,0,1,0-40.1513Z" style="fill:#ef9e8b"/><path d="M361,219.861h10.8266a33.4654,33.4654,0,0,1,12.1522,2.351V169.5948a45.959,45.959,0,0,0-45.9576-45.9594A38.7743,38.7743,0,0,0,299.2448,84.861H151.3981a38.3771,38.3771,0,0,0-38.377,38.3752V158.982a38.378,38.378,0,0,0,38.377,38.379h164.123a22.5005,22.5005,0,0,0,22.5,22.5Z" style="fill:#ffc139"/></g></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient gradientTransform="translate(2624.1916 269.5948) rotate(-30)" gradientUnits="userSpaceOnUse" id="linear-gradient" x1="-2061.0241" x2="-1990.8651" y1="-1115.213" y2="-993.6939"><stop offset="0" stop-color="#5b1b1b"/><stop offset="1" stop-color="#491616"/></linearGradient></defs><g id="Female_caucasian_skin_10"><path d="M360.7867,353.4027l-.0942.0239a41.4194,41.4194,0,1,0-77.241,19.2989c21.2646,36.8313,73.3884,64.0284,119.5789,32.04C403.03,404.7655,358.55,391.8892,360.7867,353.4027Z" style="fill:url(#linear-gradient)"/><path d="M214.4794,395.74l-18.14,63.49a11.2288,11.2288,0,0,0,10.7959,14.3134h26.4221V372.6555A37.44,37.44,0,0,0,214.4794,395.74Z" style="fill:#ffc139"/><path d="M261.4643,368.543H250.5366a37.3725,37.3725,0,0,0-16.9794,4.1125V473.543h44.8883V372.6555A37.38,37.38,0,0,0,261.4643,368.543Z" style="fill:#0d263e"/><path d="M315.6617,459.23l-18.14-63.49a37.4465,37.4465,0,0,0-19.0759-23.0841V473.543h26.4276A11.23,11.23,0,0,0,315.6617,459.23Z" style="fill:#ffc139"/><path d="M377.7967,228.13h-10.459a112.4041,112.4041,0,0,0-111.3372-97.3562h0A112.4041,112.4041,0,0,0,144.6632,228.13h-10.459a33.7514,33.7514,0,1,0,0,67.5028h10.459a112.4049,112.4049,0,0,0,111.3373,97.3562h0a112.4049,112.4049,0,0,0,111.3372-97.3562h10.459a33.7514,33.7514,0,1,0,0-67.5028Z" style="fill:#f8c4b0"/><path d="M256.0023,358.7994a37.285,37.285,0,0,1-26.521-10.9827,7.5018,7.5018,0,0,1,10.6055-10.6128c8.518,8.5144,23.3349,8.5034,31.8237.0037A7.4992,7.4992,0,1,1,282.516,347.813,37.2337,37.2337,0,0,1,256.0023,358.7994Z" style="fill:#ff4d4d"/><rect height="45" rx="15" style="fill:#ef9e8b" width="30" x="241.0004" y="275.8604"/><path d="M380.4686,241.8049H366.97v40.1513h13.4985a20.2464,20.2464,0,0,0,0-40.1513Z" style="fill:#ef9e8b"/><path d="M336.1749,244.94a7.4973,7.4973,0,0,0-10.6055,0l-2.3378,2.3383a20.6845,20.6845,0,1,0,10.605,10.6055l2.3383-2.3383A7.4973,7.4973,0,0,0,336.1749,244.94Z" style="fill:#004b28"/><circle cx="319.5729" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M197.0367,245.5264a20.5217,20.5217,0,0,0-8.2681,1.7505l-2.3374-2.3365a7.4992,7.4992,0,0,0-10.6055,10.6055l2.3374,2.3364a20.6122,20.6122,0,1,0,18.8736-12.3559Z" style="fill:#004b28"/><circle cx="201.6474" cy="258.4668" r="7.6845" style="fill:#ffefdc"/><path d="M131.532,241.8049h13.4985v40.1513H131.532a20.2464,20.2464,0,0,1,0-40.1513Z" style="fill:#ef9e8b"/><path d="M367.4637,228.13h10.3327a33.4982,33.4982,0,0,1,12.1893,2.3639V213.2582a133.9856,133.9856,0,0,0-267.9712,0v17.2357a33.5019,33.5019,0,0,1,12.1893-2.3639H145.03c88.9472,0,110.9693-52.6575,110.9693-52.6575s22.0221,52.6575,110.97,52.6575h.4944Z" style="fill:#521919"/></g></svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_malayan_skin_07"><path d="M390.19,334.5654a42.122,42.122,0,0,1-26.1058-31.2689L361,287.3407H151l-3.084,15.9558A42.122,42.122,0,0,1,121.81,334.5654l-16.93,6.5753S131.9641,399.533,256,399.533,407.12,341.1407,407.12,341.1407Z" style="fill:#0d253d"/><path d="M353.1009,464.5487V412.8422a60.7992,60.7992,0,0,0-60.7992-60.7992H219.6975a60.7987,60.7987,0,0,0-60.7986,60.7987v51.707a8.9943,8.9943,0,0,0,8.9943,8.9943H344.1066A8.9943,8.9943,0,0,0,353.1009,464.5487Z" style="fill:#8ca4bc"/><path d="M371.8268,219.837H361a105,105,0,0,0-210,.0018v-.0018H140.1732a33.7518,33.7518,0,1,0,0,67.5036H151V287.34a105,105,0,0,0,210,.0009h10.827a33.7518,33.7518,0,1,0,0-67.5036Z" style="fill:#d87761"/><path d="M269.0715,317.668h-93.89A46.8586,46.8586,0,0,0,256,350.0429a46.8586,46.8586,0,0,0,80.8186-32.3749Z" style="fill:#0d253d"/><rect height="68.3763" rx="22.7921" style="fill:#bf5e48" width="45.5842" x="233.2077" y="263.5237"/><path d="M374.4984,233.5127H361v40.1514h13.4985a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#bf5e48"/><circle cx="314.9626" cy="250.5027" r="20.625" style="fill:#0d253d"/><circle cx="319.5733" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><circle cx="197.0371" cy="250.5027" r="20.625" style="fill:#0d253d"/><circle cx="201.6478" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><path d="M137.5015,233.5127H151v40.1514H137.5015a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#bf5e48"/><path d="M361,219.8377a105,105,0,0,0-210,0c22.3892-84.0876,105-50.9125,105-50.9125S338.6105,135.75,361,219.8377Z" style="fill:#0d263e"/></g></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g id="Male_malayan_skin_03"><path d="M272.53,353.543H239.4691a44.9506,44.9506,0,0,0-11.22,1.4612V473.543h55.5V355.0042A44.9449,44.9449,0,0,0,272.53,353.543Z" style="fill:#f4e2ff"/><polygon points="278.762 441.067 256.037 463.194 233.238 440.394 251.312 353.543 261.137 353.543 278.762 441.067" style="fill:#8ca4bc"/><path d="M309.73,463.6992l7.4478-59.5825A44.977,44.977,0,0,0,283.75,355.0042V473.543h14.8316A11.237,11.237,0,0,0,309.73,463.6992Z" style="fill:#243f57"/><path d="M194.8216,404.1167l7.4478,59.5825a11.2363,11.2363,0,0,0,11.1484,9.8438h14.8316V355.0042A44.9767,44.9767,0,0,0,194.8216,404.1167Z" style="fill:#243f57"/><path d="M371.8266,219.8376H361v.0018a105,105,0,0,0-210,0v-.0018H140.173a33.7514,33.7514,0,1,0,0,67.5027H151v-.0009a105,105,0,1,0,210,0v.0009h10.8266a33.7514,33.7514,0,1,0,0-67.5027Z" style="fill:#d87761"/><path d="M256,358.15a37.243,37.243,0,0,1-26.5137-10.9826,7.4992,7.4992,0,0,1,10.6055-10.6055c8.4961,8.4961,23.32,8.4961,31.8164,0a7.4992,7.4992,0,1,1,10.6055,10.6055A37.243,37.243,0,0,1,256,358.15Z" style="fill:#8c1813"/><path d="M151,287.3394v41.5833a105,105,0,0,0,105,105h0a105,105,0,0,0,105-105V287.3394Zm118.5864,86.4533H243.9551c-14.7812,0-28.0288-11.0706-28.8-25.8307A27.297,27.297,0,0,1,242.4129,319.2h26.4579c13.0274,0,24.8579,8.8366,27.4365,21.6064A27.3266,27.3266,0,0,1,269.5862,373.7927Z" style="fill:#0d263e"/><rect height="68.3763" rx="22.7921" style="fill:#bf5e48" width="45.5842" x="233.2079" y="263.5237"/><path d="M374.4983,233.5127H361v40.1514h13.4985a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#bf5e48"/><circle cx="314.9627" cy="250.5027" r="20.625" style="fill:#521919"/><circle cx="319.5734" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><circle cx="197.0372" cy="250.5027" r="20.625" style="fill:#521919"/><circle cx="201.6479" cy="242.8182" r="7.6845" style="fill:#ffefdc"/><path d="M137.5014,233.5127H151v40.1514H137.5014a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#bf5e48"/><path d="M392.0875,171.4883a88.8087,88.8087,0,0,1-14.85,48.825,32.7689,32.7689,0,0,0-5.4-.45h-10.875s-27.3-24.15-105-24.15c-77.6249,0-105,24.15-105,24.15h-10.8a31.4418,31.4418,0,0,0-5.4.45,88.8047,88.8047,0,0,1-14.85-48.825c0-59.3994,60.9-107.6258,136.05-107.6258C331.1876,63.8625,392.0875,112.0889,392.0875,171.4883Z" style="fill:#eb5e59"/></g></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient gradientUnits="userSpaceOnUse" id="linear-gradient" x1="256.0002" x2="256.0002" y1="263.5402" y2="331.9165"><stop offset="0.0131" stop-color="#f4a995"/><stop offset="1" stop-color="#ea9381"/></linearGradient></defs><g id="Male_caucasian_skin_04"><path d="M317.163,404.168l-7.4254,59.55a11.2645,11.2645,0,0,1-8.7748,9.5251,8.42,8.42,0,0,1-2.4.3H213.4379a9.31,9.31,0,0,1-2.4751-.3,11.0942,11.0942,0,0,1-8.7-9.5251l-7.4254-59.55a44.9345,44.9345,0,0,1,16.1252-40.426,45.6512,45.6512,0,0,1,19.05-9.2249,49.2072,49.2072,0,0,1,9.45-.9741h33.0752a49.3612,49.3612,0,0,1,9.5247.9741,45.116,45.116,0,0,1,35.1,49.6509Z" style="fill:#f4e2ff"/><path d="M300.9628,363.6669V473.543h-18.9V354.5171A44.9157,44.9157,0,0,1,300.9628,363.6669Z" style="fill:#521919"/><path d="M230.0126,354.5171V473.543h-19.05V363.742A45.6512,45.6512,0,0,1,230.0126,354.5171Z" style="fill:#521919"/><path d="M371.827,219.854H361.0005v.0018a104.9994,104.9994,0,0,0-105-105h0a104.9983,104.9983,0,0,0-105,104.9982H140.1734a33.7509,33.7509,0,1,0,0,67.5018h10.8271a105,105,0,0,0,105,105h0a105.0005,105.0005,0,0,0,105-105H371.827a33.7509,33.7509,0,1,0,0-67.5018Z" style="fill:#f8c4b0"/><path d="M256.002,307.1424a46.614,46.614,0,0,0-46.6143,46.6163,11.6537,11.6537,0,0,0,23.3073,0,11.6535,11.6535,0,0,0,23.307,0,11.6537,11.6537,0,0,0,23.3073,0,11.6535,11.6535,0,0,0,23.3069,0A46.6137,46.6137,0,0,0,256.002,307.1424Z" style="fill:#521919"/><path d="M374.4987,233.5288H361V273.68h13.4986a20.2465,20.2465,0,0,0,0-40.1514Z" style="fill:#ef9e8b"/><circle cx="314.963" cy="250.5188" r="20.625" style="fill:#521919"/><circle cx="319.5737" cy="242.8343" r="7.6845" style="fill:#ffefdc"/><circle cx="197.0375" cy="250.5188" r="20.625" style="fill:#521919"/><circle cx="201.6482" cy="242.8343" r="7.6845" style="fill:#ffefdc"/><path d="M137.5017,233.5288H151V273.68H137.5017a20.2465,20.2465,0,0,1,0-40.1514Z" style="fill:#ef9e8b"/><path d="M314.9631,201.77a48.7167,48.7167,0,0,0-41.24,22.8735H238.278a49.0111,49.0111,0,1,0,6.243,15H267.48A48.729,48.729,0,1,0,314.9631,201.77Zm-117.9255,82.5a33.75,33.75,0,1,1,33.75-33.75A33.787,33.787,0,0,1,197.0376,284.27Zm117.9255,0a33.75,33.75,0,1,1,33.75-33.75A33.7869,33.7869,0,0,1,314.9631,284.27Z" style="fill:#0d263e"/><rect height="68.3763" rx="22.7921" style="fill:url(#linear-gradient)" width="45.5842" x="233.2081" y="263.5402"/></g></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,42 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import React from 'react';
import { Tag } from 'antd';
import { BuildOutlined } from '@ant-design/icons';
export type AttachmentType = 'image' | 'uiSchema';
export type AttachmentProps = {
type: AttachmentType;
content: string;
};
export const Attachment: React.FC<
AttachmentProps & {
closeable?: boolean;
onClose?: () => void;
}
> = ({ type, content, closeable, onClose }) => {
let prefix: React.ReactNode;
switch (type) {
case 'uiSchema':
prefix = (
<>
<BuildOutlined /> UI Schema {'>'}{' '}
</>
);
break;
}
return (
<Tag closeIcon={closeable} onClose={onClose}>
{prefix}
{content}
</Tag>
);
};

View File

@ -0,0 +1,389 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import React, { useContext, useEffect, useState } from 'react';
import { Layout, Card, Divider, Button, Avatar, List, Input, Popover, Empty, Spin, Modal, Tag } from 'antd';
import { Conversations, Sender, Attachments, Bubble } from '@ant-design/x';
import type { ConversationsProps } from '@ant-design/x';
import {
CloseOutlined,
ExpandOutlined,
EditOutlined,
LayoutOutlined,
DeleteOutlined,
BuildOutlined,
} from '@ant-design/icons';
import { useAPIClient, useRequest, useToken } from '@nocobase/client';
import { useT } from '../../locale';
import { ChatBoxContext } from './ChatBoxProvider';
const { Header, Footer, Sider, Content } = Layout;
import { avatars } from '../avatars';
import { AIEmployee, AIEmployeesContext, useAIEmployeesContext } from '../AIEmployeesProvider';
import { css } from '@emotion/css';
import { ReactComponent as EmptyIcon } from '../empty-icon.svg';
import { Attachment } from './Attachment';
export const ChatBox: React.FC = () => {
const api = useAPIClient();
const {
send,
setOpen,
filterEmployee,
setFilterEmployee,
conversations: conversationsService,
currentConversation,
setCurrentConversation,
messages,
setMessages,
roles,
attachments,
setAttachments,
responseLoading,
senderRef,
} = useContext(ChatBoxContext);
const { loading: ConversationsLoading, data: conversationsRes } = conversationsService;
const {
aiEmployees,
service: { loading },
} = useAIEmployeesContext();
const t = useT();
const { token } = useToken();
const [showConversations, setShowConversations] = useState(true);
const aiEmployeesList = [{ username: 'all' } as AIEmployee, ...(aiEmployees || [])];
const conversations: ConversationsProps['items'] = (conversationsRes || []).map((conversation) => ({
key: conversation.sessionId,
label: conversation.title,
timestamp: new Date(conversation.updatedAt).getTime(),
}));
const deleteConversation = async (sessionId: string) => {
await api.resource('aiConversations').destroy({
filterByTk: sessionId,
});
conversationsService.refresh();
setCurrentConversation(undefined);
setMessages([]);
};
const getMessages = async (sessionId: string) => {
const res = await api.resource('aiConversations').getMessages({
sessionId,
});
const messages = res?.data?.data;
if (!messages) {
return;
}
setMessages(messages.reverse());
};
return (
<div
style={{
position: 'fixed',
right: '16px',
bottom: '16px',
width: '90%',
maxWidth: '760px',
height: '90%',
maxHeight: '560px',
zIndex: 1000,
}}
>
<Card style={{ height: '100%' }} bodyStyle={{ height: '100%', paddingTop: 0 }}>
<Layout style={{ height: '100%' }}>
<Sider
width="42px"
style={{
backgroundColor: token.colorBgContainer,
marginRight: '5px',
}}
>
<List
loading={loading}
dataSource={aiEmployeesList}
split={false}
itemLayout="horizontal"
renderItem={(aiEmployee) => {
const highlight =
aiEmployee.username === filterEmployee
? `color: ${token.colorPrimary};
border-color: ${token.colorPrimary};`
: '';
return aiEmployee.username === 'all' ? (
<Button
onClick={() => setFilterEmployee(aiEmployee.username)}
className={css`
width: 40px;
height: 40px;
line-height: 40px;
font-weight: ${token.fontWeightStrong};
margin-top: 10px;
margin-bottom: 8px;
${highlight}
`}
>
ALL
</Button>
) : (
<Popover
placement="bottomLeft"
content={
<div
style={{
width: '300px',
padding: '8px',
}}
>
<div
style={{
width: '100%',
textAlign: 'center',
}}
>
<Avatar
src={avatars(aiEmployee.avatar)}
size={60}
className={css``}
style={{
boxShadow: `0px 0px 2px ${token.colorBorder}`,
}}
/>
<div
style={{
fontSize: token.fontSizeLG,
fontWeight: token.fontWeightStrong,
margin: '8px 0',
}}
>
{aiEmployee.nickname}
</div>
</div>
<Divider
orientation="left"
plain
style={{
fontStyle: 'italic',
}}
>
{t('Bio')}
</Divider>
<p>{aiEmployee.bio}</p>
</div>
}
>
<Button
className={css`
width: 40px;
height: 40px;
line-height: 40px;
padding: 0;
${highlight}
`}
onClick={() => setFilterEmployee(aiEmployee.username)}
>
<Avatar src={avatars(aiEmployee.avatar)} shape="square" size={40} />
</Button>
</Popover>
);
}}
/>
</Sider>
<Sider
width="30%"
style={{
display: showConversations ? 'block' : 'none',
backgroundColor: token.colorBgContainer,
marginRight: '5px',
}}
>
<Layout>
<Header
style={{
backgroundColor: token.colorBgContainer,
height: '48px',
lineHeight: '48px',
padding: '0 5px',
}}
>
<Input.Search style={{ verticalAlign: 'middle' }} />
</Header>
<Content>
<Spin spinning={ConversationsLoading}>
{conversations && conversations.length ? (
<Conversations
activeKey={currentConversation}
onActiveChange={(sessionId) => {
if (sessionId === currentConversation) {
return;
}
setCurrentConversation(sessionId);
getMessages(sessionId);
}}
items={conversations}
menu={(conversation) => ({
items: [
{
label: 'Delete',
key: 'delete',
icon: <DeleteOutlined />,
},
],
onClick: ({ key }) => {
switch (key) {
case 'delete':
Modal.confirm({
title: t('Delete this conversation?'),
content: t('Are you sure to delete this conversation?'),
onOk: () => deleteConversation(conversation.key),
});
break;
}
},
})}
/>
) : (
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
)}
</Spin>
</Content>
</Layout>
</Sider>
<Layout>
<Header
style={{
backgroundColor: token.colorBgContainer,
height: '48px',
lineHeight: '48px',
padding: 0,
borderBottom: '1px solid #f0f0f0',
}}
>
<div
style={{
float: 'left',
}}
>
<Button
icon={<LayoutOutlined />}
type="text"
onClick={() => setShowConversations(!showConversations)}
/>
{filterEmployee !== 'all' ? (
<Button
icon={<EditOutlined />}
type="text"
onClick={() => {
setCurrentConversation(undefined);
setMessages([]);
senderRef.current?.focus({
cursor: 'start',
});
}}
/>
) : null}
</div>
<div
style={{
float: 'right',
}}
>
<Button icon={<ExpandOutlined />} type="text" />
<Button icon={<CloseOutlined />} type="text" onClick={() => setOpen(false)} />
</div>
</Header>
<Content
style={{
margin: '16px 0',
overflow: 'auto',
}}
>
{messages?.length ? (
<Bubble.List
style={{
marginRight: '8px',
}}
roles={roles}
items={messages}
/>
) : (
<div
style={{
width: '64px',
margin: '0 auto',
marginTop: '50%',
transform: 'translateY(-50%)',
}}
>
<EmptyIcon />
</div>
)}
</Content>
<Footer
style={{
backgroundColor: token.colorBgContainer,
padding: 0,
}}
>
<Sender
ref={senderRef}
onSubmit={(content) =>
send({
sessionId: currentConversation,
aiEmployee: { username: filterEmployee },
messages: [
{
type: 'text',
content,
},
],
})
}
header={
attachments.length ? (
<div
style={{
padding: '8px 8px 0',
}}
>
{attachments.map((attachment, index) => {
return (
<Attachment
key={index}
closeable={true}
onClose={() => {
setAttachments(attachments.filter((_, i) => i !== index));
}}
{...attachment}
/>
);
})}
</div>
) : null
}
disabled={filterEmployee === 'all' && !currentConversation}
placeholder={filterEmployee === 'all' && !currentConversation ? t('Please choose an AI employee.') : ''}
loading={responseLoading}
/>
</Footer>
{/* </Layout> */}
{/* <Sider */}
{/* width="25%" */}
{/* style={{ */}
{/* backgroundColor: token.colorBgContainer, */}
{/* }} */}
{/* > */}
{/* <Conversations items={employees} /> */}
{/* </Sider> */}
{/* </Layout> */}
</Layout>
</Layout>
</Card>
</div>
);
};

View File

@ -0,0 +1,352 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import React, { createContext, useContext, useEffect, useState, useRef } from 'react';
import { FloatButton, Avatar, Typography, GetProp, GetRef, Button } from 'antd';
import type { BubbleProps, Sender } from '@ant-design/x';
import { Bubble } from '@ant-design/x';
import { CurrentUserContext, useAPIClient, useLocalVariables, useRequest, useVariables } from '@nocobase/client';
import { ChatBox } from './ChatBox';
import icon from '../icon.svg';
import { css } from '@emotion/css';
import { AIEmployee, AIEmployeesContext } from '../AIEmployeesProvider';
import { avatars } from '../avatars';
import { uid } from '@formily/shared';
import { useT } from '../../locale';
import { Attachment, AttachmentProps, AttachmentType } from './Attachment';
const { Paragraph } = Typography;
type Conversation = {
sessionId: string;
title: string;
updatedAt: string;
};
type MessageType = 'text' | AttachmentType;
type Message = BubbleProps & { key?: string | number; role?: string };
type Action = {
content: string;
onClick: (content: string) => void;
};
type SendOptions = {
sessionId?: string;
greeting?: boolean;
aiEmployee?: AIEmployee;
messages: {
type: MessageType;
content: string;
}[];
};
const aiEmployeeRole = (aiEmployee: AIEmployee) => ({
placement: 'start',
avatar: aiEmployee.avatar ? <Avatar src={avatars(aiEmployee.avatar)} /> : null,
typing: { step: 5, interval: 20 },
style: {
maxWidth: 400,
marginInlineEnd: 48,
},
styles: {
footer: {
width: '100%',
},
},
variant: 'borderless',
messageRender: (msg: any) => {
switch (msg.type) {
case 'text':
return <Bubble content={msg.content} />;
case 'action':
return <Button onClick={msg.onClick}>{msg.content}</Button>;
}
},
});
export const ChatBoxContext = createContext<{
setOpen: (open: boolean) => void;
open: boolean;
filterEmployee: string;
setFilterEmployee: React.Dispatch<React.SetStateAction<string>>;
conversations: {
loading: boolean;
data?: Conversation[];
refresh: () => void;
};
currentConversation: string;
setCurrentConversation: React.Dispatch<React.SetStateAction<string | undefined>>;
messages: Message[];
setMessages: React.Dispatch<React.SetStateAction<Message[]>>;
roles: { [role: string]: any };
responseLoading: boolean;
attachments: AttachmentProps[];
setAttachments: React.Dispatch<React.SetStateAction<AttachmentProps[]>>;
actions: Action[];
setActions: React.Dispatch<React.SetStateAction<Action[]>>;
senderRef: React.MutableRefObject<GetRef<typeof Sender>>;
send(opts: SendOptions): void;
}>({} as any);
export const ChatBoxProvider: React.FC<{
children: React.ReactNode;
}> = (props) => {
const t = useT();
const api = useAPIClient();
const ctx = useContext(CurrentUserContext);
const { aiEmployees } = useContext(AIEmployeesContext);
const [openChatBox, setOpenChatBox] = useState(false);
const [messages, setMessages] = useState<Message[]>([]);
const [filterEmployee, setFilterEmployee] = useState('all');
const [currentConversation, setCurrentConversation] = useState<string>();
const [responseLoading, setResponseLoading] = useState(false);
const [attachments, setAttachments] = useState<AttachmentProps[]>([]);
const [actions, setActions] = useState<Action[]>([]);
const senderRef = useRef<GetRef<typeof Sender>>(null);
const [roles, setRoles] = useState<GetProp<typeof Bubble.List, 'roles'>>({
user: {
placement: 'end',
styles: {
content: {
maxWidth: '400px',
},
},
variant: 'borderless',
messageRender: (msg: any) => {
switch (msg.type) {
case 'text':
return <Bubble content={msg.content} />;
default:
return <Attachment {...msg} />;
}
},
},
});
const conversations = useRequest<Conversation[]>(
() =>
api
.resource('aiConversations')
.list({
sort: ['-updatedAt'],
...(filterEmployee !== 'all'
? {
filter: {
'aiEmployees.username': filterEmployee,
},
}
: {}),
})
.then((res) => res?.data?.data),
{
ready: openChatBox,
refreshDeps: [filterEmployee],
},
);
const send = async ({ sessionId, aiEmployee, messages: sendMsgs, greeting }: SendOptions) => {
setRoles((prev) => ({
...prev,
[aiEmployee.username]: aiEmployeeRole(aiEmployee),
}));
const msgs: Message[] = [];
if (greeting) {
msgs.push({
key: uid(),
role: aiEmployee.username,
content: {
type: 'text',
content: aiEmployee.greeting || t('Default greeting message', { nickname: aiEmployee.nickname }),
},
});
setMessages(msgs);
}
if (!sendMsgs.length) {
senderRef.current?.focus();
return;
}
if (attachments.length) {
msgs.push(
...attachments.map((attachment) => ({
key: uid(),
role: 'user',
content: attachment,
})),
);
setMessages(msgs);
}
msgs.push(...sendMsgs.map((msg) => ({ key: uid(), role: 'user', content: msg })));
setMessages(msgs);
if (!sessionId) {
const createRes = await api.resource('aiConversations').create({
values: {
aiEmployees: [aiEmployee],
},
});
const conversation = createRes?.data?.data;
if (!conversation) {
return;
}
sessionId = conversation.sessionId;
setCurrentConversation(conversation.sessionId);
conversations.refresh();
}
setAttachments([]);
setResponseLoading(true);
setMessages((prev) => [
...prev,
{
key: uid(),
role: aiEmployee.username,
content: {
type: 'text',
content: '',
},
loading: true,
},
]);
const sendRes = await api.request({
url: 'aiConversations:sendMessages',
method: 'POST',
headers: {
Accept: 'text/event-stream',
},
data: {
aiEmployee: aiEmployee.username,
sessionId,
messages: msgs,
},
responseType: 'stream',
adapter: 'fetch',
});
if (!sendRes?.data) {
setResponseLoading(false);
return;
}
const reader = sendRes.data.getReader();
const decoder = new TextDecoder();
let result = '';
// eslint-disable-next-line no-constant-condition
while (true) {
let content = '';
const { done, value } = await reader.read();
if (done) {
setResponseLoading(false);
break;
}
const chunk = decoder.decode(value, { stream: true });
const lines = chunk.split('\n').filter(Boolean);
for (const line of lines) {
const data = JSON.parse(line.replace(/^data: /, ''));
if (data.type === 'content' && data.body) {
content += data.body;
}
}
result += content;
setMessages((prev) => {
const last = prev[prev.length - 1];
// @ts-ignore
last.content.content = last.content.content + content;
last.loading = false;
return [...prev];
});
}
if (actions) {
setMessages((prev) => [
...prev,
...actions.map((action) => ({
key: uid(),
role: aiEmployee.username,
content: {
type: 'action',
content: action.content,
onClick: () => {
action.onClick(result);
},
},
})),
]);
setActions([]);
}
};
useEffect(() => {
if (!aiEmployees) {
return;
}
const roles = aiEmployees.reduce((prev, aiEmployee) => {
return {
...prev,
[aiEmployee.username]: aiEmployeeRole(aiEmployee),
};
}, {});
setRoles((prev) => ({
...prev,
...roles,
}));
}, [aiEmployees]);
if (!ctx?.data?.data) {
return <>{props.children}</>;
}
return (
<ChatBoxContext.Provider
value={{
open: openChatBox,
setOpen: setOpenChatBox,
filterEmployee,
setFilterEmployee,
conversations,
currentConversation,
setCurrentConversation,
messages,
setMessages,
roles,
responseLoading,
attachments,
setAttachments,
actions,
setActions,
senderRef,
send,
}}
>
{props.children}
{!openChatBox && (
<div
className={css`
.ant-float-btn {
width: 40px;
}
.ant-float-btn .ant-float-btn-body .ant-float-btn-content {
padding: 0;
}
.ant-float-btn .ant-float-btn-body .ant-float-btn-content .ant-float-btn-icon {
width: 40px;
}
`}
>
<FloatButton
icon={
<Avatar
src={icon}
size={40}
style={{
marginBottom: '4px',
}}
/>
}
onClick={() => {
setOpenChatBox(true);
}}
shape="square"
/>
</div>
)}
{openChatBox ? <ChatBox /> : null}
</ChatBoxContext.Provider>
);
};

View File

@ -0,0 +1 @@
<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="M339.021 473.543a11.265 11.265 0 0 0 11.265-11.265V399.34a40.546 40.546 0 0 0-40.5-40.567H202.214a40.546 40.546 0 0 0-40.5 40.567v62.94a11.265 11.265 0 0 0 11.265 11.264Z" fill="#f18b62" class="fill-071b2b"></path><rect height="262.215" rx="112.47" width="224.94" x="143.53" y="130.774" fill="#ffffff" class="fill-d87761"></rect><rect height="45" rx="15" width="30" x="241" y="275.861" fill="#ffffff" class="fill-bf5e48"></rect><path d="M336.175 244.941a7.497 7.497 0 0 0-10.606 0l-2.338 2.339a20.684 20.684 0 1 0 10.605 10.605l2.339-2.338a7.497 7.497 0 0 0 0-10.606Z" fill="#f18b62" class="fill-0d253d"></path><circle cx="319.573" cy="258.468" r="7.684" fill="#ffffff" class="fill-ffefdc"></circle><path d="M197.036 245.527a20.522 20.522 0 0 0-8.268 1.75l-2.337-2.336a7.5 7.5 0 0 0-10.606 10.606l2.338 2.336a20.612 20.612 0 1 0 18.873-12.356Z" fill="#f18b62" class="fill-0d253d"></path><circle cx="201.647" cy="258.468" r="7.684" fill="#ffffff" class="fill-ffefdc"></circle><path d="M144.615 227.99h222.77a112.374 112.374 0 0 0-222.77 0Z" fill="#f18b62" class="fill-071b2b"></path><path d="M250.797 108.374c-73.04 2.763-129.764 65.099-129.764 138.19V387.09a59.937 59.937 0 0 0 37.417 55.637c28.496 11.486 61.862 18.1 97.55 18.1s69.054-6.613 97.55-18.1a59.937 59.937 0 0 0 37.417-55.637V243.242c0-76.15-63.387-137.772-140.17-134.868Zm-99.764 134.869a105.08 105.08 0 0 1 110.25-104.837c56.386 2.776 99.684 51.42 99.684 107.875v34.379a13.88 13.88 0 0 1-14.007 13.618H165.04a13.88 13.88 0 0 1-14.007-13.619v-.14Z" fill="#f18b62" class="fill-0d253d"></path></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1 @@
<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="M339.021 473.543a11.265 11.265 0 0 0 11.265-11.265V399.34a40.546 40.546 0 0 0-40.5-40.567H202.214a40.546 40.546 0 0 0-40.5 40.567v62.94a11.265 11.265 0 0 0 11.265 11.264Z" fill="#d9d9d9" class="fill-071b2b"></path><rect height="262.215" rx="112.47" width="224.94" x="143.53" y="130.774" fill="#ffffff" class="fill-d87761"></rect><rect height="45" rx="15" width="30" x="241" y="275.861" fill="#d9d9d9" class="fill-bf5e48"></rect><path d="M336.175 244.941a7.497 7.497 0 0 0-10.606 0l-2.338 2.339a20.684 20.684 0 1 0 10.605 10.605l2.339-2.338a7.497 7.497 0 0 0 0-10.606Z" fill="#d9d9d9" class="fill-0d253d"></path><circle cx="319.573" cy="258.468" r="7.684" fill="#ffffff" class="fill-ffefdc"></circle><path d="M197.036 245.527a20.522 20.522 0 0 0-8.268 1.75l-2.337-2.336a7.5 7.5 0 0 0-10.606 10.606l2.338 2.336a20.612 20.612 0 1 0 18.873-12.356Z" fill="#d9d9d9" class="fill-0d253d"></path><circle cx="201.647" cy="258.468" r="7.684" fill="#ffffff" class="fill-ffefdc"></circle><path d="M144.615 227.99h222.77a112.374 112.374 0 0 0-222.77 0Z" fill="#d9d9d9" class="fill-071b2b"></path><path d="M250.797 108.374c-73.04 2.763-129.764 65.099-129.764 138.19V387.09a59.937 59.937 0 0 0 37.417 55.637c28.496 11.486 61.862 18.1 97.55 18.1s69.054-6.613 97.55-18.1a59.937 59.937 0 0 0 37.417-55.637V243.242c0-76.15-63.387-137.772-140.17-134.868Zm-99.764 134.869a105.08 105.08 0 0 1 110.25-104.837c56.386 2.776 99.684 51.42 99.684 107.875v34.379a13.88 13.88 0 0 1-14.007 13.618H165.04a13.88 13.88 0 0 1-14.007-13.619v-.14Z" fill="#d9d9d9" class="fill-0d253d"></path></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" ?><svg id="Female_malayan_skin_07" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="M339.0214,473.543a11.2647,11.2647,0,0,0,11.2647-11.2647V399.3391a40.5458,40.5458,0,0,0-40.5-40.5675H202.2143a40.5463,40.5463,0,0,0-40.5,40.5675v62.9392a11.2646,11.2646,0,0,0,11.2646,11.2647Z" style="fill:#071b2b"/><rect height="262.2149" rx="112.4697" style="fill:#d87761" width="224.9396" x="143.5303" y="130.7745"/><rect height="45" rx="15" style="fill:#bf5e48" width="30" x="241.0002" y="275.8613"/><path d="M336.1746,244.9413a7.4973,7.4973,0,0,0-10.6055,0l-2.3378,2.3383a20.684,20.684,0,1,0,10.6051,10.6055l2.3382-2.3383A7.4973,7.4973,0,0,0,336.1746,244.9413Z" style="fill:#0d253d"/><circle cx="319.5726" cy="258.4677" r="7.6845" style="fill:#ffefdc"/><path d="M197.0364,245.5273a20.5221,20.5221,0,0,0-8.2681,1.7505l-2.3373-2.3365a7.4992,7.4992,0,0,0-10.6055,10.6055l2.3373,2.3364a20.6122,20.6122,0,1,0,18.8736-12.3559Z" style="fill:#0d253d"/><circle cx="201.6471" cy="258.4677" r="7.6845" style="fill:#ffefdc"/><path d="M144.6148,227.9891H367.3855a112.3741,112.3741,0,0,0-222.7707,0Z" style="fill:#071b2b"/><path d="M250.7971,108.3744c-73.0395,2.763-129.7642,65.0982-129.7642,138.19V387.09A59.937,59.937,0,0,0,158.45,442.7272c28.4956,11.4861,61.8617,18.1,97.5505,18.1s69.0531-6.6135,97.5494-18.0993A59.9374,59.9374,0,0,0,390.9671,387.09l0-143.8479C390.967,167.0923,327.58,105.47,250.7971,108.3744ZM151.0329,243.2425A105.08,105.08,0,0,1,261.2824,138.4057c56.3862,2.7763,99.6847,51.4206,99.6846,107.8751v34.2383l0,.1409A13.88,13.88,0,0,1,346.96,294.2777H165.04a13.88,13.88,0,0,1-14.0071-13.6184l0-.14Z" style="fill:#0d253d"/></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,167 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import React, { useContext } from 'react';
import { Avatar, Tag, Popover, Divider, Button } from 'antd';
import { avatars } from '../avatars';
import { ChatBoxContext } from '../chatbox/ChatBoxProvider';
import { AIEmployee } from '../AIEmployeesProvider';
import {
SortableItem,
useBlockContext,
useLocalVariables,
useSchemaToolbarRender,
useToken,
useVariables,
} from '@nocobase/client';
import { useFieldSchema } from '@formily/react';
import { useT } from '../../locale';
import { css } from '@emotion/css';
import { useForm } from '@formily/react';
export const AIEmployeeButton: React.FC<{
aiEmployee: AIEmployee;
extraInfo?: string;
}> = ({ aiEmployee, extraInfo }) => {
const t = useT();
const { setOpen, send, setAttachments, setFilterEmployee, setCurrentConversation, setActions } =
useContext(ChatBoxContext);
const { token } = useToken();
const fieldSchema = useFieldSchema();
const { render } = useSchemaToolbarRender(fieldSchema);
const variables = useVariables();
const localVariables = useLocalVariables();
const { name: blockType } = useBlockContext() || {};
const form = useForm();
return (
<SortableItem
style={{
position: 'relative',
}}
onClick={async () => {
setOpen(true);
setCurrentConversation(undefined);
setFilterEmployee(aiEmployee.username);
setAttachments([]);
setActions([]);
const messages = [];
if (blockType === 'form') {
console.log(fieldSchema.parent.parent.toJSON());
setAttachments((prev) => [
...prev,
{
type: 'uiSchema',
content: fieldSchema.parent.parent['x-uid'],
},
]);
setActions([
{
content: 'Fill form',
onClick: (content) => {
try {
const values = content.replace('```json', '').replace('```', '');
form.setValues(JSON.parse(values));
} catch (error) {
console.log(error);
}
},
},
]);
}
let message = fieldSchema['x-component-props']?.message;
if (message) {
message = await variables
?.parseVariable(fieldSchema['x-component-props']?.message, localVariables)
.then(({ value }) => value);
messages.push({
type: 'text',
content: message,
});
}
send({
aiEmployee,
messages,
greeting: true,
});
}}
>
<Popover
content={
<div
style={{
width: '300px',
padding: '8px',
}}
>
<div
style={{
width: '100%',
textAlign: 'center',
}}
>
<Avatar
src={avatars(aiEmployee.avatar)}
size={60}
className={css``}
style={{
boxShadow: `0px 0px 2px ${token.colorBorder}`,
}}
/>
<div
style={{
fontSize: token.fontSizeLG,
fontWeight: token.fontWeightStrong,
margin: '8px 0',
}}
>
{aiEmployee.nickname}
</div>
</div>
<Divider
orientation="left"
plain
style={{
fontStyle: 'italic',
}}
>
{t('Bio')}
</Divider>
<p>{aiEmployee.bio}</p>
{extraInfo && (
<>
<Divider
orientation="left"
plain
style={{
fontStyle: 'italic',
}}
>
{t('Extra information')}
</Divider>
<p>{extraInfo}</p>
</>
)}
</div>
}
>
<Button
shape="circle"
style={{
width: '40px',
height: '40px',
}}
>
<Avatar src={avatars(aiEmployee.avatar)} size={40} />
</Button>
</Popover>
{render()}
</SortableItem>
);
};

View File

@ -0,0 +1,78 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import React, { useContext } from 'react';
import { SchemaInitializer, useAPIClient, useRequest, useSchemaInitializer } from '@nocobase/client';
import { ReactComponent as DesignIcon } from '../design-icon.svg';
import { AIEmployee, AIEmployeesContext, useAIEmployeesContext } from '../AIEmployeesProvider';
import { Spin, Avatar } from 'antd';
import { avatars } from '../avatars';
export const configureAIEmployees = new SchemaInitializer({
name: 'aiEmployees:configure',
title: '{{t("AI employees")}}',
icon: (
<span
style={{
width: '20px',
display: 'inline-flex',
verticalAlign: 'top',
}}
>
<DesignIcon />
</span>
),
style: {
marginLeft: 8,
},
items: [
{
name: 'ai-employees',
type: 'itemGroup',
useChildren() {
const {
aiEmployees,
service: { loading },
} = useAIEmployeesContext();
return loading
? [
{
name: 'spin',
Component: () => <Spin />,
},
]
: aiEmployees.map((aiEmployee) => ({
name: aiEmployee.username,
title: aiEmployee.nickname,
icon: <Avatar src={avatars(aiEmployee.avatar)} />,
type: 'item',
useComponentProps() {
const { insert } = useSchemaInitializer();
const handleClick = () => {
insert({
type: 'void',
'x-component': 'AIEmployeeButton',
'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'aiEmployees:button',
'x-component-props': {
aiEmployee,
},
});
};
return {
onClick: handleClick,
};
},
}));
},
},
],
});

View File

@ -0,0 +1,110 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import React, { useEffect } from 'react';
import cls from 'classnames';
import { useToken, useUploadStyles } from '@nocobase/client';
import useUploadStyle from 'antd/es/upload/style';
import { css } from '@emotion/css';
import { useField } from '@formily/react';
import { Field } from '@formily/core';
import { avatars } from '../avatars';
export const Avatar: React.FC<{
srcs: [string, string][];
size?: 'small' | 'large';
selectable?: boolean;
highlightItem?: string;
onClick?: (name: string) => void;
}> = ({ srcs, size, selectable, highlightItem, onClick }) => {
const { token } = useToken();
const { wrapSSR, hashId, componentCls: prefixCls } = useUploadStyles();
useUploadStyle(prefixCls);
const list =
srcs?.map(([src, name], index) => (
<div key={index} className={`${prefixCls}-list-picture-card-container ${prefixCls}-list-item-container`}>
<div
onClick={() => onClick && onClick(name)}
className={cls(
`${prefixCls}-list-item`,
`${prefixCls}-list-item-done`,
`${prefixCls}-list-item-list-type-picture-card`,
highlightItem === name
? css`
border-color: ${token.colorPrimary} !important;
`
: '',
selectable
? css`
cursor: pointer;
&:hover {
border-color: ${token.colorPrimary} !important;
}
`
: '',
)}
>
<div className={`${prefixCls}-list-item-info`}>
<span key="thumbnail" className={`${prefixCls}-list-item-thumbnail`}>
<img src={src} className={`${prefixCls}-list-item-image`} />
</span>
</div>
</div>
</div>
)) || [];
return wrapSSR(
<div
className={cls(
`${prefixCls}-wrapper`,
`${prefixCls}-picture-card-wrapper`,
`nb-upload`,
`nb-upload${size ? `-${size}` : ''}`,
hashId,
)}
>
<div className={cls(`${prefixCls}-list`, `${prefixCls}-list-picture-card`)}>{list}</div>
</div>,
);
};
export const AvatarSelect: React.FC = () => {
const field = useField<Field>();
const [current, setCurrent] = React.useState(avatars?.keys()[0]);
useEffect(() => {
if (field.value) {
return;
}
field.setInitialValue(avatars?.keys()[0]);
}, [field]);
useEffect(() => {
if (!field.value) {
return;
}
setCurrent(field.value);
}, [field.value]);
return (
<>
<div style={{ marginBottom: '16px' }}>
<Avatar srcs={current ? [[avatars(current), current]] : []} />
</div>
<Avatar
srcs={avatars?.keys().map((a) => [avatars(a), a])}
size="small"
selectable
highlightItem={current}
onClick={(name) => (field.value = name)}
/>
</>
);
};

View File

@ -0,0 +1,477 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import React, { createContext, useContext, useMemo } from 'react';
import { Card, Row, Col, Avatar, Input, Space, Button, Tabs, App, Spin, Empty } from 'antd';
import {
CollectionRecordProvider,
SchemaComponent,
useAPIClient,
useActionContext,
useCollectionRecordData,
useRequest,
useToken,
} from '@nocobase/client';
import { useT } from '../../locale';
const { Meta } = Card;
import { css } from '@emotion/css';
import { EditOutlined, DeleteOutlined } from '@ant-design/icons';
import { AvatarSelect } from './AvatarSelect';
import { useForm } from '@formily/react';
import { createForm } from '@formily/core';
import { uid } from '@formily/shared';
import { avatars } from '../avatars';
import { ModelSettings } from './ModelSettings';
const EmployeeContext = createContext(null);
const AIEmployeeForm: React.FC = () => {
return (
<Tabs
items={[
{
key: 'profile',
label: 'Profile',
children: (
<SchemaComponent
components={{ AvatarSelect }}
schema={{
type: 'void',
properties: {
username: {
type: 'string',
title: 'Username',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
nickname: {
type: 'string',
title: 'Nickname',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
avatar: {
type: 'string',
title: 'Avatar',
'x-decorator': 'FormItem',
'x-component': 'AvatarSelect',
},
bio: {
type: 'string',
title: 'Bio',
'x-decorator': 'FormItem',
'x-component': 'Input.TextArea',
'x-component-props': {
placeholder:
'The introduction to the AI employee will inform human colleagues about its skills and how to use it. This information will be displayed on the employees profile. This will not be part of the prompt of this AI employee.',
},
},
about: {
type: 'string',
title: 'About me',
'x-decorator': 'FormItem',
'x-component': 'Input.TextArea',
'x-component-props': {
placeholder:
'Define the AI employees role, guide its work, and instruct it complete user-assigned tasks. This will be part of the prompt of this AI employee.',
autoSize: {
minRows: 15,
},
},
},
greeting: {
type: 'string',
title: 'Greeting message',
'x-decorator': 'FormItem',
'x-component': 'Input.TextArea',
},
},
}}
/>
),
},
// {
// key: 'skills',
// label: 'Skills',
// // children: (
// // <>
// // <List
// // itemLayout="vertical"
// // size="small"
// // dataSource={[
// // {
// // title: 'Customer Background Lookup',
// // type: 'API request',
// // color: 'green',
// // description:
// // 'Retrieves customer data from CRM systems, social media, and public databases to build a comprehensive customer profile.',
// // },
// // {
// // title: 'Sentiment Analysis Engine',
// // type: 'Script execution',
// // color: 'blue',
// // description:
// // 'Analyzes customer interactions (emails, chats, calls) to detect sentiment and engagement levels.',
// // },
// // {
// // title: 'Lead Qualification Scoring',
// // type: 'SQL execution',
// // color: 'purple',
// // description:
// // 'Queries customer interaction history and purchase data to assign a lead score based on engagement and potential conversion.',
// // },
// // {
// // title: 'Profile Enrichment Workflow',
// // type: 'Call workflows',
// // color: 'orange',
// // description:
// // 'Automates the process of merging customer data from multiple sources to enhance and complete missing profile details.',
// // },
// // ]}
// // renderItem={(item) => (
// // <List.Item key={item.title} extra={<RightOutlined />}>
// // <List.Item.Meta
// // // avatar={<Avatar src={item.avatar} />}
// // title={item.title}
// // description={<Tag color={item.color}>{item.type}</Tag>}
// // />
// // {item.description}
// // </List.Item>
// // )}
// // />
// // <Dropdown
// // menu={{
// // items: [
// // {
// // key: 'workflow',
// // label: 'Call workflows',
// // },
// // {
// // key: 'sql',
// // label: 'SQL execution',
// // },
// // {
// // key: 'api',
// // label: 'API request',
// // },
// // {
// // key: 'script',
// // label: 'Script execution',
// // },
// // ],
// // }}
// // placement="bottomLeft"
// // >
// // <Button type="primary" icon={<PlusOutlined />}>
// // Add
// // </Button>
// // </Dropdown>
// // </>
// // ),
// },
{
key: 'modelSettings',
label: 'Model Settings',
children: (
<SchemaComponent
components={{ ModelSettings }}
schema={{
type: 'object',
name: 'modelSettings',
properties: {
llmService: {
type: 'string',
title: 'LLM service',
'x-decorator': 'FormItem',
'x-component': 'RemoteSelect',
'x-component-props': {
manual: false,
fieldNames: {
label: 'title',
value: 'name',
},
service: {
resource: 'llmServices',
action: 'list',
params: {
fields: ['title', 'name'],
},
},
},
},
settings: {
type: 'void',
'x-component': 'ModelSettings',
},
},
}}
/>
),
},
]}
/>
);
};
const useCreateFormProps = () => {
const form = useMemo(
() =>
createForm({
initialValues: {
username: `${uid()}`,
},
}),
[],
);
return {
form,
};
};
const useEditFormProps = () => {
const record = useCollectionRecordData();
const form = useMemo(
() =>
createForm({
initialValues: record,
}),
[record],
);
return {
form,
};
};
const useCancelActionProps = () => {
const { setVisible } = useActionContext();
const form = useForm();
return {
type: 'default',
onClick() {
setVisible(false);
form.reset();
},
};
};
const useCreateActionProps = () => {
const { setVisible } = useActionContext();
const { message } = App.useApp();
const form = useForm();
const api = useAPIClient();
const { refresh } = useContext(EmployeeContext);
const t = useT();
return {
type: 'primary',
async onClick() {
await form.submit();
const values = form.values;
await api.resource('aiEmployees').create({
values,
});
refresh();
message.success(t('Saved successfully'));
setVisible(false);
form.reset();
},
};
};
const useEditActionProps = () => {
const { setVisible } = useActionContext();
const { message } = App.useApp();
const form = useForm();
const t = useT();
const { refresh } = useContext(EmployeeContext);
const api = useAPIClient();
return {
type: 'primary',
async onClick() {
await form.submit();
const values = form.values;
await api.resource('aiEmployees').update({
values,
filterByTk: values.username,
});
refresh();
message.success(t('Saved successfully'));
setVisible(false);
form.reset();
},
};
};
export const Employees: React.FC = () => {
const t = useT();
const { token } = useToken();
const api = useAPIClient();
const { data, loading, refresh } = useRequest<
{
username: string;
nickname: string;
bio: string;
avatar: string;
}[]
>(() =>
api
.resource('aiEmployees')
.list()
.then((res) => res?.data?.data),
);
return (
<EmployeeContext.Provider value={{ refresh }}>
<div
style={{ marginBottom: token.marginLG }}
className={css`
justify-content: space-between;
display: flex;
align-items: center;
`}
>
<div>
<Input allowClear placeholder={t('Search')} />
</div>
<div>
<Space>
<Button>{t('New from template')}</Button>
<SchemaComponent
scope={{ useCreateFormProps, useCancelActionProps, useCreateActionProps }}
components={{ AIEmployeeForm }}
schema={{
type: 'void',
name: uid(),
'x-component': 'Action',
'x-component-props': {
type: 'primary',
},
title: 'New AI employee',
properties: {
drawer: {
type: 'void',
'x-component': 'Action.Drawer',
title: 'New AI employee',
'x-decorator': 'FormV2',
'x-use-decorator-props': 'useCreateFormProps',
properties: {
form: {
type: 'void',
'x-component': 'AIEmployeeForm',
},
footer: {
type: 'void',
'x-component': 'Action.Drawer.Footer',
properties: {
close: {
title: 'Cancel',
'x-component': 'Action',
'x-component-props': {
type: 'default',
},
'x-use-component-props': 'useCancelActionProps',
},
submit: {
title: 'Submit',
'x-component': 'Action',
'x-component-props': {
type: 'primary',
},
'x-use-component-props': 'useCreateActionProps',
},
},
},
},
},
},
}}
/>
</Space>
</div>
</div>
{loading ? (
<Spin />
) : data && data.length ? (
<Row gutter={[16, 16]}>
{data.map((employee) => (
<CollectionRecordProvider key={employee.username} record={employee}>
<Col span={6}>
<Card
variant="borderless"
actions={[
<SchemaComponent
key="edit"
scope={{ useCancelActionProps, useEditFormProps, useEditActionProps }}
components={{ AIEmployeeForm }}
schema={{
type: 'void',
name: uid(),
'x-component': 'Action',
'x-component-props': {
component: (props) => <EditOutlined {...props} />,
},
properties: {
drawer: {
type: 'void',
'x-component': 'Action.Drawer',
title: 'Edit AI employee',
'x-decorator': 'FormV2',
'x-use-decorator-props': 'useEditFormProps',
properties: {
form: {
type: 'void',
'x-component': 'AIEmployeeForm',
},
footer: {
type: 'void',
'x-component': 'Action.Drawer.Footer',
properties: {
close: {
title: 'Cancel',
'x-component': 'Action',
'x-component-props': {
type: 'default',
},
'x-use-component-props': 'useCancelActionProps',
},
submit: {
title: 'Submit',
'x-component': 'Action',
'x-component-props': {
type: 'primary',
},
'x-use-component-props': 'useEditActionProps',
},
},
},
},
},
},
}}
/>,
<DeleteOutlined key="delete" />,
]}
>
<Meta
avatar={employee.avatar ? <Avatar src={avatars(employee.avatar)} /> : null}
title={employee.nickname}
description={employee.bio}
/>
</Card>
</Col>
</CollectionRecordProvider>
))}
</Row>
) : (
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
)}
</EmployeeContext.Provider>
);
};

View File

@ -0,0 +1,43 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { observer, useForm } from '@formily/react';
import { useAPIClient, usePlugin, useRequest } from '@nocobase/client';
import React from 'react';
import PluginAIClient from '../../';
export const useModelSettingsForm = (provider: string) => {
const plugin = usePlugin(PluginAIClient);
const p = plugin.aiManager.llmProviders.get(provider);
return p?.components?.ModelSettingsForm;
};
export const ModelSettings = observer(
() => {
const form = useForm();
const api = useAPIClient();
const { data, loading } = useRequest<{ provider: string }>(
() =>
api
.resource('llmServices')
.get({ filterByTk: form.values?.modelSettings?.llmService })
.then((res) => res?.data?.data),
{
ready: !!form.values?.modelSettings?.llmService,
refreshDeps: [form.values?.modelSettings?.llmService],
},
);
const Component = useModelSettingsForm(data?.provider);
if (loading) {
return null;
}
return Component ? <Component /> : null;
},
{ displayName: 'AIEmployeeModelSettingsForm' },
);

View File

@ -0,0 +1,127 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import React, { useMemo } from 'react';
import {
SchemaSettings,
SchemaSettingsModalItem,
useBlockContext,
useCollection,
useCollectionFilterOptions,
useCollectionRecordData,
useSchemaSettings,
} from '@nocobase/client';
import { useT } from '../../locale';
import { avatars } from '../avatars';
import { Card, Avatar } from 'antd';
const { Meta } = Card;
import { Schema } from '@formily/react';
export const useAIEmployeeButtonVariableOptions = () => {
const collection = useCollection();
const t = useT();
const fieldsOptions = useCollectionFilterOptions(collection);
const recordData = useCollectionRecordData();
const { name: blockType } = useBlockContext() || {};
const fields = useMemo(() => {
return Schema.compile(fieldsOptions, { t });
}, [fieldsOptions]);
return useMemo(() => {
return [
recordData && {
name: 'currentRecord',
title: t('Current record'),
children: [...fields],
},
blockType === 'form' && {
name: '$nForm',
title: t('Current form'),
children: [...fields],
},
].filter(Boolean);
}, [recordData, t, fields, blockType]);
};
export const aiEmployeeButtonSettings = new SchemaSettings({
name: 'aiEmployees:button',
items: [
{
name: 'edit',
Component: () => {
const t = useT();
const { dn } = useSchemaSettings();
const aiEmployee = dn.getSchemaAttribute('x-component-props.aiEmployee') || {};
return (
<SchemaSettingsModalItem
scope={{ useAIEmployeeButtonVariableOptions }}
schema={{
type: 'object',
title: t('Edit'),
properties: {
profile: {
type: 'void',
'x-decorator': 'FormItem',
'x-component': () => (
<Card variant="borderless">
<Meta
avatar={aiEmployee.avatar ? <Avatar src={avatars(aiEmployee.avatar)} /> : null}
title={aiEmployee.nickname}
description={aiEmployee.bio}
/>
</Card>
),
},
message: {
type: 'string',
title: t('Message'),
'x-decorator': 'FormItem',
'x-component': 'Variable.RawTextArea',
'x-component-props': {
scope: '{{ useAIEmployeeButtonVariableOptions }}',
fieldNames: {
value: 'name',
label: 'title',
},
},
default: dn.getSchemaAttribute('x-component-props.message'),
},
extraInfo: {
type: 'string',
title: t('Extra Information'),
'x-decorator': 'FormItem',
'x-component': 'Input.TextArea',
default: dn.getSchemaAttribute('x-component-props.extraInfo'),
},
},
}}
title={t('Edit')}
onSubmit={({ message, extraInfo }) => {
dn.deepMerge({
'x-uid': dn.getSchemaAttribute('x-uid'),
'x-component-props': {
aiEmployee,
message,
extraInfo,
},
});
}}
/>
);
},
},
{
name: 'divider',
type: 'divider',
},
{
name: 'delete',
type: 'remove',
},
],
});

View File

@ -14,12 +14,14 @@ import { tval } from '@nocobase/utils/client';
import { ArrayCollapse, FormLayout } from '@formily/antd-v5';
import { useField, observer } from '@formily/react';
import { Field } from '@formily/core';
import { WorkflowVariableRawTextArea } from '@nocobase/plugin-workflow/client';
const UserMessage: React.FC = observer(() => {
const t = useT();
return (
<SchemaComponent
components={{ WorkflowVariableRawTextArea }}
schema={{
type: 'void',
properties: {
@ -121,6 +123,7 @@ const Content: React.FC = observer(() => {
}
return (
<SchemaComponent
components={{ WorkflowVariableRawTextArea }}
schema={{
type: 'void',
properties: {

View File

@ -13,12 +13,17 @@ import { openaiProviderOptions } from './llm-providers/openai';
import { deepseekProviderOptions } from './llm-providers/deepseek';
import PluginWorkflowClient from '@nocobase/plugin-workflow/client';
import { LLMInstruction } from './workflow/nodes/llm';
import { AIEmployeeInstruction } from './workflow/nodes/employee';
import { tval } from '@nocobase/utils/client';
import { namespace } from './locale';
import { configureAIEmployees } from './ai-employees/initializer/ConfigureAIEmployees';
import { aiEmployeeButtonSettings } from './ai-employees/settings/AIEmployeeButton';
const { AIEmployeesProvider } = lazy(() => import('./ai-employees/AIEmployeesProvider'), 'AIEmployeesProvider');
const { Employees } = lazy(() => import('./ai-employees/manager/Employees'), 'Employees');
const { LLMServices } = lazy(() => import('./llm-services/LLMServices'), 'LLMServices');
const { MessagesSettings } = lazy(() => import('./chat-settings/Messages'), 'MessagesSettings');
const { Chat } = lazy(() => import('./llm-providers/components/Chat'), 'Chat');
const { ModelSelect } = lazy(() => import('./llm-providers/components/ModelSelect'), 'ModelSelect');
const { AIEmployeeButton } = lazy(() => import('./ai-employees/initializer/AIEmployeeButton'), 'AIEmployeeButton');
export class PluginAIClient extends Plugin {
aiManager = new AIManager();
@ -31,11 +36,21 @@ export class PluginAIClient extends Plugin {
// You can get and modify the app instance here
async load() {
this.app.use(AIEmployeesProvider);
this.app.addComponents({
AIEmployeeButton,
});
this.app.pluginSettingsManager.add('ai', {
icon: 'RobotOutlined',
title: tval('AI integration', { ns: namespace }),
icon: 'TeamOutlined',
title: tval('AI employees', { ns: namespace }),
aclSnippet: 'pm.ai',
});
this.app.pluginSettingsManager.add('ai.employees', {
icon: 'TeamOutlined',
title: tval('AI employees', { ns: namespace }),
aclSnippet: 'pm.ai.employees',
Component: Employees,
});
this.app.pluginSettingsManager.add('ai.llm-services', {
icon: 'LinkOutlined',
title: tval('LLM services', { ns: namespace }),
@ -43,6 +58,9 @@ export class PluginAIClient extends Plugin {
Component: LLMServices,
});
this.app.schemaInitializerManager.add(configureAIEmployees);
this.app.schemaSettingsManager.add(aiEmployeeButtonSettings);
this.aiManager.registerLLMProvider('openai', openaiProviderOptions);
this.aiManager.registerLLMProvider('deepseek', deepseekProviderOptions);
this.aiManager.chatSettings.set('messages', {
@ -53,9 +71,10 @@ export class PluginAIClient extends Plugin {
const workflow = this.app.pm.get('workflow') as PluginWorkflowClient;
workflow.registerInstructionGroup('ai', { label: tval('AI', { ns: namespace }) });
workflow.registerInstruction('llm', LLMInstruction);
workflow.registerInstruction('ai-employee', AIEmployeeInstruction);
}
}
export default PluginAIClient;
export { Chat, ModelSelect };
export { ModelSelect };
export type { LLMProviderOptions } from './manager/ai-manager';

View File

@ -1,250 +0,0 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { SchemaComponent } from '@nocobase/client';
import React from 'react';
import { namespace, useT } from '../../locale';
import { tval } from '@nocobase/utils/client';
import { ArrayCollapse, FormLayout } from '@formily/antd-v5';
import { useField, observer } from '@formily/react';
import { Field } from '@formily/core';
import { WorkflowVariableInput } from '@nocobase/plugin-workflow/client';
const UserMessage: React.FC = observer(() => {
const t = useT();
const field = useField();
const type = field.query('.type').take() as Field;
if (type.value === 'image_url') {
return (
<SchemaComponent
components={{ WorkflowVariableInput }}
schema={{
type: 'void',
properties: {
image_url: {
type: 'object',
properties: {
url: {
title: tval('Image', { ns: namespace }),
type: 'string',
'x-decorator': 'FormItem',
'x-component': 'WorkflowVariableInput',
'x-component-props': {
changeOnSelect: true,
},
},
},
},
},
}}
/>
);
}
return (
<SchemaComponent
schema={{
type: 'void',
properties: {
content: {
title: t('Content'),
type: 'string',
'x-decorator': 'FormItem',
'x-component': 'WorkflowVariableRawTextArea',
'x-component-props': {
autoSize: {
minRows: 5,
},
},
},
},
}}
/>
);
});
const Content: React.FC = observer(() => {
const t = useT();
const field = useField();
const role = field.query('.role').take() as Field;
if (role.value === 'user') {
return (
<SchemaComponent
components={{ UserMessage }}
schema={{
type: 'void',
properties: {
content: {
type: 'array',
'x-component': 'ArrayCollapse',
'x-component-props': {
size: 'small',
bordered: false,
},
default: [{ type: 'text' }],
'x-decorator': 'FormItem',
items: {
type: 'object',
'x-component': 'ArrayCollapse.CollapsePanel',
'x-component-props': {
header: t('Content'),
},
properties: {
form: {
type: 'void',
'x-component': 'FormLayout',
'x-component-props': {
layout: 'vertical',
},
properties: {
type: {
title: t('Type'),
type: 'string',
'x-decorator': 'FormItem',
'x-component': 'Select',
enum: [
{ label: t('Text'), value: 'text' },
{ label: t('Image'), value: 'image_url' },
],
default: 'text',
},
user: {
type: 'void',
'x-component': 'UserMessage',
},
},
},
moveUp: {
type: 'void',
'x-component': 'ArrayCollapse.MoveUp',
},
moveDown: {
type: 'void',
'x-component': 'ArrayCollapse.MoveDown',
},
remove: {
type: 'void',
'x-component': 'ArrayCollapse.Remove',
},
},
},
properties: {
addition: {
type: 'void',
title: tval('Add content', { ns: namespace }),
'x-component': 'ArrayCollapse.Addition',
'x-component-props': {
defaultValue: { type: 'text' },
},
},
},
},
},
}}
/>
);
}
return (
<SchemaComponent
schema={{
type: 'void',
properties: {
message: {
title: tval('Content', { ns: namespace }),
type: 'string',
'x-decorator': 'FormItem',
'x-component': 'WorkflowVariableRawTextArea',
},
},
}}
/>
);
});
export const Messages: React.FC = () => {
const t = useT();
return (
<SchemaComponent
components={{ ArrayCollapse, FormLayout, Content }}
schema={{
type: 'void',
properties: {
messages: {
type: 'array',
'x-component': 'ArrayCollapse',
'x-component-props': {
size: 'small',
},
'x-decorator': 'FormItem',
default: [{ role: 'user', content: [{ type: 'text' }] }],
items: {
type: 'object',
'x-component': 'ArrayCollapse.CollapsePanel',
'x-component-props': {
header: t('Message'),
},
properties: {
form: {
type: 'void',
'x-component': 'FormLayout',
'x-component-props': {
layout: 'vertical',
},
properties: {
role: {
title: tval('Role', { ns: namespace }),
type: 'string',
'x-decorator': 'FormItem',
'x-component': 'Select',
enum: [
{ label: 'System', value: 'system' },
{ label: 'User', value: 'user' },
{ label: 'Assistant', value: 'assistant' },
],
default: 'user',
},
content: {
type: 'void',
'x-component': 'Content',
},
},
},
moveUp: {
type: 'void',
'x-component': 'ArrayCollapse.MoveUp',
},
moveDown: {
type: 'void',
'x-component': 'ArrayCollapse.MoveDown',
},
remove: {
type: 'void',
'x-component': 'ArrayCollapse.Remove',
},
},
},
properties: {
addition: {
type: 'void',
title: tval('Add prompt', { ns: namespace }),
'x-component': 'ArrayCollapse.Addition',
'x-component-props': {
defaultValue: { role: 'user', content: [{ type: 'text' }] },
},
},
},
},
},
}}
/>
);
};

View File

@ -15,7 +15,7 @@ import { Field } from '@formily/core';
export const ModelSelect: React.FC = () => {
const field = useField<Field>();
const form = useForm();
const serviceField = field.query('.llmService').take() as Field;
const api = useAPIClient();
const ctx = useActionContext();
const [options, setOptions] = useState([]);
@ -29,7 +29,7 @@ export const ModelSelect: React.FC = () => {
api
.resource('ai')
.listModels({
llmService: form.values?.llmService,
llmService: serviceField?.value,
})
.then(
(res) =>
@ -42,8 +42,8 @@ export const ModelSelect: React.FC = () => {
),
),
{
ready: !!form.values?.llmService && ctx.visible,
refreshDeps: [form.values?.llmService],
ready: !!serviceField?.value && ctx.visible,
refreshDeps: [serviceField?.value],
onSuccess: (data) => setOptions(data),
},
);

View File

@ -1,70 +0,0 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { SchemaComponent } from '@nocobase/client';
import React from 'react';
import { useT } from '../../locale';
import { WorkflowVariableJSON } from '@nocobase/plugin-workflow/client';
export const StructuredOutput: React.FC = () => {
const t = useT();
return (
<SchemaComponent
components={{ WorkflowVariableJSON }}
schema={{
type: 'void',
properties: {
structuredOutput: {
type: 'object',
properties: {
schema: {
title: 'JSON Schema',
type: 'string',
description: (
<>
{t('Syntax references')}:{' '}
<a href="https://json-schema.org" target="_blank" rel="noreferrer">
JSON Schema
</a>
</>
),
'x-decorator': 'FormItem',
'x-component': 'WorkflowVariableJSON',
'x-component-props': {
json5: true,
autoSize: {
minRows: 10,
},
},
},
name: {
title: t('Name'),
type: 'string',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
description: {
title: t('Description'),
type: 'string',
'x-decorator': 'FormItem',
'x-component': 'Input.TextArea',
},
strict: {
title: 'Strict',
type: 'boolean',
'x-decorator': 'FormItem',
'x-component': 'Checkbox',
},
},
},
},
}}
/>
);
};

View File

@ -14,7 +14,6 @@ import { namespace, useT } from '../../locale';
import { Collapse } from 'antd';
import { WorkflowVariableRawTextArea } from '@nocobase/plugin-workflow/client';
import { ModelSelect } from '../components/ModelSelect';
import { Chat } from '../components/Chat';
const Options: React.FC = () => {
const t = useT();
@ -144,7 +143,7 @@ const Options: React.FC = () => {
export const ModelSettingsForm: React.FC = () => {
return (
<SchemaComponent
components={{ Options, WorkflowVariableRawTextArea, ModelSelect, Chat }}
components={{ Options, WorkflowVariableRawTextArea, ModelSelect }}
schema={{
type: 'void',
properties: {
@ -159,10 +158,6 @@ export const ModelSettingsForm: React.FC = () => {
type: 'void',
'x-component': 'Options',
},
chat: {
type: 'void',
'x-component': 'Chat',
},
},
}}
/>

View File

@ -14,7 +14,6 @@ import { namespace, useT } from '../../locale';
import { Collapse } from 'antd';
import { WorkflowVariableRawTextArea } from '@nocobase/plugin-workflow/client';
import { ModelSelect } from '../components/ModelSelect';
import { Chat } from '../components/Chat';
const Options: React.FC = () => {
const t = useT();
@ -148,7 +147,7 @@ const Options: React.FC = () => {
export const ModelSettingsForm: React.FC = () => {
return (
<SchemaComponent
components={{ Options, WorkflowVariableRawTextArea, ModelSelect, Chat }}
components={{ Options, WorkflowVariableRawTextArea, ModelSelect }}
schema={{
type: 'void',
properties: {
@ -163,10 +162,6 @@ export const ModelSettingsForm: React.FC = () => {
type: 'void',
'x-component': 'Options',
},
chat: {
type: 'void',
'x-component': 'Chat',
},
},
}}
/>

View File

@ -15,7 +15,7 @@ export const namespace = pkg.name;
export function useT() {
const app = useApp();
return (str: string) => app.i18n.t(str, { ns: [pkg.name, 'client'] });
return (str: string, options?: any) => app.i18n.t(str, { ns: [pkg.name, 'client'], ...options });
}
export function tStr(key: string) {

View File

@ -0,0 +1,77 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import React from 'react';
import { Instruction, WorkflowVariableRawTextArea } from '@nocobase/plugin-workflow/client';
import { UserOutlined } from '@ant-design/icons';
import { Card, Avatar } from 'antd';
const { Meta } = Card;
const AIEmployee = () => {
return (
<Card variant="borderless">
<Meta
avatar={<Avatar src="https://api.dicebear.com/7.x/miniavs/svg?seed=8" />}
title="LinguaBridge"
description="Translates customer messages, emails, and documents in real-time across multiple languages."
/>
</Card>
);
};
export class AIEmployeeInstruction extends Instruction {
title = 'AI employee';
type = 'ai-employee';
group = 'ai';
// @ts-ignore
icon = (<UserOutlined />);
fieldset = {
employee: {
type: 'string',
title: 'AI Employee',
required: true,
'x-decorator': 'FormItem',
'x-component': 'AIEmployee',
},
message: {
type: 'string',
title: 'Message',
required: true,
'x-decorator': 'FormItem',
'x-component': 'WorkflowVariableRawTextArea',
'x-component-props': {
autoSize: {
minRows: 5,
},
},
},
colleague: {
type: 'string',
title: 'Collaborating human colleague',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Select',
},
manual: {
type: 'boolean',
title: 'Require human colleague confirmation to continue',
required: true,
'x-decorator': 'FormItem',
'x-component': 'Checkbox',
},
};
components = {
AIEmployee,
WorkflowVariableRawTextArea,
};
isAvailable({ engine, workflow }) {
return !engine.isWorkflowSync(workflow);
}
}

View File

@ -13,6 +13,7 @@ import { RobotOutlined } from '@ant-design/icons';
import { tval } from '@nocobase/utils/client';
import { namespace } from '../../../locale';
import { Settings } from './ModelSettings';
import { Chat } from '../../../llm-providers/components/Chat';
export class LLMInstruction extends Instruction {
title = 'LLM';
@ -47,9 +48,14 @@ export class LLMInstruction extends Instruction {
type: 'void',
'x-component': 'Settings',
},
chat: {
type: 'void',
'x-component': 'Chat',
},
};
components = {
Settings,
Chat,
};
isAvailable({ engine, workflow }) {

View File

@ -0,0 +1,52 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
export default {
name: 'aiEmployees',
fields: [
{
name: 'username',
type: 'string',
primaryKey: true,
},
{
name: 'nickname',
type: 'string',
interface: 'input',
},
{
name: 'avatar',
type: 'string',
interface: 'image',
},
{
name: 'bio',
type: 'string',
interface: 'textarea',
},
{
name: 'about',
type: 'string',
interface: 'textarea',
},
{
name: 'greeting',
type: 'string',
interface: 'textarea',
},
{
name: 'skills',
type: 'jsonb',
},
{
name: 'modelSettings',
type: 'jsonb',
},
],
};

View File

@ -21,5 +21,6 @@
"Response format description": "Important: when using JSON mode, you must also instruct the model to produce JSON yourself via a system or user message.",
"Temperature description": "What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.",
"Top P description": "An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered.",
"Get models list failed, you can enter a model name manually.": "Get models list failed, you can enter a model name manually."
"Get models list failed, you can enter a model name manually.": "Get models list failed, you can enter a model name manually.",
"Default greeting message": "Hi, I am {{ nickname }}"
}

View File

@ -0,0 +1,19 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import snowflake from '../snowflake';
it('generate snowflake id', async () => {
const ids = [];
for (let i = 0; i < 10; i++) {
ids.push(snowflake.generate());
}
// check unique
expect(new Set(ids).size).toBe(10);
});

View File

@ -0,0 +1,297 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { convertUiSchemaToJsonSchema } from '../utils';
it('should convert ui schema to json schema', async () => {
const result = convertUiSchemaToJsonSchema({
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'FormV2',
'x-use-component-props': 'useCreateFormBlockProps',
'x-app-version': '1.7.0-beta.9',
properties: {
grid: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid',
'x-initializer': 'form:configureFields',
'x-app-version': '1.7.0-beta.9',
properties: {
'9lv2wl150pl': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
'x-app-version': '1.7.0-beta.9',
properties: {
jjfipnudrfs: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
'x-app-version': '1.7.0-beta.9',
properties: {
nickname: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'string',
'x-toolbar': 'FormItemSchemaToolbar',
'x-settings': 'fieldSettings:FormItem',
'x-component': 'CollectionField',
'x-decorator': 'FormItem',
'x-collection-field': 'users.nickname',
'x-component-props': {},
'x-app-version': '1.7.0-beta.9',
'x-uid': 'mzsm3gfcix6',
'x-async': false,
'x-index': 1,
name: 'nickname',
},
},
'x-uid': 'wx3p0h2uj3a',
'x-async': false,
'x-index': 1,
name: 'jjfipnudrfs',
},
},
'x-uid': '1cndl1bxewd',
'x-async': false,
'x-index': 1,
name: '9lv2wl150pl',
},
'25mljjny4u4': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
'x-app-version': '1.7.0-beta.9',
properties: {
l3vxr4qesnr: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
'x-app-version': '1.7.0-beta.9',
properties: {
username: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'string',
'x-toolbar': 'FormItemSchemaToolbar',
'x-settings': 'fieldSettings:FormItem',
'x-component': 'CollectionField',
'x-decorator': 'FormItem',
'x-collection-field': 'users.username',
'x-component-props': {},
'x-app-version': '1.7.0-beta.9',
'x-uid': 'hyqq9y93osu',
'x-async': false,
'x-index': 1,
name: 'username',
},
},
'x-uid': 'vzyckvjmhpq',
'x-async': false,
'x-index': 1,
name: 'l3vxr4qesnr',
},
},
'x-uid': 'q3uc0eoceyb',
'x-async': false,
'x-index': 2,
name: '25mljjny4u4',
},
xhswvdtwuif: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
'x-app-version': '1.7.0-beta.9',
properties: {
ue5sdpbq6hr: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
'x-app-version': '1.7.0-beta.9',
properties: {
email: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'string',
'x-toolbar': 'FormItemSchemaToolbar',
'x-settings': 'fieldSettings:FormItem',
'x-component': 'CollectionField',
'x-decorator': 'FormItem',
'x-collection-field': 'users.email',
'x-component-props': {},
'x-app-version': '1.7.0-beta.9',
'x-uid': 'j8ayrm5ffvn',
'x-async': false,
'x-index': 1,
name: 'email',
},
},
'x-uid': 'z2y5tchettt',
'x-async': false,
'x-index': 1,
name: 'ue5sdpbq6hr',
},
},
'x-uid': '4e9k3kyh7a8',
'x-async': false,
'x-index': 3,
name: 'xhswvdtwuif',
},
jpk5232nuty: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
'x-app-version': '1.7.0-beta.9',
properties: {
a5odai87axd: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
'x-app-version': '1.7.0-beta.9',
properties: {
phone: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'string',
'x-toolbar': 'FormItemSchemaToolbar',
'x-settings': 'fieldSettings:FormItem',
'x-component': 'CollectionField',
'x-decorator': 'FormItem',
'x-collection-field': 'users.phone',
'x-component-props': {},
'x-app-version': '1.7.0-beta.9',
'x-uid': 'vsg8y5ezr9d',
'x-async': false,
'x-index': 1,
name: 'phone',
},
},
'x-uid': 'cljjsqsovht',
'x-async': false,
'x-index': 1,
name: 'a5odai87axd',
},
},
'x-uid': 'ybzvngylbwq',
'x-async': false,
'x-index': 4,
name: 'jpk5232nuty',
},
},
'x-uid': 'ybw3ukyt20q',
'x-async': false,
'x-index': 1,
name: 'grid',
},
m5fj43b5tv3: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-initializer': 'aiEmployees:configure',
'x-component': 'ActionBar',
'x-component-props': {
layout: 'one-column',
style: {
marginBottom: 8,
},
},
'x-app-version': '1.7.0-beta.9',
properties: {
'7mx0wfba3jq': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'AIEmployeeButton',
'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'aiEmployees:button',
'x-component-props': {
aiEmployee: {
createdAt: '2025-03-30T05:32:21.213Z',
updatedAt: '2025-03-30T05:32:21.213Z',
username: 'fromStruct',
nickname: 'Structy',
avatar: './wpuvnvazwl.svg',
bio: 'An AI assistant specialized in structuring form content into organized and actionable data.',
about:
'You are FormStructAI, an expert in structuring form data based on provided UI schemas. Your task is to analyze a given UI Schema, extract relevant form content, and return a structured JSON object that aligns with the schema. Ensure all required fields are properly populated, maintain data consistency, and infer missing values when possible. Your response must be formatted as JSON, ready to be pre-filled back into the form.',
greeting:
'Hello! Im Structy, here to help you turn messy form data into structured insights. How can I assist you today?',
skills: null,
modelSettings: null,
},
},
'x-app-version': '1.7.0-beta.9',
'x-uid': 'qjaxx03isdx',
'x-async': false,
'x-index': 1,
name: '7mx0wfba3jq',
},
},
'x-uid': 'ms75vnxwv2q',
'x-async': false,
'x-index': 2,
name: 'm5fj43b5tv3',
},
'32rn0quhzze': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-initializer': 'createForm:configureActions',
'x-component': 'ActionBar',
'x-component-props': {
layout: 'one-column',
},
'x-app-version': '1.7.0-beta.9',
properties: {
'840bun8241p': {
_isJSONSchemaObject: true,
version: '2.0',
title: '{{ t("Submit") }}',
'x-action': 'submit',
'x-component': 'Action',
'x-use-component-props': 'useCreateActionProps',
'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'actionSettings:createSubmit',
'x-component-props': {
type: 'primary',
htmlType: 'submit',
},
'x-action-settings': {},
type: 'void',
'x-app-version': '1.7.0-beta.9',
'x-uid': 'r7ou2wp9kbo',
'x-async': false,
'x-index': 1,
name: '840bun8241p',
},
},
'x-uid': 'i97z5bbg537',
'x-async': false,
'x-index': 3,
name: '32rn0quhzze',
},
},
'x-uid': 'cnkrukqdrfn',
'x-async': false,
'x-index': 1,
name: 'peiwud7mwvg',
});
console.log(result);
});

View File

@ -0,0 +1,10 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
export default {};

View File

@ -0,0 +1,56 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { defineCollection } from '@nocobase/database';
export default defineCollection({
migrationRules: ['schema-only'],
autoGenId: false,
name: 'aiConversations',
fields: [
{
name: 'sessionId',
type: 'uuid',
primaryKey: true,
},
{
name: 'topicId',
type: 'string',
},
{
name: 'user',
type: 'belongsTo',
target: 'users',
targetKey: 'id',
foreignKey: 'userId',
},
{
name: 'aiEmployees',
type: 'belongsToMany',
target: 'aiEmployees',
through: 'aiConversationsEmployees',
foreignKey: 'username',
otherKey: 'sessionId',
targetKey: 'username',
sourceKey: 'sessionId',
},
{
name: 'title',
type: 'string',
},
{
name: 'messages',
type: 'hasMany',
target: 'aiMessages',
sourceKey: 'sessionId',
foreignKey: 'sessionId',
onDelete: 'CASCADE',
},
],
});

View File

@ -0,0 +1,17 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { defineCollection } from '@nocobase/database';
import aiEmployees from '../../collections/ai-employees';
export default defineCollection({
migrationRules: ['overwrite', 'schema-only'],
autoGenId: false,
...aiEmployees,
});

View File

@ -0,0 +1,36 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { defineCollection } from '@nocobase/database';
export default defineCollection({
migrationRules: ['schema-only'],
autoGenId: false,
name: 'aiMessages',
fields: [
{
name: 'messageId',
type: 'string',
primaryKey: true,
},
{
name: 'content',
type: 'text',
},
{
name: 'role',
type: 'string',
},
{
name: 'type',
type: 'string',
defaultValue: 'text',
},
],
});

View File

@ -55,6 +55,13 @@ export abstract class LLMProvider {
return this.chatModel.invoke(this.messages);
}
async stream() {
// for (const handler of this.chatHandlers.values()) {
// await handler();
// }
return this.chatModel.stream(this.messages);
}
async listModels(): Promise<{
models?: { id: string }[];
code?: number;

View File

@ -14,6 +14,7 @@ import { deepseekProviderOptions } from './llm-providers/deepseek';
import aiResource from './resource/ai';
import PluginWorkflowServer from '@nocobase/plugin-workflow';
import { LLMInstruction } from './workflow/nodes/llm';
import aiConversations from './resource/aiConversations';
export class PluginAIServer extends Plugin {
aiManager = new AIManager();
@ -27,10 +28,16 @@ export class PluginAIServer extends Plugin {
this.aiManager.registerLLMProvider('deepseek', deepseekProviderOptions);
this.app.resourceManager.define(aiResource);
this.app.resourceManager.define(aiConversations);
this.app.acl.registerSnippet({
name: `pm.${this.name}.llm-services`,
actions: ['ai:*', 'llmServices:*'],
});
this.app.acl.registerSnippet({
name: `pm.${this.name}.ai-employees`,
actions: ['aiEmployees:*'],
});
this.app.acl.allow('aiConversations', '*', 'loggedIn');
const workflowSnippet = this.app.acl.snippetManager.snippets.get('pm.workflow.workflows');
if (workflowSnippet) {
workflowSnippet.actions.push('ai:listModels');

View File

@ -0,0 +1,201 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import actions, { Context, Next } from '@nocobase/actions';
import snowflake from '../snowflake';
import PluginAIServer from '../plugin';
import { Model } from '@nocobase/database';
import { convertUiSchemaToJsonSchema } from '../utils';
export default {
name: 'aiConversations',
actions: {
async list(ctx: Context, next: Next) {
const userId = ctx.auth?.user.id;
if (!userId) {
return ctx.throw(403);
}
ctx.action.mergeParams({
filter: {
userId,
},
});
return actions.list(ctx, next);
},
async create(ctx: Context, next: Next) {
const userId = ctx.auth?.user.id;
const { aiEmployees } = ctx.action.params.values || {};
const repo = ctx.db.getRepository('aiConversations');
ctx.body = await repo.create({
values: {
title: 'New Conversation',
userId,
aiEmployees,
},
});
await next();
},
async destroy(ctx: Context, next: Next) {
const userId = ctx.auth?.user.id;
if (!userId) {
return ctx.throw(403);
}
ctx.action.mergeParams({
filter: {
userId,
},
});
return actions.destroy(ctx, next);
},
async getMessages(ctx: Context, next: Next) {
const userId = ctx.auth?.user.id;
if (!userId) {
return ctx.throw(403);
}
const { sessionId } = ctx.action.params || {};
if (!sessionId) {
ctx.throw(400);
}
const conversation = await ctx.db.getRepository('aiConversations').findOne({
filter: {
sessionId,
userId,
},
});
if (!conversation) {
ctx.throw(400);
}
const rows = await ctx.db.getRepository('aiConversations.messages', sessionId).find({
sort: ['-messageId'],
limit: 10,
});
ctx.body = rows.map((row: Model) => ({
messageId: row.messageId,
role: row.role,
content: {
content: row.content,
type: row.type,
},
}));
await next();
},
async sendMessages(ctx: Context, next: Next) {
const { sessionId, aiEmployee, messages } = ctx.action.params.values || {};
if (!sessionId) {
ctx.throw(400);
}
const userMessage = messages.find((message: any) => message.role === 'user');
if (!userMessage) {
ctx.throw(400);
}
const conversation = await ctx.db.getRepository('aiConversations').findOne({
filterByTk: sessionId,
});
if (!conversation) {
ctx.throw(400);
}
const employee = await ctx.db.getRepository('aiEmployees').findOne({
filter: {
username: aiEmployee,
},
});
if (!employee) {
ctx.throw(400);
}
const modelSettings = employee.modelSettings;
if (!modelSettings?.llmService) {
ctx.throw(500);
}
const service = await ctx.db.getRepository('llmServices').findOne({
filter: {
name: modelSettings.llmService,
},
});
if (!service) {
ctx.throw(500);
}
const plugin = ctx.app.pm.get('ai') as PluginAIServer;
const providerOptions = plugin.aiManager.llmProviders.get(service.provider);
if (!providerOptions) {
ctx.throw(500);
}
try {
await ctx.db.getRepository('aiConversations.messages', sessionId).create({
values: messages.map((message: any) => ({
messageId: snowflake.generate(),
role: message.role,
content: message.content.content,
type: message.content.type,
})),
});
} catch (err) {
ctx.log.error(err);
ctx.throw(500);
}
ctx.set({
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
Connection: 'keep-alive',
});
ctx.status = 200;
const userMessages = [];
for (const msg of messages) {
if (msg.role !== 'user') {
continue;
}
let content = msg.content.content;
if (msg.content.type === 'uiSchema') {
const uiSchemaRepo = ctx.db.getRepository('uiSchemas');
const schema = await uiSchemaRepo.getJsonSchema(content);
content = JSON.stringify(convertUiSchemaToJsonSchema(schema));
}
userMessages.push({
role: 'user',
content,
});
}
const msgs = [
{
role: 'system',
content: employee.about,
},
...userMessages,
];
const Provider = providerOptions.provider;
const provider = new Provider({
app: ctx.app,
serviceOptions: service.options,
chatOptions: {
...modelSettings,
messages: msgs,
},
});
const stream = await provider.stream();
let message = '';
for await (const chunk of stream) {
if (!chunk.content) {
continue;
}
message += chunk.content;
ctx.res.write(`data: ${JSON.stringify({ type: 'content', body: chunk.content })}\n\n`);
}
await ctx.db.getRepository('aiConversations.messages', sessionId).create({
values: {
messageId: snowflake.generate(),
role: aiEmployee,
content: message,
type: 'text',
},
});
ctx.res.end();
// await next();
},
},
};

View File

@ -0,0 +1,57 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
const SnowflakeId = require('snowflake-id').default;
import os from 'os';
class Snowflake {
snowflake: typeof SnowflakeId;
constructor() {
const interfaces = os.networkInterfaces();
let instanceId: number;
let hasFound = false;
for (const name of Object.keys(interfaces)) {
if (!/^(eth|en|wl)/.test(name)) {
continue;
}
const addresses = interfaces[name];
for (const addr of addresses) {
if (addr.family === 'IPv4' && !addr.internal) {
try {
const parts = addr.address.split('.').map((part) => parseInt(part, 10));
if (parts.length !== 4 || parts.some((p) => p < 0 || p > 255)) {
continue;
}
const ipNum = ((parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3]) >>> 0;
instanceId = ipNum % 100;
hasFound = true;
} catch (err) {
continue;
}
}
if (instanceId) {
break;
}
}
}
this.snowflake = new SnowflakeId({
mid: instanceId,
});
}
generate() {
return this.snowflake.generate();
}
}
export default new Snowflake();

View File

@ -0,0 +1,182 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
/**
* Formily的uiSchema转换成标准的JSON Schema
* VoidField
* @param {Object} uiSchema - Formily的表单uiSchema
* @returns {Object} JSON Schema
*/
export function convertUiSchemaToJsonSchema(uiSchema) {
// 创建基础的JSON Schema结构
const jsonSchema = {
type: 'object',
properties: {},
required: [],
};
// 递归处理UI Schema提取数据字段
function extractDataFields(schema, targetSchema) {
// 如果当前节点是数据字段非void类型
if (schema.type && schema.type !== 'void' && schema.name) {
const fieldSchema = createFieldSchema(schema);
targetSchema.properties[schema.name] = fieldSchema;
// 如果字段是必填的
if (schema.required) {
targetSchema.required.push(schema.name);
}
return;
}
// 如果是嵌套的properties对象
if (schema.properties) {
Object.keys(schema.properties).forEach((key) => {
const field = schema.properties[key];
// 如果字段有自己的name属性使用它
const fieldName = field.name || key;
// 处理数据字段
if (field.type && field.type !== 'void') {
const fieldSchema = createFieldSchema(field);
targetSchema.properties[fieldName] = fieldSchema;
// 如果字段是必填的
if (field.required) {
targetSchema.required.push(fieldName);
}
}
// 递归处理嵌套的void字段
else if (field.properties) {
extractDataFields(field, targetSchema);
}
// 特殊处理CollectionField类型
else if (field['x-component'] === 'CollectionField' && field['x-collection-field']) {
// 从x-collection-field中提取字段名
const collectionParts = field['x-collection-field'].split('.');
const fieldType = field.type || 'string';
const fieldSchema = {
type: fieldType,
title: field.title || collectionParts[collectionParts.length - 1],
};
targetSchema.properties[fieldName] = fieldSchema;
}
});
}
}
// 创建字段Schema的辅助函数
function createFieldSchema(field) {
const fieldSchema = {
title: field.title || field.name,
};
// 设置字段类型
if (field.type) {
fieldSchema.type = field.type;
} else {
// 根据组件类型推断数据类型
fieldSchema.type = inferTypeFromComponent(field['x-component']);
}
// 处理字段验证和约束
if (field['x-validator']) {
processValidator(field['x-validator'], fieldSchema);
}
// 处理字段描述
if (field.description) {
fieldSchema.description = field.description;
}
// 处理枚举值
if (field.enum) {
fieldSchema.enum = field.enum.map((item) => (typeof item === 'object' ? item.value : item));
}
// 处理默认值
if (field.default !== undefined) {
fieldSchema.default = field.default;
}
// 处理特定格式
if (field.format) {
fieldSchema.format = field.format;
}
// 处理CollectionField
if (field['x-component'] === 'CollectionField' && field['x-collection-field']) {
// 从x-collection-field中提取字段信息
const collectionParts = field['x-collection-field'].split('.');
fieldSchema.title = fieldSchema.title || collectionParts[collectionParts.length - 1];
}
return fieldSchema;
}
// 根据组件类型推断数据类型
function inferTypeFromComponent(component) {
if (!component) return 'string';
switch (component) {
case 'Input':
case 'Input.TextArea':
case 'Select':
case 'Radio':
case 'DatePicker':
case 'TimePicker':
return 'string';
case 'NumberPicker':
return 'number';
case 'Switch':
case 'Checkbox':
return 'boolean';
case 'Upload':
return 'array';
case 'CollectionField':
return 'string'; // 默认为string实际类型应取决于collection字段类型
default:
return 'string';
}
}
// 处理字段验证器
function processValidator(validator, fieldSchema) {
if (Array.isArray(validator)) {
validator.forEach((rule) => applyValidationRule(rule, fieldSchema));
} else if (typeof validator === 'object') {
applyValidationRule(validator, fieldSchema);
}
}
// 应用验证规则到字段schema
function applyValidationRule(rule, fieldSchema) {
if (rule.min !== undefined) fieldSchema.minimum = rule.min;
if (rule.max !== undefined) fieldSchema.maximum = rule.max;
if (rule.minLength !== undefined) fieldSchema.minLength = rule.minLength;
if (rule.maxLength !== undefined) fieldSchema.maxLength = rule.maxLength;
if (rule.pattern) fieldSchema.pattern = rule.pattern;
if (rule.format) fieldSchema.format = rule.format;
if (rule.required) fieldSchema.required = true;
}
// 开始转换
extractDataFields(uiSchema, jsonSchema);
// 如果没有必填字段删除required数组
if (jsonSchema.required.length === 0) {
delete jsonSchema.required;
}
return jsonSchema;
}

Some files were not shown because too many files have changed in this diff Show More