feat(asset-ai): add contextual analysis and unmet-demand feedback
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
export const GROUPS = [
|
||||
export const DIMENSIONS = [
|
||||
"region",
|
||||
"city",
|
||||
"type",
|
||||
"model",
|
||||
"department",
|
||||
"status",
|
||||
"none",
|
||||
] as const;
|
||||
export const GROUPS = [...DIMENSIONS, "none"] as const;
|
||||
export const CATEGORIES = [
|
||||
"all",
|
||||
"inventory",
|
||||
@@ -16,18 +16,55 @@ export const CATEGORIES = [
|
||||
"pending",
|
||||
"abnormal",
|
||||
] as const;
|
||||
export type Dimension = (typeof DIMENSIONS)[number];
|
||||
export type QueryPlan = {
|
||||
kind: "assets" | "flow" | "clarify";
|
||||
category: (typeof CATEGORIES)[number];
|
||||
groupBy: (typeof GROUPS)[number];
|
||||
secondaryGroupBy?: Dimension;
|
||||
view: "chart" | "table" | "list";
|
||||
filters: Partial<
|
||||
Record<"region" | "city" | "type" | "model" | "department", string>
|
||||
>;
|
||||
analysis?: "distribution" | "compare" | "exceptions";
|
||||
filters: Partial<Record<Dimension, string[]>>;
|
||||
start?: string;
|
||||
end?: string;
|
||||
comparePrevious?: boolean;
|
||||
exception?: "overdue" | "dueSoon" | "missingDueDate";
|
||||
topN?: number;
|
||||
sortBy?: "count" | "rate" | "abnormal" | "pending";
|
||||
sortOrder?: "asc" | "desc";
|
||||
vehicleIds?: string[];
|
||||
excludeFilters?: Partial<Record<Dimension, string[]>>;
|
||||
clarification?: string;
|
||||
};
|
||||
export type AssistantAction =
|
||||
| { type: "drill"; keys: Partial<Record<Dimension, string>> }
|
||||
| {
|
||||
type: "group";
|
||||
groupBy: QueryPlan["groupBy"];
|
||||
secondaryGroupBy?: Dimension;
|
||||
}
|
||||
| { type: "category"; category: QueryPlan["category"] }
|
||||
| { type: "analysis"; analysis: NonNullable<QueryPlan["analysis"]> }
|
||||
| { type: "view"; view: QueryPlan["view"] }
|
||||
| { type: "day"; date: string }
|
||||
| { type: "compare-period" }
|
||||
| { type: "exception"; exception: "overdue" }
|
||||
| { type: "restore" }
|
||||
| { type: "clear-filter"; dimension: Dimension }
|
||||
| { type: "reset-filters" }
|
||||
| {
|
||||
type: "sort";
|
||||
sortBy: "count" | "rate" | "abnormal" | "pending";
|
||||
sortOrder: "asc" | "desc";
|
||||
topN?: number;
|
||||
};
|
||||
export type AssistantRequest = {
|
||||
message?: string;
|
||||
subject: string | null;
|
||||
sessionId?: string;
|
||||
baseResultId?: string;
|
||||
action?: AssistantAction;
|
||||
};
|
||||
export type AssistantRow = {
|
||||
id: string;
|
||||
plate: string;
|
||||
@@ -37,6 +74,12 @@ export type AssistantRow = {
|
||||
city: string;
|
||||
department: string;
|
||||
status: string;
|
||||
inventory?: boolean;
|
||||
abnormal?: boolean;
|
||||
pending?: boolean;
|
||||
abnormalType?: string;
|
||||
targetCompletionTime?: string;
|
||||
actualCompletionTime?: string;
|
||||
date?: string;
|
||||
event?: string;
|
||||
};
|
||||
@@ -45,16 +88,77 @@ export type AssistantGroup = {
|
||||
count: number;
|
||||
operating: number;
|
||||
rate: number;
|
||||
keys?: Partial<Record<Dimension, string>>;
|
||||
abnormal?: number;
|
||||
pending?: number;
|
||||
share?: number;
|
||||
};
|
||||
export const GAP_REASONS = {
|
||||
unrecognized: "未识别需求",
|
||||
unsupported: "暂不支持",
|
||||
privacy: "输入未通过安全检查",
|
||||
generation: "生成失败",
|
||||
empty: "无匹配数据",
|
||||
unsatisfied: "用户标记未解决",
|
||||
} as const;
|
||||
export type GapReason = keyof typeof GAP_REASONS;
|
||||
export const GAP_STATUSES = {
|
||||
open: "待评估",
|
||||
planned: "已纳入计划",
|
||||
resolved: "已解决",
|
||||
dismissed: "暂不处理",
|
||||
} as const;
|
||||
export type GapStatus = keyof typeof GAP_STATUSES;
|
||||
export type DemandGap = {
|
||||
id: number;
|
||||
demand: string;
|
||||
reason: GapReason;
|
||||
status: GapStatus;
|
||||
occurrences: number;
|
||||
firstSeen: string;
|
||||
lastSeen: string;
|
||||
};
|
||||
export type AssistantResult = {
|
||||
plan: QueryPlan;
|
||||
answerKind?: "analysis" | "clarification" | "help";
|
||||
engine?: "deepseek" | "local";
|
||||
suggestions?: string[];
|
||||
interpretation?: string;
|
||||
contextNote?: string;
|
||||
title: string;
|
||||
summary: string;
|
||||
source: string;
|
||||
fetchedAt: string;
|
||||
sessionId?: string;
|
||||
resultId?: string;
|
||||
breadcrumbs?: { resultId: string; label: string }[];
|
||||
groups: AssistantGroup[];
|
||||
rows: AssistantRow[];
|
||||
metrics: { label: string; value: number; unit: string }[];
|
||||
insights?: string[];
|
||||
exceptions?: {
|
||||
label: string;
|
||||
count: number;
|
||||
category?: QueryPlan["category"];
|
||||
}[];
|
||||
comparison?: {
|
||||
label: string;
|
||||
current: number;
|
||||
previous: number;
|
||||
delta: number;
|
||||
rate: number | null;
|
||||
}[];
|
||||
groupComparison?: {
|
||||
baseline: string;
|
||||
rows: {
|
||||
name: string;
|
||||
count: number;
|
||||
delta: number;
|
||||
share: number;
|
||||
rateDelta: number;
|
||||
}[];
|
||||
};
|
||||
comparisonPeriod?: { start: string; end: string };
|
||||
daily?: {
|
||||
date: string;
|
||||
delivered: number;
|
||||
@@ -63,9 +167,11 @@ export type AssistantResult = {
|
||||
total: number;
|
||||
}[];
|
||||
warning?: string;
|
||||
gap?: { recorded: boolean; reason: GapReason; demand: string };
|
||||
};
|
||||
export type AssistantEvent =
|
||||
| { type: "step"; label: string }
|
||||
| { type: "answer"; text: string }
|
||||
| { type: "result"; result: AssistantResult }
|
||||
| { type: "error"; message: string };
|
||||
export const GROUP_LABELS: Record<QueryPlan["groupBy"], string> = {
|
||||
|
||||
Reference in New Issue
Block a user