示例#1
0
def systemctl(ctx: click.Context, option: str):
    click.secho(f'Service "{option}", please wait', fg='yellow')

    commons.waitAnimation()
    commons.sshCmd(f'sudo systemctl {option} ProjectAlice')
    commons.printSuccess('Done!')
    commons.returnToMainMenu(ctx, pause=True)
示例#2
0
def upgradeSystem(ctx: click.Context):
    click.secho('Upgrading device\'s system, please wait', fg='yellow')

    commons.waitAnimation()
    commons.sshCmd('sudo apt-get update && sudo apt-get dist-upgrade -y')
    commons.printSuccess('Device upgraded!')
    ctx.invoke(reboot)
示例#3
0
def updateSystem(ctx: click.Context):
    click.secho('Updating device\'s system, please wait', fg='yellow')

    commons.waitAnimation()
    commons.sshCmd('sudo apt-get update && sudo apt-get upgrade -y')
    commons.printSuccess('Device updated!')
    commons.returnToMainMenu(ctx, pause=True)
示例#4
0
def reportBug(ctx: click.Context):
    click.secho('Enabling inbuilt bug reporter', fg='yellow')

    commons.waitAnimation()
    commons.sshCmd('touch ~/ProjectAlice/alice.bugreport')
    click.secho('Restarting Alice', fg='yellow')
    commons.sshCmd('sudo systemctl restart ProjectAlice')

    commons.printSuccess(
        'Bug reporter enabled and Alice restart. As soon as a fatal error occurs and/or she is stopped, the session report will be posted to Github!'
    )
    commons.returnToMainMenu(ctx, pause=True)
示例#5
0
def displayLogs(ctx: click.Context, file: str):
    try:
        commons.sshCmd(f'tail -n 250 -f {file} & {{ read ; kill %1; }}')
    except:
        try:
            commons.SSH.exec_command('\r')
        except:
            address = commons.CONNECTED_TO
            ctx.invoke(commons.disconnect)
            if commons.tryReconnect(ctx, address):
                ctx.invoke(displayLogs, file)
            else:
                commons.printError('Connection to Alice lost')

    commons.returnToMainMenu(ctx)
示例#6
0
def reboot(ctx: click.Context, return_to_main_menu: bool = True):  # NOSONAR
    click.secho('Rebooting device, please wait', fg='yellow')

    commons.waitAnimation()
    commons.sshCmd('sudo reboot')
    address = commons.CONNECTED_TO
    ctx.invoke(commons.disconnect)
    rebooted = commons.tryReconnect(ctx, address)

    if not rebooted:
        commons.printError('Failed rebooting device')
    else:
        commons.printSuccess('Device rebooted!')

    if return_to_main_menu:
        commons.returnToMainMenu(ctx, pause=True)
示例#7
0
def uninstallSoundDevice(ctx: click.Context, device: str, return_to_main_menu: bool = True):  # NOSONAR
	click.secho('Uninstalling audio hardware', fg='yellow')
	commons.waitAnimation()
	if not device:
		device = getDeviceName()
		if not device:
			return

	if device.lower() in {'respeaker2', 'respeaker4', 'respeaker4miclineararray', 'respeaker6micarray'}:
		result = sshCmdWithReturn('test -d ~/seeed-voicecard/ && echo "1"')[0].readline()
		if result:
			sshCmd('cd ~/seeed-voicecard/ && sudo ./uninstall.sh')
			sshCmd('sudo rm -rf ~/seeed-voicecard/')
			ctx.invoke(reboot, return_to_main_menu=return_to_main_menu)
			commons.printSuccess('Sound device uninstalled!')

	if return_to_main_menu:
		commons.returnToMainMenu(ctx, pause=True)
