-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch.py
More file actions
130 lines (110 loc) · 3.73 KB
/
Copy pathsearch.py
File metadata and controls
130 lines (110 loc) · 3.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
from __future__ import annotations
import argparse
import sys
from search_core.config import Settings
from search_core.groq import GroqClient
from search_core.searchers import SearchScraper
from search_core.types import EvaluationResult
from search_core.workflows import SearchWorkflow
def parse_arguments() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Interactive web search assistant powered by Groq's API",
)
parser.add_argument("--api-key", help="Groq API key to use for requests")
parser.add_argument(
"--debug",
action="store_true",
default=None,
help="Enable verbose debug logging",
)
parser.add_argument(
"--max-retries",
type=int,
help="Maximum number of refinement iterations per query",
)
parser.add_argument(
"--results-per-query",
type=int,
help="Number of search results to fetch for each generated query",
)
parser.add_argument(
"--timeout",
type=float,
help="HTTP timeout (in seconds) for outbound requests",
)
parser.add_argument(
"--model",
help="Override the Groq model to use for completions",
)
parser.add_argument(
"--temperature",
type=float,
help="Set the sampling temperature for Groq completions",
)
parser.add_argument(
"--max-tokens",
type=int,
help="Set the maximum number of tokens Groq can generate",
)
return parser.parse_args()
def build_workflow(args: argparse.Namespace) -> SearchWorkflow:
settings = Settings.from_env(
groq_api_key=args.api_key,
debug_mode=args.debug,
max_retries=args.max_retries,
search_results_per_query=args.results_per_query,
request_timeout=args.timeout,
groq_model=args.model,
groq_temperature=args.temperature,
groq_max_tokens=args.max_tokens,
).require_api_key()
groq_client = GroqClient(
settings.groq_api_key,
model=settings.groq_model,
temperature=settings.groq_temperature,
max_tokens=settings.groq_max_tokens,
timeout=settings.request_timeout,
)
searcher = SearchScraper(settings)
return SearchWorkflow(
settings=settings,
groq_client=groq_client,
searcher=searcher,
tolerant_evaluation=False,
)
def print_progress(evaluation: EvaluationResult, attempt: int) -> None:
reason = evaluation.reason or "Trying a different approach..."
print(f"✗ Attempt {attempt}: {reason}")
def run_interactive(workflow: SearchWorkflow) -> int:
print("Type 'quit' or 'exit' to leave the assistant.\n")
while True:
try:
query = input("❖ Query: ").strip()
except (EOFError, KeyboardInterrupt):
print("\nGoodbye!")
return 0
if not query:
continue
if query.lower() in {"quit", "exit"}:
print("Goodbye!")
return 0
result = workflow.answer_query(query, progress_callback=print_progress)
answer = result.answer or "No suitable answer could be produced."
if result.evaluation.satisfactory:
print(f"⌾ {answer}\n")
else:
# Provide whatever best answer we have even if not marked satisfactory.
if result.answers_history:
print(f"⌾ {answer}\n")
else:
print("✗ Unable to find a satisfactory answer.\n")
def main() -> int:
args = parse_arguments()
try:
workflow = build_workflow(args)
except RuntimeError as exc:
print(str(exc), file=sys.stderr)
return 1
return run_interactive(workflow)
if __name__ == "__main__":
raise SystemExit(main())