mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
refactor: Update Llama app to use local model path instead of model ID
This commit is contained in:
@@ -3,6 +3,7 @@ import BaseAnalyticsAPI from "CommonServer/API/BaseAnalyticsAPI";
|
||||
import BillingInvoiceAPI from "CommonServer/API/BillingInvoiceAPI";
|
||||
import BillingPaymentMethodAPI from "CommonServer/API/BillingPaymentMethodAPI";
|
||||
import CodeRepositoryAPI from "CommonServer/API/CodeRepositoryAPI";
|
||||
import CopilotEventAPI from "CommonServer/API/CopilotEventAPI";
|
||||
import FileAPI from "CommonServer/API/FileAPI";
|
||||
import GlobalConfigAPI from "CommonServer/API/GlobalConfigAPI";
|
||||
import MonitorGroupAPI from "CommonServer/API/MonitorGroupAPI";
|
||||
@@ -30,9 +31,6 @@ import ApiKeyService, {
|
||||
import CallLogService, {
|
||||
Service as CallLogServiceType,
|
||||
} from "CommonServer/Services/CallLogService";
|
||||
import CopilotEventService, {
|
||||
Service as CopilotEventServiceType,
|
||||
} from "CommonServer/Services/CopilotEventService";
|
||||
import DomainService, {
|
||||
Service as DomainServiceType,
|
||||
} from "CommonServer/Services/DomainService";
|
||||
@@ -297,7 +295,6 @@ import Span from "Model/AnalyticsModels/Span";
|
||||
import ApiKey from "Model/Models/ApiKey";
|
||||
import ApiKeyPermission from "Model/Models/ApiKeyPermission";
|
||||
import CallLog from "Model/Models/CallLog";
|
||||
import CopilotEvent from "Model/Models/CopilotEvent";
|
||||
import Domain from "Model/Models/Domain";
|
||||
import EmailLog from "Model/Models/EmailLog";
|
||||
import EmailVerificationToken from "Model/Models/EmailVerificationToken";
|
||||
@@ -504,14 +501,6 @@ const BaseAPIFeatureSet: FeatureSet = {
|
||||
).getRouter(),
|
||||
);
|
||||
|
||||
app.use(
|
||||
`/${APP_NAME.toLocaleLowerCase()}`,
|
||||
new BaseAPI<CopilotEvent, CopilotEventServiceType>(
|
||||
CopilotEvent,
|
||||
CopilotEventService,
|
||||
).getRouter(),
|
||||
);
|
||||
|
||||
app.use(
|
||||
`/${APP_NAME.toLocaleLowerCase()}`,
|
||||
new BaseAPI<ServiceCatalogOwnerUser, ServiceCatalogOwnerUserServiceType>(
|
||||
@@ -1023,6 +1012,11 @@ const BaseAPIFeatureSet: FeatureSet = {
|
||||
new CodeRepositoryAPI().getRouter(),
|
||||
);
|
||||
|
||||
app.use(
|
||||
`/${APP_NAME.toLocaleLowerCase()}`,
|
||||
new CopilotEventAPI().getRouter(),
|
||||
);
|
||||
|
||||
app.use(
|
||||
`/${APP_NAME.toLocaleLowerCase()}`,
|
||||
new UserNotificationLogTimelineAPI().getRouter(),
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import UserMiddleware from "../Middleware/UserAuthorization";
|
||||
import CodeRepositoryAuthorization from "../Middleware/CodeRepositoryAuthorization";
|
||||
import CodeRepositoryService, {
|
||||
Service as CodeRepositoryServiceType,
|
||||
} from "../Services/CodeRepositoryService";
|
||||
import CopilotEventService from "../Services/CopilotEventService";
|
||||
import ServiceRepositoryService from "../Services/ServiceRepositoryService";
|
||||
import {
|
||||
ExpressRequest,
|
||||
@@ -15,7 +14,6 @@ import { LIMIT_PER_PROJECT } from "Common/Types/Database/LimitMax";
|
||||
import BadDataException from "Common/Types/Exception/BadDataException";
|
||||
import ObjectID from "Common/Types/ObjectID";
|
||||
import CodeRepository from "Model/Models/CodeRepository";
|
||||
import CopilotEvent from "Model/Models/CopilotEvent";
|
||||
import ServiceRepository from "Model/Models/ServiceRepository";
|
||||
|
||||
export default class CodeRepositoryAPI extends BaseAPI<
|
||||
@@ -29,7 +27,7 @@ export default class CodeRepositoryAPI extends BaseAPI<
|
||||
`${new this.entityType()
|
||||
.getCrudApiPath()
|
||||
?.toString()}/get-code-repository/:secretkey`,
|
||||
UserMiddleware.getUserMiddleware,
|
||||
CodeRepositoryAuthorization.isAuthorizedRepository,
|
||||
async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
|
||||
try {
|
||||
const secretkey: string = req.params["secretkey"]!;
|
||||
@@ -98,84 +96,5 @@ export default class CodeRepositoryAPI extends BaseAPI<
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
this.router.get(
|
||||
`${new this.entityType()
|
||||
.getCrudApiPath()
|
||||
?.toString()}/get-copilot-events-by-file/:secretkey`,
|
||||
UserMiddleware.getUserMiddleware,
|
||||
async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
|
||||
try {
|
||||
const secretkey: string = req.params["secretkey"]!;
|
||||
|
||||
if (!secretkey) {
|
||||
throw new BadDataException("Secret key is required");
|
||||
}
|
||||
|
||||
const filePath: string = req.body["filePath"]!;
|
||||
|
||||
if (!filePath) {
|
||||
throw new BadDataException("File path is required");
|
||||
}
|
||||
|
||||
const serviceCatalogId: string = req.body["serviceCatalogId"]!;
|
||||
|
||||
if (!serviceCatalogId) {
|
||||
throw new BadDataException("Service catalog id is required");
|
||||
}
|
||||
|
||||
const codeRepository: CodeRepository | null =
|
||||
await CodeRepositoryService.findOneBy({
|
||||
query: {
|
||||
secretToken: new ObjectID(secretkey),
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!codeRepository) {
|
||||
throw new BadDataException(
|
||||
"Code repository not found. Secret key is invalid.",
|
||||
);
|
||||
}
|
||||
|
||||
const copilotEvents: Array<CopilotEvent> =
|
||||
await CopilotEventService.findBy({
|
||||
query: {
|
||||
codeRepositoryId: codeRepository.id!,
|
||||
filePath: filePath,
|
||||
serviceCatalogId: new ObjectID(serviceCatalogId),
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
codeRepositoryId: true,
|
||||
serviceCatalogId: true,
|
||||
filePath: true,
|
||||
copilotEventStatus: true,
|
||||
copilotEventType: true,
|
||||
createdAt: true,
|
||||
},
|
||||
skip: 0,
|
||||
limit: LIMIT_PER_PROJECT,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
return Response.sendJsonObjectResponse(req, res, {
|
||||
copilotEvents: CopilotEvent.toJSONArray(
|
||||
copilotEvents,
|
||||
CopilotEvent,
|
||||
),
|
||||
});
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
105
CommonServer/API/CopilotEventAPI.ts
Normal file
105
CommonServer/API/CopilotEventAPI.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import CodeRepository from "Model/Models/CodeRepository";
|
||||
import CopilotEventService, {
|
||||
Service as CopilotEventServiceType,
|
||||
} from "../Services/CopilotEventService";
|
||||
import {
|
||||
ExpressRequest,
|
||||
ExpressResponse,
|
||||
NextFunction,
|
||||
} from "../Utils/Express";
|
||||
import Response from "../Utils/Response";
|
||||
import BaseAPI from "./BaseAPI";
|
||||
import { LIMIT_PER_PROJECT } from "Common/Types/Database/LimitMax";
|
||||
import BadDataException from "Common/Types/Exception/BadDataException";
|
||||
import ObjectID from "Common/Types/ObjectID";
|
||||
import CopilotEvent from "Model/Models/CopilotEvent";
|
||||
import CodeRepositoryService from "../Services/CodeRepositoryService";
|
||||
import CodeRepositoryAuthorization from "../Middleware/CodeRepositoryAuthorization";
|
||||
|
||||
export default class CopilotEventAPI extends BaseAPI<
|
||||
CopilotEvent,
|
||||
CopilotEventServiceType
|
||||
> {
|
||||
public constructor() {
|
||||
super(CopilotEvent, CopilotEventService);
|
||||
|
||||
this.router.get(
|
||||
`${new this.entityType()
|
||||
.getCrudApiPath()
|
||||
?.toString()}/copilot-events-by-file/:secretkey`,
|
||||
CodeRepositoryAuthorization.isAuthorizedRepository,
|
||||
async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
|
||||
try {
|
||||
const secretkey: string = req.params["secretkey"]!;
|
||||
|
||||
if (!secretkey) {
|
||||
throw new BadDataException("Secret key is required");
|
||||
}
|
||||
|
||||
const filePath: string = req.body["filePath"]!;
|
||||
|
||||
if (!filePath) {
|
||||
throw new BadDataException("File path is required");
|
||||
}
|
||||
|
||||
const serviceCatalogId: string = req.body["serviceCatalogId"]!;
|
||||
|
||||
if (!serviceCatalogId) {
|
||||
throw new BadDataException("Service catalog id is required");
|
||||
}
|
||||
|
||||
const codeRepository: CodeRepository | null =
|
||||
await CodeRepositoryService.findOneBy({
|
||||
query: {
|
||||
secretToken: new ObjectID(secretkey),
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!codeRepository) {
|
||||
throw new BadDataException(
|
||||
"Code repository not found. Secret key is invalid.",
|
||||
);
|
||||
}
|
||||
|
||||
const copilotEvents: Array<CopilotEvent> =
|
||||
await CopilotEventService.findBy({
|
||||
query: {
|
||||
codeRepositoryId: codeRepository.id!,
|
||||
filePath: filePath,
|
||||
serviceCatalogId: new ObjectID(serviceCatalogId),
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
codeRepositoryId: true,
|
||||
serviceCatalogId: true,
|
||||
filePath: true,
|
||||
copilotEventStatus: true,
|
||||
copilotEventType: true,
|
||||
createdAt: true,
|
||||
},
|
||||
skip: 0,
|
||||
limit: LIMIT_PER_PROJECT,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
return Response.sendJsonObjectResponse(req, res, {
|
||||
copilotEvents: CopilotEvent.toJSONArray(
|
||||
copilotEvents,
|
||||
CopilotEvent,
|
||||
),
|
||||
});
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
48
CommonServer/Middleware/CodeRepositoryAuthorization.ts
Normal file
48
CommonServer/Middleware/CodeRepositoryAuthorization.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import BadDataException from "Common/Types/Exception/BadDataException";
|
||||
import {
|
||||
ExpressRequest,
|
||||
ExpressResponse,
|
||||
NextFunction,
|
||||
} from "../Utils/Express";
|
||||
import CodeRepository from "Model/Models/CodeRepository";
|
||||
import CodeRepositoryService from "../Services/CodeRepositoryService";
|
||||
import ObjectID from "Common/Types/ObjectID";
|
||||
|
||||
export default class CodeRepositoryAuthorization {
|
||||
public static async isAuthorizedRepository(
|
||||
req: ExpressRequest,
|
||||
_res: ExpressResponse,
|
||||
next: NextFunction,
|
||||
): Promise<void> {
|
||||
try {
|
||||
const secretkey: string = req.params["secretkey"]!;
|
||||
|
||||
if (!secretkey) {
|
||||
throw new BadDataException("Secret key is required");
|
||||
}
|
||||
|
||||
const codeRepository: CodeRepository | null =
|
||||
await CodeRepositoryService.findOneBy({
|
||||
query: {
|
||||
secretToken: new ObjectID(secretkey),
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!codeRepository) {
|
||||
throw new BadDataException(
|
||||
"Code repository not found. Secret key is invalid.",
|
||||
);
|
||||
}
|
||||
|
||||
next();
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,3 +3,6 @@ ONEUPTIME_REPOSITORY_SECRET_KEY=your-repository-secret-key
|
||||
ONEUPTIME_LOCAL_REPOSITORY_PATH=/repository
|
||||
GITHUB_TOKEN=
|
||||
GITHUB_USERNAME=
|
||||
# Optional. If this is left blank then this url will be ONEUPTIME_URL/llama
|
||||
ONEUPTIME_LLAMA_SERVER_URL=
|
||||
LLM_TYPE=llama
|
||||
@@ -29,3 +29,16 @@ export const GetGitHubUsername: GetStringOrNullFunction = (): string | null => {
|
||||
const username: string | null = process.env["GITHUB_USERNAME"] || null;
|
||||
return username;
|
||||
};
|
||||
|
||||
export const GetLlamaServerUrl: GetURLFunction = () => {
|
||||
return URL.fromString(
|
||||
process.env["LLAMA_SERVER_URL"] ||
|
||||
GetOneUptimeURL().addRoute("/llama").toString(),
|
||||
);
|
||||
};
|
||||
|
||||
type GetLlmTypeFunction = () => LlmType;
|
||||
|
||||
export const GetLlmType: GetLlmTypeFunction = (): LlmType => {
|
||||
return (process.env["LLM_TYPE"] as LlmType) || LlmType.Llama;
|
||||
};
|
||||
|
||||
@@ -1,37 +1,14 @@
|
||||
import CodeRepositoryUtil, {
|
||||
CodeRepositoryResult,
|
||||
} from "./Utils/CodeRepository";
|
||||
import InitUtil from "./Utils/Init";
|
||||
import ServiceRepositoryUtil from "./Utils/ServiceRepository";
|
||||
import CodeRepositoryUtil from "./Utils/CodeRepository";
|
||||
import HTTPErrorResponse from "Common/Types/API/HTTPErrorResponse";
|
||||
import Dictionary from "Common/Types/Dictionary";
|
||||
import { PromiseVoidFunction } from "Common/Types/FunctionTypes";
|
||||
import CodeRepositoryFile from "CommonServer/Utils/CodeRepository/CodeRepositoryFile";
|
||||
import logger from "CommonServer/Utils/Logger";
|
||||
import dotenv from "dotenv";
|
||||
import Init from "./Init";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
logger.info("OneUptime Copilot is starting...");
|
||||
|
||||
const init: PromiseVoidFunction = async (): Promise<void> => {
|
||||
const codeRepositoryResult: CodeRepositoryResult = await InitUtil.init();
|
||||
|
||||
for (const serviceRepository of codeRepositoryResult.servicesRepository) {
|
||||
const filesInService: Dictionary<CodeRepositoryFile> =
|
||||
await ServiceRepositoryUtil.getFilesInServiceDirectory({
|
||||
serviceRepository,
|
||||
});
|
||||
|
||||
logger.info(
|
||||
`Files found in ${serviceRepository.serviceCatalog?.name}: ${
|
||||
Object.keys(filesInService).length
|
||||
}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
init()
|
||||
Init()
|
||||
.then(() => {
|
||||
process.exit(0);
|
||||
})
|
||||
|
||||
26
Copilot/Init.ts
Normal file
26
Copilot/Init.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { CodeRepositoryResult } from "./Utils/CodeRepository";
|
||||
import InitUtil from "./Utils/Init";
|
||||
import ServiceRepositoryUtil from "./Utils/ServiceRepository";
|
||||
import Dictionary from "Common/Types/Dictionary";
|
||||
import { PromiseVoidFunction } from "Common/Types/FunctionTypes";
|
||||
import CodeRepositoryFile from "CommonServer/Utils/CodeRepository/CodeRepositoryFile";
|
||||
import logger from "CommonServer/Utils/Logger";
|
||||
|
||||
const init: PromiseVoidFunction = async (): Promise<void> => {
|
||||
const codeRepositoryResult: CodeRepositoryResult = await InitUtil.init();
|
||||
|
||||
for (const serviceRepository of codeRepositoryResult.servicesRepository) {
|
||||
const filesInService: Dictionary<CodeRepositoryFile> =
|
||||
await ServiceRepositoryUtil.getFilesInServiceDirectory({
|
||||
serviceRepository,
|
||||
});
|
||||
|
||||
logger.info(
|
||||
`Files found in ${serviceRepository.serviceCatalog?.name}: ${
|
||||
Object.keys(filesInService).length
|
||||
}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default init;
|
||||
7
Copilot/Service/LLM/LLMBase.ts
Normal file
7
Copilot/Service/LLM/LLMBase.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import NotImplementedException from "Common/Types/Exception/NotImplementedException";
|
||||
|
||||
export default class LlmBase {
|
||||
public static async getResponse(_data: { input: string }): Promise<string> {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
48
Copilot/Service/LLM/Llama.ts
Normal file
48
Copilot/Service/LLM/Llama.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import URL from "Common/Types/API/URL";
|
||||
import { GetLlamaServerUrl } from "../../Config";
|
||||
import LlmBase from "./LLMBase";
|
||||
import API from "Common/Utils/API";
|
||||
import HTTPErrorResponse from "Common/Types/API/HTTPErrorResponse";
|
||||
import HTTPResponse from "Common/Types/API/HTTPResponse";
|
||||
import { JSONArray, JSONObject } from "Common/Types/JSON";
|
||||
import BadRequestException from "Common/Types/Exception/BadRequestException";
|
||||
|
||||
export default class Llama extends LlmBase {
|
||||
public static override async getResponse(data: {
|
||||
input: string;
|
||||
}): Promise<string> {
|
||||
const serverUrl: URL = GetLlamaServerUrl();
|
||||
|
||||
const response: HTTPErrorResponse | HTTPResponse<JSONObject> =
|
||||
await API.post(serverUrl.addRoute("/prompt"), {
|
||||
prompt: data.input,
|
||||
});
|
||||
|
||||
if (response instanceof HTTPErrorResponse) {
|
||||
throw response;
|
||||
}
|
||||
|
||||
const result: JSONObject = response.data;
|
||||
|
||||
if (
|
||||
result["response"] &&
|
||||
(result["response"] as JSONObject)["generated_text"]
|
||||
) {
|
||||
const arrayOfGeneratedText: JSONArray = (
|
||||
result["response"] as JSONObject
|
||||
)["generated_text"] as JSONArray;
|
||||
|
||||
// get last item
|
||||
|
||||
const lastItem: JSONObject = arrayOfGeneratedText[
|
||||
arrayOfGeneratedText.length - 1
|
||||
] as JSONObject;
|
||||
|
||||
if (lastItem["content"]) {
|
||||
return lastItem["content"] as string;
|
||||
}
|
||||
}
|
||||
|
||||
throw new BadRequestException("Failed to get response from Llama server");
|
||||
}
|
||||
}
|
||||
6
Copilot/Types/LlmType.ts
Normal file
6
Copilot/Types/LlmType.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
enum LlmType {
|
||||
Llama = "llama",
|
||||
OpenAI = "openai",
|
||||
}
|
||||
|
||||
export default LlmType;
|
||||
Reference in New Issue
Block a user