示例#8
0
def changeHostname(ctx: click.Context, hostname: str):
    click.secho('Changing device\'s hostname', fg='yellow')

    if not hostname:
        hostname = inquirer.text(message='Enter new device name',
                                 default='ProjectAlice',
                                 validate=lambda name: commons.
                                 validateHostname(name) is not None).execute()

    commons.waitAnimation()
    commons.sshCmd(f"sudo hostnamectl set-hostname '{hostname}'")
    ctx.invoke(reboot, ctx, return_to_main_menu=False)

    commons.waitAnimation()
    stdout, stderr = commons.sshCmdWithReturn('hostname')
    if stdout.readline().lower().strip() == hostname.lower().strip():
        commons.printSuccess('Device name changed!')
    else:
        commons.printError('Failed changing device name...')

    commons.returnToMainMenu(ctx, pause=True)
示例#9
0
def disableRespeakerLeds(ctx: click.Context):
    click.echo('Turning off Respeaker always on leds')
    commons.waitAnimation()
    click.echo('Make sure we have pip')
    commons.sshCmd('sudo apt-get install python3-pip -y')
    click.echo('Install pixel ring our savior')
    commons.sshCmd(
        'sudo pip3 install pixel_ring'
    )  # sudo is required here, that's bad, but we uninstall directly after
    click.echo('Testing the leds and turning off')
    commons.sshCmd('pixel_ring_check', hide=True)
    time.sleep(3)
    click.echo('Uninstall pixel ring as we don\'t need it anymore')
    commons.sshCmd('sudo pip3 uninstall pixel_ring -y')
    commons.stopAnimation()
    commons.printSuccess('Should be done!')
    commons.returnToMainMenu(ctx, pause=True)
示例#10
0
def installSoundDevice(ctx: click.Context, device: str):
	click.secho('Installing audio hardware', fg='yellow')
	commons.waitAnimation()
	if not device:
		device = getDeviceName()
		if not device:
			return

	ctx.invoke(uninstallSoundDevice, device=device, return_to_main_menu=False)
	commons.waitAnimation()
	sshCmd('sudo apt-get install git -y')
	if device.lower() in {'respeaker2', 'respeaker4', 'respeaker4miclineararray', 'respeaker6micarray'}:
		sshCmd('git clone https://github.com/HinTak/seeed-voicecard.git ~/seeed-voicecard/')
		sshCmd('git -C ~/seeed-voicecard/ checkout v5.9 && git -C ~/seeed-voicecard/ pull')
		sshCmd('cd ~/seeed-voicecard/ && sudo ./install.sh')
		ctx.invoke(reboot, return_to_main_menu=False)
		commons.printSuccess('Sound device installed!')

	commons.returnToMainMenu(ctx, pause=True)
示例#11
0
def updateAlice(ctx: click.Context):
    click.secho('Updating Alice, please wait', fg='yellow')

    commons.waitAnimation()
    commons.sshCmd('sudo systemctl stop ProjectAlice')
    time.sleep(2)
    commons.sshCmd('rm ~/ProjectAlice/requirements.hash')
    commons.sshCmd('rm ~/ProjectAlice/sysrequirements.hash')
    commons.sshCmd('rm ~/ProjectAlice/pipuninstalls.hash')
    commons.sshCmd(
        'cd ~/ProjectAlice && git pull && git submodules foreach git pull')
    time.sleep(2)
    commons.sshCmd('sudo systemctl start ProjectAlice')
    commons.printSuccess('Alice updated!')
    commons.returnToMainMenu(ctx, pause=True)
