flock-core 0.4.0b46__py3-none-any.whl → 0.4.0b48__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.

Potentially problematic release.


This version of flock-core might be problematic. Click here for more details.

Files changed (31) hide show
  1. flock/core/flock.py +105 -61
  2. flock/core/flock_registry.py +45 -38
  3. flock/core/util/spliter.py +4 -0
  4. flock/evaluators/__init__.py +1 -0
  5. flock/evaluators/declarative/__init__.py +1 -0
  6. flock/modules/__init__.py +1 -0
  7. flock/modules/assertion/__init__.py +1 -0
  8. flock/modules/callback/__init__.py +1 -0
  9. flock/modules/memory/__init__.py +1 -0
  10. flock/modules/output/__init__.py +1 -0
  11. flock/modules/performance/__init__.py +1 -0
  12. flock/modules/zep/__init__.py +1 -0
  13. flock/tools/__init__.py +188 -0
  14. flock/{core/tools → tools}/azure_tools.py +284 -0
  15. flock/tools/code_tools.py +56 -0
  16. flock/tools/file_tools.py +140 -0
  17. flock/{core/tools/dev_tools/github.py → tools/github_tools.py} +3 -3
  18. flock/{core/tools → tools}/markdown_tools.py +14 -4
  19. flock/tools/system_tools.py +9 -0
  20. flock/{core/tools/llm_tools.py → tools/text_tools.py} +47 -25
  21. flock/tools/web_tools.py +90 -0
  22. flock/{core/tools → tools}/zendesk_tools.py +6 -6
  23. flock/webapp/app/config.py +1 -1
  24. flock/webapp/app/main.py +109 -16
  25. flock/workflow/activities.py +1 -0
  26. {flock_core-0.4.0b46.dist-info → flock_core-0.4.0b48.dist-info}/METADATA +24 -13
  27. {flock_core-0.4.0b46.dist-info → flock_core-0.4.0b48.dist-info}/RECORD +30 -17
  28. flock/core/tools/basic_tools.py +0 -317
  29. {flock_core-0.4.0b46.dist-info → flock_core-0.4.0b48.dist-info}/WHEEL +0 -0
  30. {flock_core-0.4.0b46.dist-info → flock_core-0.4.0b48.dist-info}/entry_points.txt +0 -0
  31. {flock_core-0.4.0b46.dist-info → flock_core-0.4.0b48.dist-info}/licenses/LICENSE +0 -0
@@ -19,12 +19,12 @@ flock/cli/view_results.py,sha256=dOzK0O1FHSIDERnx48y-2Xke9BkOHS7pcOhs64AyIg0,781
19
19
  flock/cli/yaml_editor.py,sha256=K3N0bh61G1TSDAZDnurqW9e_-hO6CtSQKXQqlDhCjVo,12527
20
20
  flock/cli/assets/release_notes.md,sha256=bqnk50jxM3w5uY44Dc7MkdT8XmRREFxrVBAG9XCOSSU,4896
21
21
  flock/core/__init__.py,sha256=p7lmQULRu9ejIAELfanZiyMhW0CougIPvyFHW2nqBFQ,847
22
- flock/core/flock.py,sha256=tr7O84Ykgnu7ZXQ54bOdnjEsZw-a7ue-pDp5UNyPkn4,33837
22
+ flock/core/flock.py,sha256=1U1on8aMuCjFNAkQQMyWk7vNa0FqttWDFqoqQ1QlhEc,35674
23
23
  flock/core/flock_agent.py,sha256=-gEfBKWc569ynqNdy7Gc1iqBrCYPHmC8qvzXkxTi5m4,41115
24
24
  flock/core/flock_evaluator.py,sha256=dOXZeDOGZcAmJ9ahqq_2bdGUU1VOXY4skmwTVpAjiVw,1685
25
25
  flock/core/flock_factory.py,sha256=_4zsjkEmJnCR7IvJ3SUHnDbX6c7Tt3E4P5ohxwKvE6w,3173
26
26
  flock/core/flock_module.py,sha256=UCK6TFe4viXs596zeng0GD3gln4ZNGu_gCWkXIIMREg,3090
