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

Cleanup Project Structure To Meet .NET Standards #352

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

OoLunar
Copy link

@OoLunar OoLunar commented Nov 5, 2024

Proposed changes

This PR does the following:

  • Deduplicates many resource files
  • Flattens the projects found within the examples and tests directories per .NET convention
  • Resolves GHSA-hh2w-p6rv-4g7w
  • Updates the .gitignore file
  • Updates all dependencies to their latest version

Types of changes

What types of changes does your code introduce to the community .NET SDK?
Put an x in the boxes that apply

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update or tests (if none of the other choices apply)

Checklist

Put an x in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code.

  • I have read the CONTRIBUTING doc
  • I have lint'ed all of my code using repo standards
  • I have added tests that prove my fix is effective or that my feature works
  • I have added necessary documentation (if appropriate)

Further comments

This PR is the first of many for updating this repository to meet the standard .NET project layout and practices. The next PR will be cleaning up the example and test code, then using the conventional logging from Microsoft.Extensions.Logging.Abstractions.

https://wakatime.com/@a8e4b5db-b8cc-469a-acce-099a0a2425be/projects/dammoujrda?branches=oolunar%2Fupdate-infra&start=2024-10-30&end=2024-11-05

Summary by CodeRabbit

  • New Features

    • Introduced multiple new projects for various functionalities, including Analyze, Manage, and SpeechToText, enhancing the application's capabilities.
    • Added support for real-time speech-to-text transcription via WebSocket and REST clients.
  • Bug Fixes

    • Improved error handling and logging throughout various examples to enhance user experience and debugging.
  • Refactor

    • Restructured existing projects and removed outdated project files, streamlining the codebase.
  • Documentation

    • Updated project configurations to ensure compatibility with the latest .NET framework and dependencies.

Copy link
Contributor

coderabbitai bot commented Nov 5, 2024

Walkthrough

This pull request encompasses a comprehensive update to the project's structure, including the deletion of several Visual Studio solution and project files, specifically Deepgram.Dev.sln, Deepgram.DevBuild.sln, and various .csproj files. Additionally, it introduces a new .gitignore file with an expanded list of ignored files and directories relevant to various development tools and environments. The project files that remain have been updated to target .NET 9.0 and include new dependencies, reflecting a shift towards more modern configurations.

Changes

