feat: start rewriting as tauri app
44
.gitignore
vendored
@ -1,2 +1,42 @@
|
|||||||
/bin
|
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
/obj
|
|
||||||
|
# Compiled output
|
||||||
|
/dist
|
||||||
|
/tmp
|
||||||
|
/out-tsc
|
||||||
|
/bazel-out
|
||||||
|
|
||||||
|
# Node
|
||||||
|
/node_modules
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
.idea/
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# Visual Studio Code
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.history/*
|
||||||
|
|
||||||
|
# Miscellaneous
|
||||||
|
/.angular/cache
|
||||||
|
.sass-cache/
|
||||||
|
/connect.lock
|
||||||
|
/coverage
|
||||||
|
/libpeerconnection.log
|
||||||
|
testem.log
|
||||||
|
/typings
|
||||||
|
|
||||||
|
# System files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
15
App.axaml
@ -1,15 +0,0 @@
|
|||||||
<Application
|
|
||||||
x:Class="app.App"
|
|
||||||
xmlns="https://github.com/avaloniaui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:local="using:app"
|
|
||||||
RequestedThemeVariant="Dark">
|
|
||||||
|
|
||||||
<Application.DataTemplates>
|
|
||||||
<local:ViewLocator />
|
|
||||||
</Application.DataTemplates>
|
|
||||||
|
|
||||||
<Application.Styles>
|
|
||||||
<FluentTheme />
|
|
||||||
</Application.Styles>
|
|
||||||
</Application>
|
|
47
App.axaml.cs
@ -1,47 +0,0 @@
|
|||||||
using Avalonia;
|
|
||||||
using Avalonia.Controls.ApplicationLifetimes;
|
|
||||||
using Avalonia.Data.Core;
|
|
||||||
using Avalonia.Data.Core.Plugins;
|
|
||||||
using System.Linq;
|
|
||||||
using Avalonia.Markup.Xaml;
|
|
||||||
using app.ViewModels;
|
|
||||||
using app.Views;
|
|
||||||
|
|
||||||
namespace app;
|
|
||||||
|
|
||||||
public partial class App : Application
|
|
||||||
{
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
AvaloniaXamlLoader.Load(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnFrameworkInitializationCompleted()
|
|
||||||
{
|
|
||||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
|
||||||
{
|
|
||||||
// Avoid duplicate validations from both Avalonia and the CommunityToolkit.
|
|
||||||
// More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
|
|
||||||
DisableAvaloniaDataAnnotationValidation();
|
|
||||||
desktop.MainWindow = new MainWindow
|
|
||||||
{
|
|
||||||
DataContext = new MainWindowViewModel(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
base.OnFrameworkInitializationCompleted();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void DisableAvaloniaDataAnnotationValidation()
|
|
||||||
{
|
|
||||||
// Get an array of plugins to remove
|
|
||||||
var dataValidationPluginsToRemove =
|
|
||||||
BindingPlugins.DataValidators.OfType<DataAnnotationsValidationPlugin>().ToArray();
|
|
||||||
|
|
||||||
// remove each entry found
|
|
||||||
foreach (var plugin in dataValidationPluginsToRemove)
|
|
||||||
{
|
|
||||||
BindingPlugins.DataValidators.Remove(plugin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 172 KiB |
@ -1,9 +0,0 @@
|
|||||||
namespace app.Models;
|
|
||||||
|
|
||||||
public class ConfigModel
|
|
||||||
{
|
|
||||||
public string ApiKey { get; set; } = "";
|
|
||||||
public string SpeakModel { get; set; } = "aura-athena-en";
|
|
||||||
public string ListenModel { get; set; } = "nova-2";
|
|
||||||
public string ThinkModel { get; set; } = "claude-3-haiku-20240307";
|
|
||||||
}
|
|
21
Program.cs
@ -1,21 +0,0 @@
|
|||||||
using Avalonia;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace app;
|
|
||||||
|
|
||||||
sealed class Program
|
|
||||||
{
|
|
||||||
// Initialization code. Don't use any Avalonia, third-party APIs or any
|
|
||||||
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
|
||||||
// yet and stuff might break.
|
|
||||||
[STAThread]
|
|
||||||
public static void Main(string[] args) => BuildAvaloniaApp()
|
|
||||||
.StartWithClassicDesktopLifetime(args);
|
|
||||||
|
|
||||||
// Avalonia configuration, don't remove; also used by visual designer.
|
|
||||||
public static AppBuilder BuildAvaloniaApp()
|
|
||||||
=> AppBuilder.Configure<App>()
|
|
||||||
.UsePlatformDetect()
|
|
||||||
.WithInterFont()
|
|
||||||
.LogToTrace();
|
|
||||||
}
|
|
7
README.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Tauri + Angular
|
||||||
|
|
||||||
|
This template should help get you started developing with Tauri and Angular.
|
||||||
|
|
||||||
|
## Recommended IDE Setup
|
||||||
|
|
||||||
|
[VS Code](https://code.visualstudio.com/) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer) + [Angular Language Service](https://marketplace.visualstudio.com/items?itemName=Angular.ng-template).
|
@ -1,31 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.Controls.Templates;
|
|
||||||
using app.ViewModels;
|
|
||||||
|
|
||||||
namespace app;
|
|
||||||
|
|
||||||
public class ViewLocator : IDataTemplate
|
|
||||||
{
|
|
||||||
|
|
||||||
public Control? Build(object? param)
|
|
||||||
{
|
|
||||||
if (param is null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
|
|
||||||
var type = Type.GetType(name);
|
|
||||||
|
|
||||||
if (type != null)
|
|
||||||
{
|
|
||||||
return (Control)Activator.CreateInstance(type)!;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new TextBlock { Text = "Not Found: " + name };
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Match(object? data)
|
|
||||||
{
|
|
||||||
return data is ViewModelBase;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
namespace app.ViewModels;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text.Json;
|
|
||||||
using app.Models;
|
|
||||||
|
|
||||||
public partial class AgentWindowViewModel : ViewModelBase
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
namespace app.ViewModels;
|
|
||||||
|
|
||||||
using Avalonia.Interactivity;
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text.Json;
|
|
||||||
using app.Models;
|
|
||||||
|
|
||||||
public partial class ConfigWindowViewModel : ViewModelBase
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
namespace app.ViewModels;
|
|
||||||
|
|
||||||
public partial class HomeWindowViewModel : ViewModelBase
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,144 +0,0 @@
|
|||||||
namespace app.ViewModels;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Net.WebSockets;
|
|
||||||
using Avalonia.Controls;
|
|
||||||
using app.Models;
|
|
||||||
using app.Views;
|
|
||||||
|
|
||||||
public partial class MainWindowViewModel : ViewModelBase
|
|
||||||
{
|
|
||||||
private UserControl _currentView;
|
|
||||||
public UserControl CurrentView
|
|
||||||
{
|
|
||||||
get => _currentView;
|
|
||||||
set => SetProperty(ref _currentView, value);
|
|
||||||
}
|
|
||||||
private ConfigModel config { get; set; }
|
|
||||||
private ClientWebSocket ws { get; set; }
|
|
||||||
public string ActionButtonText { get; set; } = "Start Conversation";
|
|
||||||
public string ApiKey { get; set; }
|
|
||||||
public string SpeakModel { get; set; }
|
|
||||||
public string ListenModel { get; set; }
|
|
||||||
public string ThinkModel { get; set; }
|
|
||||||
public List<string> SpeakModels { get; } = new()
|
|
||||||
{
|
|
||||||
"aura-asteria-en", "aura-luna-en", "aura-athena-en", "aura-stella-en",
|
|
||||||
"aura-hera-en", "aura-orion-en", "aura-arcas-en", "aura-perseus-en",
|
|
||||||
"aura-angus-en", "aura-orpheus-en", "aura-helios-en", "aura-zeus-en"
|
|
||||||
};
|
|
||||||
|
|
||||||
public List<string> ListenModels { get; } = new()
|
|
||||||
{
|
|
||||||
"nova-2", "nova-2-meeting", "nova-2-phonecall", "nova-2-finance",
|
|
||||||
"nova-2-conversationalai", "nova-2-finance", "nova-2-voicemail",
|
|
||||||
"nova-2-video", "nova-2-medical", "nova-2-drivethru", "nova-2-automotive",
|
|
||||||
"nova-2-atc", "nova", "nova-phonecall", "nova-medical", "enhanced",
|
|
||||||
"enhanced-phonecall", "enhanced-meeting", "enhanced-finance", "base",
|
|
||||||
"base-phonecall", "base-meeting", "base-finance", "base-conversationalai",
|
|
||||||
"base-voicemail", "base-video", "whisper-tiny", "whisper-small",
|
|
||||||
"whisper-medium", "whisper-large", "whisper-base"
|
|
||||||
};
|
|
||||||
|
|
||||||
public List<string> ThinkModels { get; } = new()
|
|
||||||
{
|
|
||||||
"gpt-4o-mini", "claude-3-haiku-20240307"
|
|
||||||
};
|
|
||||||
|
|
||||||
public MainWindowViewModel()
|
|
||||||
{
|
|
||||||
ws = new();
|
|
||||||
config = GetConfig();
|
|
||||||
ApiKey = config.ApiKey;
|
|
||||||
SpeakModel = config.SpeakModel;
|
|
||||||
ListenModel = config.ListenModel;
|
|
||||||
ThinkModel = config.ThinkModel;
|
|
||||||
if (string.IsNullOrEmpty(config.ApiKey))
|
|
||||||
{
|
|
||||||
CurrentView = new ConfigWindow();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
CurrentView = new HomeWindow();
|
|
||||||
}
|
|
||||||
private static string ConfigPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/.config/deepgram-voice-assistant";
|
|
||||||
private static string ConfigFilePath = ConfigPath + "/config.json";
|
|
||||||
private static ConfigModel GetConfig()
|
|
||||||
{
|
|
||||||
// if config directory does not exist, create it
|
|
||||||
if (!Directory.Exists(ConfigPath))
|
|
||||||
{
|
|
||||||
Console.WriteLine("Creating config directory");
|
|
||||||
Directory.CreateDirectory(ConfigPath);
|
|
||||||
}
|
|
||||||
// check if file exists
|
|
||||||
if (!File.Exists(ConfigFilePath))
|
|
||||||
{
|
|
||||||
// create file too
|
|
||||||
Console.WriteLine("Creating config file");
|
|
||||||
using FileStream fs = File.Create(ConfigFilePath);
|
|
||||||
fs.Close();
|
|
||||||
// write default config
|
|
||||||
Console.WriteLine("Writing default config");
|
|
||||||
using StreamWriter writer = new(ConfigFilePath);
|
|
||||||
writer.WriteLine("{\n\t\"apiKey\": \"\",\n\t\"speakModel\": \"aura-athena-en\",\n\t\"listenModel\": \"nova-2\",\n\t\"thinkModel\": \"claude-3-haiku-20240307\"\n}");
|
|
||||||
writer.Close();
|
|
||||||
}
|
|
||||||
// Read the config file
|
|
||||||
using StreamReader reader = new(ConfigFilePath);
|
|
||||||
string json = reader.ReadToEnd();
|
|
||||||
reader.Close();
|
|
||||||
return JsonSerializer.Deserialize<ConfigModel>(json);
|
|
||||||
}
|
|
||||||
private static void UpdateConfig(ConfigModel config)
|
|
||||||
{
|
|
||||||
// Write the config file
|
|
||||||
using StreamWriter writer = new(ConfigFilePath);
|
|
||||||
writer.WriteLine(JsonSerializer.Serialize(config));
|
|
||||||
writer.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SaveConfig()
|
|
||||||
{
|
|
||||||
string speakModel = SpeakModel;
|
|
||||||
string listenModel = ListenModel;
|
|
||||||
string thinkModel = ThinkModel;
|
|
||||||
Console.WriteLine("Saving config");
|
|
||||||
Console.WriteLine("ApiKey: " + ApiKey);
|
|
||||||
Console.WriteLine("SpeakModel: " + speakModel);
|
|
||||||
Console.WriteLine("ListenModel: " + listenModel);
|
|
||||||
Console.WriteLine("ThinkModel: " + thinkModel);
|
|
||||||
config = new()
|
|
||||||
{
|
|
||||||
ApiKey = ApiKey,
|
|
||||||
SpeakModel = speakModel,
|
|
||||||
ListenModel = listenModel,
|
|
||||||
ThinkModel = thinkModel
|
|
||||||
};
|
|
||||||
UpdateConfig(config);
|
|
||||||
CurrentView = new HomeWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OpenConfig()
|
|
||||||
{
|
|
||||||
CurrentView = new ConfigWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CancelConfig() {
|
|
||||||
CurrentView = new HomeWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task StartAgent() {
|
|
||||||
// ws.Options.SetRequestHeader("Authorization", "token " + config.ApiKey);
|
|
||||||
// await ws.ConnectAsync(new Uri("wss://agent.deepgram.com/agent"), System.Threading.CancellationToken.None);
|
|
||||||
CurrentView = new AgentWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task EndConversation() {
|
|
||||||
CurrentView = new HomeWindow();
|
|
||||||
// await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "Conversation ended", System.Threading.CancellationToken.None);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
|
||||||
|
|
||||||
namespace app.ViewModels;
|
|
||||||
|
|
||||||
public class ViewModelBase : ObservableObject
|
|
||||||
{
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
<UserControl xmlns="https://github.com/avaloniaui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:vm="using:app.ViewModels"
|
|
||||||
x:DataType="vm:MainWindowViewModel"
|
|
||||||
x:Class="app.Views.AgentWindow">
|
|
||||||
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
|
|
||||||
<TextBlock Text="Deepgram Voice Agent" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
|
||||||
<Grid ShowGridLines="False" Margin="5" ColumnDefinitions="Auto, Auto" RowDefinitions="Auto, Auto, Auto, Auto">
|
|
||||||
<Button Grid.Row="0" Grid.Column="0" Background="Red" CornerRadius="10" Command="{Binding EndConversation}">End Conversation</Button>
|
|
||||||
</Grid>
|
|
||||||
</StackPanel>
|
|
||||||
</UserControl>
|
|
@ -1,13 +0,0 @@
|
|||||||
using Avalonia.Controls;
|
|
||||||
using app.Models;
|
|
||||||
using app.ViewModels;
|
|
||||||
|
|
||||||
namespace app.Views;
|
|
||||||
|
|
||||||
public partial class AgentWindow : UserControl
|
|
||||||
{
|
|
||||||
public AgentWindow()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
<UserControl xmlns="https://github.com/avaloniaui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:vm="using:app.ViewModels"
|
|
||||||
x:DataType="vm:MainWindowViewModel"
|
|
||||||
x:Class="app.Views.ConfigWindow">
|
|
||||||
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
|
|
||||||
<TextBlock Text="Configure your application!" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
|
||||||
<Grid ShowGridLines="False" Margin="5" ColumnDefinitions="Auto, Auto" RowDefinitions="Auto, Auto, Auto, Auto">
|
|
||||||
<Label Grid.Row="0" Grid.Column="0">API Key:</Label>
|
|
||||||
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding ApiKey, Mode=TwoWay}"/>
|
|
||||||
<Label Grid.Row="1" Grid.Column="0">Speak Model</Label>
|
|
||||||
<ComboBox Grid.Row="1" Grid.Column="1" SelectedItem="{Binding SpeakModel, Mode=TwoWay}" ItemsSource="{Binding SpeakModels}">
|
|
||||||
</ComboBox>
|
|
||||||
<Label Grid.Row="2" Grid.Column="0">Listen Model:</Label>
|
|
||||||
<ComboBox Grid.Row="2" Grid.Column="1" SelectedIndex="0" SelectedItem="{Binding ListenModel, Mode=TwoWay}" ItemsSource="{Binding ListenModels}">
|
|
||||||
</ComboBox>
|
|
||||||
<Label Grid.Row="3" Grid.Column="0">Think Model:</Label>
|
|
||||||
<ComboBox Grid.Row="3" Grid.Column="1" SelectedIndex="0" SelectedItem="{Binding ThinkModel, Mode=TwoWay}" ItemsSource="{Binding ThinkModels}">
|
|
||||||
</ComboBox>
|
|
||||||
</Grid>
|
|
||||||
<Grid ShowGridLines="False" Margin="5" ColumnDefinitions="Auto, Auto" RowDefinitions="Auto">
|
|
||||||
<Button Grid.Row="0" Grid.Column="0" CornerRadius="10" Background="Blue" Command="{Binding SaveConfig}">Save</Button>
|
|
||||||
<Button Grid.Row="0" Grid.Column="1" CornerRadius="10" Foreground="Black" Background="Yellow" Command="{Binding CancelConfig}" IsVisible="{Binding ApiKey}">Cancel</Button>
|
|
||||||
</Grid>
|
|
||||||
</StackPanel>
|
|
||||||
</UserControl>
|
|
@ -1,12 +0,0 @@
|
|||||||
using Avalonia.Controls;
|
|
||||||
|
|
||||||
namespace app.Views;
|
|
||||||
|
|
||||||
public partial class ConfigWindow : UserControl
|
|
||||||
{
|
|
||||||
|
|
||||||
public ConfigWindow()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
<UserControl xmlns="https://github.com/avaloniaui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:vm="using:app.ViewModels"
|
|
||||||
x:DataType="vm:MainWindowViewModel"
|
|
||||||
x:Class="app.Views.HomeWindow">
|
|
||||||
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
|
|
||||||
<TextBlock Text="Deepgram Voice Agent" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
|
||||||
<Grid ShowGridLines="False" Margin="5" ColumnDefinitions="Auto, Auto" RowDefinitions="Auto">
|
|
||||||
<Button Grid.Row="0" Grid.Column="0" CornerRadius="10" Background="Green" Command="{Binding StartAgent}">Start Agent</Button>
|
|
||||||
<Button Grid.Row="0" Grid.Column="1" CornerRadius="10" Foreground="Black" Background="Yellow" Command="{Binding OpenConfig}">Edit Configuration</Button>
|
|
||||||
</Grid>
|
|
||||||
</StackPanel>
|
|
||||||
</UserControl>
|
|
@ -1,11 +0,0 @@
|
|||||||
using Avalonia.Controls;
|
|
||||||
|
|
||||||
namespace app.Views;
|
|
||||||
|
|
||||||
public partial class HomeWindow : UserControl
|
|
||||||
{
|
|
||||||
public HomeWindow()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
<Window xmlns="https://github.com/avaloniaui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:vm="using:app.ViewModels"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
|
||||||
x:Class="app.Views.MainWindow"
|
|
||||||
x:DataType="vm:MainWindowViewModel"
|
|
||||||
Icon="/Assets/avalonia-logo.ico"
|
|
||||||
Title="Deepgram Voice Assistant">
|
|
||||||
|
|
||||||
<Design.DataContext>
|
|
||||||
<!-- This only sets the DataContext for the previewer in an IDE,
|
|
||||||
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
|
|
||||||
<vm:MainWindowViewModel/>
|
|
||||||
</Design.DataContext>
|
|
||||||
|
|
||||||
<ContentControl Content="{Binding CurrentView}"/>
|
|
||||||
|
|
||||||
</Window>
|
|
@ -1,12 +0,0 @@
|
|||||||
using Avalonia.Controls;
|
|
||||||
|
|
||||||
namespace app.Views;
|
|
||||||
|
|
||||||
public partial class MainWindow : Window
|
|
||||||
{
|
|
||||||
|
|
||||||
public MainWindow()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
}
|
|
67
angular.json
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
{
|
||||||
|
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||||
|
"version": 1,
|
||||||
|
"newProjectRoot": "projects",
|
||||||
|
"cli": {
|
||||||
|
"analytics": false
|
||||||
|
},
|
||||||
|
"projects": {
|
||||||
|
"deepgram-voice-assistant": {
|
||||||
|
"projectType": "application",
|
||||||
|
"root": "",
|
||||||
|
"sourceRoot": "src",
|
||||||
|
"prefix": "app",
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-angular:application",
|
||||||
|
"options": {
|
||||||
|
"outputPath": "dist/deepgram-voice-assistant",
|
||||||
|
"index": "src/index.html",
|
||||||
|
"browser": "src/main.ts",
|
||||||
|
"polyfills": ["zone.js"],
|
||||||
|
"tsConfig": "tsconfig.app.json",
|
||||||
|
"assets": ["src/assets"]
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"budgets": [
|
||||||
|
{
|
||||||
|
"type": "initial",
|
||||||
|
"maximumWarning": "500kb",
|
||||||
|
"maximumError": "1mb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "anyComponentStyle",
|
||||||
|
"maximumWarning": "2kb",
|
||||||
|
"maximumError": "4kb"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputHashing": "all"
|
||||||
|
},
|
||||||
|
"development": {
|
||||||
|
"optimization": false,
|
||||||
|
"extractLicenses": false,
|
||||||
|
"sourceMap": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultConfiguration": "production"
|
||||||
|
},
|
||||||
|
"serve": {
|
||||||
|
"builder": "@angular-devkit/build-angular:dev-server",
|
||||||
|
"options": {
|
||||||
|
"port": 1420
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"buildTarget": "deepgram-voice-assistant:build:production"
|
||||||
|
},
|
||||||
|
"development": {
|
||||||
|
"buildTarget": "deepgram-voice-assistant:build:development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultConfiguration": "development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
app.csproj
@ -1,28 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>WinExe</OutputType>
|
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
|
||||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
|
||||||
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Models\" />
|
|
||||||
<AvaloniaResource Include="Assets\**" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Avalonia" Version="11.2.1" />
|
|
||||||
<PackageReference Include="Avalonia.Desktop" Version="11.2.1" />
|
|
||||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.1" />
|
|
||||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.1" />
|
|
||||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
|
||||||
<PackageReference Include="Avalonia.Diagnostics" Version="11.2.1">
|
|
||||||
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
|
|
||||||
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
18
app.manifest
@ -1,18 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<!-- This manifest is used on Windows only.
|
|
||||||
Don't remove it as it might cause problems with window transparency and embedded controls.
|
|
||||||
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
|
|
||||||
<assemblyIdentity version="1.0.0.0" name="app.Desktop"/>
|
|
||||||
|
|
||||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
|
||||||
<application>
|
|
||||||
<!-- A list of the Windows versions that this application has been tested on
|
|
||||||
and is designed to work with. Uncomment the appropriate elements
|
|
||||||
and Windows will automatically select the most compatible environment. -->
|
|
||||||
|
|
||||||
<!-- Windows 10 -->
|
|
||||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
|
||||||
</application>
|
|
||||||
</compatibility>
|
|
||||||
</assembly>
|
|
7
deepgram-voice-assistant/.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"tauri-apps.tauri-vscode",
|
||||||
|
"rust-lang.rust-analyzer",
|
||||||
|
"angular.ng-template"
|
||||||
|
]
|
||||||
|
}
|
5
eslint.config.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import NaomisConfig from "@nhcarrigan/eslint-config";
|
||||||
|
|
||||||
|
export default [
|
||||||
|
...NaomisConfig
|
||||||
|
];
|
@ -1,24 +0,0 @@
|
|||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio Version 17
|
|
||||||
VisualStudioVersion = 17.5.2.0
|
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "app", "app.csproj", "{4195E981-2360-7259-32C6-BB2CA129A715}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|Any CPU = Debug|Any CPU
|
|
||||||
Release|Any CPU = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{4195E981-2360-7259-32C6-BB2CA129A715}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{4195E981-2360-7259-32C6-BB2CA129A715}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{4195E981-2360-7259-32C6-BB2CA129A715}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{4195E981-2360-7259-32C6-BB2CA129A715}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
|
||||||
SolutionGuid = {7CAB8223-BDA9-44EA-9FB2-675BF9E2D383}
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
45
package.json
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"name": "deepgram-voice-assistant",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"scripts": {
|
||||||
|
"ng": "ng",
|
||||||
|
"start": "ng serve",
|
||||||
|
"build": "ng build",
|
||||||
|
"watch": "ng build --watch --configuration development",
|
||||||
|
"tauri": "tauri"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@angular/animations": "^19.1.4",
|
||||||
|
"@angular/common": "^19.1.4",
|
||||||
|
"@angular/compiler": "^19.1.4",
|
||||||
|
"@angular/core": "^19.1.4",
|
||||||
|
"@angular/forms": "^19.1.4",
|
||||||
|
"@angular/platform-browser": "^19.1.4",
|
||||||
|
"@angular/platform-browser-dynamic": "^19.1.4",
|
||||||
|
"@angular/router": "^19.1.4",
|
||||||
|
"@tauri-apps/api": "^2",
|
||||||
|
"@tauri-apps/plugin-opener": "^2",
|
||||||
|
"rxjs": "~7.8.1",
|
||||||
|
"tslib": "^2.8.1",
|
||||||
|
"zone.js": "~0.15.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@angular-devkit/build-angular": "^19.1.5",
|
||||||
|
"@angular/cli": "^19.1.5",
|
||||||
|
"@angular/compiler-cli": "^19.1.4",
|
||||||
|
"@nhcarrigan/eslint-config": "5.1.0",
|
||||||
|
"@nhcarrigan/typescript-config": "4.0.0",
|
||||||
|
"@tauri-apps/cli": "^2",
|
||||||
|
"@types/jasmine": "~5.1.5",
|
||||||
|
"@types/node": "22.13.1",
|
||||||
|
"eslint": "9.19.0",
|
||||||
|
"jasmine-core": "~5.5.0",
|
||||||
|
"karma": "~6.4.4",
|
||||||
|
"karma-chrome-launcher": "~3.2.0",
|
||||||
|
"karma-coverage": "~2.2.1",
|
||||||
|
"karma-jasmine": "~5.1.0",
|
||||||
|
"karma-jasmine-html-reporter": "~2.1.0",
|
||||||
|
"typescript": "~5.7.3"
|
||||||
|
}
|
||||||
|
}
|
11570
pnpm-lock.yaml
generated
Normal file
7
src-tauri/.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Generated by Cargo
|
||||||
|
# will have compiled files and executables
|
||||||
|
/target/
|
||||||
|
|
||||||
|
# Generated by Tauri
|
||||||
|
# will have schema files for capabilities auto-completion
|
||||||
|
/gen/schemas
|
5433
src-tauri/Cargo.lock
generated
Normal file
25
src-tauri/Cargo.toml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
[package]
|
||||||
|
name = "deepgram-voice-assistant"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "A Tauri App"
|
||||||
|
authors = ["you"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
# The `_lib` suffix may seem redundant but it is necessary
|
||||||
|
# to make the lib name unique and wouldn't conflict with the bin name.
|
||||||
|
# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
|
||||||
|
name = "deepgram_voice_assistant_lib"
|
||||||
|
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
tauri-build = { version = "2", features = [] }
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
tauri = { version = "2", features = [] }
|
||||||
|
tauri-plugin-opener = "2"
|
||||||
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
serde_json = "1"
|
||||||
|
|
3
src-tauri/build.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
tauri_build::build()
|
||||||
|
}
|
10
src-tauri/capabilities/default.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"$schema": "../gen/schemas/desktop-schema.json",
|
||||||
|
"identifier": "default",
|
||||||
|
"description": "Capability for the main window",
|
||||||
|
"windows": ["main"],
|
||||||
|
"permissions": [
|
||||||
|
"core:default",
|
||||||
|
"opener:default"
|
||||||
|
]
|
||||||
|
}
|
BIN
src-tauri/icons/128x128.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
src-tauri/icons/128x128@2x.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
src-tauri/icons/32x32.png
Normal file
After Width: | Height: | Size: 974 B |
BIN
src-tauri/icons/Square107x107Logo.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
src-tauri/icons/Square142x142Logo.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
src-tauri/icons/Square150x150Logo.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
src-tauri/icons/Square284x284Logo.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
src-tauri/icons/Square30x30Logo.png
Normal file
After Width: | Height: | Size: 903 B |
BIN
src-tauri/icons/Square310x310Logo.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
src-tauri/icons/Square44x44Logo.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
src-tauri/icons/Square71x71Logo.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
src-tauri/icons/Square89x89Logo.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
src-tauri/icons/StoreLogo.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
src-tauri/icons/icon.icns
Normal file
BIN
src-tauri/icons/icon.ico
Normal file
After Width: | Height: | Size: 85 KiB |
BIN
src-tauri/icons/icon.png
Normal file
After Width: | Height: | Size: 14 KiB |
14
src-tauri/src/lib.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
|
||||||
|
#[tauri::command]
|
||||||
|
fn greet(name: &str) -> String {
|
||||||
|
format!("Hello, {}! You've been greeted from Rust!", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
|
pub fn run() {
|
||||||
|
tauri::Builder::default()
|
||||||
|
.plugin(tauri_plugin_opener::init())
|
||||||
|
.invoke_handler(tauri::generate_handler![greet])
|
||||||
|
.run(tauri::generate_context!())
|
||||||
|
.expect("error while running tauri application");
|
||||||
|
}
|
6
src-tauri/src/main.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
||||||
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
deepgram_voice_assistant_lib::run()
|
||||||
|
}
|
35
src-tauri/tauri.conf.json
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
|
"productName": "deepgram-voice-assistant",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"identifier": "com.deepgram-voice-assistant.app",
|
||||||
|
"build": {
|
||||||
|
"beforeDevCommand": "pnpm start",
|
||||||
|
"devUrl": "http://localhost:1420",
|
||||||
|
"beforeBuildCommand": "pnpm build",
|
||||||
|
"frontendDist": "../dist/deepgram-voice-assistant/browser"
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"windows": [
|
||||||
|
{
|
||||||
|
"title": "deepgram-voice-assistant",
|
||||||
|
"width": 800,
|
||||||
|
"height": 600
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"security": {
|
||||||
|
"csp": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bundle": {
|
||||||
|
"active": true,
|
||||||
|
"targets": "all",
|
||||||
|
"icon": [
|
||||||
|
"icons/32x32.png",
|
||||||
|
"icons/128x128.png",
|
||||||
|
"icons/128x128@2x.png",
|
||||||
|
"icons/icon.icns",
|
||||||
|
"icons/icon.ico"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
0
src/app/agent/agent.component.css
Normal file
1
src/app/agent/agent.component.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
<p>agent works!</p>
|
23
src/app/agent/agent.component.spec.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AgentComponent } from './agent.component';
|
||||||
|
|
||||||
|
describe('AgentComponent', () => {
|
||||||
|
let component: AgentComponent;
|
||||||
|
let fixture: ComponentFixture<AgentComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [AgentComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(AgentComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
12
src/app/agent/agent.component.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-agent',
|
||||||
|
standalone: true,
|
||||||
|
imports: [],
|
||||||
|
templateUrl: './agent.component.html',
|
||||||
|
styleUrl: './agent.component.css'
|
||||||
|
})
|
||||||
|
export class AgentComponent {
|
||||||
|
|
||||||
|
}
|
32
src/app/app.component.css
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
:root {
|
||||||
|
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
font-weight: 400;
|
||||||
|
font-synthesis: none;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
text-align: center;
|
||||||
|
color: #ffffff;
|
||||||
|
background: #000000;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
3
src/app/app.component.html
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<main>
|
||||||
|
<router-outlet></router-outlet>
|
||||||
|
</main>
|
14
src/app/app.component.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { RouterOutlet } from '@angular/router';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-root',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule, RouterOutlet],
|
||||||
|
templateUrl: './app.component.html',
|
||||||
|
styleUrl: './app.component.css'
|
||||||
|
})
|
||||||
|
export class AppComponent {
|
||||||
|
|
||||||
|
}
|
8
src/app/app.config.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { ApplicationConfig } from "@angular/core";
|
||||||
|
import { provideRouter } from "@angular/router";
|
||||||
|
|
||||||
|
import { routes } from "./app.routes";
|
||||||
|
|
||||||
|
export const appConfig: ApplicationConfig = {
|
||||||
|
providers: [provideRouter(routes)],
|
||||||
|
};
|
10
src/app/app.routes.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { Routes } from "@angular/router";
|
||||||
|
import { HomeComponent } from "./home/home.component";
|
||||||
|
import { ConfigComponent } from "./config/config.component";
|
||||||
|
import { AgentComponent } from "./agent/agent.component";
|
||||||
|
|
||||||
|
export const routes: Routes = [
|
||||||
|
{ path: "", pathMatch: "full", component: HomeComponent },
|
||||||
|
{ path: "config", component: ConfigComponent },
|
||||||
|
{ path: "agent", component: AgentComponent }
|
||||||
|
];
|
16
src/app/config.service.spec.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ConfigService } from '../../../../../.config/emacs/backups/!home!naomi!code!deepgram!deepgram-voice-assistant!src!app!config.service.ts~';
|
||||||
|
|
||||||
|
describe('ConfigService', () => {
|
||||||
|
let service: ConfigService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(ConfigService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
19
src/app/config.service.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Config } from "./interfaces/Config";
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class ConfigService {
|
||||||
|
public getConfig(): Config | null {
|
||||||
|
const config = localStorage.getItem("config");
|
||||||
|
if (!config) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return JSON.parse(config) as Config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setConfig(config: Config) {
|
||||||
|
localStorage.setItem("config", JSON.stringify(config));
|
||||||
|
}
|
||||||
|
}
|
22
src/app/config/config.component.css
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
form {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 200px 400px;
|
||||||
|
margin: auto;
|
||||||
|
width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input, select {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.green {
|
||||||
|
background: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.red {
|
||||||
|
background: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
border: 2px solid white;
|
||||||
|
}
|
61
src/app/config/config.component.html
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<h1>Configuration</h1>
|
||||||
|
<p>These settings determine how your Deepgram Voice Agent behaves.</p>
|
||||||
|
<form>
|
||||||
|
<label for="apiKey">API Key:</label>
|
||||||
|
<input name="apiKey" id="apiKey" type="text" [formControl]="apiKey">
|
||||||
|
<label for="speak">Speak Model:</label>
|
||||||
|
<select name="speak" id="speak" [formControl]="speakModel">
|
||||||
|
<option value="aura-asteria-en">aura-asteria-en</option>
|
||||||
|
<option value="aura-luna-en">aura-luna-en</option>
|
||||||
|
<option value="aura-athena-en">aura-athena-en</option>
|
||||||
|
<option value="aura-stella-en">aura-stella-en</option>
|
||||||
|
<option value="aura-hera-en">aura-hera-en</option>
|
||||||
|
<option value="aura-orion-en">aura-orion-en</option>
|
||||||
|
<option value="aura-arcas-en">aura-arcas-en</option>
|
||||||
|
<option value="aura-perseus-en">aura-perseus-en</option>
|
||||||
|
<option value="aura-angus-en">aura-angus-en</option>
|
||||||
|
<option value="aura-orpheus-en">aura-orpheus-en</option>
|
||||||
|
<option value="aura-helios-en">aura-helios-en</option>
|
||||||
|
<option value="aura-zeus-en">aura-zeus-en</option>
|
||||||
|
</select>
|
||||||
|
<label for="listen">Listen Model:</label>
|
||||||
|
<select name="listen" id="listen" [formControl]="listenModel">
|
||||||
|
<option value="nova-2">nova-2</option>
|
||||||
|
<option value="nova-2-meeting">nova-2-meeting</option>
|
||||||
|
<option value="nova-2-phonecall">nova-2-phonecall</option>
|
||||||
|
<option value="nova-2-finance">nova-2-finance</option>
|
||||||
|
<option value="nova-2-conversationalai">nova-2-conversationalai</option>
|
||||||
|
<option value="nova-2-voicemail">nova-2-voicemail</option>
|
||||||
|
<option value="nova-2-video">nova-2-video</option>
|
||||||
|
<option value="nova-2-medical">nova-2-medical</option>
|
||||||
|
<option value="nova-2-drivethru">nova-2-drivethru</option>
|
||||||
|
<option value="nova-2-automotive">nova-2-automotive</option>
|
||||||
|
<option value="nova-2-atc">nova-2-atc</option>
|
||||||
|
<option value="nova">nova</option>
|
||||||
|
<option value="nova-phonecall">nova-phonecall</option>
|
||||||
|
<option value="nova-medical">nova-medical</option>
|
||||||
|
<option value="enhanced">enhanced</option>
|
||||||
|
<option value="enhanced-phonecall">enhanced-phonecall</option>
|
||||||
|
<option value="enhanced-meeting">enhanced-meeting</option>
|
||||||
|
<option value="enhanced-finance">enhanced-finance</option>
|
||||||
|
<option value="base">base</option>
|
||||||
|
<option value="base-phonecall">base-phonecall</option>
|
||||||
|
<option value="base-meeting">base-meeting</option>
|
||||||
|
<option value="base-finance">base-finance</option>
|
||||||
|
<option value="base-conversationalai">base-conversationalai</option>
|
||||||
|
<option value="base-voicemail">base-voicemail</option>
|
||||||
|
<option value="base-video">base-video</option>
|
||||||
|
<option value="whisper-tiny">whisper-tiny</option>
|
||||||
|
<option value="whisper-small">whisper-small</option>
|
||||||
|
<option value="whisper-medium">whisper-medium</option>
|
||||||
|
<option value="whisper-large">whisper-large</option>
|
||||||
|
<option value="whisper-base">whisper-base</option>
|
||||||
|
</select>
|
||||||
|
<label for="think">Think Model:</label>
|
||||||
|
<select name="think" id="think" [formControl]="thinkModel">
|
||||||
|
<option value="gpt-4o-mini">gpt-4o-mini</option>
|
||||||
|
<option value="claude-3-haiku-20240307">claude-3-haiku-20240307</option>
|
||||||
|
</select>
|
||||||
|
</form>
|
||||||
|
<button class="green" (click)="save()">Save Configuration</button>
|
||||||
|
<button class="red" (click)="cancel()">Cancel</button>
|
23
src/app/config/config.component.spec.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ConfigComponent } from './config.component';
|
||||||
|
|
||||||
|
describe('ConfigComponent', () => {
|
||||||
|
let component: ConfigComponent;
|
||||||
|
let fixture: ComponentFixture<ConfigComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [ConfigComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ConfigComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
66
src/app/config/config.component.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { AbstractControl, FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||||
|
import { ConfigService } from '../config.service';
|
||||||
|
import { Config } from '../interfaces/Config';
|
||||||
|
import type { SpeakModel, ThinkModel, ListenModel } from "../interfaces/Settings";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-config',
|
||||||
|
standalone: true,
|
||||||
|
imports: [ReactiveFormsModule],
|
||||||
|
templateUrl: './config.component.html',
|
||||||
|
styleUrl: './config.component.css'
|
||||||
|
})
|
||||||
|
export class ConfigComponent {
|
||||||
|
public apiKey = new FormControl("", [
|
||||||
|
Validators.required
|
||||||
|
]);
|
||||||
|
public speakModel = new FormControl("aura-athena-en", [
|
||||||
|
Validators.required,
|
||||||
|
() => (control: AbstractControl) => ["aura-asteria-en", "aura-luna-en", "aura-athena-en", "aura-stella-en",
|
||||||
|
"aura-hera-en", "aura-orion-en", "aura-arcas-en", "aura-perseus-en",
|
||||||
|
"aura-angus-en", "aura-orpheus-en", "aura-helios-en", "aura-zeus-en"].includes(control.value)
|
||||||
|
]);
|
||||||
|
public listenModel = new FormControl("nova-2", [
|
||||||
|
Validators.required,
|
||||||
|
() => (control: AbstractControl) => [ "nova-2", "nova-2-meeting", "nova-2-phonecall", "nova-2-finance",
|
||||||
|
"nova-2-conversationalai", "nova-2-finance", "nova-2-voicemail",
|
||||||
|
"nova-2-video", "nova-2-medical", "nova-2-drivethru", "nova-2-automotive",
|
||||||
|
"nova-2-atc", "nova", "nova-phonecall", "nova-medical", "enhanced",
|
||||||
|
"enhanced-phonecall", "enhanced-meeting", "enhanced-finance", "base",
|
||||||
|
"base-phonecall", "base-meeting", "base-finance", "base-conversationalai",
|
||||||
|
"base-voicemail", "base-video", "whisper-tiny", "whisper-small",
|
||||||
|
"whisper-medium", "whisper-large", "whisper-base"
|
||||||
|
].includes(control.value)
|
||||||
|
]);
|
||||||
|
public thinkModel = new FormControl("claude-3-haiku-20240307", [
|
||||||
|
Validators.required,
|
||||||
|
() => (control: AbstractControl) => ["claude-3-haiku-20240307", "gpt-4o-mini"].includes(control.value)
|
||||||
|
]);
|
||||||
|
|
||||||
|
public save() {
|
||||||
|
const config: Config = {
|
||||||
|
apiKey: this.apiKey.value ?? "",
|
||||||
|
speakModel: this.speakModel.value as SpeakModel,
|
||||||
|
listenModel: this.listenModel.value as ListenModel,
|
||||||
|
thinkModel: this.thinkModel.value as ThinkModel
|
||||||
|
}
|
||||||
|
this.configService.setConfig(config);
|
||||||
|
window.location.pathname = "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
public cancel() {
|
||||||
|
window.location.pathname = "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(private configService: ConfigService) {
|
||||||
|
const config = this.configService.getConfig();
|
||||||
|
if (!config) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.apiKey.setValue(config.apiKey);
|
||||||
|
this.speakModel.setValue(config.speakModel);
|
||||||
|
this.listenModel.setValue(config.listenModel);
|
||||||
|
this.thinkModel.setValue(config.thinkModel);
|
||||||
|
}
|
||||||
|
}
|
22
src/app/home/home.component.css
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
.btn {
|
||||||
|
border: 2px solid black;
|
||||||
|
width: 200px;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.green {
|
||||||
|
background: green;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yellow {
|
||||||
|
background: yellow;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
width: 500px;
|
||||||
|
grid-template-columns: 250px 250px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
6
src/app/home/home.component.html
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<h1>Deepgram Voice Assistant</h1>
|
||||||
|
<p>Welcome to your new favourite voice-powered assistant.</p>
|
||||||
|
<div class="grid">
|
||||||
|
<a href="/agent" class="green btn">Start Agent</a>
|
||||||
|
<a href="/config" class="yellow btn">Configuration</a>
|
||||||
|
</div>
|
23
src/app/home/home.component.spec.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { HomeComponent } from './home.component';
|
||||||
|
|
||||||
|
describe('HomeComponent', () => {
|
||||||
|
let component: HomeComponent;
|
||||||
|
let fixture: ComponentFixture<HomeComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [HomeComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(HomeComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
12
src/app/home/home.component.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-home',
|
||||||
|
standalone: true,
|
||||||
|
imports: [],
|
||||||
|
templateUrl: './home.component.html',
|
||||||
|
styleUrl: './home.component.css'
|
||||||
|
})
|
||||||
|
export class HomeComponent {
|
||||||
|
|
||||||
|
}
|
8
src/app/interfaces/Config.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { ListenModel, SpeakModel, ThinkModel } from "./Settings";
|
||||||
|
|
||||||
|
export interface Config {
|
||||||
|
apiKey: string;
|
||||||
|
speakModel: SpeakModel;
|
||||||
|
thinkModel: ThinkModel;
|
||||||
|
listenModel: ListenModel;
|
||||||
|
}
|
5
src/app/interfaces/Settings.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export type ListenModel = "nova-2" | "nova-2-meeting" | "nova-2-phonecall" | "nova-2-finance" | "nova-2-conversationalai" | "nova-2-voicemail" | "nova-2-video" | "nova-2-medical" | "nova-2-drivethru" | "nova-2-automotive" | "nova-2-atc" | "nova" | "nova-phonecall" | "nova-medical" | "enhanced" | "enhanced-phonecall" | "enhanced-meeting" | "enhanced-finance" | "base" | "base-phonecall" | "base-meeting" | "base-finance" | "base-conversationalai" | "base-voicemail" | "base-video" | "whisper-tiny" | "whisper-small" | "whisper-medium" | "whisper-large" | "whisper-base";
|
||||||
|
|
||||||
|
export type ThinkModel = "gpt-4o-mini" | "claude-3-haiku-20240307";
|
||||||
|
|
||||||
|
export type SpeakModel = "aura-asteria-en" | "aura-luna-en" | "aura-athena-en" | "aura-stella-en" | "aura-hera-en" | "aura-orion-en" | "aura-arcas-en" | "aura-perseus-en" | "aura-angus-en" | "aura-oprheus-en" | "aura-helios-en" | "aura-zeus-en";
|
12
src/index.html
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Tauri + Angular</title>
|
||||||
|
<base href="/" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
</head>
|
||||||
|
<body style="margin: 0">
|
||||||
|
<app-root></app-root>
|
||||||
|
</body>
|
||||||
|
</html>
|
7
src/main.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { bootstrapApplication } from "@angular/platform-browser";
|
||||||
|
import { appConfig } from "./app/app.config";
|
||||||
|
import { AppComponent } from "./app/app.component";
|
||||||
|
|
||||||
|
bootstrapApplication(AppComponent, appConfig).catch((err) =>
|
||||||
|
console.error(err),
|
||||||
|
);
|
10
tsconfig.app.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./out-tsc/app",
|
||||||
|
"types": []
|
||||||
|
},
|
||||||
|
"files": ["src/main.ts"],
|
||||||
|
"include": ["src/**/*.d.ts"]
|
||||||
|
}
|
16
tsconfig.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||||
|
{
|
||||||
|
"extends": "@nhcarrigan/typescript-config",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./dist/out-tsc",
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "ES2022",
|
||||||
|
"lib": ["ES2022", "dom"]
|
||||||
|
},
|
||||||
|
"angularCompilerOptions": {
|
||||||
|
"enableI18nLegacyMessageIdFormat": false,
|
||||||
|
"strictInjectionParameters": true,
|
||||||
|
"strictInputAccessModifiers": true,
|
||||||
|
"strictTemplates": true
|
||||||
|
}
|
||||||
|
}
|