Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements/code cleanup #39

Merged
merged 7 commits into from
Dec 19, 2024
Merged

Improvements/code cleanup #39

merged 7 commits into from
Dec 19, 2024

Conversation

Amruth-Vamshi
Copy link
Contributor

@Amruth-Vamshi Amruth-Vamshi commented Dec 18, 2024

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a caching mechanism using Redis for improved performance.
    • Added Swagger documentation for various API endpoints, enhancing usability.
    • New user ID generation and message reaction endpoints implemented.
    • Enhanced logging capabilities across services using the NestJS logging framework.
  • Bug Fixes

    • Improved error handling and logging across multiple services and controllers.
  • Refactor

    • Replaced custom logging implementations with NestJS's built-in logging framework.
    • Removed telemetry-related functionality, simplifying the application structure.
  • Chores

    • Updated dependencies in the project configuration for enhanced functionality and performance.
    • Updated Dockerfile to use Node.js version 18 for the build stage.
    • Updated CI workflow to support only Node.js version 18.

Copy link

coderabbitai bot commented Dec 18, 2024

Walkthrough

This pull request introduces significant architectural changes to the application, focusing on logging, caching, and API documentation. The primary modifications include replacing the custom telemetry and logging systems with NestJS's native logging and Pino, integrating Redis-based caching, adding Swagger API documentation, and removing telemetry-related modules. The changes enhance observability, performance, and maintainability by standardizing logging, introducing caching mechanisms, and providing comprehensive API documentation.

Changes

File/Module Change Summary
package.json - Added Swagger, Redis cache, and Pino logging dependencies
- Removed Winston logging
prisma/schema.prisma - Removed telemetry_logs model
src/app.module.ts - Added LoggerModule with Pino configuration
- Added HttpModule and CacheModule
- Removed TelemetryModule
src/app.controller.ts, src/app.service.ts, src/modules/user/user.controller.ts, src/modules/user/user.service.ts, src/modules/conversation/conversation.service.ts, src/modules/aiTools/ai-tools.service.ts, src/global-services/prisma.service.ts, src/common/fetch.ts, src/xstate/prompt/prompt.service.ts, src/xstate/prompt/prompt.machine.ts - Replaced CustomLogger with NestJS Logger
- Updated logging mechanisms across services
src/modules/telemetry - Completely removed telemetry-related controllers, services, and modules
src/modules/cache/cache.provider.ts - Added CacheProvider for Redis-based caching
src/modules/monitoring - Enhanced metric handling and added caching capabilities
src/modules/conversation/conversation.controller.ts - Added new feedback endpoint with Swagger documentation
src/xstate/prompt/prompt.module.ts - Added HttpModule for HTTP functionalities
Dockerfile - Updated Node.js version from 16 to 18 for the build stage
.github/workflows/ci.yml - Updated CI configuration to support only Node.js version 18

Sequence Diagram

sequenceDiagram
    participant Client
    participant Controller
    participant Service
    participant CacheProvider
    participant PrismaService
    participant Logger

    Client->>Controller: HTTP Request
    Controller->>Logger: Log Request Details
    Controller->>CacheProvider: Check Cache
    alt Cache Hit
        CacheProvider-->>Controller: Return Cached Data
    else Cache Miss
        Controller->>Service: Process Request
        Service->>PrismaService: Query Database
        PrismaService-->>Service: Return Data
        Service->>CacheProvider: Store in Cache
        Service-->>Controller: Return Response
    end
    Controller->>Logger: Log Response
    Controller-->>Client: HTTP Response
Loading

Poem

🐰 A Rabbit's Ode to Code Refactoring 🔧

Logs now dance with Pino's grace,
Telemetry vanished without a trace.
Redis caches with lightning speed,
Swagger docs, our API's creed!
Hop, hop, hooray for cleaner code! 🚀


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 15

🔭 Outside diff range comments (11)
src/modules/conversation/conversation.controller.ts (1)

Line range hint 24-27: Add type safety and validation to the feedback endpoint

The current implementation lacks:

  1. Type safety (using any)
  2. Input validation
  3. Error handling
