GJDutils 0.2.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gjdutils/__init__.py +12 -0
- gjdutils/audios.py +39 -0
- gjdutils/cacheing.py +237 -0
- gjdutils/cmd.py +149 -0
- gjdutils/colab.py +39 -0
- gjdutils/collections.py +36 -0
- gjdutils/decorators.py +34 -0
- gjdutils/dicts.py +216 -0
- gjdutils/dsci.py +202 -0
- gjdutils/dt.py +296 -0
- gjdutils/env.py +64 -0
- gjdutils/errors.py +12 -0
- gjdutils/files.py +140 -0
- gjdutils/functions.py +6 -0
- gjdutils/google_translate.py +80 -0
- gjdutils/hashing.py +32 -0
- gjdutils/html.py +87 -0
- gjdutils/indexing.py +97 -0
- gjdutils/iterfunc.py +99 -0
- gjdutils/jsons.py +70 -0
- gjdutils/lists.py +13 -0
- gjdutils/llm_utils.py +167 -0
- gjdutils/llms_claude.py +131 -0
- gjdutils/llms_openai.py +299 -0
- gjdutils/misc.py +30 -0
- gjdutils/num.py +77 -0
- gjdutils/obsolete/google_text_to_speech.py +46 -0
- gjdutils/obsolete/llms_obsolete.py +298 -0
- gjdutils/outloud_text_to_speech.py +230 -0
- gjdutils/prompt_templates.py +20 -0
- gjdutils/pypi_build.py +112 -0
- gjdutils/pytest_utils.py +24 -0
- gjdutils/rand.py +65 -0
- gjdutils/regex.py +78 -0
- gjdutils/requirements_dev.txt +2 -0
- gjdutils/runtime.py +19 -0
- gjdutils/sets.py +5 -0
- gjdutils/shell.py +69 -0
- gjdutils/sorteddict.py +34 -0
- gjdutils/stopwatch.py +79 -0
- gjdutils/strings.py +218 -0
- gjdutils/todo/convert_parquet.py +28 -0
- gjdutils/typ.py +37 -0
- gjdutils/voice_speechrecognition.py +29 -0
- gjdutils/web.py +68 -0
- gjdutils-0.2.2.dist-info/METADATA +101 -0
- gjdutils-0.2.2.dist-info/RECORD +49 -0
- gjdutils-0.2.2.dist-info/WHEEL +4 -0
- gjdutils-0.2.2.dist-info/licenses/LICENSE +21 -0
gjdutils/strings.py
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from six import string_types
|
|
3
|
+
from string import punctuation
|
|
4
|
+
import textwrap
|
|
5
|
+
from typing import Optional, Sequence, Union
|
|
6
|
+
|
|
7
|
+
PathOrStr = Union[str, Path]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def is_string(x):
|
|
11
|
+
"""
|
|
12
|
+
Based on https://stackoverflow.com/questions/11301138/how-to-check-if-variable-is-string-with-python-2-and-3-compatibility
|
|
13
|
+
"""
|
|
14
|
+
return isinstance(x, string_types)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def remove_punctuation(txt: str) -> str:
|
|
18
|
+
"""Removes characters that are in string.punctuation."""
|
|
19
|
+
return txt.translate(str.maketrans("", "", punctuation))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def remove_first_line(s):
|
|
23
|
+
return "\n".join(s.splitlines()[1:])
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def truncate_chars(s: str, n: Optional[int] = None):
|
|
27
|
+
"""
|
|
28
|
+
Truncate a string to N characters, appending '...' if truncated.
|
|
29
|
+
|
|
30
|
+
trunc('1234567890', 10) -> '1234567890'
|
|
31
|
+
trunc('12345678901', 10) -> '1234567890...'
|
|
32
|
+
"""
|
|
33
|
+
if not s:
|
|
34
|
+
return s
|
|
35
|
+
if n is None:
|
|
36
|
+
return s
|
|
37
|
+
return s[:n] + "..." if len(s) > n else s
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def truncate_words(txt: str, n: Optional[int] = None):
|
|
41
|
+
if n is None:
|
|
42
|
+
return txt
|
|
43
|
+
words = txt.split(" ")
|
|
44
|
+
return " ".join(words[:n])
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def longest_substring_multi(strs: Sequence[str]) -> str:
|
|
48
|
+
"""
|
|
49
|
+
Find the longest common substring for multiple strings in list DATA.
|
|
50
|
+
|
|
51
|
+
https://stackoverflow.com/questions/2892931/longest-common-substring-from-more-than-two-strings-python
|
|
52
|
+
"""
|
|
53
|
+
substr = ""
|
|
54
|
+
if len(strs) > 1 and len(strs[0]) > 0:
|
|
55
|
+
for i in range(len(strs[0])):
|
|
56
|
+
for j in range(len(strs[0]) - i + 1):
|
|
57
|
+
if j > len(substr) and all(strs[0][i : i + j] in x for x in strs):
|
|
58
|
+
substr = strs[0][i : i + j]
|
|
59
|
+
return substr
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def calc_proportion_longest_common_substring(descriptions: Sequence[str]) -> float:
|
|
63
|
+
# find length of longest string
|
|
64
|
+
longest = max([len(description) for description in descriptions])
|
|
65
|
+
if longest == 0:
|
|
66
|
+
return 0.0
|
|
67
|
+
|
|
68
|
+
if len(descriptions) == 2:
|
|
69
|
+
# TODO try this out instead (both behaviour and speed)
|
|
70
|
+
# return fwfuzz.partial_ratio(descriptions[0], descriptions[1]) / 100
|
|
71
|
+
# this would be faster, but I can't install pylcs on my machine
|
|
72
|
+
# len_substring = pylcs.lcs2(descriptions[0], descriptions[1])
|
|
73
|
+
# so fall back on the original implementation
|
|
74
|
+
len_substring = len(longest_substring_multi(descriptions))
|
|
75
|
+
else:
|
|
76
|
+
len_substring = len(longest_substring_multi(descriptions))
|
|
77
|
+
|
|
78
|
+
if len_substring <= 1:
|
|
79
|
+
# decided to count a single letter as a 0
|
|
80
|
+
return 0.0
|
|
81
|
+
val = len_substring / longest
|
|
82
|
+
assert 0 <= val <= 1
|
|
83
|
+
return val
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def jinja_get_template_variables(template: str) -> set[str]:
|
|
87
|
+
"""
|
|
88
|
+
Extract all variables expected by a Jinja2 template.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
template_string (str): The Jinja2 template string to analyze
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
set: A set of variable names found in the template
|
|
95
|
+
|
|
96
|
+
Example:
|
|
97
|
+
>>> template = "Hello {{ name }}! Your age is {{ age }}"
|
|
98
|
+
>>> get_template_variables(template)
|
|
99
|
+
{'name', 'age'}
|
|
100
|
+
"""
|
|
101
|
+
# https://claude.ai/chat/3a2e9e93-c9cd-4b19-8313-ef7640e5971f
|
|
102
|
+
from jinja2 import Environment, meta
|
|
103
|
+
|
|
104
|
+
env = Environment()
|
|
105
|
+
ast = env.parse(template)
|
|
106
|
+
variables = meta.find_undeclared_variables(ast)
|
|
107
|
+
return variables
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def jinja_render(
|
|
111
|
+
prompt_template: str,
|
|
112
|
+
context: dict,
|
|
113
|
+
filesystem_loader: Optional[PathOrStr] = None,
|
|
114
|
+
check_surplus_context: bool = True,
|
|
115
|
+
strip=True,
|
|
116
|
+
):
|
|
117
|
+
"""
|
|
118
|
+
Render a Jinja template with the given dictionary, e.g.
|
|
119
|
+
|
|
120
|
+
jinja_render("{{name}} is {{age}} years old", {'name': 'Bob', 'age': 42}) -> "Bob is 42 years old"
|
|
121
|
+
|
|
122
|
+
Will raise an error if CONTEXT is missing any variables.
|
|
123
|
+
"""
|
|
124
|
+
from jinja2 import Environment, FileSystemLoader, StrictUndefined, Template
|
|
125
|
+
|
|
126
|
+
loader = None if filesystem_loader is None else FileSystemLoader(filesystem_loader)
|
|
127
|
+
env = Environment(loader=loader, undefined=StrictUndefined)
|
|
128
|
+
template = env.from_string(prompt_template)
|
|
129
|
+
rendered = template.render(context)
|
|
130
|
+
if strip:
|
|
131
|
+
rendered = rendered.strip()
|
|
132
|
+
if check_surplus_context:
|
|
133
|
+
# should it be an error if we have been provided more keys in the context
|
|
134
|
+
# than are used in the template? e.g. this is useful for noticing when the
|
|
135
|
+
# template has e.g. {myvar} with single instead of double braces
|
|
136
|
+
jinja_variables = jinja_get_template_variables(prompt_template)
|
|
137
|
+
surplus_context = set(context.keys()) - jinja_variables
|
|
138
|
+
if surplus_context:
|
|
139
|
+
raise ValueError(f"Surplus context: {surplus_context}")
|
|
140
|
+
|
|
141
|
+
return rendered
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
# probably better off using slugify from the slugify package
|
|
145
|
+
# import codecs
|
|
146
|
+
# import translitcodec
|
|
147
|
+
# def slugify(text, delim=u'-'):
|
|
148
|
+
# """
|
|
149
|
+
# Generates an ASCII-only slug
|
|
150
|
+
|
|
151
|
+
# Based on http://flask.pocoo.org/snippets/5/
|
|
152
|
+
# """
|
|
153
|
+
# if not text or not text.strip():
|
|
154
|
+
# return ''
|
|
155
|
+
# _punct_re = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+')
|
|
156
|
+
# result = []
|
|
157
|
+
# for word in _punct_re.split(text.lower()):
|
|
158
|
+
# # https://pypi.org/project/translitcodec/
|
|
159
|
+
# word = codecs.encode(word, 'translit/long')
|
|
160
|
+
# if word:
|
|
161
|
+
# result.append(word)
|
|
162
|
+
# return str(delim.join(result))
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def display_compare_strings(s1, s2):
|
|
166
|
+
if len(s2) > len(s1):
|
|
167
|
+
# e.g. s1='abc', s2='abcd', => s2[3:], i.e. 'd'
|
|
168
|
+
print("Truncated: %s" % s2[len(s1) :])
|
|
169
|
+
print("\n".join(["%s %s" % (pair[0], pair[1]) for pair in zip(s1, s2)]))
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def wrap_indent(s: str, indent_level: int = 0, sep=" "):
|
|
173
|
+
spaces = sep * indent_level
|
|
174
|
+
return "\n".join(textwrap.wrap(s, initial_indent=spaces, subsequent_indent=spaces))
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def indent_without_wrap(s: str, indent_txt: Optional[str] = None):
|
|
178
|
+
if indent_txt is None:
|
|
179
|
+
indent_txt = " "
|
|
180
|
+
return (
|
|
181
|
+
textwrap.fill(s, initial_indent=indent_txt, subsequent_indent=indent_txt)
|
|
182
|
+
if s and isinstance(s, str)
|
|
183
|
+
else str(s)
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def append_fullstop(s: str):
|
|
188
|
+
"""
|
|
189
|
+
Appends a fullstop if there isn't already punctuation at the end of S.
|
|
190
|
+
"""
|
|
191
|
+
if not isinstance(s, str):
|
|
192
|
+
return ""
|
|
193
|
+
s_orig = s[:]
|
|
194
|
+
s = s.strip()
|
|
195
|
+
if not s:
|
|
196
|
+
return s
|
|
197
|
+
if s[-1] in punctuation:
|
|
198
|
+
return s
|
|
199
|
+
return f"{s}."
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def str_from_num(x):
|
|
203
|
+
# todo, find a better way of doing this, e.g.
|
|
204
|
+
# if isinstance(Iterable), recur. otherwise try str(x)
|
|
205
|
+
if x is None:
|
|
206
|
+
return str(x)
|
|
207
|
+
elif isinstance(x, (bool, np.bool_)):
|
|
208
|
+
return str(x)
|
|
209
|
+
elif isinstance(x, str):
|
|
210
|
+
return x
|
|
211
|
+
elif isinstance(x, (int, float)):
|
|
212
|
+
# return f"{x:.2f}"
|
|
213
|
+
return str(round(x * 100))
|
|
214
|
+
elif isinstance(x, (list, tuple)):
|
|
215
|
+
# e.g. [0.20,0.10,-5.00]
|
|
216
|
+
return "[" + ",".join([str_from_num(item) for item in x]) + "]" # type: ignore
|
|
217
|
+
else:
|
|
218
|
+
raise Exception(f"Unknown NUM_STR type: {type(x)}, {x}")
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# USAGE:
|
|
2
|
+
# python convert_parquet.py my_parquet_file.parquet
|
|
3
|
+
#
|
|
4
|
+
# based on https://chat.openai.com/c/ea3e9401-e7bb-4288-b270-83b0fb327abe
|
|
5
|
+
#
|
|
6
|
+
# pip install pandas openpyxl pyarrow
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
import pandas as pd
|
|
10
|
+
|
|
11
|
+
# Replace 'your_file.parquet' with the path to your Parquet file
|
|
12
|
+
# parquet_file = 'vary_amount_of_training_data__adult_sexual__aps.parquet'
|
|
13
|
+
parquet_file = sys.argv[1]
|
|
14
|
+
|
|
15
|
+
assert parquet_file.endswith(".parquet")
|
|
16
|
+
|
|
17
|
+
# Read the Parquet file
|
|
18
|
+
df = pd.read_parquet(parquet_file)
|
|
19
|
+
|
|
20
|
+
# Replace 'output_file.xlsx' with the desired output file name
|
|
21
|
+
output_file = parquet_file.replace('.parquet', '.xlsx')
|
|
22
|
+
|
|
23
|
+
# Write to an Excel file
|
|
24
|
+
df.to_excel(output_file, index=False)
|
|
25
|
+
|
|
26
|
+
print(f"Wrote to {output_file}")
|
|
27
|
+
|
|
28
|
+
|
gjdutils/typ.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from inspect import isfunction
|
|
2
|
+
|
|
3
|
+
# these are occasionally useful for if statements,
|
|
4
|
+
# though probably better to rely on type-hinting wherever possible
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def isint(f, tol=0.00000001):
|
|
8
|
+
"""
|
|
9
|
+
Takes in a float F, and checks that it's within TOL of floor(f).
|
|
10
|
+
"""
|
|
11
|
+
# we're casting to float before the comparison with TOL
|
|
12
|
+
# so that decimal Fs work
|
|
13
|
+
return abs(float(f) - int(f)) <= 0.00000001
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def isnum(n):
|
|
17
|
+
try:
|
|
18
|
+
float(n)
|
|
19
|
+
return True
|
|
20
|
+
except:
|
|
21
|
+
return False
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def is_same_sign(x1, x2):
|
|
25
|
+
if x1 > 0 and x2 > 0:
|
|
26
|
+
return True
|
|
27
|
+
if x1 < 0 and x2 < 0:
|
|
28
|
+
return True
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def isiterable(x):
|
|
32
|
+
"""
|
|
33
|
+
from http://stackoverflow.com/questions/1952464/in-python-how-do-i-determine-if-a-variable-is-iterable
|
|
34
|
+
"""
|
|
35
|
+
import collections
|
|
36
|
+
|
|
37
|
+
return isinstance(x, collections.Iterable)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# from https://github.com/Uberi/speech_recognition/blob/master/examples/microphone_recognition.py
|
|
2
|
+
|
|
3
|
+
#!/usr/bin/env python3
|
|
4
|
+
|
|
5
|
+
# NOTE: this example requires PyAudio because it uses the Microphone class
|
|
6
|
+
|
|
7
|
+
from typing import Optional
|
|
8
|
+
import speech_recognition as sr
|
|
9
|
+
from .env import get_env_var
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def recognise_speech(display: Optional[str], verbose: int = 0):
|
|
13
|
+
if display:
|
|
14
|
+
print(display, end="", flush=True)
|
|
15
|
+
# obtain audio from the microphone
|
|
16
|
+
r = sr.Recognizer()
|
|
17
|
+
with sr.Microphone() as source:
|
|
18
|
+
# print("Say something!")
|
|
19
|
+
audio = r.listen(source)
|
|
20
|
+
print("... PROCESSING")
|
|
21
|
+
openai_api_key = get_env_var("OPENAI_API_KEY")
|
|
22
|
+
text = r.recognize_whisper_api(audio, api_key=openai_api_key)
|
|
23
|
+
if verbose > 0:
|
|
24
|
+
print(text)
|
|
25
|
+
return text
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
if __name__ == "__main__":
|
|
29
|
+
recognise_speech("Say something!", verbose=1)
|
gjdutils/web.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from urllib import parse as urlparse
|
|
3
|
+
import webbrowser
|
|
4
|
+
|
|
5
|
+
from gjdutils.strings import PathOrStr
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def webbrowser_open(filen: PathOrStr, browser=None):
|
|
9
|
+
"""
|
|
10
|
+
For some reason, the default webbrowser.open() doesn't work for me, so you may want to set browser to 'chrome'
|
|
11
|
+
"""
|
|
12
|
+
# I had an issue where it refused to open a non .html file
|
|
13
|
+
assert filen.endswith(".html"), "File must end with .html"
|
|
14
|
+
if browser:
|
|
15
|
+
browser = webbrowser.get(browser)
|
|
16
|
+
else:
|
|
17
|
+
browser = webbrowser
|
|
18
|
+
full_filen = f"file://{Path.cwd() / filen}"
|
|
19
|
+
return browser.open(full_filen)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def trunc_url(url):
|
|
23
|
+
"""
|
|
24
|
+
e.g. 'http://www.guardian.co.uk/blah/ -> /blah
|
|
25
|
+
|
|
26
|
+
Based on dev/guardian/data/data/greg/sharedwisdom/sharedwisdom/models.py
|
|
27
|
+
"""
|
|
28
|
+
# URLPARSE returns ParseResult(scheme='http',
|
|
29
|
+
# netloc='memrise.com',
|
|
30
|
+
# path='/blah.png',
|
|
31
|
+
# params='',
|
|
32
|
+
# query='q1=x&q2=y',
|
|
33
|
+
# fragment='')
|
|
34
|
+
scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
|
|
35
|
+
# ditch the SCHEME and NETLOC
|
|
36
|
+
# PARAMS are an arcane part that comes after a semi-colon
|
|
37
|
+
return path # + params
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def validate_request_args(args, defaults):
|
|
41
|
+
"""
|
|
42
|
+
DEFAULTS = dict of allowed query parameters, with the keys
|
|
43
|
+
being the allowed query-string-parameter-keys and values
|
|
44
|
+
as their defaults.
|
|
45
|
+
"""
|
|
46
|
+
if args:
|
|
47
|
+
unexpecteds = set(args.keys()) - set(defaults.keys())
|
|
48
|
+
assert not unexpecteds, "Unexpected key(s): %s" % unexpecteds
|
|
49
|
+
# params = {key: args.get(key, default)
|
|
50
|
+
# for key, default in defaults.items()}
|
|
51
|
+
params = defaults | args
|
|
52
|
+
return params
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def query_string_from_dict(d):
|
|
56
|
+
return "?" + "&".join(["%s=%s" % (k, v) for k, v in d.items()])
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def params_from_request(request):
|
|
60
|
+
try:
|
|
61
|
+
if request.json:
|
|
62
|
+
params_in = request.json.get("params", {})
|
|
63
|
+
else:
|
|
64
|
+
params_in = dict(request.values)
|
|
65
|
+
return params_in
|
|
66
|
+
except:
|
|
67
|
+
print("Error in PARAMS_FROM_REQUEST")
|
|
68
|
+
return {}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: GJDutils
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: A collection of useful utility functions (basics, data science/AI, web development, etc)
|
|
5
|
+
Project-URL: Homepage, https://github.com/gregdetre/gjdutils
|
|
6
|
+
Project-URL: Repository, https://github.com/gregdetre/gjdutils
|
|
7
|
+
Author-email: Greg Detre <greg@gregdetre.com>
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Keywords: ai,data science,dates,llm,strings,utilities,web development
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Topic :: Utilities
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Requires-Dist: ipython
|
|
18
|
+
Requires-Dist: jinja2
|
|
19
|
+
Requires-Dist: pydantic
|
|
20
|
+
Requires-Dist: python-dotenv
|
|
21
|
+
Provides-Extra: all-no-dev
|
|
22
|
+
Requires-Dist: azure-cognitiveservices-speech; extra == 'all-no-dev'
|
|
23
|
+
Requires-Dist: bs4; extra == 'all-no-dev'
|
|
24
|
+
Requires-Dist: cachetools; extra == 'all-no-dev'
|
|
25
|
+
Requires-Dist: elevenlabs; extra == 'all-no-dev'
|
|
26
|
+
Requires-Dist: google-cloud-texttospeech; extra == 'all-no-dev'
|
|
27
|
+
Requires-Dist: google-cloud-translate; extra == 'all-no-dev'
|
|
28
|
+
Requires-Dist: humanize; extra == 'all-no-dev'
|
|
29
|
+
Requires-Dist: openai; extra == 'all-no-dev'
|
|
30
|
+
Requires-Dist: pendulum; extra == 'all-no-dev'
|
|
31
|
+
Requires-Dist: pillow; extra == 'all-no-dev'
|
|
32
|
+
Requires-Dist: playsound; extra == 'all-no-dev'
|
|
33
|
+
Requires-Dist: pygame; extra == 'all-no-dev'
|
|
34
|
+
Requires-Dist: python-vlc; extra == 'all-no-dev'
|
|
35
|
+
Requires-Dist: speechrecognition; extra == 'all-no-dev'
|
|
36
|
+
Provides-Extra: audio-lang
|
|
37
|
+
Requires-Dist: azure-cognitiveservices-speech; extra == 'audio-lang'
|
|
38
|
+
Requires-Dist: cachetools; extra == 'audio-lang'
|
|
39
|
+
Requires-Dist: elevenlabs; extra == 'audio-lang'
|
|
40
|
+
Requires-Dist: google-cloud-texttospeech; extra == 'audio-lang'
|
|
41
|
+
Requires-Dist: google-cloud-translate; extra == 'audio-lang'
|
|
42
|
+
Requires-Dist: playsound; extra == 'audio-lang'
|
|
43
|
+
Requires-Dist: pygame; extra == 'audio-lang'
|
|
44
|
+
Requires-Dist: python-vlc; extra == 'audio-lang'
|
|
45
|
+
Requires-Dist: speechrecognition; extra == 'audio-lang'
|
|
46
|
+
Provides-Extra: dev
|
|
47
|
+
Requires-Dist: black; extra == 'dev'
|
|
48
|
+
Requires-Dist: build; extra == 'dev'
|
|
49
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
50
|
+
Requires-Dist: rich; extra == 'dev'
|
|
51
|
+
Requires-Dist: twine; extra == 'dev'
|
|
52
|
+
Requires-Dist: typer; extra == 'dev'
|
|
53
|
+
Requires-Dist: wheel; extra == 'dev'
|
|
54
|
+
Provides-Extra: dt
|
|
55
|
+
Requires-Dist: humanize; extra == 'dt'
|
|
56
|
+
Requires-Dist: pendulum; extra == 'dt'
|
|
57
|
+
Provides-Extra: html-web
|
|
58
|
+
Requires-Dist: bs4; extra == 'html-web'
|
|
59
|
+
Provides-Extra: llm
|
|
60
|
+
Requires-Dist: cachetools; extra == 'llm'
|
|
61
|
+
Requires-Dist: openai; extra == 'llm'
|
|
62
|
+
Requires-Dist: pillow; extra == 'llm'
|
|
63
|
+
Description-Content-Type: text/markdown
|
|
64
|
+
|
|
65
|
+
# gjdutils
|
|
66
|
+
|
|
67
|
+
A collection of useful utility functions (strings, dates, data science/AI, web development, types, etc).
|
|
68
|
+
|
|
69
|
+
## Installation
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
pip install gjdutils
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
For optional features:
|
|
76
|
+
```bash
|
|
77
|
+
pip install "gjdutils[dt]" # Date/time utilities
|
|
78
|
+
pip install "gjdutils[llm]" # AI/LLM integrations
|
|
79
|
+
pip install "gjdutils[audio_lang]" # Speech/translation, language-related
|
|
80
|
+
pip install "gjdutils[html_web]" # Web scraping
|
|
81
|
+
pip install "gjdutils[dev]" # Development tools (for tweaking `gjdutils` itself, e.g. pytest)
|
|
82
|
+
|
|
83
|
+
# Install all optional dependencies at once (except `dev`, which is used for developing `gjdutils` itself)
|
|
84
|
+
pip install "gjdutils[all_no_dev]"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Development Setup
|
|
88
|
+
|
|
89
|
+
If you're developing `gjdutils` itself:
|
|
90
|
+
```bash
|
|
91
|
+
# From the gjdutils root directory
|
|
92
|
+
pip install -e ".[dev]" # Install in editable mode with development dependencies
|
|
93
|
+
pip install -e ".[all_no_dev]" # Install all optional dependencies (except dev)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Adding to requirements.txt
|
|
97
|
+
|
|
98
|
+
To add to your `requirements.txt` in editable mode, e.g. to install all optional dependencies:
|
|
99
|
+
```text
|
|
100
|
+
-e "git+https://github.com/gregdetre/gjdutils.git#egg=gjdutils[all_no_dev]"
|
|
101
|
+
```
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
gjdutils/__init__.py,sha256=1pOy87RwksWpLHdzHBxDuDahPd6SLs4m3QnJydClhI4,312
|
|
2
|
+
gjdutils/audios.py,sha256=gEk_frpyyYHus2HzsU0l6RQmtmBMaBr2V7HfvT3AWSI,1286
|
|
3
|
+
gjdutils/cacheing.py,sha256=rnUrYffWhOyp5ezTOoKBaeuSTN2cNVhbX0f3piLLb0A,7434
|
|
4
|
+
gjdutils/cmd.py,sha256=FBQEP36_rKtIJzA78ftjEH2ooP5XxlfqRLNAWMcrJVQ,4890
|
|
5
|
+
gjdutils/colab.py,sha256=yZsC73qKPOjtMvztJvZAYZDLD9l3bmW0v9jKyS0fS2E,836
|
|
6
|
+
gjdutils/collections.py,sha256=XL0QQitMD3H2mtaDpnM8ffyBVS05sICfhz15GETNRCE,1264
|
|
7
|
+
gjdutils/decorators.py,sha256=x48h-kL8JCgcKaGRZlRAstzWSyPVW73B-_jBkU1Vzmg,933
|
|
8
|
+
gjdutils/dicts.py,sha256=GjBO5CeJEuPD063w-RrYPIRdX-zyw0lrPH34ol4SW_I,5563
|
|
9
|
+
gjdutils/dsci.py,sha256=XOFIbZLjyr0vmhJDspfjpTZC1-sFSmkzRfkXqGG3HlA,6201
|
|
10
|
+
gjdutils/dt.py,sha256=PIb_OvXcUDH-uHLuKC8yjF3QvYWMiTutUk75Uc0aEA4,7826
|
|
11
|
+
gjdutils/env.py,sha256=WfA-FeCdhuVdQmsfwxWN7Z8Z4tnHB59T384yGFqPrP8,1909
|
|
12
|
+
gjdutils/errors.py,sha256=JWuQ0dhTevekQWdwIQg50M_KZTCIdZzC3fvPbGu8KxQ,224
|
|
13
|
+
gjdutils/files.py,sha256=2ssTJo8iZj4WwXm7-wCpSqO32q6dn9mHKdYNcj-orGk,4193
|
|
14
|
+
gjdutils/functions.py,sha256=FbCc9wm9HgY7LCuivINCs5JHyaItisWl-99VuZoluSk,140
|
|
15
|
+
gjdutils/google_translate.py,sha256=b7wd9GdS_8_nlSo2sZJFuZcFIg_lY72lGt9ue3isQdg,2486
|
|
16
|
+
gjdutils/hashing.py,sha256=109RcUUkn3jmOZpcbV-4AFcoU_oAJn3IrFzrCb-5-ms,990
|
|
17
|
+
gjdutils/html.py,sha256=etDpcBpUt71O-kZfBaA9v4_ePj5bxAl6h_L-NXrX92c,2971
|
|
18
|
+
gjdutils/indexing.py,sha256=ZptiB1ranTjlJo7HsL56KmyAmRyjZwIS4pJx7D2cf8g,3444
|
|
19
|
+
gjdutils/iterfunc.py,sha256=4vVJZ72I5-UhRUX6-gUoqzvUE0jjPyRugNQQYJQA-r4,2519
|
|
20
|
+
gjdutils/jsons.py,sha256=Qrl382B6tl2q9PsFyXFCVGo4G5Q9CuMBW528sGK-Iwk,1971
|
|
21
|
+
gjdutils/lists.py,sha256=fGBNtld-3CmFwgATxTGltIEcmsz2gauCZC_11xOKDr0,438
|
|
22
|
+
gjdutils/llm_utils.py,sha256=HfGadqTr7q9H0uN4ffHQWgY6n3tp3SRsoSr1aFilg_8,5671
|
|
23
|
+
gjdutils/llms_claude.py,sha256=eUjK6koob5KKmaB471z3fatd1tEVOmLmB8aT6uNvqAI,4107
|
|
24
|
+
gjdutils/llms_openai.py,sha256=CiGdomHfldFugS6fe2vv6phQbpyP9d9qsOfHC-4CvBU,10401
|
|
25
|
+
gjdutils/misc.py,sha256=BpJiuf1_czKp0hLy681yV04FgyBMF6nTYlht3hxtxI4,592
|
|
26
|
+
gjdutils/num.py,sha256=x5PD3WKvUKrtZl0kGaMqX-3Ex5Ar_Fa54eMU1mseejU,2196
|
|
27
|
+
gjdutils/outloud_text_to_speech.py,sha256=1xhQjQUsgqSKM7U-oiDSvgUaNVLPP5qvYIDPQq6EoQo,8020
|
|
28
|
+
gjdutils/prompt_templates.py,sha256=WTIs-kVSDwiu6Ols0ZIWk5er4dnmL9DRZO6PjwNpgrU,634
|
|
29
|
+
gjdutils/pypi_build.py,sha256=V3g0RJucFi2mbKOuzG-6W6rjAcwJwVolczxH-ZGV7zw,3578
|
|
30
|
+
gjdutils/pytest_utils.py,sha256=qpTX6ehzNSOi4Y475JcR2YwbcMFsH71CmxczR9i5EMA,871
|
|
31
|
+
gjdutils/rand.py,sha256=_7OtrGIdDRpr7OLVwuX6b9Xz0eKK3NvyXsG9Nu-JLQA,1730
|
|
32
|
+
gjdutils/regex.py,sha256=pzQKPAcw72XXMZkdLqjzmjL3mqzcOUiGrqsIHgLeBNM,3139
|
|
33
|
+
gjdutils/requirements_dev.txt,sha256=foECC915zqqiIG2V4eohElBLF7jZ8ckpqiv5CAEOmYI,33
|
|
34
|
+
gjdutils/runtime.py,sha256=njKM7YvGm74r2joM7A4vvh6_jIHVfbvLv5sg82l5XHY,564
|
|
35
|
+
gjdutils/sets.py,sha256=749lZBOJeMweqyL0xW13xkjsshGJDB7AkYX0rkm2pq8,293
|
|
36
|
+
gjdutils/shell.py,sha256=BV6w6gavvTw-AXRUzZl5MRJp2BJtYb6Lv2WNLIVPLTs,1648
|
|
37
|
+
gjdutils/sorteddict.py,sha256=HVWHYl6L7E3T0X4c9G2lqpFVfKxAzgfpaTJ8xZTdMh4,1047
|
|
38
|
+
gjdutils/stopwatch.py,sha256=aJYbykOrPaa47D8zEaYEGEGqk4yIH0EqAhP7ucPfp0U,1905
|
|
39
|
+
gjdutils/strings.py,sha256=n6JM1ESUWAIvUxqWIedEDAw9IcELHWUJ6GpKca2W5gY,6830
|
|
40
|
+
gjdutils/typ.py,sha256=GCgaXSUWzQ4V2dwj_SUzYS-XXtzBs2AHkGv-XVTc80w,835
|
|
41
|
+
gjdutils/voice_speechrecognition.py,sha256=jWSl_vxkpBmJkf5m8v9Z1Q6Y30nPxQZ-4ezXaEJI0cI,859
|
|
42
|
+
gjdutils/web.py,sha256=bquklGMPe1syFMAxvPUEtGZiYeqiXl7xjGtI38Xd7I0,2171
|
|
43
|
+
gjdutils/obsolete/google_text_to_speech.py,sha256=PuCDf0z8oXqF2gA7ZshmF-TY9vUEmTjGJ80DeYFRC80,1974
|
|
44
|
+
gjdutils/obsolete/llms_obsolete.py,sha256=46mJ0HSV3kkvpuCN2xSA5QYJYA-xKc-S0SnLon1A6BM,10339
|
|
45
|
+
gjdutils/todo/convert_parquet.py,sha256=M1bq9cAU9lhOZLS4uwVBB5iyTyHnVGJCjn4zGqLI8zQ,699
|
|
46
|
+
gjdutils-0.2.2.dist-info/METADATA,sha256=1EogzH3PB3-pzPp1i0ZDwLoF1dS86PAHrBKhph0KUyM,3844
|
|
47
|
+
gjdutils-0.2.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
48
|
+
gjdutils-0.2.2.dist-info/licenses/LICENSE,sha256=WpqpqdB8Jg7s0BZwJaQBlLzhx1bFf-HvXEQLJYNqph4,1067
|
|
49
|
+
gjdutils-0.2.2.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Greg Detre
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|