27
- flock/core/flock_registry.py,sha256=aC-RK0js676DQkjXmNuYHuD5t6GmFhpQoCKaO3i7xFg,24920
27
+ flock/core/flock_registry.py,sha256=WKfIYXowrtblQ0HIko2zGMU8FqkSxjgIxta_ywXaekk,25764
28
28
  flock/core/flock_router.py,sha256=1OAXDsdaIIFApEfo6SRfFEDoTuGt3Si7n2MXiySEfis,2644
29
29
  flock/core/api/__init__.py,sha256=KdzUwBOwhxqqy7lAMLpysKL5GvpIiwOy6CxXELZVWaY,186
30
30
  flock/core/api/custom_endpoint.py,sha256=Mbk2owdcXVATaT5FtEWXFzllgursozcmqP8ouG5btc0,1305
@@ -67,29 +67,32 @@ flock/core/serialization/json_encoder.py,sha256=gAKj2zU_8wQiNvdkby2hksSA4fbPNwTj
67
67
  flock/core/serialization/secure_serializer.py,sha256=n5-zRvvXddgJv1FFHsaQ2wuYdL3WUSGPvG_LGaffEJo,6144
68
68
  flock/core/serialization/serializable.py,sha256=qlv8TsTqRuklXiNuCMrvro5VKz764xC2i3FlgLJSkdk,12129
69
69
  flock/core/serialization/serialization_utils.py,sha256=AHRf90trgnj2Q6aaGaq5eja5PRcuJANUsp2wafGUeig,15257
70
- flock/core/tools/azure_tools.py,sha256=hwLnI2gsEq6QzUoWj5eCGDKTdXY1XUf6K-H5Uwva2MY,17093
71
- flock/core/tools/basic_tools.py,sha256=Ye7nlI4RRkqWRy8nH9CKuItBmh_ZXxUpouGnCOfx0s0,9050
72
- flock/core/tools/llm_tools.py,sha256=Bdt4Dpur5dGpxd2KFEQyxjfZazvW1HCDKY6ydMj6UgQ,21811
73
- flock/core/tools/markdown_tools.py,sha256=W6fGM48yGHbifVlaOk1jOtVcybfRbRmf20VbDOZv8S4,6031
74
- flock/core/tools/zendesk_tools.py,sha256=deZAyUi9j-_yZaTayLQVJaFXIqIct-P6C8IGN5UU_tM,3528
75
- flock/core/tools/dev_tools/github.py,sha256=a2OTPXS7kWOVA4zrZHynQDcsmEi4Pac5MfSjQOLePzA,5308
76
70
  flock/core/util/cli_helper.py,sha256=g4u8kCtbwHRXETzBz1cw52_8muSWbWlr00CqST525jI,49963
77
71
  flock/core/util/file_path_utils.py,sha256=Odf7uU32C-x1KNighbNERSiMtkzW4h8laABIoFK7A5M,6246
78
72
  flock/core/util/hydrator.py,sha256=QJvCA8F4nkSP5akp3yg0cT6oaajOr1n7sldW5dCs6Lo,10733
79
73
  flock/core/util/input_resolver.py,sha256=KPoPSpklyCoiR2t5r6J6GJHegmPLFZ0YE126VcKBewM,4703
80
74
  flock/core/util/loader.py,sha256=j3q2qem5bFMP2SmMuYjb-ISxsNGNZd1baQmpvAnRUUk,2244
81
- flock/core/util/spliter.py,sha256=D-P4u3vdKQFyC4DltpCoX4PExXuOKnE-G5kBG_6H678,6770
75
+ flock/core/util/spliter.py,sha256=cXgxrD-v6LqfCMp87BPRQq6C_BF6CJmMmug1WgwBosQ,6972
76
+ flock/evaluators/__init__.py,sha256=Y0cEkx0dujRmy--TDpKoTqFSLzbyFz8BwEOv8kdSUhg,22
77
+ flock/evaluators/declarative/__init__.py,sha256=Y0cEkx0dujRmy--TDpKoTqFSLzbyFz8BwEOv8kdSUhg,22
82
78
  flock/evaluators/declarative/declarative_evaluator.py,sha256=q3qKHuKrj17mhaoOZuKh2HyVfiDBEEUk1Y1ZrejvggA,6328