File/Directory Path Change Summary
.gitignore Expanded list of ignored files for development environments, including Visual Studio, .NET, etc.
Deepgram.Dev.sln Deleted; was a Visual Studio solution file for the Deepgram project.
Deepgram.DevBuild.sln Deleted; was a Visual Studio solution file for the Deepgram build.
Deepgram.Microphone/Deepgram.Microphone.csproj Updated package references to fixed versions for .NET frameworks.
Deepgram.Tests/Deepgram.Tests.csproj Updated package references with newer versions.
Deepgram.sln Significant restructuring with updated project identifiers and new example projects added.
Deepgram/Deepgram.csproj Updated package references for various dependencies.
Directory.Build.props New file created to define project root property.
clean-up.sh Deleted; was a shell script for cleaning project directories.
Various examples/.../*.csproj New project files created for various examples, targeting .NET 9.0 with updated dependencies.
Various examples/.../Program.cs New C# programs introduced with updated namespaces and accessibility for main methods.
examples/analyze/.../Analyze.csproj Deleted; project files related to analyze functionality removed.
examples/manage/.../Manage.csproj Deleted; project files related to manage functionality removed.
examples/speech-to-text/.../PreRecorded.csproj Deleted; project files related to speech-to-text functionality removed.
examples/text-to-speech/.../Speak.csproj Deleted; project files related to text-to-speech functionality removed.

Possibly related PRs

Suggested reviewers

  • lukeocodes
  • jpvajda
  • naomi-lgbt

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 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.

@dvonthenen
Copy link
Contributor

Some comments:

  1. This is likely to break the release process.
  2. You need to update all the documentation to update all links to these files (ie examples, clients, etc)

Copy link
Contributor

@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: 9

🧹 Outside diff range and nitpick comments (100)
examples/Deepgram.Examples.Analyze.Sentiment/Deepgram.Examples.Analyze.Sentiment.csproj (1)

1-12: Consider adding common properties

To align better with .NET standards, consider adding these common properties:

 	<PropertyGroup>
 		<OutputType>Exe</OutputType>
 		<TargetFramework>net8.0</TargetFramework>
 		<Nullable>enable</Nullable>
+		<ImplicitUsings>enable</ImplicitUsings>
+		<IsPackable>false</IsPackable>
+		<PublishAot>false</PublishAot>
 	</PropertyGroup>

These additions will:

  • Enable implicit usings (C# 10+ feature for cleaner code)
  • Explicitly mark as non-packable (it's an example project)
  • Explicitly disable AOT compilation (examples typically don't need it)
examples/Deepgram.Examples.TextToSpeech.Rest.File.HelloWorld/Program.cs (4)

5-8: Consider reorganizing using directives and modernizing namespace declaration.

To better align with .NET conventions, consider:

  1. Grouping System namespaces first
  2. Using file-scoped namespace declaration
using System;
using System.Threading.Tasks;
using Deepgram;
using Deepgram.Models.Speak.v1.REST;

-namespace SampleApp
-{
+namespace SampleApp;

Line range hint 31-32: Remove redundant commented code.

The commented WriteLine is identical to the active line below it and should be removed.

-            //Console.WriteLine(response);
             Console.WriteLine(response);

Line range hint 16-36: Add error handling and API key validation.

The example would be more robust with proper error handling and API key validation. Consider:

  1. Validating the API key existence
  2. Adding try-catch for potential API exceptions
  3. Removing the blocking Console.ReadKey()
         static async Task Main(string[] args)
         {
+            var apiKey = Environment.GetEnvironmentVariable("DEEPGRAM_API_KEY");
+            if (string.IsNullOrEmpty(apiKey))
+            {
+                Console.WriteLine("Please set the DEEPGRAM_API_KEY environment variable");
+                return;
+            }
+
             // Initialize Library with default logging
             // Normal logging is "Info" level
             Library.Initialize();
+            try
+            {
                 // use the client factory with a API Key set with the "DEEPGRAM_API_KEY" environment variable
                 var deepgramClient = ClientFactory.CreateSpeakRESTClient();

                 var response = await deepgramClient.ToFile(
                     new TextSource("Hello World!"),
                     "test.mp3",
                     new SpeakSchema()
                     {
                         Model = "aura-asteria-en",
                     });

                 Console.WriteLine(response);
-                Console.ReadKey();
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"Error: {ex.Message}");
+            }
+            finally
+            {
                 // Teardown Library
                 Library.Terminate();
+            }
         }

Add file path validation to maintain consistency with other examples

Looking at the codebase, all other examples implement input file validation using File.Exists(). For output files in text-to-speech, we should similarly validate the path and warn about overwrites:

var outputFile = "test.mp3";
if (File.Exists(outputFile))
{
    Console.WriteLine($"Warning: {outputFile} will be overwritten");
}

var response = await deepgramClient.ToFile(
    new TextSource("Hello World!"),
    outputFile,
    new SpeakSchema()
    {
        Model = "aura-asteria-en",
    });
🔗 Analysis chain

Line range hint 22-29: Consider adding output file path validation.

The example writes to "test.mp3" without checking if the path is writable or if the file already exists.

+            var outputFile = "test.mp3";
+            if (File.Exists(outputFile))
+            {
+                Console.WriteLine($"Warning: {outputFile} will be overwritten");
+            }
+
             var response = await deepgramClient.ToFile(
                 new TextSource("Hello World!"),
-                "test.mp3",
+                outputFile,
                 new SpeakSchema()

Let me check the actual implementation in these files to see how they handle file operations.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if other examples in the codebase implement file path validation
rg -l "File\.(Exists|Create)" --type cs

Length of output: 572


Script:

#!/bin/bash
# Check how these examples implement file operations
rg "File\.(Exists|Create)" -A 3 --type cs

Length of output: 3807

examples/Deepgram.Examples.SpeechToText.Rest.Url/Program.cs (4)

5-10: Consider organizing using directives by namespace hierarchy.

For better readability and .NET conventions, consider grouping System namespaces separately from Deepgram namespaces.

-using System;
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using Deepgram;
-using Deepgram.Models.Listen.v1.REST;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+using Deepgram;
+using Deepgram.Models.Listen.v1.REST;

Line range hint 14-17: Add XML documentation comments for the Program class.

Following .NET conventions, public types should be documented with XML comments.

+/// <summary>
+/// Example program demonstrating Deepgram's REST API usage for URL-based transcription.
+/// </summary>
 class Program

Line range hint 18-41: Add error handling and implement .NET best practices.

Several improvements can be made to align with .NET standards and best practices:

  1. Add try-catch block for error handling
  2. Support cancellation tokens for async operations
  3. Extract configuration values to constants
  4. Implement proper resource disposal with using statements

Here's a suggested implementation:

-        static async Task Main(string[] args)
+        private const string AudioUrl = "https://dpgr.am/bueller.wav";
+        private const string ModelVersion = "nova-2";
+
+        static async Task Main(string[] args)
         {
-            // Initialize Library with default logging
-            // Normal logging is "Info" level
-            Library.Initialize();
+            try
+            {
+                Library.Initialize();
+                using var cts = new CancellationTokenSource();
+                Console.CancelKeyPress += (s, e) =>
+                {
+                    e.Cancel = true;
+                    cts.Cancel();
+                };
 
-            // create a ListenRESTClient directly (without using the factory method) with a API Key
-            // set using the "DEEPGRAM_API_KEY" environment variable
-            var deepgramClient = new ListenRESTClient();
+                using var deepgramClient = new ListenRESTClient();
 
-            var customOptions = new Dictionary<string, string>();
-            customOptions["smart_format"] = "true";
+                var customOptions = new Dictionary<string, string>
+                {
+                    ["smart_format"] = "true"
+                };
 
-            var response = await deepgramClient.TranscribeUrl(
-                new UrlSource("https://dpgr.am/bueller.wav"),
-                new PreRecordedSchema()
-                {
-                    Model = "nova-2",
-                },
-                null, // use the default timeout
-                customOptions);
+                var response = await deepgramClient.TranscribeUrl(
+                    new UrlSource(AudioUrl),
+                    new PreRecordedSchema
+                    {
+                        Model = ModelVersion,
+                    },
+                    null,
+                    customOptions,
+                    cts.Token);
 
-            Console.WriteLine(response);
-            Console.ReadKey();
+                Console.WriteLine(response);
+                Console.WriteLine("Press any key to exit...");
+                Console.ReadKey();
+            }
+            catch (OperationCanceledException)
+            {
+                Console.WriteLine("Operation cancelled by user.");
+            }
+            catch (Exception ex)
+            {
+                Console.Error.WriteLine($"Error: {ex.Message}");
+            }
+            finally
+            {
+                Library.Terminate();
+            }
         }

⚠️ The example audio URL is not accessible

The example URL https://dpgr.am/bueller.wav redirects to a non-functioning endpoint, resulting in a 404 error. This will cause the example to fail for users trying to test the code.

  • The URL https://dpgr.am/bueller.wav redirects to https://dg-shorturls.fly.dev/redirect?path=bueller.wav
  • The final destination returns a 404 HTTP status code
  • Consider updating the example to use a consistently available audio file URL
🔗 Analysis chain

Line range hint 18-41: Verify the API endpoint URL accessibility.

The hard-coded URL should be verified to ensure it's consistently available for example purposes.


Let me follow the redirect URL to verify the final destination and accessibility of the audio file.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if the audio URL is accessible
curl -I https://dpgr.am/bueller.wav

Length of output: 575


Script:

#!/bin/bash
# Description: Follow redirects and check final audio URL
curl -IL https://dpgr.am/bueller.wav

Length of output: 886

examples/Deepgram.Examples.Analyze.Summary/Program.cs (1)

Line range hint 14-42: Enhance error handling and resource management.

While the basic functionality is present, there are several areas that could be improved to make this example more robust and maintainable:

  1. Consider using command-line arguments for the file path instead of hardcoding it
  2. Add proper exception handling for the API call
  3. Ensure proper cleanup in all code paths
  4. Remove the blocking Console.ReadKey()

Here's a suggested improvement:

         public static async Task Main(string[] args)
         {
-            // Initialize Library with default logging
-            // Normal logging is "Info" level
-            Library.Initialize();
+            try
+            {
+                Library.Initialize();
+
+                if (args.Length == 0)
+                {
+                    Console.WriteLine("Error: Please provide the path to the text file as an argument.");
+                    return;
+                }
+
+                var filePath = args[0];
+                if (!File.Exists(filePath))
+                {
+                    Console.WriteLine($"Error: File '{filePath}' not found.");
+                    return;
+                }

-            // use the client factory with a API Key set with the "DEEPGRAM_API_KEY" environment variable
-            var deepgramClient = ClientFactory.CreateAnalyzeClient();
+                var deepgramClient = ClientFactory.CreateAnalyzeClient();
+                var audioData = await File.ReadAllBytesAsync(filePath);
+                
+                try
+                {
+                    var response = await deepgramClient.AnalyzeFile(
+                        audioData,
+                        new AnalyzeSchema()
+                        {
+                            Language = "en",
+                            Summarize = true,
+                        });
-            // check to see if the file exists
-            if (!File.Exists(@"conversation.txt"))
-            {
-                Console.WriteLine("Error: File 'conversation.txt' not found.");
-                return;
+                    Console.WriteLine(response);
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine($"Error during API call: {ex.Message}");
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"Initialization error: {ex.Message}");
+            }
+            finally
+            {
+                Library.Terminate();
             }
-
-            var audioData = File.ReadAllBytes(@"conversation.txt");
-            var response = await deepgramClient.AnalyzeFile(
-                audioData,
-                new AnalyzeSchema()
-                {
-                    Language = "en",
-                    Summarize = true,
-                });
-
-            Console.WriteLine(response);
-            Console.ReadKey();
-
-            // Teardown Library
-            Library.Terminate();
         }
examples/Deepgram.Examples.Analyze.Sentiment/Program.cs (4)

12-14: Consider using top-level statements for a more concise example.

While the current implementation is correct, consider using C# top-level statements to make the example more approachable for newcomers. This would eliminate the need for explicit Program class and Main method declarations.

Example of top-level statements:

-namespace Deepgram.Examples.Analyze.Sentiment
-{
-    public static class Program
-    {
-        public static async Task Main(string[] args)
-        {
-            // Initialize Library with default logging
+// Initialize Library with default logging

Line range hint 24-26: Use command-line arguments or configuration for file path.

The hardcoded file path conversation.txt might cause issues across different environments. Consider accepting the file path as a command-line argument or through configuration.

-if (!File.Exists(@"conversation.txt"))
+if (args.Length == 0)
+{
+    Console.WriteLine("Error: Please provide the path to the conversation file.");
+    return;
+}
+if (!File.Exists(args[0]))
 {
-    Console.WriteLine("Error: File 'conversation.txt' not found.");
+    Console.WriteLine($"Error: File '{args[0]}' not found.");
     return;
 }

Line range hint 28-35: Add error handling and use appropriate file reading method.

The code needs the following improvements:

  1. Add try-catch for API calls
  2. Use ReadAllText instead of ReadAllBytes for text files
-var audioData = File.ReadAllBytes(@"conversation.txt");
-var response = await deepgramClient.AnalyzeFile(
-    audioData,
-    new AnalyzeSchema()
-    {
-        Language = "en",
-        Sentiment = true,
-    });
+try
+{
+    var text = await File.ReadAllTextAsync(args[0]);
+    var response = await deepgramClient.AnalyzeFile(
+        text,
+        new AnalyzeSchema()
+        {
+            Language = "en",
+            Sentiment = true,
+        });
+    Console.WriteLine(response);
+}
+catch (Exception ex)
+{
+    Console.WriteLine($"Error: {ex.Message}");
+    return;
+}

Line range hint 37-38: Remove Console.ReadKey() in example code.

The Console.ReadKey() call is typically used during development/debugging and should not be included in example code as it can confuse users about its necessity.

 Console.WriteLine(response);
-Console.ReadKey();
examples/Deepgram.Examples.SpeechToText.Rest.Topic/Program.cs (4)

5-8: Consider organizing imports following Microsoft conventions.

Consider organizing the imports in the following order:

  1. System namespaces
  2. Third-party namespaces (Deepgram)
 using System;
 using System.IO;
 using System.Threading.Tasks;
+
 using Deepgram;
 using Deepgram.Models.Listen.v1.REST;

Line range hint 24-29: Improve file path handling and error messaging.

The hardcoded file path might cause issues across different environments. Consider:

  1. Using Path.Combine() for cross-platform compatibility
  2. Making the file path configurable
  3. Providing more detailed error information
-            if (!File.Exists(@"CallCenterPhoneCall.mp3"))
+            string audioFile = Path.Combine(AppContext.BaseDirectory, "CallCenterPhoneCall.mp3");
+            if (!File.Exists(audioFile))
             {
-                Console.WriteLine("Error: File 'CallCenterPhoneCall.mp3' not found.");
+                Console.WriteLine($"Error: Audio file not found at: {audioFile}");
+                Console.WriteLine("Please ensure the audio file is placed in the correct location.");
                 return;
             }

Line range hint 31-42: Add proper error handling and resource management.

The current implementation lacks proper error handling and resource management. Consider:

  1. Using try-catch blocks for file operations and API calls
  2. Implementing proper resource disposal with using statements
  3. Adding cancellation support for long-running operations
-            var audioData = File.ReadAllBytes(@"CallCenterPhoneCall.mp3");
-            var response = await deepgramClient.TranscribeFile(
-                audioData,
-                new PreRecordedSchema()
-                {
-                    Model = "nova-2",
-                    Punctuate = true,
-                    Topics = true,
-                });
-
-            Console.WriteLine(response);
-            Console.ReadKey();
-
-            // Teardown Library
-            Library.Terminate();
+            try
+            {
+                using var cts = new CancellationTokenSource();
+                Console.CancelKeyPress += (s, e) =>
+                {
+                    e.Cancel = true;
+                    cts.Cancel();
+                };
+
+                byte[] audioData;
+                using (var fileStream = new FileStream(audioFile, FileMode.Open, FileAccess.Read))
+                {
+                    audioData = new byte[fileStream.Length];
+                    await fileStream.ReadAsync(audioData, 0, (int)fileStream.Length, cts.Token);
+                }
+
+                var response = await deepgramClient.TranscribeFile(
+                    audioData,
+                    new PreRecordedSchema()
+                    {
+                        Model = "nova-2",
+                        Punctuate = true,
+                        Topics = true,
+                    },
+                    cts.Token);
+
+                Console.WriteLine(response);
+                Console.WriteLine("\nPress any key to exit...");
+                Console.ReadKey();
+            }
+            catch (OperationCanceledException)
+            {
+                Console.WriteLine("\nOperation cancelled by user.");
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"\nError: {ex.Message}");
+            }
+            finally
+            {
+                Library.Terminate();
+            }

Line range hint 19-20: Consider adding configuration validation.

The API key retrieval from environment variables should include validation to prevent runtime errors.

             // use the client factory with a API Key set with the "DEEPGRAM_API_KEY" environment variable
+            var apiKey = Environment.GetEnvironmentVariable("DEEPGRAM_API_KEY");
+            if (string.IsNullOrEmpty(apiKey))
+            {
+                Console.WriteLine("Error: DEEPGRAM_API_KEY environment variable is not set.");
+                return;
+            }
             var deepgramClient = ClientFactory.CreateListenRESTClient();
examples/Deepgram.Examples.SpeechToText.Rest.Intent/Program.cs (4)

Line range hint 15-21: Add error handling for missing API key and improve comments.

  1. The comment about logging levels is redundant. Consider removing or clarifying.
  2. Add error handling for cases where the API key environment variable is not set.
 // Initialize Library with default logging
-// Normal logging is "Info" level
 Library.Initialize();

-// use the client factory with a API Key set with the "DEEPGRAM_API_KEY" environment variable
-var deepgramClient = ClientFactory.CreateListenRESTClient();
+// Create client using API key from DEEPGRAM_API_KEY environment variable
+var apiKey = Environment.GetEnvironmentVariable("DEEPGRAM_API_KEY");
+if (string.IsNullOrEmpty(apiKey))
+{
+    Console.WriteLine("Error: DEEPGRAM_API_KEY environment variable not set.");
+    return;
+}
+var deepgramClient = ClientFactory.CreateListenRESTClient();

Line range hint 23-28: Improve file handling for better robustness.

Consider the following improvements:

  1. Accept file path as a command-line argument instead of hardcoding
  2. Add file size checks to prevent out-of-memory issues with large files
  3. Use streaming for better memory efficiency
-if (!File.Exists(@"CallCenterPhoneCall.mp3"))
+if (args.Length == 0)
+{
+    Console.WriteLine("Usage: dotnet run <audio-file-path>");
+    return;
+}
+
+var filePath = args[0];
+if (!File.Exists(filePath))
 {
-    Console.WriteLine("Error: File 'CallCenterPhoneCall.mp3' not found.");
+    Console.WriteLine($"Error: File '{filePath}' not found.");
     return;
 }
+
+var fileInfo = new FileInfo(filePath);
+if (fileInfo.Length > 100 * 1024 * 1024) // 100MB limit
+{
+    Console.WriteLine("Error: File size exceeds 100MB limit.");
+    return;
+}

Line range hint 30-39: Add error handling and improve response formatting.

The transcription call needs proper error handling and the response could be formatted for better readability.

-var audioData = File.ReadAllBytes(@"CallCenterPhoneCall.mp3");
-var response = await deepgramClient.TranscribeFile(
-    audioData,
-    new PreRecordedSchema()
-    {
-        Model = "nova-2",
-        Punctuate = true,
-        Intents = true,
-    });
-
-Console.WriteLine(response);
+try
+{
+    var audioData = File.ReadAllBytes(filePath);
+    var response = await deepgramClient.TranscribeFile(
+        audioData,
+        new PreRecordedSchema()
+        {
+            Model = "nova-2",
+            Punctuate = true,
+            Intents = true,
+        });
+
+    Console.WriteLine("Transcription Results:");
+    Console.WriteLine("---------------------");
+    Console.WriteLine(response.ToString()); // Assuming there's a proper ToString() implementation
+}
+catch (Exception ex)
+{
+    Console.WriteLine($"Error during transcription: {ex.Message}");
+    return;
+}

Line range hint 41-42: Ensure proper cleanup with try-finally.

The library cleanup should be guaranteed using a try-finally block, and consider removing the Console.ReadKey() as it's not necessary for an example.

-Console.ReadKey();
-
-// Teardown Library
-Library.Terminate();
+finally
+{
+    // Teardown Library
+    Library.Terminate();
+}
examples/Deepgram.Examples.SpeechToText.Rest.Summary/Program.cs (3)

Line range hint 14-24: Add error handling for API key initialization.

While using an environment variable for the API key is secure, the code should validate its presence and handle potential initialization failures.

Consider this improvement:

         static async Task Main(string[] args)
         {
             // Initialize Library with default logging
             // Normal logging is "Info" level
             Library.Initialize();
 
+            // Validate API key
+            var apiKey = Environment.GetEnvironmentVariable("DEEPGRAM_API_KEY");
+            if (string.IsNullOrEmpty(apiKey))
+            {
+                Console.WriteLine("Error: DEEPGRAM_API_KEY environment variable not set");
+                return;
+            }
+
+            try
+            {
                 // use the client factory with a API Key set with the "DEEPGRAM_API_KEY" environment variable
-                var deepgramClient = ClientFactory.CreateListenRESTClient();
+                var deepgramClient = ClientFactory.CreateListenRESTClient();
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"Error initializing Deepgram client: {ex.Message}");
+                return;
+            }

Line range hint 26-31: Improve file handling for robustness and cross-platform compatibility.

The current implementation has several potential issues:

  1. Hardcoded path may not work across platforms
  2. Loading entire file into memory could be problematic for large files
  3. No file size validation

Consider this more robust implementation:

-            if (!File.Exists(@"CallCenterPhoneCall.mp3"))
+            var audioFile = Path.Combine(AppContext.BaseDirectory, "CallCenterPhoneCall.mp3");
+            if (!File.Exists(audioFile))
             {
-                Console.WriteLine("Error: File 'CallCenterPhoneCall.mp3' not found.");
+                Console.WriteLine($"Error: File '{audioFile}' not found.");
                 return;
             }
 
-            var audioData = File.ReadAllBytes(@"CallCenterPhoneCall.mp3");
+            var fileInfo = new FileInfo(audioFile);
+            if (fileInfo.Length > 100 * 1024 * 1024) // 100MB limit
+            {
+                Console.WriteLine("Error: File size exceeds 100MB limit.");
+                return;
+            }
+
+            byte[] audioData;
+            using (var stream = new FileStream(audioFile, FileMode.Open, FileAccess.Read))
+            {
+                audioData = new byte[stream.Length];
+                await stream.ReadAsync(audioData, 0, (int)stream.Length);
+            }

Line range hint 33-47: Enhance API usage with proper error handling and response formatting.

The current implementation lacks error handling for the API call and could benefit from better response formatting.

Consider this improvement:

-            var response = await deepgramClient.TranscribeFile(
-                audioData,
-                new PreRecordedSchema()
-                {
-                    Model = "nova-2",
-                    Punctuate = true,
-                    Summarize = "v2",
-                });
-
-            Console.WriteLine(response);
-            Console.ReadKey();
+            try
+            {
+                var response = await deepgramClient.TranscribeFile(
+                    audioData,
+                    new PreRecordedSchema()
+                    {
+                        Model = "nova-2",
+                        Punctuate = true,
+                        Summarize = "v2",
+                    });
+
+                Console.WriteLine("Transcription Summary:");
+                Console.WriteLine("--------------------");
+                Console.WriteLine(response?.Results?.Summary ?? "No summary available");
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"Error during transcription: {ex.Message}");
+            }
+            finally
+            {
+                // Teardown Library
+                Library.Terminate();
+            }
-            // Teardown Library
-            Library.Terminate();

Also, consider removing Console.ReadKey() as it's not necessary for an example program and blocks the thread unnecessarily.

examples/Deepgram.Examples.SpeechToText.Rest.Sentiment/Program.cs (3)

Line range hint 11-21: Add error handling for API key configuration.

While the code is functional, it could be more robust with proper error handling for the API key configuration.

Consider this improvement:

     static async Task Main(string[] args)
     {
         // Initialize Library with default logging
         // Normal logging is "Info" level
         Library.Initialize();
 
+        // Verify API key is configured
+        var apiKey = Environment.GetEnvironmentVariable("DEEPGRAM_API_KEY");
+        if (string.IsNullOrEmpty(apiKey))
+        {
+            Console.WriteLine("Error: DEEPGRAM_API_KEY environment variable not set");
+            return;
+        }
+
         // use the client factory with a API Key set with the "DEEPGRAM_API_KEY" environment variable
         var deepgramClient = ClientFactory.CreateListenRESTClient();

Line range hint 22-31: Improve file handling robustness and resource management.

The current implementation has several areas for improvement regarding file handling:

  1. Hardcoded file path may cause issues in different environments
  2. Loading entire file into memory could be problematic for large files
  3. Missing proper resource disposal

Consider this more robust implementation:

-        if (!File.Exists(@"CallCenterPhoneCall.mp3"))
+        const string audioFile = "CallCenterPhoneCall.mp3";
+        var filePath = Path.Combine(AppContext.BaseDirectory, audioFile);
+        
+        if (!File.Exists(filePath))
         {
-            Console.WriteLine("Error: File 'CallCenterPhoneCall.mp3' not found.");
+            Console.WriteLine($"Error: File '{audioFile}' not found at: {filePath}");
             return;
         }
 
-        var audioData = File.ReadAllBytes(@"CallCenterPhoneCall.mp3");
+        // Check file size before loading
+        var fileInfo = new FileInfo(filePath);
+        if (fileInfo.Length > 100 * 1024 * 1024) // 100MB limit
+        {
+            Console.WriteLine($"Error: File size ({fileInfo.Length / 1024 / 1024}MB) exceeds recommended limit of 100MB");
+            return;
+        }
+
+        byte[] audioData;
+        using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
+        {
+            audioData = new byte[fileStream.Length];
+            await fileStream.ReadAsync(audioData, 0, (int)fileStream.Length);
+        }

Line range hint 32-46: Enhance API interaction with proper error handling and response formatting.

The current implementation could benefit from proper error handling and more user-friendly output formatting.

Consider this improvement:

-            var response = await deepgramClient.TranscribeFile(
-                audioData,
-                new PreRecordedSchema()
-                {
-                    Model = "nova-2",
-                    Punctuate = true,
-                    Utterances = true,
-                    Sentiment = true,
-                });
-
-            Console.WriteLine(response);
-            Console.ReadKey();
+            try 
+            {
+                var response = await deepgramClient.TranscribeFile(
+                    audioData,
+                    new PreRecordedSchema()
+                    {
+                        Model = "nova-2",
+                        Punctuate = true,
+                        Utterances = true,
+                        Sentiment = true,
+                    });
+
+                // Format response for better readability
+                Console.WriteLine("Transcription Results:");
+                Console.WriteLine("--------------------");
+                Console.WriteLine($"Transcript: {response.Results?.Channels?[0]?.Alternatives?[0]?.Transcript}");
+                Console.WriteLine("\nPress any key to exit...");
+                
+                // Use GetAwaiter().GetResult() to properly wait in async context
+                Task.Run(() => Console.ReadKey()).GetAwaiter().GetResult();
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"Error during transcription: {ex.Message}");
+            }
+            finally
+            {
+                // Ensure cleanup runs even if an error occurs
+                Library.Terminate();
+            }
-
-            // Teardown Library
-            Library.Terminate();
examples/Deepgram.Examples.Analyze.Topic/Program.cs (3)

5-7: Consider organizing using directives according to .NET conventions.

Group System namespaces together, followed by third-party namespaces:

-using System;
-using System.IO;
-using System.Threading.Tasks;
+using System;
+using System.IO;
+using System.Threading.Tasks;
+
 using Deepgram.Logger;
 using Deepgram.Models.Analyze.v1;

13-15: LGTM! Changes align with .NET standards.

The public static modifiers on the Program class follow .NET conventions for console applications. Note that the public modifier on Main is optional as it's implied for entry points, but it's fine to be explicit.


Line range hint 15-40: Consider improving error handling and file path handling.

A few suggestions to make the example more robust and maintainable:

  1. Add exception handling for API calls and file operations
  2. Use Path.Combine for file paths to ensure cross-platform compatibility
  3. Consider making the file path configurable
  4. Remove Console.ReadKey() as it blocks execution and complicates testing

Here's a suggested improvement:

         public static async Task Main(string[] args)
         {
+            try
+            {
                 // Initialize Library with default logging
                 Library.Initialize();
 
                 var deepgramClient = new AnalyzeClient();
 
+                string filePath = args.Length > 0 ? args[0] : "conversation.txt";
+                filePath = Path.Combine(AppContext.BaseDirectory, filePath);
 
-                if (!File.Exists(@"conversation.txt"))
+                if (!File.Exists(filePath))
                 {
-                    Console.WriteLine("Error: File 'conversation.txt' not found.");
+                    Console.WriteLine($"Error: File '{filePath}' not found.");
                     return;
                 }
 
-                var audioData = File.ReadAllBytes(@"conversation.txt");
+                var audioData = File.ReadAllBytes(filePath);
                 var response = await deepgramClient.AnalyzeFile(
                     audioData,
                     new AnalyzeSchema()
                     {
                         Language = "en",
                         Topics = true,
                     });
 
                 Console.WriteLine(response);
-                Console.ReadKey();
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"Error: {ex.Message}");
+            }
+            finally
+            {
                 // Teardown Library
                 Library.Terminate();
+            }
         }
examples/Deepgram.Examples.TextToSpeech.Rest.File.WoodChuck/Program.cs (4)

Line range hint 15-19: Document debugging options in XML comments

Consider moving the logging level comments into XML documentation to make them more discoverable through IntelliSense.

     class Program
     {
+        /// <summary>
+        /// Main entry point for the Deepgram Text-to-Speech example.
+        /// </summary>
+        /// <remarks>
+        /// Logging levels can be configured using Library.Initialize():
+        /// - Default: Normal "Info" level logging
+        /// - Debug: Detailed debugging information
+        /// - Verbose: Very detailed logging for troubleshooting
+        /// </remarks>
         static async Task Main(string[] args)

Line range hint 29-36: Make example more configurable

Consider extracting the text content and model name into configuration variables at the top of the file. This would make the example more maintainable and demonstrate proper configuration practices.

     class Program
     {
+        private const string SampleText = "How much wood could a woodchuck chuck? If a woodchuck could chuck wood? As much wood as a woodchuck could chuck, if a woodchuck could chuck wood.";
+        private const string ModelName = "aura-asteria-en";
+
         static async Task Main(string[] args)
         {
             // ... initialization code ...

             var response = await deepgramClient.ToFile(
-                new TextSource("How much wood could a woodchuck chuck? If a woodchuck could chuck wood? As much wood as a woodchuck could chuck, if a woodchuck could chuck wood."),
+                new TextSource(SampleText),
                 "test.mp3",
                 new SpeakSchema()
                 {
-                    Model = "aura-asteria-en",
+                    Model = ModelName,
                 });

Line range hint 38-43: Add error handling for API calls

The example should demonstrate proper error handling for API calls to help users understand how to handle potential failures in production.

         static async Task Main(string[] args)
         {
             Library.Initialize();
-            var deepgramClient = new SpeakRESTClient();
+            try
+            {
+                var deepgramClient = new SpeakRESTClient();
+                var response = await deepgramClient.ToFile(
+                    new TextSource(SampleText),
+                    "test.mp3",
+                    new SpeakSchema()
+                    {
+                        Model = ModelName,
+                    });
+                Console.WriteLine(response);
+                Console.ReadKey();
+            }
+            catch (DeepgramException ex)
+            {
+                Console.WriteLine($"Deepgram API error: {ex.Message}");
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"Unexpected error: {ex.Message}");
+            }
+            finally
+            {
+                Library.Terminate();
+            }
-
-            // ... existing code ...
-
-            Library.Terminate();
         }

The review comment is valid - example should demonstrate proper API key configuration

Looking at the SpeakRESTClient implementation, while it does support a parameterless constructor, it's designed to accept an API key and client options. The example should demonstrate this best practice since:

  1. The client constructor explicitly supports API key configuration: public SpeakRESTClient(string apiKey = "", DeepgramHttpClientOptions? deepgramClientOptions = null)
  2. The commented-out code shows the intended pattern but was left incomplete
  3. Production usage would require proper API key configuration

Recommendations:

  • Uncomment and complete the configuration code with environment variable usage
  • Add comments explaining the configuration options
  • Remove the parameterless constructor usage
🔗 Analysis chain

Line range hint 24-27: Consider demonstrating proper API key configuration

The current implementation uses a parameterless constructor, which might not reflect best practices for production use. Consider demonstrating secure API key configuration using environment variables or configuration files.


Let me check the actual implementation of API key configuration in other examples to provide accurate guidance.


Let me check the actual implementation of the SpeakRESTClient constructor to understand the default behavior and best practices.


Let me try a different approach to check the client implementation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if there are other examples showing proper API key configuration
rg -l "DeepgramHttpClientOptions" --type cs

Length of output: 1487


Script:

#!/bin/bash
# Check implementation in tests and other examples
rg -A 5 "DeepgramHttpClientOptions" examples/ tests/ --type cs

Length of output: 1588


Script:

#!/bin/bash
# Check SpeakRESTClient implementation
ast-grep --pattern 'public class SpeakRESTClient {
  $$$
}'

Length of output: 61


Script:

#!/bin/bash
# Check SpeakRESTClient implementation and constructor patterns
rg -A 10 "class SpeakRESTClient" --type cs

Length of output: 475

examples/Deepgram.Examples.Analyze.Intent/Program.cs (4)

5-11: Consider organizing using directives

While the using directives are appropriate for the functionality, consider grouping them by:

  1. System namespaces
  2. Third-party namespaces (Deepgram)

This improves readability and maintainability.

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

using Deepgram.Models.Analyze.v1;

Line range hint 28-29: Fix incorrect comment about timeout duration

The comment states "increase timeout to 60 seconds" but the code sets it to 120 seconds.

-            // increase timeout to 60 seconds
+            // increase timeout to 120 seconds

Line range hint 19-47: Consider improving error handling and configuration

Several improvements could make this example more robust and maintainable:

  1. Add exception handling for API calls
  2. Make the file path configurable
  3. Consider removing the blocking Console.ReadKey()

Here's a suggested improvement:

         public static async Task Main(string[] args)
         {
             // Initialize Library with default logging
             // Normal logging is "Info" level
             Library.Initialize();
+            try
+            {
                 // use the client factory with a API Key set with the "DEEPGRAM_API_KEY" environment variable
                 var deepgramClient = ClientFactory.CreateAnalyzeClient();
 
+                // Allow file path to be passed as argument or use default
+                string filePath = args.Length > 0 ? args[0] : "conversation.txt";
 
                 // check to see if the file exists
-                if (!File.Exists(@"conversation.txt"))
+                if (!File.Exists(filePath))
                 {
-                    Console.WriteLine("Error: File 'conversation.txt' not found.");
+                    Console.WriteLine($"Error: File '{filePath}' not found.");
                     return;
                 }
 
                 // increase timeout to 120 seconds
                 CancellationTokenSource cancelToken = new CancellationTokenSource();
                 cancelToken.CancelAfter(TimeSpan.FromSeconds(120));
 
-                var audioData = File.ReadAllBytes(@"conversation.txt");
+                var audioData = File.ReadAllBytes(filePath);
                 var response = await deepgramClient.AnalyzeFile(
                     audioData,
                     new AnalyzeSchema()
                     {
                         Language = "en",
                         Intents = true,
                     },
                     cancelToken);
 
                 Console.WriteLine(response);
-                Console.ReadKey();
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"Error: {ex.Message}");
+            }
+            finally
+            {
                 // Teardown Library
                 Library.Terminate();
+            }
         }

Line range hint 22-27: Add path validation for security

The current file path handling could be vulnerable to path traversal attacks if user input is accepted. Consider adding path validation.

+                // Validate and normalize the file path
+                filePath = Path.GetFullPath(filePath);
+                if (!filePath.StartsWith(Path.GetFullPath(Directory.GetCurrentDirectory())))
+                {
+                    Console.WriteLine("Error: File path must be within the current directory.");
+                    return;
+                }
examples/Deepgram.Examples.SpeechToText.Rest.File/Program.cs (5)

Line range hint 19-23: Consider enhancing logging documentation.

While the comments explain logging levels, consider structuring them as XML documentation to provide better IntelliSense support:

-            // Initialize Library with default logging
-            // Normal logging is "Info" level
-            //Library.Initialize();
-            // OR very chatty logging
-            Library.Initialize(LogLevel.Debug); // LogLevel.Default, LogLevel.Debug, LogLevel.Verbose
+            /// <summary>
+            /// Available logging levels:
+            /// - LogLevel.Default: Normal logging (Info level)
+            /// - LogLevel.Debug: Detailed debugging information
+            /// - LogLevel.Verbose: Most detailed logging
+            /// </summary>
+            Library.Initialize(LogLevel.Debug);

Line range hint 28-33: Improve file path handling for cross-platform compatibility.

The current implementation uses a hardcoded file path which may not work across different operating systems. Consider:

  1. Using Path.Combine for cross-platform path handling
  2. Making the file path configurable via command line arguments or environment variables
  3. Adding the audio file to the project resources
+            string audioFile = args.Length > 0 
+                ? args[0] 
+                : Path.Combine(AppContext.BaseDirectory, "Bueller-Life-moves-pretty-fast.wav");
+
-            if (!File.Exists(@"Bueller-Life-moves-pretty-fast.wav"))
+            if (!File.Exists(audioFile))
             {
-                Console.WriteLine("Error: File 'Bueller-Life-moves-pretty-fast.wav' not found.");
+                Console.WriteLine($"Error: Audio file '{audioFile}' not found.");
+                Console.WriteLine("Usage: dotnet run [path-to-audio-file]");
                 return;
             }

Line range hint 35-37: Replace magic number and consider timeout configuration.

The timeout duration is hardcoded as a magic number. Consider using TimeSpan for better readability and making it configurable:

-            CancellationTokenSource cancelToken = new CancellationTokenSource();
-            cancelToken.CancelAfter(3600000);
+            // Default timeout of 1 hour, configurable via environment variable
+            var timeout = TimeSpan.FromHours(
+                double.TryParse(Environment.GetEnvironmentVariable("DEEPGRAM_TIMEOUT_HOURS"), out var hours) 
+                    ? hours 
+                    : 1);
+            using var cancelToken = new CancellationTokenSource(timeout);

Line range hint 39-46: Consider using streaming for large files.

Loading the entire file into memory using ReadAllBytes could cause issues with large audio files. Consider using a streaming approach for better memory efficiency:

-            var audioData = File.ReadAllBytes(@"Bueller-Life-moves-pretty-fast.wav");
-            var response = await deepgramClient.TranscribeFile(
-                audioData,
+            using var fileStream = File.OpenRead(audioFile);
+            var response = await deepgramClient.TranscribeStream(
+                fileStream,
                 new PreRecordedSchema()
                 {
                     Model = "nova-2",
                     Punctuate = true,
                 },
                 cancelToken);

Line range hint 48-53: Enhance console interaction and cleanup.

Consider adding proper console input handling and cleanup:

+            Console.CancelKeyPress += (s, e) => {
+                e.Cancel = true;
+                cancelToken.Cancel();
+            };
+
             Console.WriteLine($"\n\n{response}\n\n");
-            Console.WriteLine("Press any key to exit...");
-            Console.ReadKey();
+            Console.WriteLine("Press Ctrl+C to exit...");
+            try {
+                await Task.Delay(-1, cancelToken.Token);
+            } catch (TaskCanceledException) {
+                // Expected when cancellation is requested
+            }

             // Teardown Library
             Library.Terminate();
examples/Deepgram.Examples.Manage.Balances/Program.cs (3)

10-12: LGTM! Class modifiers align with .NET conventions.

The public static modifiers on the Program class and Main method follow .NET best practices for console application entry points.

Consider adjusting the indentation to use 4 spaces consistently:

-    public static class Program
-    {
-        public static async Task Main(string[] args)
+public static class Program
+{
+    public static async Task Main(string[] args)

Line range hint 33-34: Fix typo in variable name.

The variable balanacesResponse contains a typo and should be balancesResponse.

-var balanacesResponse = await deepgramClient.GetBalances(projectId);
-if (balanacesResponse == null)
+var balancesResponse = await deepgramClient.GetBalances(projectId);
+if (balancesResponse == null)

Line range hint 15-65: Consider implementing structured logging.

The current implementation uses Console.WriteLine for output. As mentioned in the PR objectives, a future update will implement conventional logging using Microsoft.Extensions.Logging.Abstractions. Consider preparing for this transition by:

  1. Centralizing the logging calls
  2. Adding appropriate log levels for different message types
  3. Including structured data in log messages

Would you like me to provide an example implementation using Microsoft.Extensions.Logging?

examples/Deepgram.Examples.SpeechToText.Websocket.File/Program.cs (7)

5-9: Consider organizing imports by namespace.

Group the imports by namespace to improve readability:

using System;
using System.IO;
using System.Threading.Tasks;
+
using Deepgram;
using Deepgram.Models.Listen.v2.WebSocket;

Line range hint 15-24: Add environment variable validation.

The code assumes DEEPGRAM_API_KEY is set but doesn't validate its presence. This could lead to runtime errors.

 static async Task Main(string[] args)
 {
     try
     {
+        string apiKey = Environment.GetEnvironmentVariable("DEEPGRAM_API_KEY");
+        if (string.IsNullOrEmpty(apiKey))
+        {
+            throw new InvalidOperationException("DEEPGRAM_API_KEY environment variable is not set");
+        }
+
         // Initialize Library with default logging
         // Normal logging is "Info" level
         Library.Initialize();

         // use the client factory with a API Key set with the "DEEPGRAM_API_KEY" environment variable
-        var liveClient = ClientFactory.CreateListenWebSocketClient();
+        var liveClient = ClientFactory.CreateListenWebSocketClient(apiKey);

Line range hint 26-35: Improve event handler robustness and cleanup commented code.

The event handler needs error handling and the commented code should be removed.

 await liveClient.Subscribe(new EventHandler<ResultResponse>((sender, e) =>
 {
+    try
+    {
+        if (e?.Channel?.Alternatives == null || e.Channel.Alternatives.Count == 0)
+        {
+            Console.WriteLine("Received empty or invalid transcription response");
+            return;
+        }
+
         if (e.Channel.Alternatives[0].Transcript == "")
         {
             return;
         }

-        // Console.WriteLine("Transcription received: " + JsonSerializer.Serialize(e.Transcription));
         Console.WriteLine($"\n\n\nSpeaker: {e.Channel.Alternatives[0].Transcript}\n\n\n");
+    }
+    catch (Exception ex)
+    {
+        Console.WriteLine($"Error processing transcription: {ex.Message}");
+    }
 }));

Line range hint 37-47: Enhance connection configuration and error handling.

The connection setup could benefit from timeout configuration and better error handling.

+const int CONNECTION_TIMEOUT_MS = 5000;
+
 var liveSchema = new LiveSchema()
 {
     Model = "nova-2",
     Punctuate = true,
     SmartFormat = true,
 };

-bool bConnected = await liveClient.Connect(liveSchema);
-if (!bConnected)
+using var cts = new CancellationTokenSource(CONNECTION_TIMEOUT_MS);
+bool connected = await liveClient.Connect(liveSchema, cts.Token);
+if (!connected)
 {
-    Console.WriteLine("Failed to connect to the server");
+    Console.WriteLine("Failed to establish WebSocket connection within timeout period");
     return;
 }

Line range hint 49-63: Improve file handling and resource management.

The audio file handling needs validation, and the wait time should be configurable.

+const string AUDIO_FILE_PATH = "preamble.wav";
+const int RESPONSE_WAIT_TIME_MS = 45000;
+
+if (!File.Exists(AUDIO_FILE_PATH))
+{
+    Console.WriteLine($"Audio file not found: {AUDIO_FILE_PATH}");
+    return;
+}
+
 // Send some audio data
-var audioData = File.ReadAllBytes(@"preamble.wav");
-liveClient.Send(audioData);
+try
+{
+    var audioData = File.ReadAllBytes(AUDIO_FILE_PATH);
+    await liveClient.Send(audioData);
+}
+catch (IOException ex)
+{
+    Console.WriteLine($"Error reading audio file: {ex.Message}");
+    return;
+}

 // Wait for a while to receive responses
-await Task.Delay(45000);
+await Task.Delay(RESPONSE_WAIT_TIME_MS);

 // Stop the connection
 await liveClient.Stop();

Line range hint 64-67: Enhance error handling with specific exceptions.

The current catch-all exception handling could be more specific and informative.

-catch (Exception ex)
+catch (InvalidOperationException ex)
 {
-    Console.WriteLine($"Exception: {ex.Message}");
+    Console.WriteLine($"Configuration error: {ex.Message}");
+}
+catch (WebSocketException ex)
+{
+    Console.WriteLine($"WebSocket error: {ex.Message}");
+}
+catch (Exception ex)
+{
+    Console.WriteLine($"Unexpected error: {ex.Message}");
+    Console.WriteLine($"Stack trace: {ex.StackTrace}");
+}
+finally
+{
+    Library.Terminate();
 }

Line range hint 11-13: Add XML documentation for the Program class.

As this is an example file, comprehensive documentation would help users understand the implementation better.

+/// <summary>
+/// Example program demonstrating real-time speech-to-text functionality using Deepgram's WebSocket API.
+/// This example shows how to:
+/// - Initialize the Deepgram client
+/// - Configure and establish a WebSocket connection
+/// - Send audio data for transcription
+/// - Handle transcription responses
+/// </summary>
 class Program
examples/Deepgram.Examples.SpeechToText.Websocket.Http/Program.cs (2)

5-11: Remove unused namespace import.

The System.Linq.Expressions namespace is not used in this file and should be removed.

using System;
using System.IO;
-using System.Linq.Expressions;
using System.Net.Http;
using System.Threading.Tasks;
using Deepgram;
using Deepgram.Models.Listen.v2.WebSocket;

Line range hint 41-66: Consider architectural improvements for better example code.

Several enhancements would make this example more robust and educational:

  1. Make the buffer size configurable and document the recommended sizes
  2. Add cancellation token support for graceful shutdown
  3. Add specific error handling for common streaming issues
  4. Make the stream URL configurable via command line or config file

Would you like me to provide a detailed implementation incorporating these improvements?

examples/Deepgram.Examples.Manage.Members/Program.cs (5)

Line range hint 14-14: Consider moving configuration to appsettings.json

The DELETE_MEMBER_BY_EMAIL constant should be moved to a configuration file following .NET best practices.

Consider using the following structure:

-    private const string DELETE_MEMBER_BY_EMAIL = "MY_EMAIL";

And add an appsettings.json:

{
  "DeepgramSettings": {
    "MemberEmail": "MY_EMAIL"
  }
}

Then use IConfiguration to load it:

using Microsoft.Extensions.Configuration;

var configuration = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json")
    .Build();

var memberEmail = configuration.GetValue<string>("DeepgramSettings:MemberEmail");

Line range hint 20-24: Add error handling for library initialization

The library initialization lacks error handling and logging configuration best practices.

Consider adding try-catch and proper logging:

-            // Initialize Library with default logging
-            // Normal logging is "Info" level
-            Library.Initialize();
-
-            // use the client factory with a API Key set with the "DEEPGRAM_API_KEY" environment variable
-            var deepgramClient = ClientFactory.CreateManageClient();
+            try
+            {
+                Library.Initialize();
+                
+                var apiKey = Environment.GetEnvironmentVariable("DEEPGRAM_API_KEY");
+                if (string.IsNullOrEmpty(apiKey))
+                {
+                    throw new InvalidOperationException("DEEPGRAM_API_KEY environment variable is not set");
+                }
+                
+                var deepgramClient = ClientFactory.CreateManageClient();
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"Failed to initialize Deepgram client: {ex.Message}");
+                Environment.Exit(1);
+            }

Line range hint 26-36: Improve project listing efficiency and readability

The project listing logic could be more efficient and readable using LINQ and string interpolation.

Consider this improvement:

-            string myId = null;
-            foreach (var project in projectResp.Projects)
-            {
-                myId = project.ProjectId;
-                string myName = project.Name;
-                Console.WriteLine($"\n\nListProjects() - ID: {myId}, Name: {myName}\n\n");
-            }
+            var selectedProject = projectResp.Projects.FirstOrDefault()
+                ?? throw new InvalidOperationException("No projects found");
+            
+            var projectId = selectedProject.ProjectId;
+            Console.WriteLine(
+                $"""
+                
+                Project Details:
+                ID: {projectId}
+                Name: {selectedProject.Name}
+                
+                """);

Line range hint 38-93: Refactor member management logic to reduce duplication

The member listing and deletion logic contains repeated code and could benefit from better organization.

Consider extracting the member listing logic into a separate method and improving error handling:

+        private static async Task DisplayMembers(IDeepgramClient client, string projectId)
+        {
+            var members = await client.GetMembers(projectId);
+            if (members?.Members == null || !members.Members.Any())
+            {
+                Console.WriteLine("No members found in the project.");
+                return;
+            }
+
+            Console.WriteLine("\nProject Members:");
+            foreach (var member in members.Members)
+            {
+                Console.WriteLine($"- {member.Email} (ID: {member.MemberId})");
+            }
+            Console.WriteLine();
+        }
+
+        private static async Task<string> FindMemberIdByEmail(
+            IDeepgramClient client, 
+            string projectId, 
+            string email)
+        {
+            var members = await client.GetMembers(projectId);
+            return members?.Members
+                .FirstOrDefault(m => m.Email == email)?
+                .MemberId;
+        }

-            // List members
-            string delMemberId = null;
-            var listResp = await deepgramClient.GetMembers(myId);
-            // ... existing member listing code ...
-
-            // Delete member
-            if (delMemberId == null)
-            {
-                Console.WriteLine("");
-                Console.WriteLine("This example requires a project that already exists with a name specified in DELETE_MEMBER_BY_EMAIL.");
-                Console.WriteLine("This is required to exercise the RemoveMember function.");
-                Console.WriteLine("In the absence of this, this example will exit early.");
-                Console.WriteLine("");
-                Environment.Exit(1);
-            }
+            await DisplayMembers(deepgramClient, projectId);
+
+            var memberIdToDelete = await FindMemberIdByEmail(
+                deepgramClient, 
+                projectId, 
+                memberEmail);
+
+            if (memberIdToDelete == null)
+            {
+                throw new InvalidOperationException(
+                    $"Member with email {memberEmail} not found in the project.");
+            }

Also, consider replacing Console.ReadKey() with a more appropriate termination method for production code:

-            Console.WriteLine("\n\nPress any key to exit.");
-            Console.ReadKey();
+            // In a real application, you might want to implement proper
+            // shutdown handling using CancellationToken or similar mechanism

Line range hint 1-93: Add XML documentation for public members

Since this is an example file that demonstrates SDK usage, it would be beneficial to add XML documentation to help users understand the code better.

Add documentation at the class level:

/// <summary>
/// Example program demonstrating member management operations using the Deepgram SDK.
/// This includes listing projects, listing members, and removing members.
/// </summary>
/// <remarks>
/// Requires DEEPGRAM_API_KEY environment variable to be set with a valid API key.
/// </remarks>
class Program
examples/Deepgram.Examples.Manage.Usage/Program.cs (2)

Line range hint 24-29: Consider implementing more robust error handling and logging

The current error handling could be enhanced in several ways:

  1. Consider using a proper logging framework instead of Console.WriteLine
  2. Add more detailed error messages explaining why operations failed
  3. Consider implementing a consistent error handling strategy across all operations

Here's a suggested approach:

- Console.WriteLine("ListProjects failed.");
- Environment.Exit(1);
+ var errorMessage = "Failed to retrieve projects. Please check your API key and network connection.";
+ Console.Error.WriteLine(errorMessage);
+ throw new InvalidOperationException(errorMessage);

This aligns with the PR's future goals of implementing conventional logging using Microsoft.Extensions.Logging.Abstractions.

Also applies to: 65-70


Line range hint 15-102: Improve resource management and program structure

The program could benefit from more structured resource management:

  1. Consider using a try-finally block or IDisposable pattern for Library cleanup
  2. The Console.ReadKey() blocking call might not be necessary for a sample program

Here's a suggested refactor:

- static async Task Main(string[] args)
- {
-     Library.Initialize();
-     // ... rest of the code ...
-     Console.WriteLine("\n\nPress any key to exit.");
-     Console.ReadKey();
-     Library.Terminate();
- }
+ static async Task Main(string[] args)
+ {
+     try
+     {
+         Library.Initialize();
+         // ... rest of the code ...
+     }
+     catch (Exception ex)
+     {
+         Console.Error.WriteLine($"An error occurred: {ex.Message}");
+         Environment.Exit(1);
+     }
+     finally
+     {
+         Library.Terminate();
+     }
+ }
examples/Deepgram.Examples.Manage.Invitations/Program.cs (5)

Line range hint 6-12: Align namespace with project name following .NET conventions

The namespace SampleApp should match the project name Deepgram.Examples.Manage.Invitations to follow .NET naming conventions.

-namespace SampleApp
+namespace Deepgram.Examples.Manage.Invitations

Line range hint 16-20: Improve initialization and logging configuration

A few suggestions to enhance the initialization:

  1. Remove commented code for cleaner examples
  2. Consider using Info level logging by default as Debug might be too verbose
  3. Add error handling for missing API key environment variable
-            // Initialize Library with default logging
-            // Normal logging is "Info" level
-            //Library.Initialize();
-            // OR very chatty logging
-            Library.Initialize(LogLevel.Debug); // LogLevel.Default, LogLevel.Debug, LogLevel.Verbose
+            Library.Initialize(LogLevel.Info);
+
+            if (Environment.GetEnvironmentVariable("DEEPGRAM_API_KEY") == null)
+            {
+                Console.WriteLine("Error: DEEPGRAM_API_KEY environment variable not set");
+                Environment.Exit(1);
+            }

Line range hint 22-35: Enhance project management code with better error handling and LINQ

The current implementation could be improved for better error handling and readability.

-            var projectResp = await deepgramClient.GetProjects();
-            if (projectResp == null)
-            {
-                Console.WriteLine("ListProjects failed.");
-                Environment.Exit(1);
-            }
-
-            string myId = null;
-            string myName = null;
-            foreach (var project in projectResp.Projects)
-            {
-                myId = project.ProjectId;
-                myName = project.Name;
-                Console.WriteLine($"\n\nListProjects() - ID: {myId}, Name: {myName}\n\n");
-                break;
-            }
+            var projectResponse = await deepgramClient.GetProjects();
+            if (projectResponse?.Projects == null || !projectResponse.Projects.Any())
+            {
+                Console.WriteLine("Failed to retrieve projects or no projects found.");
+                Environment.Exit(1);
+            }
+
+            var firstProject = projectResponse.Projects.First();
+            var projectId = firstProject.ProjectId;
+            var projectName = firstProject.Name;
+            Console.WriteLine($"\n\nFirst Project - ID: {projectId}, Name: {projectName}\n\n");

Line range hint 37-89: Improve invite management code structure and error handling

Several improvements could enhance this example:

  1. Use a consistent placeholder email
  2. Consolidate error handling
  3. Structure console output for better readability
  4. Add comments explaining the workflow
+            const string EXAMPLE_EMAIL = "example@domain.com";
+            Console.WriteLine("\n=== Managing Invites ===\n");
+
             // list invites
             var listResp = await deepgramClient.GetInvites(myId);
-            if (listResp.Invites.Count == 0)
-            {
-                Console.WriteLine("\n\nNo invites found\n\n");
-            }
-            else
-            {
-                Console.WriteLine($"\n\n{listResp}\n\n");
-            }
+            Console.WriteLine($"Current invites: {listResp.Invites.Count}");
+            foreach (var invite in listResp.Invites)
+            {
+                Console.WriteLine($"- {invite.Email} ({invite.Scope})");
+            }

             // send invite
             var createInvite = new InviteSchema()
             {
-                Email = "spam@spam.com",
+                Email = EXAMPLE_EMAIL,
                 Scope = "member",
             };

             var createResp = await deepgramClient.SendInvite(myId, createInvite);
-            Console.WriteLine($"\n\n{createResp}\n\n");
+            Console.WriteLine($"\nInvite sent to {EXAMPLE_EMAIL}");

             // list invites
             listResp = await deepgramClient.GetInvites(myId);
-            if (listResp == null)
-            {
-                Console.WriteLine("\n\nNo invites found\n\n");
-            }
-            else
+            if (listResp?.Invites != null)
             {
-                Console.WriteLine($"\n\n{listResp}\n\n");
+                Console.WriteLine($"\nUpdated invite count: {listResp.Invites.Count}");
             }

             // delete invite
-            var delResp = await deepgramClient.DeleteInvite(myId, "spam@spam.com");
-            Console.WriteLine($"\n\n{listResp}\n\n");
+            var delResp = await deepgramClient.DeleteInvite(myId, EXAMPLE_EMAIL);
+            Console.WriteLine($"\nDeleted invite for {EXAMPLE_EMAIL}");

Line range hint 13-91: Consider adding production-ready features

While this is an example, consider adding the following features to demonstrate best practices:

  1. Proper exception handling with try-catch blocks for API calls
  2. Cancellation token support for async operations
  3. Using ILogger for structured logging instead of Console.WriteLine

Would you like me to provide an example implementation with these improvements?

examples/Deepgram.Examples.Manage.Keys/Program.cs (5)

Line range hint 11-13: Align namespace with .NET naming conventions

The namespace SampleApp should match the assembly name (project name) Deepgram.Examples.Manage.Keys to follow .NET naming conventions.

-namespace SampleApp
+namespace Deepgram.Examples.Manage.Keys

Line range hint 29-33: Enhance error handling and logging patterns

The current error handling has several areas for improvement:

  1. Direct Environment.Exit calls aren't ideal for example code
  2. Error messages lack detail about what went wrong
  3. Inconsistent error handling patterns (some errors exit, others continue)

Consider implementing a more robust error handling pattern:

-if (projectResp == null)
-{
-    Console.WriteLine("ListProjects failed.");
-    Environment.Exit(1);
-}
+if (projectResp?.Projects == null)
+{
+    Console.WriteLine("Failed to retrieve projects. Please check your API key and network connection.");
+    return;
+}

Similar improvements should be applied to all error handling blocks for consistency.

Also applies to: 44-48, 66-71, 89-94, 98-103, 107-112


Line range hint 22-24: Improve API client initialization and error handling

The API client initialization could benefit from additional error handling and security considerations:

  1. Add validation for the environment variable
  2. Wrap API calls in try-catch blocks
  3. Implement proper disposal pattern for the client

Consider implementing these improvements:

+try
+{
+    var apiKey = Environment.GetEnvironmentVariable("DEEPGRAM_API_KEY") 
+        ?? throw new InvalidOperationException("DEEPGRAM_API_KEY environment variable is not set");
     var deepgramClient = ClientFactory.CreateManageClient();
+    try
+    {
+        // Use client
+    }
+    finally
+    {
+        // Ensure proper cleanup if needed
+    }
+}
+catch (Exception ex)
+{
+    Console.WriteLine($"Failed to initialize Deepgram client: {ex.Message}");
+    return;
+}

Line range hint 15-17: Add XML documentation to improve example usability

As this is an example project, adding XML documentation would help users understand the purpose and usage of the code better.

+/// <summary>
+/// Example program demonstrating Deepgram API key management operations.
+/// </summary>
 class Program
 {
+    /// <summary>
+    /// Demonstrates basic CRUD operations for Deepgram API keys.
+    /// </summary>
     static async Task Main(string[] args)

Line range hint 61-65: Define constants for API scopes

The scope value "member" is used as a magic string. Consider defining constants or an enum for available scopes.

+private static class ApiScopes
+{
+    public const string Member = "member";
+    // Add other available scopes
+}

 var createKey = new KeySchema()
 {
     Comment = "MyTestKey",
-    Scopes = new List<string> { "member" },
+    Scopes = new List<string> { ApiScopes.Member },
 };
examples/Deepgram.Examples.Manage.Models/Program.cs (1)

Line range hint 16-108: Consider enhancing the example's robustness and consistency.

As this is an example project demonstrating SDK usage, consider the following improvements:

  1. Replace direct Environment.Exit(1) calls with proper exception handling
  2. Remove Console.ReadKey() as it's not necessary for example code
  3. Standardize string interpolation style
  4. Add more descriptive comments explaining the API interactions

Example improvement for error handling:

-            if (projectResp == null)
-            {
-                Console.WriteLine("ListProjects failed.");
-                Environment.Exit(1);
-            }
+            try
+            {
+                if (projectResp == null)
+                    throw new InvalidOperationException("Failed to retrieve projects. The API response was null.");
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"Error listing projects: {ex.Message}");
+                throw;
+            }

Example of improved comments:

-            // get projects
+            // Retrieve all projects associated with the API key
+            // This demonstrates basic project listing functionality
examples/Deepgram.Examples.Manage.Scopes/Program.cs (4)

Line range hint 13-13: Consider making MEMBER_BY_EMAIL configurable

The hardcoded email constant makes the example less flexible. Consider reading this value from environment variables or command line arguments to make the example more practical.

-    private const string MEMBER_BY_EMAIL = "MEMBER_TO_DELETE_BY_EMAIL";
+    private static string GetMemberEmail() => 
+        Environment.GetEnvironmentVariable("DEEPGRAM_MEMBER_EMAIL") 
+        ?? throw new InvalidOperationException("DEEPGRAM_MEMBER_EMAIL environment variable is required");

Line range hint 29-35: Consolidate error handling patterns

The code repeats similar error handling patterns with Console.WriteLine and Environment.Exit. Consider creating a helper method to handle these cases consistently.

+    private static void HandleError(string message)
+    {
+        Console.WriteLine($"\n\nError: {message}\n\n");
+        Environment.Exit(1);
+    }

Then use it throughout the code:

-    if (projectResp == null)
-    {
-        Console.WriteLine("ListProjects failed.");
-        Environment.Exit(1);
-    }
+    if (projectResp == null) HandleError("ListProjects failed.");

Also applies to: 56-61, 73-78, 91-96, 108-113


Line range hint 82-104: Extract scope update logic into a helper method

The pattern of updating scope and getting member scopes is repeated. Consider extracting this into a reusable method to reduce code duplication.

+    private static async Task UpdateAndVerifyScope(
+        IManageClient client,
+        string projectId,
+        string memberId,
+        string newScope)
+    {
+        var scopeUpdate = new MemberScopeSchema { Scope = newScope };
+        var updateResp = await client.UpdateMemberScope(projectId, memberId, scopeUpdate);
+        Console.WriteLine($"\n\n{updateResp}\n\n");
+
+        var memberResp = await client.GetMemberScopes(projectId, memberId);
+        if (memberResp == null) HandleError("No scopes found after update");
+        Console.WriteLine($"\n\n{memberResp}\n\n");
+    }

Console.WriteLine calls should be replaced with ILogger

The review comment is valid. The codebase already has Microsoft.Extensions.Logging infrastructure in place:

  • Both Deepgram and Deepgram.Microphone projects reference Microsoft.Extensions.Logging packages
  • The library has a dedicated logging system in the Logger namespace
  • The README documents usage of Microsoft.Extensions.Logging

The example code should be updated to use the logging infrastructure instead of Console.WriteLine for consistency with the rest of the codebase.

🔗 Analysis chain

Line range hint 15-122: Consider future logging implementation

As mentioned in the PR objectives, future updates will implement conventional logging using Microsoft.Extensions.Logging.Abstractions. The current direct Console.WriteLine usage will need to be updated.

Let's check if Microsoft.Extensions.Logging is already referenced in the project:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if logging package is referenced in any project files
fd -e csproj . | xargs grep -l "Microsoft.Extensions.Logging"

Length of output: 133


Script:

#!/bin/bash
# Check the actual logging references in the main library
cat Deepgram/Deepgram.csproj

# Check if there's any ILogger usage in the codebase
rg "ILogger|Microsoft.Extensions.Logging" -A 2

Length of output: 13397

examples/Deepgram.Examples.Manage.Projects/Program.cs (4)

5-7: Consider modernizing namespace declarations and using directives.

The code could benefit from modern C# features to improve maintainability:

  1. Use file-scoped namespaces
  2. Consider moving common using directives to a central file using global using directives
-using System;
-using System.Threading.Tasks;
-using Deepgram;
-using Deepgram.Models.Manage.v1;
-
-namespace SampleApp
-{
+namespace SampleApp;
+
+using Deepgram;
+using Deepgram.Models.Manage.v1;

Line range hint 14-22: Enhance resource management and error handling.

While the async setup is correct, consider these improvements:

  1. Add validation for the DEEPGRAM_API_KEY environment variable
  2. Implement proper disposal pattern for the client
-        static async Task Main(string[] args)
-        {
-            // Initialize Library with default logging
-            // Normal logging is "Info" level
-            Library.Initialize();
-
-            // use the client factory with a API Key set with the "DEEPGRAM_API_KEY" environment variable
-            var deepgramClient = ClientFactory.CreateManageClient();
+        static async Task Main(string[] args)
+        {
+            try
+            {
+                var apiKey = Environment.GetEnvironmentVariable("DEEPGRAM_API_KEY") 
+                    ?? throw new InvalidOperationException("DEEPGRAM_API_KEY environment variable is not set");
+
+                // Initialize Library with default logging
+                Library.Initialize();
+
+                using var deepgramClient = ClientFactory.CreateManageClient();

Line range hint 24-40: Improve project lookup logic using LINQ and null handling.

The current implementation could be more concise and maintainable:

  1. Use LINQ for project searching
  2. Use more descriptive variable names
  3. Implement null-conditional operators
-            string myId = null;
-            string myName = null;
-            string myDeleteId = null;
-            foreach (var project in listResp.Projects)
-            {
-                if (project.Name == DELETE_PROJECT_BY_NAME)
-                {
-                    myDeleteId = project.ProjectId;
-                }
-                myId = project.ProjectId;
-                myName = project.Name;
-            }
+            var projectToDelete = listResp.Projects.FirstOrDefault(p => p.Name == DELETE_PROJECT_BY_NAME);
+            var lastProject = listResp.Projects.LastOrDefault();
+            
+            var currentProjectId = lastProject?.ProjectId;
+            var currentProjectName = lastProject?.Name;
+            var projectIdToDelete = projectToDelete?.ProjectId;

Line range hint 42-124: Refactor repetitive error handling and console output patterns.

The code contains several areas that could be improved:

  1. Abstract common error handling logic
  2. Create helper methods for repeated operations
  3. Use consistent error messaging

Consider refactoring the code using this pattern:

private static async Task<T> ExecuteOperation<T>(string operationName, Func<Task<T>> operation)
{
    var result = await operation();
    if (result == null)
    {
        Console.WriteLine($"\n\n{operationName} failed.\n\n");
        Environment.Exit(1);
    }
    Console.WriteLine($"\n\n{result}\n\n");
    return result;
}

// Usage example:
var project = await ExecuteOperation("GetProject", 
    () => deepgramClient.GetProject(currentProjectId));

This would significantly reduce code duplication and maintain consistent error handling.

examples/Deepgram.Examples.SpeechToText.Websocket.Microphone/Program.cs (6)

5-7: Consider organizing using directives according to .NET conventions.

Group using directives in the following order:

  1. System namespaces
  2. Third-party namespaces (Deepgram)
  3. Project namespaces
using System;
using System.Threading.Tasks;
+
using Deepgram;
using Deepgram.Logger;
using Deepgram.Microphone;
using Deepgram.Models.Authenticate.v1;
using Deepgram.Models.Listen.v2.WebSocket;

Line range hint 26-27: Security: Do not use empty API key string.

The API key should be retrieved from environment variables or secure configuration. Currently, it's passed as an empty string which will fail authentication.

-var liveClient = ClientFactory.CreateListenWebSocketClient(apiKey: "", options: options);
+var apiKey = Environment.GetEnvironmentVariable("DEEPGRAM_API_KEY") 
+    ?? throw new InvalidOperationException("DEEPGRAM_API_KEY environment variable is not set");
+var liveClient = ClientFactory.CreateListenWebSocketClient(apiKey: apiKey, options: options);

Line range hint 19-24: Improve error handling and logging initialization.

Consider removing commented debug logging code and improve error handling by catching specific exceptions.

-                // Initialize Library with default logging
-                // Normal logging is "Info" level
                 Deepgram.Library.Initialize();
-                // OR very chatty logging
-                //Deepgram.Library.Initialize(LogLevel.Debug); // LogLevel.Default, LogLevel.Debug, LogLevel.Verbose

                 // Initialize the microphone library
                 Deepgram.Microphone.Library.Initialize();

Line range hint 47-49: Remove commented code and improve transcript logging.

Remove the commented JSON serialization code and consider adding more structured logging for the transcription results.

-                    // Console.WriteLine("Transcription received: " + JsonSerializer.Serialize(e.Transcription));
                    Console.WriteLine($"----> Speaker: {e.Channel.Alternatives[0].Transcript}");

Line range hint 73-85: Externalize configuration values and improve error handling.

Consider moving the LiveSchema configuration to a separate configuration file or environment variables for better maintainability.

+                // TODO: Move to configuration
                 var liveSchema = new LiveSchema()
                 {
                     Model = "nova-2",
                     Encoding = "linear16",
                     SampleRate = 16000,
                     Punctuate = true,
                     SmartFormat = true,
                     InterimResults = true,
                     UtteranceEnd = "1000",
                     VadEvents = true,
                 };

Line range hint 86-106: Improve resource management using IDisposable pattern.

Consider implementing proper resource cleanup using the IDisposable pattern or async using statements for the microphone and WebSocket client.

-                bool bConnected = await liveClient.Connect(liveSchema);
-                if (!bConnected)
-                {
-                    Console.WriteLine("Failed to connect to Deepgram WebSocket server.");
-                    return;
-                }
+                if (!await liveClient.Connect(liveSchema))
+                    throw new InvalidOperationException("Failed to connect to Deepgram WebSocket server.");

+                await using var microphone = new Microphone(liveClient.Send);
-                var microphone = new Microphone(liveClient.Send);
                 microphone.Start();

                 // Wait for the user to press a key
                 Console.ReadKey();

-                // Stop the microphone
-                microphone.Stop();
-
-                // Stop the connection
-                await liveClient.Stop();
-
-                // Terminate Libraries
-                Deepgram.Microphone.Library.Terminate();
-                Deepgram.Library.Terminate();
Deepgram.Microphone/Deepgram.Microphone.csproj (1)

Line range hint 9-67: Optimize NuGet packaging configuration.

The current structure has several opportunities for improvement:

  1. Duplicate properties between solution configurations can be centralized
  2. Copyright year should be dynamic to avoid manual updates

Consider refactoring the packaging configuration:

+ <PropertyGroup>
+   <!-- Common properties for both configurations -->
+   <IsPackable>true</IsPackable>
+   <Company>Deepgram</Company>
+   <Authors>Deepgram .NET SDK Contributors</Authors>
+   <Copyright>$([System.DateTime]::Now.Year) Deepgram</Copyright>
+   <PackageIcon>dg_logo.png</PackageIcon>
+   <PackageRequireLicenseAcceptance>False</PackageRequireLicenseAcceptance>
+   <PackageLicenseExpression>MIT</PackageLicenseExpression>
+   <PackageProjectUrl>https://developers.deepgram.com/sdks-tools/sdks/dotnet-sdk/</PackageProjectUrl>
+   <PackageReadmeFile>README.md</PackageReadmeFile>
+   <RepositoryUrl>https://github.com/deepgram/deepgram-dotnet-sdk</RepositoryUrl>
+   <PackageTags>speech-to-text,captions,speech-recognition,deepgram,dotnet</PackageTags>
+   <EnableNETAnalyzers>True</EnableNETAnalyzers>
+   <EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
+   <AnalysisLevel>latest</AnalysisLevel>
+ </PropertyGroup>

  <PropertyGroup Condition="'$(SolutionFileName)' == 'Deepgram.sln'">
-   <!-- Remove duplicate properties -->
+   <PackageId>Deepgram.Microphone</PackageId>
+   <Title>Deepgram .NET Microphone</Title>
+   <Description>Helper Microphone Package</Description>
+   <Summary>Helper Microphone Package</Summary>
  </PropertyGroup>

  <PropertyGroup Condition="'$(SolutionFileName)' == 'Deepgram.DevBuild.sln'">
-   <!-- Remove duplicate properties -->
+   <PackageId>Deepgram.Unstable.Microphone.Builds</PackageId>
+   <Title>Deepgram.Microphone - UNSTABLE DEVELOPER BUILDS</Title>
+   <Description>UNSTABLE DEVELOPER BUILDS - Deepgram .NET Microphone</Description>
+   <Summary>UNSTABLE DEVELOPER BUILDS - Deepgram .NET Microphone</Summary>
  </PropertyGroup>
Deepgram/Deepgram.csproj (3)

72-82: Consider using consistent version patterns across packages.

While the package updates are good, there's inconsistency in version specificity:

  • Some packages use exact versions (e.g., "8.0.2")
  • Others in net8.0 section use wildcards (e.g., "8.*")

Consider using exact versions throughout for better reproducibility and dependency control.


Line range hint 113-121: Align version specificity with other target frameworks.

The net8.0 section uses wildcard versions (8.*) while other frameworks use specific versions. This could lead to unexpected package updates and inconsistent behavior across environments.

Consider using specific versions like the other target frameworks:

-    <PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.*">
+    <PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
-    <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.*" />
+    <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
-    <PackageReference Include="Microsoft.Extensions.Logging" Version="8.*" />
+    <PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.1" />

Line range hint 1-150: Consider simplifying the project configuration approach.

The current setup maintains two separate configurations (stable and unstable) through different solution files. This isn't a common .NET practice and could be simplified:

  1. Consider using build configurations (Debug/Release) instead of separate solution files
  2. For unstable builds, consider using CI/CD pipeline configurations or build-time variables
  3. Look into using .NET's built-in preview package support instead of maintaining a separate unstable package feed

This would align better with standard .NET practices and simplify maintenance.

examples/Deepgram.Examples.TextToSpeech.Websocket.Simple/Program.cs (6)

5-13: Organize using directives according to .NET conventions.

Consider organizing the using directives into groups:

  1. System namespaces
  2. Third-party namespaces (Deepgram)

Also, remove the redundant using Deepgram.Logger as it's already included in the using Deepgram namespace.

using System;
using System.IO;
using System.Threading.Tasks;

using Deepgram;
-using Deepgram.Logger;
using Deepgram.Models.Authenticate.v1;
using Deepgram.Models.Speak.v2.WebSocket;

Line range hint 19-28: Consider adding cancellation token support for better async operation handling.

For better async operation handling in a console application, consider adding a CancellationTokenSource to allow graceful shutdown.

static async Task Main(string[] args)
{
+   using var cts = new CancellationTokenSource();
+   Console.CancelKeyPress += (s, e) => {
+       e.Cancel = true;
+       cts.Cancel();
+   };
    try
    {
        // ... rest of the code

Line range hint 47-123: Extract WAV header generation to a separate method and use modern file handling.

The WAV header generation logic is complex and should be extracted to improve maintainability. Also, consider using more modern file handling patterns.

+ private static byte[] GenerateWavHeader(int sampleRate = 48000, short bitsPerSample = 16, short channels = 1)
+ {
+     byte[] wavHeader = new byte[44];
+     int byteRate = sampleRate * channels * (bitsPerSample / 8);
+     short blockAlign = (short)(channels * (bitsPerSample / 8));
+     
+     // RIFF header
+     wavHeader[0] = 0x52; // R
+     // ... rest of the header generation
+     return wavHeader;
+ }

- if (appendWavHeader)
- {
-     using (BinaryWriter writer = new BinaryWriter(File.Open("output.wav", FileMode.Append)))
+     if (appendWavHeader)
+     {
+         byte[] wavHeader = GenerateWavHeader();
+         await File.WriteAllBytesAsync("output.wav", wavHeader, cancellationToken);
+         appendWavHeader = false;
+     }

Line range hint 125-132: Use modern file handling patterns for audio data writing.

Replace the BinaryWriter with modern async file operations.

- if (e.Stream != null)
- {
-     using (BinaryWriter writer = new BinaryWriter(File.Open("output.wav", FileMode.Append)))
-     {
-         writer.Write(e.Stream.ToArray());
-     }
- }
+ if (e.Stream != null)
+ {
+     await File.WriteAllBytesAsync("output.wav", e.Stream.ToArray(), FileMode.Append, cancellationToken);
+ }

Line range hint 167-189: Enhance connection handling and configuration management.

Consider the following improvements:

  1. Move configuration to appsettings.json
  2. Add connection timeout
  3. Validate input text
+ var config = new SpeakSchema
+ {
+     Encoding = Configuration.GetValue<string>("Deepgram:Encoding", "linear16"),
+     SampleRate = Configuration.GetValue<int>("Deepgram:SampleRate", 48000)
+ };

- var speakSchema = new SpeakSchema()
- {
-     Encoding = "linear16",
-     SampleRate = 48000,
- };
- bool bConnected = await speakClient.Connect(speakSchema);
+ using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
+ bool bConnected = await speakClient.Connect(config, cts.Token);

+ if (string.IsNullOrEmpty(textToSpeak))
+     throw new ArgumentException("Text to speak cannot be empty");
- speakClient.SpeakWithText("Hello World!");
+ await speakClient.SpeakWithText(textToSpeak);

Line range hint 191-202: Improve exception handling and resource cleanup.

Consider implementing more specific exception handling and proper async resource cleanup.

- catch (Exception ex)
+ catch (DeepgramException ex)
+ {
+     Console.WriteLine($"Deepgram API error: {ex.Message}");
+ }
+ catch (IOException ex)
+ {
+     Console.WriteLine($"File operation error: {ex.Message}");
+ }
+ catch (Exception ex)
{
-     Console.WriteLine($"Exception: {ex.Message}");
+     Console.WriteLine($"Unexpected error: {ex.Message}");
+     throw;
}
+ finally
+ {
+     if (speakClient is IAsyncDisposable disposable)
+         await disposable.DisposeAsync();
+     Library.Terminate();
+ }
.gitignore (1)

486-490: Consider using user secrets for development.

Currently ignoring web.config, app.config, and settings.json for API keys. For development scenarios, consider using .NET User Secrets instead of configuration files:

  1. Right-click the project in Visual Studio and select "Manage User Secrets"
  2. Use IConfiguration to access secrets:
builder.Configuration.GetValue<string>("ApiKey")

This provides better security and follows .NET best practices for secret management.

Deepgram.sln (1)

12-61: Consider consolidating example projects

While the current organization provides clear separation, having 24 separate example projects might increase maintenance overhead. Consider:

  1. Grouping related examples into fewer projects (e.g., all REST examples in one project)
  2. Using a consistent naming pattern for better discoverability
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between db9a7dc and 871b9fc.

⛔ Files ignored due to path filters (6)
  • examples/speech-to-text/rest/sentiment/CallCenterPhoneCall.mp3 is excluded by !**/*.mp3, !**/*.mp3
  • examples/speech-to-text/rest/summary/CallCenterPhoneCall.mp3 is excluded by !**/*.mp3, !**/*.mp3
  • examples/speech-to-text/rest/topic/CallCenterPhoneCall.mp3 is excluded by !**/*.mp3, !**/*.mp3
  • extras/Bueller-Life-moves-pretty-fast.wav is excluded by !**/*.wav, !**/*.wav
  • extras/CallCenterPhoneCall.mp3 is excluded by !**/*.mp3, !**/*.mp3
  • extras/preamble.wav is excluded by !**/*.wav, !**/*.wav
📒 Files selected for processing (82)
  • .gitignore (1 hunks)
  • Deepgram.Dev.sln (0 hunks)
  • Deepgram.DevBuild.sln (0 hunks)
  • Deepgram.Microphone/Deepgram.Microphone.csproj (2 hunks)
  • Deepgram.Tests/Deepgram.Tests.csproj (1 hunks)
  • Deepgram.sln (1 hunks)
  • Deepgram/Deepgram.csproj (2 hunks)
  • Directory.Build.props (1 hunks)
  • clean-up.sh (0 hunks)
  • examples/Deepgram.Examples.Analyze.Intent/Deepgram.Examples.Analyze.Intent.csproj (1 hunks)
  • examples/Deepgram.Examples.Analyze.Intent/Program.cs (1 hunks)
  • examples/Deepgram.Examples.Analyze.Sentiment/Deepgram.Examples.Analyze.Sentiment.csproj (1 hunks)
  • examples/Deepgram.Examples.Analyze.Sentiment/Program.cs (1 hunks)
  • examples/Deepgram.Examples.Analyze.Summary/Deepgram.Examples.Analyze.Summary.csproj (1 hunks)
  • examples/Deepgram.Examples.Analyze.Summary/Program.cs (1 hunks)
  • examples/Deepgram.Examples.Analyze.Topic/Deepgram.Examples.Analyze.Topic.csproj (1 hunks)
  • examples/Deepgram.Examples.Analyze.Topic/Program.cs (1 hunks)
  • examples/Deepgram.Examples.Manage.Balances/Deepgram.Examples.Manage.Balances.csproj (1 hunks)
  • examples/Deepgram.Examples.Manage.Balances/Program.cs (1 hunks)
  • examples/Deepgram.Examples.Manage.Invitations/Deepgram.Examples.Manage.Invitations.csproj (1 hunks)
  • examples/Deepgram.Examples.Manage.Invitations/Program.cs (1 hunks)
  • examples/Deepgram.Examples.Manage.Keys/Deepgram.Examples.Manage.Keys.csproj (1 hunks)
  • examples/Deepgram.Examples.Manage.Keys/Program.cs (1 hunks)
  • examples/Deepgram.Examples.Manage.Members/Deepgram.Examples.Manage.Members.csproj (1 hunks)
  • examples/Deepgram.Examples.Manage.Members/Program.cs (1 hunks)
  • examples/Deepgram.Examples.Manage.Models/Deepgram.Examples.Manage.Models.csproj (1 hunks)
  • examples/Deepgram.Examples.Manage.Models/Program.cs (1 hunks)
  • examples/Deepgram.Examples.Manage.Projects/Deepgram.Examples.Manage.Projects.csproj (1 hunks)
  • examples/Deepgram.Examples.Manage.Projects/Program.cs (1 hunks)
  • examples/Deepgram.Examples.Manage.Scopes/Deepgram.Examples.Manage.Scopes.csproj (1 hunks)
  • examples/Deepgram.Examples.Manage.Scopes/Program.cs (1 hunks)
  • examples/Deepgram.Examples.Manage.Usage/Deepgram.Examples.Manage.Usage.csproj (1 hunks)
  • examples/Deepgram.Examples.Manage.Usage/Program.cs (1 hunks)
  • examples/Deepgram.Examples.SpeechToText.Rest.File/Deepgram.Examples.SpeechToText.Rest.File.csproj (1 hunks)
  • examples/Deepgram.Examples.SpeechToText.Rest.File/Program.cs (1 hunks)
  • examples/Deepgram.Examples.SpeechToText.Rest.Intent/Deepgram.Examples.SpeechToText.Rest.Intent.csproj (1 hunks)
  • examples/Deepgram.Examples.SpeechToText.Rest.Intent/Program.cs (1 hunks)
  • examples/Deepgram.Examples.SpeechToText.Rest.Sentiment/Deepgram.Examples.SpeechToText.Rest.Sentiment.csproj (1 hunks)
  • examples/Deepgram.Examples.SpeechToText.Rest.Sentiment/Program.cs (1 hunks)
  • examples/Deepgram.Examples.SpeechToText.Rest.Summary/Deepgram.Examples.SpeechToText.Rest.Summary.csproj (1 hunks)
  • examples/Deepgram.Examples.SpeechToText.Rest.Summary/Program.cs (1 hunks)
  • examples/Deepgram.Examples.SpeechToText.Rest.Topic/Deepgram.Examples.SpeechToText.Rest.Topic.csproj (1 hunks)
  • examples/Deepgram.Examples.SpeechToText.Rest.Topic/Program.cs (1 hunks)
  • examples/Deepgram.Examples.SpeechToText.Rest.Url/Deepgram.Examples.SpeechToText.Rest.Url.csproj (1 hunks)
  • examples/Deepgram.Examples.SpeechToText.Rest.Url/Program.cs (1 hunks)
  • examples/Deepgram.Examples.SpeechToText.Websocket.File/Deepgram.Examples.SpeechToText.Websocket.File.csproj (1 hunks)
  • examples/Deepgram.Examples.SpeechToText.Websocket.File/Program.cs (1 hunks)
  • examples/Deepgram.Examples.SpeechToText.Websocket.Http/Deepgram.Examples.SpeechToText.Websocket.Http.csproj (1 hunks)
  • examples/Deepgram.Examples.SpeechToText.Websocket.Http/Program.cs (2 hunks)
  • examples/Deepgram.Examples.SpeechToText.Websocket.Microphone/Deepgram.Examples.SpeechToText.Websocket.Microphone.csproj (1 hunks)
  • examples/Deepgram.Examples.SpeechToText.Websocket.Microphone/Program.cs (1 hunks)
  • examples/Deepgram.Examples.TextToSpeech.Rest.File.HelloWorld/Deepgram.Examples.TextToSpeech.Rest.File.HelloWorld.csproj (1 hunks)
  • examples/Deepgram.Examples.TextToSpeech.Rest.File.HelloWorld/Program.cs (1 hunks)
  • examples/Deepgram.Examples.TextToSpeech.Rest.File.WoodChuck/Deepgram.Examples.TextToSpeech.Rest.File.WoodChuck.csproj (1 hunks)
  • examples/Deepgram.Examples.TextToSpeech.Rest.File.WoodChuck/Program.cs (1 hunks)
  • examples/Deepgram.Examples.TextToSpeech.Websocket.Simple/Deepgram.Examples.TextToSpeech.Websocket.Simple.csproj (1 hunks)
  • examples/Deepgram.Examples.TextToSpeech.Websocket.Simple/Program.cs (1 hunks)
  • examples/analyze/intent/Analyze.csproj (0 hunks)
  • examples/analyze/sentiment/Analyze.csproj (0 hunks)
  • examples/analyze/sentiment/conversation.txt (0 hunks)
  • examples/analyze/summary/Analyze.csproj (0 hunks)
  • examples/analyze/summary/conversation.txt (0 hunks)
  • examples/analyze/topic/Analyze.csproj (0 hunks)
  • examples/analyze/topic/conversation.txt (0 hunks)
  • examples/manage/balances/Manage.csproj (0 hunks)
  • examples/manage/invitations/Manage.csproj (0 hunks)
  • examples/manage/keys/Manage.csproj (0 hunks)
  • examples/manage/members/Manage.csproj (0 hunks)
  • examples/manage/models/Models.csproj (0 hunks)
  • examples/manage/projects/Manage.csproj (0 hunks)
  • examples/manage/scopes/Manage.csproj (0 hunks)
  • examples/manage/usage/Manage.csproj (0 hunks)
  • examples/speech-to-text/rest/file/PreRecorded.csproj (0 hunks)
  • examples/speech-to-text/rest/intent/PreRecorded.csproj (0 hunks)
  • examples/speech-to-text/rest/sentiment/PreRecorded.csproj (0 hunks)
  • examples/speech-to-text/rest/summary/PreRecorded.csproj (0 hunks)
  • examples/speech-to-text/rest/topic/PreRecorded.csproj (0 hunks)
  • examples/speech-to-text/rest/url/PreRecorded.csproj (0 hunks)
  • examples/speech-to-text/websocket/file/Streaming.csproj (0 hunks)
  • examples/speech-to-text/websocket/http/Streaming.csproj (0 hunks)
  • examples/speech-to-text/websocket/microphone/Streaming.csproj (0 hunks)
  • examples/text-to-speech/rest/file/hello-world/Speak.csproj (0 hunks)
⛔ Files not processed due to max files limit (26)
  • examples/text-to-speech/rest/file/woodchuck/Speak.csproj
  • examples/text-to-speech/websocket/simple/Speak.csproj
  • tests/Deepgram.Tests.EdgeCases.KeepAlive/Deepgram.Tests.EdgeCases.KeepAlive.csproj
  • tests/Deepgram.Tests.EdgeCases.KeepAlive/Program.cs
  • tests/Deepgram.Tests.EdgeCases.ReuseReconnect/Deepgram.Tests.EdgeCases.ReuseReconnect.csproj
  • tests/Deepgram.Tests.EdgeCases.ReuseReconnect/Program.cs
  • tests/Deepgram.Tests.EdgeCases.SpeechToText.V1.ClientExample/Deepgram.Tests.EdgeCases.SpeechToText.V1.ClientExample.csproj
  • tests/Deepgram.Tests.EdgeCases.SpeechToText.V1.ClientExample/Program.cs
  • tests/Deepgram.Tests.EdgeCases.TextToSpeech.V1.ClientExample/Deepgram.Tests.EdgeCases.TextToSpeech.V1.ClientExample.csproj
  • tests/Deepgram.Tests.EdgeCases.TextToSpeech.V1.ClientExample/Program.cs
  • tests/Deepgram.Tests.ExpectedFailures.Rest.BadHost/Deepgram.Tests.ExpectedFailures.Rest.BadHost.csproj
  • tests/Deepgram.Tests.ExpectedFailures.Rest.BadHost/Program.cs
  • tests/Deepgram.Tests.ExpectedFailures.Rest.ThrowException/Deepgram.Tests.ExpectedFailures.Rest.ThrowException.csproj
  • tests/Deepgram.Tests.ExpectedFailures.Rest.ThrowException/Program.cs
  • tests/Deepgram.Tests.ExpectedFailures.Rest.TriggerCancel/Deepgram.Tests.ExpectedFailures.Rest.TriggerCancel.csproj
  • tests/Deepgram.Tests.ExpectedFailures.Rest.TriggerCancel/Program.cs
  • tests/Deepgram.Tests.ExpectedFailures.Websocket.CreateTimeout/Deepgram.Tests.ExpectedFailures.Websocket.CreateTimeout.csproj
  • tests/Deepgram.Tests.ExpectedFailures.Websocket.CreateTimeout/Program.cs
  • tests/edge_cases/keepalive/KeepAlive.csproj
  • tests/edge_cases/reconnect_same_object/ReconnectStreaming.csproj
  • tests/edge_cases/stt_v1_client_example/Streaming.csproj
  • tests/edge_cases/tts_v1_client_example/Speak.csproj
  • tests/expected_failures/rest/bad_host/BadHost.csproj
  • tests/expected_failures/rest/throw_exception/ThrowException.csproj
  • tests/expected_failures/rest/trigger_cancel/TriggerCancel.csproj
  • tests/expected_failures/websocket/exercise_timeout/ExerciseTimeout.csproj
💤 Files with no reviewable changes (28)
  • Deepgram.Dev.sln
  • Deepgram.DevBuild.sln
  • clean-up.sh
  • examples/analyze/intent/Analyze.csproj
  • examples/analyze/sentiment/Analyze.csproj
  • examples/analyze/sentiment/conversation.txt
  • examples/analyze/summary/Analyze.csproj
  • examples/analyze/summary/conversation.txt
  • examples/analyze/topic/Analyze.csproj
  • examples/analyze/topic/conversation.txt
  • examples/manage/balances/Manage.csproj
  • examples/manage/invitations/Manage.csproj
  • examples/manage/keys/Manage.csproj
  • examples/manage/members/Manage.csproj
  • examples/manage/models/Models.csproj
  • examples/manage/projects/Manage.csproj
  • examples/manage/scopes/Manage.csproj
  • examples/manage/usage/Manage.csproj
  • examples/speech-to-text/rest/file/PreRecorded.csproj
  • examples/speech-to-text/rest/intent/PreRecorded.csproj
  • examples/speech-to-text/rest/sentiment/PreRecorded.csproj
  • examples/speech-to-text/rest/summary/PreRecorded.csproj
  • examples/speech-to-text/rest/topic/PreRecorded.csproj
  • examples/speech-to-text/rest/url/PreRecorded.csproj
  • examples/speech-to-text/websocket/file/Streaming.csproj
  • examples/speech-to-text/websocket/http/Streaming.csproj
  • examples/speech-to-text/websocket/microphone/Streaming.csproj
  • examples/text-to-speech/rest/file/hello-world/Speak.csproj
✅ Files skipped from review due to trivial changes (23)
  • Deepgram.Tests/Deepgram.Tests.csproj
  • Directory.Build.props
  • examples/Deepgram.Examples.Analyze.Intent/Deepgram.Examples.Analyze.Intent.csproj
  • examples/Deepgram.Examples.Analyze.Summary/Deepgram.Examples.Analyze.Summary.csproj
  • examples/Deepgram.Examples.Analyze.Topic/Deepgram.Examples.Analyze.Topic.csproj
  • examples/Deepgram.Examples.Manage.Balances/Deepgram.Examples.Manage.Balances.csproj
  • examples/Deepgram.Examples.Manage.Invitations/Deepgram.Examples.Manage.Invitations.csproj
  • examples/Deepgram.Examples.Manage.Keys/Deepgram.Examples.Manage.Keys.csproj
  • examples/Deepgram.Examples.Manage.Models/Deepgram.Examples.Manage.Models.csproj
  • examples/Deepgram.Examples.Manage.Scopes/Deepgram.Examples.Manage.Scopes.csproj
  • examples/Deepgram.Examples.Manage.Usage/Deepgram.Examples.Manage.Usage.csproj
  • examples/Deepgram.Examples.SpeechToText.Rest.File/Deepgram.Examples.SpeechToText.Rest.File.csproj
  • examples/Deepgram.Examples.SpeechToText.Rest.Intent/Deepgram.Examples.SpeechToText.Rest.Intent.csproj
  • examples/Deepgram.Examples.SpeechToText.Rest.Sentiment/Deepgram.Examples.SpeechToText.Rest.Sentiment.csproj
  • examples/Deepgram.Examples.SpeechToText.Rest.Summary/Deepgram.Examples.SpeechToText.Rest.Summary.csproj
  • examples/Deepgram.Examples.SpeechToText.Rest.Topic/Deepgram.Examples.SpeechToText.Rest.Topic.csproj
  • examples/Deepgram.Examples.SpeechToText.Rest.Url/Deepgram.Examples.SpeechToText.Rest.Url.csproj
  • examples/Deepgram.Examples.SpeechToText.Websocket.File/Deepgram.Examples.SpeechToText.Websocket.File.csproj
  • examples/Deepgram.Examples.SpeechToText.Websocket.Http/Deepgram.Examples.SpeechToText.Websocket.Http.csproj
  • examples/Deepgram.Examples.SpeechToText.Websocket.Microphone/Deepgram.Examples.SpeechToText.Websocket.Microphone.csproj
  • examples/Deepgram.Examples.TextToSpeech.Rest.File.HelloWorld/Deepgram.Examples.TextToSpeech.Rest.File.HelloWorld.csproj
  • examples/Deepgram.Examples.TextToSpeech.Rest.File.WoodChuck/Deepgram.Examples.TextToSpeech.Rest.File.WoodChuck.csproj
  • examples/Deepgram.Examples.TextToSpeech.Websocket.Simple/Deepgram.Examples.TextToSpeech.Websocket.Simple.csproj
🔇 Additional comments (33)
examples/Deepgram.Examples.Manage.Members/Deepgram.Examples.Manage.Members.csproj (3)

1-11: Project structure follows .NET conventions.

The overall project structure adheres to .NET conventions with proper SDK reference, clear property definitions, and organized ItemGroup sections. The nullable enable flag is a good practice for new projects.


9-9: Verify the $(ProjectRoot) variable resolution.

The project reference uses $(ProjectRoot) which is not a standard MSBuild variable. This might cause build issues if the variable is not properly defined in a Directory.Build.props file or similar.

#!/bin/bash
# Check for Directory.Build.props or other files that might define ProjectRoot
fd "Directory.Build.props"

# Check if other .csproj files use the same variable
fd -e csproj . | xargs grep "ProjectRoot"

8-8: Verify HTTP package compatibility with target framework.

The Microsoft.Extensions.Http package version 8.0.1 is the latest stable version, but it's designed for .NET 8. While it might work with .NET 9 preview, consider aligning the package version with the final target framework version when .NET 9 is released.

#!/bin/bash
# Check for other Microsoft.Extensions packages to ensure version consistency
fd -e csproj . | xargs grep -A 1 "Microsoft.Extensions"
examples/Deepgram.Examples.Manage.Projects/Deepgram.Examples.Manage.Projects.csproj (2)

7-10: Verify Directory.Build.props setup

The project reference uses $(ProjectRoot) variable which requires proper setup in Directory.Build.props.

Let's verify the build configuration:

✅ Verification successful

Directory.Build.props setup is correctly configured

The $(ProjectRoot) variable is properly defined in Directory.Build.props at the repository root and is consistently used across multiple projects in the solution. The variable is set to $(MSBuildThisFileDirectory), which is the standard MSBuild way to reference the directory containing the props file.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if Directory.Build.props exists and defines ProjectRoot
echo "Checking for Directory.Build.props:"
fd -e props "Directory.Build" --exec grep -l "ProjectRoot"

# Verify consistent variable usage across projects
echo "Checking ProjectRoot usage in other projects:"
fd -e csproj . --exec grep -l "ProjectRoot"

Length of output: 3534


Script:

#!/bin/bash
# Check the content of Directory.Build.props to verify ProjectRoot definition
echo "Content of Directory.Build.props:"
cat Directory.Build.props

Length of output: 229


1-6: Consider using a stable .NET version for examples

While upgrading dependencies is good, using .NET 9.0 (preview) in example projects might create challenges for users as:

  • Preview versions may have breaking changes
  • Users typically run stable .NET versions
  • Example projects should prioritize stability and broad compatibility

Consider targeting .NET 8.0 (LTS) instead.

examples/Deepgram.Examples.Analyze.Sentiment/Deepgram.Examples.Analyze.Sentiment.csproj (1)

8-8: Verify Microsoft.Extensions.Http version compatibility

The package reference to Microsoft.Extensions.Http 8.0.1 looks good and is the latest stable version.

✅ Verification successful

Microsoft.Extensions.Http version 8.0.1 is used consistently across the codebase

The version 8.0.1 of Microsoft.Extensions.Http is used consistently in all projects that reference it, including both example projects and the main SDK projects. This version is compatible with the project's target frameworks (net6.0, net7.0, net8.0, netstandard2.0) and aligns with other Microsoft.Extensions.* package versions used in the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if this version is used consistently across all example projects
# and verify if it resolves the security advisory GHSA-hh2w-p6rv-4g7w

# Test: Search for Microsoft.Extensions.Http package references
rg --type=xml 'PackageReference.*Microsoft\.Extensions\.Http.*Version'

Length of output: 221


Script:

#!/bin/bash
# Let's try a broader search for csproj files first and then look for the package reference
fd -e csproj --exec cat {}

Length of output: 29603

examples/Deepgram.Examples.Analyze.Summary/Program.cs (2)

5-10: LGTM! File structure follows .NET conventions.

The file organization with proper copyright header, using statements, and namespace structure aligns well with standard .NET practices.


12-13: LGTM! Appropriate class modifiers for an entry point.

Making the Program class public static follows .NET best practices for entry point classes, preventing instantiation and providing proper accessibility.

examples/Deepgram.Examples.Analyze.Sentiment/Program.cs (1)

5-10: LGTM! Namespace and using directives follow .NET conventions.

The namespace hierarchy properly reflects the physical folder structure, and using directives are well-organized.

examples/Deepgram.Examples.SpeechToText.Rest.Intent/Program.cs (1)

Line range hint 13-14: LGTM!

The class and Main method follow modern C# practices with proper async/await support.

examples/Deepgram.Examples.SpeechToText.Rest.Summary/Program.cs (1)

Line range hint 1-8: LGTM! Well-structured file header and imports.

The file includes proper copyright notice, license information, and organized imports.

examples/Deepgram.Examples.SpeechToText.Rest.Sentiment/Program.cs (2)

Line range hint 1-10: LGTM! Well-structured file header and imports.

The copyright header with SPDX identifier and minimal required imports follow best practices.


Line range hint 1-46: Verify security implications of file handling.

Given the security advisory mentioned in the PR (GHSA-hh2w-p6rv-4g7w), let's verify the file handling security implications.

examples/Deepgram.Examples.TextToSpeech.Rest.File.WoodChuck/Program.cs (1)

5-6: LGTM: Required using directives added for async functionality

The addition of System and System.Threading.Tasks directives properly supports the async implementation.

examples/Deepgram.Examples.Analyze.Intent/Program.cs (1)

13-15: LGTM! Changes align with modern .NET practices

The modifications to make the Program class public static and the Main method public follow recommended C# practices and improve testability.

examples/Deepgram.Examples.SpeechToText.Rest.File/Program.cs (1)

5-9: LGTM: Using directives are properly organized.

The added using directives are necessary for file operations and async programming, following .NET conventions.

examples/Deepgram.Examples.Manage.Balances/Program.cs (1)

5-8: LGTM! Namespace change aligns with .NET conventions.

The updated namespace Deepgram.Examples.Manage.Balances follows .NET naming guidelines and properly reflects the hierarchical structure of the examples.

examples/Deepgram.Examples.Manage.Members/Program.cs (1)

5-7: LGTM! Using directives are properly organized.

The using directives follow .NET conventions and include all necessary namespaces for the functionality.

examples/Deepgram.Examples.Manage.Usage/Program.cs (2)

5-6: LGTM: Necessary namespace additions for async support

The added namespaces are required to support the async/await pattern implementation.


Line range hint 15-17: Verify consistency across example projects

Let's ensure this async pattern and error handling approach is consistent across other example projects.

✅ Verification successful

Library initialization pattern is consistent across example projects

The verification shows a consistent pattern of Library initialization across all example projects:

  • All projects use Library.Initialize() with either default logging or explicit log levels
  • Comments consistently explain logging options when log levels are specified
  • Projects requiring microphone access correctly initialize both Deepgram and Microphone libraries
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for consistency in async Main methods and Library initialization across examples
echo "Checking for async Main patterns in example projects..."
ast-grep --pattern 'static async Task Main(string[] args)'

echo "\nChecking Library initialization patterns..."
rg -A 2 'Library.Initialize\(\);'

Length of output: 11985

examples/Deepgram.Examples.Manage.Models/Program.cs (1)

13-15: LGTM! Changes align with modern .NET practices.

The modifications to make the Program class and Main method public static follow current .NET conventions and improve the example's accessibility.

examples/Deepgram.Examples.Manage.Scopes/Program.cs (1)

5-6: LGTM: Necessary namespace imports added correctly

The addition of System and Task namespaces is appropriate for enabling async operations in the program.

Deepgram.Microphone/Deepgram.Microphone.csproj (2)

Line range hint 3-7: Framework targeting strategy looks good!

The multi-targeting approach with netstandard2.0 and modern .NET versions provides good compatibility while enabling the use of latest language features.


140-140: Verify PortAudioSharp2 upgrade impact.

The upgrade from version 1.0.0 to 1.0.4 might introduce breaking changes. Please ensure that the new version is compatible with your usage.

✅ Verification successful

Let me gather more information about the package versions and changes.


Let me check the changelog or release notes for this package to understand the changes between versions.


PortAudioSharp2 upgrade appears safe

Based on the codebase analysis, the usage of PortAudioSharp2 is limited to basic Stream initialization with standard parameters. The API usage pattern is straightforward and focuses on core functionality:

  • Single global import in GlobalUsings.cs
  • Basic Stream creation with standard parameters in Microphone.cs
  • No complex or deprecated API usage detected

Since no breaking changes are evident in the codebase usage patterns and the version bump is minor (1.0.0 to 1.0.4), this update appears to be safe.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for PortAudioSharp2 usage patterns that might be affected by the upgrade
rg -A 5 "PortAudioSharp" 

Length of output: 1380


Script:

#!/bin/bash
# Check the git history for changes in PortAudioSharp2 usage
git log -p -- Deepgram.Microphone/Microphone.cs | grep -A 10 -B 10 "PortAudioSharp"

# Look for any API usage patterns
ast-grep --pattern 'using PortAudioSharp;'
ast-grep --pattern 'new PortAudioSharp.Stream($$$)'

Length of output: 2300


Script:

#!/bin/bash
# Look for any documentation about version changes
fd README.md
fd CHANGELOG.md
fd HISTORY.md
fd RELEASES.md

# Check if there are any tests that might show API usage
fd test -e cs | xargs rg "PortAudioSharp"

Length of output: 155

Deepgram/Deepgram.csproj (2)

86-110: LGTM! Consistent package versions across frameworks.

The package versions are consistently maintained across net6.0 and net7.0 target frameworks, which is a good practice for dependency management.


146-148: LGTM! Serilog packages updated to latest stable versions.

The Serilog package updates are appropriate and align with the project's modernization goals.

.gitignore (4)

1-67: LGTM! Comprehensive core .NET ignores aligned with latest standards.

The core .NET and Visual Studio ignore patterns are up-to-date and comprehensive, including:

  • Latest patterns from dotnet new gitignore
  • Build outputs and temporary files
  • User-specific files
  • Essential security considerations for secrets (.env)

249-252: Review strong naming configuration.

The comment about strong name files (*.snk) presenting a security risk is noted. Given the PR's security focus:

✅ Verification successful

Strong name signing configuration is not actively used in this codebase

The codebase shows no evidence of using strong name key files (.snk) or strong naming configurations. The commented-out entry in .gitignore appears to be from a template and can be safely ignored since the feature is not in use.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if any .snk files exist in the repository
# Strong name keys should be managed securely
fd -e snk

Length of output: 103


Script:

#!/bin/bash
# Search for any references to .snk files in the codebase
rg -i "\.snk" -g "!.gitignore"

# Also check for strong naming related configurations in project files
rg -i "strongname|assemblykeypair|keyfile" -g "*.csproj" -g "*.config"

Length of output: 105


46-159: Verify test coverage tool configurations.

The coverage tool configurations are comprehensive, including support for multiple tools (NCrunch, AxoCover, Coverlet, OpenCover). However, given the PR's security focus:

✅ Verification successful

Coverage tool configurations in .gitignore are properly set

The .gitignore rules for coverage tools are working as intended. No coverage reports, test results, or related configuration files were found in the repository, confirming that the ignore patterns are effectively preventing these files from being committed. This helps maintain repository security by keeping implementation details private.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if any coverage reports are accidentally committed
# This helps prevent potential security issues from exposed implementation details
rg -l "\.coverage$|coverage\.(json|xml|info)$"

Length of output: 48


Script:

#!/bin/bash
# Let's verify if there are any coverage files in the repository despite the gitignore
fd -H ".*coverage.*\.(json|xml|info)$|\.coverage$"

# Also check if there are any build artifacts or test results that should be ignored
fd -H "TestResult\.xml|nunit-.*\.xml|\.VisualState\.xml"

# Check if the project actually uses any of these coverage tools by looking for config files
fd -H "\.axocover|\.ncrunch|coverlet\.runsettings|\.coveragerc"

Length of output: 177


201-214: Verify NuGet package security settings.

The NuGet ignore patterns are comprehensive. However, given the security advisory mentioned in the PR:

✅ Verification successful

NuGet security configuration appears to be properly maintained

The verification shows:

  • No NuGet.config files are present in the repository
  • No NuGet packages (*.nupkg, *.snupkg) are committed
  • Project files only contain standard PackageReference entries
  • No sensitive NuGet configurations or credentials are exposed

The .gitignore patterns are appropriate and working as intended.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for any committed NuGet config files that might contain credentials
rg -l "nuget\.config$"

Length of output: 103


Script:

#!/bin/bash
# Search for any NuGet config files with different casing
fd -i "nuget.config"

# Check for any NuGet package files that might have been committed
fd -e nupkg -e snupkg

# Look for potential NuGet related settings in project files
rg -l "PackageReference|RestoreSources|NuGetPackageRoot"

Length of output: 2496


Script:

#!/bin/bash
# Check project files for any NuGet source configurations
rg "RestoreSources|PackageSource" -A 2 -B 2

# Look for any potential credential or token configurations in project files
rg "ApiKey|Password|Token|Secret" --type=xml

Length of output: 241

Deepgram.sln (3)

4-11: LGTM: Core solution structure follows .NET conventions

The solution structure maintains the essential projects with proper GUID assignments and follows standard .NET conventions.


62-78: LGTM: Well-structured test organization

The test projects are well-organized with clear separation between:

  • Edge case tests
  • Expected failure scenarios
    This structure will help in maintaining test coverage and debugging.

88-228: LGTM: Standard build configurations

Build configurations are properly set up with both Debug and Release configurations for all projects.

using System;
using System.IO;
using System.Threading.Tasks;
using Deepgram;
using Deepgram.Models.Listen.v1.REST;

namespace PreRecorded
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Update namespace to match project structure.

The namespace PreRecorded should be changed to Deepgram.Examples.SpeechToText.Rest.Intent to follow .NET naming conventions and match the project structure.

-namespace PreRecorded
+namespace Deepgram.Examples.SpeechToText.Rest.Intent
📝 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
namespace PreRecorded
namespace Deepgram.Examples.SpeechToText.Rest.Intent

@@ -54,7 +59,7 @@ await liveClient.Subscribe(new EventHandler<ResultResponse>((sender, e) =>
while (liveClient.IsConnected())
{
byte[] buffer = new byte[2048];
await receiveStream.ReadAsync(buffer, 0, buffer.Length);
await receiveStream.ReadExactlyAsync(buffer);
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

⚠️ Potential issue

The context confirms the issues mentioned in the review comment. I can now provide the final response:

Critical: ReadExactlyAsync is unsuitable for streaming audio data

The current implementation in examples/Deepgram.Examples.SpeechToText.Websocket.Http/Program.cs has serious streaming issues:

  • Uses ReadExactlyAsync which blocks until exactly 2048 bytes are available
  • Sends the entire fixed buffer without accounting for partial reads
  • Will throw an exception on stream end
  • May cause indefinite blocking when streaming slows down

Suggested fix:

byte[] buffer = new byte[2048];
int bytesRead = await receiveStream.ReadAsync(buffer);
if (bytesRead > 0)
{
    liveClient.Send(buffer.AsSpan(0, bytesRead).ToArray());
}
🔗 Analysis chain

Critical: Replace ReadExactlyAsync with ReadAsync for streaming audio.

Using ReadExactlyAsync for streaming audio is problematic because:

  1. It blocks until exactly 2048 bytes are available, which may cause indefinite waiting
  2. It throws an exception if the stream ends before filling the buffer
  3. The fixed buffer size might not align with audio frames

Replace with a more appropriate streaming implementation:

-await receiveStream.ReadExactlyAsync(buffer);
+int bytesRead = await receiveStream.ReadAsync(buffer);
+if (bytesRead > 0)
+{
+    // Only send the actual bytes read
+    liveClient.Send(buffer.AsSpan(0, bytesRead).ToArray());
+}

Let's verify if this pattern is used consistently in other examples:


Let me gather more context about the streaming implementation to ensure a comprehensive verification.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for similar streaming patterns in other example files
rg -l "ReadExactlyAsync" examples/

Length of output: 100


Script:

#!/bin/bash
# Get the full context of the streaming implementation
rg -B 10 -A 10 "ReadExactlyAsync" examples/Deepgram.Examples.SpeechToText.Websocket.Http/Program.cs

Length of output: 935

Comment on lines +5 to 12
using System;
using System.Threading.Tasks;
using Deepgram;
using Deepgram.Logger;
using Deepgram.Models.Manage.v1;

namespace SampleApp
{
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Align namespace with folder structure to follow .NET conventions.

The namespace SampleApp doesn't match the project's folder structure. According to .NET conventions, the namespace should reflect the project's hierarchy.

-namespace SampleApp
+namespace Deepgram.Examples.Manage.Models
📝 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
using System;
using System.Threading.Tasks;
using Deepgram;
using Deepgram.Logger;
using Deepgram.Models.Manage.v1;
namespace SampleApp
{
using System;
using System.Threading.Tasks;
using Deepgram;
using Deepgram.Logger;
using Deepgram.Models.Manage.v1;
namespace Deepgram.Examples.Manage.Models
{

Comment on lines +13 to +15
public static class Program
{
static async Task Main(string[] args)
public static async Task Main(string[] args)
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Inconsistency found in Program class declarations across example projects

The ripgrep results show that while some example projects use public static class Program, others use just class Program. This inconsistency should be addressed for better maintainability. Here are the files that need to be updated to match the public static pattern:

  • examples/Deepgram.Examples.SpeechToText.Rest.Url/Program.cs
  • examples/Deepgram.Examples.SpeechToText.Rest.Topic/Program.cs
  • examples/Deepgram.Examples.TextToSpeech.Rest.File.WoodChuck/Program.cs
  • examples/Deepgram.Examples.TextToSpeech.Websocket.Simple/Program.cs
  • examples/Deepgram.Examples.SpeechToText.Websocket.Microphone/Program.cs
  • examples/Deepgram.Examples.TextToSpeech.Rest.File.HelloWorld/Program.cs
  • examples/Deepgram.Examples.SpeechToText.Websocket.File/Program.cs
  • examples/Deepgram.Examples.SpeechToText.Websocket.Http/Program.cs
  • examples/Deepgram.Examples.SpeechToText.Rest.Sentiment/Program.cs
  • examples/Deepgram.Examples.SpeechToText.Rest.Summary/Program.cs
  • examples/Deepgram.Examples.SpeechToText.Rest.File/Program.cs
  • examples/Deepgram.Examples.SpeechToText.Rest.Intent/Program.cs
  • examples/Deepgram.Examples.Manage.Usage/Program.cs
  • examples/Deepgram.Examples.Manage.Projects/Program.cs
  • examples/Deepgram.Examples.Manage.Scopes/Program.cs
  • examples/Deepgram.Examples.Manage.Invitations/Program.cs
  • examples/Deepgram.Examples.Manage.Keys/Program.cs
  • examples/Deepgram.Examples.Manage.Members/Program.cs
🔗 Analysis chain

Verify consistency across example projects.

Let's ensure the Program class modifications are consistent across all example projects.


Let me try again with the correct language specification for C# files.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check Program class declarations in all example projects
# Expect: All Program classes should be declared as public static

echo "Checking Program class declarations in example projects..."
ast-grep --pattern 'class Program' -l
ast-grep --pattern 'public static class Program'

echo -e "\nChecking Main method declarations..."
ast-grep --pattern 'Task Main(string[] args)'
ast-grep --pattern 'public static async Task Main(string[] args)'

Length of output: 528


Script:

#!/bin/bash
# Search for Program class declarations in C# files
echo "Checking Program class declarations in example projects..."
ast-grep --lang c-sharp --pattern 'class Program' -l
ast-grep --lang c-sharp --pattern 'public static class Program'

echo -e "\nChecking Main method declarations..."
ast-grep --lang c-sharp --pattern 'Task Main(string[] args)'
ast-grep --lang c-sharp --pattern 'public static async Task Main(string[] args)'

# Also use ripgrep as a backup to ensure we don't miss anything
echo -e "\nUsing ripgrep to verify..."
rg "class Program" --type cs -C 2
rg "Task Main\(string\[\] args\)" --type cs -C 2

Length of output: 29174

Comment on lines +72 to +82
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.*" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.*" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.*" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="6.*" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.2" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="8.0.10" />
<PackageReference Include="Polly.Contrib.WaitAndRetry" Version="1.1.1" />
<PackageReference Include="System.Text.Json" Version="6.*" />
<PackageReference Include="System.Threading.Channels" Version="6.*" />
<PackageReference Include="System.Text.Json" Version="8.0.5" />
<PackageReference Include="System.Threading.Channels" Version="8.0.0" />
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Centralize package references to reduce duplication.

The current structure duplicates package references across different framework conditions, which increases maintenance overhead and the risk of version inconsistencies.

Consider centralizing common packages in a single ItemGroup and only specify framework-specific versions where necessary:

- <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
-   <PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
-     <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
-     <PrivateAssets>all</PrivateAssets>
-   </PackageReference>
-   <!-- ... other duplicate references ... -->
- </ItemGroup>
- <!-- Similar ItemGroups for net6.0, net7.0 -->

+ <ItemGroup>
+   <PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
+     <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+     <PrivateAssets>all</PrivateAssets>
+   </PackageReference>
+   <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
+   <PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.1" />
+   <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.2" />
+   <PackageReference Include="Microsoft.Extensions.Http.Polly" Version="8.0.10" />
+   <PackageReference Include="Polly.Contrib.WaitAndRetry" Version="1.1.1" />
+   <PackageReference Include="System.Text.Json" Version="8.0.5" />
+   <PackageReference Include="System.Threading.Channels" Version="8.0.0" />
+ </ItemGroup>

+ <!-- Only keep framework-specific overrides if needed -->
+ <ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
+   <!-- Framework-specific versions -->
+ </ItemGroup>

Also applies to: 86-96, 100-110

Comment on lines +230 to +262
GlobalSection(NestedProjects) = preSolution
{BB208398-4B46-4DB5-B9E3-FAD1670A328D} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{D2B35409-FA31-4EAE-978B-BD32199D2341} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{6B4834B3-C9B4-47C3-8812-4743B26E42C9} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{4AF13653-3D33-4402-A68B-0E2C7591FC3C} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{E13D42EC-45D4-4493-B6D5-6FEEED12538A} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{D9480E28-9186-4F91-81C7-79CABCEDC990} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{736440F0-AC08-438E-BEBD-17E3B478DFCF} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{E9D90D83-9996-4B39-964D-A2F1DDEB2196} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{6C279B71-30A2-493C-82D8-1BE957E6F1FF} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{97616AC9-DFB6-443A-AA52-C8DB2CBA1265} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{FCBDF841-02AC-4C47-B6DE-CAAED5982E90} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{09903C4E-0FE6-4198-81D3-F4BD54E2F06B} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{AC8AB221-6623-4CEB-A12F-18F611B21566} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{5F6EF4BF-9322-4D0D-8E1D-EC4CE5AAF444} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{2F6288B7-7254-43A1-AEFF-8B0649230CAB} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{B820741C-6DE8-4AEB-B086-10AB4BA9E7AD} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{A23B61B4-A0D3-42F1-8923-F8BF9A9ED31D} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{E9A120AA-9F07-44E5-953B-FC3CEDACDB37} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{EE8BF074-539B-4573-A2BF-4C6A3F1D3956} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{07331F62-8816-4860-8674-02CCEDF8E58F} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{F5DB1ABF-429B-4406-BC3A-2A6BB7B14264} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{C02BE4D8-0F98-45B0-B66C-0795DA2ED44C} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{079D4774-A3F6-48E4-AE31-E117430CD12C} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{7000E1D8-BA6D-473C-B2FE-D835B0F42906} = {EB85CC21-9BCC-4265-96CC-655A17ADF86D}
{1D0FBABE-6E50-4F02-996A-FFA0E63EE7E7} = {1A015F52-9174-4A15-8C77-C8AA153DCC5F}
{176F3607-9F53-4B4C-A6EB-70C6F5D3C884} = {1A015F52-9174-4A15-8C77-C8AA153DCC5F}
{2A1A1FC9-24A5-4FA9-84F2-2B3B578FE081} = {1A015F52-9174-4A15-8C77-C8AA153DCC5F}
{5FECDC3C-1D9F-437D-A212-5187D692E880} = {1A015F52-9174-4A15-8C77-C8AA153DCC5F}
{020AD025-F982-4703-931C-3A949B005854} = {1A015F52-9174-4A15-8C77-C8AA153DCC5F}
{4637C7EE-AF14-425A-BD1E-F5150B0A8845} = {1A015F52-9174-4A15-8C77-C8AA153DCC5F}
{D5F73F1F-D140-45A8-9E55-9F3C1F7D1F5C} = {1A015F52-9174-4A15-8C77-C8AA153DCC5F}
{1CA0AFF4-7985-4F51-8F35-7FD9C458F2D5} = {1A015F52-9174-4A15-8C77-C8AA153DCC5F}
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Missing project files in solution

The solution file references multiple .csproj files that are missing from the repository. This indicates a potential issue with project organization or missing files.

  • Main projects missing:

    • Deepgram.Microphone/Deepgram.Microphone.csproj
    • Deepgram.Tests/Deepgram.Tests.csproj
    • Deepgram/Deepgram.csproj
  • All example projects under examples/ directory are missing

  • All test projects under tests/ directory are missing

🔗 Analysis chain

Verify project paths exist

The nested project structure looks good, but let's verify that all project paths exist in the repository.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that all project paths exist

# Test: Check if all .csproj files exist
echo "Checking project files..."
while IFS= read -r line; do
  if [[ $line =~ \.csproj\" ]]; then
    # Extract path from: Project(...) = "Name", "Path", "{GUID}"
    path=$(echo "$line" | sed -n 's/.*"\([^"]*\.csproj\)".*/\1/p')
    if [ ! -z "$path" ]; then
      if [ ! -f "$path" ]; then
        echo "Missing project: $path"
      fi
    fi
  fi
done < Deepgram.sln

Length of output: 64649

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