Skip to content

Commit a8d510d

Browse files
authored
Merge pull request #46 from VisActor/feat-dataAggregation-skylark
Feat data aggregation skylark
2 parents 19849ac + 31a91d5 commit a8d510d

File tree

26 files changed

+767
-298
lines changed

26 files changed

+767
-298
lines changed

common/config/rush/pnpm-lock.yaml

+21-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/vmind/__tests__/browser/src/constants/mockData.ts

+11
Original file line numberDiff line numberDiff line change
@@ -3663,3 +3663,14 @@ East Asia & Pacific,7.8,8.95,10.18,11.57,13.25
36633663
Europe & Central Asia,9.52,10.39,10.93,11.69,12.63`,
36643664
input: '看下各类别数值分布'
36653665
};
3666+
3667+
/*
3668+
* multi-measure
3669+
*/
3670+
export const mockUserInput17 = {
3671+
csv: `date,ctr,libra_ab_vid,gmv,detection_uv,User,user_count,gpm,ctcvr,version_id,co
3672+
2024-03-05,0.024752458745543306,-1,27.05042746931187,683740,31135119,683740,0.0028542157856540976,0.00011098365108464276,-1,0.01765408108609234
3673+
2024-03-06,0.025529744509421266,-1,26.0184806658061,666756,30057727,666756,0.0029282343207837846,0.00011602865071429876,-1,0.018457400571758008
3674+
2024-03-07,0.024929771518461413,-1,26.099474885828787,653568,25685979,653568,0.00305250127580487,0.00012037169363684177,-1,0.019630556105233156`,
3675+
input: '使用折线图展示'
3676+
};

packages/vmind/__tests__/browser/src/pages/DataInput.tsx

+10-9
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,13 @@ import {
3333
mockUserInput12,
3434
mockUserInput13,
3535
mockUserInput14,
36-
mockUserInput16
36+
mockUserInput16,
37+
mockUserInput17
3738
} from '../constants/mockData';
3839
import VMind from '../../../../src/index';
3940
import { Model } from '../../../../src/index';
40-
import { queryDataset } from '../../../../src/gpt/dataProcess';
4141
import { isArray } from 'lodash';
42-
import { mockDataset, mockData2 } from './mockData';
42+
import { mockDataset, mockData2, mockData3, mockData4 } from './mockData';
4343

4444
const TextArea = Input.TextArea;
4545
const Option = Select.Option;
@@ -76,11 +76,12 @@ const demoDataList: { [key: string]: any } = {
7676
'College entrance examination': acceptRatioData,
7777
'Shopping Mall Sales Performance': mallSalesData,
7878
'Global GDP': mockUserInput6Eng,
79-
'Sales of different drinkings': mockUserInput3Eng
79+
'Sales of different drinkings': mockUserInput3Eng,
80+
'Multi measure': mockUserInput17
8081
};
8182

8283
const globalVariables = (import.meta as any).env;
83-
const ModelConfigMap = {
84+
const ModelConfigMap: any = {
8485
[Model.SKYLARK2]: { url: globalVariables.VITE_SKYLARK_URL, key: globalVariables.VITE_SKYLARK_KEY },
8586
[Model.SKYLARK]: { url: globalVariables.VITE_SKYLARK_URL, key: globalVariables.VITE_SKYLARK_KEY },
8687
[Model.GPT3_5]: { url: globalVariables.VITE_GPT_URL, key: globalVariables.VITE_GPT_KEY },
@@ -95,7 +96,7 @@ export function DataInput(props: IPropsType) {
9596
const [spec, setSpec] = useState<string>('');
9697
const [time, setTime] = useState<number>(1000);
9798
const [model, setModel] = useState<Model>(Model.GPT3_5);
98-
const [cache, setCache] = useState<boolean>(false);
99+
const [cache, setCache] = useState<boolean>(true);
99100
const [showThoughts, setShowThoughts] = useState<boolean>(false);
100101
const [visible, setVisible] = React.useState(false);
101102
const [url, setUrl] = React.useState(ModelConfigMap[model]?.url ?? OPENAI_API_URL);
@@ -125,10 +126,10 @@ export function DataInput(props: IPropsType) {
125126
//const { fieldInfo: fieldInfoQuery, dataset: datasetQuery } = await vmind?.dataQuery(describe, fieldInfo, dataset);
126127
//const { fieldInfo, dataset, usage } = await vmind.parseCSVDataWithLLM(csv, describe);
127128

128-
//const dataset = mockData2
129-
//const fieldInfo = vmind?.getFieldInfo(dataset)
129+
//const dataset = mockData4;
130+
//const fieldInfo = vmind?.getFieldInfo(dataset);
130131
const startTime = new Date().getTime();
131-
const chartGenerationRes = await vmind.generateChart(describe, fieldInfo, dataset);
132+
const chartGenerationRes = await vmind.generateChart(describe, fieldInfo, dataset, true);
132133
const endTime = new Date().getTime();
133134
if (isArray(chartGenerationRes)) {
134135
props.onSpecListGenerate(chartGenerationRes.map(res => res.spec));

packages/vmind/package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@
9797
"dayjs": "~1.11.10",
9898
"js-yaml": "~4.1.0",
9999
"node-sql-parser": "~4.17.0",
100-
"@visactor/calculator": "workspace:*"
100+
"@visactor/calculator": "workspace:*",
101+
"alasql": "~4.3.2"
101102
}
102-
}
103+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { DataItem, SimpleFieldInfo } from 'src/typings';
2+
import {
3+
getValueByAttributeName,
4+
mergeMap,
5+
replaceAll,
6+
replaceDataset,
7+
replaceInvalidContent,
8+
replaceNonASCIICharacters,
9+
replaceInvalidWords,
10+
swapMap,
11+
replaceBlankSpace,
12+
replaceString,
13+
sumAllMeasureFields,
14+
convertGroupByToString
15+
} from './utils';
16+
import alasql from 'alasql';
17+
18+
export const VMIND_DATA_SOURCE = 'VMind_data_source';
19+
20+
/**
21+
* SQL query for SourceDatset
22+
* It has nothing to do with the model type model
23+
* @param sql
24+
* @param sourceDataset
25+
* @param fieldInfo
26+
* @returns dataset after query
27+
*/
28+
export const queryDataset = (sql: string, sourceDataset: DataItem[], fieldInfo: SimpleFieldInfo[]) => {
29+
const fieldNames = fieldInfo.map(field => field.fieldName);
30+
const { validStr, sqlReplaceMap, columnReplaceMap } = replaceInvalidWords(sql, fieldNames);
31+
32+
//replace field names according to replaceMap
33+
const validColumnDataset = replaceDataset(sourceDataset, columnReplaceMap, true);
34+
35+
//replace field names and data values according to replaceMap
36+
const validDataset = replaceDataset(validColumnDataset, sqlReplaceMap, false);
37+
38+
//replace blank spaces in column name
39+
const replacedFieldNames = fieldNames
40+
.map(field => replaceString(field, columnReplaceMap))
41+
.map(field => replaceString(field, sqlReplaceMap));
42+
const validSql = replaceBlankSpace(validStr, replacedFieldNames as string[]);
43+
44+
const finalSql = sumAllMeasureFields(validSql, fieldInfo, columnReplaceMap, sqlReplaceMap);
45+
//convertGroupByToString(finalSql, validDataset)
46+
47+
//replace VMIND_DATA_SOURCE with placeholder "?"
48+
const sqlParts = (finalSql + ' ').split(VMIND_DATA_SOURCE);
49+
const sqlCount = sqlParts.length - 1;
50+
const alasqlQuery = sqlParts.join('?');
51+
//do the query
52+
const alasqlDataset = alasql(alasqlQuery, new Array(sqlCount).fill(validDataset));
53+
54+
//restore the dataset
55+
const columnReversedMap = swapMap(columnReplaceMap);
56+
const columnRestoredDataset = replaceDataset(alasqlDataset, columnReversedMap, true);
57+
const sqlReversedMap = swapMap(sqlReplaceMap);
58+
const sqlRestoredDataset = replaceDataset(columnRestoredDataset, sqlReversedMap, false);
59+
60+
return sqlRestoredDataset;
61+
};

0 commit comments

Comments
 (0)