83
79
  flock/evaluators/memory/memory_evaluator.py,sha256=ySwz7kcc8suXMJ7gKNSWThW8iOMlE8lUcUzEAHvv8rw,3559
84
80
  flock/evaluators/test/test_case_evaluator.py,sha256=3Emcoty0LOLLBIuPGxSpKphuZC9Fu1DTr1vbGg-hd0Q,1233
85
81
  flock/evaluators/zep/zep_evaluator.py,sha256=6_5vTdU0yJAH8I8w3-MPXiAZx6iUPhAVCsHjrHzkPLM,2058
82
+ flock/modules/__init__.py,sha256=Y0cEkx0dujRmy--TDpKoTqFSLzbyFz8BwEOv8kdSUhg,22
83
+ flock/modules/assertion/__init__.py,sha256=Y0cEkx0dujRmy--TDpKoTqFSLzbyFz8BwEOv8kdSUhg,22
86
84
  flock/modules/assertion/assertion_module.py,sha256=2p9mIj8yBXRGgfe5pUWYXcLT86Ny13KyWHpRhe0Ehtg,12877
85
+ flock/modules/callback/__init__.py,sha256=Y0cEkx0dujRmy--TDpKoTqFSLzbyFz8BwEOv8kdSUhg,22
87
86
  flock/modules/callback/callback_module.py,sha256=FnTYQeL828uQgYlpgGUnwCz0OzW_DKdOnQ3nwQCcu5o,2956
87
+ flock/modules/memory/__init__.py,sha256=Y0cEkx0dujRmy--TDpKoTqFSLzbyFz8BwEOv8kdSUhg,22
88
88
  flock/modules/memory/memory_module.py,sha256=zxdA8RIwhwYIytB8bY0VW32j6xDToUuP9RRgk_mpCwo,15046
89
89
  flock/modules/memory/memory_parser.py,sha256=FLH7GL8XThvHiCMfX3eQH7Sz-f62fzhAUmO6_gaDI7U,4372
90
90
  flock/modules/memory/memory_storage.py,sha256=CNcLDMmvv0x7Z3YMKr6VveS_VCa7rKPw8l2d-XgqokA,27246
91
+ flock/modules/output/__init__.py,sha256=Y0cEkx0dujRmy--TDpKoTqFSLzbyFz8BwEOv8kdSUhg,22
91
92
  flock/modules/output/output_module.py,sha256=gEn1_khPAJp-hqU6Rxdv1sQz0jTLVSzYJvNbK1uVNCY,7402
93
+ flock/modules/performance/__init__.py,sha256=Y0cEkx0dujRmy--TDpKoTqFSLzbyFz8BwEOv8kdSUhg,22
92
94
  flock/modules/performance/metrics_module.py,sha256=j4_xY4HTz_MsaduFCk7mmQAzFtDZ9pTgPxKTEW-d8fE,16993
95
+ flock/modules/zep/__init__.py,sha256=Y0cEkx0dujRmy--TDpKoTqFSLzbyFz8BwEOv8kdSUhg,22
93
96
  flock/modules/zep/zep_module.py,sha256=EIs0EMDrmE--rmmkjj7vLhE-pgR_b3uRHp0dc8DiZMc,6135
94
97
  flock/platform/docker_tools.py,sha256=fpA7-6rJBjPOUBLdQP4ny2QPgJ_042nmqRn5GtKnoYw,1445
95
98
  flock/platform/jaeger_install.py,sha256=MyOMJQx4TQSMYvdUJxfiGSo3YCtsfkbNXcAcQ9bjETA,2898
@@ -440,13 +443,23 @@ flock/themes/zenburn.toml,sha256=NxOAR3cx-Z9PVErEKHFZ6jsjfKBtPmfyN_vGSri5_qo,171
440
443
  flock/themes/zenburned.toml,sha256=UEmquBbcAO3Zj652XKUwCsNoC2iQSlIh-q5c6DH-7Kc,1664
441
444
  flock/themes/zenwritten-dark.toml,sha256=To5l6520_3UqAGiEumpzGWsHhXxqu9ThrMildXKgIO0,1669
442
445
  flock/themes/zenwritten-light.toml,sha256=G1iEheCPfBNsMTGaVpEVpDzYBHA_T-MV27rolUYolmE,1666
446
+ flock/tools/__init__.py,sha256=rVCbfZvX_prgSwSbX9i5oCN0nt3jASusXsksVPU70A8,5098
447
+ flock/tools/azure_tools.py,sha256=OTJsb0B4l70GcD1W3ZMDHWd3X8nEnszhhz2sllD2z9E,30187
448
+ flock/tools/code_tools.py,sha256=CRDi3iIN4NQcgz4TJ4b-thFq7uXW_gIXPk-iEoWhF4E,1356
449
+ flock/tools/file_tools.py,sha256=zbXo5SxyKYLvrE7k3vLF5tGxCeuaeJtCCdWQ1fXJMAA,4626
450
+ flock/tools/github_tools.py,sha256=HH47-4K3HL6tRJhZhUttWDo2aloP9Hs12wRC_f_-Vkc,5329
451
+ flock/tools/markdown_tools.py,sha256=94fjGAJ5DEutoioD0ke-YRbxF6IWJQKuPVBLkNqdBo4,6345
452
+ flock/tools/system_tools.py,sha256=IUB8MiSxtQH5ZfTGOck3vl4TKva8m1lfU4-W5D5b-4w,202
453
+ flock/tools/text_tools.py,sha256=mMQ8tkyYDxIorqqzl9ccGyWYjrSynYiYFIeP9qypfdg,22491
454
+ flock/tools/web_tools.py,sha256=Wl3qO5lKq4PYtmYahgeFGBQ8tDC0uKY4k9A1Zn-MqFw,2588
455
+ flock/tools/zendesk_tools.py,sha256=HQ7qBVSrRfemwolz0IOXl8Z02vJCLE6mTd-cARVdX88,3576
443
456
  flock/webapp/__init__.py,sha256=YtRbbyciN3Z2oMB9fdXZuvM3e49R8m2mY5qHLDoapRA,37
444
457
  flock/webapp/run.py,sha256=Ekg-mQSl7RUDJAEDTBJMIlLyvhWqWPMjg8hPqmgFREE,8945
445
458
  flock/webapp/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
446
459
  flock/webapp/app/chat.py,sha256=mFc_w4J3lN5dRtd52Jr1ezt-TTS5t557Wy1KdoRY4kU,9788
447
- flock/webapp/app/config.py,sha256=RHwEPi8sXWw-Uf_0b_DGcnM8ZYYocbImccJ_ms7OeFQ,4208
460
+ flock/webapp/app/config.py,sha256=uDEDOk6V7ZhsERHvk3L08g_EpwLL1wM6wMj2A1A2dy0,4160
448
461
  flock/webapp/app/dependencies.py,sha256=8GSf2ftiEM4xD5GbfFhoiACzUmyGaWwtM6klzyP_Qw4,4492
449
- flock/webapp/app/main.py,sha256=9yDyHn5SeczpLiSfthg15BxFM2mQ3R-zF-9AahBoEdw,28569
462
+ flock/webapp/app/main.py,sha256=_JytSJ6hQ-ay6u5bEqJLADr7_cTGFqqr_7BW9s6TCCI,33845
450
463
  flock/webapp/app/models_ui.py,sha256=vrEBLbhEp6FziAgBSFOLT1M7ckwadsTdT7qus5_NduE,329
451
464
  flock/webapp/app/theme_mapper.py,sha256=QzWwLWpED78oYp3FjZ9zxv1KxCyj43m8MZ0fhfzz37w,34302
452
465
  flock/webapp/app/utils.py,sha256=RF8DMKKAj1XPmm4txUdo2OdswI1ATQ7cqUm6G9JFDzA,2942
@@ -500,14 +513,14 @@ flock/webapp/templates/partials/_sidebar.html,sha256=uA-SZKfVpxImT8Acpw2hhpJbOk1
500
513
  flock/webapp/templates/partials/_structured_data_view.html,sha256=IsmGbm2rKHZr6qx0a_n6QGs89Rq4xNFhymrZVI6OShc,2063