示例#12
0
def soundTest(ctx: click.Context):
    commons.printInfo(
        'This will test both the recording and playback of your device')
    click.pause(
        'Press enter and read aloud: I am testing my sound input and output')
    commons.printInfo('Now recording...')
    commons.sshCmd('arecord /tmp/test.wav -d 3')
    time.sleep(3.5)
    commons.printInfo('Now playing...')
    commons.sshCmd('aplay /tmp/test.wav')
    time.sleep(3.5)

    confirm = inquirer.confirm(
        message='Did you hear yourself speaking through the device?',
        default=True).execute()

    if confirm:
        commons.printSuccess(
            'Great, so both your mic and speakers are working!')
    else:
        commons.printInfo(
            "Ok... Sorry about that... Let's try the audio output only")
        click.pause()
        commons.printInfo('Testing sound output...')
        commons.waitAnimation()
        commons.sshCmd('sudo aplay /usr/share/sounds/alsa/Front_Center.wav')
        commons.stopAnimation()
        confirm = inquirer.confirm(
            message=
            'Ok, I played it and you should have heard the common "front, center" sound test, did you hear it?',
            default=True).execute()

        if confirm:
            commons.printInfo(
                "Ok, so this means your audio output is fine, but your mic doesn't capture anything"
            )
            click.pause()
            commons.sshCmd('arecord -l')
            confirm = inquirer.confirm(
                message='Do you see your mic listed in the list above?',
                default=True).execute()

            if confirm:
                commons.printInfo(
                    'Mmmh, here some potential fixes:\n- Use "alsamixer" to raise the capture volume of your device.\n- Edit your "/etc/asound.conf" to set it up correctly.\n- Try reaching out on our Discord server, maybe others had the same issue?'
                )
            else:
                commons.printInfo(
                    'Mmmh, here some potential fixes:\n Edit your "/etc/asound.conf" to set it up correctly.\n- Try reaching out on our Discord server, maybe others had the same issue?'
                )
        else:
            commons.printInfo(
                "Ok, so this would mean the output doesn't work, and maybe the input works, but you can't hear the result..."
            )
            click.pause()
            commons.sshCmd('aplay -l')
            confirm = inquirer.confirm(
                message=
                'Do you see your audio output device listed in the list above?',
                default=True).execute()
            if confirm:
                commons.printInfo(
                    'Mmmh, here some potential fixes:\n- Use "alsamixer" to raise the output volume of your device.\n- Edit your "/etc/asound.conf" to set it up correctly.\n- Try reaching out on our Discord server, maybe others had the same issue?'
                )
            else:
                commons.printInfo(
                    'Mmmh, here some potential fixes:\n Edit your "/etc/asound.conf" to set it up correctly.\n- Try reaching out on our Discord server, maybe others had the same issue?'
                )

    commons.returnToMainMenu(ctx, pause=True)
示例#13
0
def installAlice(ctx: click.Context, force: bool):
	click.secho('\nInstalling Alice!', fg='yellow')

	result = sshCmdWithReturn('test -d ~/ProjectAlice/ && echo "1"')[0].readline()
	if result:
		if not force:
			commons.printError('Alice seems to already exist on that host')
			confirm = inquirer.confirm(
				message='Erase and reinstall?',
				default=False
			).execute()

			if confirm:
				commons.returnToMainMenu(ctx)
				return

		sshCmd('sudo systemctl stop ProjectAlice')
		sshCmd('sudo rm -rf ~/ProjectAlice')

	adminPinCode = inquirer.secret(
		message='Enter an admin pin code. It must be made of 4 characters, all digits only. (default: 1234)',
		default='1234',
		validate=lambda code: code.isdigit() and int(code) < 10000,
		invalid_message='Pin must be 4 numbers',
		transformer=lambda _: commons.HIDDEN
	).execute()

	mqttHost = inquirer.text(
		message='Mqtt hostname',
		default='localhost',
		validate=EmptyInputValidator(commons.NO_EMPTY)
	).execute()

	mqttPort = inquirer.number(
		message='Mqtt port',
		default=1883,
		validate=EmptyInputValidator(commons.NO_EMPTY)
	).execute()

	activeLanguage = inquirer.select(
		message='What language should Alice be using?',
		default='en',
		choices=[
			Choice('en', name='English'),
			Choice('de', name='German'),
			Choice('fr', name='French'),
			Choice('it', name='Italian'),
			Choice('pl', name='Polish'),
		]
	).execute()

	activeCountryCode = inquirer.select(
		message='Enter the country code to use.',
		default='EN',
		choices=commons.COUNTRY_CODES
	).execute()

	releaseType = inquirer.select(
		message='What releases do you want to receive? If you are unsure, leave this to Stable releases!',
		default='master',
		choices=[
			Choice('master', name='Stable releases'),
			Choice('rc', name='Release candidates'),
			Choice('beta', name='Beta releases'),
			Choice('alpha', name='Alpha releases')
		]
	).execute()

	audioDevice = inquirer.select(
		message='Select your audio hardware if listed',
		default='respeaker2',
		choices=[
			Choice('respeaker2', name='Respeaker 2 mics'),
			Choice('respeaker4', name='Respeaker 4 mic array'),
			Choice('respeaker4MicLinear', name='Respeaker 4 mic linear array'),
			Choice('respeaker6', name='Respeaker 6 mic array'),
			Choice('respeaker7', name='Respeaker 7'),
			Choice('respeakerCoreV2', name='Respeaker Core version 2'),
			Choice('googleAIY', name='Google AIY'),
			Choice('googleAIY2', name='Google AIY 2'),
			Choice('matrixCreator', name='Matrix Creator'),
			Choice('matrixVoice', name='Matrix Voice'),
			Choice('ps3eye', name='PS3 Eye'),
			Choice('jabra410', name='Jabra 410'),
			Choice(None)
		]
	).execute()

	soundInstalled = inquirer.confirm(
		message='Did you already install your sound hardware using Alice CLI or confirmed it to be working?',
		default=False
	).execute()

	installHLC = inquirer.confirm(
		message='Do you want to install HLC? HLC can pilot leds such as the ones on Respeakers to provide visual feedback.',
		default=False
	).execute()

	advancedConfigs = inquirer.confirm(
		message='Do you want to set more advanced configs? If you do, DO NOT ABORT IN THE MIDDLE!',
		default=False
	).execute()

	asr = 'coqui'
	tts = 'pico'
	awsAccessKey = ''
	awsSecretKey = ''
	googleServiceFile = ''
	shortReplies = False
	devMode = False
	githubUsername = ''
	githubToken = ''
	enableDataStoring = True
	skillAutoUpdate = True

	if advancedConfigs:
		asr = inquirer.select(
			message='Select the ASR engine you want to use',
			default='coqui',
			choices=[
				Choice('coqui', name='Coqui'),
				Choice('snips', name='Snips (English only!)'),
				Choice('google', name='Google (Online!)'),
				Choice('deepspeech', name='Deepspeech'),
				Choice('pocketsphinx', name='PocketSphinx')
			]
		).execute()

		tts = inquirer.select(
			message='Select the TTS engine you want to use',
			default='pico',
			choices=[
				Choice('pico', name='Coqui'),
				Choice('mycroft', name='Mycroft'),
				Choice('amazon', name='Amazon'),
				Choice('google', name='Google'),
				Choice('watson', name='Watson')
			]
		).execute()

		if tts == 'amazon':
			awsAccessKey = inquirer.secret(
				message='Enter your AWS access key',
				validate=EmptyInputValidator(commons.NO_EMPTY),
				transformer=lambda _: commons.HIDDEN
			).execute()

			awsSecretKey = inquirer.secret(
				message='Enter your AWS secret key',
				validate=EmptyInputValidator(commons.NO_EMPTY),
				transformer=lambda _: commons.HIDDEN
			).execute()

		if tts == 'google' or asr == 'google':
			googleServiceFile = inquirer.filepath(
				message='Enter your Google service file path',
				default='~/',
				validate=PathValidator(is_file=True, message='Input is not a file')
			).execute()

		shortReplies = inquirer.confirm(
			message='Do you want Alice to use short replies?',
			default=False
		).execute()

		devMode = inquirer.confirm(
			message='Do you want to activate the developer mode?',
			default=False
		).execute()

		if devMode:
			githubUsername = inquirer.text(
				message='Enter your Github username. This is required for Dev Mode.',
				validate=EmptyInputValidator(commons.NO_EMPTY)
			).execute()

			githubToken = inquirer.secret(
				message='Enter your Github access token. This is required for Dev Mode.',
				validate=EmptyInputValidator(commons.NO_EMPTY),
				transformer=lambda _: commons.HIDDEN
			).execute()

		enableDataStoring = inquirer.confirm(
			message='Enable telemetry data storing?',
			default=True
		).execute()

		skillAutoUpdate = inquirer.confirm(
			message='Enable skill auto update?',
			default=True
		).execute()

	commons.waitAnimation()
	confFile = Path(Path.home(), '.pacli/projectalice.yaml')
	confFile.parent.mkdir(parents=True, exist_ok=True)

	updateSource = commons.getUpdateSource(releaseType)

	try:
		with requests.get(url=f'https://raw.githubusercontent.com/project-alice-assistant/ProjectAlice/{updateSource}/ProjectAlice.yaml', stream=True) as r:
			r.raise_for_status()
			with confFile.open('wb') as fp:
				for chunk in r.iter_content(chunk_size=8192):
					if chunk:
						fp.write(chunk)
	except Exception as e:
		commons.printError(f'Failed downloading ProjectAlice.yaml {e}')
		commons.returnToMainMenu(ctx, pause=True)

	with confFile.open(mode='r') as f:
		try:
			confs = yaml.safe_load(f)
		except yaml.YAMLError as e:
			commons.printError(f'Failed reading projectalice.yaml {e}')
			commons.returnToMainMenu(ctx, pause=True)

	confs['adminPinCode'] = str(int(adminPinCode)).zfill(4)
	confs['mqttHost'] = mqttHost
	confs['mqttPort'] = int(mqttPort)
	confs['activeLanguage'] = activeLanguage
	confs['activeCountryCode'] = activeCountryCode
	confs['useHLC'] = installHLC
	confs['aliceUpdateChannel'] = releaseType
	confs['skillsUpdateChannel'] = releaseType
	confs['ttsLanguage'] = f'{activeLanguage}-{activeCountryCode}'

	if soundInstalled:
		confs['installSound'] = False
		if audioDevice:
			confs['audioHardware'][audioDevice] = True
	else:
		confs['installSound'] = True

	confs['asr'] = asr
	confs['awsAccessKey'] = awsAccessKey
	confs['awsSecretKey'] = awsSecretKey
	confs['tts'] = tts
	confs['shortReplies'] = shortReplies
	confs['devMode'] = devMode
	confs['githubUsername'] = githubUsername
	confs['githubToken'] = githubToken
	confs['enableDataStoring'] = enableDataStoring
	confs['skillAutoUpdate'] = skillAutoUpdate

	if googleServiceFile and Path(googleServiceFile).exists():
		confs['googleServiceFile'] = Path(googleServiceFile).read_text()

	if asr == 'google':
		confs['keepASROffline'] = False

	if tts in ['amazon', 'google', 'watson']:
		confs['keepTTSOffline'] = False

	with confFile.open(mode='w') as f:
		yaml.dump(confs, f)

	commons.printSuccess('Generated ProjectAlice.yaml')

	commons.printInfo('Updating system')
	sshCmd('sudo apt-get update')
	sshCmd('sudo apt-get install git -y')
	sshCmd('git config --global user.name "Han Oter"')
	sshCmd('git config --global user.email "*****@*****.**"')

	commons.printInfo('Cloning Alice')
	sshCmd('git clone https://github.com/project-alice-assistant/ProjectAlice.git ~/ProjectAlice')

	sftp = commons.SSH.open_sftp()
	sftp.put(str(confFile), '/home/pi/ProjectAlice/ProjectAlice.yaml')
	sftp.close()

	sshCmd('sudo rm /boot/ProjectAlice.yaml')
	sshCmd('sudo cp ~/ProjectAlice/ProjectAlice.yaml /boot/ProjectAlice.yaml')

	commons.printInfo('Start install process')
	sshCmd('cd ~/ProjectAlice/ && python3 main.py')

	commons.printSuccess('Alice has completed the basic installation! She\'s now working further to complete the installation, let\'s see what she does!')
	ctx.invoke(systemLogs)