mirror of
https://github.com/Canner/WrenAI.git
synced 2026-09-24 23:29:49 +08:00
- 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:
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user