├── .gitattributes
├── .gitignore
├── AppControlPlugin
├── AppControlPlugin.cs
├── AppControlPlugin.csproj
├── AppControlPluginCommand.cs
├── AppControlPluginSettings.cs
├── AppControlPluginSettings_eng.json
└── KeyCodes.txt
├── BrowserPlugin
├── BrowserPlugin.cs
├── BrowserPlugin.csproj
├── BrowserPluginCommand.cs
├── BrowserPluginSettings.cs
└── BrowserPluginSettings_eng.json
├── CurrencyRatePlugin
├── CurrencyRatePlugin.cs
├── CurrencyRatePlugin.csproj
├── CurrencyRatePluginCommand.cs
├── CurrencyRatePluginSettings.cs
└── CurrencyRatePluginSettings_eng.json
├── GoogleCalendarPlugin
├── CalendarEvents.cs
├── GoogleCalendarPlugin.cs
├── GoogleCalendarPlugin.csproj
├── GoogleCalendarPluginCommand.cs
├── GoogleCalendarPluginSettings.cs
├── GoogleCalendarPluginSettings_eng.json
├── birthdays_calendar.jpg
└── calendarId.jpg
├── HelloPlugin
├── HelloPlugin.cs
├── HelloPlugin.csproj
├── HelloPluginCommand.cs
├── HelloPluginSettings.cs
└── HelloPluginSettings_eng.json
├── LICENSE
├── MQTTInPlugin
├── MQTTInPlugin.cs
├── MQTTInPlugin.csproj
├── MQTTInPluginSettings.cs
└── MQTTInTopic.cs
├── MQTTOutPlugin
├── MQTTOutPlugin.cs
├── MQTTOutPlugin.csproj
├── MQTTOutPluginCommand.cs
├── MQTTOutPluginSettings.cs
└── MQTTPluginSettings_eng.json
├── OpenWeatherPlugin
├── CurrentWeatherData.cs
├── OpenWeatherPlugin.cs
├── OpenWeatherPlugin.csproj
├── OpenWeatherPluginCommand.cs
├── OpenWeatherPluginSettings.cs
├── OpenWeatherPluginSettings_eng.json
├── WeatherCurrent.cs
├── WeatherForecast.cs
└── WeatherForecastData.cs
├── PluginInterface
├── Config.cs
├── GenericNumberSettings.cs
├── IAudioOutSingleton.cs
├── INumberToText.cs
├── ITextToNumber.cs
├── NumberToTextEmpty.cs
├── NumberToTextEng.cs
├── NumberToTextFactory.cs
├── NumberToTextGeneric.cs
├── NumberToTextRus.cs
├── PluginBase.cs
├── PluginCommand.cs
├── PluginInterface.csproj
├── PluginTools.cs
├── TextToNumberEmpty.cs
├── TextToNumberEng.cs
├── TextToNumberFactory.cs
├── TextToNumberGeneric.cs
└── TextToNumberRus.cs
├── README.md
├── README_rus.md
├── RunProgramPlugin
├── RunProgramPlugin.cs
├── RunProgramPlugin.csproj
├── RunProgramPluginCommand.cs
├── RunProgramPluginSettings.cs
└── RunProgramPluginSettings_eng.json
├── TimerPlugin
├── TimerPlugin.cs
├── TimerPlugin.csproj
├── TimerPluginCommand.cs
├── TimerPluginSettings.cs
├── TimerPluginSettings_eng.json
└── timer.wav
├── VoiceAssistant.sln
└── VoiceAssistant
├── AssistantStart.wav
├── AudioOutSingleton.cs
├── GenericPluginLoader.cs
├── Misrecognition.wav
├── ProcessingCommand.cs
├── Program.cs
├── VoiceAssistant.csproj
├── VoiceAssistantSettings.cs
├── VoskResult.cs
├── appsettings_eng.json
└── desktop.ini
/.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
--------------------------------------------------------------------------------
/AppControlPlugin/AppControlPlugin.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | PreserveNewest
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/AppControlPlugin/AppControlPluginCommand.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using PluginInterface;
4 |
5 | namespace AppControlPlugin
6 | {
7 | public class AppControlPluginCommand : PluginCommand
8 | {
9 | public string Response = "";
10 | public string ApplicationId = "";
11 | public string[] KeyNames = { "" };
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/AppControlPlugin/AppControlPluginSettings.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using PluginInterface;
4 |
5 | namespace AppControlPlugin
6 | {
7 | public class AppControlPluginSettings
8 | {
9 | public string KeyNotFound = "Кнопка не найдена";
10 | public string ProcessNotFound = "Процесс не найден";
11 |
12 | //[JsonProperty(Required = Required.Always)]
13 | public AppControlPluginCommand[] Commands =
14 | {
15 | new AppControlPluginCommand
16 | {
17 | Name = "MPC next",
18 | Tokens = new[]
19 | {
20 | new Token
21 | {
22 | SuccessRate = 90,
23 | Type = TokenType.Command,
24 | Value = new[] {"следующий"}
25 | },
26 | new Token
27 | {
28 | SuccessRate = 90,
29 | Type = TokenType.Command,
30 | Value = new[] {"фильм"}
31 | }
32 | },
33 | ApplicationId = "mpc-hc64",
34 | KeyNames = new[] { "VK_NEXT" },
35 | Response = "Перешел на следующий"
36 | },
37 | new AppControlPluginCommand
38 | {
39 | Name = "MPC previous",
40 | Tokens = new[]
41 | {
42 | new Token
43 | {
44 | SuccessRate = 90,
45 | Type = TokenType.Command,
46 | Value = new[] {"предыдущий"}
47 | },
48 | new Token
49 | {
50 | SuccessRate = 90,
51 | Type = TokenType.Command,
52 | Value = new[] {"фильм"}
53 | }
54 | },
55 | ApplicationId = "mpc-hc64",
56 | KeyNames = new[] { "VK_PRIOR" },
57 | Response = "Вернулся на предыдущий"
58 | },
59 | new AppControlPluginCommand
60 | {
61 | Name = "MPC play",
62 | Tokens = new[]
63 | {
64 | new Token
65 | {
66 | SuccessRate = 90,
67 | Type = TokenType.Command,
68 | Value = new[] {"Запусти"}
69 | },
70 | new Token
71 | {
72 | SuccessRate = 90,
73 | Type = TokenType.Command,
74 | Value = new[] { "фильм" }
75 | }
76 | },
77 | ApplicationId = "mpc-hc64",
78 | KeyNames = new[] { "VK_SPACE" },
79 | Response = "фильм запущен"
80 | },
81 | new AppControlPluginCommand
82 | {
83 | Name = "MPC stop",
84 | Tokens = new[]
85 | {
86 | new Token
87 | {
88 | SuccessRate = 90,
89 | Type = TokenType.Command,
90 | Value = new[] {"Останови"}
91 | },
92 | new Token
93 | {
94 | SuccessRate = 90,
95 | Type = TokenType.Command,
96 | Value = new[] { "фильм" }
97 | }
98 | },
99 | ApplicationId = "mpc-hc64",
100 | KeyNames = new[] { "VK_DECIMAL" },
101 | Response = "фильм остановлен"
102 | },
103 | new AppControlPluginCommand
104 | {
105 | Name = "MPC play/pause",
106 | Tokens = new[]
107 | {
108 | new Token
109 | {
110 | SuccessRate = 90,
111 | Type = TokenType.Command,
112 | Value = new[] { "фильм" }
113 | },
114 | new Token
115 | {
116 | SuccessRate = 90,
117 | Type = TokenType.Command,
118 | Value = new[] { "на" }
119 | },
120 | new Token
121 | {
122 | SuccessRate = 90,
123 | Type = TokenType.Command,
124 | Value = new[] {"паузу"}
125 | }
126 | },
127 | ApplicationId = "mpc-hc64",
128 | KeyNames = new[] { "VK_SPACE" },
129 | Response = "Пауза"
130 | },
131 | new AppControlPluginCommand
132 | {
133 | Name = "MPC volume up",
134 | Tokens = new[]
135 | {
136 | new Token
137 | {
138 | SuccessRate = 90,
139 | Type = TokenType.Command,
140 | Value = new[] { "сделай" }
141 | },
142 | new Token
143 | {
144 | SuccessRate = 90,
145 | Type = TokenType.Command,
146 | Value = new[] { "громче" }
147 | }
148 | },
149 | ApplicationId="mpc-hc64",
150 | KeyNames = new[] { "VK_UP","VK_UP","VK_UP","VK_UP" },
151 | Response = "сделал громче"
152 | },
153 | new AppControlPluginCommand
154 | {
155 | Name = "MPC volume down",
156 | Tokens = new[]
157 | {
158 | new Token
159 | {
160 | SuccessRate = 90,
161 | Type = TokenType.Command,
162 | Value = new[] { "сделай" }
163 | },
164 | new Token
165 | {
166 | SuccessRate = 90,
167 | Type = TokenType.Command,
168 | Value = new[] { "тише" }
169 | }
170 | },
171 | ApplicationId = "mpc-hc64",
172 | KeyNames = new[] { "VK_DOWN","VK_DOWN","VK_DOWN","VK_DOWN" },
173 | Response = "сделал тише"
174 | }
175 | };
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/AppControlPlugin/AppControlPluginSettings_eng.json:
--------------------------------------------------------------------------------
1 | {
2 | "KeyNotFound": "key code not found",
3 | "ProcessNotFound": "process not found",
4 | "Commands": [
5 | {
6 | "Response": "switched forth",
7 | "ApplicationId": "mpc-hc64",
8 | "KeyNames": [
9 | "VK_NEXT"
10 | ],
11 | "Name": "MPC next",
12 | "Tokens": [
13 | {
14 | "Value": [
15 | "next"
16 | ],
17 | "Type": "Command",
18 | "SuccessRate": 90
19 | },
20 | {
21 | "Value": [
22 | "movie"
23 | ],
24 | "Type": "Command",
25 | "SuccessRate": 90
26 | }
27 | ]
28 | },
29 | {
30 | "Response": "switched back",
31 | "ApplicationId": "mpc-hc64",
32 | "KeyNames": [
33 | "VK_PRIOR"
34 | ],
35 | "Name": "MPC previous",
36 | "Tokens": [
37 | {
38 | "Value": [
39 | "previous"
40 | ],
41 | "Type": "Command",
42 | "SuccessRate": 90
43 | },
44 | {
45 | "Value": [
46 | "movie"
47 | ],
48 | "Type": "Command",
49 | "SuccessRate": 90
50 | }
51 | ]
52 | },
53 | {
54 | "Response": "movie started",
55 | "ApplicationId": "mpc-hc64",
56 | "KeyNames": [
57 | "VK_SPACE"
58 | ],
59 | "Name": "MPC play",
60 | "Tokens": [
61 | {
62 | "Value": [
63 | "start",
64 | "play"
65 | ],
66 | "Type": "Command",
67 | "SuccessRate": 90
68 | },
69 | {
70 | "Value": [
71 | "movie"
72 | ],
73 | "Type": "Command",
74 | "SuccessRate": 90
75 | }
76 | ]
77 | },
78 | {
79 | "Response": "movie stopped",
80 | "ApplicationId": "mpc-hc64",
81 | "KeyNames": [
82 | "VK_DECIMAL"
83 | ],
84 | "Name": "MPC stop",
85 | "Tokens": [
86 | {
87 | "Value": [
88 | "stop"
89 | ],
90 | "Type": "Command",
91 | "SuccessRate": 90
92 | },
93 | {
94 | "Value": [
95 | "movie"
96 | ],
97 | "Type": "Command",
98 | "SuccessRate": 90
99 | }
100 | ]
101 | },
102 | {
103 | "Response": "movie paused",
104 | "ApplicationId": "mpc-hc64",
105 | "KeyNames": [
106 | "VK_SPACE"
107 | ],
108 | "Name": "MPC play/pause",
109 | "Tokens": [
110 | {
111 | "Value": [
112 | "pause"
113 | ],
114 | "Type": "Command",
115 | "SuccessRate": 90
116 | },
117 | {
118 | "Value": [
119 | "movie"
120 | ],
121 | "Type": "Command",
122 | "SuccessRate": 90
123 | }
124 | ]
125 | },
126 | {
127 | "Response": "volume increased",
128 | "ApplicationId": "mpc-hc64",
129 | "KeyNames": [
130 | "VK_UP",
131 | "VK_UP",
132 | "VK_UP",
133 | "VK_UP"
134 | ],
135 | "Name": "MPC volume up",
136 | "Tokens": [
137 | {
138 | "Value": [
139 | "volume"
140 | ],
141 | "Type": "Command",
142 | "SuccessRate": 90
143 | },
144 | {
145 | "Value": [
146 | "up"
147 | ],
148 | "Type": "Command",
149 | "SuccessRate": 90
150 | }
151 | ]
152 | },
153 | {
154 | "Response": "volume decreased",
155 | "ApplicationId": "mpc-hc64",
156 | "KeyNames": [
157 | "VK_DOWN",
158 | "VK_DOWN",
159 | "VK_DOWN",
160 | "VK_DOWN"
161 | ],
162 | "Name": "MPC volume down",
163 | "Tokens": [
164 | {
165 | "Value": [
166 | "volume"
167 | ],
168 | "Type": "Command",
169 | "SuccessRate": 90
170 | },
171 | {
172 | "Value": [
173 | "down"
174 | ],
175 | "Type": "Command",
176 | "SuccessRate": 90
177 | }
178 | ]
179 | }
180 | ]
181 | }
--------------------------------------------------------------------------------
/AppControlPlugin/KeyCodes.txt:
--------------------------------------------------------------------------------
1 | Constant Value Description
2 |
3 | VK_LBUTTON 0x01 Left mouse button
4 | VK_RBUTTON 0x02 Right mouse button
5 | VK_CANCEL 0x03 Control-break processing
6 | VK_MBUTTON 0x04 Middle mouse button (three-button mouse)
7 | VK_XBUTTON1 0x05 X1 mouse button
8 | VK_XBUTTON2 0x06 X2 mouse button
9 | - 0x07 Undefined
10 | VK_BACK 0x08 BACKSPACE key
11 | VK_TAB 0x09 TAB key
12 | - 0x0A-0B Reserved
13 | VK_CLEAR 0x0C CLEAR key
14 | VK_RETURN 0x0D ENTER key
15 | - 0x0E-0F Undefined
16 | VK_SHIFT 0x10 SHIFT key
17 | VK_CONTROL 0x11 CTRL key
18 | VK_MENU 0x12 ALT key
19 | VK_PAUSE 0x13 PAUSE key
20 | VK_CAPITAL 0x14 CAPS LOCK key
21 | VK_KANA 0x15 IME Kana mode
22 | VK_HANGUEL 0x15 IME Hanguel mode (maintained for compatibility; use VK_HANGUL)
23 | VK_HANGUL 0x15 IME Hangul mode
24 | VK_IME_ON 0x16 IME On
25 | VK_JUNJA 0x17 IME Junja mode
26 | VK_FINAL 0x18 IME final mode
27 | VK_HANJA 0x19 IME Hanja mode
28 | VK_KANJI 0x19 IME Kanji mode
29 | VK_IME_OFF 0x1A IME Off
30 | VK_ESCAPE 0x1B ESC key
31 | VK_CONVERT 0x1C IME convert
32 | VK_NONCONVERT 0x1D IME nonconvert
33 | VK_ACCEPT 0x1E IME accept
34 | VK_MODECHANGE 0x1F IME mode change request
35 | VK_SPACE 0x20 SPACEBAR
36 | VK_PRIOR 0x21 PAGE UP key
37 | VK_NEXT 0x22 PAGE DOWN key
38 | VK_END 0x23 END key
39 | VK_HOME 0x24 HOME key
40 | VK_LEFT 0x25 LEFT ARROW key
41 | VK_UP 0x26 UP ARROW key
42 | VK_RIGHT 0x27 RIGHT ARROW key
43 | VK_DOWN 0x28 DOWN ARROW key
44 | VK_SELECT 0x29 SELECT key
45 | VK_PRINT 0x2A PRINT key
46 | VK_EXECUTE 0x2B EXECUTE key
47 | VK_SNAPSHOT 0x2C PRINT SCREEN key
48 | VK_INSERT 0x2D INS key
49 | VK_DELETE 0x2E DEL key
50 | VK_HELP 0x2F HELP key
51 | - 0x30 0 key
52 | - 0x31 1 key
53 | - 0x32 2 key
54 | - 0x33 3 key
55 | - 0x34 4 key
56 | - 0x35 5 key
57 | - 0x36 6 key
58 | - 0x37 7 key
59 | - 0x38 8 key
60 | - 0x39 9 key
61 | - 0x3A-40 Undefined
62 | - 0x41 A key
63 | - 0x42 B key
64 | - 0x43 C key
65 | - 0x44 D key
66 | - 0x45 E key
67 | - 0x46 F key
68 | - 0x47 G key
69 | - 0x48 H key
70 | - 0x49 I key
71 | - 0x4A J key
72 | - 0x4B K key
73 | - 0x4C L key
74 | - 0x4D M key
75 | - 0x4E N key
76 | - 0x4F O key
77 | - 0x50 P key
78 | - 0x51 Q key
79 | - 0x52 R key
80 | - 0x53 S key
81 | - 0x54 T key
82 | - 0x55 U key
83 | - 0x56 V key
84 | - 0x57 W key
85 | - 0x58 X key
86 | - 0x59 Y key
87 | - 0x5A Z key
88 | VK_LWIN 0x5B Left Windows key (Natural keyboard)
89 | VK_RWIN 0x5C Right Windows key (Natural keyboard)
90 | VK_APPS 0x5D Applications key (Natural keyboard)
91 | - 0x5E Reserved
92 | VK_SLEEP 0x5F Computer Sleep key
93 | VK_NUMPAD0 0x60 Numeric keypad 0 key
94 | VK_NUMPAD1 0x61 Numeric keypad 1 key
95 | VK_NUMPAD2 0x62 Numeric keypad 2 key
96 | VK_NUMPAD3 0x63 Numeric keypad 3 key
97 | VK_NUMPAD4 0x64 Numeric keypad 4 key
98 | VK_NUMPAD5 0x65 Numeric keypad 5 key
99 | VK_NUMPAD6 0x66 Numeric keypad 6 key
100 | VK_NUMPAD7 0x67 Numeric keypad 7 key
101 | VK_NUMPAD8 0x68 Numeric keypad 8 key
102 | VK_NUMPAD9 0x69 Numeric keypad 9 key
103 | VK_MULTIPLY 0x6A Multiply key
104 | VK_ADD 0x6B Add key
105 | VK_SEPARATOR 0x6C Separator key
106 | VK_SUBTRACT 0x6D Subtract key
107 | VK_DECIMAL 0x6E Decimal key
108 | VK_DIVIDE 0x6F Divide key
109 | VK_F1 0x70 F1 key
110 | VK_F2 0x71 F2 key
111 | VK_F3 0x72 F3 key
112 | VK_F4 0x73 F4 key
113 | VK_F5 0x74 F5 key
114 | VK_F6 0x75 F6 key
115 | VK_F7 0x76 F7 key
116 | VK_F8 0x77 F8 key
117 | VK_F9 0x78 F9 key
118 | VK_F10 0x79 F10 key
119 | VK_F11 0x7A F11 key
120 | VK_F12 0x7B F12 key
121 | VK_F13 0x7C F13 key
122 | VK_F14 0x7D F14 key
123 | VK_F15 0x7E F15 key
124 | VK_F16 0x7F F16 key
125 | VK_F17 0x80 F17 key
126 | VK_F18 0x81 F18 key
127 | VK_F19 0x82 F19 key
128 | VK_F20 0x83 F20 key
129 | VK_F21 0x84 F21 key
130 | VK_F22 0x85 F22 key
131 | VK_F23 0x86 F23 key
132 | VK_F24 0x87 F24 key
133 | - 0x88-8F Unassigned
134 | VK_NUMLOCK 0x90 NUM LOCK key
135 | VK_SCROLL 0x91 SCROLL LOCK key
136 | - 0x92-96 OEM specific
137 | - 0x97-9F Unassigned
138 | VK_LSHIFT 0xA0 Left SHIFT key
139 | VK_RSHIFT 0xA1 Right SHIFT key
140 | VK_LCONTROL 0xA2 Left CONTROL key
141 | VK_RCONTROL 0xA3 Right CONTROL key
142 | VK_LMENU 0xA4 Left MENU key
143 | VK_RMENU 0xA5 Right MENU key
144 |
145 |
146 | VK_BROWSER_BACK 0xA6 Browser Back key
147 | VK_BROWSER_FORWARD 0xA7 Browser Forward key
148 | VK_BROWSER_REFRESH 0xA8 Browser Refresh key
149 | VK_BROWSER_STOP 0xA9 Browser Stop key
150 | VK_BROWSER_SEARCH 0xAA Browser Search key
151 | VK_BROWSER_FAVORITES 0xAB Browser Favorites key
152 | VK_BROWSER_HOME 0xAC Browser Start and Home key
153 | VK_VOLUME_MUTE 0xAD Volume Mute key
154 | VK_VOLUME_DOWN 0xAE Volume Down key
155 | VK_VOLUME_UP 0xAF Volume Up key
156 | VK_MEDIA_NEXT_TRACK 0xB0 Next Track key
157 | VK_MEDIA_PREV_TRACK 0xB1 Previous Track key
158 | VK_MEDIA_STOP 0xB2 Stop Media key
159 | VK_MEDIA_PLAY_PAUSE 0xB3 Play/Pause Media key
160 | VK_LAUNCH_MAIL 0xB4 Start Mail key
161 | VK_LAUNCH_MEDIA_SELECT 0xB5 Select Media key
162 |
163 |
164 | VK_LAUNCH_APP1 0xB6 Start Application 1 key
165 | VK_LAUNCH_APP2 0xB7 Start Application 2 key
166 | - 0xB8-B9 Reserved
167 | VK_OEM_1 0xBA Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ';:' key
168 | VK_OEM_PLUS 0xBB For any country/region, the '+' key
169 | VK_OEM_COMMA 0xBC For any country/region, the ',' key
170 | VK_OEM_MINUS 0xBD For any country/region, the '-' key
171 | VK_OEM_PERIOD 0xBE For any country/region, the '.' key
172 | VK_OEM_2 0xBF Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '/?' key
173 | VK_OEM_3 0xC0 Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '`~' key
174 | - 0xC1-D7 Reserved
175 | - 0xD8-DA Unassigned
176 | VK_OEM_4 0xDB Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '[{' key
177 | VK_OEM_5 0xDC Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '\|' key
178 | VK_OEM_6 0xDD Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ']}' key
179 | VK_OEM_7 0xDE Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the 'single-quote/double-quote' key
180 | VK_OEM_8 0xDF Used for miscellaneous characters; it can vary by keyboard.
181 | - 0xE0 Reserved
182 | - 0xE1 OEM specific
183 | VK_OEM_102 0xE2 The <> keys on the US standard keyboard, or the \\| key on the non-US 102-key keyboard
184 | - 0xE3-E4 OEM specific
185 | VK_PROCESSKEY 0xE5 IME PROCESS key
186 | - 0xE6 OEM specific
187 | VK_PACKET 0xE7 Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KEYUP
188 | - 0xE8 Unassigned
189 | - 0xE9-F5 OEM specific
190 | VK_ATTN 0xF6 Attn key
191 | VK_CRSEL 0xF7 CrSel key
192 | VK_EXSEL 0xF8 ExSel key
193 | VK_EREOF 0xF9 Erase EOF key
194 | VK_PLAY 0xFA Play key
195 | VK_ZOOM 0xFB Zoom key
196 | VK_NONAME 0xFC Reserved
197 | VK_PA1 0xFD PA1 key
198 | VK_OEM_CLEAR 0xFE Clear key
199 |
--------------------------------------------------------------------------------
/BrowserPlugin/BrowserPlugin.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Runtime.InteropServices;
9 |
10 | using Microsoft.Win32;
11 |
12 | using PluginInterface;
13 |
14 | namespace BrowserPlugin
15 | {
16 | public class BrowserPlugin : PluginBase
17 | {
18 | private readonly BrowserPluginCommand[] BrowserCommands;
19 | private readonly Dictionary _processes = new Dictionary();
20 | private readonly string _canNotClose;
21 | private readonly string _notRunning;
22 | private readonly string _canNotRun;
23 | private readonly string _alreadyRunning;
24 |
25 | public BrowserPlugin(IAudioOutSingleton audioOut, string currentCulture, string pluginPath) : base(audioOut, currentCulture, pluginPath)
26 | {
27 | var configBuilder = new Config($"{PluginPath}\\{PluginConfigFile}");
28 |
29 | if (!File.Exists($"{PluginPath}\\{PluginConfigFile}"))
30 | {
31 | configBuilder.SaveConfig();
32 | }
33 |
34 | BrowserCommands = configBuilder.ConfigStorage.Commands;
35 |
36 | if (BrowserCommands is PluginCommand[] newCmds)
37 | {
38 | _commands = newCmds;
39 | }
40 |
41 | _canNotClose = configBuilder.ConfigStorage.CanNotClose;
42 | _notRunning = configBuilder.ConfigStorage.NotRunning;
43 | _canNotRun = configBuilder.ConfigStorage.CanNotRun;
44 | _alreadyRunning = configBuilder.ConfigStorage.AlreadyRunning;
45 | }
46 |
47 | public override void Execute(string commandName, List commandTokens)
48 | {
49 | var command = BrowserCommands.FirstOrDefault(n => n.Name == commandName);
50 |
51 | if (command == null)
52 | {
53 | return;
54 | }
55 |
56 | var response = string.Empty;
57 | var processId = command.URL;
58 |
59 | if (command.isStopCommand)
60 | {
61 | if (_processes.TryGetValue(processId, out var proc))
62 | {
63 | if (proc != null)
64 | {
65 | try
66 | {
67 | proc.Kill();
68 | response = command.Response;
69 | }
70 | catch
71 | {
72 | response = _canNotClose;
73 | }
74 | finally
75 | {
76 | _processes.Remove(processId);
77 | }
78 | }
79 | else
80 | {
81 | response = _notRunning;
82 | }
83 | }
84 | else
85 | {
86 | response = _notRunning;
87 | }
88 | }
89 | else
90 | {
91 | if (!_processes.TryGetValue(processId, out _))
92 | {
93 | var process = OpenUrl(command.URL, command.useStandAloneBrowser);
94 |
95 | if (process != null)
96 | {
97 | if (command.useStandAloneBrowser)
98 | {
99 | _processes.Add(processId, process);
100 | }
101 |
102 | response = command.Response;
103 | }
104 | else
105 | {
106 | response = _canNotRun;
107 | }
108 | }
109 | else
110 | {
111 | response = _alreadyRunning;
112 | }
113 | }
114 | AudioOut.Speak(response);
115 | }
116 |
117 | private Process OpenUrl(string url, bool standAloneBrowser = false)
118 | {
119 | Process proc;
120 | try
121 | {
122 | if (standAloneBrowser)
123 | {
124 | string browser = string.Empty;
125 | RegistryKey key = null;
126 |
127 | try
128 | {
129 | key = Registry.ClassesRoot.OpenSubKey(@"HTTP\shell\open\command");
130 |
131 | if (key != null)
132 | {
133 | // Get default Browser
134 | browser = key.GetValue(null).ToString().ToLower().Trim(new[] { '"' });
135 | }
136 |
137 | if (!browser.EndsWith("exe"))
138 | {
139 | //Remove all after the ".exe"
140 | browser = browser.Substring(0, browser.LastIndexOf(".exe", StringComparison.InvariantCultureIgnoreCase) + 4);
141 | }
142 | }
143 | finally
144 | {
145 | if (key != null)
146 | {
147 | key.Close();
148 | }
149 | }
150 |
151 | proc = Process.Start(browser, url);
152 | }
153 | else
154 | {
155 | proc = Process.Start(url);
156 | }
157 | }
158 | catch
159 | {
160 | try
161 | {
162 | // hack because of this: https://github.com/dotnet/corefx/issues/10361
163 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
164 | {
165 | url = url.Replace("&", "^&");
166 | proc = Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
167 |
168 | /*
169 | Process myProcess = new Process();
170 | try
171 | {
172 | // true is the default, but it is important not to set it to false
173 | myProcess.StartInfo.UseShellExecute = true;
174 | myProcess.StartInfo.FileName = "http://some.domain.tld/bla";
175 | myProcess.Start();
176 | }
177 | catch (Exception e)
178 | {
179 | Console.WriteLine(e.Message);
180 | }
181 | */
182 | //Windows.System.Launcher.LaunchUriAsync(new Uri("http://google.com"));
183 | //Process.Start("explorer.exe", $"\"{uri}\"");
184 |
185 | }
186 | else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
187 | {
188 | proc = Process.Start("xdg-open", url);
189 | }
190 | else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
191 | {
192 | proc = Process.Start("open", url);
193 | }
194 | else
195 | {
196 | throw;
197 | }
198 | }
199 | catch
200 | {
201 | return null;
202 | }
203 | }
204 |
205 | return proc;
206 | }
207 | }
208 | }
209 |
--------------------------------------------------------------------------------
/BrowserPlugin/BrowserPlugin.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/BrowserPlugin/BrowserPluginCommand.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using PluginInterface;
4 |
5 | namespace BrowserPlugin
6 | {
7 | public class BrowserPluginCommand : PluginCommand
8 | {
9 | public string Response = "";
10 | public string URL = "";
11 | public bool isStopCommand = false;
12 | public bool useStandAloneBrowser = false;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/BrowserPlugin/BrowserPluginSettings.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using PluginInterface;
4 |
5 | namespace BrowserPlugin
6 | {
7 | public class BrowserPluginSettings
8 | {
9 | //[JsonProperty(Required = Required.Always)]
10 | public string CanNotClose = "не удалось закрыть";
11 | public string NotRunning = "не запущен";
12 | public string CanNotRun = "не удалось запустить";
13 | public string AlreadyRunning = "уже запущен";
14 |
15 | public BrowserPluginCommand[] Commands =
16 | {
17 | new BrowserPluginCommand
18 | {
19 | Name = "Run Yandex",
20 | Tokens = new[]
21 | {
22 | new Token
23 | {
24 | SuccessRate = 90,
25 | Type = TokenType.Command,
26 | Value = new[] {"запусти", "открой"}
27 | },
28 | new Token
29 | {
30 | SuccessRate = 90,
31 | Type = TokenType.Command,
32 | Value = new[] {"яндекс"}
33 | }
34 | },
35 | Response = "Яндекс запущен",
36 | URL = "www.yandex.ru",
37 | isStopCommand = false,
38 | useStandAloneBrowser = true
39 | },
40 | new BrowserPluginCommand
41 | {
42 | Name = "Stop Yandex",
43 | Tokens = new[]
44 | {
45 | new Token
46 | {
47 | SuccessRate = 90,
48 | Type = TokenType.Command,
49 | Value = new[] {"останови", "закрой"}
50 | },
51 | new Token
52 | {
53 | SuccessRate = 90,
54 | Type = TokenType.Command,
55 | Value = new[] {"яндекс"}
56 | }
57 | },
58 | Response = "Яндекс закрыт",
59 | URL = "www.yandex.ru",
60 | isStopCommand = true,
61 | useStandAloneBrowser = true
62 | },
63 | new BrowserPluginCommand
64 | {
65 | Name = "Run Google",
66 | Tokens = new[]
67 | {
68 | new Token
69 | {
70 | SuccessRate = 90,
71 | Type = TokenType.Command,
72 | Value = new[] {"запусти", "открой" }
73 | },
74 | new Token
75 | {
76 | SuccessRate = 90,
77 | Type = TokenType.Command,
78 | Value = new[] {"гугл"}
79 | }
80 | },
81 | Response = "Гугл запущен",
82 | URL = "www.google.com",
83 | isStopCommand = false,
84 | useStandAloneBrowser = false
85 | },
86 | new BrowserPluginCommand
87 | {
88 | Name = "Stop Google",
89 | Tokens = new[]
90 | {
91 | new Token
92 | {
93 | SuccessRate = 90,
94 | Type = TokenType.Command,
95 | Value = new[] {"останови", "закрой"}
96 | },
97 | new Token
98 | {
99 | SuccessRate = 90,
100 | Type = TokenType.Command,
101 | Value = new[] { "гугл" }
102 | }
103 | },
104 | Response = "Гугл закрыт",
105 | URL = "www.google.com",
106 | isStopCommand = true,
107 | useStandAloneBrowser = false
108 | },
109 | new BrowserPluginCommand
110 | {
111 | Name = "Run Kinopoisk",
112 | Tokens = new[]
113 | {
114 | new Token
115 | {
116 | SuccessRate = 90,
117 | Type = TokenType.Command,
118 | Value = new[] {"запусти", "открой" }
119 | },
120 | new Token
121 | {
122 | SuccessRate = 90,
123 | Type = TokenType.Command,
124 | Value = new[] {"кинопоиск"}
125 | }
126 | },
127 | Response = "Кинопоиск запущен",
128 | URL = "www.kinopoisk.ru",
129 | isStopCommand = false,
130 | useStandAloneBrowser = false
131 | },
132 | new BrowserPluginCommand
133 | {
134 | Name = "Stop Kinopoisk",
135 | Tokens = new[]
136 | {
137 | new Token
138 | {
139 | SuccessRate = 90,
140 | Type = TokenType.Command,
141 | Value = new[] {"останови", "закрой"}
142 | },
143 | new Token
144 | {
145 | SuccessRate = 90,
146 | Type = TokenType.Command,
147 | Value = new[] { "кинопоиск" }
148 | }
149 | },
150 | Response = "Кинопоиск закрыт",
151 | URL = "www.kinopoisk.ru",
152 | isStopCommand = true,
153 | useStandAloneBrowser = false
154 | }
155 | };
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/BrowserPlugin/BrowserPluginSettings_eng.json:
--------------------------------------------------------------------------------
1 | {
2 | "CanNotClose": "can not close",
3 | "NotRunning": "not running",
4 | "CanNotRun": "can not run",
5 | "AlreadyRunning": "already running",
6 | "Commands": [
7 | {
8 | "Response": "Yandex is running",
9 | "URL": "www.yandex.ru",
10 | "isStopCommand": false,
11 | "useStandAloneBrowser": true,
12 | "Name": "Run Yandex",
13 | "Tokens": [
14 | {
15 | "Value": [
16 | "Start",
17 | "Open"
18 | ],
19 | "Type": "Command",
20 | "SuccessRate": 90
21 | },
22 | {
23 | "Value": [
24 | "yandex"
25 | ],
26 | "Type": "Command",
27 | "SuccessRate": 90
28 | }
29 | ]
30 | },
31 | {
32 | "Response": "Yandex is closed",
33 | "URL": "www.yandex.ru",
34 | "isStopCommand": true,
35 | "useStandAloneBrowser": true,
36 | "Name": "Stop Yandex",
37 | "Tokens": [
38 | {
39 | "Value": [
40 | "Stop",
41 | "Close"
42 | ],
43 | "Type": "Command",
44 | "SuccessRate": 90
45 | },
46 | {
47 | "Value": [
48 | "yandex"
49 | ],
50 | "Type": "Command",
51 | "SuccessRate": 90
52 | }
53 | ]
54 | },
55 | {
56 | "Response": "Google is running",
57 | "URL": "www.google.com",
58 | "isStopCommand": false,
59 | "useStandAloneBrowser": false,
60 | "Name": "Run Google",
61 | "Tokens": [
62 | {
63 | "Value": [
64 | "Start",
65 | "Open"
66 | ],
67 | "Type": "Command",
68 | "SuccessRate": 90
69 | },
70 | {
71 | "Value": [
72 | "google"
73 | ],
74 | "Type": "Command",
75 | "SuccessRate": 90
76 | }
77 | ]
78 | },
79 | {
80 | "Response": "Google is closed",
81 | "URL": "www.google.com",
82 | "isStopCommand": true,
83 | "useStandAloneBrowser": false,
84 | "Name": "Stop Google",
85 | "Tokens": [
86 | {
87 | "Value": [
88 | "Stop",
89 | "Close"
90 | ],
91 | "Type": "Command",
92 | "SuccessRate": 90
93 | },
94 | {
95 | "Value": [
96 | "google"
97 | ],
98 | "Type": "Command",
99 | "SuccessRate": 90
100 | }
101 | ]
102 | }
103 | ]
104 | }
--------------------------------------------------------------------------------
/CurrencyRatePlugin/CurrencyRatePlugin.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Net;
8 | using System.Threading.Tasks;
9 | using System.Xml.Linq;
10 |
11 | using PluginInterface;
12 |
13 | namespace CurrencyRatePlugin
14 | {
15 | public class CurrencyRatePlugin : PluginBase
16 | {
17 | private readonly CurrencyRatePluginCommand[] CurrencyRateCommands;
18 | private readonly string CurrencyServiceUrl;
19 | private readonly string CurrencyDecimalSeparatorWord;
20 |
21 | public CurrencyRatePlugin(IAudioOutSingleton audioOut, string currentCulture, string pluginPath) : base(audioOut, currentCulture, pluginPath)
22 | {
23 | var configBuilder = new Config($"{PluginPath}\\{PluginConfigFile}");
24 | if (!File.Exists($"{PluginPath}\\{PluginConfigFile}"))
25 | {
26 | configBuilder.SaveConfig();
27 | }
28 |
29 | CurrencyRateCommands = configBuilder.ConfigStorage.Commands;
30 |
31 | if (CurrencyRateCommands is PluginCommand[] newCmds)
32 | {
33 | _commands = newCmds;
34 | }
35 | CurrencyServiceUrl = configBuilder.ConfigStorage.CurrencyServiceUrl;
36 | CurrencyDecimalSeparatorWord = configBuilder.ConfigStorage.CurrencyDecimalSeparatorWord;
37 | }
38 |
39 | public override void Execute(string commandName, List commandTokens)
40 | {
41 | var command = CurrencyRateCommands.FirstOrDefault(n => n.Name == commandName);
42 |
43 | if (command == null)
44 | {
45 | return;
46 | }
47 |
48 | var currencyRate = GetCurrencyRate(CurrencyServiceUrl, command.CurencyCode, command.RateDecimalRound).Result;
49 | if (currencyRate.Item1 > 0)
50 | {
51 | var message = string.Format(command.Response, "", currencyRate.Item1, currencyRate.Item2
52 | .ToString()
53 | .Replace(System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator,
54 | $" {CurrencyDecimalSeparatorWord} "));
55 | AudioOut.Speak(message);
56 | }
57 | }
58 |
59 | private async Task<(int, float)> GetCurrencyRate(string currencyServiceUrl, string curencyCode, int decimalRound)
60 | {
61 | var currencyRates = await GetRate(currencyServiceUrl);
62 | if (currencyRates == null)
63 | return (-1, -1);
64 |
65 | var currencyRate = currencyRates.FirstOrDefault(n => n.CurrencyCode == curencyCode);
66 | if (currencyRate == null)
67 | return (-1, -1);
68 |
69 | if (!int.TryParse(currencyRate.Nominal, out var nominal))
70 | return (-1, -1);
71 | var decimalSeparator = System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator;
72 | var v = currencyRate.Value.Replace(".", decimalSeparator);
73 | v = v.Replace(",", decimalSeparator);
74 | v = v.Substring(0, v.IndexOf(decimalSeparator) + decimalRound + 1);
75 | if (!float.TryParse(v, out var val))
76 | return (-1, -1);
77 |
78 | return (nominal, val);
79 | }
80 |
81 | private async Task GetRate(string currencyServiceUrl)
82 | {
83 | try
84 | {
85 | HttpWebRequest request = (HttpWebRequest)WebRequest.Create(currencyServiceUrl);
86 | request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
87 |
88 | using (var response = await request.GetResponseAsync())
89 | {
90 | using (Stream stream = response.GetResponseStream())
91 | {
92 | using (StreamReader reader = new StreamReader(stream))
93 | {
94 | var xmlDoc = await reader.ReadToEndAsync();
95 | XDocument xdoc = XDocument.Parse(xmlDoc);
96 |
97 | // получаем корневой узел
98 | XElement? rates = xdoc.Element("ValCurs");
99 | var currencyRates = new List();
100 |
101 | if (rates != null)
102 | {
103 | // проходим по всем элементам person
104 | foreach (XElement rate in rates.Elements("Valute"))
105 | {
106 | var code = rate.Element("CharCode");
107 | var name = rate.Element("Name");
108 | var nom = rate.Element("Nominal");
109 | var val = rate.Element("Value");
110 |
111 | var newRate = new CurrencyRate()
112 | {
113 | CurrencyCode = code?.Value,
114 | CurrencyName = name?.Value,
115 | Nominal = nom?.Value,
116 | Value = val?.Value
117 | };
118 |
119 | currencyRates.Add(newRate);
120 | }
121 | }
122 |
123 | return currencyRates.ToArray();
124 | }
125 | }
126 | }
127 | }
128 | catch (Exception ex)
129 | {
130 | Console.WriteLine($"Error reading from {currencyServiceUrl}: {ex.Message}");
131 |
132 | return null;
133 | }
134 | }
135 | }
136 |
137 | public class CurrencyRate
138 | {
139 | public string CurrencyCode;
140 | public string CurrencyName;
141 | public string Nominal;
142 | public string Value;
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/CurrencyRatePlugin/CurrencyRatePlugin.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/CurrencyRatePlugin/CurrencyRatePluginCommand.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using PluginInterface;
4 |
5 | namespace CurrencyRatePlugin
6 | {
7 | public class CurrencyRatePluginCommand : PluginCommand
8 | {
9 | public string CurencyCode = "";
10 | public int RateDecimalRound = 2;
11 | public string Response = "";
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/CurrencyRatePlugin/CurrencyRatePluginSettings.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using PluginInterface;
4 |
5 | namespace CurrencyRatePlugin
6 | {
7 | public class CurrencyRatePluginSettings
8 | {
9 | public string CurrencyServiceUrl = "http://www.cbr.ru/scripts/XML_daily.asp";
10 | public string CurrencyDecimalSeparatorWord = "точка";
11 |
12 | //[JsonProperty(Required = Required.Always)]
13 | public CurrencyRatePluginCommand[] Commands =
14 | {
15 | new CurrencyRatePluginCommand
16 | {
17 | Name = "Short USD request",
18 | Tokens = new[]
19 | {
20 | new Token
21 | {
22 | SuccessRate = 90,
23 | Type = TokenType.Command,
24 | Value = new[] {"курс"}
25 | },
26 | new Token
27 | {
28 | SuccessRate = 90,
29 | Type = TokenType.Command,
30 | Value = new[] {"доллара"}
31 | }
32 | },
33 | CurencyCode = "USD",
34 | RateDecimalRound=1,
35 | Response = "{1} доллар равен {2} рублей"
36 | },
37 | new CurrencyRatePluginCommand
38 | {
39 | Name = "Long USD request",
40 | Tokens = new[]
41 | {
42 | new Token
43 | {
44 | SuccessRate = 90,
45 | Type = TokenType.Command,
46 | Value = new[] {"какой"}
47 | },
48 | new Token
49 | {
50 | SuccessRate = 90,
51 | Type = TokenType.Command,
52 | Value = new[] {"курс"}
53 | },
54 | new Token
55 | {
56 | SuccessRate = 90,
57 | Type = TokenType.Command,
58 | Value = new[] {"доллара"}
59 | }
60 | },
61 | CurencyCode = "USD",
62 | RateDecimalRound=1,
63 | Response = "{1} доллар равен {2} рублей"
64 | },
65 | new CurrencyRatePluginCommand
66 | {
67 | Name = "Short EUR request",
68 | Tokens = new[]
69 | {
70 | new Token
71 | {
72 | SuccessRate = 90,
73 | Type = TokenType.Command,
74 | Value = new[] {"курс"}
75 | },
76 | new Token
77 | {
78 | SuccessRate = 90,
79 | Type = TokenType.Command,
80 | Value = new[] { "евро" }
81 | }
82 | },
83 | CurencyCode = "EUR",
84 | RateDecimalRound=1,
85 | Response = "{1} евро равен {2} рублей"
86 | },
87 | new CurrencyRatePluginCommand
88 | {
89 | Name = "Long EUR request",
90 | Tokens = new[]
91 | {
92 | new Token
93 | {
94 | SuccessRate = 90,
95 | Type = TokenType.Command,
96 | Value = new[] {"какой"}
97 | },
98 | new Token
99 | {
100 | SuccessRate = 90,
101 | Type = TokenType.Command,
102 | Value = new[] {"курс"}
103 | },
104 | new Token
105 | {
106 | SuccessRate = 90,
107 | Type = TokenType.Command,
108 | Value = new[] {"евро"}
109 | }
110 | },
111 | CurencyCode = "EUR",
112 | RateDecimalRound=1,
113 | Response = "{1} евро равен {2} рублей"
114 | },
115 | };
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/CurrencyRatePlugin/CurrencyRatePluginSettings_eng.json:
--------------------------------------------------------------------------------
1 | {
2 | "CurrencyServiceUrl": "http://www.cbr.ru/scripts/XML_daily.asp",
3 | "CurrencyDecimalSeparatorWord": "dot",
4 | "Commands": [
5 | {
6 | "CurencyCode": "USD",
7 | "RateDecimalRound": 1,
8 | "Response": "{1} dollar is {2} rubles",
9 | "Name": "Short USD request",
10 | "Tokens": [
11 | {
12 | "Value": [
13 | "dollar"
14 | ],
15 | "Type": "Command",
16 | "SuccessRate": 90
17 | },
18 | {
19 | "Value": [
20 | "exchange"
21 | ],
22 | "Type": "Command",
23 | "SuccessRate": 90
24 | },
25 | {
26 | "Value": [
27 | "rate"
28 | ],
29 | "Type": "Command",
30 | "SuccessRate": 90
31 | }
32 | ]
33 | },
34 | {
35 | "CurencyCode": "USD",
36 | "RateDecimalRound": 1,
37 | "Response": "{1} dollar is {2} rubles",
38 | "Name": "Long USD request",
39 | "Tokens": [
40 | {
41 | "Value": [
42 | "What"
43 | ],
44 | "Type": "Command",
45 | "SuccessRate": 90
46 | },
47 | {
48 | "Value": [
49 | "is "
50 | ],
51 | "Type": "Command",
52 | "SuccessRate": 90
53 | },
54 | {
55 | "Value": [
56 | "the"
57 | ],
58 | "Type": "Command",
59 | "SuccessRate": 90
60 | },
61 | {
62 | "Value": [
63 | "dollar"
64 | ],
65 | "Type": "Command",
66 | "SuccessRate": 90
67 | },
68 | {
69 | "Value": [
70 | "exchange"
71 | ],
72 | "Type": "Command",
73 | "SuccessRate": 90
74 | },
75 | {
76 | "Value": [
77 | "rate"
78 | ],
79 | "Type": "Command",
80 | "SuccessRate": 90
81 | }
82 | ]
83 | },
84 | {
85 | "CurencyCode": "EUR",
86 | "RateDecimalRound": 1,
87 | "Response": "{1} euro is {2} rubles",
88 | "Name": "Short EUR request",
89 | "Tokens": [
90 | {
91 | "Value": [
92 | "euro"
93 | ],
94 | "Type": "Command",
95 | "SuccessRate": 90
96 | },
97 | {
98 | "Value": [
99 | "exchange"
100 | ],
101 | "Type": "Command",
102 | "SuccessRate": 90
103 | },
104 | {
105 | "Value": [
106 | "rate"
107 | ],
108 | "Type": "Command",
109 | "SuccessRate": 90
110 | }
111 | ]
112 | },
113 | {
114 | "CurencyCode": "EUR",
115 | "RateDecimalRound": 1,
116 | "Response": "{1} euro is {2} rubles",
117 | "Name": "Long EUR request",
118 | "Tokens": [
119 | {
120 | "Value": [
121 | "What"
122 | ],
123 | "Type": "Command",
124 | "SuccessRate": 90
125 | },
126 | {
127 | "Value": [
128 | "is "
129 | ],
130 | "Type": "Command",
131 | "SuccessRate": 90
132 | },
133 | {
134 | "Value": [
135 | "the"
136 | ],
137 | "Type": "Command",
138 | "SuccessRate": 90
139 | },
140 | {
141 | "Value": [
142 | "euro"
143 | ],
144 | "Type": "Command",
145 | "SuccessRate": 90
146 | },
147 | {
148 | "Value": [
149 | "exchange"
150 | ],
151 | "Type": "Command",
152 | "SuccessRate": 90
153 | },
154 | {
155 | "Value": [
156 | "rate"
157 | ],
158 | "Type": "Command",
159 | "SuccessRate": 90
160 | }
161 | ]
162 | }
163 | ]
164 | }
--------------------------------------------------------------------------------
/GoogleCalendarPlugin/CalendarEvents.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using Google.Apis.Calendar.v3.Data;
4 |
5 | using System;
6 |
7 | namespace GoogleCalendarPlugin
8 | {
9 | public partial class GoogleCalendarPlugin
10 | {
11 | private class CalendarEvents
12 | {
13 | public string Attendees = string.Empty;
14 | public string Description = string.Empty;
15 | public string Location = string.Empty;
16 | public string Summary = string.Empty;
17 |
18 | private readonly DateTime? Start;
19 | public string StartYear => Start?.Year.ToString() ?? string.Empty;
20 | public string StartMonth => Start?.Month.ToString() ?? string.Empty;
21 | public string StartDay => Start?.Day.ToString() ?? string.Empty;
22 |
23 | public string StartDate
24 | {
25 | get
26 | {
27 | return ((DateTime)Start).ToString("dd MMMM");
28 | }
29 | }
30 |
31 | public string StartTime
32 | {
33 | get
34 | {
35 | string result = NumberToString(Start?.Hour ?? 0, oneHour, twoHours, fiveHours);
36 | result += NumberToString(Start?.Minute ?? 0, oneMinute, twoMinutes, fiveMinutes);
37 |
38 | return result;
39 | }
40 | }
41 |
42 | private readonly DateTime? End;
43 | public string EndYear => End?.Year.ToString() ?? string.Empty;
44 | public string EndMonth => End?.Month.ToString() ?? string.Empty;
45 | public string EndDay => End?.Day.ToString() ?? string.Empty;
46 |
47 | public string EndDate
48 | {
49 | get
50 | {
51 | return ((DateTime)End).ToString("dd MMMM");
52 | }
53 | }
54 |
55 | public string EndTime
56 | {
57 | get
58 | {
59 | string result = NumberToString(End?.Hour ?? 0, oneHour, twoHours, fiveHours);
60 | result += NumberToString(End?.Minute ?? 0, oneMinute, twoMinutes, fiveMinutes);
61 |
62 | return result;
63 | }
64 | }
65 |
66 | private int _lengthHour = -1;
67 | private int LengthHour
68 | {
69 | get
70 | {
71 | if (_lengthHour < 0)
72 | {
73 | if (Start != null && End != null)
74 | {
75 | var diff = ((DateTime)End).Subtract((DateTime)Start);
76 | _lengthHour = (int)diff.TotalHours;
77 | }
78 | else
79 | {
80 | _lengthHour = 0;
81 | }
82 | }
83 |
84 | return _lengthHour;
85 | }
86 | }
87 |
88 | private int _lengthMinute = -1;
89 | private int LengthMinute
90 | {
91 | get
92 | {
93 | if (_lengthMinute < 0)
94 | {
95 | if (Start != null && End != null)
96 | {
97 | var diff = ((DateTime)End).Subtract((DateTime)Start);
98 | _lengthMinute = (int)diff.TotalMinutes;
99 | }
100 | else
101 | {
102 | _lengthMinute = 0;
103 | }
104 | }
105 |
106 | return _lengthMinute;
107 | }
108 | }
109 |
110 | public CalendarEvents(Event calendarEvent)
111 | {
112 | if (calendarEvent.Attendees != null)
113 | {
114 | foreach (var attendee in calendarEvent.Attendees)
115 | {
116 | Attendees = attendee + ",";
117 | }
118 | }
119 | else
120 | {
121 | Attendees = string.Empty;
122 | }
123 |
124 | Description = calendarEvent.Description ?? string.Empty;
125 | Location = calendarEvent.Location ?? string.Empty;
126 | Summary = calendarEvent.Summary ?? string.Empty;
127 | Start = calendarEvent.Start.DateTime ?? default;
128 | End = calendarEvent.End.DateTime ?? default;
129 | }
130 |
131 | public string Length
132 | {
133 | get
134 | {
135 | string result = NumberToString(LengthHour, oneHour, twoHours, fiveHours);
136 | result += NumberToString(LengthMinute, oneMinute, twoMinutes, fiveMinutes);
137 |
138 | return result;
139 | }
140 | }
141 |
142 | private string NumberToString(int number, string one, string two, string five)
143 | {
144 | string result = "";
145 |
146 | if (number > 0)
147 | {
148 | int lastNumber = number % 10;
149 | result += number.ToString() + " ";
150 | if (lastNumber == 1)
151 | result += one + " ";
152 | else if (lastNumber > 1 && lastNumber < 5)
153 | result += two + " ";
154 | else if (lastNumber > 5)
155 | result += five + " ";
156 | }
157 |
158 | return result;
159 |
160 | }
161 | }
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/GoogleCalendarPlugin/GoogleCalendarPlugin.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using Google.Apis.Auth.OAuth2;
4 | using Google.Apis.Calendar.v3;
5 | using Google.Apis.Calendar.v3.Data;
6 | using Google.Apis.Services;
7 | using Google.Apis.Util.Store;
8 |
9 | using PluginInterface;
10 |
11 | using System;
12 | using System.Collections.Generic;
13 | using System.IO;
14 | using System.Linq;
15 | using System.Text;
16 | using System.Threading;
17 |
18 | namespace GoogleCalendarPlugin
19 | {
20 | public partial class GoogleCalendarPlugin : PluginBase
21 | {
22 | private readonly GoogleCalendarPluginCommand[] GoogleCalendarCommands;
23 | private readonly string[] Scopes = { CalendarService.Scope.Calendar };
24 | private readonly string ApplicationName = "GoogleCalendarPlugin";
25 | private readonly string GoogleApiCredentials = "";
26 | private readonly string credPath = "token_json";
27 |
28 | private static readonly string oneHour = "час";
29 | private static readonly string twoHours = "часа";
30 | private static readonly string fiveHours = "часов";
31 |
32 | private static readonly string oneMinute = "минута";
33 | private static readonly string twoMinutes = "минуты";
34 | private static readonly string fiveMinutes = "минут";
35 |
36 | private readonly string moreResultsAvailableMessage;
37 | private readonly string noEventsMessage;
38 | private readonly string NoDataMessage;
39 |
40 | public GoogleCalendarPlugin(IAudioOutSingleton audioOut, string currentCulture, string pluginPath) : base(audioOut, currentCulture, pluginPath)
41 | {
42 | var configBuilder = new Config($"{PluginPath}\\{PluginConfigFile}");
43 | if (!File.Exists($"{PluginPath}\\{PluginConfigFile}"))
44 | {
45 | configBuilder.SaveConfig();
46 | }
47 |
48 | GoogleCalendarCommands = configBuilder.ConfigStorage.Commands;
49 |
50 | if (GoogleCalendarCommands is PluginCommand[] newCmds)
51 | {
52 | _commands = newCmds;
53 | }
54 | moreResultsAvailableMessage = configBuilder.ConfigStorage.MoreResultsAvailableMessage;
55 | noEventsMessage = configBuilder.ConfigStorage.NoEventsMessage;
56 | NoDataMessage = configBuilder.ConfigStorage.NoDataMessage;
57 | }
58 |
59 | public override void Execute(string commandName, List commandTokens)
60 | {
61 | var command = GoogleCalendarCommands.FirstOrDefault(n => n.Name == commandName);
62 | if (command == null)
63 | {
64 | return;
65 | }
66 |
67 | var events = GetEvents(GoogleApiCredentials, command.CalendarId, command.DaysStart, command.DaysCount, command.MaxEvents, out var moreEvents);
68 |
69 | if (events?.Length <= 0)
70 | {
71 | AudioOut.Speak(NoDataMessage);
72 | return;
73 | }
74 |
75 | var eventsMessage = new StringBuilder();
76 | foreach (var eventItem in events)
77 | {
78 | eventsMessage.Append(PluginTools.FormatStringWithClassFields(command.SingleEventMessage, eventItem));
79 | }
80 |
81 | if (eventsMessage.Length <= 0)
82 | {
83 | eventsMessage.Append(noEventsMessage);
84 | }
85 |
86 | var message = string.Format(command.Response, null, eventsMessage);
87 | if (moreEvents)
88 | {
89 | message += moreResultsAvailableMessage;
90 | }
91 |
92 | AudioOut.Speak(message);
93 | }
94 |
95 | private CalendarEvents[] GetEvents(string apiCredentials, string calendarName, int daysStart, int daysCount, int maxEvents, out bool moreEvents)
96 | {
97 | moreEvents = false;
98 | UserCredential credential;
99 | var result = new List();
100 |
101 | try
102 | {
103 | //new FileStream("credentials.json", FileMode.Open, FileAccess.Read))
104 | using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(apiCredentials)))
105 | {
106 | // The file token.json stores the user's access and refresh tokens, and is created
107 | // automatically when the authorization flow completes for the first time.
108 | credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
109 | GoogleClientSecrets.FromStream(stream).Secrets,
110 | Scopes,
111 | "user",
112 | CancellationToken.None,
113 | new FileDataStore($"{PluginPath}\\{credPath}", true)).Result;
114 | }
115 |
116 | // Create Google Calendar API service.
117 | using var service = new CalendarService(new BaseClientService.Initializer()
118 | {
119 | HttpClientInitializer = credential,
120 | ApplicationName = ApplicationName,
121 | });
122 |
123 | if (string.IsNullOrEmpty(calendarName))
124 | {
125 | var calendarsRequest = service.CalendarList.List();
126 | var calendars = calendarsRequest.Execute();
127 |
128 | if (calendars != null)
129 | {
130 | Console.WriteLine("Available calendars:");
131 |
132 | foreach (var calendar in calendars.Items)
133 | {
134 | Console.WriteLine($"ID: {calendar.Id}\r\nDescription: {calendar.Description}\r\nSummary: {calendar.Summary}\r\n");
135 | }
136 | }
137 |
138 | // set calendar name to default
139 | calendarName = "primary";
140 | }
141 |
142 | // Define parameters of request
143 | EventsResource.ListRequest request = service.Events.List(calendarName); // "****@gmail.com", "primary", "addressbook#contacts@group.v.calendar.google.com"
144 | request.ShowDeleted = false;
145 | request.SingleEvents = true;
146 | request.MaxResults = maxEvents;
147 | request.OrderBy = EventsResource.ListRequest.OrderByEnum.StartTime;
148 | request.TimeMax = DateTime.Today.AddDays(daysCount);
149 | if (daysStart == 0)
150 | request.TimeMin = DateTime.Today.AddDays(daysStart);
151 | else
152 | request.TimeMin = DateTime.Now;
153 |
154 | // List events
155 | Events events = request.Execute();
156 | if (events.Items != null)
157 | {
158 | foreach (var eventItem in events.Items)
159 | {
160 | result.Add(new CalendarEvents(eventItem));
161 | }
162 | }
163 |
164 | // do we have more events pages? No use to list too many events at once
165 | moreEvents = !string.IsNullOrEmpty(events.NextPageToken);
166 |
167 | }
168 | catch (Exception ex)
169 | {
170 | Console.WriteLine($"Can't get GoogleCalendar data: {ex.Message}");
171 | }
172 |
173 | return result.ToArray();
174 | }
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/GoogleCalendarPlugin/GoogleCalendarPlugin.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 | true
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | PreserveNewest
19 |
20 |
21 | PreserveNewest
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/GoogleCalendarPlugin/GoogleCalendarPluginCommand.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using PluginInterface;
4 |
5 | namespace GoogleCalendarPlugin
6 | {
7 | public class GoogleCalendarPluginCommand : PluginCommand
8 | {
9 | public string SingleEventMessage = "";
10 | public string Response = "";
11 | public string CalendarId = "";
12 | public int DaysStart = 0;
13 | public int DaysCount = 7;
14 | public int MaxEvents = 10;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/GoogleCalendarPlugin/GoogleCalendarPluginSettings.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using PluginInterface;
4 |
5 | namespace GoogleCalendarPlugin
6 | {
7 | public class GoogleCalendarPluginSettings
8 | {
9 | public string[] ConfigurationNote =
10 | {
11 | "Interpolation macros:",
12 | "Only for \"SingleEventMessage\":",
13 | "{Attendees} - list of attendees",
14 | "{Description} - event description",
15 | "{Location} - event location",
16 | "{Summary} - event summary",
17 | "{Length} - event duration",
18 | "{StartYear} - event start year",
19 | "{StartMonth} - event start month",
20 | "{StartDay} - event start day",
21 | "{StarDate} - event start day and month",
22 | "{StarTime} - event start hour and minute",
23 | "{EndYear} - event end year",
24 | "{EndMonth} - event end month",
25 | "{EndDay} - event end day",
26 | "{EndDate} - event end day and month",
27 | "{EndTime} - event end hour and minute",
28 | "",
29 | "Only for \"Response\":",
30 | "{1} - use SingleEventMessage sample",
31 | };
32 |
33 | //[JsonProperty(Required = Required.Always)]
34 | public GoogleCalendarPluginCommand[] Commands =
35 | {
36 | new GoogleCalendarPluginCommand
37 | {
38 | Name = "Today's events",
39 | Tokens = new[]
40 | {
41 | new Token
42 | {
43 | SuccessRate = 90,
44 | Type = TokenType.Command,
45 | Value = new[] {"Календарь", "События", "Расписание"}
46 | },
47 | new Token
48 | {
49 | SuccessRate = 90,
50 | Type = TokenType.Command,
51 | Value = new[] {"на"}
52 | },
53 | new Token
54 | {
55 | SuccessRate = 90,
56 | Type = TokenType.Command,
57 | Value = new[] {"сегодня"}
58 | }
59 | },
60 | CalendarId = "",
61 | DaysStart = 0,
62 | DaysCount = 1,
63 | SingleEventMessage = "{StarTime} - {Summary}",
64 | Response = "Расписание на сегодня: {1}",
65 | MaxEvents = 10
66 | },
67 | new GoogleCalendarPluginCommand
68 | {
69 | Name = "Tomorrow's events",
70 | Tokens = new[]
71 | {
72 | new Token
73 | {
74 | SuccessRate = 90,
75 | Type = TokenType.Command,
76 | Value = new[] {"Календарь", "События", "Расписание"}
77 | },
78 | new Token
79 | {
80 | SuccessRate = 90,
81 | Type = TokenType.Command,
82 | Value = new[] {"на"}
83 | },
84 | new Token
85 | {
86 | SuccessRate = 90,
87 | Type = TokenType.Command,
88 | Value = new[] {"завтра"}
89 | }
90 | },
91 | CalendarId = "",
92 | DaysStart = 1,
93 | DaysCount = 1,
94 | SingleEventMessage = "{StarTime} - {Summary}",
95 | Response = "Расписание на завтра: {1}",
96 | MaxEvents = 10
97 | },
98 | new GoogleCalendarPluginCommand
99 | {
100 | Name = "Today's birthdays",
101 | Tokens = new[]
102 | {
103 | new Token
104 | {
105 | SuccessRate = 90,
106 | Type = TokenType.Command,
107 | Value = new[] {"Дни"}
108 | },
109 | new Token
110 | {
111 | SuccessRate = 90,
112 | Type = TokenType.Command,
113 | Value = new[] {"рождения"}
114 | },
115 | new Token
116 | {
117 | SuccessRate = 90,
118 | Type = TokenType.Command,
119 | Value = new[] {"сегодня"}
120 | }
121 | },
122 | CalendarId = "addressbook#contacts@group.v.calendar.google.com",
123 | DaysStart = 0,
124 | DaysCount = 1,
125 | SingleEventMessage = "{Summary}",
126 | Response = "Дни рождения сегодня: {1}",
127 | MaxEvents = 10
128 | },
129 | new GoogleCalendarPluginCommand
130 | {
131 | Name = "Tomorrow's birthdays",
132 | Tokens = new[]
133 | {
134 | new Token
135 | {
136 | SuccessRate = 90,
137 | Type = TokenType.Command,
138 | Value = new[] {"Дни"}
139 | },
140 | new Token
141 | {
142 | SuccessRate = 90,
143 | Type = TokenType.Command,
144 | Value = new[] {"рождения"}
145 | },
146 | new Token
147 | {
148 | SuccessRate = 90,
149 | Type = TokenType.Command,
150 | Value = new[] { "завтра" }
151 | }
152 | },
153 | CalendarId = "addressbook#contacts@group.v.calendar.google.com",
154 | DaysStart = 0,
155 | DaysCount = 1,
156 | SingleEventMessage = "{Summary}",
157 | Response = "Дни рождения завтра: {1}",
158 | MaxEvents = 10
159 | },
160 | new GoogleCalendarPluginCommand
161 | {
162 | Name = "Upcoming birthdays",
163 | Tokens = new[]
164 | {
165 | new Token
166 | {
167 | SuccessRate = 90,
168 | Type = TokenType.Command,
169 | Value = new[] {"Ближайшие"}
170 | },
171 | new Token
172 | {
173 | SuccessRate = 90,
174 | Type = TokenType.Command,
175 | Value = new[] {"дни"}
176 | },
177 | new Token
178 | {
179 | SuccessRate = 90,
180 | Type = TokenType.Command,
181 | Value = new[] {"рождения"}
182 | },
183 | },
184 | CalendarId = "addressbook#contacts@group.v.calendar.google.com",
185 | DaysStart = 0,
186 | DaysCount = 7,
187 | SingleEventMessage = "{StarDate} - {Summary}",
188 | Response = "Приближающиеся дни рождения: {1}",
189 | MaxEvents = 10
190 | }
191 | };
192 |
193 | public string MoreResultsAvailableMessage = "и дальнейшие события, не вошедшие в список";
194 | public string NoEventsMessage = "пусто";
195 | public string NoDataMessage = "не могу получить данные с сервера";
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/GoogleCalendarPlugin/GoogleCalendarPluginSettings_eng.json:
--------------------------------------------------------------------------------
1 | {
2 | "ConfigurationNote": [
3 | "Interpolation macros:",
4 | "Only for \"SingleEventMessage\":",
5 | "{Attendees} - list of attendees",
6 | "{Description} - event description",
7 | "{Location} - event location",
8 | "{Summary} - event summary",
9 | "{Length} - event duration",
10 | "{StartYear} - event start year",
11 | "{StartMonth} - event start month",
12 | "{StartDay} - event start day",
13 | "{StarDate} - event start day and month",
14 | "{StarTime} - event start hour and minute",
15 | "{EndYear} - event end year",
16 | "{EndMonth} - event end month",
17 | "{EndDay} - event end day",
18 | "{EndDate} - event end day and month",
19 | "{EndTime} - event end hour and minute",
20 | "",
21 | "Only for \"Response\":",
22 | "{1} - use SingleEventMessage sample"
23 | ],
24 | "Commands": [
25 | {
26 | "SingleEventMessage": "{StarTime} - {Summary}",
27 | "Response": "Today's events: {1}",
28 | "CalendarId": "",
29 | "DaysStart": 0,
30 | "DaysCount": 1,
31 | "MaxEvents": 10,
32 | "Name": "Today's events",
33 | "Tokens": [
34 | {
35 | "Value": [
36 | "Schedule",
37 | "Events"
38 | ],
39 | "Type": "Command",
40 | "SuccessRate": 90
41 | },
42 | {
43 | "Value": [
44 | "for"
45 | ],
46 | "Type": "Command",
47 | "SuccessRate": 90
48 | },
49 | {
50 | "Value": [
51 | "today"
52 | ],
53 | "Type": "Command",
54 | "SuccessRate": 90
55 | }
56 | ]
57 | },
58 | {
59 | "SingleEventMessage": "{StarTime} - {Summary}",
60 | "Response": "Tomorrow's events: {1}",
61 | "CalendarId": "",
62 | "DaysStart": 1,
63 | "DaysCount": 1,
64 | "MaxEvents": 10,
65 | "Name": "Tomorrow's events",
66 | "Tokens": [
67 | {
68 | "Value": [
69 | "Schedule",
70 | "Events"
71 | ],
72 | "Type": "Command",
73 | "SuccessRate": 90
74 | },
75 | {
76 | "Value": [
77 | "for"
78 | ],
79 | "Type": "Command",
80 | "SuccessRate": 90
81 | },
82 | {
83 | "Value": [
84 | "tomorrow"
85 | ],
86 | "Type": "Command",
87 | "SuccessRate": 90
88 | }
89 | ]
90 | },
91 | {
92 | "SingleEventMessage": "{Summary}",
93 | "Response": "Today's birthdays: {1}",
94 | "CalendarId": "addressbook#contacts@group.v.calendar.google.com",
95 | "DaysStart": 0,
96 | "DaysCount": 1,
97 | "MaxEvents": 10,
98 | "Name": "Today's birthdays",
99 | "Tokens": [
100 | {
101 | "Value": [
102 | "birthdays"
103 | ],
104 | "Type": "Command",
105 | "SuccessRate": 90
106 | },
107 | {
108 | "Value": [
109 | "for"
110 | ],
111 | "Type": "Command",
112 | "SuccessRate": 90
113 | },
114 | {
115 | "Value": [
116 | "today"
117 | ],
118 | "Type": "Command",
119 | "SuccessRate": 90
120 | }
121 | ]
122 | },
123 | {
124 | "SingleEventMessage": "{StarDate} - {Summary}",
125 | "Response": "Upcoming birthdays: {1}",
126 | "CalendarId": "addressbook#contacts@group.v.calendar.google.com",
127 | "DaysStart": 0,
128 | "DaysCount": 7,
129 | "MaxEvents": 10,
130 | "Name": "Upcoming birthdays",
131 | "Tokens": [
132 | {
133 | "Value": [
134 | "Upcoming"
135 | ],
136 | "Type": "Command",
137 | "SuccessRate": 90
138 | },
139 | {
140 | "Value": [
141 | "birthdays"
142 | ],
143 | "Type": "Command",
144 | "SuccessRate": 90
145 | }
146 | ]
147 | }
148 | ],
149 | "MoreResultsAvailableMessage": "and there are more events not fitted the list",
150 | "NoEventsMessage": "no events",
151 | "NoDataMessage": "can not get data from server"
152 | }
--------------------------------------------------------------------------------
/GoogleCalendarPlugin/birthdays_calendar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jekyll2014/VoiceAssistant/bea10e8c38475eb44d8f67e4f7300f4625a33276/GoogleCalendarPlugin/birthdays_calendar.jpg
--------------------------------------------------------------------------------
/GoogleCalendarPlugin/calendarId.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jekyll2014/VoiceAssistant/bea10e8c38475eb44d8f67e4f7300f4625a33276/GoogleCalendarPlugin/calendarId.jpg
--------------------------------------------------------------------------------
/HelloPlugin/HelloPlugin.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 |
7 | using PluginInterface;
8 |
9 | namespace HelloPlugin
10 | {
11 | public class HelloPlugin : PluginBase
12 | {
13 | private readonly HelloPluginCommand[] HelloCommands;
14 |
15 | public HelloPlugin(IAudioOutSingleton audioOut, string currentCulture, string pluginPath) : base(audioOut, currentCulture, pluginPath)
16 | {
17 | var configBuilder = new Config($"{PluginPath}\\{PluginConfigFile}");
18 | if (!File.Exists($"{PluginPath}\\{PluginConfigFile}"))
19 | {
20 | configBuilder.SaveConfig();
21 | }
22 |
23 | HelloCommands = configBuilder.ConfigStorage.Commands;
24 |
25 | if (HelloCommands is PluginCommand[] newCmds)
26 | {
27 | _commands = newCmds;
28 | }
29 |
30 | // example of listening to the audio/word stream from core module.
31 | //base.CanAcceptSound = true;
32 | //base.CanAcceptWords = true;
33 |
34 | // example of injecting command audio/text to execute by main module.
35 | //base.CanInjectSound = true;
36 | //base.CanInjectWords = true;
37 | }
38 |
39 | public override void Execute(string commandName, List commandTokens)
40 | {
41 | var command = HelloCommands.FirstOrDefault(n => n.Name == commandName);
42 |
43 | if (command == null)
44 | {
45 | return;
46 | }
47 | // example of listening to the audio/word stream from core module
48 | /*
49 | var sndData = GetSound();
50 | AudioOut.PlayDataBuffer(sndData);
51 |
52 | var wordsData = "";
53 | foreach (var w in GetWords())
54 | {
55 | wordsData += " " + w;
56 | }
57 | Console.WriteLine($"ReceivedText: {wordsData}");
58 | */
59 |
60 | // example of injecting command audio/text to execute by main module
61 | /*InjectTextCommand("Вася привет");
62 | InjectAudioCommand(new byte[1024], 44100, 16, 1);*/
63 |
64 | AudioOut.Speak(command.Response);
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/HelloPlugin/HelloPlugin.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/HelloPlugin/HelloPluginCommand.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using PluginInterface;
4 |
5 | namespace HelloPlugin
6 | {
7 | public class HelloPluginCommand : PluginCommand
8 | {
9 | public string Response = "";
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/HelloPlugin/HelloPluginSettings.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using PluginInterface;
4 |
5 | namespace HelloPlugin
6 | {
7 | public class HelloPluginSettings
8 | {
9 | //[JsonProperty(Required = Required.Always)]
10 | public HelloPluginCommand[] Commands =
11 | {
12 | new HelloPluginCommand
13 | {
14 | Name = "Greeting informal",
15 | Tokens = new[]
16 | {
17 | new Token
18 | {
19 | SuccessRate = 90,
20 | Type = TokenType.Command,
21 | Value = new[] {"привет"}
22 | }
23 | },
24 | Response = "И тебе привет"
25 | },
26 | new HelloPluginCommand
27 | {
28 | Name = "Greeting formal",
29 | Tokens = new[]
30 | {
31 | new Token
32 | {
33 | SuccessRate = 90,
34 | Type = TokenType.Command,
35 | Value = new[] {"Здравствуй"}
36 | }
37 | },
38 | Response = "И тебе не болеть"
39 | },
40 | new HelloPluginCommand
41 | {
42 | Name = "Greeting wishing",
43 | Tokens = new[]
44 | {
45 | new Token
46 | {
47 | SuccessRate = 90,
48 | Type = TokenType.Command,
49 | Value = new[] {"Доброго", "Добрый"}
50 | },
51 | new Token
52 | {
53 | SuccessRate = 90,
54 | Type = TokenType.Command,
55 | Value = new[] {"дня", "день"}
56 | }
57 | },
58 | Response = "И тебе доброго дня"
59 | },
60 | new HelloPluginCommand
61 | {
62 | Name = "Greeting short informal",
63 | Tokens = new[]
64 | {
65 | new Token
66 | {
67 | SuccessRate = 90,
68 | Type = TokenType.Command,
69 | Value = new[] {"Хай"}
70 | }
71 | },
72 | Response = "Хаюшки"
73 | }
74 | };
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/HelloPlugin/HelloPluginSettings_eng.json:
--------------------------------------------------------------------------------
1 | {
2 | "Commands": [
3 | {
4 | "Response": "Nice to hear you",
5 | "Name": "Greeting informal",
6 | "Tokens": [
7 | {
8 | "Value": [
9 | "Greeting"
10 | ],
11 | "Type": "Command",
12 | "SuccessRate": 90
13 | }
14 | ]
15 | },
16 | {
17 | "Response": "And you too",
18 | "Name": "Greeting formal",
19 | "Tokens": [
20 | {
21 | "Value": [
22 | "Hello"
23 | ],
24 | "Type": "Command",
25 | "SuccessRate": 90
26 | }
27 | ]
28 | },
29 | {
30 | "Response": "Have a good day too",
31 | "Name": "Greeting wishing",
32 | "Tokens": [
33 | {
34 | "Value": [
35 | "Have"
36 | ],
37 | "Type": "Command",
38 | "SuccessRate": 90
39 | },
40 | {
41 | "Value": [
42 | "a"
43 | ],
44 | "Type": "Command",
45 | "SuccessRate": 90
46 | },
47 | {
48 | "Value": [
49 | "good"
50 | ],
51 | "Type": "Command",
52 | "SuccessRate": 90
53 | },
54 | {
55 | "Value": [
56 | "day"
57 | ],
58 | "Type": "Command",
59 | "SuccessRate": 90
60 | }
61 | ]
62 | },
63 | {
64 | "Response": "Hi",
65 | "Name": "Greeting short informal",
66 | "Tokens": [
67 | {
68 | "Value": [
69 | "Hi"
70 | ],
71 | "Type": "Command",
72 | "SuccessRate": 90
73 | }
74 | ]
75 | }
76 | ]
77 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Andrey
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 |
--------------------------------------------------------------------------------
/MQTTInPlugin/MQTTInPlugin.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 | true
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/MQTTInPlugin/MQTTInPluginSettings.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using PluginInterface;
4 |
5 | namespace MQTTInPlugin
6 | {
7 | public class MQTTInPluginSettings
8 | {
9 | public string RequestServer = "";
10 | public int RequestServerPort = 1883;
11 | public string RequestServerLogin = "";
12 | public string RequestServerPassword = "";
13 | public string ClientID = "MQTTInPlugin";
14 | public bool AddTimeStampToClientID = true;
15 | public bool KeepConnectionAlive = true;
16 | public int ReconnectTimeOut = 60;
17 |
18 | //[JsonProperty(Required = Required.Always)]
19 | public MQTTInTopic[] Topics =
20 | {
21 | new MQTTInTopic
22 | {
23 | MQTTSubscribeTopic = "testTopic",
24 | DataIsAudio = false
25 | }
26 | };
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/MQTTInPlugin/MQTTInTopic.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | namespace MQTTInPlugin
4 | {
5 | public class MQTTInTopic
6 | {
7 | public string MQTTSubscribeTopic = "";
8 | public bool DataIsAudio = false;
9 | public int samplingRate = 16000;
10 | public int bits = 16;
11 | public int channels = 1;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/MQTTOutPlugin/MQTTOutPlugin.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 | true
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/MQTTOutPlugin/MQTTOutPluginCommand.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using PluginInterface;
4 |
5 | namespace MQTTOutPlugin
6 | {
7 | public class MQTTOutPluginCommand : PluginCommand
8 | {
9 | public string PluginResponse = "";
10 | public string MQTTRequestTopic = "";
11 | public string MQTTRequestText = "";
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/MQTTOutPlugin/MQTTOutPluginSettings.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using PluginInterface;
4 |
5 | namespace MQTTOutPlugin
6 | {
7 | public class MQTTOutPluginSettings
8 | {
9 | public string RequestServer = "";
10 | public int RequestServerPort = 1883;
11 | public string RequestServerLogin = "";
12 | public string RequestServerPassword = "";
13 | public string ClientID = "MQTTOutPlugin";
14 | public bool AddTimeStampToClientID = true;
15 | public bool KeepConnectionAlive = true;
16 | public int ReconnectTimeOut = 60;
17 |
18 | public string FailedConnectionResponse = "подключение не работает";
19 |
20 | //[JsonProperty(Required = Required.Always)]
21 | public MQTTOutPluginCommand[] Commands =
22 | {
23 | new MQTTOutPluginCommand
24 | {
25 | Name = "Test",
26 | Tokens = new[]
27 | {
28 | new Token
29 | {
30 | SuccessRate = 90,
31 | Type = TokenType.Command,
32 | Value = new[] {"тест"}
33 | },
34 | new Token
35 | {
36 | SuccessRate = 90,
37 | Type = TokenType.Command,
38 | Value = new[] {"соединения"}
39 | }
40 | },
41 | PluginResponse = "Соединение установлено",
42 | MQTTRequestText = "вася привет",
43 | MQTTRequestTopic = "testTopic"
44 | }
45 | };
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/MQTTOutPlugin/MQTTPluginSettings_eng.json:
--------------------------------------------------------------------------------
1 | {
2 | "Commands": [
3 | {
4 | "Response": "Nice to hear you",
5 | "Name": "Greeting informal",
6 | "Tokens": [
7 | {
8 | "Value": [
9 | "Greeting"
10 | ],
11 | "Type": "Command",
12 | "SuccessRate": 90
13 | }
14 | ]
15 | },
16 | {
17 | "Response": "And you too",
18 | "Name": "Greeting formal",
19 | "Tokens": [
20 | {
21 | "Value": [
22 | "Hello"
23 | ],
24 | "Type": "Command",
25 | "SuccessRate": 90
26 | }
27 | ]
28 | },
29 | {
30 | "Response": "Have a good day too",
31 | "Name": "Greeting wishing",
32 | "Tokens": [
33 | {
34 | "Value": [
35 | "Have"
36 | ],
37 | "Type": "Command",
38 | "SuccessRate": 90
39 | },
40 | {
41 | "Value": [
42 | "a"
43 | ],
44 | "Type": "Command",
45 | "SuccessRate": 90
46 | },
47 | {
48 | "Value": [
49 | "good"
50 | ],
51 | "Type": "Command",
52 | "SuccessRate": 90
53 | },
54 | {
55 | "Value": [
56 | "day"
57 | ],
58 | "Type": "Command",
59 | "SuccessRate": 90
60 | }
61 | ]
62 | },
63 | {
64 | "Response": "Hi",
65 | "Name": "Greeting short informal",
66 | "Tokens": [
67 | {
68 | "Value": [
69 | "Hi"
70 | ],
71 | "Type": "Command",
72 | "SuccessRate": 90
73 | }
74 | ]
75 | }
76 | ]
77 | }
--------------------------------------------------------------------------------
/OpenWeatherPlugin/CurrentWeatherData.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using System;
4 |
5 | namespace OpenWeatherPlugin
6 | {
7 | public partial class OpenWeatherPlugin
8 | {
9 | public class CurrentWeatherData
10 | {
11 | // weather.description - Weather condition within the group. You can get the output in your language.
12 | public string WeatherDescription;
13 |
14 | // main.temp - Temperature
15 | public int Temperature;
16 |
17 | // main.humidity - Humidity, %
18 | public int Humidity;
19 |
20 | // main.pressure - Atmospheric pressure (on the sea level, if there is no sea_level or grnd_level data), hPa
21 | public int Pressure;
22 |
23 | // wind.speed - Wind speed. Unit Default: meter/sec, Metric: meter/sec, Imperial: miles/hour
24 | public int WindSpeed;
25 |
26 | // wind.deg - Wind direction, degrees (meteorological)
27 | public int WindDirection;
28 |
29 | public string WindDirectionName;
30 |
31 | // clouds.all - Cloudiness, %
32 | public int Clouds;
33 |
34 | // dt - Time of data calculation, unix, UTC
35 | public DateTime RecordDateTime;
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/OpenWeatherPlugin/OpenWeatherPlugin.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/OpenWeatherPlugin/OpenWeatherPluginCommand.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using PluginInterface;
4 |
5 | namespace OpenWeatherPlugin
6 | {
7 | public class OpenWeatherPluginCommand : PluginCommand
8 | {
9 | public string DayTime = "";
10 | public string CityId = "";
11 | public string Response = "";
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/OpenWeatherPlugin/OpenWeatherPluginSettings_eng.json:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jekyll2014/VoiceAssistant/bea10e8c38475eb44d8f67e4f7300f4625a33276/OpenWeatherPlugin/OpenWeatherPluginSettings_eng.json
--------------------------------------------------------------------------------
/OpenWeatherPlugin/WeatherCurrent.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using System.Collections.Generic;
4 |
5 | namespace OpenWeatherPlugin
6 | {
7 | public class WeatherCurrent
8 | {
9 | public Coord coord { get; set; }
10 | public List weather { get; set; }
11 | public string @base { get; set; }
12 | public Main main { get; set; }
13 | public int visibility { get; set; }
14 | public Wind wind { get; set; }
15 | public Clouds clouds { get; set; }
16 | public Rain rain { get; set; }
17 | public Snow snow { get; set; }
18 | public int dt { get; set; }
19 | public Sys sys { get; set; }
20 | public int timezone { get; set; }
21 | public int id { get; set; }
22 | public string name { get; set; }
23 | public int cod { get; set; }
24 |
25 | public class Coord
26 | {
27 | public double lon { get; set; }
28 | public double lat { get; set; }
29 | }
30 |
31 | public class Weather
32 | {
33 | public int id { get; set; }
34 | public string main { get; set; }
35 | public string description { get; set; }
36 | public string icon { get; set; }
37 | }
38 |
39 | public class Main
40 | {
41 | public double temp { get; set; }
42 | public double feels_like { get; set; }
43 | public double temp_min { get; set; }
44 | public double temp_max { get; set; }
45 | public int pressure { get; set; }
46 | public int humidity { get; set; }
47 | }
48 |
49 | public class Wind
50 | {
51 | public double speed { get; set; }
52 | public int deg { get; set; }
53 | }
54 |
55 | public class Clouds
56 | {
57 | public int all { get; set; }
58 | }
59 |
60 | public class Rain
61 | {
62 | //[JsonProperty(PropertyName = "1h")]
63 | public int _1h { get; set; }
64 | //[JsonProperty(PropertyName = "3h")]
65 | public int _3h { get; set; }
66 | }
67 |
68 | public class Snow
69 | {
70 | public int _1h { get; set; }
71 | public int _3h { get; set; }
72 | }
73 |
74 | public class Sys
75 | {
76 | public int type { get; set; }
77 | public int id { get; set; }
78 | public string country { get; set; }
79 | public int sunrise { get; set; }
80 | public int sunset { get; set; }
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/OpenWeatherPlugin/WeatherForecast.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using System.Collections.Generic;
4 |
5 | namespace OpenWeatherPlugin
6 | {
7 | // Root myDeserializedClass = JsonConvert.DeserializeObject(myJsonResponse);
8 | public class WeatherForecast
9 | {
10 | public string cod { get; set; }
11 | public int message { get; set; }
12 | public int cnt { get; set; }
13 | public List list { get; set; }
14 | public City city { get; set; }
15 |
16 | public class Main
17 | {
18 | public double temp { get; set; }
19 | public double feels_like { get; set; }
20 | public double temp_min { get; set; }
21 | public double temp_max { get; set; }
22 | public int pressure { get; set; }
23 | public int sea_level { get; set; }
24 | public int grnd_level { get; set; }
25 | public int humidity { get; set; }
26 | public double temp_kf { get; set; }
27 | }
28 |
29 | public class Weather
30 | {
31 | public int id { get; set; }
32 | public string main { get; set; }
33 | public string description { get; set; }
34 | public string icon { get; set; }
35 | }
36 |
37 | public class Clouds
38 | {
39 | public int all { get; set; }
40 | }
41 |
42 | public class Wind
43 | {
44 | public double speed { get; set; }
45 | public int deg { get; set; }
46 | public double gust { get; set; }
47 | }
48 |
49 | public class Sys
50 | {
51 | public string pod { get; set; }
52 | }
53 |
54 | public class Rain
55 | {
56 | public double _3h { get; set; }
57 | }
58 |
59 | public class Snow
60 | {
61 | public double _3h { get; set; }
62 | }
63 |
64 | public class List
65 | {
66 | public int dt { get; set; }
67 | public Main main { get; set; }
68 | public List weather { get; set; }
69 | public Clouds clouds { get; set; }
70 | public Wind wind { get; set; }
71 | public int visibility { get; set; }
72 | public double pop { get; set; }
73 | public Sys sys { get; set; }
74 | public string dt_txt { get; set; }
75 | public Rain rain { get; set; }
76 | public Snow snow { get; set; }
77 | }
78 |
79 | public class Coord
80 | {
81 | public double lat { get; set; }
82 | public double lon { get; set; }
83 | }
84 |
85 | public class City
86 | {
87 | public int id { get; set; }
88 | public string name { get; set; }
89 | public Coord coord { get; set; }
90 | public string country { get; set; }
91 | public int population { get; set; }
92 | public int timezone { get; set; }
93 | public int sunrise { get; set; }
94 | public int sunset { get; set; }
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/OpenWeatherPlugin/WeatherForecastData.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using System;
4 |
5 | namespace OpenWeatherPlugin
6 | {
7 | public partial class OpenWeatherPlugin
8 | {
9 | public class WeatherForecastData
10 | {
11 | // weather.description - Weather condition within the group. You can get the output in your language.
12 | public string WeatherDescription;
13 |
14 | // main.temp - Temperature
15 | public int Temperature;
16 | public int MinTemperature;
17 | public int MaxTemperature;
18 |
19 | // main.humidity - Humidity, %
20 | public int Humidity;
21 | public int MinHumidity;
22 | public int MaxHumidity;
23 |
24 | // main.pressure - Atmospheric pressure (on the sea level, if there is no sea_level or grnd_level data), hPa
25 | public int Pressure;
26 | public int MinPressure;
27 | public int MaxPressure;
28 |
29 | // wind.speed - Wind speed. Unit Default: meter/sec, Metric: meter/sec, Imperial: miles/hour
30 | public int WindSpeed;
31 | public int MinWindSpeed;
32 | public int MaxWindSpeed;
33 |
34 | // wind.deg - Wind direction, degrees (meteorological)
35 | public int WindDirection;
36 | public int MinWindDirection;
37 | public int MaxWindDirection;
38 |
39 | public string WindDirectionName;
40 | public string MinWindDirectionName;
41 | public string MaxWindDirectionName;
42 |
43 | // clouds.all - Cloudiness, %
44 | public int Clouds;
45 | public int MinClouds;
46 | public int MaxClouds;
47 |
48 | // dt - Time of data calculation, unix, UTC
49 | public DateTime RecordDateTime;
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/PluginInterface/Config.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using Newtonsoft.Json;
4 | using Newtonsoft.Json.Linq;
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using System.IO;
9 |
10 | namespace PluginInterface
11 | {
12 | public class Config where T : class, new()
13 | {
14 | private readonly string _configFileName;
15 |
16 | public T ConfigStorage { get; set; } = new T();
17 |
18 | public Config(string file)
19 | {
20 | _configFileName = file;
21 | LoadConfig();
22 | }
23 |
24 | public bool LoadConfig()
25 | {
26 | if (string.IsNullOrEmpty(_configFileName))
27 | return false;
28 |
29 | try
30 | {
31 | var json = JObject.Parse(File.ReadAllText(_configFileName));
32 | ConfigStorage = GetSection(json, "");
33 | }
34 | catch
35 | {
36 | return false;
37 | }
38 |
39 | return true;
40 | }
41 |
42 | public TK GetSection(JObject json, string sectionName = null) where TK : class, new()
43 | {
44 | if (string.IsNullOrEmpty(_configFileName))
45 | return default;
46 |
47 | if (string.IsNullOrEmpty(sectionName))
48 | return json?.ToObject() ??
49 | throw new InvalidOperationException($"Cannot find section {sectionName}");
50 |
51 | return json[sectionName]?.ToObject() ??
52 | throw new InvalidOperationException($"Cannot find section {sectionName}");
53 | }
54 |
55 | public bool SaveConfig()
56 | {
57 | if (string.IsNullOrEmpty(_configFileName))
58 | return false;
59 |
60 | try
61 | {
62 | File.WriteAllText(_configFileName,
63 | JsonConvert.SerializeObject(ConfigStorage, Formatting.Indented, new Newtonsoft.Json.JsonSerializerSettings()
64 | {
65 | Converters = new List
66 | {
67 | new Newtonsoft.Json.Converters.StringEnumConverter()
68 | }
69 | }));
70 | }
71 | catch
72 | {
73 | return false;
74 | }
75 |
76 | return true;
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/PluginInterface/GenericNumberSettings.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | namespace PluginInterface
4 | {
5 | public class GenericNumberSettings
6 | {
7 | public string Culture = "ru-RU";
8 |
9 | public string Minus = "минус";
10 | public string Plus = "плюс";
11 | public string Zero = "ноль";
12 | public string OneFemale = "одна";
13 | public string TwoFemale = "две";
14 |
15 | public string One = "один";
16 | public string Two = "два";
17 | public string Three = "три";
18 | public string Four = "четыре";
19 | public string Five = "пять";
20 | public string Six = "шесть";
21 | public string Seven = "семь";
22 | public string Eight = "восемь";
23 | public string Nine = "девять";
24 | public string Elleven = "одиннадцать";
25 | public string Twelve = "двенадцать";
26 | public string Thirteen = "тринадцать";
27 | public string Fourteen = "четырнадцать";
28 | public string Fifteen = "пятнадцать";
29 | public string Sixteen = "шестнадцать";
30 | public string Seventeen = "семнадцать";
31 | public string Eighteen = "восемнадцать";
32 | public string Nineteen = "девятнадцать";
33 |
34 | public string Ten = "десять";
35 | public string Twenty = "двадцать";
36 | public string Thirty = "тридцать";
37 | public string Forty = "сорок";
38 | public string Fifty = "пятьдесят";
39 | public string Sixty = "шестьдесят";
40 | public string Seventy = "семьдесят";
41 | public string Eighty = "восемьдесят";
42 | public string Ninety = "девяносто";
43 |
44 | public string OneHundred = "сто";
45 | public string TwoHundred = "двести";
46 | public string ThreeHundred = "триста";
47 | public string FourHundred = "четыреста";
48 | public string FiveHundred = "пятьсот";
49 | public string SixHundred = "шестьсот";
50 | public string SevenHundred = "семьсот";
51 | public string EightHundred = "восемьсот";
52 | public string NineHundred = "девятьсот";
53 |
54 | public string OneThousand = "тысяча";
55 | public string TwoThousand = "тысячи";
56 | public string FiveThousand = "тысяч";
57 |
58 | public string OneMillion = "миллион";
59 | public string TwoMillion = "миллиона";
60 | public string FiveMillion = "миллионов";
61 |
62 | public string OneBillion = "миллиард";
63 | public string TwoBillion = "миллиарда";
64 | public string FiveBillion = "миллиардов";
65 |
66 | public string OneTrillion = "триллион";
67 | public string TwoTrillion = "триллиона";
68 | public string FiveTrillion = "триллионов";
69 |
70 | public string OneQuadrillion = "квадриллион";
71 | public string TwoQuadrillion = "квадриллиона";
72 | public string FiveQuadrillion = "квадриллионов";
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/PluginInterface/IAudioOutSingleton.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | namespace PluginInterface
4 | {
5 | public interface IAudioOutSingleton
6 | {
7 | void PlayFile(string audioFile, bool exclusive = true);
8 | void Speak(string text, bool exclusive = true);
9 | void PlayDataBuffer(byte[] data, bool exclusive = true);
10 | }
11 | }
--------------------------------------------------------------------------------
/PluginInterface/INumberToText.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | namespace PluginInterface
4 | {
5 | public interface INumberToText
6 | {
7 | public abstract string ConvertNumberToString(long val);
8 | }
9 | }
--------------------------------------------------------------------------------
/PluginInterface/ITextToNumber.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | namespace PluginInterface
4 | {
5 | public interface ITextToNumber
6 | {
7 | public abstract long ConvertStringToNumber(string numberString, int ratio = 100);
8 | }
9 | }
--------------------------------------------------------------------------------
/PluginInterface/NumberToTextEmpty.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | namespace PluginInterface
4 | {
5 | public class NumberToTextEmpty : INumberToText
6 | {
7 | public string ConvertNumberToString(long val)
8 | {
9 | return string.Empty;
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/PluginInterface/NumberToTextEng.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using System;
4 |
5 | namespace PluginInterface
6 | {
7 | public class NumberToTextEng : INumberToText
8 | {
9 | //converts any number between 0 & INT_MAX (2,147,483,647)
10 | public string ConvertNumberToString(long val)
11 | {
12 | var result = string.Empty;
13 |
14 | if (val < 0)
15 | {
16 | result = "minus ";
17 | val = -val;
18 | }
19 |
20 | if (val == 0)
21 | result = "zero";
22 | else if (val < 10)
23 | result += ConvertDigitToString(val);
24 | else if (val < 20)
25 | result += ConvertTeensToString(val);
26 | else if (val < 100)
27 | result += ConvertHighTensToString(val);
28 | else if (val < 1000)
29 | result += ConvertBigNumberToString(val, (long)1e2, "hundred");
30 | else if (val < 1e6)
31 | result += ConvertBigNumberToString(val, (long)1e3, "thousand");
32 | else if (val < 1e9)
33 | result += ConvertBigNumberToString(val, (long)1e6, "million");
34 | else if (val < 1e12)
35 | result += ConvertBigNumberToString(val, (long)1e9, "billion");
36 | else if (val < 1e15)
37 | result += ConvertBigNumberToString(val, (long)1e12, "trillion");
38 | else if (val < 1e18)
39 | result += ConvertBigNumberToString(val, (long)1e15, "quadrillion");
40 | else if (val < 1e21)
41 | result += ConvertBigNumberToString(val, (long)1e18, "quintillion");
42 | else
43 | return "more than quintillion";
44 |
45 | return result;
46 | }
47 |
48 | private string ConvertDigitToString(long i)
49 | {
50 | switch (i)
51 | {
52 | case 0: return "";
53 | case 1: return "one";
54 | case 2: return "two";
55 | case 3: return "three";
56 | case 4: return "four";
57 | case 5: return "five";
58 | case 6: return "six";
59 | case 7: return "seven";
60 | case 8: return "eight";
61 | case 9: return "nine";
62 | default:
63 | throw new IndexOutOfRangeException(String.Format("{0} not a digit", i));
64 | }
65 | }
66 |
67 | //assumes a number between 10 & 19
68 | private string ConvertTeensToString(long n)
69 | {
70 | switch (n)
71 | {
72 | case 10: return "ten";
73 | case 11: return "eleven";
74 | case 12: return "twelve";
75 | case 13: return "thirteen";
76 | case 14: return "fourteen";
77 | case 15: return "fiveteen";
78 | case 16: return "sixteen";
79 | case 17: return "seventeen";
80 | case 18: return "eighteen";
81 | case 19: return "nineteen";
82 | default:
83 | throw new IndexOutOfRangeException(String.Format("{0} not a teen", n));
84 | }
85 | }
86 |
87 | //assumes a number between 20 and 99
88 | private string ConvertHighTensToString(long n)
89 | {
90 | long tensDigit = (long)(Math.Floor((double)n / 10.0));
91 |
92 | string tensStr;
93 | switch (tensDigit)
94 | {
95 | case 2: tensStr = "twenty"; break;
96 | case 3: tensStr = "thirty"; break;
97 | case 4: tensStr = "forty"; break;
98 | case 5: tensStr = "fifty"; break;
99 | case 6: tensStr = "sixty"; break;
100 | case 7: tensStr = "seventy"; break;
101 | case 8: tensStr = "eighty"; break;
102 | case 9: tensStr = "ninety"; break;
103 | default:
104 | throw new IndexOutOfRangeException(String.Format("{0} not in range 20-99", n));
105 | }
106 | if (n % 10 == 0) return tensStr;
107 | string onesStr = ConvertDigitToString(n - tensDigit * 10);
108 | return tensStr + "-" + onesStr;
109 | }
110 |
111 | // Use this to convert any integer bigger than 99
112 | private string ConvertBigNumberToString(long n, long baseNum, string baseNumStr)
113 | {
114 | // special case: use commas to separate portions of the number, unless we are in the hundreds
115 | string separator = (baseNumStr != "hundred") ? ", " : " ";
116 |
117 | // Strategy: translate the first portion of the number, then recursively translate the remaining sections.
118 | // Step 1: strip off first portion, and convert it to string:
119 | long bigPart = (long)(Math.Floor((double)n / baseNum));
120 | string bigPartStr = ConvertNumberToString(bigPart) + " " + baseNumStr;
121 | // Step 2: check to see whether we're done:
122 | if (n % baseNum == 0) return bigPartStr;
123 | // Step 3: concatenate 1st part of string with recursively generated remainder:
124 | long restOfNumber = n - bigPart * baseNum;
125 | return bigPartStr + separator + ConvertNumberToString(restOfNumber);
126 | }
127 | }
128 | }
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/PluginInterface/NumberToTextFactory.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | namespace PluginInterface
4 | {
5 | public static class NumberToTextFactory
6 | {
7 | public static INumberToText GetNumberToTextConvertor(string culture)
8 | {
9 | if (culture.StartsWith("ru-"))
10 | return new NumberToTextRus();
11 | else if (culture.StartsWith("en-"))
12 | return new NumberToTextEng();
13 | else
14 | return new NumberToTextGeneric();
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/PluginInterface/NumberToTextRus.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using System;
4 | using System.Text;
5 |
6 | namespace PluginInterface
7 | {
8 | public class NumberToTextRus : INumberToText
9 | {
10 | //Наименования сотен
11 | private readonly string[] _hundreds =
12 | {
13 | "", "сто ", "двести ", "триста ", "четыреста ",
14 | "пятьсот ", "шестьсот ", "семьсот ", "восемьсот ", "девятьсот "
15 | };
16 |
17 | //Наименования десятков
18 | private readonly string[] _tens =
19 | {
20 | "", "десять ", "двадцать ", "тридцать ", "сорок ", "пятьдесят ",
21 | "шестьдесят ", "семьдесят ", "восемьдесят ", "девяносто "
22 | };
23 |
24 | private readonly string[] _frac20 =
25 | {
26 | "", "один ", "два ", "три ", "четыре ", "пять ", "шесть ",
27 | "семь ", "восемь ", "девять ", "десять ", "одиннадцать ",
28 | "двенадцать ", "тринадцать ", "четырнадцать ", "пятнадцать ",
29 | "шестнадцать ", "семнадцать ", "восемнадцать ", "девятнадцать "
30 | };
31 |
32 | private readonly string[] _OneTwoFiveThousand = { "тысяча", "тысячи", "тысяч" };
33 | private readonly string[] _OneTwoFiveMillion = { "миллион", "миллиона", "миллионов" };
34 | private readonly string[] _OneTwoFiveBillion = { "миллиард", "миллиарда", "миллиардов" };
35 | private readonly string[] _OneTwoFiveTrillion = { "триллион", "триллиона", "триллионов" };
36 | private readonly string[] _OneTwoFiveQuadrillion = { "квадриллион", "квадриллиона", "квадриллионов" };
37 |
38 | private readonly string _zero = "ноль ";
39 | private readonly string _oneFemale = "одна ";
40 | private readonly string _twoFemale = "две ";
41 | private readonly string _minus = "минус ";
42 |
43 | ///
44 | /// Перевод целого числа в строку
45 | ///
46 | /// Число
47 | /// Возвращает строковую запись числа
48 | public string ConvertNumberToString(long val)
49 | {
50 | var minus = false;
51 |
52 | if (val < 0)
53 | {
54 | val = -val;
55 | minus = true;
56 | }
57 |
58 | var n = val;
59 |
60 | var r = new StringBuilder();
61 |
62 | if (0 == n)
63 | r.Append(_zero);
64 |
65 | if (n % 1000 != 0)
66 | r.Append(Str(n, true, new[] { "", "", "" }));
67 |
68 | n /= 1000;
69 |
70 | r.Insert(0, Str(n, false, _OneTwoFiveThousand));
71 | n /= 1000;
72 |
73 | r.Insert(0, Str(n, true, _OneTwoFiveMillion));
74 | n /= 1000;
75 |
76 | r.Insert(0, Str(n, true, _OneTwoFiveBillion));
77 | n /= 1000;
78 |
79 | r.Insert(0, Str(n, true, _OneTwoFiveTrillion));
80 | n /= 1000;
81 |
82 | r.Insert(0, Str(n, true, _OneTwoFiveQuadrillion));
83 |
84 | if (minus)
85 | r.Insert(0, _minus);
86 |
87 | return r.ToString();
88 | }
89 |
90 | ///
91 | /// Перевод в строку числа с учётом падежного окончания относящегося к числу существительного
92 | ///
93 | /// Число
94 | /// Род существительного, которое относится к числу
95 | /// Форма существительного в единственном числе
96 | /// Форма существительного от двух до четырёх
97 | /// Форма существительного от пяти и больше
98 | ///
99 | private string Str(long val, bool male, string[] oneTwoFive)
100 | {
101 | var num = val % 1000;
102 | if (0 == num) return "";
103 |
104 | if (num < 0) throw new ArgumentOutOfRangeException(nameof(val), "Parameter can't be less than zero");
105 |
106 | if (!male)
107 | {
108 | _frac20[1] = _oneFemale + " ";
109 | _frac20[2] = _twoFemale + " ";
110 | }
111 |
112 | var r = new StringBuilder(_hundreds[num / 100] + " ");
113 |
114 | if (num % 100 < 20)
115 | {
116 | r.Append(_frac20[num % 100] + " ");
117 | }
118 | else
119 | {
120 | r.Append(_tens[num % 100 / 10] + " ");
121 | r.Append(_frac20[num % 10] + " ");
122 | }
123 |
124 | r.Append(Case(num, oneTwoFive[0], oneTwoFive[1], oneTwoFive[2]));
125 |
126 | if (r.Length != 0)
127 | r.Append(" ");
128 |
129 | return r.ToString();
130 | }
131 |
132 | ///
133 | /// Выбор правильного падежного окончания сущесвительного
134 | ///
135 | /// Число
136 | /// Форма существительного в единственном числе
137 | /// Форма существительного от двух до четырёх
138 | /// Форма существительного от пяти и больше
139 | /// Возвращает существительное с падежным окончанием, которое соответсвует числу
140 | private string Case(long val, string one, string two, string five)
141 | {
142 | var t = val % 100 > 20 ? val % 10 : val % 20;
143 |
144 | switch (t)
145 | {
146 | case 1: return one + " ";
147 | case 2:
148 | case 3:
149 | case 4: return two + " ";
150 | default: return five + " ";
151 | }
152 | }
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/PluginInterface/PluginBase.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Threading.Tasks;
6 |
7 | namespace PluginInterface
8 | {
9 | public abstract class PluginBase
10 | {
11 | public const string PluginInterfaceVersion = "1.1";
12 | protected readonly string PluginPath;
13 | protected readonly string PluginConfigFile;
14 | protected readonly IAudioOutSingleton AudioOut;
15 | public volatile bool CanAcceptSound = false;
16 | public volatile bool CanAcceptWords = false;
17 | public volatile bool CanInjectSound = false;
18 | public volatile bool CanInjectWords = false;
19 | private static readonly object SyncRootAudio = new object();
20 | private static readonly object SyncRootWords = new object();
21 | private readonly List _recognizedWords = new List();
22 | private readonly List _recordedAudio = new List();
23 | private readonly int _recognizedWordsBufferLimit = 1024;
24 | private readonly int _recordedAudioBufferLimit = 1024 * 1024;
25 | private readonly bool _recognizedWordsAlwaysBuffer = true;
26 | private readonly bool _recordedAudioAlwaysBuffer = true;
27 |
28 | protected string _pluginName;
29 | public string PluginName => _pluginName;
30 |
31 | protected string _currentCulture;
32 | public string CurrentCulture => _currentCulture;
33 |
34 | protected PluginCommand[] _commands;
35 | public PluginCommand[] Commands => _commands;
36 |
37 | public delegate void ExternalAudioCommandHandler(byte[] buffer, int samplingRate, int bits, int channels);
38 | public event ExternalAudioCommandHandler ExternalAudioCommand;
39 |
40 | public delegate void ExternalTextCommandHandler(string command);
41 | public event ExternalTextCommandHandler ExternalTextCommand;
42 |
43 | public delegate void RecordedAudioCommandHandler(byte[] buffer, int samplingRate, int bits, int channels);
44 | public event RecordedAudioCommandHandler RecordedAudioCommand;
45 |
46 | public delegate void RecordedTextCommandHandler(string command);
47 | public event RecordedTextCommandHandler RecordedTextCommand;
48 |
49 | protected PluginBase(IAudioOutSingleton audioOut, string currentCulture, string pluginPath)
50 | {
51 | var file = new FileInfo(pluginPath);
52 | AudioOut = audioOut;
53 | PluginPath = file.DirectoryName;
54 | _pluginName = file.Name;
55 | PluginConfigFile = file.Name[..^file.Extension.Length] + "Settings.json";
56 | _currentCulture = currentCulture;
57 | }
58 |
59 | public abstract void Execute(string commandName, List commandTokens);
60 |
61 | public void AddWords(string words)
62 | {
63 | var tmpWords = words;
64 | Task.Run(() =>
65 | {
66 | lock (SyncRootWords)
67 | {
68 | if (RecordedTextCommand == null || _recognizedWordsAlwaysBuffer)
69 | {
70 | var newBuffer = tmpWords.Split(' ');
71 | var newBufferLength = _recognizedWords.Count + newBuffer.Length;
72 |
73 | if (newBufferLength > _recognizedWordsBufferLimit)
74 | {
75 | var removeWords = newBufferLength - _recognizedWordsBufferLimit;
76 | _recognizedWords.RemoveRange(0, removeWords);
77 | }
78 |
79 | _recognizedWords.AddRange(newBuffer);
80 | }
81 |
82 | RecordedTextCommand?.Invoke(words);
83 | }
84 | });
85 | }
86 |
87 | protected string[] GetWords()
88 | {
89 | lock (SyncRootWords)
90 | {
91 | var result = _recognizedWords.ToArray();
92 | _recognizedWords.Clear();
93 | return result;
94 | }
95 | }
96 |
97 | public void AddSound(byte[] data, int samplingRate, int bits, int channels)
98 | {
99 | var tmpData = data;
100 | Task.Run(() =>
101 | {
102 | lock (SyncRootAudio)
103 | {
104 | if (RecordedAudioCommand == null || _recordedAudioAlwaysBuffer)
105 | {
106 | var newBufferLength = _recordedAudio.Count + tmpData.Length;
107 |
108 | if (newBufferLength > _recordedAudioBufferLimit)
109 | {
110 | var removeBytes = newBufferLength - _recordedAudioBufferLimit;
111 | _recordedAudio.RemoveRange(0, removeBytes);
112 | }
113 |
114 | _recordedAudio.AddRange(tmpData);
115 | }
116 |
117 | RecordedAudioCommand?.Invoke(data, samplingRate, bits, channels);
118 | }
119 | });
120 | }
121 |
122 | protected byte[] GetSound()
123 | {
124 | lock (SyncRootAudio)
125 | {
126 | var result = _recordedAudio.ToArray();
127 | _recordedAudio.Clear();
128 | return result;
129 | }
130 | }
131 |
132 | protected void InjectTextCommand(string command)
133 | {
134 | ExternalTextCommand?.Invoke(command);
135 | }
136 |
137 | protected void InjectAudioCommand(byte[] buffer, int samplingRate, int bits, int channels)
138 | {
139 | ExternalAudioCommand?.Invoke(buffer, samplingRate, bits, channels);
140 | }
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/PluginInterface/PluginCommand.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 |
7 | namespace PluginInterface
8 | {
9 | public class PluginCommand
10 | {
11 | public string Name;
12 | public Token[] Tokens;
13 |
14 | public Token GetParameter(string paramName, IEnumerable tokens)
15 | {
16 | for (var i = 0; i < Tokens.Length; i++)
17 | if (Tokens[i].Value.Contains(paramName))
18 | return tokens.ElementAt(i);
19 |
20 | return null;
21 | }
22 |
23 | public override string ToString()
24 | {
25 | var sb = new StringBuilder();
26 |
27 | if (Tokens != null && Tokens.Length > 0)
28 | {
29 | foreach (var token in Tokens.Select(n => n.Value))
30 | {
31 | if (sb.Length > 0)
32 | {
33 | sb.Append(" ");
34 | }
35 |
36 | if (token.Length == 1)
37 | {
38 | sb.Append($"{token[0]}");
39 | }
40 | else
41 | {
42 | sb.Append("[");
43 | var nextElement = false;
44 |
45 | foreach (var word in token)
46 | {
47 | if (nextElement)
48 | {
49 | sb.Append(", ");
50 | }
51 |
52 | sb.Append($"{word}");
53 | nextElement = true;
54 | }
55 |
56 | sb.Append("]");
57 | }
58 | }
59 | }
60 |
61 | return sb.ToString().Trim();
62 | }
63 | }
64 |
65 | public class Token
66 | {
67 | public string[] Value;
68 | public TokenType Type = TokenType.Unknown;
69 | public int SuccessRate = 100; // success ratio for fuzzy compare
70 | }
71 |
72 | public enum TokenType
73 | {
74 | Unknown,
75 | Command,
76 | Parameter
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/PluginInterface/PluginInterface.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/PluginInterface/PluginTools.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using System.Text;
4 |
5 | namespace PluginInterface
6 | {
7 | public static class PluginTools
8 | {
9 | public static string FormatStringWithClassFields(string sample, object sourceClass)
10 | {
11 | var result = new StringBuilder();
12 | var openBracketPosition = sample.IndexOf('{');
13 |
14 | if (openBracketPosition < 0)
15 | {
16 | return sample;
17 | }
18 |
19 | if (openBracketPosition > 0)
20 | {
21 | result.Append(sample.Substring(0, openBracketPosition));
22 | }
23 |
24 | while (openBracketPosition >= 0)
25 | {
26 | var closeBracketPosition = sample.IndexOf('}', openBracketPosition + 1);
27 | if (closeBracketPosition < 0)
28 | {
29 | result.Append(sample.Substring(openBracketPosition));
30 |
31 | return result.ToString();
32 | }
33 |
34 | var propertyName = sample.Substring(openBracketPosition + 1, closeBracketPosition - openBracketPosition - 1);
35 |
36 | object propertyValue = null;
37 | try
38 | {
39 | propertyValue = sourceClass.GetType()?.GetField(propertyName)?.GetValue(sourceClass);
40 | propertyValue ??= sourceClass.GetType()?.GetProperty(propertyName)?.GetValue(sourceClass);
41 | }
42 | catch
43 | {
44 | //no property or field found for the name
45 | }
46 |
47 | if (propertyValue != null)
48 | {
49 | result.Append(propertyValue.ToString());
50 | }
51 | else
52 | {
53 | result.Append("{" + propertyName + "}");
54 | }
55 |
56 | openBracketPosition = sample.IndexOf('{', closeBracketPosition + 1);
57 |
58 | if (openBracketPosition > 0)
59 | {
60 | result.Append(sample.Substring(closeBracketPosition + 1, openBracketPosition - closeBracketPosition - 1));
61 | }
62 | else
63 | {
64 | result.Append(sample.Substring(closeBracketPosition + 1));
65 | }
66 | }
67 |
68 | return result.ToString();
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/PluginInterface/TextToNumberEmpty.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | namespace PluginInterface
4 | {
5 | public class TextToNumberEmpty : ITextToNumber
6 | {
7 | public long ConvertStringToNumber(string numberString, int ratio = 100)
8 | {
9 | return 0;
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/PluginInterface/TextToNumberEng.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text.RegularExpressions;
7 |
8 | namespace PluginInterface
9 | {
10 | class TextToNumberEng : ITextToNumber
11 | {
12 | private readonly Dictionary numberTable = new Dictionary
13 | {
14 | {"zero",0},
15 | {"one",1},
16 | {"two",2},
17 | {"three",3},
18 | {"four",4},
19 | {"five",5},
20 | {"six",6},
21 | {"seven",7},
22 | {"eight",8},
23 | {"nine",9},
24 | {"ten",10},
25 | {"eleven",11},
26 | {"twelve",12},
27 | {"thirteen",13},
28 | {"fourteen",14},
29 | {"fifteen",15},
30 | {"sixteen",16},
31 | {"seventeen",17},
32 | {"eighteen",18},
33 | {"nineteen",19},
34 | {"twenty",20},
35 | {"thirty",30},
36 | {"forty",40},
37 | {"fifty",50},
38 | {"sixty",60},
39 | {"seventy",70},
40 | {"eighty",80},
41 | {"ninety",90},
42 | {"hundred",100},
43 | {"thousand",1000},
44 | {"lakh",100000},
45 | {"million",1000000},
46 | {"billion",1000000000},
47 | {"trillion",1000000000000},
48 | {"quadrillion",1000000000000000},
49 | {"quintillion",1000000000000000000}
50 | };
51 |
52 | public long ConvertStringToNumber(string numberString, int ratio = 100)
53 | {
54 | var numbers = Regex.Matches(numberString, @"\w+").Cast()
55 | .Select(m => m.Value.ToLowerInvariant())
56 | .Where(v => numberTable.ContainsKey(v))
57 | .Select(v => numberTable[v]);
58 |
59 | long acc = 0, total = 0;
60 |
61 | foreach (var n in numbers)
62 | {
63 | if (n >= 1000)
64 | {
65 | total += acc * n;
66 | acc = 0;
67 | }
68 | else if (n >= 100)
69 | {
70 | acc *= n;
71 | }
72 | else acc += n;
73 | }
74 |
75 | return (total + acc) * (numberString.StartsWith("minus",
76 | StringComparison.InvariantCultureIgnoreCase) ? -1 : 1);
77 | }
78 | }
79 | }
--------------------------------------------------------------------------------
/PluginInterface/TextToNumberFactory.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | namespace PluginInterface
4 | {
5 | public static class TextToNumberFactory
6 | {
7 | public static ITextToNumber GetTextToNumberConvertor(string culture)
8 | {
9 | if (culture.StartsWith("ru-"))
10 | return new TextToNumberRus();
11 | else if (culture.StartsWith("en-"))
12 | return new TextToNumberEng();
13 | else
14 | return new TextToNumberGeneric();
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/PluginInterface/TextToNumberGeneric.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using FuzzySharp;
4 |
5 | using System.Collections.Generic;
6 | using System.IO;
7 |
8 | namespace PluginInterface
9 | {
10 | class TextToNumberGeneric : ITextToNumber
11 | {
12 | private const string _settingsConfigFile = "GenericNumberSettings.json";
13 |
14 | private readonly Dictionary Signs;
15 | private readonly Dictionary Numbers;
16 | private readonly Dictionary Multipliers;
17 |
18 | public TextToNumberGeneric()
19 | {
20 | var configBuilder = new Config($"{_settingsConfigFile}");
21 | if (!File.Exists($"{_settingsConfigFile}"))
22 | {
23 | configBuilder.SaveConfig();
24 | }
25 |
26 | var configStorage = configBuilder.ConfigStorage;
27 |
28 | Signs = new Dictionary
29 | {
30 | {configStorage.Minus, false},
31 | {configStorage.Plus, true}
32 | };
33 |
34 | Numbers = new Dictionary
35 | {
36 | {configStorage.Zero, 0},
37 | {configStorage.One, 1},
38 | {configStorage.OneFemale, 1},
39 | {configStorage.Two, 2},
40 | {configStorage.TwoFemale, 2},
41 | {configStorage.Three, 3},
42 | {configStorage.Four, 4},
43 | {configStorage.Five, 5},
44 | {configStorage.Six, 6},
45 | {configStorage.Seven, 7},
46 | {configStorage.Eight, 8},
47 | {configStorage.Nine, 9},
48 | {configStorage.Ten, 10},
49 | {configStorage.Elleven, 11},
50 | {configStorage.Twelve, 12},
51 | {configStorage.Thirteen, 13},
52 | {configStorage.Fourteen, 14},
53 | {configStorage.Fifteen, 15},
54 | {configStorage.Sixteen, 16},
55 | {configStorage.Seventeen, 17},
56 | {configStorage.Eighteen, 18},
57 | {configStorage.Nineteen, 19},
58 | {configStorage.Twenty, 20},
59 | {configStorage.Thirty, 30},
60 | {configStorage.Forty, 40},
61 | {configStorage.Fifty, 50},
62 | {configStorage.Sixty, 60},
63 | {configStorage.Seventy, 70},
64 | {configStorage.Eighty, 80},
65 | {configStorage.Ninety, 90},
66 | {configStorage.OneHundred, 100},
67 | {configStorage.TwoHundred, 200},
68 | {configStorage.ThreeHundred, 300},
69 | {configStorage.FourHundred, 400},
70 | {configStorage.FiveHundred, 500},
71 | {configStorage.SixHundred, 600},
72 | {configStorage.SevenHundred, 700},
73 | {configStorage.EightHundred, 800},
74 | {configStorage.NineHundred, 900},
75 | {configStorage.OneThousand, 1000},
76 | {configStorage.OneMillion, 1000000},
77 | {configStorage.OneBillion, 1000000000},
78 | {configStorage.OneTrillion, 1000000000000},
79 | {configStorage.OneQuadrillion, 1000000000000},
80 | };
81 |
82 | Multipliers = new Dictionary
83 | {
84 | {configStorage.OneThousand, 1000},
85 | {configStorage.TwoThousand, 1000},
86 | {configStorage.FiveThousand, 1000},
87 |
88 | {configStorage.OneMillion, 1000000},
89 | {configStorage.TwoMillion, 1000000},
90 | {configStorage.FiveMillion, 1000000},
91 |
92 | {configStorage.OneBillion, 1000000000},
93 | {configStorage.TwoBillion, 1000000000},
94 | {configStorage.FiveBillion, 1000000000},
95 |
96 | {configStorage.OneTrillion, 1000000000000},
97 | {configStorage.TwoTrillion, 1000000000000},
98 | {configStorage.FiveTrillion, 1000000000000},
99 |
100 | {configStorage.OneQuadrillion, 1000000000000000},
101 | {configStorage.TwoQuadrillion, 1000000000000000},
102 | {configStorage.FiveQuadrillion, 1000000000000000}
103 | };
104 | }
105 |
106 | public long ConvertStringToNumber(string numberString, int ratio = 100)
107 | {
108 | long result = 0;
109 | var positive = true;
110 | var i = 0;
111 | var tokens = numberString.ToLower().Split(' ');
112 |
113 | if (TryGetValueFuzz(Signs, tokens[0], ratio, out var p))
114 | {
115 | positive = p;
116 | i++;
117 | }
118 |
119 | for (; i < tokens.Length; i++)
120 | if (TryGetValueFuzz(Numbers, tokens[i], ratio, out var number))
121 | {
122 | if (i + 1 < tokens.Length &&
123 | TryGetValueFuzz(Multipliers, tokens[i + 1], ratio, out var multiplier))
124 | {
125 | number *= multiplier;
126 | i++;
127 | }
128 |
129 | result += number;
130 | }
131 | else
132 | {
133 | i = tokens.Length;
134 | }
135 |
136 | if (!positive)
137 | result *= -1;
138 |
139 | return result;
140 | }
141 |
142 | private bool TryGetValueFuzz(Dictionary dict, string sample, int ratio, out T value)
143 | {
144 | value = default;
145 |
146 | foreach (var (key1, value1) in dict)
147 | {
148 | if (Fuzz.WeightedRatio(key1, sample) > ratio)
149 | {
150 | value = value1;
151 | return true;
152 | }
153 | }
154 |
155 | return false;
156 | }
157 | }
158 | }
--------------------------------------------------------------------------------
/PluginInterface/TextToNumberRus.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using FuzzySharp;
4 |
5 | using System.Collections.Generic;
6 |
7 | namespace PluginInterface
8 | {
9 | public class TextToNumberRus : ITextToNumber
10 | {
11 | private readonly Dictionary Signs = new Dictionary
12 | {
13 | {"минус", false},
14 | {"плюс", true}
15 | };
16 |
17 | private readonly Dictionary Numbers = new Dictionary
18 | {
19 | {"ноль", 0},
20 | {"один", 1},
21 | {"одна", 1},
22 | {"одну", 1},
23 | {"два", 2},
24 | {"две", 2},
25 | {"три", 3},
26 | {"четыре", 4},
27 | {"пять", 5},
28 | {"шесть", 6},
29 | {"семь", 7},
30 | {"восемь", 8},
31 | {"девять", 9},
32 | {"десять", 10},
33 | {"одиннадцать", 11},
34 | {"двенадцать", 12},
35 | {"тринадцать", 13},
36 | {"четырнадцать", 14},
37 | {"пятнадцать", 15},
38 | {"шестнадцать", 16},
39 | {"семнадцать", 17},
40 | {"восемнадцать", 18},
41 | {"девятнадцать", 19},
42 | {"двадцать", 20},
43 | {"тридцать", 30},
44 | {"сорок", 40},
45 | {"пятьдесят", 50},
46 | {"шестьдесят", 60},
47 | {"семьдесят", 70},
48 | {"восемьдесят", 80},
49 | {"девяносто", 90},
50 | {"сто", 100},
51 | {"двести", 200},
52 | {"триста", 300},
53 | {"четыреста", 400},
54 | {"пятьсот", 500},
55 | {"шестьсот", 600},
56 | {"семьсот", 700},
57 | {"восемьсот", 800},
58 | {"девятьсот", 900},
59 | {"тысяча", 1000},
60 | {"миллион", 1000000},
61 | {"миллиард", 1000000000},
62 | {"триллион", 1000000000000},
63 | {"квадриллион", 1000000000000},
64 | };
65 |
66 | private readonly Dictionary Multipliers = new Dictionary
67 | {
68 | {"тысяча", 1000},
69 | {"тысячи", 1000},
70 | {"тысяч", 1000},
71 |
72 | {"миллион", 1000000},
73 | {"миллиона", 1000000},
74 | {"миллионов", 1000000},
75 |
76 | {"миллиард", 1000000000},
77 | {"миллиарда", 1000000000},
78 | {"миллиардов", 1000000000},
79 |
80 | {"триллион", 1000000000000},
81 | {"триллиона", 1000000000000},
82 | {"триллионов", 1000000000000},
83 |
84 | {"квадриллион", 1000000000000000},
85 | {"квадриллиона", 1000000000000000},
86 | {"квадриллионов", 1000000000000000}
87 | };
88 |
89 | public long ConvertStringToNumber(string numberString, int ratio = 100)
90 | {
91 | long result = 0;
92 | var positive = true;
93 | var i = 0;
94 | var tokens = numberString.ToLower().Split(' ');
95 |
96 | if (TryGetValueFuzz(Signs, tokens[0], ratio, out var p))
97 | {
98 | positive = p;
99 | i++;
100 | }
101 |
102 | for (; i < tokens.Length; i++)
103 | if (TryGetValueFuzz(Numbers, tokens[i], ratio, out var number))
104 | {
105 | if (i + 1 < tokens.Length &&
106 | TryGetValueFuzz(Multipliers, tokens[i + 1], ratio, out var multiplier))
107 | {
108 | number *= multiplier;
109 | i++;
110 | }
111 |
112 | result += number;
113 | }
114 | else
115 | {
116 | i = tokens.Length;
117 | }
118 |
119 | if (!positive)
120 | result *= -1;
121 |
122 | return result;
123 | }
124 |
125 | private bool TryGetValueFuzz(Dictionary dict, string sample, int ratio, out TK value)
126 | {
127 | value = default;
128 |
129 | foreach (var (key1, value1) in dict)
130 | {
131 | if (Fuzz.WeightedRatio(key1, sample) > ratio)
132 | {
133 | value = value1;
134 | return true;
135 | }
136 | }
137 |
138 | return false;
139 | }
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/RunProgramPlugin/RunProgramPlugin.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Runtime.InteropServices;
8 |
9 | using PluginInterface;
10 |
11 | namespace RunProgramPlugin
12 | {
13 | public class RunProgramPlugin : PluginBase
14 | {
15 | private readonly RunProgramPluginCommand[] RunProgramCommands;
16 | private readonly Dictionary _processes = new Dictionary();
17 | private readonly string _canNotClose;
18 | private readonly string _notRunning;
19 | private readonly string _canNotRun;
20 | private readonly string _alreadyRunning;
21 |
22 | public RunProgramPlugin(IAudioOutSingleton audioOut, string currentCulture, string pluginPath) : base(audioOut, currentCulture, pluginPath)
23 | {
24 | var configBuilder = new Config($"{PluginPath}\\{PluginConfigFile}");
25 |
26 | if (!File.Exists($"{PluginPath}\\{PluginConfigFile}"))
27 | {
28 | configBuilder.SaveConfig();
29 | }
30 |
31 | RunProgramCommands = configBuilder.ConfigStorage.Commands;
32 |
33 | if (RunProgramCommands is PluginCommand[] newCmds)
34 | {
35 | _commands = newCmds;
36 | }
37 |
38 | _canNotClose = configBuilder.ConfigStorage.CanNotClose;
39 | _notRunning = configBuilder.ConfigStorage.NotRunning;
40 | _canNotRun = configBuilder.ConfigStorage.CanNotRun;
41 | _alreadyRunning = configBuilder.ConfigStorage.AlreadyRunning;
42 | }
43 |
44 | public override void Execute(string commandName, List commandTokens)
45 | {
46 | var command = RunProgramCommands.FirstOrDefault(n => n.Name == commandName);
47 |
48 | if (command == null)
49 | {
50 | return;
51 | }
52 |
53 | var response = string.Empty;
54 | var processId = command.CommandLine;
55 |
56 | if (command.IsStopCommand)
57 | {
58 | if (_processes.TryGetValue(processId, out var proc))
59 | {
60 | if (proc != null)
61 | {
62 | try
63 | {
64 | proc.Kill();
65 | response = command.Response;
66 | }
67 | catch
68 | {
69 | response = _canNotClose;
70 | }
71 | finally
72 | {
73 | _processes.Remove(processId);
74 | }
75 | }
76 | else
77 | {
78 | response = _notRunning;
79 | }
80 | }
81 | else
82 | {
83 | response = _notRunning;
84 | }
85 | }
86 | else
87 | {
88 | if (!_processes.TryGetValue(processId, out _))
89 | {
90 | var process = RunCommand(command.CommandLine);
91 |
92 | if (process != null)
93 | {
94 | if (!command.AllowMultiple)
95 | {
96 | _processes.Add(processId, process);
97 | }
98 |
99 | response = command.Response;
100 | }
101 | else
102 | {
103 | response = _canNotRun;
104 | }
105 | }
106 | else
107 | {
108 | response = _alreadyRunning;
109 | }
110 | }
111 |
112 | AudioOut.Speak(response);
113 | }
114 |
115 | private Process RunCommand(string command)
116 | {
117 | Process proc;
118 | try
119 | {
120 | proc = Process.Start(command);
121 | }
122 | catch
123 | {
124 | try
125 | {
126 | // hack because of this: https://github.com/dotnet/corefx/issues/10361
127 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
128 | {
129 | command = command.Replace("&", "^&");
130 | proc = Process.Start(new ProcessStartInfo(command) { UseShellExecute = true });
131 |
132 | /*
133 | Process myProcess = new Process();
134 | try
135 | {
136 | // true is the default, but it is important not to set it to false
137 | myProcess.StartInfo.UseShellExecute = true;
138 | myProcess.StartInfo.FileName = "http://some.domain.tld/bla";
139 | myProcess.Start();
140 | }
141 | catch (Exception e)
142 | {
143 | Console.WriteLine(e.Message);
144 | }
145 | */
146 | //Windows.System.Launcher.LaunchUriAsync(new Uri("http://google.com"));
147 | //Process.Start("explorer.exe", $"\"{uri}\"");
148 |
149 | }
150 | else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
151 | {
152 | proc = Process.Start("xdg-open", command);
153 | }
154 | else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
155 | {
156 | proc = Process.Start("open", command);
157 | }
158 | else
159 | {
160 | throw;
161 | }
162 | }
163 | catch
164 | {
165 | return null;
166 | }
167 | }
168 |
169 | return proc;
170 | }
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/RunProgramPlugin/RunProgramPlugin.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/RunProgramPlugin/RunProgramPluginCommand.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using PluginInterface;
4 |
5 | namespace RunProgramPlugin
6 | {
7 | public class RunProgramPluginCommand : PluginCommand
8 | {
9 | public string Response = "";
10 | public string CommandLine = "";
11 | public bool IsStopCommand = false;
12 | public bool AllowMultiple = false;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/RunProgramPlugin/RunProgramPluginSettings.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using PluginInterface;
4 |
5 | namespace RunProgramPlugin
6 | {
7 | public class RunProgramPluginSettings
8 | {
9 | //[JsonProperty(Required = Required.Always)]
10 | public string CanNotClose = "не удалось закрыть";
11 | public string NotRunning = "не запущен";
12 | public string CanNotRun = "не удалось запустить";
13 | public string AlreadyRunning = "уже запущен";
14 |
15 | public RunProgramPluginCommand[] Commands =
16 | {
17 | new RunProgramPluginCommand
18 | {
19 | Name = "Run VSCode",
20 | Tokens = new[]
21 | {
22 | new Token
23 | {
24 | SuccessRate = 90,
25 | Type = TokenType.Command,
26 | Value = new[] {"запусти", "открой"}
27 | },
28 | new Token
29 | {
30 | SuccessRate = 90,
31 | Type = TokenType.Command,
32 | Value = new[] {"вес"}
33 | },
34 | new Token
35 | {
36 | SuccessRate = 90,
37 | Type = TokenType.Command,
38 | Value = new[] {"код"}
39 | }
40 | },
41 | Response = "Вижуал студио код запущена",
42 | CommandLine = "code",
43 | IsStopCommand = false,
44 | AllowMultiple = true
45 | },
46 | new RunProgramPluginCommand
47 | {
48 | Name = "Stop VSCode",
49 | Tokens = new[]
50 | {
51 | new Token
52 | {
53 | SuccessRate = 90,
54 | Type = TokenType.Command,
55 | Value = new[] {"останови", "закрой"}
56 | },
57 | new Token
58 | {
59 | SuccessRate = 90,
60 | Type = TokenType.Command,
61 | Value = new[] {"вес"}
62 | },
63 | new Token
64 | {
65 | SuccessRate = 90,
66 | Type = TokenType.Command,
67 | Value = new[] {"код"}
68 | }
69 | },
70 | Response = "Вижуал студио код закрыт",
71 | CommandLine = "code",
72 | IsStopCommand = true,
73 | AllowMultiple = true
74 | },
75 | new RunProgramPluginCommand
76 | {
77 | Name = "Run notepad++",
78 | Tokens = new[]
79 | {
80 | new Token
81 | {
82 | SuccessRate = 90,
83 | Type = TokenType.Command,
84 | Value = new[] {"запусти", "открой" }
85 | },
86 | new Token
87 | {
88 | SuccessRate = 90,
89 | Type = TokenType.Command,
90 | Value = new[] {"блокнот"}
91 | }
92 | },
93 | Response = "Блокнот запущен",
94 | CommandLine = "notepad++.exe",
95 | IsStopCommand = false,
96 | AllowMultiple = false
97 | },
98 | new RunProgramPluginCommand
99 | {
100 | Name = "Stop notepad++",
101 | Tokens = new[]
102 | {
103 | new Token
104 | {
105 | SuccessRate = 90,
106 | Type = TokenType.Command,
107 | Value = new[] {"останови", "закрой"}
108 | },
109 | new Token
110 | {
111 | SuccessRate = 90,
112 | Type = TokenType.Command,
113 | Value = new[] { "блокнот" }
114 | }
115 | },
116 | Response = "Блокнот закрыт",
117 | CommandLine = "notepad++.exe",
118 | IsStopCommand = true,
119 | AllowMultiple = false
120 | }
121 | };
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/RunProgramPlugin/RunProgramPluginSettings_eng.json:
--------------------------------------------------------------------------------
1 | {
2 | "CanNotClose": "can not close",
3 | "NotRunning": "not running",
4 | "CanNotRun": "can not run",
5 | "AlreadyRunning": "already running",
6 | "Commands": [
7 | {
8 | "Response": "Visual Studio Code is running",
9 | "CommandLine": "code",
10 | "IsStopCommand": false,
11 | "AllowMultiple": true,
12 | "Name": "Run VSCode",
13 | "Tokens": [
14 | {
15 | "Value": [
16 | "run",
17 | "open"
18 | ],
19 | "Type": "Command",
20 | "SuccessRate": 90
21 | },
22 | {
23 | "Value": [
24 | "vs"
25 | ],
26 | "Type": "Command",
27 | "SuccessRate": 90
28 | },
29 | {
30 | "Value": [
31 | "code"
32 | ],
33 | "Type": "Command",
34 | "SuccessRate": 90
35 | }
36 | ]
37 | },
38 | {
39 | "Response": "Visual Studio Code closed",
40 | "CommandLine": "code",
41 | "IsStopCommand": true,
42 | "AllowMultiple": true,
43 | "Name": "Stop VSCode",
44 | "Tokens": [
45 | {
46 | "Value": [
47 | "stop",
48 | "close"
49 | ],
50 | "Type": "Command",
51 | "SuccessRate": 90
52 | },
53 | {
54 | "Value": [
55 | "vs"
56 | ],
57 | "Type": "Command",
58 | "SuccessRate": 90
59 | },
60 | {
61 | "Value": [
62 | "code"
63 | ],
64 | "Type": "Command",
65 | "SuccessRate": 90
66 | }
67 | ]
68 | },
69 | {
70 | "Response": "notepad is running",
71 | "CommandLine": "notepad++.exe",
72 | "IsStopCommand": false,
73 | "AllowMultiple": false,
74 | "Name": "Run notepad++",
75 | "Tokens": [
76 | {
77 | "Value": [
78 | "run",
79 | "open"
80 | ],
81 | "Type": "Command",
82 | "SuccessRate": 90
83 | },
84 | {
85 | "Value": [
86 | "notepad"
87 | ],
88 | "Type": "Command",
89 | "SuccessRate": 90
90 | }
91 | ]
92 | },
93 | {
94 | "Response": "notepad is closed",
95 | "CommandLine": "notepad++.exe",
96 | "IsStopCommand": true,
97 | "AllowMultiple": false,
98 | "Name": "Stop notepad++",
99 | "Tokens": [
100 | {
101 | "Value": [
102 | "stop",
103 | "close"
104 | ],
105 | "Type": "Command",
106 | "SuccessRate": 90
107 | },
108 | {
109 | "Value": [
110 | "notepad"
111 | ],
112 | "Type": "Command",
113 | "SuccessRate": 90
114 | }
115 | ]
116 | }
117 | ]
118 | }
--------------------------------------------------------------------------------
/TimerPlugin/TimerPlugin.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Timers;
8 |
9 | using PluginInterface;
10 |
11 | namespace TimerPlugin
12 | {
13 | public class TimerPlugin : PluginBase
14 | {
15 | private readonly TimerPluginCommand[] TimerCommands;
16 | private readonly string _alarmSound;
17 | private readonly string _incorrectTime;
18 | private readonly string _timerNotFound;
19 | private readonly List<(string, Timer)> _timers = new List<(string, Timer)>();
20 |
21 | public TimerPlugin(IAudioOutSingleton audioOut, string currentCulture, string pluginPath) : base(audioOut, currentCulture, pluginPath)
22 | {
23 | var configBuilder = new Config($"{PluginPath}\\{PluginConfigFile}");
24 | if (!File.Exists($"{PluginPath}\\{PluginConfigFile}"))
25 | {
26 | configBuilder.SaveConfig();
27 | }
28 |
29 | TimerCommands = configBuilder.ConfigStorage.Commands;
30 |
31 | if (TimerCommands is PluginCommand[] newCmds)
32 | {
33 | _commands = newCmds;
34 | }
35 |
36 | _alarmSound = configBuilder.ConfigStorage.AlarmSound;
37 | _incorrectTime = configBuilder.ConfigStorage.IncorrectTime;
38 | _timerNotFound = configBuilder.ConfigStorage.TimerNotFound;
39 | }
40 |
41 | public override void Execute(string commandName, List commandTokens)
42 | {
43 | var command = TimerCommands.FirstOrDefault(n => n.Name == commandName);
44 |
45 |
46 | if (command == null)
47 | {
48 | return;
49 | }
50 |
51 | var minToken = command.GetParameter("%minutes%", commandTokens);
52 | var secToken = command.GetParameter("%seconds%", commandTokens);
53 | var minCount = 0;
54 |
55 | var stringToNumberConvertor = TextToNumberFactory.GetTextToNumberConvertor(CurrentCulture);
56 |
57 | if (minToken != null)
58 | {
59 | minCount = (int)stringToNumberConvertor.ConvertStringToNumber(minToken.Value[0], minToken.SuccessRate);
60 | }
61 |
62 | var secCount = 0;
63 | if (secToken != null)
64 | {
65 | secCount = (int)stringToNumberConvertor.ConvertStringToNumber(secToken.Value[0], secToken.SuccessRate);
66 | }
67 |
68 | var response = string.Empty;
69 | if (!command.isStopCommand && minCount + secCount == 0)
70 | {
71 | response = _incorrectTime;
72 | }
73 | else
74 | {
75 | var delay = $"{minCount}+{secCount}";
76 |
77 | var NumberToStringConvertor = NumberToTextFactory.GetNumberToTextConvertor(CurrentCulture);
78 |
79 |
80 | if (command.isStopCommand)
81 | {
82 | var timer = _timers.FirstOrDefault(n => n.Item2.Enabled && n.Item1 == delay);
83 |
84 | if (timer.Item2 != null)
85 | {
86 | timer.Item2.Stop();
87 | _timers.Remove(timer);
88 | // string.Empty is used to avoid using {0} int templates
89 | response = string.Format(command.Response, string.Empty,
90 | NumberToStringConvertor.ConvertNumberToString(minCount),
91 | NumberToStringConvertor.ConvertNumberToString(secCount));
92 | }
93 | else
94 | {
95 | response = _timerNotFound;
96 | }
97 | }
98 | else
99 | {
100 | var t = new Timer
101 | {
102 | AutoReset = false,
103 | Interval = new TimeSpan(0, minCount, secCount).TotalMilliseconds
104 | };
105 |
106 | t.Elapsed += (obj, args) =>
107 | {
108 | var timer = _timers.FirstOrDefault(n => n.Item2 == obj);
109 |
110 | if (timer.Item2 != null)
111 | {
112 | _timers.Remove(timer);
113 | }
114 |
115 | AudioOut.PlayFile($"{PluginPath}\\{_alarmSound}");
116 | };
117 |
118 | _timers.Add((delay, t));
119 | t.Start();
120 |
121 | // string.Empty is used to avoid using {0} int templates
122 | response = string.Format(command.Response, string.Empty,
123 | NumberToStringConvertor.ConvertNumberToString(minCount),
124 | NumberToStringConvertor.ConvertNumberToString(secCount));
125 | }
126 | }
127 |
128 | AudioOut.Speak(response);
129 | }
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/TimerPlugin/TimerPlugin.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | PreserveNewest
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/TimerPlugin/TimerPluginCommand.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using PluginInterface;
4 |
5 | namespace TimerPlugin
6 | {
7 | public class TimerPluginCommand : PluginCommand
8 | {
9 | public string Response = "";
10 | public bool isStopCommand = false;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/TimerPlugin/TimerPluginSettings_eng.json:
--------------------------------------------------------------------------------
1 | {
2 | "AlarmSound": "timer.wav",
3 | "IncorrectTime": "incorrect time",
4 | "TimerNotFound": "timer not found",
5 | "Commands": [
6 | {
7 | "Response": "Timer set to {1} minutes",
8 | "isStopCommand": false,
9 | "Name": "Run timer minutes",
10 | "Tokens": [
11 | {
12 | "Value": [
13 | "set",
14 | "start",
15 | "run"
16 | ],
17 | "Type": "Command",
18 | "SuccessRate": 90
19 | },
20 | {
21 | "Value": [
22 | "timer"
23 | ],
24 | "Type": "Command",
25 | "SuccessRate": 90
26 | },
27 | {
28 | "Value": [
29 | "to"
30 | ],
31 | "Type": "Command",
32 | "SuccessRate": 90
33 | },
34 | {
35 | "Value": [
36 | "%minutes%"
37 | ],
38 | "Type": "Parameter",
39 | "SuccessRate": 90
40 | },
41 | {
42 | "Value": [
43 | "minute",
44 | "minutes"
45 | ],
46 | "Type": "Command",
47 | "SuccessRate": 90
48 | }
49 | ]
50 | },
51 | {
52 | "Response": "{1} minutes timer stopped",
53 | "isStopCommand": true,
54 | "Name": "Stop timer minutes",
55 | "Tokens": [
56 | {
57 | "Value": [
58 | "stop",
59 | "delete"
60 | ],
61 | "Type": "Command",
62 | "SuccessRate": 90
63 | },
64 | {
65 | "Value": [
66 | "%minutes%"
67 | ],
68 | "Type": "Parameter",
69 | "SuccessRate": 90
70 | },
71 | {
72 | "Value": [
73 | "minute",
74 | "minutes"
75 | ],
76 | "Type": "Command",
77 | "SuccessRate": 90
78 | },
79 | {
80 | "Value": [
81 | "timer"
82 | ],
83 | "Type": "Command",
84 | "SuccessRate": 90
85 | },
86 | ]
87 | },
88 | {
89 | "Response": "Timer set to {2} seconds",
90 | "isStopCommand": false,
91 | "Name": "Run timer seconds",
92 | "Tokens": [
93 | {
94 | "Value": [
95 | "set",
96 | "start",
97 | "run"
98 | ],
99 | "Type": "Command",
100 | "SuccessRate": 90
101 | },
102 | {
103 | "Value": [
104 | "timer"
105 | ],
106 | "Type": "Command",
107 | "SuccessRate": 90
108 | },
109 | {
110 | "Value": [
111 | "to"
112 | ],
113 | "Type": "Command",
114 | "SuccessRate": 90
115 | },
116 | {
117 | "Value": [
118 | "%seconds%"
119 | ],
120 | "Type": "Parameter",
121 | "SuccessRate": 90
122 | },
123 | {
124 | "Value": [
125 | "second",
126 | "seconds"
127 | ],
128 | "Type": "Command",
129 | "SuccessRate": 90
130 | }
131 | ]
132 | },
133 | {
134 | "Response": "Таймер на {2} секунд остановлен",
135 | "isStopCommand": true,
136 | "Name": "Stop timer seconds",
137 | "Tokens": [
138 | {
139 | "Value": [
140 | "stop",
141 | "delete"
142 | ],
143 | "Type": "Command",
144 | "SuccessRate": 90
145 | },
146 | {
147 | "Value": [
148 | "%seconds%"
149 | ],
150 | "Type": "Parameter",
151 | "SuccessRate": 90
152 | },
153 | {
154 | "Value": [
155 | "second",
156 | "seconds"
157 | ],
158 | "Type": "Command",
159 | "SuccessRate": 90
160 | },
161 | {
162 | "Value": [
163 | "timer"
164 | ],
165 | "Type": "Command",
166 | "SuccessRate": 90
167 | }
168 | ]
169 | },
170 | {
171 | "Response": "Timer set to {1} minutes {2} seconds",
172 | "isStopCommand": false,
173 | "Name": "Run timer minutes, seconds",
174 | "Tokens": [
175 | {
176 | "Value": [
177 | "set",
178 | "start",
179 | "run"
180 | ],
181 | "Type": "Command",
182 | "SuccessRate": 90
183 | },
184 | {
185 | "Value": [
186 | "timer"
187 | ],
188 | "Type": "Command",
189 | "SuccessRate": 90
190 | },
191 | {
192 | "Value": [
193 | "to"
194 | ],
195 | "Type": "Command",
196 | "SuccessRate": 90
197 | },
198 | {
199 | "Value": [
200 | "%minutes%"
201 | ],
202 | "Type": "Parameter",
203 | "SuccessRate": 90
204 | },
205 | {
206 | "Value": [
207 | "minute",
208 | "minutes"
209 | ],
210 | "Type": "Command",
211 | "SuccessRate": 90
212 | },
213 | {
214 | "Value": [
215 | "%seconds%"
216 | ],
217 | "Type": "Parameter",
218 | "SuccessRate": 90
219 | },
220 | {
221 | "Value": [
222 | "second",
223 | "seconds"
224 | ],
225 | "Type": "Command",
226 | "SuccessRate": 90
227 | }
228 | ]
229 | },
230 | {
231 | "Response": "{1} minutes {2} seconds timer stopped",
232 | "isStopCommand": true,
233 | "Name": "Stop timer minutes, seconds",
234 | "Tokens": [
235 | {
236 | "Value": [
237 | "stop",
238 | "delete"
239 | ],
240 | "Type": "Command",
241 | "SuccessRate": 90
242 | },
243 | {
244 | "Value": [
245 | "%minutes%"
246 | ],
247 | "Type": "Parameter",
248 | "SuccessRate": 90
249 | },
250 | {
251 | "Value": [
252 | "minute",
253 | "minutes"
254 | ],
255 | "Type": "Command",
256 | "SuccessRate": 90
257 | },
258 | {
259 | "Value": [
260 | "%seconds%"
261 | ],
262 | "Type": "Parameter",
263 | "SuccessRate": 90
264 | },
265 | {
266 | "Value": [
267 | "second",
268 | "seconds"
269 | ],
270 | "Type": "Command",
271 | "SuccessRate": 90
272 | },
273 | {
274 | "Value": [
275 | "timer"
276 | ],
277 | "Type": "Command",
278 | "SuccessRate": 90
279 | }
280 | ]
281 | },
282 | {
283 | "Response": "Timers stopped",
284 | "isStopCommand": true,
285 | "Name": "Stop timers",
286 | "Tokens": [
287 | {
288 | "Value": [
289 | "stop",
290 | "delete"
291 | ],
292 | "Type": "Command",
293 | "SuccessRate": 90
294 | },
295 | {
296 | "Value": [
297 | "timers"
298 | ],
299 | "Type": "Command",
300 | "SuccessRate": 90
301 | }
302 | ]
303 | },
304 | {
305 | "Response": "all timers stopped",
306 | "isStopCommand": true,
307 | "Name": "Stop all timers",
308 | "Tokens": [
309 | {
310 | "Value": [
311 | "stop",
312 | "delete"
313 | ],
314 | "Type": "Command",
315 | "SuccessRate": 90
316 | },
317 | {
318 | "Value": [
319 | "all"
320 | ],
321 | "Type": "Command",
322 | "SuccessRate": 90
323 | },
324 | {
325 | "Value": [
326 | "timers"
327 | ],
328 | "Type": "Command",
329 | "SuccessRate": 90
330 | }
331 | ]
332 | }
333 | ]
334 | }
--------------------------------------------------------------------------------
/TimerPlugin/timer.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jekyll2014/VoiceAssistant/bea10e8c38475eb44d8f67e4f7300f4625a33276/TimerPlugin/timer.wav
--------------------------------------------------------------------------------
/VoiceAssistant.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.2.32616.157
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VoiceAssistant", "VoiceAssistant\VoiceAssistant.csproj", "{298A14AF-23B7-4520-AC88-F34499FA784A}"
7 | ProjectSection(ProjectDependencies) = postProject
8 | {D8E672A3-242D-436B-9C6C-F92B8F864F4C} = {D8E672A3-242D-436B-9C6C-F92B8F864F4C}
9 | EndProjectSection
10 | EndProject
11 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TimerPlugin", "TimerPlugin\TimerPlugin.csproj", "{FBC63F53-EE4B-4E6E-81D6-0AF31019F517}"
12 | ProjectSection(ProjectDependencies) = postProject
13 | {D8E672A3-242D-436B-9C6C-F92B8F864F4C} = {D8E672A3-242D-436B-9C6C-F92B8F864F4C}
14 | EndProjectSection
15 | EndProject
16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HelloPlugin", "HelloPlugin\HelloPlugin.csproj", "{D4F6D69B-7655-44A6-8E82-38698B3C19B6}"
17 | ProjectSection(ProjectDependencies) = postProject
18 | {D8E672A3-242D-436B-9C6C-F92B8F864F4C} = {D8E672A3-242D-436B-9C6C-F92B8F864F4C}
19 | EndProjectSection
20 | EndProject
21 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PluginInterface", "PluginInterface\PluginInterface.csproj", "{D8E672A3-242D-436B-9C6C-F92B8F864F4C}"
22 | EndProject
23 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BrowserPlugin", "BrowserPlugin\BrowserPlugin.csproj", "{B8B95E2A-AB96-42B6-B9CD-3C402F5FDD6A}"
24 | EndProject
25 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RunProgramPlugin", "RunProgramPlugin\RunProgramPlugin.csproj", "{167C8B0A-E613-4B9B-AE8A-C09C8B167166}"
26 | EndProject
27 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CurrencyRatePlugin", "CurrencyRatePlugin\CurrencyRatePlugin.csproj", "{CA81441C-2635-4847-A86D-0F8C57F7243D}"
28 | EndProject
29 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppControlPlugin", "AppControlPlugin\AppControlPlugin.csproj", "{EC559348-A4A1-4A34-BC79-9D42EC85956A}"
30 | EndProject
31 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenWeatherPlugin", "OpenWeatherPlugin\OpenWeatherPlugin.csproj", "{66B0ADBA-EE01-4674-9CA1-018ABA79058C}"
32 | EndProject
33 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GoogleCalendarPlugin", "GoogleCalendarPlugin\GoogleCalendarPlugin.csproj", "{53B5123F-6468-4F45-A8B5-209384312E42}"
34 | EndProject
35 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTOutPlugin", "MQTTOutPlugin\MQTTOutPlugin.csproj", "{BDF6B74D-D98F-4B78-95BB-39C63BE8BB77}"
36 | ProjectSection(ProjectDependencies) = postProject
37 | {D8E672A3-242D-436B-9C6C-F92B8F864F4C} = {D8E672A3-242D-436B-9C6C-F92B8F864F4C}
38 | EndProjectSection
39 | EndProject
40 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MQTTInPlugin", "MQTTInPlugin\MQTTInPlugin.csproj", "{107E156F-D939-43AD-BE00-70EBBB3333DA}"
41 | EndProject
42 | Global
43 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
44 | Debug|Any CPU = Debug|Any CPU
45 | Release|Any CPU = Release|Any CPU
46 | EndGlobalSection
47 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
48 | {298A14AF-23B7-4520-AC88-F34499FA784A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
49 | {298A14AF-23B7-4520-AC88-F34499FA784A}.Debug|Any CPU.Build.0 = Debug|Any CPU
50 | {298A14AF-23B7-4520-AC88-F34499FA784A}.Release|Any CPU.ActiveCfg = Release|Any CPU
51 | {298A14AF-23B7-4520-AC88-F34499FA784A}.Release|Any CPU.Build.0 = Release|Any CPU
52 | {FBC63F53-EE4B-4E6E-81D6-0AF31019F517}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
53 | {FBC63F53-EE4B-4E6E-81D6-0AF31019F517}.Debug|Any CPU.Build.0 = Debug|Any CPU
54 | {FBC63F53-EE4B-4E6E-81D6-0AF31019F517}.Release|Any CPU.ActiveCfg = Release|Any CPU
55 | {FBC63F53-EE4B-4E6E-81D6-0AF31019F517}.Release|Any CPU.Build.0 = Release|Any CPU
56 | {D4F6D69B-7655-44A6-8E82-38698B3C19B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
57 | {D4F6D69B-7655-44A6-8E82-38698B3C19B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
58 | {D4F6D69B-7655-44A6-8E82-38698B3C19B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
59 | {D4F6D69B-7655-44A6-8E82-38698B3C19B6}.Release|Any CPU.Build.0 = Release|Any CPU
60 | {D8E672A3-242D-436B-9C6C-F92B8F864F4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
61 | {D8E672A3-242D-436B-9C6C-F92B8F864F4C}.Debug|Any CPU.Build.0 = Debug|Any CPU
62 | {D8E672A3-242D-436B-9C6C-F92B8F864F4C}.Release|Any CPU.ActiveCfg = Release|Any CPU
63 | {D8E672A3-242D-436B-9C6C-F92B8F864F4C}.Release|Any CPU.Build.0 = Release|Any CPU
64 | {B8B95E2A-AB96-42B6-B9CD-3C402F5FDD6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
65 | {B8B95E2A-AB96-42B6-B9CD-3C402F5FDD6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
66 | {B8B95E2A-AB96-42B6-B9CD-3C402F5FDD6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
67 | {B8B95E2A-AB96-42B6-B9CD-3C402F5FDD6A}.Release|Any CPU.Build.0 = Release|Any CPU
68 | {167C8B0A-E613-4B9B-AE8A-C09C8B167166}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
69 | {167C8B0A-E613-4B9B-AE8A-C09C8B167166}.Debug|Any CPU.Build.0 = Debug|Any CPU
70 | {167C8B0A-E613-4B9B-AE8A-C09C8B167166}.Release|Any CPU.ActiveCfg = Release|Any CPU
71 | {167C8B0A-E613-4B9B-AE8A-C09C8B167166}.Release|Any CPU.Build.0 = Release|Any CPU
72 | {CA81441C-2635-4847-A86D-0F8C57F7243D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
73 | {CA81441C-2635-4847-A86D-0F8C57F7243D}.Debug|Any CPU.Build.0 = Debug|Any CPU
74 | {CA81441C-2635-4847-A86D-0F8C57F7243D}.Release|Any CPU.ActiveCfg = Release|Any CPU
75 | {CA81441C-2635-4847-A86D-0F8C57F7243D}.Release|Any CPU.Build.0 = Release|Any CPU
76 | {EC559348-A4A1-4A34-BC79-9D42EC85956A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
77 | {EC559348-A4A1-4A34-BC79-9D42EC85956A}.Debug|Any CPU.Build.0 = Debug|Any CPU
78 | {EC559348-A4A1-4A34-BC79-9D42EC85956A}.Release|Any CPU.ActiveCfg = Release|Any CPU
79 | {EC559348-A4A1-4A34-BC79-9D42EC85956A}.Release|Any CPU.Build.0 = Release|Any CPU
80 | {66B0ADBA-EE01-4674-9CA1-018ABA79058C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
81 | {66B0ADBA-EE01-4674-9CA1-018ABA79058C}.Debug|Any CPU.Build.0 = Debug|Any CPU
82 | {66B0ADBA-EE01-4674-9CA1-018ABA79058C}.Release|Any CPU.ActiveCfg = Release|Any CPU
83 | {66B0ADBA-EE01-4674-9CA1-018ABA79058C}.Release|Any CPU.Build.0 = Release|Any CPU
84 | {53B5123F-6468-4F45-A8B5-209384312E42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
85 | {53B5123F-6468-4F45-A8B5-209384312E42}.Debug|Any CPU.Build.0 = Debug|Any CPU
86 | {53B5123F-6468-4F45-A8B5-209384312E42}.Release|Any CPU.ActiveCfg = Release|Any CPU
87 | {53B5123F-6468-4F45-A8B5-209384312E42}.Release|Any CPU.Build.0 = Release|Any CPU
88 | {BDF6B74D-D98F-4B78-95BB-39C63BE8BB77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
89 | {BDF6B74D-D98F-4B78-95BB-39C63BE8BB77}.Debug|Any CPU.Build.0 = Debug|Any CPU
90 | {BDF6B74D-D98F-4B78-95BB-39C63BE8BB77}.Release|Any CPU.ActiveCfg = Release|Any CPU
91 | {BDF6B74D-D98F-4B78-95BB-39C63BE8BB77}.Release|Any CPU.Build.0 = Release|Any CPU
92 | {107E156F-D939-43AD-BE00-70EBBB3333DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
93 | {107E156F-D939-43AD-BE00-70EBBB3333DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
94 | {107E156F-D939-43AD-BE00-70EBBB3333DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
95 | {107E156F-D939-43AD-BE00-70EBBB3333DA}.Release|Any CPU.Build.0 = Release|Any CPU
96 | EndGlobalSection
97 | GlobalSection(SolutionProperties) = preSolution
98 | HideSolutionNode = FALSE
99 | EndGlobalSection
100 | GlobalSection(ExtensibilityGlobals) = postSolution
101 | SolutionGuid = {E98BAD0E-2957-4758-9F3E-6094D374516D}
102 | EndGlobalSection
103 | EndGlobal
104 |
--------------------------------------------------------------------------------
/VoiceAssistant/AssistantStart.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jekyll2014/VoiceAssistant/bea10e8c38475eb44d8f67e4f7300f4625a33276/VoiceAssistant/AssistantStart.wav
--------------------------------------------------------------------------------
/VoiceAssistant/AudioOutSingleton.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using NAudio.Wave;
4 |
5 | using PluginInterface;
6 |
7 | using System.Globalization;
8 | using System.IO;
9 | using System.Speech.AudioFormat;
10 | using System.Speech.Synthesis;
11 | using System.Threading;
12 |
13 | namespace VoiceAssistant
14 | {
15 | public class AudioOutSingleton : IAudioOutSingleton
16 | {
17 | private static AudioOutSingleton _instance;
18 | private static readonly object SyncRoot = new();
19 | private readonly SpeechSynthesizer _synthesizer;
20 | private readonly PromptBuilder _promptBuilder;
21 | private readonly WaveOut _waveOut;
22 | private readonly int _sampleRate;
23 | private readonly string _speakerLanguage;
24 |
25 | protected AudioOutSingleton(string speakerLanguage, SpeechSynthesizer synthesizer, PromptBuilder promptBuilder,
26 | WaveOut waveOut, int sampleRate)
27 | {
28 | _speakerLanguage = speakerLanguage;
29 | _synthesizer = synthesizer;
30 | _promptBuilder = promptBuilder;
31 | _waveOut = waveOut;
32 | _sampleRate = sampleRate;
33 | }
34 |
35 | public static AudioOutSingleton GetInstance(string speakerLanguage, SpeechSynthesizer synthesizer,
36 | PromptBuilder promptBuilder, WaveOut waveOut, int sampleRate)
37 | {
38 | if (_instance != null)
39 | return _instance;
40 |
41 | lock (SyncRoot)
42 | {
43 | _instance ??= new AudioOutSingleton(speakerLanguage, synthesizer, promptBuilder, waveOut,
44 | sampleRate);
45 | }
46 |
47 | return _instance;
48 | }
49 |
50 | public void Speak(string text, bool exclusive = true)
51 | {
52 | if (_instance == null)
53 | return;
54 |
55 | lock (SyncRoot)
56 | {
57 | var speechStream = new MemoryStream();
58 | var rs = new RawSourceWaveStream(speechStream, new WaveFormat(_sampleRate, 2));
59 | _synthesizer.SetOutputToAudioStream(speechStream,
60 | new SpeechAudioFormatInfo(_sampleRate, AudioBitsPerSample.Sixteen, AudioChannel.Stereo));
61 |
62 | _promptBuilder.StartVoice(new CultureInfo(_speakerLanguage));
63 | _promptBuilder.AppendText(text);
64 | _promptBuilder.EndVoice();
65 | _synthesizer.Speak(_promptBuilder);
66 | _promptBuilder.ClearContent();
67 |
68 | rs.Position = 0;
69 | _waveOut.Init(rs);
70 | _waveOut.Play();
71 |
72 | if (!exclusive)
73 | return;
74 |
75 | while (_waveOut.PlaybackState == PlaybackState.Playing)
76 | {
77 | Thread.Sleep(100);
78 | }
79 | }
80 | }
81 |
82 | public void PlayFile(string audioFile, bool exclusive = true)
83 | {
84 | if (_instance == null)
85 | return;
86 |
87 | lock (SyncRoot)
88 | {
89 | using (var file = new AudioFileReader(audioFile))
90 | {
91 | _waveOut.Init(file);
92 | _waveOut.Play();
93 |
94 | if (!exclusive)
95 | return;
96 |
97 | while (_waveOut.PlaybackState == PlaybackState.Playing)
98 | {
99 | Thread.Sleep(100);
100 | }
101 | }
102 | }
103 | }
104 |
105 | public void PlayDataBuffer(byte[] data, bool exclusive = true)
106 | {
107 | if (_instance == null)
108 | return;
109 |
110 | lock (SyncRoot)
111 | {
112 | using (var provider = new RawSourceWaveStream(new MemoryStream(data), new WaveFormat(16000, 1)))
113 | {
114 | provider.Position = 0;
115 | _waveOut.Init(provider);
116 | _waveOut.Play();
117 |
118 | if (!exclusive)
119 | return;
120 |
121 | while (_waveOut.PlaybackState == PlaybackState.Playing)
122 | {
123 | Thread.Sleep(100);
124 | }
125 | }
126 | }
127 | }
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/VoiceAssistant/GenericPluginLoader.cs:
--------------------------------------------------------------------------------
1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it.
2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Reflection;
8 | using System.Runtime.Loader;
9 |
10 | using PluginInterface;
11 |
12 | namespace VoiceAssistant
13 | {
14 | public class GenericPluginLoader where T : PluginBase
15 | {
16 | private readonly List> _loadContexts = new();
17 |
18 | public List LoadAll(string pluginPath, string filter, params object[] constructorArgs)
19 | {
20 | var plugins = new List();
21 |
22 | foreach (var filePath in Directory.EnumerateFiles(pluginPath, filter, SearchOption.AllDirectories))
23 | {
24 | try
25 | {
26 | var plugin = Load(filePath, constructorArgs);
27 |
28 | if (plugin != null)
29 | {
30 | plugins.Add(plugin);
31 | }
32 | }
33 | catch (Exception ex)
34 | {
35 | Console.WriteLine($"Error loading plugin {filePath}: {ex}");
36 | }
37 | }
38 |
39 | return plugins;
40 | }
41 |
42 | private T Load(string pluginPath, params object[] constructorArgs)
43 | {
44 | var loadContext = new GenericAssemblyLoadContext(pluginPath);
45 |
46 | _loadContexts.Add(loadContext);
47 |
48 | var assembly = loadContext.LoadFromAssemblyPath(pluginPath);
49 |
50 | var type = assembly.GetTypes().FirstOrDefault(t => typeof(T).IsAssignableFrom(t));
51 | if (type == null) return null;
52 |
53 | var newArgs = new List