mirror of
https://github.com/Canner/WrenAI.git
synced 2026-09-24 23:29:49 +08:00
chore(wren-ui): Remove candidate summary & add correcting state to prompt (#913)
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* @param { import("knex").Knex } knex
|
||||
* @returns { Promise<void> }
|
||||
*/
|
||||
exports.up = function (knex) {
|
||||
return knex.schema.alterTable('thread_response', function (table) {
|
||||
table.dropColumn('summary');
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param { import("knex").Knex } knex
|
||||
* @returns { Promise<void> }
|
||||
*/
|
||||
exports.down = function (knex) {
|
||||
return knex.schema.alterTable('thread_response', function (table) {
|
||||
table
|
||||
.string('summary')
|
||||
.nullable()
|
||||
.comment('the summary of the thread response');
|
||||
});
|
||||
};
|
||||
@@ -28,6 +28,7 @@ export type AskingTaskInput = {
|
||||
};
|
||||
|
||||
export enum AskingTaskStatus {
|
||||
CORRECTING = 'CORRECTING',
|
||||
FAILED = 'FAILED',
|
||||
FINISHED = 'FINISHED',
|
||||
GENERATING = 'GENERATING',
|
||||
@@ -98,14 +99,12 @@ export type CreateSimpleMetricInput = {
|
||||
export type CreateThreadInput = {
|
||||
question?: InputMaybe<Scalars['String']>;
|
||||
sql?: InputMaybe<Scalars['String']>;
|
||||
summary?: InputMaybe<Scalars['String']>;
|
||||
viewId?: InputMaybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
export type CreateThreadResponseInput = {
|
||||
question?: InputMaybe<Scalars['String']>;
|
||||
sql?: InputMaybe<Scalars['String']>;
|
||||
summary?: InputMaybe<Scalars['String']>;
|
||||
viewId?: InputMaybe<Scalars['Int']>;
|
||||
};
|
||||
|
||||
@@ -234,7 +233,6 @@ export type DetailedThread = {
|
||||
responses: Array<ThreadResponse>;
|
||||
/** @deprecated Doesn't seem to be reasonable to put a sql in a thread */
|
||||
sql: Scalars['String'];
|
||||
summary: Scalars['String'];
|
||||
};
|
||||
|
||||
export type Diagram = {
|
||||
@@ -849,7 +847,6 @@ export type ResolveSchemaChangeWhereInput = {
|
||||
export type ResultCandidate = {
|
||||
__typename?: 'ResultCandidate';
|
||||
sql: Scalars['String'];
|
||||
summary: Scalars['String'];
|
||||
type: ResultCandidateType;
|
||||
view?: Maybe<ViewInfo>;
|
||||
};
|
||||
@@ -955,7 +952,6 @@ export type ThreadResponse = {
|
||||
id: Scalars['Int'];
|
||||
question: Scalars['String'];
|
||||
status: AskingTaskStatus;
|
||||
summary: Scalars['String'];
|
||||
};
|
||||
|
||||
export type ThreadResponseDetail = {
|
||||
|
||||
@@ -5,7 +5,7 @@ import * as Apollo from '@apollo/client';
|
||||
const defaultOptions = {} as const;
|
||||
export type CommonErrorFragment = { __typename?: 'Error', code?: string | null, shortMessage?: string | null, message?: string | null, stacktrace?: Array<string | null> | null };
|
||||
|
||||
export type CommonResponseFragment = { __typename?: 'ThreadResponse', id: number, question: string, summary: string, status: Types.AskingTaskStatus, detail?: { __typename?: 'ThreadResponseDetail', sql?: string | null, description?: string | null, steps: Array<{ __typename?: 'DetailStep', summary: string, sql: string, cteName?: string | null }>, view?: { __typename?: 'ViewInfo', id: number, name: string, statement: string, displayName: string } | null } | null };
|
||||
export type CommonResponseFragment = { __typename?: 'ThreadResponse', id: number, question: string, status: Types.AskingTaskStatus, detail?: { __typename?: 'ThreadResponseDetail', sql?: string | null, description?: string | null, steps: Array<{ __typename?: 'DetailStep', summary: string, sql: string, cteName?: string | null }>, view?: { __typename?: 'ViewInfo', id: number, name: string, statement: string, displayName: string } | null } | null };
|
||||
|
||||
export type SuggestedQuestionsQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
||||
|
||||
@@ -17,7 +17,7 @@ export type AskingTaskQueryVariables = Types.Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type AskingTaskQuery = { __typename?: 'Query', askingTask: { __typename?: 'AskingTask', status: Types.AskingTaskStatus, type?: Types.AskingTaskType | null, candidates: Array<{ __typename?: 'ResultCandidate', sql: string, summary: string, type: Types.ResultCandidateType, view?: { __typename?: 'ViewInfo', id: number, name: string, statement: string, displayName: string } | null }>, error?: { __typename?: 'Error', code?: string | null, shortMessage?: string | null, message?: string | null, stacktrace?: Array<string | null> | null } | null } };
|
||||
export type AskingTaskQuery = { __typename?: 'Query', askingTask: { __typename?: 'AskingTask', status: Types.AskingTaskStatus, type?: Types.AskingTaskType | null, candidates: Array<{ __typename?: 'ResultCandidate', sql: string, type: Types.ResultCandidateType, view?: { __typename?: 'ViewInfo', id: number, name: string, statement: string, displayName: string } | null }>, error?: { __typename?: 'Error', code?: string | null, shortMessage?: string | null, message?: string | null, stacktrace?: Array<string | null> | null } | null } };
|
||||
|
||||
export type ThreadsQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
||||
|
||||
@@ -29,14 +29,14 @@ export type ThreadQueryVariables = Types.Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type ThreadQuery = { __typename?: 'Query', thread: { __typename?: 'DetailedThread', id: number, sql: string, summary: string, responses: Array<{ __typename?: 'ThreadResponse', id: number, question: string, summary: string, status: Types.AskingTaskStatus, error?: { __typename?: 'Error', code?: string | null, shortMessage?: string | null, message?: string | null, stacktrace?: Array<string | null> | null } | null, detail?: { __typename?: 'ThreadResponseDetail', sql?: string | null, description?: string | null, steps: Array<{ __typename?: 'DetailStep', summary: string, sql: string, cteName?: string | null }>, view?: { __typename?: 'ViewInfo', id: number, name: string, statement: string, displayName: string } | null } | null }> } };
|
||||
export type ThreadQuery = { __typename?: 'Query', thread: { __typename?: 'DetailedThread', id: number, sql: string, responses: Array<{ __typename?: 'ThreadResponse', id: number, question: string, status: Types.AskingTaskStatus, error?: { __typename?: 'Error', code?: string | null, shortMessage?: string | null, message?: string | null, stacktrace?: Array<string | null> | null } | null, detail?: { __typename?: 'ThreadResponseDetail', sql?: string | null, description?: string | null, steps: Array<{ __typename?: 'DetailStep', summary: string, sql: string, cteName?: string | null }>, view?: { __typename?: 'ViewInfo', id: number, name: string, statement: string, displayName: string } | null } | null }> } };
|
||||
|
||||
export type ThreadResponseQueryVariables = Types.Exact<{
|
||||
responseId: Types.Scalars['Int'];
|
||||
}>;
|
||||
|
||||
|
||||
export type ThreadResponseQuery = { __typename?: 'Query', threadResponse: { __typename?: 'ThreadResponse', id: number, question: string, summary: string, status: Types.AskingTaskStatus, error?: { __typename?: 'Error', code?: string | null, shortMessage?: string | null, message?: string | null, stacktrace?: Array<string | null> | null } | null, detail?: { __typename?: 'ThreadResponseDetail', sql?: string | null, description?: string | null, steps: Array<{ __typename?: 'DetailStep', summary: string, sql: string, cteName?: string | null }>, view?: { __typename?: 'ViewInfo', id: number, name: string, statement: string, displayName: string } | null } | null } };
|
||||
export type ThreadResponseQuery = { __typename?: 'Query', threadResponse: { __typename?: 'ThreadResponse', id: number, question: string, status: Types.AskingTaskStatus, error?: { __typename?: 'Error', code?: string | null, shortMessage?: string | null, message?: string | null, stacktrace?: Array<string | null> | null } | null, detail?: { __typename?: 'ThreadResponseDetail', sql?: string | null, description?: string | null, steps: Array<{ __typename?: 'DetailStep', summary: string, sql: string, cteName?: string | null }>, view?: { __typename?: 'ViewInfo', id: number, name: string, statement: string, displayName: string } | null } | null } };
|
||||
|
||||
export type CreateAskingTaskMutationVariables = Types.Exact<{
|
||||
data: Types.AskingTaskInput;
|
||||
@@ -57,7 +57,7 @@ export type CreateThreadMutationVariables = Types.Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type CreateThreadMutation = { __typename?: 'Mutation', createThread: { __typename?: 'Thread', id: number, sql: string, summary: string } };
|
||||
export type CreateThreadMutation = { __typename?: 'Mutation', createThread: { __typename?: 'Thread', id: number, sql: string } };
|
||||
|
||||
export type CreateThreadResponseMutationVariables = Types.Exact<{
|
||||
threadId: Types.Scalars['Int'];
|
||||
@@ -65,7 +65,7 @@ export type CreateThreadResponseMutationVariables = Types.Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type CreateThreadResponseMutation = { __typename?: 'Mutation', createThreadResponse: { __typename?: 'ThreadResponse', id: number, question: string, summary: string, status: Types.AskingTaskStatus, error?: { __typename?: 'Error', code?: string | null, shortMessage?: string | null, message?: string | null, stacktrace?: Array<string | null> | null } | null, detail?: { __typename?: 'ThreadResponseDetail', sql?: string | null, description?: string | null, steps: Array<{ __typename?: 'DetailStep', summary: string, sql: string, cteName?: string | null }>, view?: { __typename?: 'ViewInfo', id: number, name: string, statement: string, displayName: string } | null } | null } };
|
||||
export type CreateThreadResponseMutation = { __typename?: 'Mutation', createThreadResponse: { __typename?: 'ThreadResponse', id: number, question: string, status: Types.AskingTaskStatus, error?: { __typename?: 'Error', code?: string | null, shortMessage?: string | null, message?: string | null, stacktrace?: Array<string | null> | null } | null, detail?: { __typename?: 'ThreadResponseDetail', sql?: string | null, description?: string | null, steps: Array<{ __typename?: 'DetailStep', summary: string, sql: string, cteName?: string | null }>, view?: { __typename?: 'ViewInfo', id: number, name: string, statement: string, displayName: string } | null } | null } };
|
||||
|
||||
export type UpdateThreadMutationVariables = Types.Exact<{
|
||||
where: Types.ThreadUniqueWhereInput;
|
||||
@@ -122,7 +122,6 @@ export const CommonResponseFragmentDoc = gql`
|
||||
fragment CommonResponse on ThreadResponse {
|
||||
id
|
||||
question
|
||||
summary
|
||||
status
|
||||
detail {
|
||||
sql
|
||||
@@ -185,7 +184,6 @@ export const AskingTaskDocument = gql`
|
||||
type
|
||||
candidates {
|
||||
sql
|
||||
summary
|
||||
type
|
||||
view {
|
||||
id
|
||||
@@ -268,7 +266,6 @@ export const ThreadDocument = gql`
|
||||
thread(threadId: $threadId) {
|
||||
id
|
||||
sql
|
||||
summary
|
||||
responses {
|
||||
...CommonResponse
|
||||
error {
|
||||
@@ -415,7 +412,6 @@ export const CreateThreadDocument = gql`
|
||||
createThread(data: $data) {
|
||||
id
|
||||
sql
|
||||
summary
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -13,7 +13,6 @@ const COMMON_RESPONSE = gql`
|
||||
fragment CommonResponse on ThreadResponse {
|
||||
id
|
||||
question
|
||||
summary
|
||||
status
|
||||
detail {
|
||||
sql
|
||||
@@ -51,7 +50,6 @@ export const ASKING_TASK = gql`
|
||||
type
|
||||
candidates {
|
||||
sql
|
||||
summary
|
||||
type
|
||||
view {
|
||||
id
|
||||
@@ -82,7 +80,6 @@ export const THREAD = gql`
|
||||
thread(threadId: $threadId) {
|
||||
id
|
||||
sql
|
||||
summary
|
||||
responses {
|
||||
...CommonResponse
|
||||
error {
|
||||
@@ -127,7 +124,6 @@ export const CREATE_THREAD = gql`
|
||||
createThread(data: $data) {
|
||||
id
|
||||
sql
|
||||
summary
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -34,7 +34,7 @@ export interface IWrenAIAdaptor {
|
||||
|
||||
/**
|
||||
* Ask AI service a question.
|
||||
* AI service will return anwser candidates containing sql and summary.
|
||||
* AI service will return anwser candidates containing sql.
|
||||
* 1. use ask() to ask a question, AI service will return a queryId
|
||||
* 2. use getAskResult() to get the result of the queryId
|
||||
* 3. use cancelAsk() to cancel the query
|
||||
@@ -72,7 +72,7 @@ export class WrenAIAdaptor implements IWrenAIAdaptor {
|
||||
|
||||
/**
|
||||
* Ask AI service a question.
|
||||
* AI service will return anwser candidates containing sql and summary.
|
||||
* AI service will return anwser candidates containing sql.
|
||||
*/
|
||||
|
||||
public async ask(input: AskInput): Promise<AsyncQueryResponse> {
|
||||
@@ -307,7 +307,6 @@ export class WrenAIAdaptor implements IWrenAIAdaptor {
|
||||
const candidates = (body?.response || []).map((candidate: any) => ({
|
||||
type: candidate?.type?.toUpperCase() as AskCandidateType,
|
||||
sql: candidate.sql,
|
||||
summary: candidate.summary,
|
||||
viewId: candidate?.viewId ? Number(candidate.viewId) : null,
|
||||
}));
|
||||
|
||||
|
||||
@@ -50,7 +50,6 @@ export interface AskStep {
|
||||
|
||||
export interface AskHistory {
|
||||
sql: string;
|
||||
summary: string;
|
||||
steps: Array<AskStep>;
|
||||
}
|
||||
|
||||
@@ -73,6 +72,7 @@ export enum AskResultStatus {
|
||||
UNDERSTANDING = 'UNDERSTANDING',
|
||||
SEARCHING = 'SEARCHING',
|
||||
GENERATING = 'GENERATING',
|
||||
CORRECTING = 'CORRECTING',
|
||||
FINISHED = 'FINISHED',
|
||||
FAILED = 'FAILED',
|
||||
STOPPED = 'STOPPED',
|
||||
@@ -101,7 +101,6 @@ export interface AskResponse<R, S> {
|
||||
export interface AskDetailInput {
|
||||
query: string;
|
||||
sql: string;
|
||||
summary: string;
|
||||
configurations?: AskConfigurations;
|
||||
}
|
||||
|
||||
@@ -117,7 +116,6 @@ export type AskResult = AskResponse<
|
||||
Array<{
|
||||
type: AskCandidateType;
|
||||
sql: string;
|
||||
summary: string;
|
||||
viewId?: number | null;
|
||||
}>,
|
||||
AskResultStatus
|
||||
|
||||
@@ -24,14 +24,12 @@ export interface ThreadResponse {
|
||||
threadId: number; // Reference to thread.id
|
||||
queryId: string; // Thread response query ID
|
||||
question: string; // Thread response question
|
||||
summary: string; // Summary comes from the user's original question
|
||||
status: string; // Thread response status
|
||||
detail: ThreadResponseDetail; // Thread response detail
|
||||
error: object; // Thread response error
|
||||
}
|
||||
|
||||
export interface ThreadResponseWithThreadContext extends ThreadResponse {
|
||||
threadSummary: string; // Thread summary is generated by AI first, and can be updated by the user
|
||||
sql: string;
|
||||
}
|
||||
|
||||
@@ -55,7 +53,6 @@ export class ThreadResponseRepository
|
||||
const query = this.knex(this.tableName)
|
||||
.select('thread_response.*')
|
||||
.select('thread.sql as sql')
|
||||
.select('thread.summary as thread_summary')
|
||||
.where({ thread_id: threadId })
|
||||
.leftJoin('thread', 'thread.id', 'thread_response.thread_id');
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@ export interface AskingTask {
|
||||
status: AskResultStatus;
|
||||
candidates: Array<{
|
||||
sql: string;
|
||||
summary: string;
|
||||
}>;
|
||||
error: WrenAIError | null;
|
||||
}
|
||||
@@ -50,7 +49,6 @@ export interface AskingTask {
|
||||
export interface DetailedThread {
|
||||
id: number; // ID
|
||||
sql: string; // SQL
|
||||
summary: string; // Thread summary
|
||||
responses: ThreadResponse[];
|
||||
}
|
||||
|
||||
@@ -207,7 +205,6 @@ export class AskingResolver {
|
||||
return {
|
||||
type: response.type,
|
||||
sql: response.sql,
|
||||
summary: response.summary,
|
||||
view,
|
||||
};
|
||||
}),
|
||||
@@ -227,7 +224,6 @@ export class AskingResolver {
|
||||
data: {
|
||||
question?: string;
|
||||
sql?: string;
|
||||
summary?: string;
|
||||
viewId?: number;
|
||||
};
|
||||
},
|
||||
@@ -272,20 +268,12 @@ export class AskingResolver {
|
||||
if (!acc.id) {
|
||||
acc.id = response.threadId;
|
||||
acc.sql = response.sql;
|
||||
acc.summary = response.threadSummary;
|
||||
acc.responses = [];
|
||||
}
|
||||
|
||||
acc.responses.push({
|
||||
id: response.id,
|
||||
question: response.question,
|
||||
|
||||
// we added summary in version 0.3.0.
|
||||
// if summary is not available, we use description and question instead.
|
||||
summary:
|
||||
response.summary ||
|
||||
response.detail?.description ||
|
||||
response.question,
|
||||
status: response.status,
|
||||
detail: response.detail,
|
||||
error: response.error,
|
||||
@@ -357,7 +345,6 @@ export class AskingResolver {
|
||||
data: {
|
||||
question?: string;
|
||||
sql?: string;
|
||||
summary?: string;
|
||||
viewId?: number;
|
||||
};
|
||||
},
|
||||
@@ -395,13 +382,7 @@ export class AskingResolver {
|
||||
const askingService = ctx.askingService;
|
||||
const response = await askingService.getResponse(responseId);
|
||||
|
||||
// we added summary in version 0.3.0.
|
||||
// if summary is not available, we use description and question instead.
|
||||
return {
|
||||
...response,
|
||||
summary:
|
||||
response.summary || response.detail?.description || response.question,
|
||||
};
|
||||
return response;
|
||||
}
|
||||
|
||||
public async previewData(
|
||||
|
||||
@@ -842,7 +842,6 @@ export class ModelResolver {
|
||||
// properties from the thread response
|
||||
responseId, // helpful for mapping back to the thread response
|
||||
question: response.question,
|
||||
summary: response.summary,
|
||||
// detail is not going to send to AI service for indexing, but useful if we want display on UI
|
||||
detail: response.detail,
|
||||
};
|
||||
|
||||
@@ -537,6 +537,7 @@ export const typeDefs = gql`
|
||||
UNDERSTANDING
|
||||
SEARCHING
|
||||
GENERATING
|
||||
CORRECTING
|
||||
FINISHED
|
||||
FAILED
|
||||
STOPPED
|
||||
@@ -556,7 +557,6 @@ export const typeDefs = gql`
|
||||
type ResultCandidate {
|
||||
type: ResultCandidateType!
|
||||
sql: String!
|
||||
summary: String!
|
||||
view: ViewInfo
|
||||
}
|
||||
|
||||
@@ -594,14 +594,12 @@ export const typeDefs = gql`
|
||||
input CreateThreadInput {
|
||||
question: String
|
||||
sql: String
|
||||
summary: String
|
||||
viewId: Int
|
||||
}
|
||||
|
||||
input CreateThreadResponseInput {
|
||||
question: String
|
||||
sql: String
|
||||
summary: String
|
||||
viewId: Int
|
||||
}
|
||||
|
||||
@@ -638,7 +636,6 @@ export const typeDefs = gql`
|
||||
type ThreadResponse {
|
||||
id: Int!
|
||||
question: String!
|
||||
summary: String!
|
||||
status: AskingTaskStatus!
|
||||
detail: ThreadResponseDetail
|
||||
error: Error
|
||||
@@ -661,7 +658,6 @@ export const typeDefs = gql`
|
||||
@deprecated(
|
||||
reason: "Doesn't seem to be reasonable to put a sql in a thread"
|
||||
)
|
||||
summary: String!
|
||||
responses: [ThreadResponse!]!
|
||||
}
|
||||
|
||||
|
||||
@@ -51,10 +51,13 @@ export interface AskingTaskInput {
|
||||
export interface AskingDetailTaskInput {
|
||||
question?: string;
|
||||
sql?: string;
|
||||
summary?: string;
|
||||
viewId?: number;
|
||||
}
|
||||
|
||||
export interface AskingDetailTaskUpdateInput {
|
||||
summary?: string;
|
||||
}
|
||||
|
||||
export enum RecommendQuestionResultStatus {
|
||||
NOT_STARTED = 'NOT_STARTED',
|
||||
GENERATING = 'GENERATING',
|
||||
@@ -92,7 +95,7 @@ export interface IAskingService {
|
||||
): Promise<Thread>;
|
||||
updateThread(
|
||||
threadId: number,
|
||||
input: Partial<AskingDetailTaskInput>,
|
||||
input: Partial<AskingDetailTaskUpdateInput>,
|
||||
): Promise<Thread>;
|
||||
deleteThread(threadId: number): Promise<void>;
|
||||
listThreads(): Promise<Thread[]>;
|
||||
@@ -460,7 +463,7 @@ export class AskingService implements IAskingService {
|
||||
const deployId = await this.getDeployId();
|
||||
|
||||
// if it's a follow-up question, then the input will have a threadId
|
||||
// then use the threadId to get the sql, summary and get the steps of last thread response
|
||||
// then use the threadId to get the sql and get the steps of last thread response
|
||||
// construct it into AskHistory and pass to ask
|
||||
const history: AskHistory = threadId
|
||||
? await this.getHistory(threadId)
|
||||
@@ -514,7 +517,6 @@ export class AskingService implements IAskingService {
|
||||
const response = await this.wrenAIAdaptor.generateAskDetail({
|
||||
query: input.question,
|
||||
sql: input.sql,
|
||||
summary: input.summary,
|
||||
configurations: { language },
|
||||
});
|
||||
|
||||
@@ -523,15 +525,13 @@ export class AskingService implements IAskingService {
|
||||
const thread = await this.threadRepository.createOne({
|
||||
projectId: id,
|
||||
sql: input.sql,
|
||||
summary: input.summary,
|
||||
summary: input.question,
|
||||
});
|
||||
|
||||
// in follow-up questions, we still need to save the summary
|
||||
const threadResponse = await this.threadResponseRepository.createOne({
|
||||
threadId: thread.id,
|
||||
queryId: response.queryId,
|
||||
question: input.question,
|
||||
summary: input.summary,
|
||||
status: AskResultStatus.UNDERSTANDING,
|
||||
});
|
||||
|
||||
@@ -549,7 +549,7 @@ export class AskingService implements IAskingService {
|
||||
|
||||
public async updateThread(
|
||||
threadId: number,
|
||||
input: Partial<AskingDetailTaskInput>,
|
||||
input: Partial<AskingDetailTaskUpdateInput>,
|
||||
): Promise<Thread> {
|
||||
// if input is empty, throw error
|
||||
if (isEmpty(input)) {
|
||||
@@ -594,18 +594,15 @@ export class AskingService implements IAskingService {
|
||||
const response = await this.wrenAIAdaptor.generateAskDetail({
|
||||
query: input.question,
|
||||
sql: input.sql,
|
||||
summary: input.summary,
|
||||
configurations: { language },
|
||||
});
|
||||
|
||||
// 2. create a thread and the first thread response
|
||||
// in follow-up questions, we still need to save the summary
|
||||
// insert question first, another API all the asked questions to generate the next recommendation questions
|
||||
const threadResponse = await this.threadResponseRepository.createOne({
|
||||
threadId: thread.id,
|
||||
queryId: response.queryId,
|
||||
question: input.question,
|
||||
summary: input.summary,
|
||||
status: AskResultStatus.UNDERSTANDING,
|
||||
});
|
||||
|
||||
@@ -718,7 +715,6 @@ export class AskingService implements IAskingService {
|
||||
const latestResponse = responses[0];
|
||||
return {
|
||||
sql: latestResponse.sql,
|
||||
summary: latestResponse.summary,
|
||||
steps: latestResponse.detail.steps,
|
||||
};
|
||||
}
|
||||
@@ -747,7 +743,6 @@ export class AskingService implements IAskingService {
|
||||
threadId: thread.id,
|
||||
queryId: QUERY_ID_PLACEHOLDER,
|
||||
question: properties.question,
|
||||
summary: properties.summary,
|
||||
status: AskResultStatus.FINISHED,
|
||||
detail: {
|
||||
...properties.detail,
|
||||
|
||||
@@ -41,7 +41,7 @@ interface Props {
|
||||
recommendedQuestions: RecommendedQuestionsTask;
|
||||
};
|
||||
error?: any;
|
||||
onSelectResult: (payload: { sql: string; summary: string }) => void;
|
||||
onSelectResult: (payload: { sql: string }) => void;
|
||||
onSelectQuestion: (question: string) => void;
|
||||
onClose: () => void;
|
||||
onStop: () => void;
|
||||
@@ -160,8 +160,7 @@ const Finished = (props: Props) => {
|
||||
useEffect(() => {
|
||||
if (candidates.length) {
|
||||
const [result] = candidates;
|
||||
onSelectResult &&
|
||||
onSelectResult({ sql: result.sql, summary: result.summary });
|
||||
onSelectResult && onSelectResult({ sql: result.sql });
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ import {
|
||||
interface Props {
|
||||
onSelect: (payload: {
|
||||
sql?: string;
|
||||
summary?: string;
|
||||
question?: string;
|
||||
viewId?: number;
|
||||
}) => Promise<void>;
|
||||
@@ -63,6 +62,8 @@ const convertAskingTaskToProcessState = (data: AskingTask) => {
|
||||
[AskingTaskStatus.UNDERSTANDING]: PROCESS_STATE.UNDERSTANDING,
|
||||
[AskingTaskStatus.SEARCHING]: PROCESS_STATE.SEARCHING,
|
||||
[AskingTaskStatus.GENERATING]: PROCESS_STATE.GENERATING,
|
||||
// Show generating state component when AI correcting
|
||||
[AskingTaskStatus.CORRECTING]: PROCESS_STATE.GENERATING,
|
||||
[AskingTaskStatus.FINISHED]: PROCESS_STATE.FINISHED,
|
||||
}[data.status];
|
||||
|
||||
@@ -147,7 +148,6 @@ export default forwardRef<Attributes, Props>(function Prompt(props, ref) {
|
||||
} else if (question) {
|
||||
data = {
|
||||
sql: payload.sql,
|
||||
summary: payload.summary,
|
||||
question,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { useState } from 'react';
|
||||
import clsx from 'clsx';
|
||||
import Link from 'next/link';
|
||||
import { Col, Button, Row, Skeleton, Typography } from 'antd';
|
||||
import { Button, Skeleton, Typography, Alert } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
import { Path } from '@/utils/enum';
|
||||
import CheckCircleFilled from '@ant-design/icons/CheckCircleFilled';
|
||||
import QuestionCircleOutlined from '@ant-design/icons/QuestionCircleOutlined';
|
||||
import MessageOutlined from '@ant-design/icons/MessageOutlined';
|
||||
import SaveOutlined from '@ant-design/icons/SaveOutlined';
|
||||
import FileDoneOutlined from '@ant-design/icons/FileDoneOutlined';
|
||||
import StepContent from '@/components/pages/home/promptThread/StepContent';
|
||||
import { getIsFinished } from '@/hooks/useAskPrompt';
|
||||
import { ThreadResponse } from '@/apollo/client/graphql/__types__';
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
|
||||
@@ -25,20 +27,6 @@ const StyledAnswer = styled(Typography)`
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledQuestion = styled(Row)`
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
color: var(--gray-6);
|
||||
background-color: var(--gray-3);
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--gray-4) !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledSkeleton = styled(Skeleton)`
|
||||
.ant-skeleton-title {
|
||||
margin-top: 0;
|
||||
@@ -47,116 +35,111 @@ const StyledSkeleton = styled(Skeleton)`
|
||||
|
||||
interface Props {
|
||||
motion: boolean;
|
||||
loading: boolean;
|
||||
question: string;
|
||||
description: string;
|
||||
answerResultSteps: Array<{
|
||||
summary: string;
|
||||
sql: string;
|
||||
}>;
|
||||
fullSql: string;
|
||||
threadResponseId: number;
|
||||
threadResponse: ThreadResponse;
|
||||
isLastThreadResponse: boolean;
|
||||
summary: string;
|
||||
view?: {
|
||||
id: number;
|
||||
displayName: string;
|
||||
};
|
||||
onOpenSaveAsViewModal: (data: { sql: string; responseId: number }) => void;
|
||||
onInitPreviewDone: () => void;
|
||||
}
|
||||
|
||||
const QuestionTitle = (props) => {
|
||||
const { question, className } = props;
|
||||
return (
|
||||
<Title
|
||||
className={clsx('d-flex bg-gray-1 rounded mt-0', className)}
|
||||
level={4}
|
||||
>
|
||||
<MessageOutlined className="geekblue-5 mt-1 mr-3" />
|
||||
<Text className="text-medium gray-8">{question}</Text>
|
||||
</Title>
|
||||
);
|
||||
};
|
||||
|
||||
export default function AnswerResult(props: Props) {
|
||||
const {
|
||||
motion,
|
||||
loading,
|
||||
question,
|
||||
description,
|
||||
answerResultSteps,
|
||||
fullSql,
|
||||
threadResponseId,
|
||||
threadResponse,
|
||||
isLastThreadResponse,
|
||||
onOpenSaveAsViewModal,
|
||||
onInitPreviewDone,
|
||||
summary,
|
||||
view,
|
||||
} = props;
|
||||
|
||||
const { question, status, error } = threadResponse;
|
||||
|
||||
const { steps, description, view, sql } = threadResponse?.detail || {};
|
||||
|
||||
const loading = !getIsFinished(status);
|
||||
|
||||
const isViewSaved = !!view;
|
||||
|
||||
const [ellipsis, setEllipsis] = useState(true);
|
||||
const resultStyle = isLastThreadResponse
|
||||
? { minHeight: 'calc(100vh - (194px))' }
|
||||
: null;
|
||||
|
||||
return (
|
||||
<div style={resultStyle}>
|
||||
<StyledQuestion wrap={false} onClick={() => setEllipsis(!ellipsis)}>
|
||||
<Col className="text-center" flex="96px">
|
||||
<QuestionCircleOutlined className="mr-2 gray-6" />
|
||||
<Text className="gray-6 text-base text-medium">Question:</Text>
|
||||
</Col>
|
||||
<Col flex="auto">
|
||||
<Text className="gray-6" ellipsis={ellipsis}>
|
||||
{question}
|
||||
</Text>
|
||||
</Col>
|
||||
</StyledQuestion>
|
||||
<Title className="mb-6 text-bold gray-10" level={3}>
|
||||
{summary}
|
||||
</Title>
|
||||
<StyledSkeleton active loading={loading}>
|
||||
<div className={motion ? 'promptThread-answer' : ''}>
|
||||
<StyledAnswer className="text-md gray-10 p-3 pr-10 pt-6">
|
||||
<Text className="adm-answer-title px-2">
|
||||
<CheckCircleFilled className="mr-2 green-6" />
|
||||
Summary
|
||||
</Text>
|
||||
<div className="pl-7 pb-5">{description}</div>
|
||||
{(answerResultSteps || []).map((step, index) => (
|
||||
<StepContent
|
||||
isLastStep={index === answerResultSteps.length - 1}
|
||||
key={`${step.summary}-${index}`}
|
||||
sql={step.sql}
|
||||
fullSql={fullSql}
|
||||
stepIndex={index}
|
||||
summary={step.summary}
|
||||
threadResponseId={threadResponseId}
|
||||
onInitPreviewDone={onInitPreviewDone}
|
||||
isLastThreadResponse={isLastThreadResponse}
|
||||
/>
|
||||
))}
|
||||
</StyledAnswer>
|
||||
{isViewSaved ? (
|
||||
<div className="mt-2 gray-6 text-medium">
|
||||
<FileDoneOutlined className="mr-2" />
|
||||
Generated from saved view{' '}
|
||||
<Link
|
||||
className="gray-7"
|
||||
href={`${Path.Modeling}?viewId=${view.id}&openMetadata=true`}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
<QuestionTitle className="mb-9" question={question} />
|
||||
{error ? (
|
||||
<Alert
|
||||
message={error.shortMessage}
|
||||
description={error.message}
|
||||
type="error"
|
||||
showIcon
|
||||
/>
|
||||
) : (
|
||||
<StyledSkeleton active loading={loading}>
|
||||
<div className={clsx({ 'promptThread-answer': motion })}>
|
||||
<StyledAnswer className="text-md gray-10 p-3 pr-10 pt-6">
|
||||
<Text className="adm-answer-title px-2">
|
||||
<CheckCircleFilled className="mr-2 green-6" />
|
||||
Summary
|
||||
</Text>
|
||||
<div className="pl-7 pb-5">{description}</div>
|
||||
{(steps || []).map((step, index) => (
|
||||
<StepContent
|
||||
isLastStep={index === steps.length - 1}
|
||||
key={`${step.summary}-${index}`}
|
||||
sql={step.sql}
|
||||
fullSql={sql}
|
||||
stepIndex={index}
|
||||
summary={step.summary}
|
||||
threadResponseId={threadResponse.id}
|
||||
onInitPreviewDone={onInitPreviewDone}
|
||||
isLastThreadResponse={isLastThreadResponse}
|
||||
/>
|
||||
))}
|
||||
</StyledAnswer>
|
||||
{isViewSaved ? (
|
||||
<div className="mt-2 gray-6 text-medium">
|
||||
<FileDoneOutlined className="mr-2" />
|
||||
Generated from saved view{' '}
|
||||
<Link
|
||||
className="gray-7"
|
||||
href={`${Path.Modeling}?viewId=${view.id}&openMetadata=true`}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
{view.displayName}
|
||||
</Link>
|
||||
</div>
|
||||
) : (
|
||||
<Button
|
||||
className="mt-2 gray-6"
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<SaveOutlined />}
|
||||
onClick={() =>
|
||||
onOpenSaveAsViewModal({
|
||||
sql,
|
||||
responseId: threadResponse.id,
|
||||
})
|
||||
}
|
||||
>
|
||||
{view.displayName}
|
||||
</Link>
|
||||
</div>
|
||||
) : (
|
||||
<Button
|
||||
className="mt-2 gray-6"
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<SaveOutlined />}
|
||||
onClick={() =>
|
||||
onOpenSaveAsViewModal({
|
||||
sql: fullSql,
|
||||
responseId: threadResponseId,
|
||||
})
|
||||
}
|
||||
>
|
||||
Save as View
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</StyledSkeleton>
|
||||
Save as View
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</StyledSkeleton>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { useRouter } from 'next/router';
|
||||
import { useEffect, useMemo, useRef } from 'react';
|
||||
import { Alert, Divider } from 'antd';
|
||||
import { Divider } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
import AnswerResult from './AnswerResult';
|
||||
import { makeIterable } from '@/utils/iteration';
|
||||
import { makeIterable, IterableComponent } from '@/utils/iteration';
|
||||
import {
|
||||
AskingTaskStatus,
|
||||
DetailedThread,
|
||||
ThreadResponse,
|
||||
} from '@/apollo/client/graphql/__types__';
|
||||
import { getIsFinished } from '@/hooks/useAskPrompt';
|
||||
|
||||
@@ -39,49 +39,34 @@ const StyledPromptThread = styled.div`
|
||||
}
|
||||
`;
|
||||
|
||||
const AnswerResultTemplate = ({
|
||||
id,
|
||||
const AnswerResultTemplate: React.FC<
|
||||
IterableComponent<ThreadResponse> & {
|
||||
motion: boolean;
|
||||
onOpenSaveAsViewModal: (data: { sql: string; responseId: number }) => void;
|
||||
onInitPreviewDone: () => void;
|
||||
}
|
||||
> = ({
|
||||
data,
|
||||
index,
|
||||
error,
|
||||
status,
|
||||
detail,
|
||||
summary,
|
||||
question,
|
||||
motion,
|
||||
// callbacks
|
||||
onOpenSaveAsViewModal,
|
||||
onInitPreviewDone,
|
||||
...threadResponse
|
||||
}) => {
|
||||
const { id } = threadResponse;
|
||||
const lastResponseId = data[data.length - 1].id;
|
||||
const isLastThreadResponse = id === lastResponseId;
|
||||
|
||||
return (
|
||||
<div key={`${id}-${index}`}>
|
||||
{index > 0 && <Divider />}
|
||||
{error ? (
|
||||
<Alert
|
||||
message={error.shortMessage}
|
||||
description={error.message}
|
||||
type="error"
|
||||
showIcon
|
||||
/>
|
||||
) : (
|
||||
<AnswerResult
|
||||
motion={motion}
|
||||
answerResultSteps={detail?.steps}
|
||||
description={detail?.description}
|
||||
loading={status !== AskingTaskStatus.FINISHED}
|
||||
question={question}
|
||||
summary={summary}
|
||||
view={detail?.view}
|
||||
fullSql={detail?.sql}
|
||||
threadResponseId={id}
|
||||
onOpenSaveAsViewModal={onOpenSaveAsViewModal}
|
||||
onInitPreviewDone={onInitPreviewDone}
|
||||
isLastThreadResponse={isLastThreadResponse}
|
||||
/>
|
||||
)}
|
||||
<AnswerResult
|
||||
motion={motion}
|
||||
isLastThreadResponse={isLastThreadResponse}
|
||||
onOpenSaveAsViewModal={onOpenSaveAsViewModal}
|
||||
onInitPreviewDone={onInitPreviewDone}
|
||||
threadResponse={threadResponse}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -150,7 +150,8 @@ export default function useAskPrompt(threadId?: number) {
|
||||
|
||||
const onStopRecommend = () => instantRecommendedQuestionsResult.stopPolling();
|
||||
|
||||
const onStoreThreadQuestions = (questions: string[]) => setThreadQuestions(questions);
|
||||
const onStoreThreadQuestions = (questions: string[]) =>
|
||||
setThreadQuestions(questions);
|
||||
|
||||
return {
|
||||
data,
|
||||
|
||||
@@ -94,8 +94,8 @@ export default function HomeThread() {
|
||||
}
|
||||
|
||||
// store thread questions for instant recommended questions
|
||||
const questions = thread?.responses.flatMap((res) => res.question || [])
|
||||
if(questions) askPrompt.onStoreThreadQuestions(questions);
|
||||
const questions = thread?.responses.flatMap((res) => res.question || []);
|
||||
if (questions) askPrompt.onStoreThreadQuestions(questions);
|
||||
}, [thread]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user