dolphinium
commited on
Commit
Β·
dae6a10
1
Parent(s):
131ad34
dynamic core selection according to agentic api's output.
Browse files- data_processing.py +51 -35
- extract_results.py +52 -13
- llm_prompts.py +6 -3
- ui.py +59 -30
data_processing.py
CHANGED
@@ -40,32 +40,50 @@ def parse_suggestions_from_report(report_text):
|
|
40 |
|
41 |
|
42 |
def llm_generate_analysis_plan_with_history(llm_model, natural_language_query, chat_history):
|
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 |
|
@@ -79,17 +97,15 @@ def execute_quantitative_query(solr_client, plan):
|
|
79 |
"rows": 0,
|
80 |
"json.facet": json.dumps(plan['quantitative_request']['json.facet'])
|
81 |
}
|
82 |
-
|
83 |
-
|
84 |
-
base_url = "http://69.167.186.48:8983/solr/news/select"
|
85 |
query_string = urllib.parse.urlencode(params)
|
86 |
full_url = f"{base_url}?{query_string}"
|
87 |
-
|
88 |
-
print(f"[DEBUG] Solr QUANTITIVE query URL: {full_url}")
|
89 |
results = solr_client.search(**params)
|
90 |
return results.raw_response.get("facets", {}), full_url
|
91 |
except Exception as e:
|
92 |
-
print(f"Error in quantitative query: {e}")
|
93 |
return None, None
|
94 |
|
95 |
def execute_qualitative_query(solr_client, plan):
|
@@ -104,15 +120,15 @@ def execute_qualitative_query(solr_client, plan):
|
|
104 |
"fl": "*,score",
|
105 |
**qual_request
|
106 |
}
|
107 |
-
|
|
|
108 |
query_string = urllib.parse.urlencode(params)
|
109 |
full_url = f"{base_url}?{query_string}"
|
110 |
-
|
111 |
print(f"[DEBUG] Solr QUALITATIVE query URL: {full_url}")
|
112 |
results = solr_client.search(**params)
|
113 |
return results.grouped, full_url
|
114 |
except Exception as e:
|
115 |
-
print(f"Error in qualitative query: {e}")
|
116 |
return None, None
|
117 |
|
118 |
def llm_synthesize_enriched_report_stream(llm_model, query, quantitative_data, qualitative_data, plan):
|
|
|
40 |
|
41 |
|
42 |
def llm_generate_analysis_plan_with_history(llm_model, natural_language_query, chat_history):
|
43 |
+
"""
|
44 |
+
Generates a complete analysis plan from a user query, considering chat history
|
45 |
+
and dynamic field suggestions from an external API.
|
46 |
+
"""
|
47 |
+
search_fields, search_name, field_mappings = [], "", {}
|
48 |
+
try:
|
49 |
+
# Call the external API to get dynamic fields, core name, and mappings
|
50 |
+
search_fields, search_name, field_mappings = get_search_list_params(natural_language_query)
|
51 |
+
print(f"API returned core: '{search_name}' with {len(search_fields)} fields and {len(field_mappings)} mappings.")
|
52 |
+
except Exception as e:
|
53 |
+
print(f"Warning: Could not retrieve dynamic search fields. Proceeding without them. Error: {e}")
|
54 |
+
|
55 |
+
# Determine the core name, default to 'news' if not provided by the API
|
56 |
+
core_name = search_name if search_name else 'news'
|
57 |
+
|
58 |
+
# Apply the field mappings to the suggestions before sending them to the LLM
|
59 |
+
mapped_search_fields = []
|
60 |
+
if search_fields and field_mappings:
|
61 |
+
for field in search_fields:
|
62 |
+
original_name = field.get('field_name')
|
63 |
+
# Create a new dict to avoid modifying the original
|
64 |
+
mapped_field = field.copy()
|
65 |
+
if original_name in field_mappings:
|
66 |
+
mapped_field['field_name'] = field_mappings[original_name]
|
67 |
+
print(f"Mapped field '{original_name}' to '{mapped_field['field_name']}'")
|
68 |
+
mapped_search_fields.append(mapped_field)
|
69 |
+
else:
|
70 |
+
mapped_search_fields = search_fields
|
71 |
+
|
72 |
+
|
73 |
+
# Generate the prompt, passing the mapped fields and the dynamic core name
|
74 |
+
prompt = get_analysis_plan_prompt(natural_language_query, chat_history, mapped_search_fields, core_name)
|
75 |
+
|
76 |
+
try:
|
77 |
+
response = llm_model.generate_content(prompt)
|
78 |
+
cleaned_text = re.sub(r'```json\s*|\s*```', '', response.text, flags=re.MULTILINE | re.DOTALL).strip()
|
79 |
+
plan = json.loads(cleaned_text)
|
80 |
+
# Return the plan, the mapped fields for UI display, and the core name
|
81 |
+
return plan, mapped_search_fields, core_name
|
82 |
+
except Exception as e:
|
83 |
+
raw_response_text = response.text if 'response' in locals() else 'N/A'
|
84 |
+
print(f"Error in llm_generate_analysis_plan_with_history: {e}\nRaw Response:\n{raw_response_text}")
|
85 |
+
# Return None for the plan but still return other data for debugging
|
86 |
+
return None, mapped_search_fields, core_name
|
87 |
|
88 |
|
89 |
|
|
|
97 |
"rows": 0,
|
98 |
"json.facet": json.dumps(plan['quantitative_request']['json.facet'])
|
99 |
}
|
100 |
+
# Build the full Solr URL manually (for logging) from the client's current URL
|
101 |
+
base_url = f"{solr_client.url}/select"
|
|
|
102 |
query_string = urllib.parse.urlencode(params)
|
103 |
full_url = f"{base_url}?{query_string}"
|
104 |
+
print(f"[DEBUG] Solr QUANTITATIVE query URL: {full_url}")
|
|
|
105 |
results = solr_client.search(**params)
|
106 |
return results.raw_response.get("facets", {}), full_url
|
107 |
except Exception as e:
|
108 |
+
print(f"Error in quantitative query on core specified in client ({solr_client.url}): {e}")
|
109 |
return None, None
|
110 |
|
111 |
def execute_qualitative_query(solr_client, plan):
|
|
|
120 |
"fl": "*,score",
|
121 |
**qual_request
|
122 |
}
|
123 |
+
# Build the full Solr URL manually (for logging) from the client's current URL
|
124 |
+
base_url = f"{solr_client.url}/select"
|
125 |
query_string = urllib.parse.urlencode(params)
|
126 |
full_url = f"{base_url}?{query_string}"
|
|
|
127 |
print(f"[DEBUG] Solr QUALITATIVE query URL: {full_url}")
|
128 |
results = solr_client.search(**params)
|
129 |
return results.grouped, full_url
|
130 |
except Exception as e:
|
131 |
+
print(f"Error in qualitative query on core specified in client ({solr_client.url}): {e}")
|
132 |
return None, None
|
133 |
|
134 |
def llm_synthesize_enriched_report_stream(llm_model, query, quantitative_data, qualitative_data, plan):
|
extract_results.py
CHANGED
@@ -1,28 +1,67 @@
|
|
1 |
import requests
|
2 |
import json
|
3 |
import yaml
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
|
5 |
def get_search_list_params(query, k=20):
|
6 |
"""
|
7 |
-
|
|
|
|
|
|
|
8 |
"""
|
9 |
url = "https://aitest.ebalina.com/stream"
|
10 |
|
11 |
-
response = requests.post(
|
12 |
-
|
13 |
-
|
14 |
-
|
|
|
|
|
15 |
|
|
|
|
|
|
|
|
|
16 |
for line in response.iter_lines():
|
17 |
if line and line.startswith(b'data: '):
|
18 |
try:
|
19 |
-
|
20 |
-
if
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
continue
|
26 |
|
27 |
-
|
28 |
-
|
|
|
|
1 |
import requests
|
2 |
import json
|
3 |
import yaml
|
4 |
+
import re
|
5 |
+
|
6 |
+
def _parse_mappings(mapping_str: str) -> dict:
|
7 |
+
"""Parses the field mapping string into a dictionary."""
|
8 |
+
mappings = {}
|
9 |
+
if not mapping_str:
|
10 |
+
return mappings
|
11 |
+
# Example line: "Mapping 'company_territory' to 'owner_company_territory' under 'compound'."
|
12 |
+
pattern = re.compile(r"Mapping '([^']*)' to '([^']*)'")
|
13 |
+
for line in mapping_str.split('\n'):
|
14 |
+
match = pattern.search(line)
|
15 |
+
if match:
|
16 |
+
original_field, mapped_field = match.groups()
|
17 |
+
mappings[original_field] = mapped_field
|
18 |
+
return mappings
|
19 |
|
20 |
def get_search_list_params(query, k=20):
|
21 |
"""
|
22 |
+
Connects to the external API, parses the stream, and returns the core name,
|
23 |
+
search fields, and field mappings.
|
24 |
+
|
25 |
+
Returns tuple: (search_fields, search_name, field_mappings)
|
26 |
"""
|
27 |
url = "https://aitest.ebalina.com/stream"
|
28 |
|
29 |
+
response = requests.post(
|
30 |
+
url,
|
31 |
+
headers={'Content-Type': 'application/json'},
|
32 |
+
json={"query": query, "k": k},
|
33 |
+
stream=True
|
34 |
+
)
|
35 |
|
36 |
+
search_fields = []
|
37 |
+
search_name = ""
|
38 |
+
field_mappings_str = ""
|
39 |
+
|
40 |
for line in response.iter_lines():
|
41 |
if line and line.startswith(b'data: '):
|
42 |
try:
|
43 |
+
line_str = line.decode('utf-8')[6:]
|
44 |
+
if not line_str or line_str.isspace():
|
45 |
+
continue
|
46 |
+
|
47 |
+
data = json.loads(line_str)
|
48 |
+
log_title = data.get('log_title')
|
49 |
+
|
50 |
+
if log_title == 'Search List Result':
|
51 |
+
content = data.get('content', '')
|
52 |
+
if content:
|
53 |
+
yaml_data = yaml.safe_load(content)
|
54 |
+
print("DEBUG:", yaml_data)
|
55 |
+
# This is the dynamic core name
|
56 |
+
search_name = yaml_data.get('search_name', '')
|
57 |
+
search_fields = yaml_data.get('search_fields', [])
|
58 |
+
|
59 |
+
elif log_title == 'Field Mapping Outputs':
|
60 |
+
field_mappings_str = data.get('content', '')
|
61 |
+
|
62 |
+
except (json.JSONDecodeError, yaml.YAMLError, AttributeError):
|
63 |
continue
|
64 |
|
65 |
+
field_mappings = _parse_mappings(field_mappings_str)
|
66 |
+
|
67 |
+
return search_fields, search_name, field_mappings
|
llm_prompts.py
CHANGED
@@ -11,15 +11,17 @@ import datetime
|
|
11 |
import json
|
12 |
from solr_metadata import format_metadata_for_prompt
|
13 |
|
14 |
-
def get_analysis_plan_prompt(natural_language_query, chat_history, search_fields=None):
|
15 |
"""
|
16 |
Generates the prompt for creating a Solr analysis plan from a user query.
|
17 |
Args:
|
18 |
natural_language_query (str): The user's query.
|
19 |
chat_history (list): A list of previous user and bot messages.
|
20 |
search_fields (list, optional): A list of dictionaries with 'field_name' and 'field_value'.
|
|
|
21 |
"""
|
22 |
-
|
|
|
23 |
formatted_history = ""
|
24 |
for user_msg, bot_msg in chat_history:
|
25 |
if user_msg:
|
@@ -27,6 +29,7 @@ def get_analysis_plan_prompt(natural_language_query, chat_history, search_fields
|
|
27 |
|
28 |
dynamic_fields_prompt_section = ""
|
29 |
if search_fields:
|
|
|
30 |
formatted_fields = "\n".join([f" - {field['field_name']}: {field['field_value']}" for field in search_fields])
|
31 |
dynamic_fields_prompt_section = f"""
|
32 |
---
|
@@ -84,7 +87,7 @@ This is the most critical part of your task. A bad choice leads to a useless, bo
|
|
84 |
* **IMPLICIT COUNT:** If the user asks a "what," "who," "how many," or "most common" question without specifying a value metric, the measure is `count`.
|
85 |
|
86 |
---
|
87 |
-
### FIELD DEFINITIONS (Your Source of Truth)
|
88 |
|
89 |
{formatted_field_info}
|
90 |
{dynamic_fields_prompt_section}
|
|
|
11 |
import json
|
12 |
from solr_metadata import format_metadata_for_prompt
|
13 |
|
14 |
+
def get_analysis_plan_prompt(natural_language_query, chat_history, search_fields=None, core_name="news"):
|
15 |
"""
|
16 |
Generates the prompt for creating a Solr analysis plan from a user query.
|
17 |
Args:
|
18 |
natural_language_query (str): The user's query.
|
19 |
chat_history (list): A list of previous user and bot messages.
|
20 |
search_fields (list, optional): A list of dictionaries with 'field_name' and 'field_value'.
|
21 |
+
core_name (str): The name of the Solr core to use for field metadata.
|
22 |
"""
|
23 |
+
# Dynamically get field info for the specified core
|
24 |
+
formatted_field_info = format_metadata_for_prompt(core_name)
|
25 |
formatted_history = ""
|
26 |
for user_msg, bot_msg in chat_history:
|
27 |
if user_msg:
|
|
|
29 |
|
30 |
dynamic_fields_prompt_section = ""
|
31 |
if search_fields:
|
32 |
+
# The search_fields are now pre-mapped, so we can use them directly
|
33 |
formatted_fields = "\n".join([f" - {field['field_name']}: {field['field_value']}" for field in search_fields])
|
34 |
dynamic_fields_prompt_section = f"""
|
35 |
---
|
|
|
87 |
* **IMPLICIT COUNT:** If the user asks a "what," "who," "how many," or "most common" question without specifying a value metric, the measure is `count`.
|
88 |
|
89 |
---
|
90 |
+
### FIELD DEFINITIONS (Your Source of Truth for Core: {core_name})
|
91 |
|
92 |
{formatted_field_info}
|
93 |
{dynamic_fields_prompt_section}
|
ui.py
CHANGED
@@ -21,6 +21,7 @@ from data_processing import (
|
|
21 |
parse_suggestions_from_report
|
22 |
)
|
23 |
|
|
|
24 |
def create_ui(llm_model, solr_client):
|
25 |
"""
|
26 |
Builds the Gradio UI and wires up all the event handlers.
|
@@ -36,28 +37,39 @@ def create_ui(llm_model, solr_client):
|
|
36 |
with gr.Column(scale=4):
|
37 |
gr.Markdown("# PharmaCircle AI Data Analyst")
|
38 |
with gr.Column(scale=1):
|
39 |
-
clear_button = gr.Button(
|
|
|
40 |
|
41 |
gr.Markdown("Ask a question to begin your analysis. I will generate an analysis plan, retrieve quantitative and qualitative data, create a visualization, and write an enriched report.")
|
42 |
|
43 |
with gr.Row():
|
44 |
with gr.Column(scale=1):
|
45 |
-
chatbot = gr.Chatbot(
|
46 |
-
|
|
|
|
|
47 |
|
48 |
with gr.Column(scale=2):
|
49 |
with gr.Accordion("Dynamic Field Suggestions", open=False):
|
50 |
-
suggestions_display = gr.Markdown(
|
|
|
51 |
with gr.Accordion("Generated Analysis Plan", open=False):
|
52 |
-
plan_display = gr.Markdown(
|
|
|
53 |
with gr.Accordion("Retrieved Quantitative Data", open=False):
|
54 |
-
quantitative_url_display = gr.Markdown(
|
55 |
-
|
|
|
|
|
56 |
with gr.Accordion("Retrieved Qualitative Data (Examples)", open=False):
|
57 |
-
qualitative_url_display = gr.Markdown(
|
58 |
-
|
59 |
-
|
60 |
-
|
|
|
|
|
|
|
|
|
61 |
|
62 |
def process_analysis_flow(user_input, history, state):
|
63 |
"""
|
@@ -80,12 +92,12 @@ def create_ui(llm_model, solr_client):
|
|
80 |
history.append((user_input, f"Analyzing: '{query_context}'\n\n*Generating analysis plan...*"))
|
81 |
yield (history, state, None, None, None, None, None, None, None, None)
|
82 |
|
83 |
-
# Generate plan and get search field suggestions
|
84 |
-
analysis_plan,
|
85 |
|
86 |
# Update and display search field suggestions in its own accordion
|
87 |
-
if
|
88 |
-
suggestions_md = "**
|
89 |
suggestions_display_update = gr.update(value=suggestions_md, visible=True)
|
90 |
else:
|
91 |
suggestions_display_update = gr.update(value="No suggestions were returned from the external API.", visible=True)
|
@@ -95,30 +107,45 @@ def create_ui(llm_model, solr_client):
|
|
95 |
yield (history, state, None, None, None, None, None, None, None, suggestions_display_update)
|
96 |
return
|
97 |
|
98 |
-
history.append((None, "β
Analysis plan generated
|
99 |
plan_summary = f"""
|
100 |
-
* **Analysis Dimension:** `{analysis_plan.get('analysis_dimension')}`
|
101 |
-
* **Analysis Measure:** `{analysis_plan.get('analysis_measure')}`
|
102 |
-
* **Query Filter:** `{analysis_plan.get('query_filter')}`
|
103 |
-
"""
|
104 |
history.append((None, plan_summary))
|
105 |
-
formatted_plan = f"**Full Analysis Plan:**\n```json\n{json.dumps(analysis_plan, indent=2)}\n```"
|
106 |
yield (history, state, None, None, gr.update(value=formatted_plan, visible=True), None, None, None, None, suggestions_display_update)
|
107 |
|
108 |
history.append((None, "*Executing queries for aggregates and examples...*"))
|
109 |
yield (history, state, None, None, gr.update(value=formatted_plan, visible=True), None, None, None, None, suggestions_display_update)
|
110 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
111 |
# Execute queries in parallel
|
112 |
aggregate_data, quantitative_url = None, None
|
113 |
example_data, qualitative_url = None, None
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
119 |
|
120 |
if not aggregate_data or aggregate_data.get('count', 0) == 0:
|
121 |
-
history.append((None, "No data was found for your query. Please try a different question."))
|
122 |
yield (history, state, None, None, gr.update(value=formatted_plan, visible=True), None, None, None, None, suggestions_display_update)
|
123 |
return
|
124 |
|
@@ -178,7 +205,8 @@ def create_ui(llm_model, solr_client):
|
|
178 |
msg_textbox.submit(
|
179 |
fn=process_analysis_flow,
|
180 |
inputs=[msg_textbox, chatbot, state],
|
181 |
-
outputs=[chatbot, state, plot_display, report_display, plan_display, quantitative_url_display,
|
|
|
182 |
).then(
|
183 |
lambda: gr.update(value=""),
|
184 |
None,
|
@@ -189,8 +217,9 @@ def create_ui(llm_model, solr_client):
|
|
189 |
clear_button.click(
|
190 |
fn=reset_all,
|
191 |
inputs=None,
|
192 |
-
outputs=[chatbot, state, msg_textbox, plot_display, report_display, plan_display, quantitative_url_display,
|
|
|
193 |
queue=False
|
194 |
)
|
195 |
|
196 |
-
return demo
|
|
|
21 |
parse_suggestions_from_report
|
22 |
)
|
23 |
|
24 |
+
|
25 |
def create_ui(llm_model, solr_client):
|
26 |
"""
|
27 |
Builds the Gradio UI and wires up all the event handlers.
|
|
|
37 |
with gr.Column(scale=4):
|
38 |
gr.Markdown("# PharmaCircle AI Data Analyst")
|
39 |
with gr.Column(scale=1):
|
40 |
+
clear_button = gr.Button(
|
41 |
+
"π Start New Analysis", variant="primary")
|
42 |
|
43 |
gr.Markdown("Ask a question to begin your analysis. I will generate an analysis plan, retrieve quantitative and qualitative data, create a visualization, and write an enriched report.")
|
44 |
|
45 |
with gr.Row():
|
46 |
with gr.Column(scale=1):
|
47 |
+
chatbot = gr.Chatbot(
|
48 |
+
label="Analysis Chat Log", height=700, show_copy_button=True)
|
49 |
+
msg_textbox = gr.Textbox(
|
50 |
+
placeholder="Ask a question, e.g., 'Show me the top 5 companies by total deal value in 2023'", label="Your Question", interactive=True)
|
51 |
|
52 |
with gr.Column(scale=2):
|
53 |
with gr.Accordion("Dynamic Field Suggestions", open=False):
|
54 |
+
suggestions_display = gr.Markdown(
|
55 |
+
"Suggestions from the external API will appear here...", visible=True)
|
56 |
with gr.Accordion("Generated Analysis Plan", open=False):
|
57 |
+
plan_display = gr.Markdown(
|
58 |
+
"Plan will appear here...", visible=True)
|
59 |
with gr.Accordion("Retrieved Quantitative Data", open=False):
|
60 |
+
quantitative_url_display = gr.Markdown(
|
61 |
+
"Quantitative URL will appear here...", visible=False)
|
62 |
+
quantitative_data_display = gr.Markdown(
|
63 |
+
"Aggregate data will appear here...", visible=False)
|
64 |
with gr.Accordion("Retrieved Qualitative Data (Examples)", open=False):
|
65 |
+
qualitative_url_display = gr.Markdown(
|
66 |
+
"Qualitative URL will appear here...", visible=False)
|
67 |
+
qualitative_data_display = gr.Markdown(
|
68 |
+
"Example data will appear here...", visible=False)
|
69 |
+
plot_display = gr.Image(
|
70 |
+
label="Visualization", type="filepath", visible=False)
|
71 |
+
report_display = gr.Markdown(
|
72 |
+
"Report will be streamed here...", visible=False)
|
73 |
|
74 |
def process_analysis_flow(user_input, history, state):
|
75 |
"""
|
|
|
92 |
history.append((user_input, f"Analyzing: '{query_context}'\n\n*Generating analysis plan...*"))
|
93 |
yield (history, state, None, None, None, None, None, None, None, None)
|
94 |
|
95 |
+
# Generate plan and get search field suggestions. This now returns the core name.
|
96 |
+
analysis_plan, mapped_search_fields, core_name = llm_generate_analysis_plan_with_history(llm_model, query_context, history)
|
97 |
|
98 |
# Update and display search field suggestions in its own accordion
|
99 |
+
if mapped_search_fields:
|
100 |
+
suggestions_md = "**API Suggestions (with mappings applied):**\n" + "\n".join([f"- `{field['field_name']}`: `{field['field_value']}`" for field in mapped_search_fields])
|
101 |
suggestions_display_update = gr.update(value=suggestions_md, visible=True)
|
102 |
else:
|
103 |
suggestions_display_update = gr.update(value="No suggestions were returned from the external API.", visible=True)
|
|
|
107 |
yield (history, state, None, None, None, None, None, None, None, suggestions_display_update)
|
108 |
return
|
109 |
|
110 |
+
history.append((None, f"β
Analysis plan generated for core: **`{core_name}`**"))
|
111 |
plan_summary = f"""
|
112 |
+
* **Analysis Dimension:** `{analysis_plan.get('analysis_dimension')}`
|
113 |
+
* **Analysis Measure:** `{analysis_plan.get('analysis_measure')}`
|
114 |
+
* **Query Filter:** `{analysis_plan.get('query_filter')}`
|
115 |
+
"""
|
116 |
history.append((None, plan_summary))
|
117 |
+
formatted_plan = f"**Full Analysis Plan (Core: `{core_name}`):**\n```json\n{json.dumps(analysis_plan, indent=2)}\n```"
|
118 |
yield (history, state, None, None, gr.update(value=formatted_plan, visible=True), None, None, None, None, suggestions_display_update)
|
119 |
|
120 |
history.append((None, "*Executing queries for aggregates and examples...*"))
|
121 |
yield (history, state, None, None, gr.update(value=formatted_plan, visible=True), None, None, None, None, suggestions_display_update)
|
122 |
|
123 |
+
# --- DYNAMIC CORE SWITCH (Thread-safe) ---
|
124 |
+
original_solr_url = solr_client.url
|
125 |
+
# Correctly construct the new URL by replacing the last component (the core name)
|
126 |
+
base_url = original_solr_url.rsplit('/', 1)[0]
|
127 |
+
new_url = f"{base_url}/{core_name}"
|
128 |
+
solr_client.url = new_url
|
129 |
+
print(f"[INFO] Switched Solr client to core: {core_name} at URL: {solr_client.url}")
|
130 |
+
# ---
|
131 |
+
|
132 |
# Execute queries in parallel
|
133 |
aggregate_data, quantitative_url = None, None
|
134 |
example_data, qualitative_url = None, None
|
135 |
+
try:
|
136 |
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
137 |
+
future_agg = executor.submit(execute_quantitative_query, solr_client, analysis_plan)
|
138 |
+
future_ex = executor.submit(execute_qualitative_query, solr_client, analysis_plan)
|
139 |
+
aggregate_data, quantitative_url = future_agg.result()
|
140 |
+
example_data, qualitative_url = future_ex.result()
|
141 |
+
finally:
|
142 |
+
# --- IMPORTANT: Reset client to default URL ---
|
143 |
+
solr_client.url = original_solr_url
|
144 |
+
print(f"[INFO] Reset Solr client to default URL: {original_solr_url}")
|
145 |
+
# ---
|
146 |
|
147 |
if not aggregate_data or aggregate_data.get('count', 0) == 0:
|
148 |
+
history.append((None, f"No data was found for your query in the '{core_name}' core. Please try a different question."))
|
149 |
yield (history, state, None, None, gr.update(value=formatted_plan, visible=True), None, None, None, None, suggestions_display_update)
|
150 |
return
|
151 |
|
|
|
205 |
msg_textbox.submit(
|
206 |
fn=process_analysis_flow,
|
207 |
inputs=[msg_textbox, chatbot, state],
|
208 |
+
outputs=[chatbot, state, plot_display, report_display, plan_display, quantitative_url_display,
|
209 |
+
quantitative_data_display, qualitative_url_display, qualitative_data_display, suggestions_display],
|
210 |
).then(
|
211 |
lambda: gr.update(value=""),
|
212 |
None,
|
|
|
217 |
clear_button.click(
|
218 |
fn=reset_all,
|
219 |
inputs=None,
|
220 |
+
outputs=[chatbot, state, msg_textbox, plot_display, report_display, plan_display, quantitative_url_display,
|
221 |
+
quantitative_data_display, qualitative_url_display, qualitative_data_display, suggestions_display],
|
222 |
queue=False
|
223 |
)
|
224 |
|
225 |
+
return demo
|