- update recommend status to generating after creating a recommend task.

- move the type definition to /models to avoid "ReferenceError: Cannot access 'IbisAdaptor' before initialization "
This commit is contained in:
onlyjackfrost
2024-11-18 16:08:57 +08:00
committed by Andy Yen
parent ca2f9f0283
commit f61007c42b
10 changed files with 202 additions and 205 deletions
@@ -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');
@@ -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<AskStep>;
}
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<R, S> {
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
@@ -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,
+162
View File
@@ -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<AskStep>;
}
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<R, S> {
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
>;
@@ -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;
@@ -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;
@@ -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;
}
@@ -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;
@@ -1,7 +1,5 @@
import {
IWrenAIAdaptor,
WrenAIDeployStatusEnum,
} from '../adaptors/wrenAIAdaptor';
import { WrenAIDeployStatusEnum } from '@server/models/adaptor';
import { IWrenAIAdaptor } from '../adaptors/wrenAIAdaptor';
import {
Deploy,
DeployStatusEnum,
@@ -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();