Jump to content

Do Slower Part of the Script Later in Script Filter


Recommended Posts

I have a sadly slow script written in Python. The result from the slow part of it is not always needed so I'm thinking if I can modify the script so that when the user type the argument, the script will return a quick result immediately, and start to do the calculations for the slow part, if it finishes before user starts typing again, the full result is shown; otherwise stop the calculation and show the quick result for the new argument. 

I have separated the fast and slow part of the script, used two 

sys.stdout.write()

statements, but it seem that Alfred doesn't accept the result from the quick part unless the whole script is finished -- aka when the slow part is done too!

 

Does anyone have the same need or question, is this possible in Script Filter or in other actions? 

Any help will be appreciated!

Link to comment

You may want to have a look at the "rerun" key.

 

Quote

Rerunning script filters automatically

Scripts can be set to re-run automatically after an interval using the rerun key with a value from 0.1 to 5.0 seconds. The script will only be re-run if the script filter is still active and the user hasn't changed the state of the filter by typing and triggering a re-run.

{
    "rerun": 1,
    "items": [
        ...
    ]
}

See the built in "Advanced Script Filter" getting started guide for more info, and to see this in practice.

 

On the first run, return the results that are loaded quickly, immediately rerun, then execute the slow script and return the results. If the Alfred window is still open, the first results will be replaced. (You could pass a variable that acts as a token to indicate that the slow script should be run now).

Link to comment
14 hours ago, zeitlings said:

You may want to have a look at the "rerun" key.

 

 

On the first run, return the results that are loaded quickly, immediately rerun, then execute the slow script and return the results. If the Alfred window is still open, the first results will be replaced. (You could pass a variable that acts as a token to indicate that the slow script should be run now).

Thanks for the reply! I missed the feature that the variable field that is passed back into a rerun. I made it… kind of work. But I'm confused how to tell between a state that the user just typed (need to run the fast part), and the state the slow part needs to run after the result from the fast part is shown to the user… I tried to keep a record of what the user has typed and based on that, but that didn't work, the script still waits until the slow part is done as the user types. 

Here's my sample script:

import json
import os
import sys
import uuid
import time


def get_query() -> str:
    """Join the arguments into a query string."""
    return " ".join(sys.argv[1:])


def provide_history():
    """Provide the history of the user."""
    prompt = get_query()

    if os.getenv("uuid_") is None or (os.getenv("former_user_prompt") == os.getenv("user_prompt") and os.getenv("user_prompt") != prompt):
        uuid_ = str(uuid.uuid1())

        pre_history_dict = {
            "variables": {
                "user_prompt": prompt,
            },
            "rerun": 0.1,
            "items": [
                {
                    "type": "default",
                    "title": prompt,
                    "subtitle": f"Talk to {prompt} 💬".strip(),
                    "arg": [uuid_, prompt],
                    "autocomplete": prompt,
                }
            ],
        }

        pre_history_dict["variables"]["uuid_"] = uuid_
        pre_history_dict["variables"]["former_user_prompt"] = os.getenv("user_prompt")

        sys.stdout.write(json.dumps(pre_history_dict))
    else:
    #slow part
        time.sleep(1)
        response_dict = {
            "variables": {
                "user_prompt": prompt,
            },
            "items": [
                {
                    "type": "default",
                    "title": "slow part",
                    "subtitle": f"Talk to {prompt} 💬".strip(),
                    "arg": [os.getenv("uuid_"), prompt],
                    "autocomplete": prompt,
                }
            ],
        }
        response_dict["variables"]["former_user_prompt"] = os.getenv("user_prompt")

        sys.stdout.write(json.dumps(response_dict))




provide_history()

And this is the behavior setting of the script. image.thumb.png.dce99614c4092404a5c973c232aac439.png

 

I'm expecting it to terminate the slow part every time I after started typing. The logic for the tracking user input part seemed to have worked, but Alfred won't terminate the script when a new input has arrived and he's doing the slow part despite this behavior setting. 

Link to comment

This seems to do the trick:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import json
import os
import sys
import uuid
import time

def get_query() -> str:
    """Join the arguments into a query string."""
    return " ".join(sys.argv[1:])

def provide_history():
    """Provide the history of the user."""
    prompt = get_query()

    if os.getenv("did_rerun") is None or (prompt != os.getenv("former_user_prompt")):
        uuid_ = str(uuid.uuid1())
        pre_history_dict = {
            "variables": {
                "former_user_prompt": prompt,
                "did_rerun": True
            },
            "rerun": 0.1,
            "items": [
                {
                    "type": "default",
                    "title": prompt,
                    "subtitle": f"Talk to {prompt} 💬".strip(),
                    "arg": [uuid_, prompt],
                    "autocomplete": "prompt",
                }
            ],
        }
        sys.stdout.write(json.dumps(pre_history_dict))
    else:
    #slow part
        time.sleep(1)
        response_dict = {
            "variables": {
                "former_user_prompt": prompt,
            },
            "items": [
                {
                    "type": "default",
                    "title": "slow part",
                    "subtitle": f"Talk to {prompt} 💬".strip(),
                    "arg": [os.getenv("uuid_"), prompt],
                    "autocomplete": prompt,
                }
            ],
        }
        sys.stdout.write(json.dumps(response_dict))

provide_history()

 

image.thumb.png.39edc592fd30818b7dd50d8af7c2eed6.png

Edited by zeitlings
run behaviour
Link to comment

Thank you so much for modifying my code! 👍👍 Than's exactly how I would like it to work!

 

Looked at my original code and found out that the quick part does not trigger a rerun of itself to let user_prompt and former_user_prompt sync since os.getenv("former_user_prompt") == os.getenv("user_prompt") is no longer true. 

 

Your solution is way better! Thanks in advance!

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...