Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Diagnostics;
- using System.IO;
- using System.Net.Http;
- using System.Net.Http.Headers;
- using System.Runtime.InteropServices;
- using System.Threading;
- using System.Threading.Tasks;
- using System.Windows.Forms;
- using NAudio.Wave;
- using Newtonsoft.Json.Linq;
- namespace VkVoiceTyper
- {
- class Program
- {
- // === СЕРВИСНЫЙ ТОКЕН VK CLOUD ===
- // Вставьте токен из настроек проекта VK Cloud
- private const string ServiceToken = "ВАШ_СЕРВИСНЫЙ_ТОКЕН_VC_...";
- private const string OutputFileName = "voice_temp.wav";
- // === ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ ===
- private static WaveInEvent? waveIn;
- private static WaveFileWriter? writer;
- private static bool isRecording = false;
- private static bool isProcessing = false;
- // === HOOK API ===
- private const int WH_KEYBOARD_LL = 13;
- private const int WM_KEYDOWN = 0x0100;
- private const int WM_KEYUP = 0x0101;
- private const int VK_RCONTROL = 0xA3;
- private const int VK_ESCAPE = 0x1B;
- private static LowLevelKeyboardProc proc = HookCallback;
- private static IntPtr hookID = IntPtr.Zero;
- // HttpClient с таймаутом
- private static readonly HttpClient httpClient = new HttpClient()
- {
- Timeout = TimeSpan.FromSeconds(15)
- };
- static void Main(string[] args)
- {
- Console.WriteLine("🎙️ VK VoiceTyper (Service Token)");
- Console.WriteLine("👉 Удерживайте ПРАВЫЙ CTRL для записи");
- Console.WriteLine("🔚 ESC — выход");
- Console.WriteLine("================================\n");
- // Проверка токена при старте
- if (string.IsNullOrEmpty(ServiceToken) || ServiceToken == "ВАШ_СЕРВИСНЫЙ_ТОКЕН_VC_...")
- {
- Console.WriteLine("❌ Ошибка: Вставьте сервисный токен в код!");
- Console.WriteLine("Нажмите любую клавишу для выхода...");
- Console.ReadKey();
- return;
- }
- Console.WriteLine("✅ Токен загружен. Сервис готов.\n");
- hookID = SetHook(proc);
- Application.Run();
- }
- // === HOOK CALLBACK ===
- private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
- {
- if (nCode >= 0)
- {
- int vkCode = Marshal.ReadInt32(lParam);
- if (wParam == (IntPtr)WM_KEYDOWN && vkCode == VK_RCONTROL)
- {
- if (!isRecording && !isProcessing)
- Task.Run(() => StartRecordingAsync());
- }
- else if (wParam == (IntPtr)WM_KEYUP && vkCode == VK_RCONTROL)
- {
- if (isRecording)
- Task.Run(() => StopRecordingAndProcessAsync());
- }
- else if (wParam == (IntPtr)WM_KEYDOWN && vkCode == VK_ESCAPE)
- {
- UnhookWindowsHookEx(hookID);
- Application.Exit();
- return (IntPtr)1;
- }
- }
- return CallNextHookEx(hookID, nCode, wParam, lParam);
- }
- private static IntPtr SetHook(LowLevelKeyboardProc proc)
- {
- using Process curProcess = Process.GetCurrentProcess();
- using ProcessModule? curModule = curProcess.MainModule;
- return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
- GetModuleHandle(curModule?.ModuleName), 0);
- }
- private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
- [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
- [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static extern bool UnhookWindowsHookEx(IntPtr hhk);
- [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
- [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- private static extern IntPtr GetModuleHandle(string? lpModuleName);
- // === ЗАПИСЬ ===
- private static void StartRecordingAsync()
- {
- if (isRecording) return;
- isRecording = true;
- Console.WriteLine("🔴 Запись... (отпустите RCtrl)");
- var waveFormat = new WaveFormat(16000, 16, 1);
- waveIn = new WaveInEvent { WaveFormat = waveFormat };
- writer = new WaveFileWriter(OutputFileName, waveIn.WaveFormat);
- waveIn.DataAvailable += (s, e) => writer?.Write(e.Buffer, 0, e.BytesRecorded);
- waveIn.StartRecording();
- }
- private static async Task StopRecordingAndProcessAsync()
- {
- if (!isRecording) return;
- isRecording = false;
- Console.WriteLine("⏹️ Остановка...");
- waveIn?.StopRecording();
- waveIn?.Dispose();
- writer?.Dispose();
- waveIn = null;
- writer = null;
- await Task.Delay(200);
- if (!File.Exists(OutputFileName))
- {
- Console.WriteLine("⚠️ Файл не создан");
- return;
- }
- long fileSize = new FileInfo(OutputFileName).Length;
- if (fileSize < 1000)
- {
- Console.WriteLine($"⚠️ Слишком короткая запись ({fileSize} байт)");
- return;
- }
- isProcessing = true;
- Console.WriteLine("🔄 Распознавание...");
- try
- {
- string? recognizedText = await RecognizeSpeechAsync(ServiceToken, OutputFileName);
- if (!string.IsNullOrWhiteSpace(recognizedText))
- {
- Console.WriteLine($"✅ Распознано: \"{recognizedText}\"");
- InsertTextInStaThread(recognizedText);
- }
- else
- {
- Console.WriteLine("⚠️ Текст не распознан");
- System.Media.SystemSounds.Beep.Play();
- }
- }
- catch (TaskCanceledException)
- {
- Console.WriteLine("❌ Таймаут! Сервер не ответил за 15 секунд.");
- System.Media.SystemSounds.Beep.Play();
- }
- catch (Exception ex)
- {
- Console.WriteLine($"❌ Ошибка: {ex.Message}");
- if (ex.InnerException != null)
- Console.WriteLine($" Детали: {ex.InnerException.Message}");
- System.Media.SystemSounds.Beep.Play();
- }
- finally
- {
- isProcessing = false;
- if (File.Exists(OutputFileName))
- File.Delete(OutputFileName);
- }
- }
- // === ВСТАВКА ТЕКСТА ===
- private static void InsertTextInStaThread(string text)
- {
- Thread staThread = new Thread(() =>
- {
- try
- {
- Clipboard.SetText(text, TextDataFormat.Text);
- Thread.Sleep(150);
- Console.WriteLine("📋 Текст скопирован в буфер обмена (Ctrl+V для вставки)");
- }
- catch (Exception ex)
- {
- Console.WriteLine($"⚠️ Ошибка буфера: {ex.Message}");
- }
- });
- staThread.SetApartmentState(ApartmentState.STA);
- staThread.Start();
- staThread.Join();
- }
- // === РАСПОЗНАВАНИЕ (с сервисным токеном) ===
- private static async Task<string?> RecognizeSpeechAsync(string token, string filePath)
- {
- try
- {
- byte[] fileBytes = File.ReadAllBytes(filePath);
- var content = new ByteArrayContent(fileBytes);
- content.Headers.ContentType = new MediaTypeHeaderValue("audio/wave");
- var request = new HttpRequestMessage(HttpMethod.Post, "https://voice.mcs.mail.ru/asr");
- // ✅ Сервисный токен используется напрямую
- request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
- request.Content = content;
- Console.WriteLine("📤 Отправка в VK Cloud Voice...");
- var response = await httpClient.SendAsync(request);
- if (response.IsSuccessStatusCode)
- {
- var json = await response.Content.ReadAsStringAsync();
- var jobject = JObject.Parse(json);
- if (jobject["result"]?["texts"] is JArray texts && texts.Count > 0)
- {
- return texts[0]["punctuated_text"]?.ToString();
- }
- else
- {
- Console.WriteLine($"⚠️ Ответ сервера: {json}");
- return null;
- }
- }
- else
- {
- var error = await response.Content.ReadAsStringAsync();
- Console.WriteLine($"🔌 API ошибка: {response.StatusCode}");
- Console.WriteLine($" Детали: {error}");
- // Проверка на истёкший токен
- if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
- {
- Console.WriteLine("⚠️ Токен недействителен. Получите новый в VK Cloud.");
- }
- return null;
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine($"🔌 Ошибка распознавания: {ex.Message}");
- throw;
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment