feat: start rewriting as tauri app
44
.gitignore
vendored
@ -1,2 +1,42 @@
|
||||
/bin
|
||||
/obj
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# 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
|
||||
}
|
||||
}
|