├── .gitattributes ├── .gitignore ├── AIOrchestrator.csproj ├── AIOrchestrator.sln ├── App.xaml ├── App.xaml.cs ├── LICENSE.txt ├── Main.razor ├── MainPage.xaml ├── MainPage.xaml.cs ├── MauiProgram.cs ├── Model ├── AIOrchestratorDatabase.cs ├── ChatMessage.cs ├── LogService.cs ├── OrchestratorMethods.CompleteChapter.cs ├── OrchestratorMethods.CompleteStory.cs ├── OrchestratorMethods.LoadCharacters.cs ├── OrchestratorMethods.LoadStory.cs ├── OrchestratorMethods.SummarizeTextLong.cs ├── OrchestratorMethods.SummarizeTextShort.cs ├── OrchestratorMethods.SummerizeCharacter.cs ├── OrchestratorMethods.cs ├── SettingsService.cs ├── Utility.cs └── VectorData.cs ├── Pages ├── Counter.razor ├── Home.razor ├── Index.razor ├── Logs.razor ├── Memory.razor └── Settings.razor ├── Platforms ├── Android │ ├── AndroidManifest.xml │ ├── MainActivity.cs │ ├── MainApplication.cs │ └── Resources │ │ └── values │ │ └── colors.xml ├── MacCatalyst │ ├── AppDelegate.cs │ ├── Info.plist │ └── Program.cs ├── Tizen │ ├── Main.cs │ └── tizen-manifest.xml ├── Windows │ ├── App.xaml │ ├── App.xaml.cs │ ├── Package.appxmanifest │ └── app.manifest └── iOS │ ├── AppDelegate.cs │ ├── Info.plist │ └── Program.cs ├── Properties └── launchSettings.json ├── README.md ├── Resources ├── AppIcon │ ├── appicon.svg │ └── appiconfg.svg ├── Fonts │ └── OpenSans-Regular.ttf ├── Images │ └── dotnet_bot.svg ├── Raw │ ├── A Room with a View.txt │ ├── A Tale of Two Cities.txt │ └── The Great Gatsby.txt └── Splash │ └── splash.svg ├── Shared ├── MainLayout.razor ├── MainLayout.razor.css ├── NavMenu.razor └── NavMenu.razor.css ├── _Imports.razor └── wwwroot ├── css ├── app.css ├── bootstrap │ ├── bootstrap.min.css │ └── bootstrap.min.css.map └── open-iconic │ ├── FONT-LICENSE │ ├── ICON-LICENSE │ ├── README.md │ └── font │ ├── css │ └── open-iconic-bootstrap.min.css │ └── fonts │ ├── open-iconic.eot │ ├── open-iconic.otf │ ├── open-iconic.svg │ ├── open-iconic.ttf │ └── open-iconic.woff ├── favicon.ico └── index.html /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Oo]ut/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # ASP.NET Scaffolding 67 | ScaffoldingReadMe.txt 68 | 69 | # StyleCop 70 | StyleCopReport.xml 71 | 72 | # Files built by Visual Studio 73 | *_i.c 74 | *_p.c 75 | *_h.h 76 | *.ilk 77 | *.meta 78 | *.obj 79 | *.iobj 80 | *.pch 81 | *.pdb 82 | *.ipdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *_wpftmp.csproj 93 | *.log 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # CodeRush personal settings 313 | .cr/personal 314 | 315 | # Python Tools for Visual Studio (PTVS) 316 | __pycache__/ 317 | *.pyc 318 | 319 | # Cake - Uncomment if you are using it 320 | # tools/** 321 | # !tools/packages.config 322 | 323 | # Tabs Studio 324 | *.tss 325 | 326 | # Telerik's JustMock configuration file 327 | *.jmconfig 328 | 329 | # BizTalk build output 330 | *.btp.cs 331 | *.btm.cs 332 | *.odx.cs 333 | *.xsd.cs 334 | 335 | # OpenCover UI analysis results 336 | OpenCover/ 337 | 338 | # Azure Stream Analytics local run output 339 | ASALocalRun/ 340 | 341 | # MSBuild Binary and Structured Log 342 | *.binlog 343 | 344 | # NVidia Nsight GPU debugger configuration file 345 | *.nvuser 346 | 347 | # MFractors (Xamarin productivity tool) working folder 348 | .mfractor/ 349 | 350 | # Local History for Visual Studio 351 | .localhistory/ 352 | 353 | # BeatPulse healthcheck temp database 354 | healthchecksdb 355 | 356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 357 | MigrationBackup/ 358 | 359 | # Ionide (cross platform F# VS Code tools) working folder 360 | .ionide/ 361 | 362 | # Fody - auto-generated XML schema 363 | FodyWeavers.xsd -------------------------------------------------------------------------------- /AIOrchestrator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | ;net7.0-android 5 | 6 | 7 | Exe 8 | AIOrchestrator 9 | true 10 | true 11 | enable 12 | false 13 | 14 | 15 | AIOrchestrator 16 | 17 | 18 | com.companyname.aiorchestrator 19 | 0C446A46-10E5-418F-ADEA-8A1D9BF26A68 20 | 21 | 22 | 1.0 23 | 1 24 | 25 | 14.2 26 | 14.0 27 | 24.0 28 | 10.0.17763.0 29 | 10.0.17763.0 30 | 6.5 31 | False 32 | True 33 | 5FFDEF89196C4112331E94B78B47872040AEAB17 34 | SHA256 35 | True 36 | True 37 | True 38 | 0 39 | AI Orchestrator 40 | BlazorHelpWebsite.com 41 | Allows you to import a book and have it write an original chapter based on your description 42 | https://github.com/ADefWebserver/AIOrchestrator 43 | https://github.com/ADefWebserver/AIOrchestrator 44 | git 45 | 46 | 47 | 48 | $(TargetFrameworks);net7.0-windows10.0.19041.0 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /AIOrchestrator.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.34009.444 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AIOrchestrator", "AIOrchestrator.csproj", "{EB4811C8-8452-4156-8DC3-1E117ACD8F84}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {EB4811C8-8452-4156-8DC3-1E117ACD8F84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {EB4811C8-8452-4156-8DC3-1E117ACD8F84}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {EB4811C8-8452-4156-8DC3-1E117ACD8F84}.Debug|Any CPU.Deploy.0 = Debug|Any CPU 17 | {EB4811C8-8452-4156-8DC3-1E117ACD8F84}.Release|Any CPU.ActiveCfg = Release|Any CPU 18 | {EB4811C8-8452-4156-8DC3-1E117ACD8F84}.Release|Any CPU.Build.0 = Release|Any CPU 19 | {EB4811C8-8452-4156-8DC3-1E117ACD8F84}.Release|Any CPU.Deploy.0 = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(SolutionProperties) = preSolution 22 | HideSolutionNode = FALSE 23 | EndGlobalSection 24 | GlobalSection(ExtensibilityGlobals) = postSolution 25 | SolutionGuid = {079A0E83-79AD-4DE9-B91F-3C66E888F004} 26 | EndGlobalSection 27 | EndGlobal 28 | -------------------------------------------------------------------------------- /App.xaml: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | 9 | #512bdf 10 | White 11 | 12 | 16 | 17 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /App.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace AIOrchestrator 2 | { 3 | public partial class App : Application 4 | { 5 | public App() 6 | { 7 | InitializeComponent(); 8 | 9 | MainPage = new MainPage(); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [year] [fullname] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Main.razor: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 |

Sorry, there's nothing at this address.

