-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathformatting.py
More file actions
153 lines (125 loc) · 5.5 KB
/
formatting.py
File metadata and controls
153 lines (125 loc) · 5.5 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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
"""
Output formatting functionality for IQ CLI.
Handles displaying answers with citations and source mapping.
"""
from typing import List
from colorama import Fore, Style, init
from search import SearchResult
from charts import ChartGenerator
# Initialize colorama for cross-platform color support
init(autoreset=True)
class OutputFormatter:
"""Handles formatting and displaying IQ output."""
def __init__(self, use_colors: bool = True, verbose: bool = False):
self.use_colors = use_colors
self.verbose = verbose
self.chart_generator = ChartGenerator(use_colors=use_colors, verbose=verbose)
def format_response(self, answer: str, search_results: List[SearchResult]) -> str:
"""
Format the complete response with answer and citations.
Args:
answer: LLM-generated answer with inline citations
search_results: List of SearchResult objects for source mapping
Returns:
Formatted response string
"""
output = []
# Add header
output.append(self._format_header("IQ Answer"))
output.append("")
# Add the synthesized answer
output.append(self._format_answer(answer))
output.append("")
# Generate and add charts if applicable
if self.verbose:
print("DEBUG: Calling chart_generator.generate_charts()")
chart_output = self.chart_generator.generate_charts(answer, search_results)
if self.verbose:
print(f"DEBUG: chart_output = {chart_output is not None}")
if chart_output:
output.append(chart_output)
output.append("")
# Add sources section
if search_results:
output.append(self._format_sources_header())
output.append("")
for i, result in enumerate(search_results, 1):
output.append(self._format_source(i, result))
output.append("")
return "\n".join(output)
def format_error(self, error_message: str) -> str:
"""Format error messages."""
if self.use_colors:
return f"{Fore.RED}Error: {error_message}{Style.RESET_ALL}"
return f"Error: {error_message}"
def format_status(self, message: str) -> str:
"""Format status messages."""
if self.use_colors:
return f"{Fore.YELLOW}⏳ {message}...{Style.RESET_ALL}"
return f"⏳ {message}..."
def format_success(self, message: str) -> str:
"""Format success messages."""
if self.use_colors:
return f"{Fore.GREEN}✓ {message}{Style.RESET_ALL}"
return f"✓ {message}"
def format_info(self, message: str) -> str:
"""Format info messages."""
if self.use_colors:
return f"{Fore.CYAN}ℹ {message}{Style.RESET_ALL}"
return f"ℹ {message}"
def _format_header(self, title: str) -> str:
"""Format the main header."""
if self.use_colors:
return f"{Fore.CYAN}{Style.BRIGHT}{'=' * 50}\n{title.center(50)}\n{'=' * 50}{Style.RESET_ALL}"
return f"{'=' * 50}\n{title.center(50)}\n{'=' * 50}"
def _format_answer(self, answer: str) -> str:
"""Format the main answer text."""
if self.use_colors:
# Highlight citations in the answer
formatted_answer = answer
# Simple highlighting of [1], [2], etc.
import re
citation_pattern = r'\[(\d+)\]'
formatted_answer = re.sub(
citation_pattern,
f'{Fore.BLUE}[\\1]{Style.RESET_ALL}',
formatted_answer
)
return formatted_answer
return answer
def _format_sources_header(self) -> str:
"""Format the sources section header."""
if self.use_colors:
return f"{Fore.MAGENTA}{Style.BRIGHT}Sources:{Style.RESET_ALL}"
return "Sources:"
def _format_source(self, number: int, result: SearchResult) -> str:
"""Format a single source entry."""
if self.use_colors:
return (f"{Fore.BLUE}[{number}]{Style.RESET_ALL} "
f"{Fore.WHITE}{Style.BRIGHT}{result.title}{Style.RESET_ALL}\n"
f" {Fore.CYAN}{result.url}{Style.RESET_ALL}\n"
f" {Fore.WHITE}{result.snippet}{Style.RESET_ALL}")
else:
return (f"[{number}] {result.title}\n"
f" {result.url}\n"
f" {result.snippet}")
def print_response(self, answer: str, search_results: List[SearchResult]):
"""Print the complete formatted response."""
print(self.format_response(answer, search_results))
def print_citations(self, search_results: List[SearchResult]):
"""Print just the citations/sources section."""
if search_results:
print(self._format_sources_header())
print()
for i, result in enumerate(search_results, 1):
print(self._format_source(i, result))
print()
def print_error(self, error_message: str):
"""Print formatted error message."""
print(self.format_error(error_message))
def print_status(self, message: str):
"""Print formatted status message."""
print(self.format_status(message))
def print_success(self, message: str):
"""Print formatted success message."""
print(self.format_success(message))