Skip to content

Commit

Permalink
Merge pull request #12 from OpenVoiceOS/release-0.3.0a1
Browse files Browse the repository at this point in the history
Release 0.3.0a1
  • Loading branch information
JarbasAl authored Oct 17, 2024
2 parents 5821228 + d853a18 commit 4e2e91b
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 32 deletions.
11 changes: 7 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
# Changelog

## [0.2.1a1](https://github.com/OpenVoiceOS/ovos-skill-application-launcher/tree/0.2.1a1) (2024-10-15)
## [0.3.0a1](https://github.com/OpenVoiceOS/ovos-skill-application-launcher/tree/0.3.0a1) (2024-10-17)

[Full Changelog](https://github.com/OpenVoiceOS/ovos-skill-application-launcher/compare/V0.1.0...0.2.1a1)
[Full Changelog](https://github.com/OpenVoiceOS/ovos-skill-application-launcher/compare/V0.2.1...0.3.0a1)

**Merged pull requests:**

- fix:update\_requirements [\#9](https://github.com/OpenVoiceOS/ovos-skill-application-launcher/pull/9) ([JarbasAl](https://github.com/JarbasAl))
- Add Catalan translation [\#8](https://github.com/OpenVoiceOS/ovos-skill-application-launcher/pull/8) ([gitlocalize-app[bot]](https://github.com/apps/gitlocalize-app))
- feat:close application intent [\#11](https://github.com/OpenVoiceOS/ovos-skill-application-launcher/pull/11) ([JarbasAl](https://github.com/JarbasAl))

## [V0.2.1](https://github.com/OpenVoiceOS/ovos-skill-application-launcher/tree/V0.2.1) (2024-10-15)

[Full Changelog](https://github.com/OpenVoiceOS/ovos-skill-application-launcher/compare/0.2.1...V0.2.1)



Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Scanned folders:
## Examples
* "Open Volume Control"
* "Launch Firefox"
* "Close Firefox"

## Category
**Productivity**
Expand Down
98 changes: 79 additions & 19 deletions __init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import os
import shlex
import subprocess
import time
from os import listdir
from os.path import expanduser, isdir, join

import psutil
from langcodes import closest_match
from ovos_utils.bracket_expansion import expand_options
from ovos_utils.lang import standardize_lang_tag
from ovos_utils.log import LOG
from ovos_utils.parse import match_one
from ovos_utils.parse import match_one, fuzzy_match
from ovos_workshop.skills.fallback import FallbackSkill
from padacioso import IntentContainer

Expand Down Expand Up @@ -31,14 +38,20 @@ def initialize(self):
self.register_fallback(self.handle_fallback, 4)

def register_fallback_intents(self):
# TODO close application intent
intents = ["close", "launch"]
for lang in os.listdir(f"{self.root_dir}/locale"):
self.intent_matchers[lang] = IntentContainer()
launch = join(self.root_dir, "locale", self.lang, "launch.intent")
with open(launch) as f:
samples = [l for l in f.read().split("\n")
if not l.startswith("#") and l.strip()]
self.intent_matchers[lang].add_intent('launch', samples)
for intent_name in intents:
launch = join(self.root_dir, "locale", lang, f"{intent_name}.intent")
if not os.path.isfile(launch):
continue
lang = standardize_lang_tag(lang)
if lang not in self.intent_matchers:
self.intent_matchers[lang] = IntentContainer()
with open(launch) as f:
samples = [option for line in f.read().split("\n")
if not line.startswith("#") and line.strip()
for option in expand_options(line)]
self.intent_matchers[lang].add_intent(intent_name, samples)

def get_app_aliases(self):
apps = self.settings.get("user_commands") or {}
Expand All @@ -55,8 +68,8 @@ def get_app_aliases(self):
is_app = True
if os.path.isdir(path):
continue
with open(path) as f:
for l in f.read().split("\n"):
with open(path) as fi:
for l in fi.read().split("\n"):
if "Name=" in l:
name = l.split("Name=")[-1]
names.append(norm(name))
Expand Down Expand Up @@ -91,26 +104,73 @@ def get_app_aliases(self):
LOG.debug(f"found app {f} with aliases: {names}")
return apps

def launch_app(self, app: str) -> bool:
applist = self.get_app_aliases()
cmd, score = match_one(app.title(), applist)
if score >= self.settings.get("thresh", 0.85):
LOG.info(f"Matched application: {app} (command: {cmd})")
try:
# Launch the application in a new process without blocking
subprocess.Popen(shlex.split(cmd))
return True
except Exception as e:
LOG.error(f"Failed to launch {app}: {e}")
return False

def close_app(self, app: str) -> bool:
"""Close the application with the given name."""
applist = self.get_app_aliases()

cmd, _ = match_one(app.title(), applist)
cmd = cmd.split(" ")[0].split("/")[-1]
terminated = []

for proc in psutil.process_iter(['pid', 'name']):
score = fuzzy_match(cmd, proc.info['name'])
if score > 0.9:
LOG.debug(f"Matched '{app}' to {proc}")
try:
LOG.info(f"Terminating process: {proc.info['name']} (PID: {proc.info['pid']})")
proc.terminate() # or process.kill() to forcefully kill
terminated.append(proc.info['pid'])

except (psutil.NoSuchProcess, psutil.AccessDenied):
LOG.error(f"Failed to terminate {proc}")

if terminated:
LOG.debug(f"Terminated PIDs: {terminated}")
return True
return False

def handle_fallback(self, message):

utterance = message.data.get("utterance", "")
if self.lang not in self.intent_matchers:
best_lang, score = closest_match(self.lang, list(self.intent_matchers.keys()))

if score >= 10:
# unsupported lang
return False

res = self.intent_matchers[self.lang].calc_intent(utterance)
best_lang = standardize_lang_tag(best_lang)

res = self.intent_matchers[best_lang].calc_intent(utterance)

app = res.get('entities', {}).get("application")
if app:
applist = self.get_app_aliases()
cmd, score = match_one(app.title(), applist)
if score >= self.settings.get("thresh", 0.85):
LOG.info(f"Executing command: {cmd}")
os.system(cmd)
return True
if res["name"] == "launch":
return self.launch_app(app)
elif res["name"] == "close":
return self.close_app(app)


if __name__ == "__main__":
LOG.set_level("DEBUG")
from ovos_utils.fakebus import FakeBus
from ovos_bus_client.message import Message

s = ApplicationLauncherSkill(skill_id="fake.test", bus=FakeBus())
s.handle_fallback(Message("", {"utterance": "launch firefox"}))
s.handle_fallback(Message("", {"utterance": "abrir firefox", "lang": "pt-pt"}))
time.sleep(2)
# s.handle_fallback(Message("", {"utterance": "kill firefox"}))
time.sleep(2)
s.handle_fallback(Message("", {"utterance": "launch firefox", "lang": "en-UK"}))
5 changes: 5 additions & 0 deletions locale/en-us/close.intent
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
close {application}
terminate {application}
kill {application}
exit {application}
quit {application}
4 changes: 3 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
padacioso>=0.1.1
ovos-workshop>=0.0.15,<2.0.0
ovos-workshop>=0.0.15,<2.0.0
ovos-utils>=0.3.5
psutil
17 changes: 12 additions & 5 deletions translations/en-us/intents.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
{
"launch.intent": [
"launch {application}",
"open {application}",
"run {application}"
]
"launch.intent": [
"launch {application}",
"open {application}",
"run {application}"
],
"close.intent": [
"close {application}",
"terminate {application}",
"kill {application}",
"exit {application}",
"quit {application}"
]
}
6 changes: 3 additions & 3 deletions version.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# START_VERSION_BLOCK
VERSION_MAJOR = 0
VERSION_MINOR = 2
VERSION_BUILD = 1
VERSION_ALPHA = 0
VERSION_MINOR = 3
VERSION_BUILD = 0
VERSION_ALPHA = 1
# END_VERSION_BLOCK

0 comments on commit 4e2e91b

Please sign in to comment.