-  async createOrUpdateFeedback(@Body() body: any) {
+  async createOrUpdateFeedback(
+    @Body() feedbackDto: FeedbackDto
+  ): Promise<{ success: boolean }> {
+    try {
+      await this.conversationService.createOrUpdateFeedback(feedbackDto);
+      return { success: true };
+    } catch (error) {
+      throw new BadRequestException('Failed to process feedback');
+    }
   }
src/modules/conversation/conversation.service.ts (1)

Line range hint 15-31: Add error logging for database operations

The saveConversation method should include error logging and proper error handling.

 async saveConversation(
   sessionId: string,
   userId: string,
   context: any,
   state: string,
   flowId: string
 ): Promise<any> {
+  try {
     return await this.prisma.conversation.upsert({
       where: { id: sessionId },
       create: { 
           id: sessionId,
           userId,
           context,
           state,
           flowId
        },
       update: { state, context },
     });
+  } catch (error) {
+    this.logger.error('Failed to save conversation', {
+      sessionId,
+      userId,
+      error: error.message
+    });
+    throw error;
+  }
 }
src/common/utils.ts (1)

Line range hint 156-180: Improve error handling in encryptRequest

The error handling in the encryption process needs improvement.

 export const encryptRequest = async (text: string) => {
   try {
     var myHeaders = new Headers();
     myHeaders.append("Content-Type", "application/json");
-    logger.log("text: ", text);
+    logger.log('Encrypting request', { textLength: text.length });
     var raw = JSON.stringify({
       EncryptedRequest: text,
     });

     var requestOptions: any = {
       method: "POST",
       headers: myHeaders,
       body: raw,
       redirect: "follow",
     };

+    if (!process.env.PM_KISAN_ENC_DEC_API) {
+      throw new Error('Encryption API URL not configured');
+    }

     let response: any = await fetch(
       `${process.env.PM_KISAN_ENC_DEC_API}/EncryptedRequest`,
       requestOptions
     );
+    if (!response.ok) {
+      throw new Error(`Encryption failed with status: ${response.status}`);
+    }
     response = await response.json();
     return response;
   } catch (error) {
+    logger.error('Failed to encrypt request', { error: error.message });
     return {
-      error: "Error while encrypting the message.",
+      error: `Encryption failed: ${error.message}`,
     };
   }
 };
src/modules/user/user.service.ts (2)

Line range hint 203-205: Critical: SQL Injection vulnerability in raw queries

Direct string interpolation in SQL queries creates a security vulnerability. Use parameterized queries instead.

Example fix for one of the queries:

-    return this.prisma.$queryRawUnsafe(`
-      SELECT * from "Message" where id = '${id}'
-    `);
+    return this.prisma.$queryRaw`
+      SELECT * from "Message" where id = ${id}
+    `;

Also applies to: 211-213, 220-222


Line range hint 195-205: Restore error handling in likeQuery method

The commented-out try-catch block leaves the method vulnerable to unhandled exceptions. Database operations should always include proper error handling.

 async likeQuery(id): Promise<Message> {
-    // try {
+    try {
     await this.prisma.$queryRawUnsafe(`
         UPDATE "Message" SET 
         "reaction" = 1
         WHERE "id" = '${id}'`);
+    } catch (error) {
+      this.logger.error('Failed to update reaction', error);
+      throw error;
+    }
-    // } catch {
-    //   return null;
-    // }
     this.monitoringService.incrementPositveFeedbackCount();
     return this.prisma.$queryRawUnsafe(`
       SELECT * from "Message" where id = '${id}'
     `);
 }
src/modules/monitoring/monitoring.controller.ts (2)

Line range hint 9-10: Replace console.log with structured logging

Use the NestJS Logger for consistent logging across the application.

-    console.log(metric)
+    private readonly logger = new Logger(MonitoringController.name);
+    this.logger.log(`Incrementing metric: ${metric}`);

Line range hint 9-186: Refactor long switch statement for better maintainability

The current implementation has several issues:

  1. The method is too long
  2. Lacks type safety for metric parameter
  3. Contains repetitive code patterns

Consider creating an enum for metrics and a map of metric handlers:

enum MetricType {
  BHASHINI_COUNT = 'bhashiniCount',
  BHASHINI_SUCCESS_COUNT = 'bhashiniSuccessCount',
  // ... other metrics
}

interface MetricHandler {
  increment: () => void;
  get: () => Promise<number>;
}

private metricHandlers: Map<MetricType, MetricHandler> = new Map([
  [MetricType.BHASHINI_COUNT, {
    increment: () => this.monitoringService.incrementBhashiniCount(),
    get: () => this.monitoringService.getBhashiniCount()
  }],
  // ... other handlers
]);

async incrementmetrics(@Body() metric: MetricType): Promise<any> {
  const handler = this.metricHandlers.get(metric);
  if (!handler) {
    return `'${metric}' metric does not exist`;
  }
  
  handler.increment();
  return await handler.get();
}
src/xstate/prompt/prompt.service.ts (1)

Line range hint 155-275: Improve data handling and method organization

The method has several concerns:

  1. Potential exposure of sensitive data in logs
  2. Complex error handling
  3. Multiple responsibilities

Consider splitting the method into smaller, focused methods and improving data handling:

private async getUserType(userIdentifier: string): Promise<{type: string, isValid: boolean}> {
  if (/^[6-9]\d{9}$/.test(userIdentifier)) {
    return { type: 'Mobile', isValid: true };
  }
  // ... other type checks
  return { type: '', isValid: false };
}

private sanitizeLogData(data: any): any {
  const sensitiveFields = ['BeneficiaryName', 'FatherName', 'DOB', 'Address'];
  return Object.entries(data).reduce((acc, [key, value]) => {
    acc[key] = sensitiveFields.includes(key) ? '[REDACTED]' : value;
    return acc;
  }, {});
}

async fetchUserData(context, event) {
  this.logger.log('Fetching user data');
  const userIdentifier = `${context.userAadhaarNumber}${context.lastAadhaarDigits}`;
  
  const { type, isValid } = await this.getUserType(userIdentifier);
  if (!isValid) {
    throw new Error('Invalid identifier format');
  }
  
  const userData = await this.userService.getUserData(userIdentifier, type);
  this.logger.log('User data fetched', this.sanitizeLogData(userData));
  
  // ... rest of the implementation
}
src/modules/aiTools/ai-tools.service.ts (3)

Line range hint 143-247: Consider extracting common Bhashini configuration handling

Both methods share similar patterns for Bhashini configuration and error handling. Consider extracting these into reusable utilities.

Consider creating a shared utility:

private async getBhashiniTaskConfig(
  task: string,
  language: Language,
  additionalConfig: Record<string, any> = {}
) {
  const baseConfig = {
    language: {
      sourceLanguage: language
    },
    ...additionalConfig
  };
  
  return this.getBhashiniConfig(task, baseConfig);
}

This would simplify both methods and reduce code duplication.


Line range hint 249-274: Critical: Fix potential XSS vulnerability and modernize HTTP client usage

  1. The query parameter is not properly encoded, which could lead to XSS
  2. The method uses deprecated node-fetch instead of the injected HttpService

Apply these changes:

 async textClassification(text: string) {
   try {
-    var myHeaders = new Headers();
-    myHeaders.append("accept", "application/json");
-    myHeaders.append("X-API-Key", this.configService.get("WADHWANI_API_KEY"));
-    let response: any = await fetch(
-      `${this.configService.get(
-        "WADHWANI_BASE_URL"
-      )}/detect_query_intent?query=${text}`,
-      {
-        headers: myHeaders,
-        method: "GET",
-        mode: "cors",
-        credentials: "omit",
-      }
-    );
-    response = await response.text();
+    const response = await this.httpService.get(
+      `${this.configService.get("WADHWANI_BASE_URL")}/detect_query_intent`,
+      {
+        params: { query: text },
+        headers: {
+          'X-API-Key': this.configService.get("WADHWANI_API_KEY")
+        }
+      }
+    ).toPromise();
+    
     return response;
   } catch (error) {
     this.logger.error(error);
     return {
       error,
     };
   }
 }

Line range hint 276-303: Critical: Fix security vulnerabilities and improve HTTP client usage

Similar to textClassification, this method needs security improvements:

  1. URL parameters need proper encoding
  2. Should use HttpService instead of node-fetch
  3. Good addition of performance logging, but could be extracted into a decorator

Apply these changes:

+ private logApiTiming(startDate: Date, userId: string, sessionId: string, url: string) {
+   const endDate = new Date();
+   const duration = endDate.getTime() - startDate.getTime();
+   this.logger.log(`${endDate}: userId: ${userId} sessionId: ${sessionId} URL: ${url} Responded successfully in ${duration} ms.`);
+ }

 async getResponseViaWadhwani(
   sessionId: string,
   userId: string,
   text: string,
   schemeName: string
 ) {
   try {
     const startDate = new Date();
-    var myHeaders = new Headers();
-    myHeaders.append("accept", "application/json");
-    myHeaders.append("X-API-Key", this.configService.get("WADHWANI_API_KEY"));
     
-    let response: any = await fetch(`${this.configService.get("WADHWANI_BASE_URL")}/get_bot_response?query=${text}&user_id=${userId}&session_id=${sessionId}&scheme_name=${schemeName}`, {
-      headers: myHeaders,
-      "method": "GET",
-      "mode": "cors",
-      "credentials": "omit"
-    });
+    const response = await this.httpService.get(
+      `${this.configService.get("WADHWANI_BASE_URL")}/get_bot_response`,
+      {
+        params: {
+          query: text,
+          user_id: userId,
+          session_id: sessionId,
+          scheme_name: schemeName
+        },
+        headers: {
+          'X-API-Key': this.configService.get("WADHWANI_API_KEY")
+        }
+      }
+    ).toPromise();
     
-    response = await response.json()
+    this.logApiTiming(startDate, userId, sessionId, response.config.url);
     
     return response;
   } catch(error) {
     this.logger.error(error);
     return { error };
   }
 }
🧹 Nitpick comments (32)
src/modules/user/user.controller.ts (3)

1-1: Use consistent import ordering.
While functional, it's often a good practice to group external and local imports consistently for readability.


12-12: Replace direct initialization with DI if reuse is needed.
Currently, the controller manually initializes a generic Logger instance. If more sophisticated or custom usage is needed, consider injecting the logger. For now, this is acceptable.


18-18: Log context name 'main' might be too generic.
Consider using a more specific context like 'UserController' for clarity in logs.

src/app.module.ts (1)

22-46: New logging configuration with pinoHttp and Loki integration.
This approach standardizes logs with pino-loki. Check that environment-specific details (e.g., LOKI_INTERNAL_BASE_URL) are properly set in production.

src/app.controller.ts (9)

90-90: Add AiToolsService usage with HttpService
Double-check any concurrency or error handling logic if large requests are made.


103-103: Logger context set to AppService
Might be more precise to reference AppController, but it’s acceptable.


202-202: Comment logs
Consider removing or converting to debug logs if not needed in production.


210-210: Detecting input language
Watch for performance overhead if done frequently. Possibly cache language detection results.


216-216: Commented-out logger code
Consider removing dead code if not needed for future debugging.


258-258: Commented code
Evaluate removing if it’s no longer needed for debugging.


297-297: Create a new message
In-line comments are commented out. If not needed, remove them for clarity.


359-359: Error logging
Ensure that repeated error messages do not spam logs.


616-617: Detailed log with userId, sessionId, and current state
Valuable for debugging. If logs become large, consider adjusting the level to debug.

src/modules/monitoring/monitoring.service.ts (5)

577-577: Increment totalSuccessfullSessions
Ensure consistent spelling: “Successful” vs. “Successfull.”

-  totalSuccessfullSessions
+  totalSuccessfulSessions

642-642: incrementPositveFeedbackCount
Check for spelling: “positive.”

- incrementPositveFeedbackCount
+ incrementPositiveFeedbackCount

806-806: Catch block
Only logs error with console.log. Consider adding structured logger usage.


818-818: Repetitive code
Possible refactoring into a shared private method for upsert logic.


832-832: Catch block
Same suggestion: replace console.log with structured logging.

src/xstate/prompt/prompt.machine.ts (1)

483-483: Logging Assigned Query Type
Logging the assigned query type here is helpful for debugging user input classification. Consider including additional contextual info (like user ID if available) to further enhance traceability.

src/common/fetch.ts (1)

5-7: Consider dependency injection for logger

Instead of creating a new Logger instance directly, consider using dependency injection to align with NestJS best practices and improve testability.

-const logger = new Logger(
-  'fetch'
-);

Then inject it where this module is used:

@Injectable()
class SomeService {
  constructor(private readonly logger: Logger) {
    this.logger.setContext('fetch');
  }
}
src/app.service.ts (3)

40-43: Move cron schedule to configuration

The cron schedule should be configurable through the ConfigService for better maintainability.

-this.logger.log("scheduling cron for every 30min");
-cron.schedule('*/30 * * * *', () => {
+const cronSchedule = this.configService.get('AADHAAR_CLEANUP_SCHEDULE', '*/30 * * * *');
+this.logger.log(`Scheduling Aadhaar cleanup cron: ${cronSchedule}`);
+cron.schedule(cronSchedule, () => {

82-84: Enhance error logging

The error logging should include more context and use structured logging.

-this.logger.log('Cleared userAadhaarNumber in conversations older than 30 minutes.');
+this.logger.log(`Cleared Aadhaar numbers from ${conversations.length} conversations`);
 } catch (error) {
-  this.logger.error('Error clearing Aadhaar numbers:', error);
+  this.logger.error('Failed to clear Aadhaar numbers', {
+    error: error.message,
+    stack: error.stack,
+    timestamp: new Date().toISOString()
+  });

Line range hint 46-81: Consider implementing secure data handling for Aadhaar numbers

The current implementation directly manipulates sensitive Aadhaar data. Consider:

  1. Using encryption for Aadhaar numbers in the database
  2. Implementing audit logging for all Aadhaar-related operations
  3. Adding rate limiting for the cleanup operation

Would you like me to provide a detailed implementation for these security enhancements?

src/modules/conversation/conversation.service.ts (2)

13-13: Use more specific logger context

The logger context 'main' is too generic. Consider using the service name or a more descriptive context.

-this.logger = new Logger('main');
+this.logger = new Logger(ConversationService.name);

8-8: Improve type safety

Consider adding proper TypeScript interfaces for the context and feedback objects instead of using any.

interface ConversationContext {
  userAadhaarNumber?: string;
  lastAadhaarDigits?: string;
  isOTPVerified: boolean;
  currentState: string;
  type: string;
  query: string;
  response: string;
}
src/main.ts (1)

34-42: Enhance Swagger documentation setup

The Swagger configuration looks good but could be enhanced with more details.

Consider adding:

 const config = new DocumentBuilder()
   .setTitle('PM Kisan API Documentation')
   .setDescription('The PM Kisan API description')
   .setVersion('1.0')
+  .addTag('PM Kisan')
+  .addServer('http://localhost:3001', 'Local environment')
+  .addServer('https://api.pmkisan.example.com', 'Production environment')
   .addBearerAuth()
+  .setContact('PM Kisan Team', 'https://www.pmkisan.example.com', '[email protected]')
+  .setLicense('Private', 'https://www.pmkisan.example.com/license')
   .build();
src/common/utils.ts (1)

157-159: Enhance logging in encryptRequest

The logging implementation could be improved with structured logging.

-    logger.log("text: ", text);
+    logger.log('Encrypting request', { textLength: text.length });
src/modules/user/user.service.ts (1)

11-11: Consider using class name as logger identifier

The logger is initialized with a generic 'main' identifier. For better log traceability and consistency, consider using the class name 'UserService' as the logger identifier.

-    this.logger = new Logger('main');
+    this.logger = new Logger(UserService.name);

Also applies to: 17-17

src/modules/aiTools/ai-tools.service.ts (4)

Line range hint 28-77: Consider enhancing error handling and simplifying logic

While the logging improvements are good, consider these enhancements:

  1. The nested conditions for language detection could be simplified
  2. The error handling could be more consistent across different scenarios

Consider this refactor:

 async detectLanguage(text: string, userId: string, sessionId: string): Promise<any> {
   try {
-    let input = {
+    const input = {
       input: [
         {
           source: text,
         },
       ],
     };
 
-    let response: any = await this.computeBhashini(
+    const response: any = await this.computeBhashini(
       // ... existing parameters ...
     )
-    if(response["error"]){
+    if (response.error) {
       this.logger.error(response["error"])
       throw new Error(response["error"])
     }
-    let language: Language;
-    if(response.output && response.output.length){
-      language = response.data?.pipelineResponse[0]?.output[0]?.langPrediction[0]?.langCode as Language
+    
+    const language = response.output?.length 
+      ? response.data?.pipelineResponse[0]?.output[0]?.langPrediction[0]?.langCode as Language
+      : 'unk';
+    
+    if (language !== 'unk') {
       this.monitoringService.incrementBhashiniSuccessCount()
-      return {
-        language: language || 'unk',
-        error: null
-      }
-    } else {
+    } else {
       this.monitoringService.incrementBhashiniFailureCount()
-      return {
-        language: 'unk',
-        error: null
-      }
     }
+    return { language, error: null }

Line range hint 79-141: Consider documenting URL handling and extracting helper methods

The URL handling logic using placeholders is clever but could benefit from:

  1. Documentation explaining the placeholder mechanism
  2. Extraction of URL handling into a separate method

Consider this refactor:

+ /**
+  * Handles translation while preserving URLs in the text
+  * @param source Source language
+  * @param target Target language
+  * @param text Text to translate
+  * @param userId User ID for tracking
+  * @param sessionId Session ID for tracking
+  * @returns Translated text with preserved URLs
+  */
 async translate(
   source: Language,
   target: Language,
   text: string,
   userId: string,
   sessionId: string
 ) {
   try {
-    const urlRegex = /(https?:\/\/[^\s]+)|(www\.[^\s]+)/g;
-    const urls = text.match(urlRegex) || [];
-    const placeHolder = "9814567092798090023722437987555212294";
-    const textWithoutUrls = text.replace(urlRegex, placeHolder);
+    const { textWithoutUrls, urls, placeHolder } = this.extractUrls(text);
     
     // ... rest of the method
   }
 }

+ /**
+  * Extracts URLs from text and replaces them with a placeholder
+  * @param text Input text
+  * @returns Object containing processed text and extracted URLs
+  */
+ private extractUrls(text: string) {
+   const urlRegex = /(https?:\/\/[^\s]+)|(www\.[^\s]+)/g;
+   const urls = text.match(urlRegex) || [];
+   const placeHolder = "9814567092798090023722437987555212294";
+   const textWithoutUrls = text.replace(urlRegex, placeHolder);
+   return { textWithoutUrls, urls, placeHolder };
+ }

Line range hint 305-371: Consider simplifying retry logic and enhancing error handling

The caching implementation is good, but the retry logic could be simplified:

  1. The callback binding is complex and could be made more readable
  2. Error handling could be more specific

Consider these improvements:

 async getBhashiniConfig(task, config, userId, sessionId) {
   const cacheKey = `getBhashiniConfig:${JSON.stringify({ task, config })}`;
   
   try {
     const cachedData = await this.cacheManager.get(cacheKey);
     if (cachedData) {
       return cachedData;
     }
     
+    const headers = {
+      userID: this.configService.get("ULCA_USER_ID"),
+      ulcaApiKey: this.configService.get("ULCA_API_KEY"),
+      'Content-Type': 'application/json'
+    };
     
-    var myHeaders = new Headers();
-    myHeaders.append("userID", this.configService.get("ULCA_USER_ID"));
-    // ... rest of headers
     
+    const retryCallback = (retry: number) => {
+      const elapsed = Date.now() - startTime;
+      this.logger.error(
+        `userId: ${userId} sessionId: ${sessionId} URL: ${url} (config API) ` +
+        `Re-Trying: ${retry}, Previous failed call Time Taken: ${elapsed}ms`
+      );
+    };
     
     // ... rest of the method
   }
 }

Line range hint 373-447: Consider extracting common patterns and improving type safety

The method has good task-specific caching but could benefit from:

  1. Type definitions for tasks and configs
  2. Extraction of common retry logic

Consider adding these improvements:

type BhashiniTask = 'asr' | 'tts' | 'translation';

interface BhashiniConfig {
  serviceId: string;
  gender?: 'male' | 'female';
  samplingRate?: number;
  // ... other config properties
}

private createRetryCallback(
  startTime: number,
  userId: string,
  sessionId: string,
  url: string,
  task?: string
) {
  return (retry: number) => {
    const elapsed = Date.now() - startTime;
    const taskInfo = task ? `for task (${task})` : '';
    this.logger.error(
      `userId: ${userId} sessionId: ${sessionId} URL: ${url} ${taskInfo} ` +
      `Re-Trying: ${retry}, Previous failed call Time Taken: ${elapsed}ms`
    );
  };
}

This would improve type safety and reduce code duplication.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a5da5e3 and 97fd6e6.

📒 Files selected for processing (26)
  • package.json (3 hunks)
  • prisma/migrations/20241129023712_removed_telemetry_logs/migration.sql (1 hunks)
  • prisma/schema.prisma (0 hunks)
  • src/app.controller.ts (19 hunks)
  • src/app.module.ts (2 hunks)
  • src/app.service.ts (3 hunks)
  • src/common/fetch.ts (2 hunks)
  • src/common/logger.ts (0 hunks)
  • src/common/utils.ts (2 hunks)
  • src/global-services/prisma.service.ts (1 hunks)
  • src/main.ts (4 hunks)
  • src/modules/aiTools/ai-tools.service.ts (12 hunks)
  • src/modules/cache/cache.provider.ts (1 hunks)
  • src/modules/conversation/conversation.controller.ts (1 hunks)
  • src/modules/conversation/conversation.service.ts (1 hunks)
  • src/modules/monitoring/monitoring.controller.ts (1 hunks)
  • src/modules/monitoring/monitoring.module.ts (1 hunks)
  • src/modules/monitoring/monitoring.service.ts (10 hunks)
  • src/modules/telemetry/telemetry.controller.ts (0 hunks)
  • src/modules/telemetry/telemetry.module.ts (0 hunks)
  • src/modules/telemetry/telemetry.service.ts (0 hunks)
  • src/modules/user/user.controller.ts (1 hunks)
  • src/modules/user/user.service.ts (7 hunks)
  • src/xstate/prompt/prompt.machine.ts (4 hunks)
  • src/xstate/prompt/prompt.module.ts (1 hunks)
  • src/xstate/prompt/prompt.service.ts (9 hunks)
💤 Files with no reviewable changes (5)
  • src/modules/telemetry/telemetry.module.ts
  • src/modules/telemetry/telemetry.controller.ts
  • prisma/schema.prisma
  • src/common/logger.ts
  • src/modules/telemetry/telemetry.service.ts
🔇 Additional comments (82)
src/modules/user/user.controller.ts (6)

5-6: Great addition of ConfigService and Swagger decorators.
Enhancing the controller with configuration management and Swagger docs improves maintainability and API clarity.


9-9: API tags are properly defined.
This aligns with best practices for grouping endpoints in Swagger.


15-16: Constructor injection of PrismaService and ConfigService is correct.
No issues found; it follows NestJS injection best practices.


30-32: Message reaction endpoints are well-defined.
Ensure the userService methods handle errors gracefully (e.g., message not found).


38-40: Dislike endpoint is consistent with the like endpoint design.
Looks good. Just confirm userService handles DB constraints or missing messages.


46-48: Reaction removal endpoint is consistent.
No immediate issues. Ensure userService handles cases where there’s nothing to remove.

src/app.module.ts (5)

47-47: HttpModule included.
Helps make outbound requests. Confirm if it’s actually used throughout the code.


48-50: Global ConfigModule usage.
This is beneficial for broad configuration access. No issues found.


81-81: CacheProvider is injected as a provider.
Checks out. Ensure it’s used consistently across all modules that require caching.


83-83: Re-exporting CacheProvider.
Good for consistent usage across modules.


16-18: Added new dependencies (CacheProvider, HttpModule, LoggerModule).
Ensure they are all necessary and used in the codebase.

✅ Verification successful

Based on the search results, I can generate the final response as we have sufficient evidence showing that all three dependencies are actively used in the codebase:

All new dependencies are properly utilized in the codebase

  • CacheProvider is defined in cache.provider.ts, used in monitoring module, and exported by app.module
  • HttpModule is imported and used in both prompt and monitoring modules
  • LoggerModule is configured in app.module using forRoot()
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
rg 'CacheProvider|HttpModule|LoggerModule'

Length of output: 1236

src/app.controller.ts (12)

10-10: Switching to standard Logger.
This simplifies logging management and aligns with NestJS best practices.


28-29: HttpService and Swagger decorators are introduced.
Centralizing HTTP-based features and documentation is beneficial.


69-69: ApiTags('App') annotation for top-level controller.
This helps group endpoints meaningfully in Swagger.


77-77: Replaced CustomLogger with standard Logger property.
Fits the new logging architecture.


82-82: HttpService is now injected.
Ensure it’s used for necessary external calls and consider adding relevant error handling.


106-107: New Swagger doc for 'Get hello message'
Properly specifying summary and response improves clarity in API docs.


113-119: Enhanced API documentation for prompt endpoint.
This is a good practice for describing request/response expectations.


130-131: Logging userId and sessionId
Good approach for traceability. Verify that no sensitive info is overexposed.


234-234: Logger.error usage
Ensure sensitive data is not logged.


246-246: Logging 'Unsupported media'
This helps diagnose requests with invalid content.


284-284: Hashed Aadhaar
Great that it’s not stored as plain text. Ensure salt usage or additional security best practices.
[approve]


346-346: Logging error on translation failure
Well handled. Confirms error coverage.

src/modules/monitoring/monitoring.service.ts (46)

4-4: CacheProvider import
Good improvement for caching metrics and reducing DB load.


8-8: Injected CacheProvider in constructor
This ensures consistent usage of caching across the service.


10-10: initializeAsync method now uses cache
Be mindful of potential stale data if the cache isn’t updated frequently.


46-46: New stage counters
Stage-based metric tracking is clear. Ensure values are incremented at correct transitions.


51-51: Loop to upsert metrics
Efficient approach. Confirm that concurrency issues won’t arise if multiple processes do the same.


55-56: Retrieving existing metrics from DB
Checks if the record already exists. This is correct to avoid duplicates.
[approve]


72-73: Ensuring totalFailureSessions are synced with cache
Good alignment of cache and DB counters.


Line range hint 202-202: (No lines changed here; skipping)


558-558: Cache increment for Bhashini count
Check that no integer overflow occurs for very large volumes.


563-563: BhashiniSuccessCount
Similar approach. Looks fine.


572-572: Increment totalSessions
Aligns with new caching strategy.


582-582: Increment totalFailureSessions
Matches the pattern.


587-587: Increment totalIncompleteSessions
Good addition to track partial flows.


592-592: Increment totalSessionsInHindi
Make sure language detection is accurate.


597-597: Increment totalSessionsInTamil
Consistent pattern across languages.


602-602: Increment totalSessionsInOdia
Follow the same verification approach for detection.


607-607: Increment totalSessionsInTelugu
Good.


612-612: Increment totalSessionsInMarathi
Same approach. No issues.


617-617: Increment totalSessionsInBangla
No concerns.


622-622: Increment totalSessionsInEnglish
Be sure that fallback logic for unknown languages doesn’t artificially inflate English.


627-627: incrementAadhaarCount
Ensure that sensitive data is not included in logs or metrics.


632-632: incrementRegistrationIdCount
No issues.


637-637: incrementMobileNumberCount
Same caution about sensitive data.


647-647: incrementNegativeFeedbackCount
Looks consistent with positive feedback approach.


652-652: incrementMicUsedCount
Tracks usage stats properly.


657-657: incrementDirectMessageTypedCount
Clear metric for user interaction type.


662-662: incrementSampleQueryUsedCount
Tracks how often users rely on sample queries.


667-667: incrementInternalServerErrorCount
Ensures error metrics are tracked.


672-672: incrementBadGatewayCount
Matches the error metric pattern.


677-677: incrementGatewayTimeoutCount
No issues.


682-682: incrementSomethingWentWrongCount
Covers unexpected error occurrences.


687-687: incrementUnsupportedMediaCount
Useful for diagnosing content-related issues.


692-692: incrementUnableToTranslateCount
Aligns with user translation failure scenarios.


697-697: incrementSomethingWentWrongTryAgainCount
Clearly tracks repeated attempts.


702-702: incrementUnableToGetUserDetailsCount
Captures user retrieval failures in metrics.


707-707: incrementNoUserRecordsFoundCount
Consistent usage.


712-712: incrementUntrainedQueryCount
Tracks unrecognized queries.


717-717: incrementResentOTPCount
Captures OTP resending events.


722-722: incrementStage1Count
Stage-based tracking. No issues.


727-727: incrementStage2Count
Matches the pattern.


732-732: incrementStage3Count
All good.


737-737: incrementStage4Count
Same pattern.


742-742: incrementStage5Count
Completes the stage coverage.


747-749: Collecting metrics in onExit
Ensures final data is upserted to DB upon shutdown or service termination.


792-792: Update or create metrics
Handles scenario of existing or new metrics.


813-813: setMetrics method
Similar logic for upserting metrics.

src/xstate/prompt/prompt.machine.ts (4)

2-2: Use of NestJS Logger Import
Great job replacing the old logging approach with the standard NestJS Logger, which is more aligned with NestJS best practices.


8-10: Logger Initialization
Instantiating the logger at the top-level scope ensures it's readily accessible within this module. This centralizes logging behavior and makes it easier to control log outputs.


748-748: Logging OTP Assignment
Using the logger to record OTP setting is beneficial. Ensure no user-sensitive information is unintentionally exposed to logs in production.


1392-1392: Repeated OTP Logger Usage
Logging each OTP assignment consistently is valuable for debugging. Just be mindful of any potential PII or security exposure.

prisma/migrations/20241129023712_removed_telemetry_logs/migration.sql (1)

1-8: Dropping telemetry_logs table
Be certain you have thoroughly verified that none of the dropped data is needed for future analytics or auditing. The warning is clear about data loss; consider making a backup prior to running this migration in production.

src/xstate/prompt/prompt.module.ts (2)

1-1: HttpModule Import
Introducing HttpModule allows this module to perform HTTP requests natively with NestJS, opening up more integration possibilities.


9-9: HttpModule in Imports Array
Great job adding HttpModule into the module’s imports. This ensures Http functionality is available for providers or other classes within PromptModule.

src/global-services/prisma.service.ts (3)

1-1: Introducing HttpService Import
Consider verifying if the service is indeed using HttpService functionalities. If not, it may be removed to keep the file lean.


5-5: Use of Logger
Switching to NestJS Logger Streamlines the logging process and ensures consistency throughout the application.


14-15: Refactoring from CustomLogger to Logger
This is a welcome change. The built-in Logger improves maintainability and aligns with best practices.

src/common/fetch.ts (1)

34-36: 🛠️ Refactor suggestion

Enhance error logging

The catch block should log the error details using logger.error() to maintain proper error tracking.

 if (opts && opts.pause) {
     if (opts && !opts.silent) logger.log("pausing..");
+    logger.error('Fetch failed, retrying...', e);
     await sleep(opts.pause);
     if (opts && !opts.silent) logger.log("done pausing...");
 }

Likely invalid or redundant comment.

package.json (1)

41-41: Verify version compatibility and security

The new dependencies look good, but we should verify version compatibility and check for any known vulnerabilities.

Also applies to: 51-51, 74-74

✅ Verification successful

Let me gather more information about version compatibility by checking the package.json for related NestJS dependencies.


Dependencies are compatible and secure

The @nestjs/swagger version 8.0.7 is perfectly aligned with other NestJS dependencies in the package.json, which are all on version 8.x.x. No security vulnerabilities were found for @nestjs/swagger or cache-manager-redis-store. The version constraints are appropriate, maintaining compatibility while allowing for patch updates.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for compatible versions and security advisories
echo "Checking @nestjs/swagger..."
gh api graphql -f query='
{
  securityVulnerabilities(first: 5, ecosystem: NPM, package: "@nestjs/swagger") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
    }
  }
}'

echo "Checking cache-manager-redis-store..."
gh api graphql -f query='
{
  securityVulnerabilities(first: 5, ecosystem: NPM, package: "cache-manager-redis-store") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
    }
  }
}'

Length of output: 746


Script:

#!/bin/bash
# Check NestJS related dependencies and their versions
echo "Package.json content for NestJS dependencies:"
cat package.json | jq '.dependencies | with_entries(select(.key | contains("@nestjs")))'

# Check if there are any peer dependencies specified in package-lock.json
echo -e "\nChecking package-lock.json for peer dependencies:"
if [ -f "package-lock.json" ]; then
    cat package-lock.json | jq '.packages."node_modules/@nestjs/swagger".peerDependencies // empty'
fi

Length of output: 660

src/modules/aiTools/ai-tools.service.ts (1)

Line range hint 1-26: LGTM! Good improvements in dependency management and logging setup

The changes follow NestJS best practices by:

  • Using the built-in Logger service for consistent logging
  • Properly injecting HttpService for HTTP operations
  • Initializing the logger with the class name for better log identification

Comment on lines +21 to +23
@ApiOperation({ summary: 'Generate user ID' })
@ApiParam({ name: 'identifier', description: 'Unique identifier to generate UUID' })
@ApiResponse({ status: 200, description: 'User ID generated successfully' })
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Input validation needed for the identifier parameter

The endpoint currently lacks input validation for the identifier parameter. While the global ValidationPipe is configured in both app.module.ts and user.module.ts, there are no specific validation rules applied to the identifier parameter. Consider:

  • The identifier is used to generate a UUID v5, which requires a valid input string
  • No length limits or format validation is currently in place
  • No sanitization is performed on the input

Recommendations:

  • Create a DTO with class-validator decorators to validate the identifier
  • Add validation rules for minimum/maximum length
  • Consider adding a format pattern check if the identifier should follow a specific format
  • Apply the validation pipe at the parameter level with appropriate transform options
🔗 Analysis chain

UUID generation looks good.
You might want to verify that no further validation or sanitization is needed on the identifier.


Let me check if there's any input validation or sanitization in the codebase for this endpoint.


Let me check if there are any validation pipes or DTOs being used in the codebase that might be relevant.


Let me check the content of these modules to see how validation is configured.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
rg -A 3 'generateUserId'

Length of output: 378


Script:

#!/bin/bash
# Check for any input validation or sanitization related to the identifier
ast-grep --pattern 'class UserController {
  $$$
  generateUserId($$$) {
    $$$
  }
  $$$
}'

# Look for any validation pipes or decorators
rg -B 2 -A 2 '@Param.*identifier'

Length of output: 3935


Script:

#!/bin/bash
# Look for validation pipes in the codebase
rg -l "ValidationPipe"

# Look for any DTOs that might be related to user or identifier validation
fd -e ts dto

Length of output: 87


Script:

#!/bin/bash
# Check validation setup in the modules
cat src/app.module.ts
cat src/modules/user/user.module.ts

# Look for any input validation or sanitization utilities
rg -l "class-validator|class-transformer"

Length of output: 3328

}
res["messageId"] = uuid.v4();
res["conversationId"] = conversation?.id;
return res;
} else {
//translate to english
// console.log("Translating to English...")
// this.logger.log("Translating to English...")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Translating user input
Consider timeouts or fallback steps if translation fails or is too slow.

Comment on lines +20 to +28
// Method to get a value from cache
async get<T>(key: string): Promise<T | null> {
return this.cache.get(key);
}

// Method to set a value in cache
async set<T>(key: string, value: T): Promise<void> {
return this.cache.set(key, value);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance type safety and error handling for cache operations

The current implementation lacks proper error handling and type safety.

-  async get<T>(key: string): Promise<T | null> {
-    return this.cache.get(key);
+  async get<T>(key: string): Promise<T | null> {
+    try {
+      const value = await this.cache.get<T>(key);
+      return value;
+    } catch (error) {
+      console.error(`Error getting cache key ${key}:`, error);
+      return null;
+    }
   }

-  async set<T>(key: string, value: T): Promise<void> {
-    return this.cache.set(key, value);
+  async set<T>(key: string, value: T): Promise<void> {
+    try {
+      await this.cache.set(key, value);
+    } catch (error) {
+      console.error(`Error setting cache key ${key}:`, error);
+      throw new CacheException(`Failed to set cache key: ${key}`);
+    }
   }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +35 to +42
async increment(key: string): Promise<void> {
let value: any = await this.get(key);
if(value) value= parseInt(value)
if(value){
return this.set(key, value + 1);
}
return this.set(key, 1);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Fix type safety and error handling in increment method

The current implementation has several issues:

  1. Unsafe type casting
  2. Missing error handling
  3. Inconsistent code formatting
   async increment(key: string): Promise<void> {
-    let value: any = await this.get(key);
-    if(value) value= parseInt(value)
-    if(value){
-      return this.set(key, value + 1);
+    try {
+      const value = await this.get<string>(key);
+      const numericValue = value ? Number(value) : 0;
+      
+      if (Number.isNaN(numericValue)) {
+        throw new Error(`Cache value for key ${key} is not a number`);
+      }
+      
+      await this.set(key, numericValue + 1);
+    } catch (error) {
+      console.error(`Error incrementing cache key ${key}:`, error);
+      throw new CacheException(`Failed to increment cache key: ${key}`);
     }
-    return this.set(key, 1);
   }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 11 to 18
constructor() {
this.redisClient = createClient({ url: 'redis://localhost:6379' });
this.cache = cacheManager.caching({
store: redisStore,
client: this.redisClient,
ttl: 60 * 5, // Time to live in seconds
});
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Critical: Improve Redis client configuration and error handling

Several architectural improvements are needed:

  1. Move Redis configuration to environment variables
  2. Add error handling for connection failures
  3. Implement proper cleanup on application shutdown

Consider this implementation:

-  constructor() {
+  constructor(private configService: ConfigService) {
+    this.initializeRedisClient();
+  }
+
+  private async initializeRedisClient() {
+    const redisUrl = this.configService.get<string>('REDIS_URL');
     this.redisClient = createClient({ 
-      url: 'redis://localhost:6379' 
+      url: redisUrl
     });
+
+    this.redisClient.on('error', (err) => {
+      console.error('Redis Client Error:', err);
+    });
+
+    await this.redisClient.connect();
+
     this.cache = cacheManager.caching({
       store: redisStore,
       client: this.redisClient,
-      ttl: 60 * 5, // Time to live in seconds
+      ttl: this.configService.get<number>('REDIS_TTL', 300),
     });
   }
+
+  async onApplicationShutdown() {
+    await this.redisClient.quit();
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
constructor() {
this.redisClient = createClient({ url: 'redis://localhost:6379' });
this.cache = cacheManager.caching({
store: redisStore,
client: this.redisClient,
ttl: 60 * 5, // Time to live in seconds
});
}
constructor(private configService: ConfigService) {
this.initializeRedisClient();
}
private async initializeRedisClient() {
const redisUrl = this.configService.get<string>('REDIS_URL');
this.redisClient = createClient({
url: redisUrl
});
this.redisClient.on('error', (err) => {
console.error('Redis Client Error:', err);
});
await this.redisClient.connect();
this.cache = cacheManager.caching({
store: redisStore,
client: this.redisClient,
ttl: this.configService.get<number>('REDIS_TTL', 300),
});
}
async onApplicationShutdown() {
await this.redisClient.quit();
}

src/main.ts Outdated
@@ -72,7 +86,7 @@
await app.register(multipart);
await app.register(compression, { encodings: ["gzip", "deflate"] });
app.useStaticAssets({ root: join(__dirname, "../../fileUploads") });
await app.listen(3000, "0.0.0.0");
await app.listen(3001, "0.0.0.0");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Port change requires environment configuration

The hardcoded port change from 3000 to 3001 should be configurable through environment variables.

-  await app.listen(3001, "0.0.0.0");
+  const port = configService.get<number>('PORT', 3001);
+  await app.listen(port, "0.0.0.0");
+  logger.log(`Application is running on: http://localhost:${port}`);

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +77 to +80
"nestjs-pino": "^4.1.0",
"pino-http": "^10.3.0",
"pino-loki": "^2.4.0",
"pino-pretty": "^13.0.0",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Move pino-http to devDependencies and ensure proper package organization

The codebase shows a well-structured logging setup using nestjs-pino, with pino-loki for production logging and pino-pretty for development formatting. However:

  • nestjs-pino is correctly used as the main logging framework
  • pino-loki is actively used for production logging to Loki
  • pino-pretty is used for development-time log formatting
  • pino-http is a dependency of nestjs-pino but not directly used, so it should be moved to devDependencies

Suggested changes:

  • Move pino-http to devDependencies section in package.json
  • Keep nestjs-pino, pino-loki, and pino-pretty as they serve specific purposes in the logging setup
🔗 Analysis chain

Consider consolidating logging packages

The addition of multiple Pino-related packages is good for enhanced logging, but we should ensure they're all necessary.

Consider if all these packages are necessary for your use case. If some are only used in development, move them to devDependencies.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if all logging packages are being used
rg "pino-http" -g "*.ts"
rg "pino-loki" -g "*.ts"
rg "pino-pretty" -g "*.ts"

Length of output: 183


Script:

#!/bin/bash
# Let's check the actual usage context in app.module.ts
cat src/app.module.ts

Length of output: 2636

Comment on lines +1 to +9
const fetch = require("./fetch");
const { Headers } = fetch;
const { Logger } = require('@nestjs/common');
const { HttpService } = require('@nestjs/axios');
const { ConfigService } = require('@nestjs/config');

const logger = new Logger(
'utils'
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve module imports and logger initialization

The logger initialization and imports could be improved.

-const fetch = require("./fetch");
-const { Headers } = fetch;
-const { Logger } = require('@nestjs/common');
-const { HttpService } = require('@nestjs/axios');
-const { ConfigService } = require('@nestjs/config');
+import fetch, { Headers } from './fetch';
+import { Logger } from '@nestjs/common';
+import { HttpService } from '@nestjs/axios';
+import { ConfigService } from '@nestjs/config';

-const logger = new Logger(
-  'utils'
-);
+const logger = new Logger('Utils');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const fetch = require("./fetch");
const { Headers } = fetch;
const { Logger } = require('@nestjs/common');
const { HttpService } = require('@nestjs/axios');
const { ConfigService } = require('@nestjs/config');
const logger = new Logger(
'utils'
);
import fetch, { Headers } from './fetch';
import { Logger } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { ConfigService } from '@nestjs/config';
const logger = new Logger('Utils');

Comment on lines +46 to +66
async questionClassifier (context) {
this.logger.log("IN questionclassifier");
try{
let response: any = await this.aiToolsService.getResponseViaWadhwani(context.sessionId, context.userId, context.query, context.schemeName)
if (response.error) throw new Error(`${response.error}, please try again.`)
let intent;
if (response.query_intent == "Invalid") intent = "convo"
if (response.query_intent == "convo_starter") intent = "convo"
if (response.query_intent == "convo_ender") intent = "convo"
if (response.query_intent == "Installment Not Received") intent = "payment"
else {
intent = "invalid"
}
return {
class: intent,
response: response.response
}
} catch (error){
return Promise.reject(error)
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve intent mapping and error handling

The current implementation has several areas for improvement:

  1. Intent mapping uses magic strings
  2. Unclear logic in intent assignment
  3. Inconsistent error handling

Consider this refactor:

enum QueryIntent {
  INVALID = 'Invalid',
  CONVO_STARTER = 'convo_starter',
  CONVO_ENDER = 'convo_ender',
  INSTALLMENT_NOT_RECEIVED = 'Installment Not Received'
}

enum IntentClass {
  CONVO = 'convo',
  PAYMENT = 'payment',
  INVALID = 'invalid'
}

private getIntentClass(queryIntent: string): IntentClass {
  switch (queryIntent) {
    case QueryIntent.INVALID:
    case QueryIntent.CONVO_STARTER:
    case QueryIntent.CONVO_ENDER:
      return IntentClass.CONVO;
    case QueryIntent.INSTALLMENT_NOT_RECEIVED:
      return IntentClass.PAYMENT;
    default:
      return IntentClass.INVALID;
  }
}

async questionClassifier(context) {
  this.logger.log('Starting question classification');
  try {
    const response = await this.aiToolsService.getResponseViaWadhwani(
      context.sessionId,
      context.userId,
      context.query,
      context.schemeName
    );
    
    if (response.error) {
      throw new Error(`Classification failed: ${response.error}`);
    }
    
    return {
      class: this.getIntentClass(response.query_intent),
      response: response.response
    };
  } catch (error) {
    this.logger.error('Question classification failed', error);
    throw error;
  }
}

Comment on lines +63 to +65
} catch (error){
return Promise.reject(error)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Standardize error handling across the service

Error handling is inconsistent across different methods. Some errors are logged, while others are silently rejected.

Consider implementing a centralized error handling approach:

private handleError(error: Error, context: string): never {
  this.logger.error(`Error in ${context}:`, error);
  throw new Error(`Operation failed in ${context}: ${error.message}`);
}

// Usage in methods:
async questionClassifier(context) {
  try {
    // ... implementation
  } catch (error) {
    this.handleError(error, 'questionClassifier');
  }
}

Also applies to: 110-112, 272-274

@codecov-commenter
Copy link

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

ℹ️ You can also turn on project coverage checks and project coverage reporting on Pull Request comment

Thanks for integrating Codecov - We've got you covered ☂️

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
src/modules/cache/cache.provider.ts (3)

11-23: ⚠️ Potential issue

Critical: Improve Redis configuration and connection handling

The Redis client initialization needs several improvements:

  1. Use ConfigService for configuration management
  2. Add connection and error handling
  3. Implement proper cleanup
  4. Remove the ambiguous comment about host

Additionally, verify the Redis connection configuration:

#!/bin/bash
# Check if Redis configuration is defined in environment files
fd -t f "env" -x grep -l "REDIS_"

25-33: ⚠️ Potential issue

Enhance error handling in get/set operations

The cache operations need proper error handling and type safety improvements.


40-47: ⚠️ Potential issue

Fix type safety and error handling in increment method

The increment operation has several issues with type safety and error handling.

🧹 Nitpick comments (1)
src/modules/cache/cache.provider.ts (1)

1-48: Consider additional cache management features

Consider enhancing the implementation with:

  1. Cache eviction policies and memory limits
  2. Cache hit/miss metrics for monitoring
  3. Circuit breaker pattern for Redis connection failures
  4. Cache warming strategies

Would you like assistance implementing any of these features?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d63a202 and ab93e2a.

📒 Files selected for processing (2)
  • src/main.ts (3 hunks)
  • src/modules/cache/cache.provider.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main.ts
🔇 Additional comments (1)
src/modules/cache/cache.provider.ts (1)

1-10: LGTM! Class structure and imports are well-organized.

The imports and class declaration follow NestJS best practices, with proper dependency imports and class decoration.

Comment on lines +35 to +38
// Optional: Method to delete a key from cache
async del(key: string): Promise<void> {
return this.cache.del(key);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling to delete operation

The del method should include error handling similar to other cache operations.

   async del(key: string): Promise<void> {
-    return this.cache.del(key);
+    try {
+      await this.cache.del(key);
+    } catch (error) {
+      console.error(`Error deleting cache key ${key}:`, error);
+      throw new Error(`Failed to delete cache key: ${key}`);
+    }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Optional: Method to delete a key from cache
async del(key: string): Promise<void> {
return this.cache.del(key);
}
// Optional: Method to delete a key from cache
async del(key: string): Promise<void> {
try {
await this.cache.del(key);
} catch (error) {
console.error(`Error deleting cache key ${key}:`, error);
throw new Error(`Failed to delete cache key: ${key}`);
}
}

@Amruth-Vamshi Amruth-Vamshi merged commit 34e37f3 into main Dec 19, 2024
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants