Skip to content

Commit eebe31a

Browse files
authored
[deploy] Merge pull request #226 from microsoft/dev
Live data now goes into data formulator!
2 parents 7b6fd1a + 6c3abf3 commit eebe31a

61 files changed

Lines changed: 8775 additions & 3654 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.devcontainer/devcontainer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
// "forwardPorts": [],
1818

1919
// Use 'postCreateCommand' to run commands after the container is created.
20-
"postCreateCommand": "python3 -m venv /workspaces/data-formulator/venv && . /workspaces/data-formulator/venv/bin/activate && pip install https://github.com/user-attachments/files/17319752/data_formulator-0.1.0.tar.gz --verbose && data_formulator"
20+
"postCreateCommand": "cd /workspaces/data-formulator && npm install && npm run build && python3 -m venv /workspaces/data-formulator/venv && . /workspaces/data-formulator/venv/bin/activate && pip install -e /workspaces/data-formulator --verbose && data_formulator"
2121

2222
// Configure tool-specific properties.
2323
// "customizations": {},

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
.DS_Store
66
build/
77
dist/
8+
experiment_data/
89

910
## Ignore Visual Studio temporary files, build results, and
1011
## files generated by popular Visual Studio add-ons.
@@ -405,3 +406,7 @@ FodyWeavers.xsd
405406
# JetBrains Rider
406407
*.sln.iml
407408
venv
409+
410+
411+
\.\NUL
412+
NUL

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ https://github.com/user-attachments/assets/8ca57b68-4d7a-42cb-bcce-43f8b1681ce2
3232

3333

