To remind my very-existing readership what the buttons look like so far, here’s a picture:
Extremely basic, pretty ugly, shows the functionality but that’s about it. I started with some CSS styling to make them look better and bring them closer together.
These classes were then added to the html on my template:
But I wasn’t quite done. Previously, I was using Bootstrap’s built-in text
classes to color the buttons different colors. I wanted to customize these colors more, and to do that I would need some new, custom classes. I created four, each with a different background color, as a proof of concept:
Then, I went back into my utils.py
folder to modify the code that aligned the classes. While there, I decided to do a quick refactor that I’d made a note of before. First, I created a dictionary that linked the names of the entities from spaCy’s system with teh class names that I had just created:
Here, "O"
is what spaCy uses to mark that a word is not an entity.
Next, I modified the color_entities_in_line()
function to use the dictionary instead of a bunch of if
statements (though I still needed a few). My code went from this:
… to this:
Cutting the length of the function in half (9 to 18 lines) and increasing the reusability (since I use the line_colors
dictionary in other areas).
So now the cleaning page was feeding through my custom class. Behold:
These colors aren’t perfect and I’m currently lacking any coherent sense of style (just like real life zing), but the important thing is that I have editable classes that are fed in through the spaCy program.
Note: At this point, I also realized that it would probably be better to train my spaCy model to recognize all numbers as one entity, rather than separating independent numbers from number/measurement pairs. It makes more sense to the reader that way. Just something to keep in mind for the future.
Adding Functionality
Now, it’s time to add the ability to change the classes. Recall that, previously, I had only used the toggleClass()
function of jQuery to hide the button when clicked on, more as a proof of concept than as any actual functionality. It was time to change that.
First, on a note of housekeeping, I separated the jQuery script from the HTML template (previously it had made its home in a <script>
tag at the bottom of the page), and put it into its own .js
file. A simple url_for()
command took care of the linking:
Now, onto the JavaScript itself. I thought for a bit of how best to implement the ability to change the color: do I click to cycle, or have a sort of palette where the desired category is selected to determine what category the click is set to. Ultimately, I decided on the former, because it seemed easier to implement and because it seemed easier to work on mobile devices (always a concern!). In the future, I might make the selection process a bit smarter (for example, if the selection is a number, prevent it from being selected as an “ingredient”), but for now the simpler option is what I’m going with.
Now, for the second quesiton: how to structure the code? Because I’m trying to improve my Think Like A Programmer (tm) skills, I wanted to come up with a more elegant solution than a simple set of if
statements. After some pondering, I decided to create a makeshift dictionary object, and link the button classes together so that they formed a loop:
Then, I wrote a small regex function to extract the button class (delineated with the “btn-“ prefix). This was necessary in case the button had other classes associated with it; I wanted to avoid redundancies. From there, I made two toggleClass()
calls to turn of the current class, and turn on whatever class was next in the dictionary cycle.
From there, I reviewed the ajax code that I’d written previously and found, to my delight, that it mostly would continue to work as written. I made a few minor changes to ensure that the right class was being passed to the request, but otherwise the routing and requests continued to work as expected:
I loaded everything up, and…
Oops. Something was wrong. The recipe lines weren’t getting parsed correctly. I checked back through my code and smacked my head when I realized that I’d forgotten a crucial part of the python refactor I’d done last time. The code was still using the old Bootstrap classes to parse the lines:
Those classes, of course, were nowhere to be seen. Luckily, this was an easy fix. I simply brought in the dictionary object I created earlier. Here’s the changed code:
This could probably still be refactored better in the future (hell, most of this can), but I’m satisfied for now.
And does it work? Oh yeah.
Here you can see a cleaned list, with the appropriate labels for each ingredient, amount, and measurement. Note in particular the “uncooked medium shrimp” line, which spaCy didn’t catch at all. Matters much less when the user can edit the response themselves.
And when submit is pressed, the list compiles properly:
(Kronk voice) Oh yeah, it’s all coming together.
Next Steps
- implement the same editing functionality on the main list page
- fix the “Add Line” button