https://github.com/Acreom/quickadd Skip to content Toggle navigation Sign up * Product + Actions Automate any workflow + Packages Host and manage packages + Security Find and fix vulnerabilities + Codespaces Instant dev environments + Copilot Write better code with AI + Code review Manage code changes + Issues Plan and track work + Discussions Collaborate outside of code + Explore + All features + Documentation + GitHub Skills + Blog * Solutions + For + Enterprise + Teams + Startups + Compare all + By Solution + CI/CD & Automation + DevOps + DevSecOps + Case Studies + Customer Stories + Resources * Open Source + GitHub Sponsors Fund open source developers + The ReadME Project GitHub community articles + Repositories + Topics + Trending + Collections * Pricing [ ] * # In this repository All GitHub | Jump to | * No suggested jump to results * # In this repository All GitHub | Jump to | * # In this organization All GitHub | Jump to | * # In this repository All GitHub | Jump to | Sign in Sign up {{ message }} Acreom / quickadd Public forked from comtravo/ctparse * Notifications * Fork 16 * Star 76 Parse natural language time and date expressions in python acreom.com License MIT license 76 stars 16 forks Star Notifications * Code * Pull requests 0 * Actions * Projects 0 * Security * Insights More * Code * Pull requests * Actions * Projects * Security * Insights Acreom/quickadd This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository. master Switch branches/tags [ ] Branches Tags Could not load branches Nothing to show {{ refName }} default View all branches Could not load tags Nothing to show {{ refName }} default View all tags Name already in use A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch? Cancel Create 7 branches 51 tags Code * Local * Codespaces * Clone HTTPS GitHub CLI [https://github.com/A] Use Git or checkout with SVN using the web URL. [gh repo clone Acreom] Work fast with our official CLI. Learn more. * Open with GitHub Desktop * Download ZIP Sign In Required Please sign in to use Codespaces. Launching GitHub Desktop If nothing happens, download GitHub Desktop and try again. Launching GitHub Desktop If nothing happens, download GitHub Desktop and try again. Launching Xcode If nothing happens, download Xcode and try again. Launching Visual Studio Code Your codespace will open once ready. There was a problem preparing your codespace, please try again. This branch is 124 commits ahead, 12 commits behind comtravo:master. Latest commit @inferense inferense Update README.rst ... 539b860 Nov 22, 2022 Update README.rst 539b860 Git stats * 352 commits Files Permalink Failed to load latest commit information. Type Name Latest commit message Commit time .github ctparse datasets docs scripts tests .codecov.yml .editorconfig .gitignore .pyup.yml .travis.yml AUTHORS.rst CONTRIBUTING.rst HISTORY.rst LICENSE MANIFEST.in Makefile README.rst mypy.ini requirements.txt requirements_dev.txt setup.cfg setup.py tox.ini View code [ ] quickadd Installation Main upgrades include: Base Capabilities Ctparse Example Latent time Implementation Rules Technical Background Credits README.rst quickadd quickadd is a natural language date & time parser written in python. It builds on top of ctparse and is an actively maintained fork. Installation With pip install -e git+https://github.com/Acreom/quickadd.git#egg= quickadd or run python setup.py install in the root directory after forking. Main upgrades include: Recurring events r = ctparse("beer daily 4pm") r.resolution Recurring[5-14]{daily 1 2021-05-09 16:00 (X/X) 2021-05-09 16:00 (X/X)} r = ctparse("beer every thursday 4") r.resolution Recurring[5-21]{weekly 1 2021-04-15 16:00 (X/X) 2021-04-15 16:00 (X/X)} r = ctparse("beer every friday 9-5") r.resolution Recurring[5-21]{weekly 1 2021-05-14 09:00 (X/X) 2021-05-14 17:00 (X/X)} r = ctparse("beer september 24 / beer every 24.9") r.resolution Recurring[5-21]{YEARLY 1 2021-09-24 (X/X) 2021-09-24 (X/X)} r = ctparse("beer thursdays 3pm and wednesdays 4pm") r.resolution RecurringArray[5-37]{ Recurring instance: weekly 1 2021-05-13 15:00 (X/X) 2021-05-13 15:00 (X/X) Recurring instance: weekly 1 2021-05-12 16:00 (X/X) 2021-05-12 16:00 (X/X) } r = ctparse("beer 9pm weekdays") r.resolution RecurringArray[5-17]{ Recurring instance: weekly 1 2021-05-10 21:00 (X/X) 2021-05-10 21:00 (X/X) Recurring instance: weekly 1 2021-05-11 21:00 (X/X) 2021-05-11 21:00 (X/X) Recurring instance: weekly 1 2021-05-12 21:00 (X/X) 2021-05-12 21:00 (X/X) Recurring instance: weekly 1 2021-05-13 21:00 (X/X) 2021-05-13 21:00 (X/X) Recurring instance: weekly 1 2021-05-14 21:00 (X/X) 2021-05-14 21:00 (X/X)} rrule support r.resolution.to_rrule() Out[4]: 'RRULE:FREQ=DAILY;COUNT=1' Subject extraction r = ctparse("beers and burgers friday 8pm-9pm") r.subject Out[2]: 'beers and burgers' Label extraction r = ctparse("beers and burgers friday 8pm-9pm #fun") r.labels Out[3]: ['fun'] PM bias r = ctparse("fix the issue tmrw 2") r.resolution Time[14-20]{2022-11-23 14:00 (X/X)} r = ctparse("fix the issue tmrw 2", pm_bias=False) r.resolution Time[14-20]{2022-11-23 02:00 (X/X)} Rules for ambigious natural language expressions r = ctparse("code 9-5") r.resolution Interval[0-0]{2022-11-23 09:00 (X/X) - 2022-11-23 17:00 (X/X)} US/EU date format r = ctparse("fix the issue 5.3") r.resolution Time[14-17]{2023-03-05 X:X (X/X)} r = ctparse("fix the issue 5.3", date_format="US") r.resolution Time[14-17]{2023-05-03 X:X (X/X)} Rule combinations r = ctparse("beer in 3 days 4pm") r.resolution Time[5-18]{2021-05-12 16:00 (X/X)} r = ctparse("beer in 3 days 4pm every week") r.resolution Recurring[5-29]{weekly 1 2021-05-12 16:00 (X/X) 2021-05-12 16:00 (X/X)} r = ctparse("beer every friday 4-6:30pm") r.resolution Recurring[5-26]{WEEKLY 1 2022-11-25 16:00 (X/X) 2022-11-25 18:30 (X/X)} + performance improvements Base Capabilities Time "beer thursday 4" Time[5-15]{2021-05-13 16:00 (X/X)} Interval "beer 4-6" Interval[0-0]{2021-05-09 16:00 (X/X) - 2021-05-09 18:00 (X/X)} Duration "beer in 4 hours" Duration[5-15]{4 hours} Ctparse The package ctparse is a pure python package to parse time expressions from natural language (i.e. strings). In many ways it builds on similar concepts as Facebook's duckling package (https:// github.com/facebook/duckling). However, for the time being it only targets times and only German and English text. In principle ctparse can be used to detect time expressions in a text, however its main use case is the semantic interpretation of such expressions. Detecting time expressions in the first place can - to our experience - be done more efficiently (and precisely) using e.g. CRFs or other models targeted at this specific task. ctparse is designed with the use case in mind where interpretation of time expressions is done under the following assumptions: * All expressions are relative to some pre-defined reference times * Unless explicitly specified in the time expression, valid resolutions are in the future relative to the reference time (i.e. 12.5. will be the next 12th of May, but 12.5.2012 should correctly resolve to the 12th of May 2012). * If in doubt, resolutions in the near future are more likely than resolutions in the far future (not implemented yet, but any resolution more than i.e. 3 month in the future is extremely unlikely). The specific comtravo use-case is resolving time expressions in booking requests which almost always refer to some point in time within the next 4-8 weeks. ctparse currently is language agnostic and supports German and English expressions. This might get an extension in the future. The main reason is that in real world communication more often than not people write in one language (their business language) but use constructs to express times that are based on their mother tongue and /or what they believe to be the way to express dates in the target language. This leads to text in German with English time expressions and vice-versa. Using a language detection upfront on the complete original text is for obvious no solution - rather it would make the problem worse. Example from ctparse import ctparse from datetime import datetime # Set reference time ts = datetime(2018, 3, 12, 14, 30) ctparse('May 5th 2:30 in the afternoon', ts=ts) This should return a Time object represented as Time[0-29]{2018-05-05 14:30 (X/X)}, indicating that characters 0-29 were used in the resolution, that the resolved date time is the 5th of May 2018 at 14:30 and that this resolution is neither based on a day of week (first X) nor a part of day (second X). Latent time Normally, ctparse will anchor time expressions to the reference time. For example, when parsing the time expression 8:00 pm, ctparse will resolve the expression to 8 pm after the reference time as follows parse = ctparse("8:00 pm", ts=datetime(2020, 1, 1, 7, 0), latent_time=True) # default # parse.resolution -> Time(2020, 1, 1, 20, 00) This behavior can be customized using the option latent_time=False, which will return a time resolution not anchored to a particular date parse = ctparse("8:00 pm", ts=datetime(2020, 1, 1, 7, 0), latent_time=False) # parse.resolution -> Time(None, None, None, 20, 00) Implementation ctparse - as duckling - is a mixture of a rule and regular expression based system + some probabilistic modeling. In this sense it resembles a PCFG. Rules At the core ctparse is a collection of production rules over sequences of regular expressions and (intermediate) productions. Productions are either of type Time, Interval, Duration or Recurring and can have certain predicates (e.g. whether a Time is a part of day like 'afternoon'). A typical rule than looks like this: @rule(predicate('isDate'), dimension(Interval)) I.e. this rule is applicable when the intermediate production resulted in something that has a date, followed by something that is in interval (like e.g. in 'May 5th 9-10'). The actual production is a python function with the following signature: @rule(predicate('isDate'), dimension(Interval)) def ruleDateInterval(ts, d, i): """ param ts: datetime - the current refenrence time d: Time - a time that contains at least a full date i: Interval - some Interval """ if not (i.t_from.isTOD and i.t_to.isTOD): return None return Interval( t_from=Time(year=d.year, month=d.month, day=d.day, hour=i.t_from.hour, minute=i.t_from.minute), t_to=Time(year=d.year, month=d.month, day=d.day, hour=i.t_to.hour, minute=i.t_to.minute)) This production will return a new interval at the date of predicate ('isDate') spanning the time coded in dimension(Interval). If the latter does code for something else than a time of day (TOD), no production is returned, e.g. the rule matched but failed. Technical Background Some observations on the problem: * Each rule is a combination of regular expressions and productions. * Consequently, each production must originate in a sequence of regular expressions that must have matched (parts of) the text. * Hence, only subsequence of all regular expressions in all rules can lead to a successful production. To this end the algorithm proceeds as follows: 1. Input a string and a reference time 2. Find all matches of all regular expressions from all rules in the input strings. Each regular expression is assigned an identifier. 3. Find all distinct sequences of these matches where two matches do not overlap nor have a gap inbetween 4. To each such subsequence apply all rules at all possible positions until no further rules can be applied - in which case one solution is produced Obviously, not all sequences of matching expressions and not all sequences of rules applied on top lead to meaningful results. Here the PCFG kicks in: * Based on example data (corpus.py) a model is calibrated to predict how likely a production is to lead to a/the correct result. Instead of doing a breadth first search, the most promising productions are applied first. * Resolutions are produced until there are no more resolutions or a timeout is hit. * Based on the same model from all resolutions the highest scoring is returned. Credits This package was created with Cookiecutter and the audreyr/ cookiecutter-pypackage project template. About Parse natural language time and date expressions in python acreom.com Topics python nlp parser machine-learning python-library naive-bayes-classifier Resources Readme License MIT license Stars 76 stars Watchers 2 watching Forks 16 forks Releases 51 tags Packages 0 No packages published Languages * Python 99.1% * Makefile 0.9% Footer (c) 2022 GitHub, Inc. Footer navigation * Terms * Privacy * Security * Status * Docs * Contact GitHub * Pricing * API * Training * Blog * About You can't perform that action at this time. You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.