Русский
Русский
English
Статистика
Реклама

Помощник

Из Vue 2 на Vue 3 Migration Helper

09.06.2021 20:16:20 | Автор: admin

Предистория

Была у меня курсовая по веб-разработке, делать очередной интернет-магазин как-то не хотелось, и решил я написать помощник миграции из Vue 2 (options-api) в Vue 3 (composition-api) с авторазделением на композиции с помощью алгоритма Косарайю по поиску областей сильной связности

Для тех, кто не в теме, поясню, так выглядит код с options-api:

export default {  data () {    return {      foo: 0,      bar: 'hello',    }  },  watch: {    ...  },  methods: {    log(v) {      console.log(v);    },  },  mounted () {    this.log('Hello');  }}

и примерно так с composition-api:

export default {  setup (props) {    const foo = reactive(0);    const bar = reactive('hello');    watch(...);    const log = (v) => { console.log(v); };    onMounted(() => { log('hello'); });    return {      foo,      bar,      log,    };  }}

Автоматическое разделение на композиции

Дабы не отходить от самой идеи композиций, помимо трансляции кода под новый синтаксис composition-api, было принято решение добавить и возможность разделения монолитного компонента на самостоятельные композиции, и их последующее переиспользование в главном компоненте. Как же это сделать?

Сначала зададимся вопросом, что же такое композиции? Для себя я ответил так:

Композиции это самодостаточная группа блоков кода, отвечающих за один функционал, зависящих только друг от друга. Зависимости тут самое главное!

Блоками кода в нашем случае будем считать: свойства data, методы, вотчеры, хуки, и все то, из чего строится компонент Vue.

Теперь определимся на счёт зависимостей блоков кода между собой. С этим во Vue достаточно просто:

  • Если computed, method, hook, provide свойство внутри себя использует другие свойства, то оно от них и зависит

  • Если на свойство навешен вотчер, то вотчер зависит от наблюдаемого им свойства

  • и так далее :)

