chatterer 0.1.22__py3-none-any.whl → 0.1.24__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.
- chatterer/examples/__main__.py +75 -0
- chatterer/examples/{anything_to_markdown.py → any2md.py} +9 -9
- chatterer/examples/pdf2md.py +338 -0
- chatterer/examples/{pdf_to_text.py → pdf2txt.py} +5 -5
- chatterer/examples/{make_ppt.py → ppt.py} +5 -7
- chatterer/examples/pw.py +137 -0
- chatterer/examples/{get_code_snippets.py → snippet.py} +7 -7
- chatterer/examples/{transcription_api.py → transcribe.py} +6 -6
- chatterer/examples/{upstage_parser.py → upstage.py} +17 -17
- chatterer/examples/{webpage_to_markdown.py → web2md.py} +8 -12
- chatterer/strategies/atom_of_thoughts.py +161 -161
- chatterer/tools/convert_pdf_to_markdown.py +326 -94
- {chatterer-0.1.22.dist-info → chatterer-0.1.24.dist-info}/METADATA +6 -9
- {chatterer-0.1.22.dist-info → chatterer-0.1.24.dist-info}/RECORD +17 -16
- chatterer-0.1.24.dist-info/entry_points.txt +2 -0
- chatterer/examples/login_with_playwright.py +0 -156
- chatterer/examples/pdf_to_markdown.py +0 -77
- chatterer-0.1.22.dist-info/entry_points.txt +0 -10
- {chatterer-0.1.22.dist-info → chatterer-0.1.24.dist-info}/WHEEL +0 -0
- {chatterer-0.1.22.dist-info → chatterer-0.1.24.dist-info}/top_level.txt +0 -0
@@ -2,15 +2,15 @@ import logging
|
|
2
2
|
from pathlib import Path
|
3
3
|
from typing import Optional
|
4
4
|
|
5
|
-
from spargear import
|
5
|
+
from spargear import RunnableArguments
|
6
6
|
|
7
7
|
from chatterer import CodeSnippets
|
8
8
|
|
9
9
|
logger = logging.getLogger(__name__)
|
10
10
|
|
11
11
|
|
12
|
-
class
|
13
|
-
|
12
|
+
class Arguments(RunnableArguments[CodeSnippets]):
|
13
|
+
PATH_OR_PACKAGE_NAME: str
|
14
14
|
"""Path to the package or file from which to extract code snippets."""
|
15
15
|
output: Optional[str] = None
|
16
16
|
"""Output path for the extracted code snippets. If not provided, defaults to a file with the same name as the input."""
|
@@ -33,7 +33,7 @@ class GetCodeSnippetsArgs(BaseArguments):
|
|
33
33
|
output = None
|
34
34
|
|
35
35
|
cs = CodeSnippets.from_path_or_pkgname(
|
36
|
-
path_or_pkgname=self.
|
36
|
+
path_or_pkgname=self.PATH_OR_PACKAGE_NAME,
|
37
37
|
ban_file_patterns=self.ban_file_patterns,
|
38
38
|
glob_patterns=self.glob_patterns,
|
39
39
|
case_sensitive=self.case_sensitive,
|
@@ -41,14 +41,14 @@ class GetCodeSnippetsArgs(BaseArguments):
|
|
41
41
|
if output is not None:
|
42
42
|
output.parent.mkdir(parents=True, exist_ok=True)
|
43
43
|
output.write_text(cs.snippets_text, encoding="utf-8")
|
44
|
-
logger.info(f"Extracted code snippets from `{self.
|
44
|
+
logger.info(f"Extracted code snippets from `{self.PATH_OR_PACKAGE_NAME}` and saved to `{output}`.")
|
45
45
|
else:
|
46
|
-
logger.info(f"Extracted code snippets from `{self.
|
46
|
+
logger.info(f"Extracted code snippets from `{self.PATH_OR_PACKAGE_NAME}`.")
|
47
47
|
return cs
|
48
48
|
|
49
49
|
|
50
50
|
def main() -> None:
|
51
|
-
|
51
|
+
Arguments().run()
|
52
52
|
|
53
53
|
|
54
54
|
if __name__ == "__main__":
|
@@ -6,14 +6,14 @@ from typing import Optional, cast
|
|
6
6
|
|
7
7
|
from openai import OpenAI
|
8
8
|
from pydub import AudioSegment
|
9
|
-
from spargear import
|
9
|
+
from spargear import RunnableArguments
|
10
10
|
|
11
11
|
# Maximum chunk length in seconds
|
12
12
|
MAX_CHUNK_DURATION = 600
|
13
13
|
|
14
14
|
|
15
|
-
class
|
16
|
-
|
15
|
+
class Arguments(RunnableArguments[None]):
|
16
|
+
AUDIO_PATH: Path
|
17
17
|
"""The audio file to transcribe."""
|
18
18
|
output: Optional[Path] = None
|
19
19
|
"""Path to save the transcription output."""
|
@@ -31,7 +31,7 @@ class TranscriptionApiArguments(BaseArguments):
|
|
31
31
|
|
32
32
|
client = OpenAI(api_key=self.api_key, base_url=self.base_url)
|
33
33
|
|
34
|
-
audio = load_audio_segment(self.
|
34
|
+
audio = load_audio_segment(self.AUDIO_PATH)
|
35
35
|
|
36
36
|
segments = split_audio(audio, MAX_CHUNK_DURATION)
|
37
37
|
print(f"[i] Audio duration: {len(audio) / 1000:.1f}s; splitting into {len(segments)} segment(s)")
|
@@ -42,7 +42,7 @@ class TranscriptionApiArguments(BaseArguments):
|
|
42
42
|
transcripts.append(transcribe_segment(seg, client, model, self.prompt))
|
43
43
|
|
44
44
|
full_transcript = "\n\n".join(transcripts)
|
45
|
-
output_path: Path = self.output or self.
|
45
|
+
output_path: Path = self.output or self.AUDIO_PATH.with_suffix(".txt")
|
46
46
|
output_path.write_text(full_transcript, encoding="utf-8")
|
47
47
|
print(f"[✓] Transcription saved to: {output_path}")
|
48
48
|
|
@@ -105,7 +105,7 @@ def transcribe_segment(segment: AudioSegment, client: OpenAI, model: str, prompt
|
|
105
105
|
|
106
106
|
|
107
107
|
def main() -> None:
|
108
|
-
|
108
|
+
Arguments().run()
|
109
109
|
|
110
110
|
|
111
111
|
if __name__ == "__main__":
|
@@ -19,8 +19,8 @@ from chatterer.tools.upstage_document_parser import (
|
|
19
19
|
logger = logging.getLogger(__name__)
|
20
20
|
|
21
21
|
|
22
|
-
class
|
23
|
-
|
22
|
+
class Arguments(BaseArguments):
|
23
|
+
INPUT_PATH: Path
|
24
24
|
"""Input file to parse. Can be a PDF, image, or other supported formats."""
|
25
25
|
output: Optional[Path] = None
|
26
26
|
"""Output file path for the parsed content. Defaults to input file with .md suffix if not provided."""
|
@@ -52,25 +52,25 @@ class UpstageParserArguments(BaseArguments):
|
|
52
52
|
)
|
53
53
|
|
54
54
|
def run(self) -> None:
|
55
|
-
input =
|
56
|
-
out =
|
55
|
+
input = self.INPUT_PATH.resolve()
|
56
|
+
out = self.output or input.with_suffix(".md")
|
57
57
|
|
58
58
|
parser = UpstageDocumentParseParser(
|
59
|
-
api_key=
|
60
|
-
base_url=
|
61
|
-
model=
|
62
|
-
split=
|
63
|
-
ocr=
|
64
|
-
output_format=
|
65
|
-
coordinates=
|
66
|
-
base64_encoding=
|
67
|
-
image_description_instruction=
|
68
|
-
image_dir=
|
69
|
-
chatterer=
|
59
|
+
api_key=self.api_key,
|
60
|
+
base_url=self.base_url,
|
61
|
+
model=self.model,
|
62
|
+
split=self.split,
|
63
|
+
ocr=self.ocr,
|
64
|
+
output_format=self.output_format,
|
65
|
+
coordinates=self.coordinates,
|
66
|
+
base64_encoding=self.base64_encoding,
|
67
|
+
image_description_instruction=self.image_description_instruction,
|
68
|
+
image_dir=self.image_dir,
|
69
|
+
chatterer=self.chatterer.value,
|
70
70
|
)
|
71
71
|
docs = parser.parse(Blob.from_path(input)) # pyright: ignore[reportUnknownMemberType]
|
72
72
|
|
73
|
-
if
|
73
|
+
if self.image_dir:
|
74
74
|
for path, image in parser.image_data.items():
|
75
75
|
(path := Path(path)).parent.mkdir(parents=True, exist_ok=True)
|
76
76
|
path.write_bytes(image)
|
@@ -82,7 +82,7 @@ class UpstageParserArguments(BaseArguments):
|
|
82
82
|
|
83
83
|
|
84
84
|
def main() -> None:
|
85
|
-
|
85
|
+
Arguments().run()
|
86
86
|
|
87
87
|
|
88
88
|
if __name__ == "__main__":
|
@@ -1,13 +1,13 @@
|
|
1
1
|
from pathlib import Path
|
2
2
|
from typing import Literal
|
3
3
|
|
4
|
-
from spargear import ArgumentSpec,
|
4
|
+
from spargear import ArgumentSpec, RunnableArguments
|
5
5
|
|
6
6
|
from chatterer import Chatterer, MarkdownLink, PlayWrightBot
|
7
7
|
|
8
8
|
|
9
|
-
class
|
10
|
-
|
9
|
+
class Arguments(RunnableArguments[None]):
|
10
|
+
URL: str
|
11
11
|
"""The URL to crawl."""
|
12
12
|
output: str = Path(__file__).with_suffix(".md").as_posix()
|
13
13
|
"""The output file path for the markdown file."""
|
@@ -21,7 +21,7 @@ class WebpageToMarkdownArgs(BaseArguments):
|
|
21
21
|
|
22
22
|
def run(self) -> None:
|
23
23
|
chatterer = self.chatterer.value
|
24
|
-
url: str = self.
|
24
|
+
url: str = self.URL.strip()
|
25
25
|
output: Path = Path(self.output).resolve()
|
26
26
|
with PlayWrightBot(chatterer=chatterer, engine=self.engine) as bot:
|
27
27
|
md = bot.url_to_md(url)
|
@@ -32,15 +32,13 @@ class WebpageToMarkdownArgs(BaseArguments):
|
|
32
32
|
links = MarkdownLink.from_markdown(md, referer_url=url)
|
33
33
|
for link in links:
|
34
34
|
if link.type == "link":
|
35
|
-
print(
|
36
|
-
f"- [{truncate_string(link.url)}] {truncate_string(link.inline_text)} ({truncate_string(link.inline_title)})"
|
37
|
-
)
|
35
|
+
print(f"- [{truncate_string(link.url)}] {truncate_string(link.inline_text)} ({truncate_string(link.inline_title)})")
|
38
36
|
elif link.type == "image":
|
39
37
|
print(f"- ![{truncate_string(link.url)}] ({truncate_string(link.inline_text)})")
|
40
38
|
|
41
39
|
async def arun(self) -> None:
|
42
40
|
chatterer = self.chatterer.value
|
43
|
-
url: str = self.
|
41
|
+
url: str = self.URL.strip()
|
44
42
|
output: Path = Path(self.output).resolve()
|
45
43
|
async with PlayWrightBot(chatterer=chatterer, engine=self.engine) as bot:
|
46
44
|
md = await bot.aurl_to_md(url)
|
@@ -51,9 +49,7 @@ class WebpageToMarkdownArgs(BaseArguments):
|
|
51
49
|
links = MarkdownLink.from_markdown(md, referer_url=url)
|
52
50
|
for link in links:
|
53
51
|
if link.type == "link":
|
54
|
-
print(
|
55
|
-
f"- [{truncate_string(link.url)}] {truncate_string(link.inline_text)} ({truncate_string(link.inline_title)})"
|
56
|
-
)
|
52
|
+
print(f"- [{truncate_string(link.url)}] {truncate_string(link.inline_text)} ({truncate_string(link.inline_title)})")
|
57
53
|
elif link.type == "image":
|
58
54
|
print(f"- ![{truncate_string(link.url)}] ({truncate_string(link.inline_text)})")
|
59
55
|
|
@@ -63,7 +59,7 @@ def truncate_string(s: str) -> str:
|
|
63
59
|
|
64
60
|
|
65
61
|
def main() -> None:
|
66
|
-
|
62
|
+
Arguments().run()
|
67
63
|
|
68
64
|
|
69
65
|
if __name__ == "__main__":
|
@@ -781,143 +781,143 @@ class AoTPipeline:
|
|
781
781
|
# 4.6) Build or export a reasoning graph
|
782
782
|
# ---------------------------------------------------------------------------------
|
783
783
|
|
784
|
-
def get_reasoning_graph(self, global_id_prefix: str = "AoT"):
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
784
|
+
# def get_reasoning_graph(self, global_id_prefix: str = "AoT"):
|
785
|
+
# """
|
786
|
+
# Constructs a Graph object (from hypothetical `neo4j_extension`)
|
787
|
+
# capturing the pipeline steps, including devil's advocate steps.
|
788
|
+
# """
|
789
|
+
# from neo4j_extension import Graph, Node, Relationship
|
790
|
+
|
791
|
+
# g = Graph()
|
792
|
+
# step_nodes: dict[int, Node] = {}
|
793
|
+
# subq_nodes: dict[str, Node] = {}
|
794
|
+
|
795
|
+
# # Step A: Create nodes for each pipeline step
|
796
|
+
# for i, record in enumerate(self.steps_history):
|
797
|
+
# # We'll skip nested Decomposition steps only if we want to flatten them.
|
798
|
+
# # But let's keep them for clarity.
|
799
|
+
# step_node = Node(
|
800
|
+
# properties=record.as_properties(), labels={record.step_name}, globalId=f"{global_id_prefix}_step_{i}"
|
801
|
+
# )
|
802
|
+
# g.add_node(step_node)
|
803
|
+
# step_nodes[i] = step_node
|
804
|
+
|
805
|
+
# # Step B: Collect sub-questions from each DECOMPOSITION or DEVILS_ADVOCATE
|
806
|
+
# all_sub_questions: dict[str, tuple[int, int, SubQuestionNode]] = {}
|
807
|
+
# for i, record in enumerate(self.steps_history):
|
808
|
+
# if record.sub_questions:
|
809
|
+
# for sq_idx, sq in enumerate(record.sub_questions):
|
810
|
+
# sq_id = f"{global_id_prefix}_decomp_{i}_sub_{sq_idx}"
|
811
|
+
# all_sub_questions[sq_id] = (i, sq_idx, sq)
|
812
|
+
|
813
|
+
# for sq_id, (i, sq_idx, sq) in all_sub_questions.items():
|
814
|
+
# n_subq = Node(
|
815
|
+
# properties={
|
816
|
+
# "question": sq.question,
|
817
|
+
# "answer": sq.answer or "",
|
818
|
+
# },
|
819
|
+
# labels={"SubQuestion"},
|
820
|
+
# globalId=sq_id,
|
821
|
+
# )
|
822
|
+
# g.add_node(n_subq)
|
823
|
+
# subq_nodes[sq_id] = n_subq
|
824
|
+
|
825
|
+
# # Step C: Add relationships. We do a simple approach:
|
826
|
+
# # - If StepRecord is DECOMPOSITION or DEVILS_ADVOCATE with sub_questions, link them via SPLIT_INTO.
|
827
|
+
# for i, record in enumerate(self.steps_history):
|
828
|
+
# if record.sub_questions:
|
829
|
+
# start_node = step_nodes[i]
|
830
|
+
# for sq_idx, sq in enumerate(record.sub_questions):
|
831
|
+
# sq_id = f"{global_id_prefix}_decomp_{i}_sub_{sq_idx}"
|
832
|
+
# end_node = subq_nodes[sq_id]
|
833
|
+
# rel = Relationship(
|
834
|
+
# properties={},
|
835
|
+
# rel_type=StepRelation.SPLIT_INTO,
|
836
|
+
# start_node=start_node,
|
837
|
+
# end_node=end_node,
|
838
|
+
# globalId=f"{global_id_prefix}_split_{i}_{sq_idx}",
|
839
|
+
# )
|
840
|
+
# g.add_relationship(rel)
|
841
|
+
# # Also add sub-question dependencies
|
842
|
+
# for dep in sq.depend:
|
843
|
+
# # The same record i -> sub-question subq
|
844
|
+
# if 0 <= dep < len(record.sub_questions):
|
845
|
+
# dep_id = f"{global_id_prefix}_decomp_{i}_sub_{dep}"
|
846
|
+
# if dep_id in subq_nodes:
|
847
|
+
# dep_node = subq_nodes[dep_id]
|
848
|
+
# rel_dep = Relationship(
|
849
|
+
# properties={},
|
850
|
+
# rel_type=StepRelation.DEPEND_ON,
|
851
|
+
# start_node=end_node,
|
852
|
+
# end_node=dep_node,
|
853
|
+
# globalId=f"{global_id_prefix}_dep_{i}_q_{sq_idx}_on_{dep}",
|
854
|
+
# )
|
855
|
+
# g.add_relationship(rel_dep)
|
856
|
+
|
857
|
+
# # Step D: We add PRECEDES relationships in a linear chain for the pipeline steps
|
858
|
+
# for i in range(len(self.steps_history) - 1):
|
859
|
+
# start_node = step_nodes[i]
|
860
|
+
# end_node = step_nodes[i + 1]
|
861
|
+
# rel = Relationship(
|
862
|
+
# properties={},
|
863
|
+
# rel_type=StepRelation.PRECEDES,
|
864
|
+
# start_node=start_node,
|
865
|
+
# end_node=end_node,
|
866
|
+
# globalId=f"{global_id_prefix}_precede_{i}_to_{i + 1}",
|
867
|
+
# )
|
868
|
+
# g.add_relationship(rel)
|
869
|
+
|
870
|
+
# # Step E: CRITIQUES, SELECTS, RESULT_OF can be similarly added:
|
871
|
+
# # We'll do a simple pass:
|
872
|
+
# # If step_name ends with CRITIQUE => it critiques the step before it
|
873
|
+
# for i, record in enumerate(self.steps_history):
|
874
|
+
# if "CRITIQUE" in record.step_name:
|
875
|
+
# # Let it point to the preceding step
|
876
|
+
# if i > 0:
|
877
|
+
# start_node = step_nodes[i]
|
878
|
+
# end_node = step_nodes[i - 1]
|
879
|
+
# rel = Relationship(
|
880
|
+
# properties={},
|
881
|
+
# rel_type=StepRelation.CRITIQUES,
|
882
|
+
# start_node=start_node,
|
883
|
+
# end_node=end_node,
|
884
|
+
# globalId=f"{global_id_prefix}_crit_{i}",
|
885
|
+
# )
|
886
|
+
# g.add_relationship(rel)
|
887
|
+
|
888
|
+
# # If there's a BEST_APPROACH_DECISION step, link it to the step it uses
|
889
|
+
# best_decision_idx = None
|
890
|
+
# used_step_idx = None
|
891
|
+
# for i, record in enumerate(self.steps_history):
|
892
|
+
# if record.step_name == StepName.BEST_APPROACH_DECISION and record.used:
|
893
|
+
# best_decision_idx = i
|
894
|
+
# # find the step with that name
|
895
|
+
# used_step_idx = next((j for j in step_nodes if self.steps_history[j].step_name == record.used), None)
|
896
|
+
# if used_step_idx is not None:
|
897
|
+
# rel = Relationship(
|
898
|
+
# properties={},
|
899
|
+
# rel_type=StepRelation.SELECTS,
|
900
|
+
# start_node=step_nodes[i],
|
901
|
+
# end_node=step_nodes[used_step_idx],
|
902
|
+
# globalId=f"{global_id_prefix}_select_{i}_use_{used_step_idx}",
|
903
|
+
# )
|
904
|
+
# g.add_relationship(rel)
|
905
|
+
|
906
|
+
# # And link the final answer to the best approach
|
907
|
+
# final_answer_idx = next(
|
908
|
+
# (i for i, r in enumerate(self.steps_history) if r.step_name == StepName.FINAL_ANSWER), None
|
909
|
+
# )
|
910
|
+
# if final_answer_idx is not None and best_decision_idx is not None:
|
911
|
+
# rel = Relationship(
|
912
|
+
# properties={},
|
913
|
+
# rel_type=StepRelation.RESULT_OF,
|
914
|
+
# start_node=step_nodes[final_answer_idx],
|
915
|
+
# end_node=step_nodes[best_decision_idx],
|
916
|
+
# globalId=f"{global_id_prefix}_final_{final_answer_idx}_resultof_{best_decision_idx}",
|
917
|
+
# )
|
918
|
+
# g.add_relationship(rel)
|
919
|
+
|
920
|
+
# return g
|
921
921
|
|
922
922
|
|
923
923
|
# ---------------------------------------------------------------------------------
|
@@ -944,32 +944,32 @@ class AoTStrategy(BaseStrategy):
|
|
944
944
|
msgs = self.pipeline.chatterer.client._convert_input(messages).to_messages() # type: ignore
|
945
945
|
return self.pipeline.run_pipeline(msgs)
|
946
946
|
|
947
|
-
def get_reasoning_graph(self):
|
948
|
-
|
949
|
-
|
947
|
+
# def get_reasoning_graph(self):
|
948
|
+
# """Return the AoT reasoning graph from the pipeline’s steps history."""
|
949
|
+
# return self.pipeline.get_reasoning_graph(global_id_prefix="AoT")
|
950
950
|
|
951
951
|
|
952
952
|
# ---------------------------------------------------------------------------------
|
953
953
|
# Example usage (pseudo-code)
|
954
954
|
# ---------------------------------------------------------------------------------
|
955
|
-
if __name__ == "__main__":
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
955
|
+
# if __name__ == "__main__":
|
956
|
+
# from neo4j_extension import Neo4jConnection # or your actual DB connector
|
957
|
+
|
958
|
+
# # You would create a Chatterer with your chosen LLM backend (OpenAI, etc.)
|
959
|
+
# chatterer = Chatterer.openai() # pseudo-code
|
960
|
+
# pipeline = AoTPipeline(chatterer=chatterer, max_depth=3)
|
961
|
+
# strategy = AoTStrategy(pipeline=pipeline)
|
962
|
+
|
963
|
+
# question = "Solve 5.9 = 5.11 - x. Also compare 9.11 and 9.9."
|
964
|
+
# answer = strategy.invoke(question)
|
965
|
+
# print("Final Answer:", answer)
|
966
|
+
|
967
|
+
# # Build the reasoning graph
|
968
|
+
# graph = strategy.get_reasoning_graph()
|
969
|
+
# print(f"\nGraph has {len(graph.nodes)} nodes and {len(graph.relationships)} relationships.")
|
970
|
+
|
971
|
+
# # Optionally store in Neo4j
|
972
|
+
# with Neo4jConnection() as conn:
|
973
|
+
# conn.clear_all()
|
974
|
+
# conn.upsert_graph(graph)
|
975
|
+
# print("Graph stored in Neo4j.")
|