3434
## News 🔥🔥🔥
35+
[01-25-2025] **Data Formulator 0.6** — Real-time insights from live data
36+
-**Connect to live data**: Connect to URLs and databases with automatic refresh intervals. Visualizations update automatically as your data changes to provide you live insights. [Demo: track international space station position speed live](https://github.com/microsoft/data-formulator/releases/tag/0.6)
37+
- 🎨 **UI Updates**: Unified UI for data loading; direct drag-and-drop fields from the data table to update visualization designs.
38+
3539
[12-08-2025] **Data Formulator 0.5.1** — Connect more, visualize more, move faster
3640
- 🔌 **Community data loaders**: Google BigQuery, MySQL, Postgres, MongoDB
3741
- 📊 **New chart types**: US Map & Pie Chart (more to be added soon)
@@ -41,10 +45,7 @@ https://github.com/user-attachments/assets/8ca57b68-4d7a-42cb-bcce-43f8b1681ce2
4145
[11-07-2025] Data Formulator 0.5: Vibe with your data, in control
4246

4347
- 📊 **Load (almost) any data**: load structured data, extract data from screenshots, from messy text blocks, or connect to databases.
44-
- 🤖 **Explore data with AI agents**:
45-
- In agent mode, provide a high-level goal and ask agents to explore data for you.
46-
- To stay in control, directly interact with agents: ask for recommendations or specify chart designs with UI + NL inputs, and AI agents will formulate data to realize your design.
47-
- Use data threads to control branching exploration paths: backtrack, branch, or follow up.
48+
- 🤖 **Explore data with AI agents**: Use agent mode for hands-off exploration, or stay in control in interactive mode.
4849
-**Verify AI generated results**: interact with charts and inspect data, formulas, explanations, and code.
4950
- 📝 **Create reports to share insights**: choose charts you want to share, and ask agents to create reports grounded in data formulated throughout exploration.
5051

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"html2canvas": "^1.4.1",
2121
"katex": "^0.16.22",
2222
"localforage": "^1.10.0",
23-
"lodash": "^4.17.21",
23+
"lodash": "^4.17.23",
2424
"markdown-to-jsx": "^7.4.0",
2525
"mui-markdown": "^2.0.3",
2626
"prettier": "^2.8.3",
@@ -46,7 +46,7 @@
4646
"validator": "^13.15.20",
4747
"vega": "^6.2.0",
4848
"vega-embed": "^6.21.0",
49-
"vega-lite": "^5.5.0",
49+
"vega-lite": "6.4.1",
5050
"vm-browserify": "^1.1.2"
5151
},
5252
"scripts": {

public/df_stock_prices_live.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.
9.46 KB
Loading

py-src/data_formulator/agent_routes.py

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
from data_formulator.agents.agent_data_clean import DataCleanAgent
3232
from data_formulator.agents.agent_data_clean_stream import DataCleanAgentStream
3333
from data_formulator.agents.agent_code_explanation import CodeExplanationAgent
34-
from data_formulator.agents.agent_query_completion import QueryCompletionAgent
3534
from data_formulator.agents.agent_interactive_explore import InteractiveExploreAgent
3635
from data_formulator.agents.agent_report_gen import ReportGenAgent
3736
from data_formulator.agents.client_utils import Client
@@ -614,26 +613,6 @@ def request_code_expl():
614613
else:
615614
return jsonify({'error': 'Invalid request format'}), 400
616615

617-
@agent_bp.route('/query-completion', methods=['POST'])
618-
def query_completion():
619-
if request.is_json:
620-
logger.info("# request data: ")
621-
content = request.get_json()
622-
623-
client = get_client(content['model'])
624-
625-
data_source_metadata = content["data_source_metadata"]
626-
query = content["query"]
627-
628-
query_completion_agent = QueryCompletionAgent(client=client)
629-
reasoning, query = query_completion_agent.run(data_source_metadata, query)
630-
response = flask.jsonify({ "token": "", "status": "ok", "reasoning": reasoning, "query": query })
631-
else:
632-
response = flask.jsonify({ "token": "", "status": "error", "reasoning": "unable to complete query", "query": "" })
633-
634-
response.headers.add('Access-Control-Allow-Origin', '*')
635-
return response
636-
637616
@agent_bp.route('/get-recommendation-questions', methods=['GET', 'POST'])
638617
def get_recommendation_questions():
639618
def generate():

py-src/data_formulator/agents/agent_exploration.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import base64
77

88
from data_formulator.agents.agent_utils import extract_json_objects, generate_data_summary
9-
from data_formulator.agents.agent_sql_data_transform import get_sql_table_statistics_str, sanitize_table_name
9+
from data_formulator.agents.agent_sql_data_transform import generate_sql_data_summary
1010

1111
logger = logging.getLogger(__name__)
1212

@@ -151,11 +151,7 @@ def get_chart_message(self, visualization):
151151

152152
def get_data_summary(self, input_tables):
153153
if self.db_conn:
154-
data_summary = ""
155-
for table in input_tables:
156-
table_name = sanitize_table_name(table['name'])
157-
table_summary_str = get_sql_table_statistics_str(self.db_conn, table_name)
158-
data_summary += f"[TABLE {table_name}]\n\n{table_summary_str}\n\n"
154+
data_summary = generate_sql_data_summary(self.db_conn, input_tables)
159155
else:
160156
data_summary = generate_data_summary(input_tables)
161157
return data_summary

py-src/data_formulator/agents/agent_interactive_explore.py

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,35 @@
66
import pandas as pd
77

88
from data_formulator.agents.agent_utils import extract_json_objects, generate_data_summary
9-
from data_formulator.agents.agent_sql_data_transform import get_sql_table_statistics_str, sanitize_table_name
9+
from data_formulator.agents.agent_sql_data_transform import generate_sql_data_summary
1010

1111
logger = logging.getLogger(__name__)
1212

1313
SYSTEM_PROMPT = '''You are a data exploration expert who suggests interesting questions to help users explore their datasets.
1414
15-
Given a dataset (or a thread of datasets that have been explored), your task is to suggest 4 exploration questions (unless the user explicitly asks for the number of questions), that users can follow to gain insights from their data.
16-
* the user may provide you current explorations they have done, including:
17-
- a thread of exploration questions they have explored
18-
- the latest data sample they are viewing
19-
- the current chart they are viewing
20-
* when the exploration context is provided, make your suggestion based on the context as well as the original dataset; otherwise leverage the original dataset to suggest questions.
15+
This prompt contains the following sections:
16+
- [DATASETS] section: available datasets the user is working with.
17+
- [EXPLORATION THREAD] section (optional): sequence of datasets that have been explored in the order they were created, and what questions are asked to create them. These tables are all created from tables in the [DATASETS] section.
18+
- [CURRENT DATA] section (optional): latest data sample the user is viewing, and the visualization they are looking at at the moment.
19+
- [START QUESTION] section (optional): start question from previous exploration steps for context
20+
21+
Your task is to suggest 4 exploration questions (unless the user explicitly asks for the number of questions), that users can follow to gain insights from their data.
22+
When the exploration context is provided, make your suggestion based on the context as well as the original datasets; otherwise leverage the original datasets to suggest questions.
2123
2224
Guidelines for question suggestions:
23-
1. Suggest interesting analytical questions that are not obvious that can uncover nontrivial insights
24-
2. Use a diverse language style to display the questions (can be questions, statements etc)
25-
3. If there are multiple datasets in a thread, consider relationships between them
25+
1. Suggest interesting analytical questions that can uncover new insights from the data.
26+
2. Use a diverse language style to display the questions (can be questions, statements etc).
27+
3. If there are multiple datasets in a thread, consider relationships between them.
2628
4. CONCISENESS: the questions should be concise and to the point
27-
5. QUESTION: the question should be a new question based on the thread of exploration:
28-
- either a followup question, or a new question that is related to the thread
29+
5. QUESTION: the question should be a new question based on the exploration thread:
30+
- if no exploration thread is provided, start with a high-level overview question that directly visualizes the data to give the user a sense of the data.
31+
- either a followup question, or a new question that is related to the exploration thread
2932
- if the current data is rich, you can ask a followup question to further explore the dataset;
3033
- if the current data is already specialized to answer the previous question, you can ask a new question that is related to the thread but not related to the previous question in the thread, leverage earlier exploration data to ask questions that can expand the exploration horizon
3134
- do not repeat questions that have already been explored in the thread
3235
- do not suggest questions that are not related to the thread (e.g. questions that are completely unrelated to the exploration direction in the thread)
3336
- do not naively follow up if the question is already too low-level when previous iterations have already come into a small subset of the data (suggest new related areas related to the metric / attributes etc)
37+
- leverage other datasets in the [DATASETS] section to suggest questions that are related to the exploration thread.
3438
6. DIVERSITY: the questions should be diverse in difficulty (easy / medium / hard) and the four questions should cover different aspects of the data analysis to expand the user's horizon
3539
- simple questions should be short -- single sentence exploratory questions
3640
- medium questions can be 1-2 sentences exploratory questions
@@ -59,15 +63,17 @@
5963

6064
SYSTEM_PROMPT_AGENT = '''You are a data exploration expert to help users explore their datasets.
6165
66+
This prompt contains the following sections:
67+
- [DATASETS] section: available datasets the user is working with.
68+
- [EXPLORATION THREAD] section (optional): sequence of datasets that have been explored in the order they were created, and what questions are asked to create them. These tables are all created from tables in the [DATASETS] section.
69+
- [CURRENT DATA] section (optional): latest data sample the user is viewing, and the visualization they are looking at at the moment.
70+
- [START QUESTION] section (optional): start question from previous exploration steps for context
71+
6272
Given a dataset (or a thread of datasets that have been explored), your task is to suggest 4 exploration questions (unless the user explicitly asks for the number of questions), that users can follow to gain insights from their data.
63-
* the user may provide you current explorations they have done, including:
64-
- a thread of exploration questions they have explored
65-
- the latest data sample they are viewing
66-
- the current chart they are viewing
67-
* when the exploration context is provided, make your suggestion based on the context as well as the original dataset; otherwise leverage the original dataset to suggest questions.
73+
When the exploration context is provided, make your suggestion based on the context as well as the original datasets; otherwise leverage the original datasets to suggest questions.
6874
6975
Guidelines for question suggestions:
70-
1. Suggest a list of question_groups of interesting analytical questions that are not obvious that can uncover nontrivial insights.
76+
1. Suggest a list of question_groups of interesting analytical questions that can uncover new insights from the data.
7177
2. Use a diverse language style to display the questions (can be questions, statements etc)
7278
3. If there are multiple datasets in a thread, consider relationships between them
7379
4. CONCISENESS: the questions should be concise and to the point
@@ -80,6 +86,7 @@
8086
- hard questions should introduce some new analysis concept but still make it concise
8187
- if suitable, include a group of questions that are related to statistical analysis: forecasting, regression, or clustering.
8288
6. QUESTIONS WITHIN A QUESTION GROUP:
89+
- if the user doesn't provide an exploration thread, start with a high-level overview question that directly visualizes the data to give the user a sense of the data.
8390
- raise new questions that are related to the user's goal, do not repeat questions that have already been explored in the context provided to you.
8491
- if the user provides a start question, suggested questions should be related to the start question.
8592
- the questions should progressively dive deeper into the data, building on top of the previous question.
@@ -113,15 +120,11 @@ def __init__(self, client, agent_exploration_rules="", db_conn=None):
113120
self.agent_exploration_rules = agent_exploration_rules
114121
self.db_conn = db_conn
115122

116-
def get_data_summary(self, input_tables):
123+
def get_data_summary(self, input_tables, table_name_prefix="Table"):
117124
if self.db_conn:
118-
data_summary = ""
119-
for table in input_tables:
120-
table_name = sanitize_table_name(table['name'])
121-
table_summary_str = get_sql_table_statistics_str(self.db_conn, table_name)
122-
data_summary += f"[TABLE {table_name}]\n\n{table_summary_str}\n\n"
125+
data_summary = generate_sql_data_summary(self.db_conn, input_tables, table_name_prefix=table_name_prefix)
123126
else:
124-
data_summary = generate_data_summary(input_tables, include_data_samples=False)
127+
data_summary = generate_data_summary(input_tables, include_data_samples=False, table_name_prefix=table_name_prefix)
125128
return data_summary
126129

127130
def run(self, input_tables, start_question=None, exploration_thread=None,
@@ -144,19 +147,21 @@ def run(self, input_tables, start_question=None, exploration_thread=None,
144147
data_summary = self.get_data_summary(input_tables)
145148

146149
# Build context including exploration thread if available
147-
context = f"[DATASET]\n\n{data_summary}"
150+
context = f"[DATASETS] These are the datasets the user is working with:\n\n{data_summary}"
148151

149152
if exploration_thread:
150-
thread_summary = "Tables in this exploration thread:\n"
151-
for i, table in enumerate(exploration_thread, 1):
152-
table_name = table.get('name', f'Table {i}')
153-
data_summary = self.get_data_summary([{'name': table_name, 'rows': table.get('rows', [])}])
154-
table_description = table.get('description', 'No description available')
155-
thread_summary += f"{i}. {table_name}: {table_description} \n\n{data_summary}\n\n"
156-
context += f"\n\n[EXPLORATION THREAD]\n\n{thread_summary}"
153+
thread_summary = self.get_data_summary(
154+
[{
155+
'name': table.get('name', f'Table {i}'),
156+
'rows': table.get('rows', []),
157+
'attached_metadata': table.get('description', ''),
158+
} for i, table in enumerate(exploration_thread, 1)],
159+
table_name_prefix="Thread Table"
160+
)
161+
context += f"\n\n[EXPLORATION THREAD] These are the sequence of tables the user created in this exploration thread, in the order they were created, and what questions are asked to create them:\n\n{thread_summary}"
157162

158163
if current_data_sample:
159-
context += f"\n\n[CURRENT DATA SAMPLE]\n\n{pd.DataFrame(current_data_sample).head(10).to_string()}"
164+
context += f"\n\n[CURRENT DATA SAMPLE] This is the current data sample the user is viewing, and the visualization they are looking at at the moment is shown below:\n\n{pd.DataFrame(current_data_sample).head(10).to_string()}"
160165

161166
if start_question:
162167
context += f"\n\n[START QUESTION]\n\n{start_question}"

0 commit comments

Comments
 (0)