9 |
10 |
11 |
12 | -------------------------------------------------------------------------------- /MainPage.xaml: -------------------------------------------------------------------------------- 1 |  2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /MainPage.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace AIOrchestrator 2 | { 3 | public partial class MainPage : ContentPage 4 | { 5 | public MainPage() 6 | { 7 | InitializeComponent(); 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /MauiProgram.cs: -------------------------------------------------------------------------------- 1 | using AIOrchestrator.Model; 2 | using Microsoft.Extensions.Logging; 3 | using Radzen; 4 | 5 | namespace AIOrchestrator 6 | { 7 | public static class MauiProgram 8 | { 9 | public static MauiApp CreateMauiApp() 10 | { 11 | var builder = MauiApp.CreateBuilder(); 12 | builder 13 | .UseMauiApp() 14 | .ConfigureFonts(fonts => 15 | { 16 | fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); 17 | }); 18 | 19 | builder.Services.AddMauiBlazorWebView(); 20 | 21 | #if DEBUG 22 | builder.Services.AddBlazorWebViewDeveloperTools(); 23 | builder.Logging.AddDebug(); 24 | #endif 25 | 26 | builder.Services.AddSingleton(); 27 | builder.Services.AddSingleton(); 28 | builder.Services.AddSingleton(); 29 | 30 | // Radzen 31 | builder.Services.AddScoped(); 32 | builder.Services.AddScoped(); 33 | builder.Services.AddScoped(); 34 | builder.Services.AddScoped(); 35 | 36 | // Load Default files 37 | var folderPath = ""; 38 | var filePath = ""; 39 | 40 | // AIOrchestrator Directory 41 | folderPath = $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/AIOrchestrator"; 42 | if (!Directory.Exists(folderPath)) 43 | { 44 | Directory.CreateDirectory(folderPath); 45 | } 46 | 47 | // AIOrchestrator Documents Directory 48 | var folderDocumentsPath = $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/AIOrchestrator/Documents"; 49 | if (!Directory.Exists(folderDocumentsPath)) 50 | { 51 | Directory.CreateDirectory(folderDocumentsPath); 52 | 53 | // Copy all files Assets to the AIOrchestrator Documents Directory 54 | List files = new List 55 | { 56 | "A Room with a View.txt", 57 | "A Tale of Two Cities.txt", 58 | "The Great Gatsby.txt" 59 | }; 60 | 61 | foreach (var file in files) 62 | { 63 | using var stream = FileSystem.OpenAppPackageFileAsync(file); 64 | using var reader = new StreamReader(stream.Result); 65 | var text = reader.ReadToEnd(); 66 | File.WriteAllText(Path.Combine(folderDocumentsPath, file), text); 67 | } 68 | } 69 | 70 | // AIOrchestratorLog.csv 71 | filePath = Path.Combine(folderPath, "AIOrchestratorLog.csv"); 72 | 73 | if (!File.Exists(filePath)) 74 | { 75 | using (var streamWriter = new StreamWriter(filePath)) 76 | { 77 | streamWriter.WriteLine("Application started at " + DateTime.Now); 78 | } 79 | } 80 | else 81 | { 82 | // File already exists 83 | string[] AIOrchestratorLog; 84 | 85 | // Open the file to get existing content 86 | using (var file = new System.IO.StreamReader(filePath)) 87 | { 88 | AIOrchestratorLog = file.ReadToEnd().Split('\n'); 89 | 90 | if (AIOrchestratorLog[AIOrchestratorLog.Length - 1].Trim() == "") 91 | { 92 | AIOrchestratorLog = AIOrchestratorLog.Take(AIOrchestratorLog.Length - 1).ToArray(); 93 | } 94 | } 95 | 96 | // Append the text to csv file 97 | using (var streamWriter = new StreamWriter(filePath)) 98 | { 99 | streamWriter.WriteLine(string.Join("\n", "Application started at " + DateTime.Now)); 100 | streamWriter.WriteLine(string.Join("\n", AIOrchestratorLog)); 101 | } 102 | } 103 | 104 | // AIOrchestratorMemory.csv 105 | filePath = Path.Combine(folderPath, "AIOrchestratorMemory.csv"); 106 | 107 | if (!File.Exists(filePath)) 108 | { 109 | using (var streamWriter = new StreamWriter(filePath)) 110 | { 111 | streamWriter.WriteLine("** AIOrchestratorMemory started at " + DateTime.Now + "|"); 112 | } 113 | } 114 | 115 | // AIOrchestratorDatabase.json 116 | filePath = Path.Combine(folderPath, "AIOrchestratorDatabase.json"); 117 | 118 | if (!File.Exists(filePath)) 119 | { 120 | using (var streamWriter = new StreamWriter(filePath)) 121 | { 122 | streamWriter.WriteLine( 123 | """ 124 | { 125 | } 126 | """); 127 | } 128 | } 129 | 130 | // AIOrchestratorSettings.config 131 | filePath = Path.Combine(folderPath, "AIOrchestratorSettings.config"); 132 | 133 | if (!File.Exists(filePath)) 134 | { 135 | using (var streamWriter = new StreamWriter(filePath)) 136 | { 137 | streamWriter.WriteLine( 138 | """ 139 | { 140 | "OpenAIServiceOptions": { 141 | "Organization": "** Your OpenAI Organization **", 142 | "ApiKey": "** Your OpenAI ApiKey **" } 143 | } 144 | """); 145 | } 146 | } 147 | 148 | return builder.Build(); 149 | } 150 | } 151 | } -------------------------------------------------------------------------------- /Model/AIOrchestratorDatabase.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using OpenAI.Files; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace AIOrchestrator.Model 10 | { 11 | public class AIOrchestratorDatabase 12 | { 13 | // Constructor 14 | public AIOrchestratorDatabase() { } 15 | 16 | public string ReadFile() 17 | { 18 | string response; 19 | string folderPath = $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/AIOrchestrator"; 20 | string filePath = Path.Combine(folderPath, "AIOrchestratorDatabase.json"); 21 | 22 | // Open the file to get existing content 23 | using (var streamReader = new StreamReader(filePath)) 24 | { 25 | response = streamReader.ReadToEnd(); 26 | } 27 | 28 | return response; 29 | } 30 | 31 | public dynamic ReadFileDynamic() 32 | { 33 | string FileContents; 34 | string folderPath = $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/AIOrchestrator"; 35 | string filePath = Path.Combine(folderPath, "AIOrchestratorDatabase.json"); 36 | 37 | // Open the file to get existing content 38 | using (var streamReader = new StreamReader(filePath)) 39 | { 40 | FileContents = streamReader.ReadToEnd(); 41 | } 42 | 43 | dynamic AIOrchestratorDatabaseObject = JsonConvert.DeserializeObject(FileContents); 44 | 45 | return AIOrchestratorDatabaseObject; 46 | } 47 | 48 | public async Task WriteFile(dynamic AIOrchestratorDatabaseObject) 49 | { 50 | string folderPath = $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/AIOrchestrator"; 51 | string filePath = Path.Combine(folderPath, "AIOrchestratorDatabase.json"); 52 | 53 | // Convert the dynamic object back to JSON 54 | var AIOrchestratorSettings = JsonConvert.SerializeObject(AIOrchestratorDatabaseObject, Formatting.Indented); 55 | 56 | // Write the JSON to the file 57 | using (var streamWriter = new StreamWriter(filePath)) 58 | { 59 | await streamWriter.WriteAsync(AIOrchestratorSettings); 60 | } 61 | } 62 | 63 | public async Task WriteFile(string AIOrchestratorDatabaseContent) 64 | { 65 | string folderPath = $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/AIOrchestrator"; 66 | string filePath = Path.Combine(folderPath, "AIOrchestratorDatabase.json"); 67 | 68 | // Write the JSON to the file 69 | using (var streamWriter = new StreamWriter(filePath)) 70 | { 71 | await streamWriter.WriteAsync(AIOrchestratorDatabaseContent); 72 | } 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /Model/ChatMessage.cs: -------------------------------------------------------------------------------- 1 | namespace AIOrchestrator.Model 2 | { 3 | public class ChatMessage 4 | { 5 | public string Prompt { get; set; } 6 | public OpenAI.Chat.Role Role { get; set; } 7 | public string FunctionName { get; set; } 8 | public int Tokens { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Model/LogService.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using OpenAI.Files; 3 | 4 | namespace AIOrchestrator.Model 5 | { 6 | public class LogService 7 | { 8 | // Properties 9 | public string[] AIOrchestratorLog { get; set; } 10 | 11 | // Constructor 12 | public LogService() 13 | { 14 | loadLog(); 15 | } 16 | 17 | public void loadLog() 18 | { 19 | var AIOrchestratorLogPath = 20 | $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/AIOrchestrator/AIOrchestratorLog.csv"; 21 | 22 | // Read the lines from the .csv file 23 | using (var file = new System.IO.StreamReader(AIOrchestratorLogPath)) 24 | { 25 | AIOrchestratorLog = file.ReadToEnd().Split('\n'); 26 | if (AIOrchestratorLog[AIOrchestratorLog.Length - 1].Trim() == "") 27 | { 28 | AIOrchestratorLog = AIOrchestratorLog.Take(AIOrchestratorLog.Length - 1).ToArray(); 29 | } 30 | } 31 | } 32 | 33 | public void WriteToLog(string LogText) 34 | { 35 | // Open the file to get existing content 36 | var AIOrchestratorLogPath = 37 | $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/AIOrchestrator/AIOrchestratorLog.csv"; 38 | 39 | using (var file = new System.IO.StreamReader(AIOrchestratorLogPath)) 40 | { 41 | AIOrchestratorLog = file.ReadToEnd().Split('\n'); 42 | 43 | if (AIOrchestratorLog[AIOrchestratorLog.Length - 1].Trim() == "") 44 | { 45 | AIOrchestratorLog = AIOrchestratorLog.Take(AIOrchestratorLog.Length - 1).ToArray(); 46 | } 47 | } 48 | 49 | // Append the text to csv file 50 | using (var streamWriter = new StreamWriter(AIOrchestratorLogPath)) 51 | { 52 | // Remove line breaks from the log text 53 | LogText = LogText.Replace("\n", " "); 54 | 55 | streamWriter.WriteLine(LogText); 56 | streamWriter.WriteLine(string.Join("\n", AIOrchestratorLog)); 57 | } 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /Model/OrchestratorMethods.CompleteChapter.cs: -------------------------------------------------------------------------------- 1 | using OpenAI; 2 | using OpenAI.Chat; 3 | using System.Net; 4 | using OpenAI.Files; 5 | using OpenAI.Models; 6 | using System.Text.RegularExpressions; 7 | using System.Text.Json.Nodes; 8 | using System.Text.Json; 9 | using Newtonsoft.Json; 10 | using static AIOrchestrator.Model.OrchestratorMethods; 11 | using Microsoft.Maui.Storage; 12 | using static AIOrchestrator.Pages.Memory; 13 | using System.Collections.Generic; 14 | 15 | namespace AIOrchestrator.Model 16 | { 17 | public partial class OrchestratorMethods 18 | { 19 | #region public async Task CompleteChapter(string NewChapter, string SelectedModel) 20 | public async Task CompleteChapter(string NewChapter, string SelectedModel) 21 | { 22 | LogService.WriteToLog("CompleteChapter - Start"); 23 | string Organization = SettingsService.Organization; 24 | string ApiKey = SettingsService.ApiKey; 25 | string SystemMessage = ""; 26 | 27 | ChatMessages = new List(); 28 | 29 | // **** Create AIOrchestratorDatabase.json 30 | // Store Tasks in the Database as an array in a single property 31 | // Store the Last Read Index as a Property in Database 32 | // Store Summary as a Property in the Database 33 | AIOrchestratorDatabaseObject = new 34 | { 35 | CurrentTask = "Read Text", 36 | LastWordRead = 0, 37 | Summary = "" 38 | }; 39 | 40 | // Save AIOrchestratorDatabase.json 41 | AIOrchestratorDatabase objAIOrchestratorDatabase = new AIOrchestratorDatabase(); 42 | objAIOrchestratorDatabase.WriteFile(AIOrchestratorDatabaseObject); 43 | 44 | // Create a new OpenAIClient object 45 | // with the provided API key and organization 46 | var api = new OpenAIClient(new OpenAIAuthentication(ApiKey, Organization)); 47 | 48 | // Create a colection of chatPrompts 49 | ChatResponse ChatResponseResult = new ChatResponse(); 50 | List chatPrompts = new List(); 51 | 52 | // ***************************************************** 53 | dynamic Databasefile = AIOrchestratorDatabaseObject; 54 | 55 | // Get Background Text - Perform vector search using NewChapter 56 | List<(string, float)> SearchResults = await SearchMemory(NewChapter, 20); 57 | 58 | // Create a single string from the first colum of SearchResults 59 | string BackgroundText = string.Join(",", SearchResults.Select(x => x.Item1)); 60 | 61 | ReadTextEvent?.Invoke(this, new ReadTextEventArgs($"Background retrieved: {BackgroundText.Split(' ').Length} words.")); 62 | 63 | // Trim BackgroundText to 5000 words (so we don't run out of tokens) 64 | BackgroundText = OrchestratorMethods.TrimToMaxWords(BackgroundText, 10000); 65 | 66 | ReadTextEvent?.Invoke(this, new ReadTextEventArgs($"Background trimmed to: {BackgroundText.Split(' ').Length} words.")); 67 | 68 | // Update System Message 69 | SystemMessage = CreateSystemMessageChapter(NewChapter, BackgroundText); 70 | 71 | chatPrompts = new List(); 72 | 73 | chatPrompts.Insert(0, 74 | new Message( 75 | Role.System, 76 | SystemMessage 77 | ) 78 | ); 79 | 80 | ReadTextEvent?.Invoke(this, new ReadTextEventArgs($"Call ChatGPT...")); 81 | 82 | // Get a response from ChatGPT 83 | var FinalChatRequest = new ChatRequest( 84 | chatPrompts, 85 | model: SelectedModel, 86 | temperature: 0.0, 87 | topP: 1, 88 | frequencyPenalty: 0, 89 | presencePenalty: 0); 90 | 91 | ChatResponseResult = await api.ChatEndpoint.GetCompletionAsync(FinalChatRequest); 92 | 93 | // ***************************************************** 94 | 95 | LogService.WriteToLog($"TotalTokens: {ChatResponseResult.Usage.TotalTokens} - ChatResponseResult - {ChatResponseResult.FirstChoice.Message.Content}"); 96 | 97 | return ChatResponseResult.FirstChoice.Message.Content; 98 | } 99 | #endregion 100 | 101 | // Methods 102 | 103 | #region private string CreateSystemMessageChapter(string paramChapterDescription, string paramBackgroundText) 104 | private string CreateSystemMessageChapter(string paramChapterDescription, string paramBackgroundText) 105 | { 106 | return "You are a program that will write a complete 2000 word Chapter that follows " + 107 | "the description in ###CHAPTER DESCRIPTION###. Write the Chapter \n" + 108 | "only using information from ###Background Text###.\n" + 109 | "Only respond with output that contains the Chapter nothing else.\n" + 110 | "Only use information from ###CHAPTER DESCRIPTION### and ###Background Text###.\n" + 111 | $"###CHAPTER DESCRIPTION### is: {paramChapterDescription}\n" + 112 | $"###Background Text### is: {paramBackgroundText}\n"; 113 | } 114 | #endregion 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Model/OrchestratorMethods.CompleteStory.cs: -------------------------------------------------------------------------------- 1 | using OpenAI; 2 | using OpenAI.Chat; 3 | using System.Net; 4 | using OpenAI.Files; 5 | using OpenAI.Models; 6 | using System.Text.RegularExpressions; 7 | using System.Text.Json.Nodes; 8 | using System.Text.Json; 9 | using Newtonsoft.Json; 10 | using static AIOrchestrator.Model.OrchestratorMethods; 11 | using Microsoft.Maui.Storage; 12 | using static AIOrchestrator.Pages.Memory; 13 | using System.Collections.Generic; 14 | 15 | namespace AIOrchestrator.Model 16 | { 17 | public partial class OrchestratorMethods 18 | { 19 | #region public async Task CompleteStory(string NewStory, string SelectedModel) 20 | public async Task CompleteStory(string NewStory, string SelectedModel) 21 | { 22 | LogService.WriteToLog("CompleteStory - Start"); 23 | string Organization = SettingsService.Organization; 24 | string ApiKey = SettingsService.ApiKey; 25 | string SystemMessage = ""; 26 | 27 | ChatMessages = new List(); 28 | 29 | // **** Create AIOrchestratorDatabase.json 30 | // Store Tasks in the Database as an array in a single property 31 | // Store the Last Read Index as a Property in Database 32 | // Store Summary as a Property in the Database 33 | AIOrchestratorDatabaseObject = new 34 | { 35 | CurrentTask = "Read Text", 36 | LastWordRead = 0, 37 | Summary = "" 38 | }; 39 | 40 | // Save AIOrchestratorDatabase.json 41 | AIOrchestratorDatabase objAIOrchestratorDatabase = new AIOrchestratorDatabase(); 42 | objAIOrchestratorDatabase.WriteFile(AIOrchestratorDatabaseObject); 43 | 44 | // Create a new OpenAIClient object 45 | // with the provided API key and organization 46 | var api = new OpenAIClient(new OpenAIAuthentication(ApiKey, Organization)); 47 | 48 | // Create a colection of chatPrompts 49 | ChatResponse ChatResponseResult = new ChatResponse(); 50 | List chatPrompts = new List(); 51 | 52 | // ***************************************************** 53 | dynamic Databasefile = AIOrchestratorDatabaseObject; 54 | 55 | // Get Background Text - Perform vector search using NewStory 56 | List<(string, float)> SearchResults = await SearchMemory(NewStory, 5); 57 | 58 | // Create a single string from the first colum of SearchResults 59 | string BackgroundText = string.Join(",", SearchResults.Select(x => x.Item1)); 60 | 61 | // Update System Message 62 | SystemMessage = CreateSystemMessageStory(NewStory, BackgroundText); 63 | 64 | chatPrompts = new List(); 65 | 66 | chatPrompts.Insert(0, 67 | new Message( 68 | Role.System, 69 | SystemMessage 70 | ) 71 | ); 72 | 73 | // Get a response from ChatGPT 74 | var FinalChatRequest = new ChatRequest( 75 | chatPrompts, 76 | model: SelectedModel, 77 | temperature: 0.0, 78 | topP: 1, 79 | frequencyPenalty: 0, 80 | presencePenalty: 0); 81 | 82 | ChatResponseResult = await api.ChatEndpoint.GetCompletionAsync(FinalChatRequest); 83 | 84 | // ***************************************************** 85 | 86 | LogService.WriteToLog($"TotalTokens: {ChatResponseResult.Usage.TotalTokens} - ChatResponseResult - {ChatResponseResult.FirstChoice.Message.Content}"); 87 | 88 | return ChatResponseResult.FirstChoice.Message.Content; 89 | } 90 | #endregion 91 | 92 | // Methods 93 | 94 | #region private string CreateSystemMessageStory(string paramNewText, string paramBackgroundText) 95 | private string CreateSystemMessageStory(string paramNewText, string paramBackgroundText) 96 | { 97 | return "You are a program that will write a paragraph to continue a story starting " + 98 | "with the content in ###New Text###. Write the paragraph \n" + 99 | "only using information from ###New Text### and ###Background Text###.\n" + 100 | "Only respond with a paragraph that completes the story nothing else.\n" + 101 | "Only use information from ###New Text### and ###Background Text###.\n" + 102 | $"###New Text### is: {paramNewText}\n" + 103 | $"###Background Text### is: {paramBackgroundText}\n"; 104 | } 105 | #endregion 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /Model/OrchestratorMethods.LoadCharacters.cs: -------------------------------------------------------------------------------- 1 | using OpenAI; 2 | using OpenAI.Chat; 3 | using System.Net; 4 | using OpenAI.Files; 5 | using OpenAI.Models; 6 | using System.Text.RegularExpressions; 7 | using System.Text.Json.Nodes; 8 | using System.Text.Json; 9 | using Newtonsoft.Json; 10 | using static AIOrchestrator.Model.OrchestratorMethods; 11 | using Microsoft.Maui.Storage; 12 | using static AIOrchestrator.Pages.Memory; 13 | 14 | namespace AIOrchestrator.Model 15 | { 16 | public partial class OrchestratorMethods 17 | { 18 | #region public async Task> LoadCharacters(string Filename, int intMaxLoops, int intChunkSize) 19 | public async Task> LoadCharacters(string Filename, int intMaxLoops, int intChunkSize) 20 | { 21 | LogService.WriteToLog("LoadCharacters - Start"); 22 | 23 | string CharacterSummary = ""; 24 | string Organization = SettingsService.Organization; 25 | string ApiKey = SettingsService.ApiKey; 26 | string SystemMessage = ""; 27 | int TotalTokens = 0; 28 | 29 | ChatMessages = new List(); 30 | 31 | // **** Create AIOrchestratorDatabase.json 32 | // Store Tasks in the Database as an array in a single property 33 | // Store the Last Read Index as a Property in Database 34 | // Store Summary as a Property in the Database 35 | AIOrchestratorDatabaseObject = new 36 | { 37 | CurrentTask = "Read Text", 38 | LastWordRead = 0, 39 | Summary = "" 40 | }; 41 | 42 | // Save AIOrchestratorDatabase.json 43 | AIOrchestratorDatabase objAIOrchestratorDatabase = new AIOrchestratorDatabase(); 44 | objAIOrchestratorDatabase.WriteFile(AIOrchestratorDatabaseObject); 45 | 46 | // Create a new OpenAIClient object 47 | // with the provided API key and organization 48 | var api = new OpenAIClient(new OpenAIAuthentication(ApiKey, Organization)); 49 | 50 | // Create a colection of chatPrompts 51 | ChatResponse ChatResponseResult = new ChatResponse(); 52 | List chatPrompts = new List(); 53 | 54 | // Call ChatGPT 55 | int CallCount = 0; 56 | 57 | // We need to start a While loop 58 | bool ChatGPTCallingComplete = false; 59 | int StartWordIndex = 0; 60 | 61 | while (!ChatGPTCallingComplete) 62 | { 63 | // Read Text 64 | var CurrentText = await ExecuteRead(Filename, StartWordIndex, intChunkSize); 65 | 66 | // ***************************************************** 67 | dynamic Databasefile = AIOrchestratorDatabaseObject; 68 | 69 | // Update System Message 70 | SystemMessage = CreateSystemMessageCharacters(CurrentText); 71 | 72 | chatPrompts = new List(); 73 | 74 | chatPrompts.Insert(0, 75 | new Message( 76 | Role.System, 77 | SystemMessage 78 | ) 79 | ); 80 | 81 | // Get a response from ChatGPT 82 | var FinalChatRequest = new ChatRequest( 83 | chatPrompts, 84 | model: "gpt-3.5-turbo", 85 | temperature: 0.0, 86 | topP: 1, 87 | frequencyPenalty: 0, 88 | presencePenalty: 0); 89 | 90 | ChatResponseResult = await api.ChatEndpoint.GetCompletionAsync(FinalChatRequest); 91 | 92 | var NamedCharactersFound = ChatResponseResult.FirstChoice.Message.Content; 93 | 94 | // ******************************************************* 95 | // Update the Character Summary 96 | CharacterSummary = CombineAndSortLists(CharacterSummary, NamedCharactersFound); 97 | 98 | // Update the total number of tokens used by the API 99 | TotalTokens = TotalTokens + ChatResponseResult.Usage.TotalTokens ?? 0; 100 | 101 | LogService.WriteToLog($"Iteration: {CallCount} - TotalTokens: {TotalTokens} - result.FirstChoice.Message - {ChatResponseResult.FirstChoice.Message}"); 102 | 103 | if (Databasefile.CurrentTask == "Read Text") 104 | { 105 | // Keep looping 106 | ChatGPTCallingComplete = false; 107 | CallCount = CallCount + 1; 108 | StartWordIndex = Databasefile.LastWordRead; 109 | 110 | // Update the AIOrchestratorDatabase.json file 111 | AIOrchestratorDatabaseObject = new 112 | { 113 | CurrentTask = "Read Text", 114 | LastWordRead = Databasefile.LastWordRead, 115 | Summary = ChatResponseResult.FirstChoice.Message.Content 116 | }; 117 | 118 | // Check if we have exceeded the maximum number of calls 119 | if (CallCount > intMaxLoops) 120 | { 121 | // Break out of the loop 122 | ChatGPTCallingComplete = true; 123 | LogService.WriteToLog($"* Breaking out of loop * Iteration: {CallCount}"); 124 | ReadTextEvent?.Invoke(this, new ReadTextEventArgs($"Break out of the loop - Iteration: {CallCount}")); 125 | } 126 | else 127 | { 128 | ReadTextEvent?.Invoke(this, new ReadTextEventArgs($"Continue to Loop - Iteration: {CallCount}")); 129 | } 130 | } 131 | else 132 | { 133 | // Break out of the loop 134 | ChatGPTCallingComplete = true; 135 | LogService.WriteToLog($"Iteration: {CallCount}"); 136 | ReadTextEvent?.Invoke(this, new ReadTextEventArgs($"Break out of the loop - Iteration: {CallCount}")); 137 | } 138 | } 139 | 140 | // ***************************************************** 141 | // Output final summary 142 | 143 | // Save AIOrchestratorDatabase.json 144 | objAIOrchestratorDatabase.WriteFile(AIOrchestratorDatabaseObject); 145 | 146 | LogService.WriteToLog($"CharacterSummary - {CharacterSummary}"); 147 | 148 | string[] CharacterSummaryArray = CharacterSummary.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); 149 | 150 | return CharacterSummaryArray.ToList(); 151 | } 152 | #endregion 153 | 154 | // Methods 155 | 156 | #region private string CreateSystemMessageCharacters(string paramNewText) 157 | private string CreateSystemMessageCharacters(string paramNewText) 158 | { 159 | return "You are a program that will identify the names of the named characters in the content of ###New Text###.\n" + 160 | "Only respond with the names of the named characters nothing else.\n" + 161 | "Only list each character name once.\n" + 162 | "List each character on a seperate line.\n" + 163 | "Only respond with the names of the named characters nothing else.\n" + 164 | $"###New Text### is: {paramNewText}\n"; 165 | } 166 | #endregion 167 | } 168 | } -------------------------------------------------------------------------------- /Model/OrchestratorMethods.LoadStory.cs: -------------------------------------------------------------------------------- 1 | using OpenAI; 2 | using OpenAI.Chat; 3 | using System.Net; 4 | using OpenAI.Files; 5 | using OpenAI.Models; 6 | using System.Text.RegularExpressions; 7 | using System.Text.Json.Nodes; 8 | using System.Text.Json; 9 | using Newtonsoft.Json; 10 | using static AIOrchestrator.Model.OrchestratorMethods; 11 | using Microsoft.Maui.Storage; 12 | using static AIOrchestrator.Pages.Memory; 13 | 14 | namespace AIOrchestrator.Model 15 | { 16 | public partial class OrchestratorMethods 17 | { 18 | #region public async Task LoadStory(string Filename, int intMaxLoops, int intChunkSize) 19 | public async Task LoadStory(string Filename, int intMaxLoops, int intChunkSize) 20 | { 21 | LogService.WriteToLog("LoadStory - Start"); 22 | 23 | bool StoryLoaded = false; 24 | string Organization = SettingsService.Organization; 25 | string ApiKey = SettingsService.ApiKey; 26 | string SystemMessage = ""; 27 | int TotalTokens = 0; 28 | 29 | ChatMessages = new List(); 30 | 31 | // **** Create AIOrchestratorDatabase.json 32 | // Store Tasks in the Database as an array in a single property 33 | // Store the Last Read Index as a Property in Database 34 | // Store Summary as a Property in the Database 35 | AIOrchestratorDatabaseObject = new 36 | { 37 | CurrentTask = "Read Text", 38 | LastWordRead = 0, 39 | Summary = "" 40 | }; 41 | 42 | // Save AIOrchestratorDatabase.json 43 | AIOrchestratorDatabase objAIOrchestratorDatabase = new AIOrchestratorDatabase(); 44 | objAIOrchestratorDatabase.WriteFile(AIOrchestratorDatabaseObject); 45 | 46 | // Create a new OpenAIClient object 47 | // with the provided API key and organization 48 | var api = new OpenAIClient(new OpenAIAuthentication(ApiKey, Organization)); 49 | 50 | // Create a colection of chatPrompts 51 | ChatResponse ChatResponseResult = new ChatResponse(); 52 | List chatPrompts = new List(); 53 | 54 | // Call ChatGPT 55 | int CallCount = 0; 56 | 57 | // We need to start a While loop 58 | bool ChatGPTCallingComplete = false; 59 | int StartWordIndex = 0; 60 | 61 | while (!ChatGPTCallingComplete) 62 | { 63 | // Read Text 64 | var CurrentText = await ExecuteRead(Filename, StartWordIndex, intChunkSize); 65 | 66 | // ***************************************************** 67 | dynamic Databasefile = AIOrchestratorDatabaseObject; 68 | 69 | // Update System Message 70 | SystemMessage = CreateSystemMessageLoadStory(CurrentText); 71 | 72 | chatPrompts = new List(); 73 | 74 | chatPrompts.Insert(0, 75 | new Message( 76 | Role.System, 77 | SystemMessage 78 | ) 79 | ); 80 | 81 | // Get a response from ChatGPT 82 | var FinalChatRequest = new ChatRequest( 83 | chatPrompts, 84 | model: "gpt-3.5-turbo", 85 | temperature: 0.0, 86 | topP: 1, 87 | frequencyPenalty: 0, 88 | presencePenalty: 0); 89 | 90 | ChatResponseResult = await api.ChatEndpoint.GetCompletionAsync(FinalChatRequest); 91 | 92 | var ChatResponseContent = ChatResponseResult.FirstChoice.Message.Content; 93 | 94 | // Create a Vector database entry 95 | if (ChatResponseContent != "") 96 | { 97 | // ******************************************************* 98 | // Create a Vector database entry for each Character summary found 99 | await CreateVectorEntry(ChatResponseContent); 100 | } 101 | 102 | // Update the Summary 103 | Summary = Summary + ChatResponseContent + "\n\n"; 104 | 105 | // Update the total number of tokens used by the API 106 | TotalTokens = TotalTokens + ChatResponseResult.Usage.TotalTokens ?? 0; 107 | 108 | LogService.WriteToLog($"Iteration: {CallCount} - TotalTokens: {TotalTokens} - result.FirstChoice.Message - {ChatResponseResult.FirstChoice.Message}"); 109 | 110 | if (Databasefile.CurrentTask == "Read Text") 111 | { 112 | // Keep looping 113 | ChatGPTCallingComplete = false; 114 | CallCount = CallCount + 1; 115 | StartWordIndex = Databasefile.LastWordRead; 116 | 117 | // Update the AIOrchestratorDatabase.json file 118 | AIOrchestratorDatabaseObject = new 119 | { 120 | CurrentTask = "Read Text", 121 | LastWordRead = Databasefile.LastWordRead, 122 | Summary = ChatResponseResult.FirstChoice.Message.Content 123 | }; 124 | 125 | // Check if we have exceeded the maximum number of calls 126 | if (CallCount > intMaxLoops) 127 | { 128 | // Break out of the loop 129 | ChatGPTCallingComplete = true; 130 | LogService.WriteToLog($"* Breaking out of loop * Iteration: {CallCount}"); 131 | ReadTextEvent?.Invoke(this, new ReadTextEventArgs($"Break out of the loop - Iteration: {CallCount}")); 132 | } 133 | else 134 | { 135 | ReadTextEvent?.Invoke(this, new ReadTextEventArgs($"Continue to Loop - Iteration: {CallCount}")); 136 | } 137 | } 138 | else 139 | { 140 | // Break out of the loop 141 | ChatGPTCallingComplete = true; 142 | LogService.WriteToLog($"Iteration: {CallCount}"); 143 | ReadTextEvent?.Invoke(this, new ReadTextEventArgs($"Break out of the loop - Iteration: {CallCount}")); 144 | } 145 | } 146 | 147 | // ***************************************************** 148 | // Save AIOrchestratorDatabase.json 149 | objAIOrchestratorDatabase.WriteFile(AIOrchestratorDatabaseObject); 150 | 151 | StoryLoaded = true; 152 | 153 | LogService.WriteToLog($"StoryLoaded - {StoryLoaded}"); 154 | return StoryLoaded; 155 | } 156 | #endregion 157 | 158 | // Methods 159 | 160 | #region private string CreateSystemMessageLoadStory(string paramNewText) 161 | private string CreateSystemMessageLoadStory(string paramNewText) 162 | { 163 | return "You are a program that will produce a summary of the content of ###New Text###.\n" + 164 | "Only respond with the contents of the summary nothing else.\n" + 165 | "Always output complete sentences.\n" + 166 | "Only respond with the contents of the summary nothing else.\n" + 167 | $"###New Text### is: {paramNewText}\n"; 168 | } 169 | #endregion 170 | } 171 | } -------------------------------------------------------------------------------- /Model/OrchestratorMethods.SummarizeTextLong.cs: -------------------------------------------------------------------------------- 1 | using OpenAI; 2 | using OpenAI.Chat; 3 | using System.Net; 4 | using OpenAI.Files; 5 | using OpenAI.Models; 6 | using System.Text.RegularExpressions; 7 | using System.Text.Json.Nodes; 8 | using System.Text.Json; 9 | using Newtonsoft.Json; 10 | using static AIOrchestrator.Model.OrchestratorMethods; 11 | using Microsoft.Maui.Storage; 12 | 13 | namespace AIOrchestrator.Model 14 | { 15 | public partial class OrchestratorMethods 16 | { 17 | #region public async Task ReadTextLong(string Filename, int intMaxLoops, int intChunkSize) 18 | public async Task ReadTextLong(string Filename, int intMaxLoops, int intChunkSize) 19 | { 20 | LogService.WriteToLog("ReadTextLong - Start"); 21 | 22 | string Summary = ""; 23 | string Organization = SettingsService.Organization; 24 | string ApiKey = SettingsService.ApiKey; 25 | string SystemMessage = ""; 26 | int TotalTokens = 0; 27 | 28 | ChatMessages = new List(); 29 | 30 | // **** Create AIOrchestratorDatabase.json 31 | // Store Tasks in the Database as an array in a single property 32 | // Store the Last Read Index as a Property in Database 33 | // Store Summary as a Property in the Database 34 | AIOrchestratorDatabaseObject = new 35 | { 36 | CurrentTask = "Read Text", 37 | LastWordRead = 0, 38 | Summary = "" 39 | }; 40 | 41 | // Save AIOrchestratorDatabase.json 42 | AIOrchestratorDatabase objAIOrchestratorDatabase = new AIOrchestratorDatabase(); 43 | objAIOrchestratorDatabase.WriteFile(AIOrchestratorDatabaseObject); 44 | 45 | // Create a new OpenAIClient object 46 | // with the provided API key and organization 47 | var api = new OpenAIClient(new OpenAIAuthentication(ApiKey, Organization)); 48 | 49 | // Create a colection of chatPrompts 50 | ChatResponse ChatResponseResult = new ChatResponse(); 51 | List chatPrompts = new List(); 52 | 53 | // Call ChatGPT 54 | int CallCount = 0; 55 | 56 | // We need to start a While loop 57 | bool ChatGPTCallingComplete = false; 58 | int StartWordIndex = 0; 59 | 60 | while (!ChatGPTCallingComplete) 61 | { 62 | // Read Text 63 | var CurrentText = await ExecuteRead(Filename, StartWordIndex, intChunkSize); 64 | 65 | // ***************************************************** 66 | dynamic Databasefile = AIOrchestratorDatabaseObject; 67 | 68 | // Update System Message 69 | SystemMessage = CreateSystemMessageLong(CurrentText); 70 | 71 | chatPrompts = new List(); 72 | 73 | chatPrompts.Insert(0, 74 | new Message( 75 | Role.System, 76 | SystemMessage 77 | ) 78 | ); 79 | 80 | // Get a response from ChatGPT 81 | var FinalChatRequest = new ChatRequest( 82 | chatPrompts, 83 | model: "gpt-3.5-turbo", 84 | temperature: 0.0, 85 | topP: 1, 86 | frequencyPenalty: 0, 87 | presencePenalty: 0); 88 | 89 | ChatResponseResult = await api.ChatEndpoint.GetCompletionAsync(FinalChatRequest); 90 | 91 | var ChatResponseContent = ChatResponseResult.FirstChoice.Message.Content; 92 | 93 | // Create a Vector database entry 94 | if (ChatResponseContent != "") 95 | { 96 | // ******************************************************* 97 | // Create a Vector database entry for each Character summary found 98 | await CreateVectorEntry(ChatResponseContent); 99 | } 100 | 101 | // Update the Summary 102 | Summary = Summary + ChatResponseContent + "\n\n"; 103 | 104 | // Update the total number of tokens used by the API 105 | TotalTokens = TotalTokens + ChatResponseResult.Usage.TotalTokens ?? 0; 106 | 107 | LogService.WriteToLog($"Iteration: {CallCount} - TotalTokens: {TotalTokens} - result.FirstChoice.Message - {ChatResponseResult.FirstChoice.Message}"); 108 | 109 | if (Databasefile.CurrentTask == "Read Text") 110 | { 111 | // Keep looping 112 | ChatGPTCallingComplete = false; 113 | CallCount = CallCount + 1; 114 | StartWordIndex = Databasefile.LastWordRead; 115 | 116 | // Update the AIOrchestratorDatabase.json file 117 | AIOrchestratorDatabaseObject = new 118 | { 119 | CurrentTask = "Read Text", 120 | LastWordRead = Databasefile.LastWordRead, 121 | Summary = ChatResponseResult.FirstChoice.Message.Content 122 | }; 123 | 124 | // Check if we have exceeded the maximum number of calls 125 | if (CallCount > intMaxLoops) 126 | { 127 | // Break out of the loop 128 | ChatGPTCallingComplete = true; 129 | LogService.WriteToLog($"* Breaking out of loop * Iteration: {CallCount}"); 130 | ReadTextEvent?.Invoke(this, new ReadTextEventArgs($"Break out of the loop - Iteration: {CallCount}")); 131 | } 132 | else 133 | { 134 | ReadTextEvent?.Invoke(this, new ReadTextEventArgs($"Continue to Loop - Iteration: {CallCount}")); 135 | } 136 | } 137 | else 138 | { 139 | // Break out of the loop 140 | ChatGPTCallingComplete = true; 141 | LogService.WriteToLog($"Iteration: {CallCount}"); 142 | ReadTextEvent?.Invoke(this, new ReadTextEventArgs($"Break out of the loop - Iteration: {CallCount}")); 143 | } 144 | } 145 | 146 | // ***************************************************** 147 | // Output final summary 148 | 149 | // Save AIOrchestratorDatabase.json 150 | objAIOrchestratorDatabase.WriteFile(AIOrchestratorDatabaseObject); 151 | 152 | LogService.WriteToLog($"Summary - {Summary}"); 153 | return Summary; 154 | } 155 | #endregion 156 | 157 | // Methods 158 | 159 | #region private string CreateSystemMessageLong(string paramNewText) 160 | private string CreateSystemMessageLong(string paramNewText) 161 | { 162 | return "You are a program that will produce a summary of the content of ###New Text###.\n" + 163 | "Only respond with the contents of the summary nothing else.\n" + 164 | "Always output complete sentences.\n" + 165 | "Only respond with the contents of the summary nothing else.\n" + 166 | $"###New Text### is: {paramNewText}\n"; 167 | } 168 | #endregion 169 | } 170 | } -------------------------------------------------------------------------------- /Model/OrchestratorMethods.SummarizeTextShort.cs: -------------------------------------------------------------------------------- 1 | using OpenAI; 2 | using OpenAI.Chat; 3 | using System.Net; 4 | using OpenAI.Files; 5 | using OpenAI.Models; 6 | using System.Text.RegularExpressions; 7 | using System.Text.Json.Nodes; 8 | using System.Text.Json; 9 | using Newtonsoft.Json; 10 | using static AIOrchestrator.Model.OrchestratorMethods; 11 | using Microsoft.Maui.Storage; 12 | 13 | namespace AIOrchestrator.Model 14 | { 15 | public partial class OrchestratorMethods 16 | { 17 | #region public async Task ReadTextShort(string Filename, int intMaxLoops, int intChunkSize) 18 | public async Task ReadTextShort(string Filename, int intMaxLoops, int intChunkSize) 19 | { 20 | LogService.WriteToLog("ReadTextShort - Start"); 21 | 22 | string Organization = SettingsService.Organization; 23 | string ApiKey = SettingsService.ApiKey; 24 | string SystemMessage = ""; 25 | int TotalTokens = 0; 26 | 27 | ChatMessages = new List(); 28 | 29 | // **** Create AIOrchestratorDatabase.json 30 | // Store Tasks in the Database as an array in a single property 31 | // Store the Last Read Index as a Property in Database 32 | // Store Summary as a Property in the Database 33 | AIOrchestratorDatabaseObject = new 34 | { 35 | CurrentTask = "Read Text", 36 | LastWordRead = 0, 37 | Summary = "" 38 | }; 39 | 40 | // Save AIOrchestratorDatabase.json 41 | AIOrchestratorDatabase objAIOrchestratorDatabase = new AIOrchestratorDatabase(); 42 | objAIOrchestratorDatabase.WriteFile(AIOrchestratorDatabaseObject); 43 | 44 | // Create a new OpenAIClient object 45 | // with the provided API key and organization 46 | var api = new OpenAIClient(new OpenAIAuthentication(ApiKey, Organization)); 47 | 48 | // Create a colection of chatPrompts 49 | ChatResponse ChatResponseResult = new ChatResponse(); 50 | List chatPrompts = new List(); 51 | 52 | // Call ChatGPT 53 | int CallCount = 0; 54 | 55 | // We need to start a While loop 56 | bool ChatGPTCallingComplete = false; 57 | int StartWordIndex = 0; 58 | 59 | while (!ChatGPTCallingComplete) 60 | { 61 | // Read Text 62 | var CurrentText = await ExecuteRead(Filename, StartWordIndex, intChunkSize); 63 | 64 | // ***************************************************** 65 | dynamic Databasefile = AIOrchestratorDatabaseObject; 66 | string CurrentSummary = AIOrchestratorDatabaseObject.Summary ?? ""; 67 | 68 | // Update System Message 69 | SystemMessage = CreateSystemMessage(CurrentSummary, CurrentText); 70 | 71 | chatPrompts = new List(); 72 | 73 | chatPrompts.Insert(0, 74 | new Message( 75 | Role.System, 76 | SystemMessage 77 | ) 78 | ); 79 | 80 | // Get a response from ChatGPT 81 | var FinalChatRequest = new ChatRequest( 82 | chatPrompts, 83 | model: "gpt-3.5-turbo", 84 | temperature: 0.0, 85 | topP: 1, 86 | frequencyPenalty: 0, 87 | presencePenalty: 0); 88 | 89 | ChatResponseResult = await api.ChatEndpoint.GetCompletionAsync(FinalChatRequest); 90 | 91 | // Update the total number of tokens used by the API 92 | TotalTokens = TotalTokens + ChatResponseResult.Usage.TotalTokens ?? 0; 93 | 94 | LogService.WriteToLog($"Iteration: {CallCount} - TotalTokens: {TotalTokens} - result.FirstChoice.Message - {ChatResponseResult.FirstChoice.Message}"); 95 | 96 | if (Databasefile.CurrentTask == "Read Text") 97 | { 98 | // Keep looping 99 | ChatGPTCallingComplete = false; 100 | CallCount = CallCount + 1; 101 | StartWordIndex = Databasefile.LastWordRead; 102 | 103 | // Update the AIOrchestratorDatabase.json file 104 | AIOrchestratorDatabaseObject = new 105 | { 106 | CurrentTask = "Read Text", 107 | LastWordRead = Databasefile.LastWordRead, 108 | Summary = ChatResponseResult.FirstChoice.Message.Content 109 | }; 110 | 111 | // Check if we have exceeded the maximum number of calls 112 | if (CallCount > intMaxLoops) 113 | { 114 | // Break out of the loop 115 | ChatGPTCallingComplete = true; 116 | LogService.WriteToLog($"* Breaking out of loop * Iteration: {CallCount}"); 117 | ReadTextEvent?.Invoke(this, new ReadTextEventArgs($"Break out of the loop - Iteration: {CallCount}")); 118 | } 119 | else 120 | { 121 | ReadTextEvent?.Invoke(this, new ReadTextEventArgs($"Continue to Loop - Iteration: {CallCount}")); 122 | } 123 | } 124 | else 125 | { 126 | // Break out of the loop 127 | ChatGPTCallingComplete = true; 128 | LogService.WriteToLog($"Iteration: {CallCount}"); 129 | ReadTextEvent?.Invoke(this, new ReadTextEventArgs($"Break out of the loop - Iteration: {CallCount}")); 130 | } 131 | } 132 | 133 | // ***************************************************** 134 | // Clean up the final summary 135 | ReadTextEvent?.Invoke(this, new ReadTextEventArgs($"Clean up the final summary")); 136 | string RawSummary = ChatResponseResult.FirstChoice.Message.Content; 137 | 138 | chatPrompts = new List(); 139 | 140 | chatPrompts.Insert(0, 141 | new Message( 142 | Role.System, 143 | $"Format the following summary to break it up into paragraphs: {RawSummary}" 144 | ) 145 | ); 146 | 147 | // Get a response from ChatGPT 148 | var chatRequest = new ChatRequest( 149 | chatPrompts, 150 | model: "gpt-3.5-turbo", 151 | temperature: 0.0, 152 | topP: 1, 153 | frequencyPenalty: 0, 154 | presencePenalty: 0); 155 | 156 | ChatResponseResult = await api.ChatEndpoint.GetCompletionAsync(chatRequest); 157 | 158 | // Save AIOrchestratorDatabase.json 159 | objAIOrchestratorDatabase.WriteFile(AIOrchestratorDatabaseObject); 160 | 161 | LogService.WriteToLog($"result.FirstChoice.Message - {ChatResponseResult.FirstChoice.Message}"); 162 | return ChatResponseResult.FirstChoice.Message; 163 | } 164 | #endregion 165 | 166 | // Methods 167 | 168 | #region private string CreateSystemMessage(string paramCurrentSummary, string paramNewText) 169 | private string CreateSystemMessage(string paramCurrentSummary, string paramNewText) 170 | { 171 | // The AI should keep this under 1000 words but here we will ensure it 172 | paramCurrentSummary = EnsureMaxWords(paramCurrentSummary, 1000); 173 | 174 | return "You are a program that will produce a summary not to exceed 1000 words. \n" + 175 | "Only respond with the contents of the summary nothing else. \n" + 176 | "Output a summary that combines the contents of ###Current Summary### with the additional content in ###New Text###. \n" + 177 | "In the summary only use content from ###Current Summary### and ###New Text###. \n" + 178 | "Only respond with the contents of the summary nothing else. \n" + 179 | "Do not allow the summary to exceed 1000 words. \n" + 180 | $"###Current Summary### is: {paramCurrentSummary}\n" + 181 | $"###New Text### is: {paramNewText}\n"; 182 | } 183 | #endregion 184 | 185 | #region public static string EnsureMaxWords(string paramCurrentSummary, int maxWords) 186 | public static string EnsureMaxWords(string paramCurrentSummary, int maxWords) 187 | { 188 | // Split the string by spaces to get words 189 | var words = paramCurrentSummary.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); 190 | 191 | if (words.Length <= maxWords) 192 | { 193 | // If the number of words is within the limit, return the original string 194 | return paramCurrentSummary; 195 | } 196 | 197 | // If the number of words exceeds the limit, return only the last 'maxWords' words 198 | return string.Join(" ", words.Reverse().Take(maxWords).Reverse()); 199 | } 200 | #endregion 201 | } 202 | } -------------------------------------------------------------------------------- /Model/OrchestratorMethods.SummerizeCharacter.cs: -------------------------------------------------------------------------------- 1 | using OpenAI; 2 | using OpenAI.Chat; 3 | using System.Net; 4 | using OpenAI.Files; 5 | using OpenAI.Models; 6 | using System.Text.RegularExpressions; 7 | using System.Text.Json.Nodes; 8 | using System.Text.Json; 9 | using Newtonsoft.Json; 10 | using static AIOrchestrator.Model.OrchestratorMethods; 11 | using Microsoft.Maui.Storage; 12 | using static AIOrchestrator.Pages.Memory; 13 | 14 | namespace AIOrchestrator.Model 15 | { 16 | public partial class OrchestratorMethods 17 | { 18 | #region public async Task SummarizeCharacter(string Filename, string paramSelectedCharacter, int intMaxLoops, int intChunkSize) 19 | public async Task SummarizeCharacter(string Filename, string paramSelectedCharacter, int intMaxLoops, int intChunkSize) 20 | { 21 | LogService.WriteToLog("SummarizeCharacter - Start"); 22 | 23 | string FinalSummary = ""; 24 | string Organization = SettingsService.Organization; 25 | string ApiKey = SettingsService.ApiKey; 26 | string SystemMessage = ""; 27 | int TotalTokens = 0; 28 | 29 | ChatMessages = new List(); 30 | 31 | // **** Create AIOrchestratorDatabase.json 32 | // Store Tasks in the Database as an array in a single property 33 | // Store the Last Read Index as a Property in Database 34 | // Store Summary as a Property in the Database 35 | AIOrchestratorDatabaseObject = new 36 | { 37 | CurrentTask = "Read Text", 38 | LastWordRead = 0, 39 | Summary = "" 40 | }; 41 | 42 | // Save AIOrchestratorDatabase.json 43 | AIOrchestratorDatabase objAIOrchestratorDatabase = new AIOrchestratorDatabase(); 44 | objAIOrchestratorDatabase.WriteFile(AIOrchestratorDatabaseObject); 45 | 46 | // Create a new OpenAIClient object 47 | // with the provided API key and organization 48 | var api = new OpenAIClient(new OpenAIAuthentication(ApiKey, Organization)); 49 | 50 | // Create a colection of chatPrompts 51 | ChatResponse ChatResponseResult = new ChatResponse(); 52 | List chatPrompts = new List(); 53 | 54 | // Call ChatGPT 55 | int CallCount = 0; 56 | 57 | // We need to start a While loop 58 | bool ChatGPTCallingComplete = false; 59 | int StartWordIndex = 0; 60 | 61 | while (!ChatGPTCallingComplete) 62 | { 63 | // Read Text 64 | var CurrentText = await ExecuteRead(Filename, StartWordIndex, intChunkSize); 65 | 66 | // ***************************************************** 67 | dynamic Databasefile = AIOrchestratorDatabaseObject; 68 | 69 | // Update System Message 70 | SystemMessage = CreateSystemMessageCharacterSummary(paramSelectedCharacter, CurrentText); 71 | 72 | chatPrompts = new List(); 73 | 74 | chatPrompts.Insert(0, 75 | new Message( 76 | Role.System, 77 | SystemMessage 78 | ) 79 | ); 80 | 81 | // Get a response from ChatGPT 82 | var FinalChatRequest = new ChatRequest( 83 | chatPrompts, 84 | model: "gpt-3.5-turbo", 85 | temperature: 0.0, 86 | topP: 1, 87 | frequencyPenalty: 0, 88 | presencePenalty: 0); 89 | 90 | ChatResponseResult = await api.ChatEndpoint.GetCompletionAsync(FinalChatRequest); 91 | 92 | var CharacterSummaryFound = ChatResponseResult.FirstChoice.Message.Content; 93 | 94 | // Create a Vector database entry 95 | if ((CharacterSummaryFound != "") && (!CharacterSummaryFound.Contains("[empty]"))) 96 | { 97 | // ******************************************************* 98 | // Create a Vector database entry for each Character summary found 99 | await CreateVectorEntry(CharacterSummaryFound); 100 | 101 | FinalSummary = FinalSummary + CharacterSummaryFound + "\n\n"; 102 | } 103 | 104 | // ******************************************************* 105 | // Update the Summary 106 | 107 | // Update the total number of tokens used by the API 108 | TotalTokens = TotalTokens + ChatResponseResult.Usage.TotalTokens ?? 0; 109 | 110 | LogService.WriteToLog($"Iteration: {CallCount} - TotalTokens: {TotalTokens} - result.FirstChoice.Message - {ChatResponseResult.FirstChoice.Message}"); 111 | 112 | if (Databasefile.CurrentTask == "Read Text") 113 | { 114 | // Keep looping 115 | ChatGPTCallingComplete = false; 116 | CallCount = CallCount + 1; 117 | StartWordIndex = Databasefile.LastWordRead; 118 | 119 | // Update the AIOrchestratorDatabase.json file 120 | AIOrchestratorDatabaseObject = new 121 | { 122 | CurrentTask = "Read Text", 123 | LastWordRead = Databasefile.LastWordRead, 124 | Summary = ChatResponseResult.FirstChoice.Message.Content 125 | }; 126 | 127 | // Check if we have exceeded the maximum number of calls 128 | if (CallCount > intMaxLoops) 129 | { 130 | // Break out of the loop 131 | ChatGPTCallingComplete = true; 132 | LogService.WriteToLog($"* Breaking out of loop * Iteration: {CallCount}"); 133 | ReadTextEvent?.Invoke(this, new ReadTextEventArgs($"Break out of the loop - Iteration: {CallCount}")); 134 | } 135 | else 136 | { 137 | ReadTextEvent?.Invoke(this, new ReadTextEventArgs($"Continue to Loop - Iteration: {CallCount}")); 138 | } 139 | } 140 | else 141 | { 142 | // Break out of the loop 143 | ChatGPTCallingComplete = true; 144 | LogService.WriteToLog($"Iteration: {CallCount}"); 145 | ReadTextEvent?.Invoke(this, new ReadTextEventArgs($"Break out of the loop - Iteration: {CallCount}")); 146 | } 147 | } 148 | 149 | // ***************************************************** 150 | // Output final summary 151 | 152 | // Save AIOrchestratorDatabase.json 153 | objAIOrchestratorDatabase.WriteFile(AIOrchestratorDatabaseObject); 154 | 155 | LogService.WriteToLog($"Summary - {FinalSummary}"); 156 | return FinalSummary; 157 | } 158 | #endregion 159 | 160 | // Methods 161 | 162 | #region private string CreateSystemMessageCharacterSummary(string paramCharacterName, string paramNewText) 163 | private string CreateSystemMessageCharacterSummary(string paramCharacterName, string paramNewText) 164 | { 165 | return "You are a program that will produce a short summary about ###Named Character### in the content of ###New Text###.\n" + 166 | "Only respond with a short summary about ###Named Character### nothing else.\n" + 167 | "If ###Named Character### is not mentioned in ###New Text### return [empty] as a response.\n" + 168 | $"###Named Character### is: {paramCharacterName}\n" + 169 | $"###New Text### is: {paramNewText}\n"; 170 | } 171 | #endregion 172 | } 173 | } -------------------------------------------------------------------------------- /Model/OrchestratorMethods.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using OpenAI; 3 | using static AIOrchestrator.Pages.Memory; 4 | 5 | namespace AIOrchestrator.Model 6 | { 7 | public partial class OrchestratorMethods 8 | { 9 | public event EventHandler ReadTextEvent; 10 | public SettingsService SettingsService { get; set; } 11 | public LogService LogService { get; set; } 12 | public string Summary { get; set; } 13 | dynamic AIOrchestratorDatabaseObject { get; set; } 14 | 15 | public List ChatMessages = new List(); 16 | 17 | public List<(string, float)> similarities = new List<(string, float)>(); 18 | 19 | public Dictionary AIOrchestratorMemory = new Dictionary(); 20 | 21 | // Constructor 22 | public OrchestratorMethods(SettingsService _SettingsService, LogService _LogService) 23 | { 24 | SettingsService = _SettingsService; 25 | LogService = _LogService; 26 | } 27 | 28 | // Reading Text 29 | 30 | #region private async Task ExecuteRead(string Filename, int paramStartWordIndex, int intChunkSize) 31 | private async Task ExecuteRead(string Filename, int paramStartWordIndex, int intChunkSize) 32 | { 33 | // Read the Text from the file 34 | var ReadTextResult = await ReadText(Filename, paramStartWordIndex, intChunkSize); 35 | 36 | // ***************************************************** 37 | dynamic ReadTextFromFileObject = JsonConvert.DeserializeObject(ReadTextResult); 38 | string ReadTextFromFileText = ReadTextFromFileObject.Text; 39 | int intCurrentWord = ReadTextFromFileObject.CurrentWord; 40 | int intTotalWords = ReadTextFromFileObject.TotalWords; 41 | 42 | // ***************************************************** 43 | dynamic Databasefile = AIOrchestratorDatabaseObject; 44 | 45 | string strCurrentTask = Databasefile.CurrentTask; 46 | int intLastWordRead = intCurrentWord; 47 | string strSummary = Databasefile.Summary ?? ""; 48 | 49 | // If we are done reading the text, then summarize it 50 | if (intCurrentWord >= intTotalWords) 51 | { 52 | strCurrentTask = "Summarize"; 53 | } 54 | 55 | // Prepare object to save to AIOrchestratorDatabase.json 56 | AIOrchestratorDatabaseObject = new 57 | { 58 | CurrentTask = strCurrentTask, 59 | LastWordRead = intLastWordRead, 60 | Summary = strSummary 61 | }; 62 | 63 | return ReadTextFromFileText; 64 | } 65 | #endregion 66 | 67 | #region private async Task ReadText(string FileDocumentPath, int startWordIndex, int intChunkSize) 68 | private async Task ReadText(string FileDocumentPath, int startWordIndex, int intChunkSize) 69 | { 70 | // Read the text from the file 71 | string TextFileRaw = ""; 72 | 73 | // Open the file to get existing content 74 | using (var streamReader = new StreamReader(FileDocumentPath)) 75 | { 76 | TextFileRaw = await streamReader.ReadToEndAsync(); 77 | } 78 | 79 | // Split the text into words 80 | string[] TextFileWords = TextFileRaw.Split(new char[] { ' ', '\t', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); 81 | 82 | // Get the total number of words 83 | int TotalWords = TextFileWords.Length; 84 | 85 | // Get words starting at the startWordIndex 86 | string[] TextFileWordsChunk = TextFileWords.Skip(startWordIndex).Take(intChunkSize).ToArray(); 87 | 88 | // Set the current word to the startWordIndex + intChunkSize 89 | int CurrentWord = startWordIndex + intChunkSize; 90 | 91 | if (CurrentWord >= TotalWords) 92 | { 93 | // Set the current word to the total words 94 | CurrentWord = TotalWords; 95 | } 96 | 97 | string ReadTextFromFileResponse = """ 98 | { 99 | "Text": "{TextFileWordsChunk}", 100 | "CurrentWord": {CurrentWord}, 101 | "TotalWords": {TotalWords}, 102 | } 103 | """; 104 | 105 | ReadTextFromFileResponse = ReadTextFromFileResponse.Replace("{TextFileWordsChunk}", string.Join(" ", TextFileWordsChunk)); 106 | ReadTextFromFileResponse = ReadTextFromFileResponse.Replace("{CurrentWord}", CurrentWord.ToString()); 107 | ReadTextFromFileResponse = ReadTextFromFileResponse.Replace("{TotalWords}", TotalWords.ToString()); 108 | 109 | return ReadTextFromFileResponse; 110 | } 111 | #endregion 112 | 113 | // Memory and Vectors 114 | 115 | #region private async Task CreateVectorEntry(string vectorcontent) 116 | private async Task CreateVectorEntry(string VectorContent) 117 | { 118 | // **** Call OpenAI and get embeddings for the memory text 119 | // Create an instance of the OpenAI client 120 | var api = new OpenAIClient(new OpenAIAuthentication(SettingsService.ApiKey, SettingsService.Organization)); 121 | // Get the model details 122 | var model = await api.ModelsEndpoint.GetModelDetailsAsync("text-embedding-ada-002"); 123 | // Get embeddings for the text 124 | var embeddings = await api.EmbeddingsEndpoint.CreateEmbeddingAsync(VectorContent, model); 125 | // Get embeddings as an array of floats 126 | var EmbeddingVectors = embeddings.Data[0].Embedding.Select(d => (float)d).ToArray(); 127 | // Loop through the embeddings 128 | List AllVectors = new List(); 129 | for (int i = 0; i < EmbeddingVectors.Length; i++) 130 | { 131 | var embeddingVector = new VectorData 132 | { 133 | VectorValue = EmbeddingVectors[i] 134 | }; 135 | AllVectors.Add(embeddingVector); 136 | } 137 | // Convert the floats to a single string 138 | var VectorsToSave = "[" + string.Join(",", AllVectors.Select(x => x.VectorValue)) + "]"; 139 | 140 | // Write the memory to the .csv file 141 | var AIOrchestratorMemoryPath = $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/AIOrchestrator/AIOrchestratorMemory.csv"; 142 | using (var streamWriter = new StreamWriter(AIOrchestratorMemoryPath, true)) 143 | { 144 | streamWriter.WriteLine(VectorContent + "|" + VectorsToSave); 145 | } 146 | } 147 | #endregion 148 | 149 | #region public async Task> SearchMemory(string SearchText, int intResultsToReturn) 150 | public async Task> SearchMemory(string SearchText, int intResultsToReturn) 151 | { 152 | // Clear the memory 153 | AIOrchestratorMemory = new Dictionary(); 154 | 155 | // Read the lines from the .csv file 156 | var AIOrchestratorMemoryPath = 157 | $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/AIOrchestrator/AIOrchestratorMemory.csv"; 158 | 159 | // Read the lines from the .csv file 160 | foreach (var line in System.IO.File.ReadAllLines(AIOrchestratorMemoryPath)) 161 | { 162 | var splitLine = line.Split('|'); 163 | var KEY = splitLine[0]; 164 | var VALUE = splitLine[1]; 165 | 166 | AIOrchestratorMemory.Add(KEY, VALUE); 167 | } 168 | 169 | // **** Call OpenAI and get embeddings for the memory text 170 | // Create an instance of the OpenAI client 171 | var api = new OpenAIClient(new OpenAIAuthentication(SettingsService.ApiKey, SettingsService.Organization)); 172 | // Get the model details 173 | var model = await api.ModelsEndpoint.GetModelDetailsAsync("text-embedding-ada-002"); 174 | // Get embeddings for the text 175 | var embeddings = await api.EmbeddingsEndpoint.CreateEmbeddingAsync(SearchText, model); 176 | // Get embeddings as an array of floats 177 | var EmbeddingVectors = embeddings.Data[0].Embedding.Select(d => (float)d).ToArray(); 178 | 179 | // Reset the similarities list 180 | similarities = new List<(string, float)>(); 181 | 182 | // Calculate the similarity between the prompt's 183 | // embedding and each existing embedding 184 | foreach (var embedding in AIOrchestratorMemory) 185 | { 186 | if (embedding.Value != null) 187 | { 188 | if (embedding.Value != "") 189 | { 190 | var ConvertEmbeddingToFloats = JsonConvert.DeserializeObject>(embedding.Value); 191 | 192 | var similarity = 193 | CosineSimilarity( 194 | EmbeddingVectors, 195 | ConvertEmbeddingToFloats.ToArray()); 196 | 197 | similarities.Add((embedding.Key, similarity)); 198 | } 199 | } 200 | } 201 | 202 | // Sort the results by similarity in descending order 203 | similarities.Sort((a, b) => b.Item2.CompareTo(a.Item2)); 204 | 205 | return similarities.Take(intResultsToReturn).ToList(); 206 | } 207 | #endregion 208 | 209 | // Utility Methods 210 | 211 | #region public static float CosineSimilarity(float[] vector1, float[] vector2) 212 | public static float CosineSimilarity(float[] vector1, float[] vector2) 213 | { 214 | // Initialize variables for dot product and 215 | // magnitudes of the vectors 216 | float dotProduct = 0; 217 | float magnitude1 = 0; 218 | float magnitude2 = 0; 219 | 220 | // Iterate through the vectors and calculate 221 | // the dot product and magnitudes 222 | for (int i = 0; i < vector1?.Length; i++) 223 | { 224 | // Calculate dot product 225 | dotProduct += vector1[i] * vector2[i]; 226 | 227 | // Calculate squared magnitude of vector1 228 | magnitude1 += vector1[i] * vector1[i]; 229 | 230 | // Calculate squared magnitude of vector2 231 | magnitude2 += vector2[i] * vector2[i]; 232 | } 233 | 234 | // Take the square root of the squared magnitudes 235 | // to obtain actual magnitudes 236 | magnitude1 = (float)Math.Sqrt(magnitude1); 237 | magnitude2 = (float)Math.Sqrt(magnitude2); 238 | 239 | // Calculate and return cosine similarity by dividing 240 | // dot product by the product of magnitudes 241 | return dotProduct / (magnitude1 * magnitude2); 242 | } 243 | #endregion 244 | 245 | #region private string CombineAndSortLists(string paramExistingList, string paramNewList) 246 | private string CombineAndSortLists(string paramExistingList, string paramNewList) 247 | { 248 | // Split the lists into an arrays 249 | string[] ExistingListArray = paramExistingList.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); 250 | string[] NewListArray = paramNewList.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); 251 | 252 | // Combine the lists 253 | string[] CombinedListArray = ExistingListArray.Concat(NewListArray).ToArray(); 254 | 255 | // Remove duplicates 256 | CombinedListArray = CombinedListArray.Distinct().ToArray(); 257 | 258 | // Sort the array 259 | Array.Sort(CombinedListArray); 260 | 261 | // Combine the array into a string 262 | string CombinedList = string.Join("\n", CombinedListArray); 263 | 264 | return CombinedList; 265 | } 266 | #endregion 267 | 268 | #region public static string TrimToMaxWords(string input, int maxWords = 500) 269 | public static string TrimToMaxWords(string input, int maxWords = 500) 270 | { 271 | if (string.IsNullOrEmpty(input)) 272 | return input; 273 | 274 | string[] words = input.Split(new[] { ' ', '\t', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); 275 | 276 | if (words.Length <= maxWords) 277 | return input; 278 | 279 | return string.Join(" ", words.Take(maxWords)); 280 | } 281 | #endregion 282 | 283 | #region public class ReadTextEventArgs : EventArgs 284 | public class ReadTextEventArgs : EventArgs 285 | { 286 | public string Message { get; set; } 287 | 288 | public ReadTextEventArgs(string message) 289 | { 290 | Message = message; 291 | } 292 | } 293 | #endregion 294 | } 295 | } -------------------------------------------------------------------------------- /Model/SettingsService.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace AIOrchestrator.Model 4 | { 5 | public class SettingsService 6 | { 7 | // Properties 8 | public string Organization { get; set; } 9 | public string ApiKey { get; set; } 10 | 11 | // Constructor 12 | public SettingsService() 13 | { 14 | ReloadSettings(); 15 | } 16 | 17 | public void ReloadSettings() 18 | { 19 | // Get OpenAI API key from appsettings.json 20 | // AIOrchestrator Directory 21 | var AIOrchestratorSettingsPath = $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/AIOrchestrator/AIOrchestratorSettings.config"; 22 | 23 | string AIOrchestratorSettings = ""; 24 | 25 | // Open the file to get existing content 26 | using (var streamReader = new StreamReader(AIOrchestratorSettingsPath)) 27 | { 28 | AIOrchestratorSettings = streamReader.ReadToEnd(); 29 | } 30 | 31 | // Convert the JSON to a dynamic object 32 | dynamic AIOrchestratorSettingsObject = JsonConvert.DeserializeObject(AIOrchestratorSettings); 33 | 34 | Organization = AIOrchestratorSettingsObject.OpenAIServiceOptions.Organization; 35 | ApiKey = AIOrchestratorSettingsObject.OpenAIServiceOptions.ApiKey; 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /Model/Utility.cs: -------------------------------------------------------------------------------- 1 | using OpenAI.Chat; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Windows.ApplicationModel.Chat; 8 | 9 | namespace AIOrchestrator.Model 10 | { 11 | public class Utility 12 | { 13 | #region private List AddExistingChatMessags(List chatPrompts, string SystemMessage) 14 | private List AddExistingChatMessags(List chatPrompts, string SystemMessage) 15 | { 16 | List ChatMessages = new List(); 17 | 18 | // Create a new LinkedList of ChatMessages 19 | LinkedList ChatPromptsLinkedList = new LinkedList(); 20 | 21 | // Loop through the ChatMessages and add them to the LinkedList 22 | foreach (var item in ChatMessages) 23 | { 24 | // Do not add the system message to the chat prompts 25 | // because we will add this manully later 26 | if (item.Prompt == SystemMessage) 27 | { 28 | continue; 29 | } 30 | ChatPromptsLinkedList.AddLast(item); 31 | } 32 | 33 | // Set the current word count to 0 34 | int CurrentWordCount = 0; 35 | 36 | // Reverse the chat messages to start from the most recent messages 37 | foreach (var item in ChatPromptsLinkedList.Reverse()) 38 | { 39 | if (item.Prompt != null) 40 | { 41 | int promptWordCount = item.Prompt.Split( 42 | new char[] { ' ', '\t', '\n', '\r' }, 43 | StringSplitOptions.RemoveEmptyEntries).Length; 44 | 45 | if (CurrentWordCount + promptWordCount >= 1000) 46 | { 47 | // This message would cause the total to exceed 1000 words, 48 | // so break out of the loop 49 | break; 50 | } 51 | // Add the message to the chat prompts 52 | chatPrompts.Insert( 53 | 0, 54 | new Message(item.Role, item.Prompt, item.FunctionName)); 55 | CurrentWordCount += promptWordCount; 56 | } 57 | } 58 | 59 | // Add the first message to the chat prompts to indicate the System message 60 | chatPrompts.Insert(0, 61 | new Message( 62 | Role.System, 63 | SystemMessage 64 | ) 65 | ); 66 | 67 | return chatPrompts; 68 | } 69 | #endregion 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Model/VectorData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace AIOrchestrator.Model 8 | { 9 | public class VectorData 10 | { 11 | public double VectorValue { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Pages/Counter.razor: -------------------------------------------------------------------------------- 1 | @page "/counter" 2 | 3 |

Counter

4 | 5 |

Current count: @currentCount

6 | 7 | 8 | 9 | @code { 10 | private int currentCount = 0; 11 | 12 | private void IncrementCount() 13 | { 14 | currentCount++; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Pages/Home.razor: -------------------------------------------------------------------------------- 1 | @using AIOrchestrator.Model; 2 | @using Newtonsoft.Json; 3 | @using OpenAI; 4 | @using static AIOrchestrator.Model.OrchestratorMethods; 5 | @inject NotificationService NotificationService 6 | @inject DialogService DialogService 7 | @inject SettingsService SettingsService 8 | @inject LogService LogService 9 | @inject OrchestratorMethods OrchestratorMethods 10 | @implements IDisposable 11 |

Home

12 | @if (@InProgress) 13 | { 14 |
15 | 16 |
17 | } 18 | 19 |
20 |
21 | Select File: 22 | 27 |
28 |
29 |
30 | 31 | 32 | 33 |
34 |
35 |    38 |
39 |
40 | 41 |
42 | 43 |
44 |
45 |    48 | Chunk Size (words):   49 |    50 | Max Iterations:   51 |
52 |
53 | 54 |
55 | 56 |
57 |
58 |    61 | Chunk Size (words):   62 |    63 | Max Iterations:   64 |
65 |
66 | 67 |
68 | 69 |
70 |
71 | Chunk Size (words):   72 |    73 | Max Iterations:   74 |

75 |
76 |
77 |      80 | @if (colCharacters.Count > 0) 81 | { 82 | 85 | } 86 |
87 |
88 |
89 |
90 | 91 |
92 | 93 |
94 |
95 | Chunk Size (words):   96 |    97 | Max Iterations:   98 |

99 |
100 |
101 | @if (!StoryLoaded) 102 | { 103 | 106 | } 107 |
108 |
109 |
110 |
111 | @if (StoryLoaded) 112 | { 113 | 114 | }  
115 | @if (StoryLoaded) 116 | { 117 | Select Model: 118 | 121 | }   122 | @if (StoryLoaded) 123 | { 124 | 127 | }   128 | @if (StoryLoaded) 129 | { 130 | 133 | }   134 |
135 | 136 |
137 |
138 | Chunk Size (words):   139 |    140 | Max Iterations:   141 |

142 |
143 |
144 | @if (!StoryLoaded) 145 | { 146 | 149 | } 150 |
151 |
152 |
153 |
154 | @if (StoryLoaded) 155 | { 156 | 157 | 158 | }  
159 | @if (StoryLoaded) 160 | { 161 | Select Model: 162 | 165 | }   166 | @if (StoryLoaded) 167 | { 168 | 171 | }   172 | @if (StoryLoaded) 173 | { 174 | 177 | }   178 |
179 |
180 |
181 | @code { 182 | private string TextFileRaw = ""; 183 | private string txtSummarizeTextShort = ""; 184 | private string txtSummarizeTextLong = ""; 185 | private string txtSummarizeCharacter = ""; 186 | private bool StoryLoaded = false; 187 | private string txtNewStory = ""; 188 | string txtChapterDescription = ""; 189 | string txtNewChapter = ""; 190 | private List colModels = new List() { "gpt-3.5-turbo", "gpt-4" }; 191 | string SelectedModel = "gpt-3.5-turbo"; 192 | private string SelectedCharacter = ""; 193 | private List colCharacters = new List(); 194 | bool InProgress = false; 195 | 196 | List DocumentFiles = new List(); 197 | string SelectedFile { get; set; } 198 | 199 | int intMaxLoops = 3; 200 | int intChunkSize = 2000; 201 | 202 | protected override void OnInitialized() 203 | { 204 | // Get the list of files in the Documents directory 205 | var DocumentPath = $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}\\AIOrchestrator\\Documents"; 206 | var dir = new DirectoryInfo(DocumentPath); 207 | DocumentFiles = dir.GetFiles().ToList(); 208 | 209 | if (DocumentFiles.Count > 0) 210 | { 211 | SelectedFile = DocumentFiles[0].FullName; 212 | } 213 | 214 | OrchestratorMethods.ReadTextEvent += OrchestratorMethods_ReadTextEvent; 215 | } 216 | 217 | private async Task LoadText() 218 | { 219 | try 220 | { 221 | InProgress = true; 222 | 223 | // Open the file to get existing content 224 | using (var streamReader = new StreamReader(SelectedFile)) 225 | { 226 | TextFileRaw = await streamReader.ReadToEndAsync(); 227 | } 228 | 229 | InProgress = false; 230 | } 231 | catch (Exception ex) 232 | { 233 | LogService.WriteToLog($"Error: {ex.Message}"); 234 | 235 | NotificationService.Notify(new NotificationMessage 236 | { 237 | Severity = NotificationSeverity.Error, 238 | Summary = "Error", 239 | Detail = ex.Message, 240 | Duration = 4000 241 | }); 242 | } 243 | } 244 | 245 | private async Task SummarizeTextShort() 246 | { 247 | try 248 | { 249 | InProgress = true; 250 | 251 | ClearLog(); 252 | 253 | txtSummarizeTextShort = await OrchestratorMethods.ReadTextShort(SelectedFile, intMaxLoops, intChunkSize); 254 | InProgress = false; 255 | } 256 | catch (Exception ex) 257 | { 258 | LogService.WriteToLog($"Error: {ex.Message}"); 259 | 260 | NotificationService.Notify(new NotificationMessage 261 | { 262 | Severity = NotificationSeverity.Error, 263 | Summary = "Error", 264 | Detail = ex.Message, 265 | Duration = 4000 266 | }); 267 | } 268 | } 269 | 270 | private async Task SummarizeTextLong() 271 | { 272 | try 273 | { 274 | InProgress = true; 275 | 276 | ClearLog(); 277 | ClearMemory(""); 278 | 279 | txtSummarizeTextLong = await OrchestratorMethods.ReadTextLong(SelectedFile, intMaxLoops, intChunkSize); 280 | InProgress = false; 281 | 282 | NotificationService.Notify(new NotificationMessage 283 | { 284 | Severity = NotificationSeverity.Success, 285 | Summary = "Data Indexed", 286 | Detail = "You can perform a vector search on the Memory page", 287 | Duration = 8000 288 | }); 289 | } 290 | catch (Exception ex) 291 | { 292 | LogService.WriteToLog($"Error: {ex.Message}"); 293 | 294 | NotificationService.Notify(new NotificationMessage 295 | { 296 | Severity = NotificationSeverity.Error, 297 | Summary = "Error", 298 | Detail = ex.Message, 299 | Duration = 4000 300 | }); 301 | } 302 | } 303 | 304 | private async Task LoadCharacters() 305 | { 306 | try 307 | { 308 | InProgress = true; 309 | 310 | ClearLog(); 311 | 312 | colCharacters = await OrchestratorMethods.LoadCharacters(SelectedFile, intMaxLoops, intChunkSize); 313 | InProgress = false; 314 | } 315 | catch (Exception ex) 316 | { 317 | LogService.WriteToLog($"Error: {ex.Message}"); 318 | 319 | NotificationService.Notify(new NotificationMessage 320 | { 321 | Severity = NotificationSeverity.Error, 322 | Summary = "Error", 323 | Detail = ex.Message, 324 | Duration = 4000 325 | }); 326 | } 327 | } 328 | 329 | private async Task SummarizeCharacter() 330 | { 331 | try 332 | { 333 | if (SelectedCharacter == "") 334 | { 335 | NotificationService.Notify(new NotificationMessage 336 | { 337 | Severity = NotificationSeverity.Error, 338 | Summary = "Error", 339 | Detail = "Please select a character", 340 | Duration = 4000 341 | }); 342 | 343 | return; 344 | } 345 | 346 | InProgress = true; 347 | 348 | ClearLog(); 349 | ClearMemory(""); 350 | 351 | txtSummarizeCharacter = await OrchestratorMethods.SummarizeCharacter(SelectedFile, SelectedCharacter, intMaxLoops, intChunkSize); 352 | InProgress = false; 353 | 354 | NotificationService.Notify(new NotificationMessage 355 | { 356 | Severity = NotificationSeverity.Success, 357 | Summary = "Data Indexed", 358 | Detail = "You can perform a vector search on the Memory page", 359 | Duration = 8000 360 | }); 361 | } 362 | catch (Exception ex) 363 | { 364 | LogService.WriteToLog($"Error: {ex.Message}"); 365 | 366 | NotificationService.Notify(new NotificationMessage 367 | { 368 | Severity = NotificationSeverity.Error, 369 | Summary = "Error", 370 | Detail = ex.Message, 371 | Duration = 4000 372 | }); 373 | } 374 | } 375 | 376 | private async Task LoadStory() 377 | { 378 | try 379 | { 380 | InProgress = true; 381 | 382 | StoryLoaded = false; 383 | ClearLog(); 384 | ClearMemory(SelectedFile); 385 | 386 | StoryLoaded = await OrchestratorMethods.LoadStory(SelectedFile, intMaxLoops, intChunkSize); 387 | InProgress = false; 388 | 389 | NotificationService.Notify(new NotificationMessage 390 | { 391 | Severity = NotificationSeverity.Success, 392 | Summary = "Data Indexed", 393 | Detail = "You can perform a vector search on the Memory page", 394 | Duration = 8000 395 | }); 396 | } 397 | catch (Exception ex) 398 | { 399 | LogService.WriteToLog($"Error: {ex.Message}"); 400 | 401 | NotificationService.Notify(new NotificationMessage 402 | { 403 | Severity = NotificationSeverity.Error, 404 | Summary = "Error", 405 | Detail = ex.Message, 406 | Duration = 4000 407 | }); 408 | } 409 | } 410 | 411 | private void ResetStory() 412 | { 413 | try 414 | { 415 | InProgress = true; 416 | 417 | StoryLoaded = false; 418 | 419 | ClearLog(); 420 | ClearMemory(""); 421 | 422 | InProgress = false; 423 | } 424 | catch (Exception ex) 425 | { 426 | LogService.WriteToLog($"Error: {ex.Message}"); 427 | 428 | NotificationService.Notify(new NotificationMessage 429 | { 430 | Severity = NotificationSeverity.Error, 431 | Summary = "Error", 432 | Detail = ex.Message, 433 | Duration = 4000 434 | }); 435 | } 436 | } 437 | 438 | private async Task CompleteStory() 439 | { 440 | try 441 | { 442 | InProgress = true; 443 | 444 | var result = await OrchestratorMethods.CompleteStory(txtNewStory, SelectedModel); 445 | InProgress = false; 446 | 447 | txtNewStory = result; 448 | 449 | NotificationService.Notify(new NotificationMessage 450 | { 451 | Severity = NotificationSeverity.Success, 452 | Summary = "Story Complete", 453 | Detail = "Processed", 454 | Duration = 4000 455 | }); 456 | } 457 | catch (Exception ex) 458 | { 459 | LogService.WriteToLog($"Error: {ex.Message}"); 460 | 461 | NotificationService.Notify(new NotificationMessage 462 | { 463 | Severity = NotificationSeverity.Error, 464 | Summary = "Error", 465 | Detail = ex.Message, 466 | Duration = 4000 467 | }); 468 | } 469 | } 470 | 471 | private async Task CompleteChapter() 472 | { 473 | try 474 | { 475 | InProgress = true; 476 | 477 | txtNewChapter = ""; 478 | 479 | // Trim the description to 500 words 480 | txtChapterDescription = OrchestratorMethods.TrimToMaxWords(txtChapterDescription, 500); 481 | 482 | var result = await OrchestratorMethods.CompleteChapter(txtChapterDescription, SelectedModel); 483 | InProgress = false; 484 | 485 | txtNewChapter = result; 486 | 487 | NotificationService.Notify(new NotificationMessage 488 | { 489 | Severity = NotificationSeverity.Success, 490 | Summary = "Chapter Complete", 491 | Detail = "Processed", 492 | Duration = 4000 493 | }); 494 | } 495 | catch (Exception ex) 496 | { 497 | LogService.WriteToLog($"Error: {ex.Message}"); 498 | 499 | NotificationService.Notify(new NotificationMessage 500 | { 501 | Severity = NotificationSeverity.Error, 502 | Summary = "Error", 503 | Detail = ex.Message, 504 | Duration = 4000 505 | }); 506 | } 507 | } 508 | 509 | // Events 510 | 511 | private void OrchestratorMethods_ReadTextEvent(object sender, EventArgs e) 512 | { 513 | ReadTextEventArgs ReadTextEventArguments = (ReadTextEventArgs)e; 514 | 515 | NotificationService.Notify(new NotificationMessage 516 | { 517 | Severity = NotificationSeverity.Info, 518 | Summary = "Info", 519 | Detail = ReadTextEventArguments.Message, 520 | Duration = 4000 521 | }); 522 | } 523 | 524 | void OnTabChange(int index) 525 | { 526 | if ((index == 4) || (index == 5)) // Complete Story Tab 527 | { 528 | // Read the first line to see if the latest story is loaded 529 | var AIOrchestratorMemoryPath = 530 | $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/AIOrchestrator/AIOrchestratorMemory.csv"; 531 | 532 | string firstLine = ""; 533 | using (StreamReader sr = new StreamReader(AIOrchestratorMemoryPath)) 534 | { 535 | firstLine = sr.ReadLine(); 536 | } 537 | 538 | // Get the filename from the path 539 | string fileName = Path.GetFileName(SelectedFile); 540 | 541 | if (firstLine != (fileName + "|")) 542 | { 543 | StoryLoaded = false; 544 | } 545 | else 546 | { 547 | StoryLoaded = true; 548 | } 549 | } 550 | } 551 | 552 | void OnDropdownChange() 553 | { 554 | // Read the first line to see if the latest story is loaded 555 | var AIOrchestratorMemoryPath = 556 | $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/AIOrchestrator/AIOrchestratorMemory.csv"; 557 | 558 | string firstLine = ""; 559 | using (StreamReader sr = new StreamReader(AIOrchestratorMemoryPath)) 560 | { 561 | firstLine = sr.ReadLine(); 562 | } 563 | 564 | // Get the filename from the path 565 | string fileName = Path.GetFileName(SelectedFile); 566 | 567 | if (firstLine != (fileName + "|")) 568 | { 569 | StoryLoaded = false; 570 | } 571 | else 572 | { 573 | StoryLoaded = true; 574 | } 575 | } 576 | 577 | public void Dispose() 578 | { 579 | OrchestratorMethods.ReadTextEvent -= OrchestratorMethods_ReadTextEvent; 580 | } 581 | 582 | // Utility 583 | 584 | private void ClearLog() 585 | { 586 | try 587 | { 588 | var AIOrchestratorLogPath = $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/AIOrchestrator/AIOrchestratorLog.csv"; 589 | 590 | using (var streamWriter = new StreamWriter(AIOrchestratorLogPath)) 591 | { 592 | streamWriter.WriteLine(string.Join("\n", "Log cleared on " + DateTime.Now)); 593 | } 594 | } 595 | catch (Exception ex) 596 | { 597 | NotificationService.Notify(new NotificationMessage 598 | { 599 | Severity = NotificationSeverity.Error, 600 | Summary = "Error", 601 | Detail = ex.Message, 602 | Duration = 4000 603 | }); 604 | } 605 | } 606 | 607 | private void ClearMemory(string paramSelectedFile) 608 | { 609 | try 610 | { 611 | var AIOrchestratorMemoryPath = 612 | $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/AIOrchestrator/AIOrchestratorMemory.csv"; 613 | 614 | using (var streamWriter = new StreamWriter(AIOrchestratorMemoryPath)) 615 | { 616 | if (paramSelectedFile == "") 617 | { 618 | streamWriter.WriteLine("** AIOrchestratorMemory started at " + DateTime.Now + "|"); 619 | } 620 | else 621 | { 622 | // Get the filename from the path 623 | string fileName = Path.GetFileName(paramSelectedFile); 624 | streamWriter.WriteLine(fileName + "|"); 625 | } 626 | } 627 | } 628 | catch (Exception ex) 629 | { 630 | NotificationService.Notify(new NotificationMessage 631 | { 632 | Severity = NotificationSeverity.Error, 633 | Summary = "Error", 634 | Detail = ex.Message, 635 | Duration = 4000 636 | }); 637 | } 638 | } 639 | } -------------------------------------------------------------------------------- /Pages/Index.razor: -------------------------------------------------------------------------------- 1 | @page "/" 2 | @using System.IO 3 | @using System.Threading.Tasks 4 | @using Microsoft.AspNetCore.Components.Forms 5 | @using Newtonsoft.Json; 6 | 7 | 8 | 9 | 10 | 11 | 12 | @if (HomeVisible) 13 | { 14 | 15 | } 16 | @if (SettingsVisible) 17 | { 18 | 19 | } 20 | @if (MemoryVisible) 21 | { 22 | 23 | } 24 | @if (LogsVisible) 25 | { 26 | 27 | } 28 | @code { 29 | bool HomeVisible = true; 30 | bool SettingsVisible = false; 31 | bool MemoryVisible = false; 32 | bool LogsVisible = false; 33 | 34 | void OnHomeClicked(MenuItemEventArgs args) 35 | { 36 | HomeVisible = true; 37 | SettingsVisible = false; 38 | MemoryVisible = false; 39 | LogsVisible = false; 40 | } 41 | 42 | void OnSettingsClicked(MenuItemEventArgs args) 43 | { 44 | HomeVisible = false; 45 | SettingsVisible = true; 46 | MemoryVisible = false; 47 | LogsVisible = false; 48 | } 49 | 50 | void OnMemoryClicked(MenuItemEventArgs args) 51 | { 52 | HomeVisible = false; 53 | SettingsVisible = false; 54 | MemoryVisible = true; 55 | LogsVisible = false; 56 | } 57 | 58 | void OnLogsClicked(MenuItemEventArgs args) 59 | { 60 | HomeVisible = false; 61 | SettingsVisible = false; 62 | MemoryVisible = false; 63 | LogsVisible = true; 64 | } 65 | } -------------------------------------------------------------------------------- /Pages/Logs.razor: -------------------------------------------------------------------------------- 1 | @inject NotificationService NotificationService 2 | @inject DialogService DialogService 3 |

Logs

4 |
5 |
6 |    9 |
10 |
11 | 14 | 15 | 16 | 21 | 22 | 23 | 24 | 25 | 26 | @code { 27 | string AIOrchestratorLogPath = ""; 28 | string[] AIOrchestratorLog; 29 | 30 | protected override void OnInitialized() 31 | { 32 | AIOrchestratorLogPath = 33 | $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/AIOrchestrator/AIOrchestratorLog.csv"; 34 | 35 | // Read the lines from the .csv file 36 | using (var file = new System.IO.StreamReader(AIOrchestratorLogPath)) 37 | { 38 | AIOrchestratorLog = file.ReadToEnd().Split('\n'); 39 | if (AIOrchestratorLog[AIOrchestratorLog.Length - 1].Trim() == "") 40 | { 41 | AIOrchestratorLog = AIOrchestratorLog.Take(AIOrchestratorLog.Length - 1).ToArray(); 42 | } 43 | } 44 | } 45 | 46 | private void ClearLog() 47 | { 48 | try 49 | { 50 | using (var streamWriter = new StreamWriter(AIOrchestratorLogPath)) 51 | { 52 | streamWriter.WriteLine(string.Join("\n", "Log cleared on " + DateTime.Now)); 53 | } 54 | 55 | // Read the lines from the .csv file 56 | using (var file = new System.IO.StreamReader(AIOrchestratorLogPath)) 57 | { 58 | AIOrchestratorLog = file.ReadToEnd().Split('\n'); 59 | if (AIOrchestratorLog[AIOrchestratorLog.Length - 1].Trim() == "") 60 | { 61 | AIOrchestratorLog = AIOrchestratorLog.Take(AIOrchestratorLog.Length - 1).ToArray(); 62 | } 63 | } 64 | 65 | NotificationService.Notify(new NotificationMessage 66 | { 67 | Severity = NotificationSeverity.Success, 68 | Summary = "Success", 69 | Detail = "Log Cleared", 70 | Duration = 4000 71 | }); 72 | } 73 | catch (Exception ex) 74 | { 75 | NotificationService.Notify(new NotificationMessage 76 | { 77 | Severity = NotificationSeverity.Error, 78 | Summary = "Error", 79 | Detail = ex.Message, 80 | Duration = 4000 81 | }); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Pages/Memory.razor: -------------------------------------------------------------------------------- 1 | @using AIOrchestrator.Model; 2 | @using Newtonsoft.Json; 3 | @using OpenAI; 4 | @inject NotificationService NotificationService 5 | @inject DialogService DialogService 6 | @inject SettingsService SettingsService 7 | @inject OrchestratorMethods OrchestratorMethods 8 |

Memory

9 |
10 |
11 |    14 |    17 |    20 |
21 |
22 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | @code { 33 | RadzenDataGrid> MemoryGrid; 34 | string AIOrchestratorMemoryPath = ""; 35 | Dictionary AIOrchestratorMemory = new Dictionary(); 36 | List<(string, float)> similarities = new List<(string, float)>(); 37 | 38 | protected override void OnInitialized() 39 | { 40 | AIOrchestratorMemoryPath = 41 | $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/AIOrchestrator/AIOrchestratorMemory.csv"; 42 | 43 | // Read the lines from the .csv file 44 | foreach (var line in System.IO.File.ReadAllLines(AIOrchestratorMemoryPath)) 45 | { 46 | try 47 | { 48 | var splitLine = line.Split('|'); 49 | var KEY = splitLine[0]; 50 | var VALUE = splitLine[1]; 51 | 52 | AIOrchestratorMemory.Add(KEY, VALUE); 53 | } 54 | catch { } 55 | } 56 | } 57 | 58 | private async Task AddMemory() 59 | { 60 | try 61 | { 62 | string MemoryText = ""; 63 | 64 | // Display inline Radzen dialog to capture text 65 | var result = await DialogService.OpenAsync("New Memory", ds => 66 | @ 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | ); 76 | 77 | if (result) 78 | { 79 | // **** Call OpenAI and get embeddings for the memory text 80 | // Create an instance of the OpenAI client 81 | var api = new OpenAIClient(new OpenAIAuthentication(SettingsService.ApiKey, SettingsService.Organization)); 82 | // Get the model details 83 | var model = await api.ModelsEndpoint.GetModelDetailsAsync("text-embedding-ada-002"); 84 | // Get embeddings for the text 85 | var embeddings = await api.EmbeddingsEndpoint.CreateEmbeddingAsync(MemoryText, model); 86 | // Get embeddings as an array of floats 87 | var EmbeddingVectors = embeddings.Data[0].Embedding.Select(d => (float)d).ToArray(); 88 | // Loop through the embeddings 89 | List AllVectors = new List(); 90 | for (int i = 0; i < EmbeddingVectors.Length; i++) 91 | { 92 | var embeddingVector = new VectorData 93 | { 94 | VectorValue = EmbeddingVectors[i] 95 | }; 96 | AllVectors.Add(embeddingVector); 97 | } 98 | // Convert the floats to a single string 99 | var VectorsToSave = "[" + string.Join(",", AllVectors.Select(x => x.VectorValue)) + "]"; 100 | 101 | // Write the memory to the .csv file 102 | using (var streamWriter = new StreamWriter(AIOrchestratorMemoryPath, true)) 103 | { 104 | streamWriter.WriteLine(MemoryText + "|" + VectorsToSave); 105 | } 106 | 107 | // Add the memory to the dictionary 108 | AIOrchestratorMemory.Add(MemoryText, VectorsToSave); 109 | await MemoryGrid.Reload(); 110 | 111 | NotificationService.Notify(new NotificationMessage 112 | { 113 | Severity = NotificationSeverity.Success, 114 | Summary = "Success", 115 | Detail = $"Memory Added", 116 | Duration = 4000 117 | }); 118 | } 119 | } 120 | catch (Exception ex) 121 | { 122 | NotificationService.Notify(new NotificationMessage 123 | { 124 | Severity = NotificationSeverity.Error, 125 | Summary = "Error", 126 | Detail = ex.Message, 127 | Duration = 4000 128 | }); 129 | } 130 | } 131 | 132 | private async Task SearchMemory() 133 | { 134 | try 135 | { 136 | string SearchText = ""; 137 | 138 | // Display inline Radzen dialog to capture text 139 | var result = await DialogService.OpenAsync("Search Memory", ds => 140 | @ 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | ); 150 | 151 | if (result) 152 | { 153 | List<(string, float)> FinalResults = await OrchestratorMethods.SearchMemory(SearchText, 10); 154 | 155 | // Display inline Radzen dialog to capture text 156 | await DialogService.OpenAsync("Search Results", ds => 157 | @ 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | ); 166 | 167 | } 168 | 169 | } 170 | catch (Exception ex) 171 | { 172 | NotificationService.Notify(new NotificationMessage 173 | { 174 | Severity = NotificationSeverity.Error, 175 | Summary = "Error", 176 | Detail = ex.Message, 177 | Duration = 4000 178 | }); 179 | } 180 | } 181 | 182 | 183 | private async Task ClearMemory() 184 | { 185 | try 186 | { 187 | AIOrchestratorMemory = new Dictionary(); 188 | 189 | using (var streamWriter = new StreamWriter(AIOrchestratorMemoryPath)) 190 | { 191 | streamWriter.WriteLine("** AIOrchestratorMemory started at " + DateTime.Now + "|"); 192 | } 193 | 194 | // Read the lines from the .csv file 195 | foreach (var line in System.IO.File.ReadAllLines(AIOrchestratorMemoryPath)) 196 | { 197 | var splitLine = line.Split('|'); 198 | var KEY = splitLine[0]; 199 | var VALUE = splitLine[1]; 200 | 201 | AIOrchestratorMemory.Add(KEY, VALUE); 202 | } 203 | await MemoryGrid.Reload(); 204 | 205 | NotificationService.Notify(new NotificationMessage 206 | { 207 | Severity = NotificationSeverity.Success, 208 | Summary = "Success", 209 | Detail = "Log Cleared", 210 | Duration = 4000 211 | }); 212 | } 213 | catch (Exception ex) 214 | { 215 | NotificationService.Notify(new NotificationMessage 216 | { 217 | Severity = NotificationSeverity.Error, 218 | Summary = "Error", 219 | Detail = ex.Message, 220 | Duration = 4000 221 | }); 222 | } 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /Pages/Settings.razor: -------------------------------------------------------------------------------- 1 | @using AIOrchestrator.Model; 2 | @using Newtonsoft.Json; 3 | @inject NotificationService NotificationService 4 | @inject DialogService DialogService 5 | @inject SettingsService SettingsService 6 |

Settings

7 |
8 |
9 | 10 | 11 | 12 |
13 |
14 | 15 | 16 | 17 |
18 |
19 |
20 |
21 |
22 |    25 |
26 |
27 | @code { 28 | 29 | Variant variant = Variant.Outlined; 30 | 31 | dynamic AIOrchestratorSettingsObject; 32 | string AIOrchestratorSettingsPath = ""; 33 | string AIOrchestratorSettings = ""; 34 | string Organization = ""; 35 | string ApiKey = ""; 36 | 37 | protected override void OnInitialized() 38 | { 39 | // AIOrchestrator Directory 40 | AIOrchestratorSettingsPath = 41 | $"{Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)}/AIOrchestrator/AIOrchestratorSettings.config"; 42 | 43 | // Open the file to get existing content 44 | using (var streamReader = new StreamReader(AIOrchestratorSettingsPath)) 45 | { 46 | AIOrchestratorSettings = streamReader.ReadToEnd(); 47 | } 48 | 49 | // Convert the JSON to a dynamic object 50 | AIOrchestratorSettingsObject = JsonConvert.DeserializeObject(AIOrchestratorSettings); 51 | Organization = AIOrchestratorSettingsObject.OpenAIServiceOptions.Organization; 52 | ApiKey = AIOrchestratorSettingsObject.OpenAIServiceOptions.ApiKey; 53 | } 54 | 55 | private async Task SettingsSave() 56 | { 57 | try 58 | { 59 | // Update the dynamic object 60 | AIOrchestratorSettingsObject.OpenAIServiceOptions.Organization = Organization; 61 | AIOrchestratorSettingsObject.OpenAIServiceOptions.ApiKey = ApiKey; 62 | 63 | // Convert the dynamic object back to JSON 64 | AIOrchestratorSettings = JsonConvert.SerializeObject(AIOrchestratorSettingsObject, Formatting.Indented); 65 | 66 | // Write the JSON back to the file 67 | using (var streamWriter = new StreamWriter(AIOrchestratorSettingsPath)) 68 | { 69 | await streamWriter.WriteAsync(AIOrchestratorSettings); 70 | } 71 | 72 | SettingsService.ReloadSettings(); 73 | 74 | NotificationService.Notify(new NotificationMessage 75 | { 76 | Severity = NotificationSeverity.Success, 77 | Summary = "Success", 78 | Detail = "Saved", 79 | Duration = 4000 80 | }); 81 | } 82 | catch (Exception ex) 83 | { 84 | NotificationService.Notify(new NotificationMessage 85 | { 86 | Severity = NotificationSeverity.Error, 87 | Summary = "Error", 88 | Detail = ex.Message, 89 | Duration = 4000 90 | }); 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /Platforms/Android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Platforms/Android/MainActivity.cs: -------------------------------------------------------------------------------- 1 | using Android.App; 2 | using Android.Content.PM; 3 | using Android.OS; 4 | 5 | namespace AIOrchestrator 6 | { 7 | [Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)] 8 | public class MainActivity : MauiAppCompatActivity 9 | { 10 | } 11 | } -------------------------------------------------------------------------------- /Platforms/Android/MainApplication.cs: -------------------------------------------------------------------------------- 1 | using Android.App; 2 | using Android.Runtime; 3 | 4 | namespace AIOrchestrator 5 | { 6 | [Application] 7 | public class MainApplication : MauiApplication 8 | { 9 | public MainApplication(IntPtr handle, JniHandleOwnership ownership) 10 | : base(handle, ownership) 11 | { 12 | } 13 | 14 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); 15 | } 16 | } -------------------------------------------------------------------------------- /Platforms/Android/Resources/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #512BD4 4 | #2B0B98 5 | #2B0B98 6 | -------------------------------------------------------------------------------- /Platforms/MacCatalyst/AppDelegate.cs: -------------------------------------------------------------------------------- 1 | using Foundation; 2 | 3 | namespace AIOrchestrator 4 | { 5 | [Register("AppDelegate")] 6 | public class AppDelegate : MauiUIApplicationDelegate 7 | { 8 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); 9 | } 10 | } -------------------------------------------------------------------------------- /Platforms/MacCatalyst/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIDeviceFamily 6 | 7 | 1 8 | 2 9 | 10 | UIRequiredDeviceCapabilities 11 | 12 | arm64 13 | 14 | UISupportedInterfaceOrientations 15 | 16 | UIInterfaceOrientationPortrait 17 | UIInterfaceOrientationLandscapeLeft 18 | UIInterfaceOrientationLandscapeRight 19 | 20 | UISupportedInterfaceOrientations~ipad 21 | 22 | UIInterfaceOrientationPortrait 23 | UIInterfaceOrientationPortraitUpsideDown 24 | UIInterfaceOrientationLandscapeLeft 25 | UIInterfaceOrientationLandscapeRight 26 | 27 | XSAppIconAssets 28 | Assets.xcassets/appicon.appiconset 29 | 30 | 31 | -------------------------------------------------------------------------------- /Platforms/MacCatalyst/Program.cs: -------------------------------------------------------------------------------- 1 | using ObjCRuntime; 2 | using UIKit; 3 | 4 | namespace AIOrchestrator 5 | { 6 | public class Program 7 | { 8 | // This is the main entry point of the application. 9 | static void Main(string[] args) 10 | { 11 | // if you want to use a different Application Delegate class from "AppDelegate" 12 | // you can specify it here. 13 | UIApplication.Main(args, null, typeof(AppDelegate)); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /Platforms/Tizen/Main.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Maui; 2 | using Microsoft.Maui.Hosting; 3 | using System; 4 | 5 | namespace AIOrchestrator 6 | { 7 | internal class Program : MauiApplication 8 | { 9 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); 10 | 11 | static void Main(string[] args) 12 | { 13 | var app = new Program(); 14 | app.Run(args); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Platforms/Tizen/tizen-manifest.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | maui-appicon-placeholder 7 | 8 | 9 | 10 | 11 | http://tizen.org/privilege/internet 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Platforms/Windows/App.xaml: -------------------------------------------------------------------------------- 1 |  7 | 8 | 9 | -------------------------------------------------------------------------------- /Platforms/Windows/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml; 2 | 3 | // To learn more about WinUI, the WinUI project structure, 4 | // and more about our project templates, see: http://aka.ms/winui-project-info. 5 | 6 | namespace AIOrchestrator.WinUI 7 | { 8 | /// 9 | /// Provides application-specific behavior to supplement the default Application class. 10 | /// 11 | public partial class App : MauiWinUIApplication 12 | { 13 | /// 14 | /// Initializes the singleton application object. This is the first line of authored code 15 | /// executed, and as such is the logical equivalent of main() or WinMain(). 16 | /// 17 | public App() 18 | { 19 | this.InitializeComponent(); 20 | } 21 | 22 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); 23 | } 24 | } -------------------------------------------------------------------------------- /Platforms/Windows/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | $placeholder$ 15 | User Name 16 | $placeholder$.png 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /Platforms/Windows/app.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | true/PM 12 | PerMonitorV2, PerMonitor 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Platforms/iOS/AppDelegate.cs: -------------------------------------------------------------------------------- 1 | using Foundation; 2 | 3 | namespace AIOrchestrator 4 | { 5 | [Register("AppDelegate")] 6 | public class AppDelegate : MauiUIApplicationDelegate 7 | { 8 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); 9 | } 10 | } -------------------------------------------------------------------------------- /Platforms/iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | LSRequiresIPhoneOS 6 | 7 | UIDeviceFamily 8 | 9 | 1 10 | 2 11 | 12 | UIRequiredDeviceCapabilities 13 | 14 | arm64 15 | 16 | UISupportedInterfaceOrientations 17 | 18 | UIInterfaceOrientationPortrait 19 | UIInterfaceOrientationLandscapeLeft 20 | UIInterfaceOrientationLandscapeRight 21 | 22 | UISupportedInterfaceOrientations~ipad 23 | 24 | UIInterfaceOrientationPortrait 25 | UIInterfaceOrientationPortraitUpsideDown 26 | UIInterfaceOrientationLandscapeLeft 27 | UIInterfaceOrientationLandscapeRight 28 | 29 | XSAppIconAssets 30 | Assets.xcassets/appicon.appiconset 31 | 32 | 33 | -------------------------------------------------------------------------------- /Platforms/iOS/Program.cs: -------------------------------------------------------------------------------- 1 | using ObjCRuntime; 2 | using UIKit; 3 | 4 | namespace AIOrchestrator 5 | { 6 | public class Program 7 | { 8 | // This is the main entry point of the application. 9 | static void Main(string[] args) 10 | { 11 | // if you want to use a different Application Delegate class from "AppDelegate" 12 | // you can specify it here. 13 | UIApplication.Main(args, null, typeof(AppDelegate)); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Windows Machine": { 4 | "commandName": "MsixPackage", 5 | "nativeDebugging": false 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AIOrchestrator 2 | ##### "This allows you to import a book and have it write an original chapter based on your description." 3 | 4 | ## A sub Project of [AIStoryBuilders](https://github.com/AIStoryBuilders) 5 | 6 | * [AIStoryBuilders](https://github.com/AIStoryBuilders/AIStoryBuilders) 7 | 8 | ## Read the Blog post describing this project 9 | 10 | [Processing Large Amounts of Text in LLM Models](https://blazorhelpwebsite.com/ViewBlogPost/12069) 11 | 12 | ![image](https://github.com/ADefWebserver/AIOrchestrator/assets/1857799/39b7bab3-9932-47b5-adb3-11d00e2cca8c) 13 | 14 | ![image](https://github.com/ADefWebserver/AIOrchestrator/assets/1857799/25b6189a-b40f-4397-b71a-e4c262b2e56b) 15 | 16 | ![image](https://github.com/ADefWebserver/AIOrchestrator/assets/1857799/fc84de22-af6d-48d3-9693-d4ee341facbe) 17 | 18 | ![image](https://github.com/ADefWebserver/AIOrchestrator/assets/1857799/d8bc287f-5493-44e0-bdb6-6019636b23cf) 19 | -------------------------------------------------------------------------------- /Resources/AppIcon/appicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Resources/AppIcon/appiconfg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Resources/Fonts/OpenSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIStoryBuilders/AIOrchestrator/596676d7294a32431b2621b248887eb99b1f979c/Resources/Fonts/OpenSans-Regular.ttf -------------------------------------------------------------------------------- /Resources/Images/dotnet_bot.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /Resources/Splash/splash.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Shared/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @inherits LayoutComponentBase 2 | 3 | 4 | 5 | 6 |
7 | 10 | 11 |
12 | @Body 13 |
14 |
15 | 16 |
17 |
18 | © @year 19 |
20 |
21 |
22 | @code { 23 | private string year = DateTime.Now.Year.ToString(); 24 | } -------------------------------------------------------------------------------- /Shared/MainLayout.razor.css: -------------------------------------------------------------------------------- 1 | .page { 2 | position: relative; 3 | display: flex; 4 | flex-direction: column; 5 | } 6 | 7 | main { 8 | flex: 1; 9 | } 10 | 11 | .sidebar { 12 | background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); 13 | } 14 | 15 | .top-row { 16 | background-color: #f7f7f7; 17 | border-bottom: 1px solid #d6d5d5; 18 | justify-content: flex-end; 19 | height: 3.5rem; 20 | display: flex; 21 | align-items: center; 22 | } 23 | 24 | .top-row ::deep a, .top-row ::deep .btn-link { 25 | white-space: nowrap; 26 | margin-left: 1.5rem; 27 | text-decoration: none; 28 | } 29 | 30 | .top-row ::deep a:hover, .top-row ::deep .btn-link:hover { 31 | text-decoration: underline; 32 | } 33 | 34 | .top-row ::deep a:first-child { 35 | overflow: hidden; 36 | text-overflow: ellipsis; 37 | } 38 | 39 | @media (max-width: 640.98px) { 40 | .top-row:not(.auth) { 41 | display: none; 42 | } 43 | 44 | .top-row.auth { 45 | justify-content: space-between; 46 | } 47 | 48 | .top-row ::deep a, .top-row ::deep .btn-link { 49 | margin-left: 0; 50 | } 51 | } 52 | 53 | @media (min-width: 641px) { 54 | .page { 55 | flex-direction: row; 56 | } 57 | 58 | .sidebar { 59 | width: 250px; 60 | height: 100vh; 61 | position: sticky; 62 | top: 0; 63 | } 64 | 65 | .top-row { 66 | position: sticky; 67 | top: 0; 68 | z-index: 1; 69 | } 70 | 71 | .top-row, article { 72 | padding-left: 2rem !important; 73 | padding-right: 1.5rem !important; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Shared/NavMenu.razor: -------------------------------------------------------------------------------- 1 |  9 | 10 |
11 | 28 |
29 | 30 | @code { 31 | private bool collapseNavMenu = true; 32 | 33 | private string NavMenuCssClass => collapseNavMenu ? "collapse" : null; 34 | 35 | private void ToggleNavMenu() 36 | { 37 | collapseNavMenu = !collapseNavMenu; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Shared/NavMenu.razor.css: -------------------------------------------------------------------------------- 1 | .navbar-toggler { 2 | background-color: rgba(255, 255, 255, 0.1); 3 | } 4 | 5 | .top-row { 6 | height: 3.5rem; 7 | background-color: rgba(0,0,0,0.4); 8 | } 9 | 10 | .navbar-brand { 11 | font-size: 1.1rem; 12 | } 13 | 14 | .oi { 15 | width: 2rem; 16 | font-size: 1.1rem; 17 | vertical-align: text-top; 18 | top: -2px; 19 | } 20 | 21 | .nav-item { 22 | font-size: 0.9rem; 23 | padding-bottom: 0.5rem; 24 | } 25 | 26 | .nav-item:first-of-type { 27 | padding-top: 1rem; 28 | } 29 | 30 | .nav-item:last-of-type { 31 | padding-bottom: 1rem; 32 | } 33 | 34 | .nav-item ::deep a { 35 | color: #d7d7d7; 36 | border-radius: 4px; 37 | height: 3rem; 38 | display: flex; 39 | align-items: center; 40 | line-height: 3rem; 41 | } 42 | 43 | .nav-item ::deep a.active { 44 | background-color: rgba(255,255,255,0.25); 45 | color: white; 46 | } 47 | 48 | .nav-item ::deep a:hover { 49 | background-color: rgba(255,255,255,0.1); 50 | color: white; 51 | } 52 | 53 | @media (min-width: 641px) { 54 | .navbar-toggler { 55 | display: none; 56 | } 57 | 58 | .collapse { 59 | /* Never collapse the sidebar for wide screens */ 60 | display: block; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using Microsoft.AspNetCore.Components.Forms 3 | @using Microsoft.AspNetCore.Components.Routing 4 | @using Microsoft.AspNetCore.Components.Web 5 | @using Microsoft.AspNetCore.Components.Web.Virtualization 6 | @using Microsoft.JSInterop 7 | @using AIOrchestrator 8 | @using AIOrchestrator.Shared 9 | @using Radzen 10 | @using Radzen.Blazor -------------------------------------------------------------------------------- /wwwroot/css/app.css: -------------------------------------------------------------------------------- 1 | @import url('open-iconic/font/css/open-iconic-bootstrap.min.css'); 2 | 3 | html, body { 4 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 5 | } 6 | 7 | h1:focus { 8 | outline: none; 9 | } 10 | 11 | a, .btn-link { 12 | color: #0071c1; 13 | } 14 | 15 | .btn-primary { 16 | color: #fff; 17 | background-color: #1b6ec2; 18 | border-color: #1861ac; 19 | } 20 | 21 | .content { 22 | padding-top: 1.1rem; 23 | } 24 | 25 | .valid.modified:not([type=checkbox]) { 26 | outline: 1px solid #26b050; 27 | } 28 | 29 | .invalid { 30 | outline: 1px solid red; 31 | } 32 | 33 | .validation-message { 34 | color: red; 35 | } 36 | 37 | #blazor-error-ui { 38 | background: lightyellow; 39 | bottom: 0; 40 | box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); 41 | display: none; 42 | left: 0; 43 | padding: 0.6rem 1.25rem 0.7rem 1.25rem; 44 | position: fixed; 45 | width: 100%; 46 | z-index: 1000; 47 | } 48 | 49 | #blazor-error-ui .dismiss { 50 | cursor: pointer; 51 | position: absolute; 52 | right: 0.75rem; 53 | top: 0.5rem; 54 | } 55 | 56 | .blazor-error-boundary { 57 | background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121; 58 | padding: 1rem 1rem 1rem 3.7rem; 59 | color: white; 60 | } 61 | 62 | .blazor-error-boundary::after { 63 | content: "An error has occurred." 64 | } 65 | 66 | .status-bar-safe-area { 67 | display: none; 68 | } 69 | 70 | @supports (-webkit-touch-callout: none) { 71 | .status-bar-safe-area { 72 | display: flex; 73 | position: sticky; 74 | top: 0; 75 | height: env(safe-area-inset-top); 76 | background-color: #f7f7f7; 77 | width: 100%; 78 | z-index: 1; 79 | } 80 | 81 | .flex-column, .navbar-brand { 82 | padding-left: env(safe-area-inset-left); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /wwwroot/css/open-iconic/FONT-LICENSE: -------------------------------------------------------------------------------- 1 | SIL OPEN FONT LICENSE Version 1.1 2 | 3 | Copyright (c) 2014 Waybury 4 | 5 | PREAMBLE 6 | The goals of the Open Font License (OFL) are to stimulate worldwide 7 | development of collaborative font projects, to support the font creation 8 | efforts of academic and linguistic communities, and to provide a free and 9 | open framework in which fonts may be shared and improved in partnership 10 | with others. 11 | 12 | The OFL allows the licensed fonts to be used, studied, modified and 13 | redistributed freely as long as they are not sold by themselves. The 14 | fonts, including any derivative works, can be bundled, embedded, 15 | redistributed and/or sold with any software provided that any reserved 16 | names are not used by derivative works. The fonts and derivatives, 17 | however, cannot be released under any other type of license. The 18 | requirement for fonts to remain under this license does not apply 19 | to any document created using the fonts or their derivatives. 20 | 21 | DEFINITIONS 22 | "Font Software" refers to the set of files released by the Copyright 23 | Holder(s) under this license and clearly marked as such. This may 24 | include source files, build scripts and documentation. 25 | 26 | "Reserved Font Name" refers to any names specified as such after the 27 | copyright statement(s). 28 | 29 | "Original Version" refers to the collection of Font Software components as 30 | distributed by the Copyright Holder(s). 31 | 32 | "Modified Version" refers to any derivative made by adding to, deleting, 33 | or substituting -- in part or in whole -- any of the components of the 34 | Original Version, by changing formats or by porting the Font Software to a 35 | new environment. 36 | 37 | "Author" refers to any designer, engineer, programmer, technical 38 | writer or other person who contributed to the Font Software. 39 | 40 | PERMISSION & CONDITIONS 41 | Permission is hereby granted, free of charge, to any person obtaining 42 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 43 | redistribute, and sell modified and unmodified copies of the Font 44 | Software, subject to the following conditions: 45 | 46 | 1) Neither the Font Software nor any of its individual components, 47 | in Original or Modified Versions, may be sold by itself. 48 | 49 | 2) Original or Modified Versions of the Font Software may be bundled, 50 | redistributed and/or sold with any software, provided that each copy 51 | contains the above copyright notice and this license. These can be 52 | included either as stand-alone text files, human-readable headers or 53 | in the appropriate machine-readable metadata fields within text or 54 | binary files as long as those fields can be easily viewed by the user. 55 | 56 | 3) No Modified Version of the Font Software may use the Reserved Font 57 | Name(s) unless explicit written permission is granted by the corresponding 58 | Copyright Holder. This restriction only applies to the primary font name as 59 | presented to the users. 60 | 61 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 62 | Software shall not be used to promote, endorse or advertise any 63 | Modified Version, except to acknowledge the contribution(s) of the 64 | Copyright Holder(s) and the Author(s) or with their explicit written 65 | permission. 66 | 67 | 5) The Font Software, modified or unmodified, in part or in whole, 68 | must be distributed entirely under this license, and must not be 69 | distributed under any other license. The requirement for fonts to 70 | remain under this license does not apply to any document created 71 | using the Font Software. 72 | 73 | TERMINATION 74 | This license becomes null and void if any of the above conditions are 75 | not met. 76 | 77 | DISCLAIMER 78 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 79 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 80 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 81 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 82 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 83 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 84 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 85 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 86 | OTHER DEALINGS IN THE FONT SOFTWARE. 87 | -------------------------------------------------------------------------------- /wwwroot/css/open-iconic/ICON-LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Waybury 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /wwwroot/css/open-iconic/README.md: -------------------------------------------------------------------------------- 1 | [Open Iconic v1.1.1](https://github.com/iconic/open-iconic) 2 | =========== 3 | 4 | ### Open Iconic is the open source sibling of [Iconic](https://github.com/iconic/open-iconic). It is a hyper-legible collection of 223 icons with a tiny footprint—ready to use with Bootstrap and Foundation. [View the collection](https://github.com/iconic/open-iconic) 5 | 6 | 7 | 8 | ## What's in Open Iconic? 9 | 10 | * 223 icons designed to be legible down to 8 pixels 11 | * Super-light SVG files - 61.8 for the entire set 12 | * SVG sprite—the modern replacement for icon fonts 13 | * Webfont (EOT, OTF, SVG, TTF, WOFF), PNG and WebP formats 14 | * Webfont stylesheets (including versions for Bootstrap and Foundation) in CSS, LESS, SCSS and Stylus formats 15 | * PNG and WebP raster images in 8px, 16px, 24px, 32px, 48px and 64px. 16 | 17 | 18 | ## Getting Started 19 | 20 | #### For code samples and everything else you need to get started with Open Iconic, check out our [Icons](https://github.com/iconic/open-iconic) and [Reference](https://github.com/iconic/open-iconic) sections. 21 | 22 | ### General Usage 23 | 24 | #### Using Open Iconic's SVGs 25 | 26 | We like SVGs and we think they're the way to display icons on the web. Since Open Iconic are just basic SVGs, we suggest you display them like you would any other image (don't forget the `alt` attribute). 27 | 28 | ``` 29 | icon name 30 | ``` 31 | 32 | #### Using Open Iconic's SVG Sprite 33 | 34 | Open Iconic also comes in a SVG sprite which allows you to display all the icons in the set with a single request. It's like an icon font, without being a hack. 35 | 36 | Adding an icon from an SVG sprite is a little different than what you're used to, but it's still a piece of cake. *Tip: To make your icons easily style able, we suggest adding a general class to the* `` *tag and a unique class name for each different icon in the* `` *tag.* 37 | 38 | ``` 39 | 40 | 41 | 42 | ``` 43 | 44 | Sizing icons only needs basic CSS. All the icons are in a square format, so just set the `` tag with equal width and height dimensions. 45 | 46 | ``` 47 | .icon { 48 | width: 16px; 49 | height: 16px; 50 | } 51 | ``` 52 | 53 | Coloring icons is even easier. All you need to do is set the `fill` rule on the `` tag. 54 | 55 | ``` 56 | .icon-account-login { 57 | fill: #f00; 58 | } 59 | ``` 60 | 61 | To learn more about SVG Sprites, read [Chris Coyier's guide](http://css-tricks.com/svg-sprites-use-better-icon-fonts/). 62 | 63 | #### Using Open Iconic's Icon Font... 64 | 65 | 66 | ##### …with Bootstrap 67 | 68 | You can find our Bootstrap stylesheets in `font/css/open-iconic-bootstrap.{css, less, scss, styl}` 69 | 70 | 71 | ``` 72 | 73 | ``` 74 | 75 | 76 | ``` 77 | 78 | ``` 79 | 80 | ##### …with Foundation 81 | 82 | You can find our Foundation stylesheets in `font/css/open-iconic-foundation.{css, less, scss, styl}` 83 | 84 | ``` 85 | 86 | ``` 87 | 88 | 89 | ``` 90 | 91 | ``` 92 | 93 | ##### …on its own 94 | 95 | You can find our default stylesheets in `font/css/open-iconic.{css, less, scss, styl}` 96 | 97 | ``` 98 | 99 | ``` 100 | 101 | ``` 102 | 103 | ``` 104 | 105 | 106 | ## License 107 | 108 | ### Icons 109 | 110 | All code (including SVG markup) is under the [MIT License](http://opensource.org/licenses/MIT). 111 | 112 | ### Fonts 113 | 114 | All fonts are under the [SIL Licensed](http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web). 115 | -------------------------------------------------------------------------------- /wwwroot/css/open-iconic/font/css/open-iconic-bootstrap.min.css: -------------------------------------------------------------------------------- 1 | @font-face{font-family:Icons;src:url(../fonts/open-iconic.eot);src:url(../fonts/open-iconic.eot?#iconic-sm) format('embedded-opentype'),url(../fonts/open-iconic.woff) format('woff'),url(../fonts/open-iconic.ttf) format('truetype'),url(../fonts/open-iconic.otf) format('opentype'),url(../fonts/open-iconic.svg#iconic-sm) format('svg');font-weight:400;font-style:normal}.oi{position:relative;top:1px;display:inline-block;speak:none;font-family:Icons;font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.oi:empty:before{width:1em;text-align:center;box-sizing:content-box}.oi.oi-align-center:before{text-align:center}.oi.oi-align-left:before{text-align:left}.oi.oi-align-right:before{text-align:right}.oi.oi-flip-horizontal:before{-webkit-transform:scale(-1,1);-ms-transform:scale(-1,1);transform:scale(-1,1)}.oi.oi-flip-vertical:before{-webkit-transform:scale(1,-1);-ms-transform:scale(-1,1);transform:scale(1,-1)}.oi.oi-flip-horizontal-vertical:before{-webkit-transform:scale(-1,-1);-ms-transform:scale(-1,1);transform:scale(-1,-1)}.oi-account-login:before{content:'\e000'}.oi-account-logout:before{content:'\e001'}.oi-action-redo:before{content:'\e002'}.oi-action-undo:before{content:'\e003'}.oi-align-center:before{content:'\e004'}.oi-align-left:before{content:'\e005'}.oi-align-right:before{content:'\e006'}.oi-aperture:before{content:'\e007'}.oi-arrow-bottom:before{content:'\e008'}.oi-arrow-circle-bottom:before{content:'\e009'}.oi-arrow-circle-left:before{content:'\e00a'}.oi-arrow-circle-right:before{content:'\e00b'}.oi-arrow-circle-top:before{content:'\e00c'}.oi-arrow-left:before{content:'\e00d'}.oi-arrow-right:before{content:'\e00e'}.oi-arrow-thick-bottom:before{content:'\e00f'}.oi-arrow-thick-left:before{content:'\e010'}.oi-arrow-thick-right:before{content:'\e011'}.oi-arrow-thick-top:before{content:'\e012'}.oi-arrow-top:before{content:'\e013'}.oi-audio-spectrum:before{content:'\e014'}.oi-audio:before{content:'\e015'}.oi-badge:before{content:'\e016'}.oi-ban:before{content:'\e017'}.oi-bar-chart:before{content:'\e018'}.oi-basket:before{content:'\e019'}.oi-battery-empty:before{content:'\e01a'}.oi-battery-full:before{content:'\e01b'}.oi-beaker:before{content:'\e01c'}.oi-bell:before{content:'\e01d'}.oi-bluetooth:before{content:'\e01e'}.oi-bold:before{content:'\e01f'}.oi-bolt:before{content:'\e020'}.oi-book:before{content:'\e021'}.oi-bookmark:before{content:'\e022'}.oi-box:before{content:'\e023'}.oi-briefcase:before{content:'\e024'}.oi-british-pound:before{content:'\e025'}.oi-browser:before{content:'\e026'}.oi-brush:before{content:'\e027'}.oi-bug:before{content:'\e028'}.oi-bullhorn:before{content:'\e029'}.oi-calculator:before{content:'\e02a'}.oi-calendar:before{content:'\e02b'}.oi-camera-slr:before{content:'\e02c'}.oi-caret-bottom:before{content:'\e02d'}.oi-caret-left:before{content:'\e02e'}.oi-caret-right:before{content:'\e02f'}.oi-caret-top:before{content:'\e030'}.oi-cart:before{content:'\e031'}.oi-chat:before{content:'\e032'}.oi-check:before{content:'\e033'}.oi-chevron-bottom:before{content:'\e034'}.oi-chevron-left:before{content:'\e035'}.oi-chevron-right:before{content:'\e036'}.oi-chevron-top:before{content:'\e037'}.oi-circle-check:before{content:'\e038'}.oi-circle-x:before{content:'\e039'}.oi-clipboard:before{content:'\e03a'}.oi-clock:before{content:'\e03b'}.oi-cloud-download:before{content:'\e03c'}.oi-cloud-upload:before{content:'\e03d'}.oi-cloud:before{content:'\e03e'}.oi-cloudy:before{content:'\e03f'}.oi-code:before{content:'\e040'}.oi-cog:before{content:'\e041'}.oi-collapse-down:before{content:'\e042'}.oi-collapse-left:before{content:'\e043'}.oi-collapse-right:before{content:'\e044'}.oi-collapse-up:before{content:'\e045'}.oi-command:before{content:'\e046'}.oi-comment-square:before{content:'\e047'}.oi-compass:before{content:'\e048'}.oi-contrast:before{content:'\e049'}.oi-copywriting:before{content:'\e04a'}.oi-credit-card:before{content:'\e04b'}.oi-crop:before{content:'\e04c'}.oi-dashboard:before{content:'\e04d'}.oi-data-transfer-download:before{content:'\e04e'}.oi-data-transfer-upload:before{content:'\e04f'}.oi-delete:before{content:'\e050'}.oi-dial:before{content:'\e051'}.oi-document:before{content:'\e052'}.oi-dollar:before{content:'\e053'}.oi-double-quote-sans-left:before{content:'\e054'}.oi-double-quote-sans-right:before{content:'\e055'}.oi-double-quote-serif-left:before{content:'\e056'}.oi-double-quote-serif-right:before{content:'\e057'}.oi-droplet:before{content:'\e058'}.oi-eject:before{content:'\e059'}.oi-elevator:before{content:'\e05a'}.oi-ellipses:before{content:'\e05b'}.oi-envelope-closed:before{content:'\e05c'}.oi-envelope-open:before{content:'\e05d'}.oi-euro:before{content:'\e05e'}.oi-excerpt:before{content:'\e05f'}.oi-expand-down:before{content:'\e060'}.oi-expand-left:before{content:'\e061'}.oi-expand-right:before{content:'\e062'}.oi-expand-up:before{content:'\e063'}.oi-external-link:before{content:'\e064'}.oi-eye:before{content:'\e065'}.oi-eyedropper:before{content:'\e066'}.oi-file:before{content:'\e067'}.oi-fire:before{content:'\e068'}.oi-flag:before{content:'\e069'}.oi-flash:before{content:'\e06a'}.oi-folder:before{content:'\e06b'}.oi-fork:before{content:'\e06c'}.oi-fullscreen-enter:before{content:'\e06d'}.oi-fullscreen-exit:before{content:'\e06e'}.oi-globe:before{content:'\e06f'}.oi-graph:before{content:'\e070'}.oi-grid-four-up:before{content:'\e071'}.oi-grid-three-up:before{content:'\e072'}.oi-grid-two-up:before{content:'\e073'}.oi-hard-drive:before{content:'\e074'}.oi-header:before{content:'\e075'}.oi-headphones:before{content:'\e076'}.oi-heart:before{content:'\e077'}.oi-home:before{content:'\e078'}.oi-image:before{content:'\e079'}.oi-inbox:before{content:'\e07a'}.oi-infinity:before{content:'\e07b'}.oi-info:before{content:'\e07c'}.oi-italic:before{content:'\e07d'}.oi-justify-center:before{content:'\e07e'}.oi-justify-left:before{content:'\e07f'}.oi-justify-right:before{content:'\e080'}.oi-key:before{content:'\e081'}.oi-laptop:before{content:'\e082'}.oi-layers:before{content:'\e083'}.oi-lightbulb:before{content:'\e084'}.oi-link-broken:before{content:'\e085'}.oi-link-intact:before{content:'\e086'}.oi-list-rich:before{content:'\e087'}.oi-list:before{content:'\e088'}.oi-location:before{content:'\e089'}.oi-lock-locked:before{content:'\e08a'}.oi-lock-unlocked:before{content:'\e08b'}.oi-loop-circular:before{content:'\e08c'}.oi-loop-square:before{content:'\e08d'}.oi-loop:before{content:'\e08e'}.oi-magnifying-glass:before{content:'\e08f'}.oi-map-marker:before{content:'\e090'}.oi-map:before{content:'\e091'}.oi-media-pause:before{content:'\e092'}.oi-media-play:before{content:'\e093'}.oi-media-record:before{content:'\e094'}.oi-media-skip-backward:before{content:'\e095'}.oi-media-skip-forward:before{content:'\e096'}.oi-media-step-backward:before{content:'\e097'}.oi-media-step-forward:before{content:'\e098'}.oi-media-stop:before{content:'\e099'}.oi-medical-cross:before{content:'\e09a'}.oi-menu:before{content:'\e09b'}.oi-microphone:before{content:'\e09c'}.oi-minus:before{content:'\e09d'}.oi-monitor:before{content:'\e09e'}.oi-moon:before{content:'\e09f'}.oi-move:before{content:'\e0a0'}.oi-musical-note:before{content:'\e0a1'}.oi-paperclip:before{content:'\e0a2'}.oi-pencil:before{content:'\e0a3'}.oi-people:before{content:'\e0a4'}.oi-person:before{content:'\e0a5'}.oi-phone:before{content:'\e0a6'}.oi-pie-chart:before{content:'\e0a7'}.oi-pin:before{content:'\e0a8'}.oi-play-circle:before{content:'\e0a9'}.oi-plus:before{content:'\e0aa'}.oi-power-standby:before{content:'\e0ab'}.oi-print:before{content:'\e0ac'}.oi-project:before{content:'\e0ad'}.oi-pulse:before{content:'\e0ae'}.oi-puzzle-piece:before{content:'\e0af'}.oi-question-mark:before{content:'\e0b0'}.oi-rain:before{content:'\e0b1'}.oi-random:before{content:'\e0b2'}.oi-reload:before{content:'\e0b3'}.oi-resize-both:before{content:'\e0b4'}.oi-resize-height:before{content:'\e0b5'}.oi-resize-width:before{content:'\e0b6'}.oi-rss-alt:before{content:'\e0b7'}.oi-rss:before{content:'\e0b8'}.oi-script:before{content:'\e0b9'}.oi-share-boxed:before{content:'\e0ba'}.oi-share:before{content:'\e0bb'}.oi-shield:before{content:'\e0bc'}.oi-signal:before{content:'\e0bd'}.oi-signpost:before{content:'\e0be'}.oi-sort-ascending:before{content:'\e0bf'}.oi-sort-descending:before{content:'\e0c0'}.oi-spreadsheet:before{content:'\e0c1'}.oi-star:before{content:'\e0c2'}.oi-sun:before{content:'\e0c3'}.oi-tablet:before{content:'\e0c4'}.oi-tag:before{content:'\e0c5'}.oi-tags:before{content:'\e0c6'}.oi-target:before{content:'\e0c7'}.oi-task:before{content:'\e0c8'}.oi-terminal:before{content:'\e0c9'}.oi-text:before{content:'\e0ca'}.oi-thumb-down:before{content:'\e0cb'}.oi-thumb-up:before{content:'\e0cc'}.oi-timer:before{content:'\e0cd'}.oi-transfer:before{content:'\e0ce'}.oi-trash:before{content:'\e0cf'}.oi-underline:before{content:'\e0d0'}.oi-vertical-align-bottom:before{content:'\e0d1'}.oi-vertical-align-center:before{content:'\e0d2'}.oi-vertical-align-top:before{content:'\e0d3'}.oi-video:before{content:'\e0d4'}.oi-volume-high:before{content:'\e0d5'}.oi-volume-low:before{content:'\e0d6'}.oi-volume-off:before{content:'\e0d7'}.oi-warning:before{content:'\e0d8'}.oi-wifi:before{content:'\e0d9'}.oi-wrench:before{content:'\e0da'}.oi-x:before{content:'\e0db'}.oi-yen:before{content:'\e0dc'}.oi-zoom-in:before{content:'\e0dd'}.oi-zoom-out:before{content:'\e0de'} -------------------------------------------------------------------------------- /wwwroot/css/open-iconic/font/fonts/open-iconic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIStoryBuilders/AIOrchestrator/596676d7294a32431b2621b248887eb99b1f979c/wwwroot/css/open-iconic/font/fonts/open-iconic.eot -------------------------------------------------------------------------------- /wwwroot/css/open-iconic/font/fonts/open-iconic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIStoryBuilders/AIOrchestrator/596676d7294a32431b2621b248887eb99b1f979c/wwwroot/css/open-iconic/font/fonts/open-iconic.otf -------------------------------------------------------------------------------- /wwwroot/css/open-iconic/font/fonts/open-iconic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIStoryBuilders/AIOrchestrator/596676d7294a32431b2621b248887eb99b1f979c/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf -------------------------------------------------------------------------------- /wwwroot/css/open-iconic/font/fonts/open-iconic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIStoryBuilders/AIOrchestrator/596676d7294a32431b2621b248887eb99b1f979c/wwwroot/css/open-iconic/font/fonts/open-iconic.woff -------------------------------------------------------------------------------- /wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AIStoryBuilders/AIOrchestrator/596676d7294a32431b2621b248887eb99b1f979c/wwwroot/favicon.ico -------------------------------------------------------------------------------- /wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | AI Orchestrator 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 |
Loading...
19 | 20 |
21 | An unhandled error has occurred. 22 | Reload 23 | 🗙 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 | --------------------------------------------------------------------------------