501
514
  flock/webapp/templates/partials/_theme_preview.html,sha256=81vP5z8958LjhGWGwjVAVw3zW0uvYwfcXlU30i9exmo,867
502
515
  flock/workflow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
503
- flock/workflow/activities.py,sha256=Rcgcepa-RzaEjKo2aNuI14O_sX8ij0RrqeyPa0oSw8M,9910
516
+ flock/workflow/activities.py,sha256=fyvefDOWZhhj5gCYIHR9Aqm2DbE6XI6-sXESFnnYRuc,9911
504
517
  flock/workflow/agent_activities.py,sha256=NhBZscflEf2IMfSRa_pBM_TRP7uVEF_O0ROvWZ33eDc,963
505
518
  flock/workflow/agent_execution_activity.py,sha256=Gy6FtuVAjf0NiUXmC3syS2eJpNQF4R3pmwMq47NYW3U,9462
506
519
  flock/workflow/flock_workflow.py,sha256=iSUF_soFvWar0ffpkzE4irkDZRx0p4HnwmEBi_Ne2sY,9666
507
520
  flock/workflow/temporal_config.py,sha256=3_8O7SDEjMsSMXsWJBfnb6XTp0TFaz39uyzSlMTSF_I,3988
508
521
  flock/workflow/temporal_setup.py,sha256=YIHnSBntzOchHfMSh8hoLeNXrz3B1UbR14YrR6soM7A,1606
