Skip to content

Commit

Permalink
Add embedding service with Xenova transformers for vector embeddings
Browse files Browse the repository at this point in the history
Implement context service for code indexing and function mapping
Configure embedding settings with batch processing and rate limiting
Update code repository to separate table creation and data insertion
Add @xenova/transformers dependency
Refactor TypeScriptAtsMapper to use singleton pattern
  • Loading branch information
olasunkanmiraymond committed Jan 20, 2025
1 parent bc7b1f9 commit a9e9b75
Show file tree
Hide file tree
Showing 9 changed files with 369 additions and 51 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@
"@google/generative-ai": "^0.3.0",
"@libsql/client": "^0.14.0",
"@types/node-fetch": "^2.6.11",
"@xenova/transformers": "^2.17.2",
"dotenv": "^16.1.4",
"groq-sdk": "^0.3.2",
"markdown-it": "^14.1.0",
Expand Down
9 changes: 9 additions & 0 deletions src/application/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,12 @@ export enum FSPROPS {
TS_FILE_PATTERN = "**/*.ts",
TSCONFIG_FILE = "tsconfig.json",
}

export const EmbeddingsConfig = {
batchSize: 5,
maxRetries: 3,
retryDelay: 1000,
rateLimit: 1500,
embeddingModel: "Xenova/all-MiniLM-L6-v2",
textModel: "gemini-1.5-flash",
};
34 changes: 17 additions & 17 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export async function activate(context: vscode.ExtensionContext) {
const codeMapper = new TypeScriptAtsMapper();
const mappedCode = await codeMapper.buildCodebaseMap();
const ats = Object.values(mappedCode).flatMap((repo) =>
Object.values(repo.modules),
Object.values(repo.modules)
);
const mapper = new CodeStructureMapper(ats);
return mapper.normalizeData();
Expand All @@ -70,49 +70,49 @@ export async function activate(context: vscode.ExtensionContext) {
} = OLA_ACTIONS;
const getComment = new Comments(
`${USER_MESSAGE} generates the code comments...`,
context,
context
);
const getInLineChat = new InLineChat(
`${USER_MESSAGE} generates a response...`,
context,
context
);
const generateOptimizeCode = new OptimizeCode(
`${USER_MESSAGE} optimizes the code...`,
context,
context
);
const generateRefactoredCode = new RefactorCode(
`${USER_MESSAGE} refactors the code...`,
context,
context
);
const explainCode = new ExplainCode(
`${USER_MESSAGE} explains the code...`,
context,
context
);
const generateReview = new ReviewCode(
`${USER_MESSAGE} reviews the code...`,
context,
context
);
const codeChartGenerator = new CodeChartGenerator(
`${USER_MESSAGE} creates the code chart...`,
context,
context
);
const codePattern = new FileUploader(context);
const knowledgeBase = new ReadFromKnowledgeBase(
`${USER_MESSAGE} generate your code pattern...`,
context,
context
);
const generateCommitMessage = new GenerateCommitMessage(
`${USER_MESSAGE} generates a commit message...`,
context,
context
);
const generateInterviewQuestions = new InterviewMe(
`${USER_MESSAGE} generates interview questions...`,
context,
context
);

const generateUnitTests = new GenerateUnitTest(
`${USER_MESSAGE} generates unit tests...`,
context,
context
);

const actionMap = {
Expand All @@ -126,7 +126,7 @@ export async function activate(context: vscode.ExtensionContext) {
new FixError(
`${USER_MESSAGE} finds a solution to the error...`,
context,
errorMessage,
errorMessage
).execute(errorMessage),
[explain]: () => explainCode.execute(),
[pattern]: () => codePattern.uploadFileHandler(),
Expand All @@ -137,7 +137,7 @@ export async function activate(context: vscode.ExtensionContext) {
};

const subscriptions: vscode.Disposable[] = Object.entries(actionMap).map(
([action, handler]) => vscode.commands.registerCommand(action, handler),
([action, handler]) => vscode.commands.registerCommand(action, handler)
);

const selectedGenerativeAiModel = getConfigValue("generativeAi.option");
Expand All @@ -146,7 +146,7 @@ export async function activate(context: vscode.ExtensionContext) {
const quickFixCodeAction: vscode.Disposable =
vscode.languages.registerCodeActionsProvider(
{ scheme: "file", language: "*" },
quickFix,
quickFix
);

const modelConfigurations: {
Expand Down Expand Up @@ -186,13 +186,13 @@ export async function activate(context: vscode.ExtensionContext) {
key,
webviewProviderClass,
subscriptions,
quickFixCodeAction,
quickFixCodeAction
);
}
} catch (error) {
Brain.clear();
vscode.window.showErrorMessage(
"An Error occured while setting up generative AI model",
"An Error occured while setting up generative AI model"
);
console.log(error);
}
Expand Down
22 changes: 18 additions & 4 deletions src/infrastructure/repository/code-repository.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ICodeRepository } from "../../application/interfaces/code.repository.interface";
import { Client, createClient, ResultSet, Row } from "@libsql/client";
import { Logger } from "../logger/logger";
import { createTableQuery, selectFunctionProps } from "./sql";
import { createTableQuery, insertDataQuery, selectFunctionProps } from "./sql";

export class CodeRepository implements ICodeRepository {
private client: Client | undefined;
Expand Down Expand Up @@ -30,9 +30,23 @@ export class CodeRepository implements ICodeRepository {
return CodeRepository.instance;
}

async CreateTable(values: string): Promise<ResultSet[] | undefined> {
async CreateTable(): Promise<ResultSet[] | undefined> {
try {
const query = createTableQuery(values);
const query = createTableQuery();
const table = await this.client?.batch(query, "write");
if (table) {
this.logger.info("Database initialized successfully");
}
return table;
} catch (error) {
this.logger.error("Failed to initialize database", error);
throw error;
}
}

async InsertData(values: string) {
try {
const query = insertDataQuery(values);
const table = await this.client?.batch(query, "write");
if (table) {
this.logger.info("Database initialized successfully");
Expand All @@ -46,7 +60,7 @@ export class CodeRepository implements ICodeRepository {

async searchSimilarFunctions(
queryEmbeddings: number[],
limit: number,
limit: number
): Promise<Row[] | undefined> {
try {
const query = selectFunctionProps();
Expand Down
9 changes: 7 additions & 2 deletions src/infrastructure/repository/sql.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const createTableQuery = (values: string) => {
export const createTableQuery = () => {
return [
"DROP TABLE IF EXISTS code_functions",
`CREATE TABLE IF NOT EXISTS code_functions (
Expand All @@ -9,8 +9,13 @@ export const createTableQuery = (values: string) => {
embedding F32_BLOB(768) NOT NULL
)`,
"CREATE INDEX IF NOT EXISTS code_functions_idx ON code_functions (libsql_vector_idx(embedding))",
];
};

export const insertDataQuery = (values: string) => {
return [
`INSERT INTO code_functions (class_name, function_name, file_path, created_at, embedding)
VALUES ${values}`,
VALUES ${values}`,
];
};

Expand Down
10 changes: 5 additions & 5 deletions src/services/code-structure.mapper.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export class CodeStructureMapper {
*/
private getMappedFunctions(
codeEntry: ICodeEntry,
primaryClass: ICodeClass | null,
primaryClass: ICodeClass | null
): IMappedFunction[] {
try {
const sourceFunctions = this.getSourceFunctions(codeEntry, primaryClass);
Expand All @@ -77,7 +77,7 @@ export class CodeStructureMapper {
*/
private getSourceFunctions(
codeEntry: ICodeEntry,
primaryClass: ICodeClass | null,
primaryClass: ICodeClass | null
): IMappedFunction[] | undefined {
try {
return (codeEntry.functions?.length ?? 0) > 0
Expand All @@ -97,7 +97,7 @@ export class CodeStructureMapper {
*/
private mapFunctions(
functions: IMappedFunction[],
codeEntry?: ICodeEntry,
codeEntry?: ICodeEntry
): IMappedFunction[] {
try {
return functions.map((func) => ({
Expand All @@ -111,7 +111,7 @@ export class CodeStructureMapper {
func,
codeEntry?.dependencies && codeEntry?.dependencies.length > 0
? codeEntry.dependencies
: undefined,
: undefined
),
}));
} catch (error) {
Expand All @@ -122,7 +122,7 @@ export class CodeStructureMapper {

private createCompositeText(
functionProps: IMappedFunction,
dependencies: string[] = [],
dependencies: string[] = []
): string {
if (!this.createDescriptionText(functionProps)) {
return "";
Expand Down
45 changes: 45 additions & 0 deletions src/services/context-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { EmbeddingService } from "./embedding-service";
import { APP_CONFIG } from "../application/constant";
import { IFunctionData } from "../application/interfaces";
import { getConfigValue } from "../application/utils";
import { Logger } from "../infrastructure/logger/logger";
import { CodeStructureMapper } from "./code-structure.mapper.service";
import { TypeScriptAtsMapper } from "./typescript-ats.service";

export class ContextService {
logger: Logger;
embeddingService: EmbeddingService;
constructor() {
this.logger = new Logger("ContextService");
const apiKey = this.getAPIKey();
this.embeddingService = new EmbeddingService(apiKey);
}

getAPIKey(): string {
const { geminiKey } = APP_CONFIG;
const apiKey = getConfigValue(geminiKey);
if (!apiKey) {
this.logger.info("Gemini API Key is required for code indexing");
throw new Error("Gemini API Key is required for code indexing");
}
return apiKey;
}

async buildFunctionStructureMap() {
const codeATS = TypeScriptAtsMapper.getInstance();
const mappedCode = await codeATS.buildCodebaseMap();
const ats = Object.values(mappedCode).flatMap((repo) =>
Object.values(repo.modules)
);
const mapper = new CodeStructureMapper(ats);
return mapper.normalizeData();
}

async generateFunctionDescription() {
const functions =
(await this.buildFunctionStructureMap()) as IFunctionData[];
return await this.embeddingService.processFunctions(functions);
}

// async generateContextEmbeddings
}
Loading

0 comments on commit a9e9b75

Please sign in to comment.