feat: ai employees
@ -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',
|
||||
|
@ -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',
|
||||
|
@ -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',
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
@ -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 };
|
||||
};
|
@ -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$/,
|
||||
});
|
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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>
|
||||
);
|
||||
};
|
@ -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>
|
||||
);
|
||||
};
|
@ -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>
|
||||
);
|
||||
};
|
@ -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 |
@ -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 |
@ -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 |
@ -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>
|
||||
);
|
||||
};
|
@ -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,
|
||||
};
|
||||
},
|
||||
}));
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
@ -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)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
@ -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 employee’s 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 employee’s 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>
|
||||
);
|
||||
};
|
@ -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' },
|
||||
);
|
@ -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',
|
||||
},
|
||||
],
|
||||
});
|
@ -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: {
|
||||
|
@ -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';
|
||||
|
@ -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' }] },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
@ -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),
|
||||
},
|
||||
);
|
||||
|
@ -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',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
@ -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',
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
@ -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',
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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 }) {
|
||||
|
@ -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',
|
||||
},
|
||||
],
|
||||
};
|
@ -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 }}"
|
||||
}
|
||||
|
@ -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);
|
||||
});
|
@ -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! I’m 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);
|
||||
});
|
@ -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 {};
|
@ -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',
|
||||
},
|
||||
],
|
||||
});
|
@ -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,
|
||||
});
|
@ -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',
|
||||
},
|
||||
],
|
||||
});
|
@ -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;
|
||||
|
@ -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');
|
||||
|
@ -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();
|
||||
},
|
||||
},
|
||||
};
|
57
packages/plugins/@nocobase/plugin-ai/src/server/snowflake.ts
Normal 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();
|
182
packages/plugins/@nocobase/plugin-ai/src/server/utils.ts
Normal 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;
|
||||
}
|