509
- flock_core-0.4.0b46.dist-info/METADATA,sha256=vG3wZwb_mlMNL9DhujdpQYCj1nEw3HTH5BnjGUH_NTA,17125
510
- flock_core-0.4.0b46.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
511
- flock_core-0.4.0b46.dist-info/entry_points.txt,sha256=rWaS5KSpkTmWySURGFZk6PhbJ87TmvcFQDi2uzjlagQ,37
512
- flock_core-0.4.0b46.dist-info/licenses/LICENSE,sha256=iYEqWy0wjULzM9GAERaybP4LBiPeu7Z1NEliLUdJKSc,1072
513
- flock_core-0.4.0b46.dist-info/RECORD,,
522
+ flock_core-0.4.0b48.dist-info/METADATA,sha256=d3b9EUOv5ndu60u2Xn79MWYFYeUnYVw4NWzr8GHwd10,17809
523
+ flock_core-0.4.0b48.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
524
+ flock_core-0.4.0b48.dist-info/entry_points.txt,sha256=rWaS5KSpkTmWySURGFZk6PhbJ87TmvcFQDi2uzjlagQ,37
525
+ flock_core-0.4.0b48.dist-info/licenses/LICENSE,sha256=iYEqWy0wjULzM9GAERaybP4LBiPeu7Z1NEliLUdJKSc,1072
526
+ flock_core-0.4.0b48.dist-info/RECORD,,
@@ -1,317 +0,0 @@
1
- """This module contains basic agentic tools for performing various tasks."""
2
-
3
- import importlib
4
- import json
5
- import os
6
- import re
7
- from typing import Any, Literal
8
-
9
- from flock.core.interpreter.python_interpreter import PythonInterpreter
10
- from flock.core.logging.trace_and_logged import traced_and_logged
11
-
12
-
13
- @traced_and_logged
14
- def web_search_tavily(query: str):
15
- if importlib.util.find_spec("tavily") is not None:
16
- from tavily import TavilyClient
17
-
18
- client = TavilyClient(api_key=os.getenv("TAVILY_API_KEY"))
19
- try:
20
- response = client.search(query, include_answer=True) # type: ignore
21
- return response
22
- except Exception:
23
- raise
24
- else:
25
- raise ImportError(
26
- "Optional tool dependencies not installed. Install with 'pip install flock-core[tools]'."
27
- )
28
-
29
-
30
- @traced_and_logged
31
- def web_search_duckduckgo(
32
- keywords: str, search_type: Literal["news", "web"] = "web"
33
- ):
34
- try:
35
- from duckduckgo_search import DDGS
36
-
37
- if search_type == "news":
38
- response = DDGS().news(keywords)
39
- else:
40
- response = DDGS().text(keywords)
41
-
42
- return response
43
- except Exception:
44
- raise
45
-
46
-
47
- @traced_and_logged
48
- def web_search_bing(keywords: str):
49
- try:
50
- import httpx
51
-
52
- subscription_key = os.environ["BING_SEARCH_V7_SUBSCRIPTION_KEY"]
53
- endpoint = "https://api.bing.microsoft.com/v7.0/search"
54
-
55
- # Query term(s) to search for.
56
- query = keywords
57
-
58
- # Construct a request
59
- mkt = "en-US"
60
- params = {"q": query, "mkt": mkt}
61
- headers = {"Ocp-Apim-Subscription-Key": subscription_key}
62
-
63
- response = httpx.get(endpoint, headers=headers, params=params)
64
- response.raise_for_status()
65
- search_results = response.json()
66
- return search_results["webPages"]
67
- except Exception:
68
- raise
69
-
70
-
71
- def extract_links_from_markdown(markdown: str, url: str) -> list:
72
- # Regular expression to find all markdown links
73
- link_pattern = re.compile(r"\[([^\]]+)\]\(([^)]+)\)")
74
- links = link_pattern.findall(markdown)
75
- return [url + link[1] for link in links]
76
-
77
-
78
- @traced_and_logged
79
- def get_web_content_as_markdown(url: str) -> str:
80
- if (
81
- importlib.util.find_spec("httpx") is not None
82
- and importlib.util.find_spec("markdownify") is not None
83
- ):
84
- import httpx
85
- from markdownify import markdownify as md
86
-
87
- try:
88
- response = httpx.get(url)
89
- response.raise_for_status()
90
- markdown = md(response.text)
91
- return markdown
92
- except Exception:
93
- raise
94
- else:
95
- raise ImportError(
96
- "Optional tool dependencies not installed. Install with 'pip install flock-core[tools]'."
97
- )
98
-
99
-
100
- @traced_and_logged
101
- def get_anything_as_markdown(url_or_file_path: str):
102
- if importlib.util.find_spec("docling") is not None:
103
- from docling.document_converter import DocumentConverter
104
-
105
- try:
106
- converter = DocumentConverter()
107
- result = converter.convert(url_or_file_path)
108
- markdown = result.document.export_to_markdown()
109
- return markdown
110
- except Exception:
111
- raise
112
- else:
113
- raise ImportError(
114
- "Optional tool dependencies not installed. Install with 'pip install flock-core[all-tools]'."
115
- )
116
-
117
-
118
- @traced_and_logged
119
- def evaluate_math(expression: str) -> float:
120
- try:
121
- result = PythonInterpreter(
122
- {},
123
- [
124
- "os",
125
- "math",
126
- "random",
127
- "datetime",
128
- "time",
129
- "string",
130
- "collections",
131
- "itertools",
132
- "functools",
133
- "typing",
134
- "enum",
135
- "json",
136
- "ast",
137
- ],
138
- verbose=True,
139
- ).execute(expression)
140
- return result
141
- except Exception:
142
- raise
143
-
144
-
145
- @traced_and_logged
146
- def code_eval(python_code: str) -> str:
147
- try:
148
- result = PythonInterpreter(
149
- {},
150
- [
151
- "os",
152
- "math",
153
- "random",
154
- "datetime",
155
- "time",
156
- "string",
157
- "collections",
158
- "itertools",
159
- "functools",
160
- "typing",
161
- "enum",
162
- "json",
163
- "ast",
164
- ],
165
- verbose=True,
166
- ).execute(python_code)
167
- return result
168
- except Exception:
169
- raise
170
-
171
-
172
- @traced_and_logged
173
- def get_current_time() -> str:
174
- import datetime
175
-
176
- time = datetime.datetime.now().isoformat()
177
- return time
178
-
179
-
180
- @traced_and_logged
181
- def count_words(text: str) -> int:
182
- count = len(text.split())
183
- return count
184
-
185
-
186
- @traced_and_logged
187
- def extract_urls(text: str) -> list[str]:
188
- import re
189
-
190
- url_pattern = r"https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+"
191
- urls = re.findall(url_pattern, text)
192
- return urls
193
-
194
-
195
- @traced_and_logged
196
- def extract_numbers(text: str) -> list[float]:
197
- import re
198
-
199
- numbers = [float(x) for x in re.findall(r"-?\d*\.?\d+", text)]
200
- return numbers
201
-
202
-
203
- @traced_and_logged
204
- def json_parse_safe(text: str) -> dict:
205
- try:
206
- result = json.loads(text)
207
- return result
208
- except Exception:
209
- return {}
210
-
211
-
212
- @traced_and_logged
213
- def save_to_file(content: str, filename: str):
214
- try:
215
- with open(filename, "w") as f:
216
- f.write(content)
217
- except Exception:
218
- raise
219
-
220
-
221
- @traced_and_logged
222
- def read_from_file(filename: str) -> str:
223
- with open(filename, encoding="utf-8") as file:
224
- return file.read()
225
-
226
-
227
- @traced_and_logged
228
- def json_search(
229
- json_file_path: str, search_query: str, case_sensitive: bool = False
230
- ) -> list:
231
- """Search a JSON file for objects containing the specified search query.
232
-
233
- Args:
234
- json_file_path (str): Path to the JSON file to search
235
- search_query (str): Text to search for within the JSON objects
236
- case_sensitive (bool, optional): Whether to perform a case-sensitive search. Defaults to False.
237
-
238
- Returns:
239
- list: List of JSON objects (as dicts) that contain the search query
240
-
241
- Example:
242
- >>> matching_tickets = json_search("tickets.json", "error 404")
243
- >>> print(
244
- ... f"Found {len(matching_tickets)} tickets mentioning '404 error'"
245
- ... )
246
- """
247
- try:
248
- # Read the JSON file
249
- file_content = read_from_file(json_file_path)
250
-
251
- # Parse the JSON content
252
- json_data = json_parse_safe(file_content)
253
-
254
- # Convert search query to lowercase if case-insensitive search
255
- if not case_sensitive:
256
- search_query = search_query.lower()
257
-
258
- results = []
259
-
260
- # Determine if the JSON root is an object or array
261
- if isinstance(json_data, dict):
262
- # Handle case where root is a dictionary object
263
- for key, value in json_data.items():
264
- if isinstance(value, list):
265
- # If this key contains a list of objects, search within them
266
- matching_items = _search_in_list(
267
- value, search_query, case_sensitive
268
- )
269
- results.extend(matching_items)
270
- elif _contains_text(value, search_query, case_sensitive):
271
- # The entire object matches
272
- results.append(json_data)
273
- break
274
- elif isinstance(json_data, list):
275
- # Handle case where root is an array
276
- matching_items = _search_in_list(
277
- json_data, search_query, case_sensitive
278
- )
279
- results.extend(matching_items)
280
-
281
- return results
282
-
283
- except Exception as e:
284
- return [{"error": f"Error searching JSON file: {e!s}"}]
285
-
286
-
287
- def _search_in_list(
288
- items: list, search_query: str, case_sensitive: bool
289
- ) -> list:
290
- """Helper function to search for text in a list of items."""
291
- matching_items = []
292
- for item in items:
293
- if _contains_text(item, search_query, case_sensitive):
294
- matching_items.append(item)
295
- return matching_items
296
-
297
-
298
- def _contains_text(obj: Any, search_query: str, case_sensitive: bool) -> bool:
299
- """Recursively check if an object contains the search query in any of its string values."""
300
- if isinstance(obj, str):
301
- # For string values, check if they contain the search query
302
- if case_sensitive:
303
- return search_query in obj
304
- else:
305
- return search_query in obj.lower()
306
- elif isinstance(obj, dict):
307
- # For dictionaries, check each value
308
- for value in obj.values():
309
- if _contains_text(value, search_query, case_sensitive):
310
- return True
311
- elif isinstance(obj, list):
312
- # For lists, check each item
313
- for item in obj:
314
- if _contains_text(item, search_query, case_sensitive):
315
- return True
316
- # For other types (numbers, booleans, None), return False
317
- return False