From f61007c42b640d0902444aee354063fcf2c825f7 Mon Sep 17 00:00:00 2001 From: onlyjackfrost Date: Thu, 14 Nov 2024 14:53:18 +0800 Subject: [PATCH] - update recommend status to generating after creating a recommend task. - move the type definition to /models to avoid "ReferenceError: Cannot access 'IbisAdaptor' before initialization " --- .../adaptors/tests/wrenAIAdaptor.test.ts | 7 +- .../apollo/server/adaptors/wrenAIAdaptor.ts | 177 ++---------------- .../server/backgrounds/recommend-question.ts | 6 +- wren-ui/src/apollo/server/models/adaptor.ts | 162 ++++++++++++++++ .../repositories/threadResponseRepository.ts | 2 +- .../apollo/server/resolvers/askingResolver.ts | 4 +- .../apollo/server/resolvers/modelResolver.ts | 23 +-- .../apollo/server/services/askingService.ts | 9 +- .../apollo/server/services/deployService.ts | 6 +- .../apollo/server/services/projectService.ts | 11 +- 10 files changed, 202 insertions(+), 205 deletions(-) create mode 100644 wren-ui/src/apollo/server/models/adaptor.ts diff --git a/wren-ui/src/apollo/server/adaptors/tests/wrenAIAdaptor.test.ts b/wren-ui/src/apollo/server/adaptors/tests/wrenAIAdaptor.test.ts index dc5ba93d3..69252623f 100644 --- a/wren-ui/src/apollo/server/adaptors/tests/wrenAIAdaptor.test.ts +++ b/wren-ui/src/apollo/server/adaptors/tests/wrenAIAdaptor.test.ts @@ -1,6 +1,9 @@ import axios from 'axios'; -import { RecommendationQuestionsInput, WrenAIAdaptor } from '../wrenAIAdaptor'; -import { RecommendationQuestionStatus } from '../wrenAIAdaptor'; +import { WrenAIAdaptor } from '../wrenAIAdaptor'; +import { + RecommendationQuestionsInput, + RecommendationQuestionStatus, +} from '@server/models/adaptor'; import { Manifest } from '../../mdl/type'; jest.mock('axios'); diff --git a/wren-ui/src/apollo/server/adaptors/wrenAIAdaptor.ts b/wren-ui/src/apollo/server/adaptors/wrenAIAdaptor.ts index 934f08388..a94d5af5f 100644 --- a/wren-ui/src/apollo/server/adaptors/wrenAIAdaptor.ts +++ b/wren-ui/src/apollo/server/adaptors/wrenAIAdaptor.ts @@ -1,172 +1,27 @@ import axios from 'axios'; import { Readable } from 'stream'; -import { Manifest } from '@server/mdl/type'; +import { + AskCandidateType, + AskDetailInput, + AskDetailResult, + AskHistory, + AskResult, + AskResultStatus, + AsyncQueryResponse, + RecommendationQuestionsInput, + RecommendationQuestionsResult, + WrenAIDeployStatusEnum, + WrenAISystemStatus, + WrenAIDeployResponse, + DeployData, + AskInput, +} from '@server/models/adaptor'; import { getLogger } from '@server/utils'; import * as Errors from '@server/utils/error'; const logger = getLogger('WrenAIAdaptor'); logger.level = 'debug'; -export interface WrenAIError { - code: Errors.GeneralErrorCodes; - message: string; -} - -export enum WrenAIDeployStatusEnum { - SUCCESS = 'SUCCESS', - FAILED = 'FAILED', -} - -export interface WrenAIDeployResponse { - status: WrenAIDeployStatusEnum; - error?: string; -} - -enum WrenAISystemStatus { - INDEXING = 'INDEXING', - FINISHED = 'FINISHED', - FAILED = 'FAILED', -} - -export enum WrenAILanguage { - EN = 'English', - ES = 'Spanish', - FR = 'French', - ZH_TW = 'Traditional Chinese', - ZH_CN = 'Simplified Chinese', - DE = 'German', - PT = 'Portuguese', - RU = 'Russian', - JA = 'Japanese', - KO = 'Korean', -} - -export interface DeployData { - manifest: Manifest; - hash: string; - projectId: string; -} - -// ask -export interface AskStep { - summary: string; - sql: string; - cteName: string; -} - -export interface AskHistory { - sql: string; - summary: string; - steps: Array; -} - -export interface AskConfigurations { - language: string; -} - -export interface AskInput { - query: string; - deployId: string; - history?: AskHistory; - configurations?: AskConfigurations; -} - -export interface AsyncQueryResponse { - queryId: string; -} - -export enum AskResultStatus { - UNDERSTANDING = 'UNDERSTANDING', - SEARCHING = 'SEARCHING', - GENERATING = 'GENERATING', - FINISHED = 'FINISHED', - FAILED = 'FAILED', - STOPPED = 'STOPPED', -} - -export enum AskResultType { - GENERAL = 'GENERAL', - TEXT_TO_SQL = 'TEXT_TO_SQL', - MISLEADING_QUERY = 'MISLEADING_QUERY', -} - -// if it's view, viewId will be returned as well. It means the candidate is originally saved in mdl as a view. -// if it's llm, viewId will not be returned. It means the candidate is generated by AI service. -export enum AskCandidateType { - VIEW = 'VIEW', - LLM = 'LLM', -} - -export interface AskResponse { - type: AskResultType | null; - status: S; - response: R | null; - error: WrenAIError | null; -} - -export interface AskDetailInput { - query: string; - sql: string; - summary: string; - configurations?: AskConfigurations; -} - -export type AskDetailResult = AskResponse< - { - description: string; - steps: AskStep[]; - }, - AskResultStatus ->; - -export type AskResult = AskResponse< - Array<{ - type: AskCandidateType; - sql: string; - summary: string; - viewId?: number | null; - }>, - AskResultStatus ->; - -export enum RecommendationQuestionStatus { - GENERATING = 'GENERATING', - FINISHED = 'FINISHED', - FAILED = 'FAILED', -} - -export type RecommendationQuestionsInput = { - // JSON string of the MDL (Model Definition Language) - manifest: Manifest; - // Optional list of previous questions - previousQuestions?: string[]; - // Optional project ID - projectId?: string; - // Optional max number of questions to generate (default: 5) - maxQuestions?: number; - // Optional max number of categories (default: 3) - maxCategories?: number; - regenerate?: boolean; // Optional regenerate questions (default: false) - // Optional configuration settings - configuration?: { - // Optional language (default: "English") - language?: string; - }; -}; - -export type RecommendationQuestion = { - question: string; - category: string; // category for the question - sql: string; // validated sql for this question, can be used in generateAskDetail -}; - -export type RecommendationQuestionsResult = AskResponse< - { - questions: RecommendationQuestion[]; - }, - RecommendationQuestionStatus ->; - const getAISerciceError = (error: any) => { const { data } = error.response || {}; return data?.detail diff --git a/wren-ui/src/apollo/server/backgrounds/recommend-question.ts b/wren-ui/src/apollo/server/backgrounds/recommend-question.ts index a767cc998..9047ac6bf 100644 --- a/wren-ui/src/apollo/server/backgrounds/recommend-question.ts +++ b/wren-ui/src/apollo/server/backgrounds/recommend-question.ts @@ -1,8 +1,6 @@ import { IProjectRepository } from '../repositories/projectRepository'; -import { - IWrenAIAdaptor, - RecommendationQuestionStatus, -} from '../adaptors/wrenAIAdaptor'; +import { RecommendationQuestionStatus } from '@server/models/adaptor'; +import { IWrenAIAdaptor } from '../adaptors/wrenAIAdaptor'; import { IThreadRepository, Project, Thread } from '../repositories'; import { ITelemetry, diff --git a/wren-ui/src/apollo/server/models/adaptor.ts b/wren-ui/src/apollo/server/models/adaptor.ts new file mode 100644 index 000000000..ec00c81c6 --- /dev/null +++ b/wren-ui/src/apollo/server/models/adaptor.ts @@ -0,0 +1,162 @@ +import * as Errors from '@server/utils/error'; +import { Manifest } from '@server/mdl/type'; + +export interface WrenAIError { + code: Errors.GeneralErrorCodes; + message: string; +} + +export enum WrenAIDeployStatusEnum { + SUCCESS = 'SUCCESS', + FAILED = 'FAILED', +} + +export interface WrenAIDeployResponse { + status: WrenAIDeployStatusEnum; + error?: string; +} + +export enum WrenAISystemStatus { + INDEXING = 'INDEXING', + FINISHED = 'FINISHED', + FAILED = 'FAILED', +} + +export enum WrenAILanguage { + EN = 'English', + ES = 'Spanish', + FR = 'French', + ZH_TW = 'Traditional Chinese', + ZH_CN = 'Simplified Chinese', + DE = 'German', + PT = 'Portuguese', + RU = 'Russian', + JA = 'Japanese', + KO = 'Korean', +} + +export interface DeployData { + manifest: Manifest; + hash: string; + projectId: string; +} + +// ask +export interface AskStep { + summary: string; + sql: string; + cteName: string; +} + +export interface AskHistory { + sql: string; + summary: string; + steps: Array; +} + +export interface AskConfigurations { + language: string; +} + +export interface AskInput { + query: string; + deployId: string; + history?: AskHistory; + configurations?: AskConfigurations; +} + +export interface AsyncQueryResponse { + queryId: string; +} + +export enum AskResultStatus { + UNDERSTANDING = 'UNDERSTANDING', + SEARCHING = 'SEARCHING', + GENERATING = 'GENERATING', + FINISHED = 'FINISHED', + FAILED = 'FAILED', + STOPPED = 'STOPPED', +} + +export enum AskResultType { + GENERAL = 'GENERAL', + TEXT_TO_SQL = 'TEXT_TO_SQL', + MISLEADING_QUERY = 'MISLEADING_QUERY', +} + +// if it's view, viewId will be returned as well. It means the candidate is originally saved in mdl as a view. +// if it's llm, viewId will not be returned. It means the candidate is generated by AI service. +export enum AskCandidateType { + VIEW = 'VIEW', + LLM = 'LLM', +} + +export interface AskResponse { + type: AskResultType | null; + status: S; + response: R | null; + error: WrenAIError | null; +} + +export interface AskDetailInput { + query: string; + sql: string; + summary: string; + configurations?: AskConfigurations; +} + +export type AskDetailResult = AskResponse< + { + description: string; + steps: AskStep[]; + }, + AskResultStatus +>; + +export type AskResult = AskResponse< + Array<{ + type: AskCandidateType; + sql: string; + summary: string; + viewId?: number | null; + }>, + AskResultStatus +>; + +export enum RecommendationQuestionStatus { + GENERATING = 'GENERATING', + FINISHED = 'FINISHED', + FAILED = 'FAILED', +} + +export type RecommendationQuestionsInput = { + // JSON string of the MDL (Model Definition Language) + manifest: Manifest; + // Optional list of previous questions + previousQuestions?: string[]; + // Optional project ID + projectId?: string; + // Optional max number of questions to generate (default: 5) + maxQuestions?: number; + // Optional max number of categories (default: 3) + maxCategories?: number; + regenerate?: boolean; // Optional regenerate questions (default: false) + // Optional configuration settings + configuration?: { + // Optional language (default: "English") + language?: string; + }; +}; + +export type RecommendationQuestion = { + question: string; + category: string; // category for the question + sql: string; // validated sql for this question, can be used in generateAskDetail +}; + +export type RecommendationQuestionsResult = AskResponse< + { + questions: RecommendationQuestion[]; + }, + RecommendationQuestionStatus +>; diff --git a/wren-ui/src/apollo/server/repositories/threadResponseRepository.ts b/wren-ui/src/apollo/server/repositories/threadResponseRepository.ts index 47690d172..9416cc821 100644 --- a/wren-ui/src/apollo/server/repositories/threadResponseRepository.ts +++ b/wren-ui/src/apollo/server/repositories/threadResponseRepository.ts @@ -5,7 +5,7 @@ import { IQueryOptions, } from './baseRepository'; import { camelCase, isPlainObject, mapKeys, mapValues } from 'lodash'; -import { AskResultStatus, WrenAIError } from '../adaptors/wrenAIAdaptor'; +import { AskResultStatus, WrenAIError } from '@server/models/adaptor'; export interface DetailStep { summary: string; diff --git a/wren-ui/src/apollo/server/resolvers/askingResolver.ts b/wren-ui/src/apollo/server/resolvers/askingResolver.ts index 13303f332..0b302bfa6 100644 --- a/wren-ui/src/apollo/server/resolvers/askingResolver.ts +++ b/wren-ui/src/apollo/server/resolvers/askingResolver.ts @@ -4,7 +4,7 @@ import { AskResultStatus, AskResultType, RecommendationQuestionStatus, -} from '../adaptors/wrenAIAdaptor'; +} from '@server/models/adaptor'; import { Thread } from '../repositories/threadRepository'; import { DetailStep, @@ -58,7 +58,7 @@ export interface RecommendedQuestionsTask { questions: { question: string; category: string; - explanation: string; + sql: string; }[]; status: RecommendationQuestionStatus; error: WrenAIError | null; diff --git a/wren-ui/src/apollo/server/resolvers/modelResolver.ts b/wren-ui/src/apollo/server/resolvers/modelResolver.ts index ad1689c71..566edb6e3 100644 --- a/wren-ui/src/apollo/server/resolvers/modelResolver.ts +++ b/wren-ui/src/apollo/server/resolvers/modelResolver.ts @@ -228,28 +228,7 @@ export class ModelResolver { project.id, args.force, ); - const recommendQuestionResult = - await ctx.wrenAIAdaptor.generateRecommendationQuestions({ - manifest, - projectId: project.id.toString(), - maxCategories: 3, - maxQuestions: 9, - configuration: { - language: project.language, - }, - }); - const updatedProject = await ctx.projectRepository.updateOne(project.id, { - queryId: recommendQuestionResult.queryId, - questionsStatus: null, - questions: null, - questionsError: null, - }); - const tasks = ctx.projectRecommendQuestionBackgroundTracker.getTasks(); - const taskKey = - ctx.projectRecommendQuestionBackgroundTracker.taskKey(updatedProject); - if (!tasks[taskKey]) { - ctx.projectRecommendQuestionBackgroundTracker.addTask(updatedProject); - } + await ctx.projectService.generateProjectRecommendationQuestions(); return deployRes; } diff --git a/wren-ui/src/apollo/server/services/askingService.ts b/wren-ui/src/apollo/server/services/askingService.ts index 51bc2f5b3..61521a1ee 100644 --- a/wren-ui/src/apollo/server/services/askingService.ts +++ b/wren-ui/src/apollo/server/services/askingService.ts @@ -1,13 +1,14 @@ +import { IWrenAIAdaptor } from '@server/adaptors/wrenAIAdaptor'; import { AskResult, - IWrenAIAdaptor, AskResultStatus, AskHistory, RecommendationQuestionsResult, RecommendationQuestionsInput, RecommendationQuestion, WrenAIError, -} from '@server/adaptors/wrenAIAdaptor'; + RecommendationQuestionStatus, +} from '@server/models/adaptor'; import { IDeployService } from './deployService'; import { IProjectService } from './projectService'; import { IThreadRepository, Thread } from '../repositories/threadRepository'; @@ -424,9 +425,9 @@ export class AskingService implements IAskingService { // reset thread recommended questions const updatedThread = await this.threadRepository.updateOne(threadId, { queryId: result.queryId, - questions: null, + questionsStatus: RecommendationQuestionStatus.GENERATING, + questions: [], questionsError: null, - questionsStatus: null, }); this.threadRecommendQuestionBackgroundTracker.addTask(updatedThread); return; diff --git a/wren-ui/src/apollo/server/services/deployService.ts b/wren-ui/src/apollo/server/services/deployService.ts index db856ef7f..3c751d315 100644 --- a/wren-ui/src/apollo/server/services/deployService.ts +++ b/wren-ui/src/apollo/server/services/deployService.ts @@ -1,7 +1,5 @@ -import { - IWrenAIAdaptor, - WrenAIDeployStatusEnum, -} from '../adaptors/wrenAIAdaptor'; +import { WrenAIDeployStatusEnum } from '@server/models/adaptor'; +import { IWrenAIAdaptor } from '../adaptors/wrenAIAdaptor'; import { Deploy, DeployStatusEnum, diff --git a/wren-ui/src/apollo/server/services/projectService.ts b/wren-ui/src/apollo/server/services/projectService.ts index b8b07c158..6b6c37ce2 100644 --- a/wren-ui/src/apollo/server/services/projectService.ts +++ b/wren-ui/src/apollo/server/services/projectService.ts @@ -10,12 +10,13 @@ import { RecommendConstraint, } from './metadataService'; import { DataSourceName } from '../types'; -import { encryptConnectionInfo } from '../dataSource'; import { - IWrenAIAdaptor, RecommendationQuestion, + RecommendationQuestionStatus, WrenAIError, -} from '../adaptors'; +} from '@server/models/adaptor'; +import { encryptConnectionInfo } from '../dataSource'; +import { IWrenAIAdaptor } from '../adaptors'; import { RecommendQuestionResultStatus } from './askingService'; import { IMDLService } from './mdlService'; import { ProjectRecommendQuestionBackgroundTracker } from '../backgrounds'; @@ -106,8 +107,8 @@ export class ProjectService implements IProjectService { }); const updatedProject = await this.projectRepository.updateOne(project.id, { queryId: recommendQuestionResult.queryId, - questionsStatus: null, - questions: null, + questionsStatus: RecommendationQuestionStatus.GENERATING, + questions: [], questionsError: null, }); const tasks = this.projectRecommendQuestionBackgroundTracker.getTasks();