Skip to content

Commit d87a964

Browse files
leondt1xueren.dt
andauthored
fix(ava): make extract work (#835)
* fix(ava): make extract work * fix(ava): fix unit test --------- Co-authored-by: xueren.dt <xueren.dt@antgroup.com>
1 parent f0ab004 commit d87a964

20 files changed

Lines changed: 54 additions & 76 deletions

File tree

packages/ava/src/advisor/advise-chart-pipeline/plugins/advisePlugin.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export class AdvisePlugin implements AdvisorPlugin<AdviseChartParams> {
2828

2929
execute = async (input: AdviseChartPluginInput) => {
3030
const { dataStore } = input;
31-
const { dataShards } = dataStore.data;
31+
const { dataShards } = dataStore.extract;
3232
// create all valid chart configs using field data
3333
const shard = dataShards[0];
3434
if (shard.shape === DATA_SHAPE.PLAIN) {

packages/ava/src/advisor/advise-chart-pipeline/plugins/extractPlugin.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,9 @@ export class ExtractPlugin implements AdvisorPlugin<AdviseChartParams> {
1313

1414
async execute(ctx: AdviseChartPluginInput) {
1515
try {
16-
const { purpose } = ctx.context;
17-
const { data } = ctx.context;
16+
const { data, llm, purpose } = ctx.context;
1817
const input = `${purpose}\n${JSON.stringify(data)}`;
19-
const dataShards = await extractData(input);
18+
const dataShards = await extractData(input, { llmConfig: llm });
2019
ctx.dataStore.extract.dataShards = dataShards;
2120
} catch (e) {
2221
ctx.dataStore.extract.dataShards = [];

packages/ava/src/advisor/chartAdvise/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ export const optimizeChartConfig = (params: {
676676
case CHART_NAME.wordCloud: {
677677
const hasNegatives = metas.some((field) => {
678678
if (field.dataType === COLUMN_TYPE.number) {
679-
return (field.statisticsFeature as NumberColumnFeature).minimum < 0;
679+
return (field.statisticsFeature as NumberColumnFeature)?.minimum < 0;
680680
}
681681
return false;
682682
});

packages/ava/src/constants/pipeline.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
export enum AdviseChartPluginEnum {
22
ExtractPlugin = 'extractPlugin',
3-
DataPlugin = 'dataPlugin',
43
AdvisePlugin = 'advisePlugin',
54
GeneratePlugin = 'generatePlugin',
65
}

packages/ava/src/extract/extract/index.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import { requestTboxLLM } from '@ava/utils/llm';
1+
import { requestLLM } from '../../utils';
22

33
import { getExtractPrompt } from './prompt';
44

5-
import type { TboxLLM } from '@ava/types';
5+
import type { AdvisorConfig } from '../../types';
66

7-
export const extract = async (input: string, config: TboxLLM) => {
7+
export const extract = async (input: string, config: AdvisorConfig['llm']) => {
88
try {
9-
const res = await requestTboxLLM({
9+
const res = await requestLLM({
1010
config,
1111
prompt: getExtractPrompt(input),
1212
});

packages/ava/src/extract/extract/prompt.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ export const getExtractPrompt = (input: string) => {
22
return `
33
# 你是一个数据解析专家,你的任务是将用户输入的文本解析为结构化数据,并理解用户的分析意图。
44
## 通过 typescript 类型来定义输出的类型,如下:
5-
type PlainDataType = Array<Record<string, string | number>> | Array<Array<string | number>>; // 常规的二维明细数据
5+
type PlainLikeDataType = Array<Record<string, string | number>> | Array<Array<string | number>>; // 常规的二维明细数据
66
type DATA_SHAPE = 'plain' | 'graph' | 'tree' | 'flow'; // 数据形状
77
type HierarchyDataType = Array<{
88
id: string;
@@ -44,7 +44,7 @@ export const getExtractPrompt = (input: string) => {
4444
? FlowDataType
4545
: T extends 'graph'
4646
? RelationDataType
47-
: PlainDataType; // 数据类型统一定义
47+
: PlainLikeDataType; // 数据类型统一定义
4848
4949
type DataShards = Array<{
5050
shape: DATA_SHAPE;
@@ -61,10 +61,10 @@ export const getExtractPrompt = (input: string) => {
6161
purposeDesc?: string; // 分析意图的简要说明
6262
};
6363
}>;
64-
## 需要你根据用户的输入文本,解析出其中的数据,并根据用户的意图,将其转化为上述 ts 类型中的 DataShards,并用标准 JSON 输出
64+
## 需要你根据用户的输入文本,解析出其中的数据,并根据用户的意图,将其转化为上述 ts 类型中的 DataShards,并用标准 JSON 字符串输出,不要使用\`\`\`JSON等任何代码块包裹
6565
## 建议的执行步骤是
6666
### 一、分离数据和文本
67-
### 二、解析数据,判断数据形状,并将其转化为 PlainDataType、TreeDataType、GraphDataType、FlowDataType 中的一种
67+
### 二、解析数据,判断数据形状,并将其转化为 PlainLikeDataType、TreeDataType、GraphDataType、FlowDataType 中的一种
6868
### 三、理解用户意图,分析字段的名词和key,并将其转化为 DataShards 中的 purpose 信息
6969
### 四、如果用户没有意图,请根据你对这份数据的理解,拆解出一到两个分析意图,并构建 purpose 信息
7070
### 五、将数据和文本转化为 DataShards 数组结构,注意 DataShards 需要是一个数组,并用纯文本的 JSON 字符串输出

packages/ava/src/extract/features/plain.ts

Lines changed: 14 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -70,42 +70,23 @@ export function isOrdinal(info: ColumnFeature): boolean {
7070
const { rawData, recommendation } = info;
7171
if (recommendation !== COLUMN_TYPE.string) return false;
7272
if (isConst(info)) return false;
73-
const list = rawData.filter((item) => !isNil(item) && isBasicType(item));
73+
const list = rawData.filter((item) => !isNil(item) && isBasicType(item)).map((item) => `${item}`);
7474
if (list.length === 0) return false;
75-
let start: null | string = null;
76-
let end: null | string = null;
75+
// Compute common prefix and suffix lengths safely to avoid infinite loops
76+
const minLen = Math.min(...list.map((s) => s.length));
7777
let startIndex = -1;
78-
let endIndex = -1;
79-
80-
let through = true;
81-
while (through) {
82-
let through = true;
83-
for (let i = 0; i < list.length; i += 1) {
84-
const item = list[i];
85-
const char = item[startIndex + 1];
86-
if (start === null || i === 0) start = char;
87-
if (char !== start) {
88-
through = false;
89-
break;
90-
}
91-
}
92-
if (!through) break;
93-
startIndex += 1;
78+
for (let idx = 0; idx < minLen; idx += 1) {
79+
const c0 = list[0][idx];
80+
const allSame = list.every((s) => s[idx] === c0);
81+
if (!allSame) break;
82+
startIndex = idx;
9483
}
95-
through = true;
96-
while (through) {
97-
let through = true;
98-
for (let i = 0; i < list.length; i += 1) {
99-
const item = list[i];
100-
const char = item[item.length - 1 - (endIndex + 1)];
101-
if (end === null || i === 0) end = char;
102-
if (char !== end) {
103-
through = false;
104-
break;
105-
}
106-
}
107-
if (!through) break;
108-
endIndex += 1;
84+
let endIndex = -1;
85+
for (let idx = 0; idx < minLen; idx += 1) {
86+
const c0 = list[0][list[0].length - 1 - idx];
87+
const allSame = list.every((s) => s[s.length - 1 - idx] === c0);
88+
if (!allSame) break;
89+
endIndex = idx;
10990
}
11091
const patterns = [/\d+/, /(||||||||||)+/, /(||||||)/, /^[a-z]$/, /^[A-Z]$/];
11192
if (startIndex === -1 && endIndex === -1) return false;

packages/ava/src/extract/index.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,22 @@ import { extract } from '@ava/extract/extract';
99
import type {
1010
DataShard,
1111
Meta,
12-
TboxLLM,
13-
OpenAiLLM,
1412
PlainLikeDataType,
1513
HierarchyLikeDataType,
1614
RelationLikeDataType,
17-
} from '@ava/types';
15+
AdvisorConfig,
16+
} from '../types';
1817

1918
export const extractData: (
2019
input: string | Record<string, any> | Record<string, any>[],
2120
config?: {
22-
llmConfig?: TboxLLM | OpenAiLLM;
21+
llmConfig?: AdvisorConfig['llm'];
2322
}
2423
) => Promise<DataShard[]> = async (input, config) => {
2524
const shards: DataShard[] = [];
2625
if (typeof input === 'string') {
27-
const res = await extract(input, config?.llmConfig as TboxLLM);
28-
return res;
26+
const res = await extract(input, config?.llmConfig);
27+
return [res];
2928
}
3029
const inferRes = matchDataShape(input);
3130
if (inferRes.shape === DATA_SHAPE.PLAIN) {

packages/ava/src/utils/llm.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { logError, sleep } from './common';
77
import type { OpenAiLLM, TboxLLM } from '@ava/types';
88

99
const DEFAULT_MAX_RETRY_COUNT = 3;
10-
const DEFAULT_TIMEOUT = 10000;
10+
const DEFAULT_TIMEOUT = 60000;
1111
const DEFAULT_DELAY = 500;
1212

1313
/**

playground/src/examples/advise/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import { render } from '../../utils';
77
// 创建 advisor 实例并为该实例绑定渲染器
88
const advisor = new Advisor({
99
llm: {
10-
appId: '202510APxPmo00551539',
11-
authorization: 'TBox-c4ae8a71224e42baaafb1c01d15395a7',
10+
appId: '202511APkFwG00560135',
11+
authorization: 'TBox-174d46eaa4374e96b3fd99b6fec527d7',
1212
},
1313
});
1414

0 commit comments

Comments
 (0)