data: () => ({  array: ['Hello', 'World'], // block 1}),watch: {  array() { // block 2 (watch handler) depends on block 1    console.log('array changed');  },},computed: {  arrayCount() { // block 3    return this.array.length; // block 3 depends on block 1  },},methods: {  arrayToString() { // block 4    return this.array.join(' '); // block 4 depends on block 1  }},

Допустим, мы смогли пройтись по коду и выделить все-все зависимости свойств между собой. Как всё это делить на композиции?

А теперь абстрагируемся от Vue, проблемы миграции, синтаксиса и т.д. Оставим только сами свойства и их зависимости друг с другом.

Выделим из этого ориентированный граф, где вершинами будут свойства, а ребрами - зависимости между свойствами. А теперь самое интересное!

Алгоритм Косарайю

Алгоритм поискаобластей сильной связностив ориентированном графе. Заключается он в двух проходах в глубину по исходному и транспонированному графам и небольшой магии.

Никогда бы не подумал, что простое переписывание реализации из C на TS может быть таким проблемным :)

Так вот. Применяя данный алгоритм, мы и получим заветные композиции, состоящие из сгруппированных по связям свойств. Если же свойство оказалось одиноким и без пары, мы отнесем его к самому будущему компоненту, если же нет выделим группу в одну композицию, которую будем переиспользовать.

Поиск зависимостей

Примечание: во всех функциях компонента в options-api свойства доступны через this

Здесь немного грусти, поскольку искать зависимости в .js приходится так:

const splitter = /this.[0-9a-zA-Z]{0,}/const splitterThis = 'this.'export const findDepsByString = (  vueExpression: string,  instanceDeps: InstanceDeps): ConnectionsType | undefined => {  return vueExpression    .match(splitter)    ?.map((match) => match.split(splitterThis)[1])    .filter((value) => instanceDeps[value])    .map((value) => value)

Да, просто проходясь регуляркой по строкому представлению функции в поисках всего, что идет после this. :(

Более продвинутый вариант, но такой же костыльный:

export const findDeps = (  vueExpression: Noop,  instanceDeps: InstanceDeps): ConnectionsType | undefined => {  const target = {}  const proxy = new Proxy(target, {  // прокси, который записывает в объект вызываемые им свойства    get(target: any, name) {      target[name] = 'get'      return true    },    set(target: any, name) {      target[name] = 'set'      return true    }  })  try {    vueExpression.bind(proxy)() // вызываем функцию в скоупе прокси    return Object.keys(target) || [] // все свойства которые вызвались при this.  } catch (e) { // при ошибке возвращаемся к первому способу    return findDepsByString(vueExpression.toString(), instanceDeps) || []  }}

При использовании прокси вышло несколько проблем:

  • не работает с анонимными функциями

  • при использовании вызывается сама функция а если вы там пентагон взламываете?

Создание файлов и кода

Вспомним зачем мы тут собрались: миграция.

Используя все вышеописанное, получив разбитые по полочкам свойства, нужно составить новый код в синтаксисе composition-api, то есть собрать строки, которые в конечном счете будут являться содержимыми файлов в проекте.

Для этого надо уметь представлять экземпляры объектов, строк, массивов и всего остального в их естественном, кодовом, виде. Вот эта функция:

const toString = (item: any): string => {  if (Array.isArray(item)) {    // array    const builder: string[] = []    item.forEach((_) => {      builder.push(toString(_)) // wow, it's recursion!    })    return `[${builder.join(',')}]`  }  if (typeof item === 'object' && item !== null) {    // object    const builder: string[] = []    Object.keys(item).forEach((name) => {      builder.push(`${name}: ${toString(item[name])}`) // wow, it's recursion!    })    return `{${builder.join(',')}}`  }  if (typeof item === 'string') {    // string    return `'${item}'`  }  return item // number, float, boolean}// Exampleconsole.log(toString([{ foo: { bar: 'hello', baz: 'hello', }}, 1]);// [{foo:{bar: 'hello',baz: 'hello'}},1]  т.е. то же самое, что и в коде

Про остальной говнокод я тактично промолчу :)

Итоговые строки мы записываем в новые файлы через простой fs.writeFile() в ноде и получаем результат

Пример работы

Собрав всё это в пакет, протестировав и опубликовав, можно наконец увидеть результат работы.

Ставим пакет vue2-to-3 глобально (иначе не будет работать через консоль) и проверяем!

Пример HelloWorld.js:

export default {  name: 'HelloWorld',  data: () => ({    some: 0,    another: 0,    foo: ['potato'],  }),  methods: {    somePlus() {      this.some++;    },    anotherPlus() {      this.another++;    },  },};

Пишем в консоли: migrate ./HelloWorld.js и получаем на выход 3 файла:

// CompositionSome.jsimport { reactive } from 'vue';export const CompositionSome = () => {  const some = reactive(0);  const somePlus = () => { some++ };  return {    some,    somePlus,  };};// CompositionAnother.jsimport { reactive } from 'vue';export const CompositionAnother = () => {  const another = reactive(0);  const anotherPlus = () => { another++ };  return {    another,    anotherPlus,  };};// HelloWorld.jsimport { reactive } from 'vue';import { CompositionSome } from './CompositionSome.js'import { CompositionAnother } from './CompositionAnother.js'export default {  name: 'HelloWorld',  setup() {    const _CompositionSome = CompositionSome();    const _CompositionAnother = CompositionAnother();    const foo = reactive(['potato']);    return {      foo,      some: _CompositionSome.some,      somePlus: _CompositionSome.somePlus,      another: _CompositionAnother.another,      anotherPlus: _CompositionAnother.anotherPlus,    };  },};

Итого

На данный момент все это доступно и работает, но ещё есть некоторые баги со строковым представлением не анонимных функций и путями (в некоторых случаях фатально для linux систем)

В планах запилить миграцию для single-file-components и .ts файлов (сейчас работает только для .js)

Спасибо за внимание!

npm, git

Подробнее..

Открываем дверь при помощи голосового ассистента

18.12.2020 18:13:39 | Автор: admin


Всем привет!
Сегодня у меня статья про то, как при помощи Яндекс-колонки Алиса и Ардуино, можно открыть дверь, подключенную к домофону. Если Вам это интересно, то прошу под кат.

Часто бывает так, что кто-то звонит в домофон, а ты в этот момент чем-то занят или просто лень подходить для того, чтобы открыть дверь. Знакомая ситуация, не правда ли?
А мой домофон так вообще без поднятия трубки не открывает дверь и если в течении 30 секунд после вызова не поднять трубку, то кнопка открывания двери перестанет быть активной до того момента, пока не поступит новый вызов. Так как домофон не из дешёвых (на тот момент) меня жаба душила менять его на другой. И я решил с этим бороться.

Первая идея упростить себе жизнь появилась 10 лет назад, я решил сделать адаптер домофон-телефон, чтобы звонок с домофона дублировался на домашний телефон. Нарисовал схему, собрал прототип на макетной плате. Все заработало, но дальше этого прототипа я так и не продвинулся. Всё так и валяется по сей день в хламе.

Второй проект был реализован на роутере TL-MR3020 с прошивкой CyberWRT и программным СИП телефоном BareSIP. При нажатии на кнопку вызывной панели, роутер параллельно с вызовом интеркома звонил на мобильный телефон и можно было даже находясь в другом городе разговаривать с человеком, стоящим около двери твоей квартиры, но программный телефон или сам роутер, работали крайне нестабильно и пришлось от него отказаться.
Но тут к моему счастью в прошлом году на день рождения мне подарили голосового ассистента Алису и у меня появилась новая идея отрывать дверь голосом, через Яндекс колонку.
И сегодня настал тот день, когда я взялся реализовать свою задумку.

Немного о том, как работает вызывная панель видео-домофона.


Вызывная панель соединена с монитором домофона при помощи 4-х проводов GND, +12 В, аудио и видео.
Если на вызывной панели, провод Audio замкнуть через резистор 100 Ом на GND, то раздастся сигнал вызова. А если на провод Audio подать напряжение +12 В, то сработает реле открытия электромагнитного замка.

На изображении ниже показана схема соединения вызывной панели с домофоном.



Если для подключения вызывной панели к монитору, у Вас используется специальный домофонный кабель, то он подключается как правило по следующей инструкции:

GND экранирующая оплетка
+12 В красный провод
Аудио синий провод
Видео центральная жила коаксиального кабеля



Схема


Из схемы видно, что для подключения устройства на Ардуино к домофону, потребуется подсоединить всего 2 провода. Для коммутации этих проводов я использовал то, что у меня было под рукой. Вместо реле можно использовать ключ на N-P-N транзисторе или оптроне PC817.

ИК приемник я применил, первый попавшийся мне на глаза, который я когда-то выпаял из старого телевизора и который пролежал у меня на полке в хламе очень много лет.


Используемые компоненты


Ардуино Нано
Модуль реле
ИК приемник 38 кГц
Провода Dupont

Вместо Arduino nano можно применить любой другой микроконтроллер из линейки ардуино. Я же использовал Ардуино нано потому, что у меня их достаточно много.

Исходник для Arduino


Код достаточно простой и понятный.
Для получения и сохранения кода нажатой кнопки, нужно перевести контроллер Ардуино в режим добавления кнопки пульта. Потребуется установить перемычку на выводы D2 и GND и нажать кнопку сброса на Arduino, после чего на плате контроллера засветится системный светодиод и контроллер будет ожидать нажатия кнопки на пульте.

Рекомендую использовать пульт от телевизора, чтобы кроме голосового управления можно было открыть дверь с ПДУ, не вставая с дивана. На пульте лучше всего выбрать кнопку, которой редко пользуетесь, как правило это четыре цветных кнопки, предназначенные для телетекста. После получения кодовой посылки Ардуино весело подмигнет светодиодом и снова перейдет в режим ожидания.

Можно нажимать кнопки сколько угодно, но Arduino запомнит только последнее нажатие. Чтобы выйти из режима запоминания кода, достаточно удалить перемычку и нажать на микроконтроллере кнопку Reset.

Код для Ардуино
#include <IRremote.h>
#include <EEPROM.h>

//#define TOLERANCE 35 // процент допустимого отклонения принимаемого сигнала
#define IR_RECEIVE_PIN 11 // Вход для подключения ИК приемника
#define RELAY_PIN 12 // Выход для управления реле
#define SET_PIN 2 // Вход для перевода в режим программирования пульта

IRrecv irrecv(IR_RECEIVE_PIN);
decode_results results;

void setup()
{
irrecv.enableIRIn(); //запустить ожидание нажатия кнопки на пульте
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
pinMode(SET_PIN, INPUT_PULLUP); //D10 конфигурируем на вход, для режима запоминания кода
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
// Serial.begin(115200);

while(!digitalRead(SET_PIN)) //если пины D2 и GND замкнуты то заходим в режим запоминания ИК кода
{
set_command();
}
}

void loop()
{
if (irrecv.decode(&results)) //если был принят код с пульта
{
if(LoadEEPROM()==results.value) //если код совпадает с сохраненным (ir_command==results.value)LoadEEPROM();
{
digitalWrite(RELAY_PIN, HIGH); //включить реле
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
digitalWrite(LED_BUILTIN, LOW);
digitalWrite(RELAY_PIN, LOW); //Выключить реле
}
irrecv.resume(); //запустить ожидание нажатия кнопки на пульте
}
}

void set_command() //режим запоминания кода пульта ДУ
{
digitalWrite(LED_BUILTIN, HIGH);
if (irrecv.decode(&results))
{
digitalWrite(LED_BUILTIN, LOW);
SaveEEPROM(results.value); //сохраняем полученый код кнопки ПДУ в EEPROM
irrecv.resume(); //запустить ожидание нажатия с пульта
}
delay(100);
}

void SaveEEPROM(unsigned long ir_code) // записываем полученый код кнопки ПДУ в EEPROM
{
EEPROM.write(0, ir_code & 0xFF);
EEPROM.write(1, (ir_code & 0xFF00) >> 8);
EEPROM.write(2, (ir_code & 0xFF0000) >> 16);
EEPROM.write(3, (ir_code & 0xFF000000) >> 24);
}

unsigned long LoadEEPROM() // считываем код кнопки ПДУ из EEPROM
{
byte val = EEPROM.read(3);
unsigned long ir_code=val;
val = EEPROM.read(2);
ir_code= (ir_code << 8) | val;
val = EEPROM.read(1);
ir_code= (ir_code << 8) | val;
val = EEPROM.read(0);
ir_code= (ir_code << 8) | val;
return ir_code;
}

При публичном размещении, выложенного мной выше кода указывайте, пожалуйста, ссылку на первоисточник.

Подключение к Яндекс.Станции Алиса


Для подключения к умной колонке понадобится Умный пульт Яндекс.

Не обязательно его покупать у Российского поисковика и партнеров, пульт можно купить на Алиэкспресс немного дешевле. Но разница не настолько большая, чтобы играть в лотерею, покупая пульт у китайцев. Рассказывать, как подключить пульт к станции, я не буду, так как в интернете очень много подробных инструкций на эту тему, Вы без труда сможете их найти у того же Яндекса. Я только расскажу как настроить взаимодействие Яндекс.Станции с Ардуино открывалкой.
Для этого нужно зайти приложение Яндекс.Браузер Все сервисы Устройства Управление устройствами Пульт Добавить устройство Настроить вручную вводим название Дверь Добавить команду вводим название голосовой команды Открой берем пульт от любой бытовой техники, направляем его на Яндекс.пульт и нажимаем требуемую кнопку. После того, как синий светодиод на Я.пульте погас колонка готова к выполнению этой команды. Теперь можно проверять, произносим фразу Алиса открой дверь, она, немного подумав, выполнит Ваш приказ.

Заключение


Использование Яндекс пульта в умном доме позволит Вам управлять любой бытовой техникой, в состав которой входит ПДУ. А так же достаточно легко, собрав простейшую схему на Arduino интегрировать управление любыми другими устройствами, не имеющих ПДУ. Это просто, надежно и не требует подключения этих устройств к интернету.

Если Вам понравилась моя статья можете подписаться на мой канал, чтобы не пропустить следующую публикацию.

Если у Вас есть вопросы, то можете их задать в комментариях.
Подробнее..

Голосовой ассистент на Python (Виталий alfa 2.0)

14.01.2021 20:16:39 | Автор: admin

Привет хабр! Меня зовут Глеб Пряхин, мне 14 лет, я написал голосового ассистента на python 3 и скомпилировал его в exe.

(Ссылка на скомпилированный вариант)

Прошу протестировать помощника и позадавать ему вопросы,

если у вас появились вопросы или вы хотите написать в поддержку: в комментах под постом, или на эл. почту glebilic@gmail.com.


Приступим к коду! Для начала импортируем модули:

import pyttsx3import osimport timeimport datetimeimport speech_recognition as srimport randomimport webbrowserimport sounddevice as sd

Для добавления голосов скачиваем и устанавливаем RHvoice.

Теперь ассистент читает файл с кол-во просмотров и подгружает файл tts, где хранится нумер голоса. Переменная num123 = количеству просмотров, а tts1 = нумеру голоса в синтезаторе речи.

f = open("sp.txt", "r")num123 = f.read(1000)num123 = int(num123)f.closef = open("tts.txt", "r")tts1 = int(f.read(1))f.close()#синтез речиtts = pyttsx3.init()speak_engine = pyttsx3.init()voices = speak_engine.getProperty('voices')speak_engine.setProperty('voice', voices[tts1].id)

Простейшая шапка для программы:

os.system('cls' if os.name == 'nt' else 'clear')print("ВИТАЛИЙ 2.0 ALFA \nBy Глеб Пряхин\n2021 \n-загрузка...")

Теперь мы читаем файл name и понимаем, что ужас! Наш пациент, ой то есть клиент не зарегистрировался в системе! Вызываем форму регистрации:

f = open('name.txt', 'r')if f.read(1) == "":    os.system('cls' if os.name == 'nt' else 'clear')    tts.say("Добрый день, я Виталий, я здесь, что бы вывести ваше взаимодействие с компьютером на новый, продуктивный уровень. Давайте знакомится. Как вас зовут?")    tts.runAndWait()    r = sr.Recognizer()    with sr.Microphone(device_index = 1) as source:        print(' ')        r.adjust_for_ambient_noise(source, duration=0.5) #настройка посторонних шумов        print('...')        audio = r.listen(source)        print(' ')    try:        query = r.recognize_google(audio, language = 'ru-RU')        name = query.lower()        print(f'Вы сказали: {query.lower()}')                except:        print('-')    tts.say("Вас зовут")    tts.runAndWait()    tts.say(name)    tts.runAndWait()    tts.say("Подтвердите пожалуйста.")    tts.runAndWait()    r = sr.Recognizer()    with sr.Microphone(device_index = 1) as source:        print(' ')        r.adjust_for_ambient_noise(source, duration=0.5) #настройка посторонних шумов        print('...')        audio = r.listen(source)        print(' ')    try:        query = r.recognize_google(audio, language = 'ru-RU')        ver = query.lower()        print(f'Вы сказали: {query.lower()}')                except:        print('-')    if "да" in ver or "подтверждаю" in ver:        f = open('name.txt', 'w')        f.write(name.title())        f.close()        tts.say("Готово! Теперь давайте поболтаем!")        tts.runAndWait()        else:        tts.say("напишите свое имя на клавиатуре")        tts.runAndWait()        name = input("Ваше имя: ")        tts.say("Готово! Теперь давайте поболтаем!")        tts.runAndWait()        f = open('name.txt', 'w')        f.write(name.title())        f.close()

Теперь, мы читаем кол-во просмотров, и понимаем что это "первый раз", поэтому начинаем читать инструктаж:

if num123 == 0:        tts.say("Но сначала я хочу научить основным командам: И так вот список моих команд:")        tts.runAndWait()        tts.say("Тут текст инструктажа")        tts.runAndWait()

Подготавливаем программу ко входу в центральный цикл:

#тут мы добавляем просмотр к счетчику просмотровf = open("sp.txt", "w")num123 = num123 + 1num123 = str(num123)num123 = f.write(num123)f.close#а тут читаем имя и создаем рандомное числоf = open('name.txt', 'r')name = f.read(10)r = random.randint(1,10)

В прошлом блоке мы сгенерировали рандомное число и занесли его в переменную r, теперь создадим elif`ки и зададим переменные cont, они понадобятся нам позже:

cont = ""if r == 1:    tts.say("Добрый день")    tts.runAndWait()    tts.say(name)    tts.runAndWait()    tts.say("Как дела?")    tts.runAndWait()elif r == 2:    tts.say("Привет")    tts.runAndWait()    tts.say(name)    tts.runAndWait()    tts.say("Чем могу помочь?")    tts.runAndWait()elif r == 3:    tts.say("Привет привет")    tts.runAndWait()    tts.say(name)    tts.runAndWait()    tts.say("Чем займемся?")    tts.runAndWait()elif r == 4:    tts.say("Добрый день")    tts.runAndWait()    tts.say(name)    tts.runAndWait()    tts.say("Хотите открою почту?")    tts.runAndWait()    cont = ("почта")elif r == 5:    tts.say("Добрый день")    tts.runAndWait()    tts.say(name)    tts.runAndWait()    tts.say("Открыть ютуб?")    tts.runAndWait()    cont = "ютуб"elif r == 6:    tts.say("Привет")    tts.runAndWait()    tts.say(name)    tts.runAndWait()    tts.say("Посмотрим кино?")    tts.runAndWait()    cont = "кино"elif r == 7:    tts.say("Добрый день")    tts.runAndWait()    tts.say(name)    tts.runAndWait()    tts.say("Что хотите узнать?")    tts.runAndWait()elif r == 8:    tts.say("Приветики")    tts.runAndWait()    tts.say(name)    tts.runAndWait()    tts.say("Хотите почитать последние новости?")    tts.runAndWait()    cont = "новости"elif r == 9:    tts.say("Добрый день")    tts.runAndWait()    tts.say(name)    tts.runAndWait()    tts.say("Где вы были?")    tts.runAndWait()elif r == 10:    tts.say("Добрый день")    tts.runAndWait()    tts.say(name)    tts.runAndWait()    tts.say("Как дела?")    tts.runAndWait()

Входим в цикл:

while True:    cikl = cikl + 1    ca = 0    ra = random.randint(1,10)    an = ""    #распознание    r = sr.Recognizer()    with sr.Microphone(device_index = 1) as source:        print(' ')        r.adjust_for_ambient_noise(source, duration=0.5) #настройка посторонних шумов        print('...')        audio = r.listen(source)        print(' ')    try:        query = r.recognize_google(audio, language = 'ru-RU')        an = query.lower()        print(f'Вы сказали: {query.lower()}')                except:        print('-')

И создадим первую команду "да", помните переменную cont? Так вот она отличает ответ "да" на вопрос "открыть ютуб?", и "да" на вопрос "Включить новости?", если контекста нет, то он просто ответит стандартным ответом.

 #да    if "да" in an and len(an) == 2 or "давай" in an or "почему-бы и нет" in an:        ca = 1        if cont == "почта":            f = open('email.txt', 'r')            if f.read(1) == "":                tts.say("Я совсем забыл, на каком сервисе зарегистрирована ваша почта! Пожайлуста выберете на экране нужную.")                tts.runAndWait()                a = 1                while True:                    v = input("Вставьте ссылку для почтового сервиса.")                    f = open('email.txt', 'w')                    if "https" in v:                        web = v                        f.write(web)                        f.close()                        break            tts.say("открываю почту")            f = open('email.txt', 'r')            web = f.read(97)            f.close()            tts.runAndWait()            webbrowser.open(web)                elif cont == "ютуб":            tts.say("Хорошо, включаю его")            tts.runAndWait()            webbrowser.open('https://www.youtube.com/')        elif cont == "кино":            tts.say("Давайте подберем что нибудь на око")            tts.runAndWait()            webbrowser.open('https://okko.tv/')        elif cont == "новости":            tts.say("Открываю евроньюс!")            tts.runAndWait()            webbrowser.open('https://www.youtube.com/watch?v=E3rH3KdVWcc')                elif cont == "ютубпр":            tts.say("Вот, надеюсь вам понравится")            tts.runAndWait()            webbrowser.open('https://www.youtube.com/channel/UCy0uukwm4dOSFCGyfp8g2sw')        else:            tts.say("Это очень хорошо.")            tts.runAndWait()

Теперь перейдем к интернет командам. Я приведу по 1 примеру на каждый их вид:

Супер простая команда открывающая один сайт:

elif "вк " in an or "вконтакте" in an:        ca = 1        tts.say("Включаю вконтакте")        tts.runAndWait()        webbrowser.open("https:/vk.com")

Команда, которая выполняет поиск по сайту:

elif "найди в интернете" in an:        ca = 1        tts.say("Выполняю поиск по запросу")        tts.runAndWait()        tts.say(an[an.find("ете")+3:])        tts.runAndWait()        sear = an[an.find("ете")+3:]        webbrowser.open("https://www.google.com/search?q=" + sear)

Команда открывающая сайт, который сохранен в файл, и может изменятся:

elif "почт" in an:        ca = 1        f = open('email.txt', 'r')        if f.read(1) == "":            tts.say("Я совсем забыл, на каком сервисе зарегистрирована ваша почта! Пожайлуста выберете на экране нужную.")            tts.runAndWait()            a = 1            while True:                v = input("Вставьте ссылку для почтового сервиса.")                f = open('email.txt', 'w')                if "https" in v:                    web = v                    f.write(web)                    f.close()                    break

Далее перейдем к командам для компа:

Команда на выполнение команды в командной строке:

elif "если я скажу это" in an:        ca = 1        os.system('то помощник выполнит эту команду через командную строку')        tts.say("И скажет это")        tts.runAndWait()        tts.say(name) #а потом имя произнесет.        tts.runAndWait()

Команда на выключение компа:

 elif "выключи компьютер" in an or "заверши работу" in an:        ca = 1        tts.say("Досвидания")        tts.runAndWait()        tts.say(name)        tts.runAndWait()        tts.say("До новых встреч. Идет завершение работы.")        tts.runAndWait()        os.system('cls' if os.name == 'nt' else 'clear')        print("Выключение через 10 секунд.")        time.sleep(1)        os.system('cls' if os.name == 'nt' else 'clear')        print("Выключение через 09 секунд.")        time.sleep(1)        os.system('cls' if os.name == 'nt' else 'clear')        print("Выключение через 08 секунд.")        time.sleep(1)        os.system('cls' if os.name == 'nt' else 'clear')        print("Выключение через 07 секунд.")        time.sleep(1)        os.system('cls' if os.name == 'nt' else 'clear')        print("Выключение через 06 секунд.")        time.sleep(1)        os.system('cls' if os.name == 'nt' else 'clear')        print("Выключение через 05 секунд.")        time.sleep(1)        os.system('cls' if os.name == 'nt' else 'clear')        print("Выключение через 04 секунд.")        time.sleep(1)        os.system('cls' if os.name == 'nt' else 'clear')        print("Выключение через 03 секунд.")        time.sleep(1)        os.system('cls' if os.name == 'nt' else 'clear')        print("Выключение через 02 секунд.")        time.sleep(1)        os.system('cls' if os.name == 'nt' else 'clear')        print("Выключение через 01 секунд.")        time.sleep(1)        os.system('cls' if os.name == 'nt' else 'clear')        print("Выключение...")        time.sleep(1)        os.system('shutdown -s')

Заметки. Ассистент умеет хранить заметки, вот какой код работает для этого:

#память        elif "запомни" in an or "напомни" in an:        ca = 1        f = open("z1.txt", "a")        if an[len("запомни"):] == "":            tts.say("Заметка не может быть пустой! Если хотите создать новую, скажите запомни и то что вы хотите сохранить.")            tts.runAndWait()            print("Ошибка! Вы пытаетесь создать пустую заметку!")        else:            tts.say("Я запомнил, что бы прочитать эту заметку скажите, что ты помнишь?")            tts.runAndWait()            an45 = an[len("запомни"):] + ","            f.write(an45)            f.close()    elif "помн" in an:        ca = 1        f = open("z1.txt", "r")        if f.read(1) == "":            tts.say("Похоже у вас еще нет заметок. Если хотите создать новую, скажите запомни и то что вы хотите сохранить.")            tts.runAndWait()        else:            st = f.read()            print(st)            tts.say("И так вот что я помню:")            tts.runAndWait()            tts.say(st)            tts.runAndWait()            tts.say("Если хотите их удалить, скажите удалить все заметки.")            tts.runAndWait()            f.close()    elif "удалить все заметки" in an or "удали все заметки" in an:        ca = 1        print("Вы уверены?")        tts.say("Вы хотите удалить все заметки? Подтвердите пожайлуста.")        tts.runAndWait()        #распознание        r = sr.Recognizer()        with sr.Microphone(device_index = 1) as source:            print(' ')            r.adjust_for_ambient_noise(source, duration=0.5) #настройка посторонних шумов            print('...')            audio = r.listen(source)            print(' ')        try:            query = r.recognize_google(audio, language = 'ru-RU')            an = query.lower()            print(f'Вы сказали: {query.lower()}')                    except:            print('-')        if an == "да" or "подтверждаю" in an or "утверждаю" in an:            ca = 1            print("Удаление...")            f = open("z1.txt", "w")            f.write("")            tts.say("Удаление заметок завершено.")            tts.runAndWait()        else:            print("Отмена...")            tts.say("Подтверждение не получено, заметки не удалены. Ну вы меня и напугали...")            tts.runAndWait()        f.close()

Еще пара полезных функций:

elif "настройки" in an:ca = 1        tts1 = input("введите номер голоса:")        f = open("tts.txt", "w")        f.write(tts1)        f.close() elif "замолчи" in an or "стоп" in an:        ca = 1        tts.say("Хорошо, микрофон выключен. Для продолжения работы нажмите энтр")        tts.runAndWait()        an4925479864 = input("[ПАУЗА] Нажмите enter: ")        tts.say("Привет-привет, чем займемся?.")        tts.runAndWait()

Смол толк. У меня он может быть выключен, если коротко, то смол толк это "разговор ни о чем" типа "как дела".

elif "виталий активируй диалоги" in an:        ca = 1        tts.say("Возможность диалогов активирована, О чём поговорим?")        tts.runAndWait()        f = open('dialogset.txt', 'w')        f.write("1")        f.close()    elif "виталий выключи диалоги" in an:        ca = 1        tts.say("Возможность диалогов отключена.")        tts.runAndWait()        f = open('dialogset.txt', 'w')        f.write("0")        f.close()    f = open('dialogset.txt', 'r')    an4897987 = f.read(1)    f.close()        if an4897987 == "1":        rsm = random.randint(1,3)        if "привет" in an or "здрав" in an:            ca = 1            if rsm == 1:                tts.say("Привет, чем могу пом очь?.")                tts.runAndWait()            elif rsm == 2:                tts.say("Добрый день.")                tts.runAndWait()            elif rsm == 3:                tts.say("Хэлоу.")                tts.runAndWait()         #пример фразы смол толк`а        elif "в1" in an or "в2" in an:            ca = 1            if rsm == 1:                tts.say("1в ответа")                tts.runAndWait()            elif rsm == 2:                tts.say("2в ответа.")                tts.runAndWait()            elif rsm == 3:                tts.say("3в ответа")                tts.runAndWait()                elif "как" in an and "дел" in an:            ca = 1            if rsm == 1:                tts.say("Как сказала-бы Алиса, у меня всё хорошо, но немного одиноко, обращайтесь ко мне по-чаще.")                tts.runAndWait()            elif rsm == 2:                tts.say("У меня прекрасно! Заходил на официальный канал проекта. Там очень интересно. Хотите посмотреть?")                tts.runAndWait()                cont = "ютубпр"                cikl = 0            elif rsm == 3:                tts.say("У меня всё прекрасно! А у вас?")                tts.runAndWait()           elif "хорошо" in an or "прекрасно" in an:            ca = 1            if rsm == 1:                tts.say("Я рад за вас, чем займемся?")                tts.runAndWait()            elif rsm == 2:                tts.say("Я рад за вас, у меня тоже всё хорошо.")                tts.runAndWait()            elif rsm == 3:                tts.say("Я рад за вас.")                tts.runAndWait()

А если ошибка? Или, что бот будет делать в случае, если не найдет ответа? Вот что. Кстати ассистент понимает, что не выполнил за цикл ни одной команды, если переменная ca = 0.

if an == "":            print("")            ca = 1    if ca == 0:        print("ошибка")        if ra == 1 or ra ==2:            tts.say("Ну наверное...")            tts.runAndWait()        elif ra == 3 or ra == 4:            tts.say("Даже не знаю.")            tts.runAndWait()        elif ra == 5 or ra == 6:            tts.say("Незнаю что на это ответить.")            tts.runAndWait()        elif ra == 7 or ra == 8:            tts.say("Я вас не то что бы понял, но по смыслу понял")            tts.runAndWait()        elif ra == 9 or ra == 10:            tts.say("Наверное я вас не правильно понял.")            tts.runAndWait()

Осталось только "обнулить", нет не этого, а переменный, что бы не было повторных сработок:

    an = ""    if cikl == 2:        cikl = 0        cont = ""

Вот и весь мой код, если будете использовать, то, пожалуйста, укажите ссылку на этот пост в коде или интерфейсе.

Вот ссылка на готовую и скомпилированную версию.

Жду ваших советов, идей и критики в комментариях под постом и на почте: glebilic@gmail.com.

Пока!

Подробнее..

Голосовой ассистент Виталий (школьный проект)

26.03.2021 14:15:31 | Автор: admin

Предостережение

Данный пост создан исключительно для получения отзывов у специалистов, поэтому смело минусуйте его, дабы не засорять ленту школьными проектами.

Также не советую использовать пост как гайд, так как я сам учусь и собираю отзывы и советы от знающих людей.

Введение

Меня зовут Глеб (8 кл) и я задался целью сделать хорошую открывалку/закрывалку и немного говорилку для windows, вообщем голосового ассистента на python.

На момент написания поста ассистент имеет версию alfa 4.0 и непозицианирует себя как серьезный продукт или не дай бог конкурента Алисе или Siri.

Для ассистента был по-быстрому накидан сайт, где можно скачать exe или исходник на питоне, который вероятно вам и интересен. Гитхаб тоже в наличии.

КОД

Так как я уже прикреплял гитхаб, предлагаю с акцентировать внимание на интересных, спорных или непонятных для меня моментах.

РАСПОЗНОВАНИЕ РЕЧИ

Для работы разпозновалки я выбрал speech recognition и в итоге был реализован такой код(сборная солянка из видеоуроков):

import speech_recognition as sr#кортеж с предлжениями, каждую итерацию цикла ассистент дает рандомное предложение (Скажите что-нибудь например "открой браузер")recomend = ("Открой браузер", "Найди в интернете стихи А. Пушкина.", "Как дела?", "Что ты умеешь?", "Запомни код от домофона 495 544.", "Найди на ютубе котиков.")#распознование (и не просите, в функцию не добавлю так, как оно все-равно нужно только раз за итерацию цикла)    rec1 = len(recomend) - 1    rec2 = recomend[random.randint(0, rec1)]    print('-------------------')    r = sr.Recognizer()    with sr.Microphone() as source:    print("Скажите что нибудь, например:", rec2)    r.pause_threshold = 1    #r.adjust_for_ambient_noise(source, duration=1)    audio = r.listen(source)    try:    #разпознаное сохраняется в переменную an (answer)      an = r.recognize_google(audio, language="ru-RU").lower()    print("Вы сказали: " + an)    except sr.UnknownValueError:        t = "Я вас не слышу, говорите громче!"        print("Сбой системы распознования речи. ")

Очень прошу в комментарии покидать более качественные аналоги speech recognition.

СИНТЕЗ РЕЧИ

Для синтеза речи я выбрал голос vokolizer, а также библиотеку pyttsx3. В коде это выглядит так:

import pyttsx3#Настройка голоса, индекс голоса читаем из файла.f = open("tts.txt", "r")tts1 = int(f.read(1))f.close()text = ""tts = pyttsx3.init()speak_engine = pyttsx3.init()voices = speak_engine.getProperty('voices')speak_engine.setProperty('voice', voices[tts1].id)#функция синтезы речиdef run():    tts.say(t)    tts.runAndWait()    print("Виталий:", t)    #пример запросаt = "Привет мир"run()

ПОДБОР ФРАЗ ДЛЯ КРАСИВОГО SMALLTALK

Тут я решил сделать возможность быстрого изменения фраз, поэтому сделал такой алгоритм:

import os#читаем файл smalltalk и делаем 2 списка: 1 - с ключевыми словами, 2 - с ответами ассистентаf = open("smalltalk.txt", "r", encoding="utf-8")smalltalkdialog = f.read()asksmalltalk = smalltalkdialog[len("вопросы: "):smalltalkdialog.find(" | [конецстроки1]")].split(" | ")answersmalltalk = smalltalkdialog[smalltalkdialog.find("ответы: ") + len("ответы: "):smalltalkdialog.find(" | [конецстроки2]")].split(" | ")#подбор нужной фразыfor word in range(len(asksmalltalk)):    if asksmalltalk[word] in an:        t = answersmalltalk[word]        run()        break

Тут тоже нужен ваш совет: подскажите пожалуйста более эфективный способ искать фразы.

К Dialog Flove у меня непреязнь. Личная.

ОТКРТИЕ ПРОГРАММ, САЙТОВ И ПОИСК В ИНТЕРНЕТЕ

import webbrowser#переменная error сообщает о том, нашла-ли программа ответ на фразу пользователя, если да, то error = 0while условный True:    #поиск    elif "найди" in an:        error = 0        if "в интернете" in an:            t = "Начинаю поиск в интернете" + an[an.find("ете")+3:]            run()            sear = an[an.find("ете")+3:]            webbrowser.open("https://www.google.com/search?q=" + sear)        elif "youtube" in an:            sear = an[an.find("be")+2:]            t = "Начинаю поиск в ютубе " + sear            run()            webbrowser.open("https://www.youtube.com/results?search_query=" + sear)        else:            t = "Вы дали мало данных, скажите найди в интернете, либо найди в ютубе и ваш вопрос."            run()        continue    #функция на закрытие Тут мы берем 2 кортежа, в кортеже "listprogram" у нас ключевые слова, а в "listprogram2" команды.    elif "закрой" in an:        listprogram = ("steam", "skype", "браузер")        listprogram2 = ("TASKKILL /IM steam.exe", "TASKKILL /IM skype.exe", "TASKKILL /IM chrome.exe")        for net in range(len(listprogram)):            if listprogram[net] in an:                program = listprogram2[net]                os.system(program)                os.system('cls' if os.name == 'nt' else 'clear')                t = "Закрываю " + listprogram[net]                 run()                error = 0        continue    #синтезатор речи    elif "текст" in an:        error = 0        t = "Вставьте сюда текст, который надо синтезировать. в конце текста напишите команду стопсинтез"        run()        t = ""        while True:            t = t + " " + str(input("Вставьте сюда текст > "))            if "стопсинтез" in t:                break                t = t[:t.find("стопсинтез")]        run()             #интернет Тут мы берем 2 кортежа, в кортеже "fordefweb" у нас ключевые слова, а в "fordefweb" ссылки.    fordefweb = ("youtube", "вконтакте", "браузер", "google", "новости", "окко", "хабр", "facebook", "wifmedia", "свой сайт")    fordefweb2 = ("https://www.youtube.com/", "https:/vk.com", "https://www.google.ru/", "https://www.google.ru/", "https://lenta.ru/", "https://okko.tv/", "http://personeltest.ru/aways/habr.com/ru/feed/", "https://www.facebook.com/", "https://wifmedia.com/", "http://vitaliy.renderforestsites.com")    for net in range(len(fordefweb)):        if fordefweb[net] in an:            web = fordefweb2[net]            runweb()            error = 0    #программы Тут мы берем 2 кортежа, в кортеже "listprogram" у нас ключевые слова, а в "listprogram2" команды.    listprogram = ("проводник", "skype")    listprogram2 = ("explorer.exe", "start skype.exe")    for net in range(len(listprogram)):        if listprogram[net] in an:            program = listprogram2[net]            os.system(program)            t = "Открываю " + listprogram[net]             run()            error = 0

Опять-же не могу найти ничего действенее elif, но в этой версии и хотя-бы меньше.

ОСТАЛЬНОЕ

Напоследок хочу похвастатся возможностью ассистента запоминать имя пользователя и хранить заметки, эти функции можно найти в полном коде проекта на гитхаб.

Материаллы

САЙТ (просто дешевая одностраничка на renderforest)

ГИТХАБ

демонстрационный ролик

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru