cboettig commited on
Commit
daec3df
β€’
1 Parent(s): f03c8f7
app.py CHANGED
@@ -1,193 +1,22 @@
1
- # This example does not use a langchain agent,
2
- # The langchain sql chain has knowledge of the database, but doesn't interact with it becond intialization.
3
- # The output of the sql chain is parsed seperately and passed to `duckdb.sql()` by streamlit
4
-
5
- import os
6
- os.environ["WEBSOCKET_TIMEOUT_MS"] = "300000" # no effect
7
-
8
  import streamlit as st
9
- import geopandas as gpd
10
- from shapely import wkb
11
- import leafmap.foliumap as leafmap
12
-
13
- # Helper plotting functions
14
- import pydeck as pdk
15
- def deck_map(gdf):
16
- st.write(
17
- pdk.Deck(
18
- map_style="mapbox://styles/mapbox/light-v9",
19
- initial_view_state={
20
- "latitude": 35,
21
- "longitude": -100,
22
- "zoom": 3,
23
- "pitch": 50,
24
- },
25
- layers=[
26
- pdk.Layer(
27
- "GeoJsonLayer",
28
- gdf,
29
- pickable=True,
30
- stroked=True,
31
- filled=True,
32
- extruded=True,
33
- elevation_scale=10,
34
- get_fill_color=[2, 200, 100],
35
- get_line_color=[0,0,0],
36
- line_width_min_pixels=0,
37
- ),
38
- ],
39
- )
40
- )
41
-
42
- def leaf_map(gdf):
43
- m = leafmap.Map(center=[35, -100], zoom=4, layers_control=True)
44
- m.add_gdf(gdf)
45
- return m.to_streamlit()
46
-
47
-
48
- @st.cache_data
49
- def query_database(response):
50
- return con.sql(response).to_pandas().head(25)
51
-
52
- @st.cache_data
53
- def get_geom(tbl):
54
- tbl['geometry'] = tbl['geometry'].apply(wkb.loads)
55
- gdf = gpd.GeoDataFrame(tbl, geometry='geometry')
56
- return gdf
57
-
58
-
59
- ## Database connection
60
- from sqlalchemy import create_engine
61
- from langchain.sql_database import SQLDatabase
62
- db_uri = "duckdb:///pad.duckdb"
63
- engine = create_engine(db_uri, connect_args={'read_only': True})
64
- db = SQLDatabase(engine, view_support=True)
65
-
66
- import ibis
67
- con = ibis.connect("duckdb://pad.duckdb", read_only=True)
68
- con.load_extension("spatial")
69
-
70
- ## ChatGPT Connection
71
- from langchain_openai import ChatOpenAI
72
-
73
- # Requires ollama server running locally
74
- from langchain_community.llms import Ollama
75
-
76
- ## should we use ChatOllama instead?
77
- # from langchain_community.llms import ChatOllama
78
-
79
- models = {"chatgpt3.5": ChatOpenAI(model="gpt-3.5-turbo", temperature=0, api_key=st.secrets["OPENAI_API_KEY"])}
80
-
81
- other_models = {
82
- "chatgpt4": ChatOpenAI(model="gpt-4", temperature=0, api_key=st.secrets["OPENAI_API_KEY"]),
83
- "duckdb-nsql": Ollama(model="duckdb-nsql", temperature=0),
84
- "command-r-plus": Ollama(model="command-r-plus", temperature=0),
85
- "mixtral:8x22b": Ollama(model="mixtral:8x22b", temperature=0),
86
- "wizardlm2:8x22b": Ollama(model="wizardlm2:8x22b", temperature=0),
87
- "sqlcoder": Ollama(model="sqlcoder", temperature=0),
88
- "zephyr": Ollama(model="zephyr", temperature=0),
89
- "gemma:7b": Ollama(model="gemma:7b", temperature=0),
90
- "codegemma": Ollama(model="codegemma", temperature=0),
91
- "llama2": Ollama(model="llama2", temperature=0),
92
- }
93
-
94
-
95
- st.set_page_config(page_title="Protected Areas Database Chat", page_icon="🦜", layout="wide")
96
- st.title("Protected Areas Database Chat")
97
-
98
- map_tool = {"leafmap": leaf_map,
99
- "deckgl": deck_map
100
- }
101
-
102
- with st.sidebar:
103
- choice = st.radio("Select an LLM:", models)
104
- llm = models[choice]
105
- map_choice = st.radio("Select mapping tool", map_tool)
106
- mapper = map_tool[map_choice]
107
- ## A SQL Chain
108
- from langchain.chains import create_sql_query_chain
109
- chain = create_sql_query_chain(llm, db)
110
 
 
 
 
 
111
 
112
- main = st.container()
113
 
114
- ## Does not preserve history
115
- with main:
116
 
117
- '''
118
  The Protected Areas Database of the United States (PAD-US) is the official national inventory of
119
  America’s parks and other protected lands, and is published by the USGS Gap Analysis Project,
120
  [https://doi.org/10.5066/P9Q9LQ4B.](https://doi.org/10.5066/P9Q9LQ4B).
121
 
122
- This interactive tool allows users to explore the dataset, as well as a range of biodiversity
123
- and climate indicators associated with each protected area. These indicators are integrated into
124
- a single table format shown below. The chatbot assistant can turn natural language queries into
125
- SQL queries based on the table schema.
126
 
127
  See our [Protected Areas Explorer](https://huggingface.co/spaces/boettiger-lab/pad-us) for a companion non-chat-based tool.
128
 
129
- ##### Example Queries returning summary tables
130
-
131
- - What is the percent area in each gap code as a fraction of the total protected area?
132
- - The manager_type column indicates whether a manager is federal, state, local, private, or NGO.
133
- the manager_name column indicates the responsible agency (National Park Service, Bureau of Land Management,
134
- etc) in the case of federal manager types. Which of the federal managers manage the most land in
135
- gap_code 1 or 2, as a fraction of the total area?
136
-
137
- When queries refer to specific managed areas, the chatbot can show those areas on an interactive map.
138
- Do to software limitations, these maps will show no more than 25 polygons, even if more areas match the
139
- requested search. The chatbot sometimes requires help identifying the right columns. In order to create
140
- a map, the SQL query must also return the geometry column. Conisder the following examples:
141
-
142
- ##### Example queries returning maps + tables
143
-
144
- - Show me all the national monuments (designation_type) in Utah. Include the geometry column
145
- - Show examples of Bureau of Land Management (manager_name) with the highest species richness? Include the geometry column
146
- - Which site has the overall highest range-size-rarity? Include the geometry column, manager_name, and IUCN category.
147
-
148
- '''
149
-
150
- st.markdown("## 🦜 Chatbot:")
151
- chatbox = st.container()
152
- with chatbox:
153
- if prompt := st.chat_input(key="chain"):
154
- st.chat_message("user").write(prompt)
155
- with st.chat_message("assistant"):
156
- response = chain.invoke({"question": prompt})
157
- st.write(response)
158
- tbl = query_database(response)
159
- if 'geometry' in tbl:
160
- gdf = get_geom(tbl)
161
- mapper(gdf)
162
- n = len(gdf)
163
- st.write(f"matching features: {n}")
164
- st.dataframe(tbl)
165
-
166
-
167
- st.divider()
168
-
169
- with st.container():
170
- st.text("Database schema (top 3 rows)")
171
- tbl = tbl = query_database("select * from pad limit 3")
172
- st.dataframe(tbl)
173
-
174
-
175
- st.divider()
176
-
177
- '''
178
- Experimental prototype.
179
-
180
- - Author: [Carl Boettiger](https://carlboettiger.info)
181
- - For data sources and processing, see: https://beta.source.coop/repositories/cboettig/pad-us-3/description/
182
-
183
-
184
- '''
185
-
186
- # duckdb_sql fails but chatgpt3.5 succeeds with a query like:
187
- # use the st_area function and st_GeomFromWKB functions to compute the area of the Shape column in the fee table, and then use that to compute the total area under each GAP_Sts category
188
-
189
- # For most queries, duckdb_sql does much better than alternative open models though
190
-
191
- # Federal agencies are identified as 'FED' in the Mang_Type column in the 'combined' data table. The Mang_Name column indicates the different agencies. Which federal agencies manage the greatest area of GAP_Sts 1 or 2 land?
192
 
193
- # Federal agencies are identified as 'FED' in the Mang_Type column in the table named "fee". The Mang_Name column indicates the different agencies. List which managers manage the largest total areas that identified as GAP_Sts '1' or '2' ?
 
 
 
 
 
 
 
 
1
  import streamlit as st
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
+ st.set_page_config(
4
+ page_title="Protected Area Database Chat tool",
5
+ page_icon="🦜",
6
+ )
7
 
8
+ st.sidebar.success("Select a demo above.")
9
 
10
+ st.markdown('''
 
11
 
 
12
  The Protected Areas Database of the United States (PAD-US) is the official national inventory of
13
  America’s parks and other protected lands, and is published by the USGS Gap Analysis Project,
14
  [https://doi.org/10.5066/P9Q9LQ4B.](https://doi.org/10.5066/P9Q9LQ4B).
15
 
16
+ These interactive tools allows users to explore the dataset, as well as a range of biodiversity
17
+ and climate indicators associated with each protected area. Select a tool from the menu on the left.
 
 
18
 
19
  See our [Protected Areas Explorer](https://huggingface.co/spaces/boettiger-lab/pad-us) for a companion non-chat-based tool.
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
+ ''')
graphs.py β†’ pages/1_🌍_Mapping_Demo.py RENAMED
@@ -7,44 +7,8 @@ os.environ["WEBSOCKET_TIMEOUT_MS"] = "300000" # no effect
7
 
8
  import streamlit as st
9
  import geopandas as gpd
10
- import pandas as pd
11
  from shapely import wkb
12
-
13
-
14
- st.set_page_config(page_title="Protected Areas Database Chat", page_icon="🦜", layout="wide")
15
- st.title("Protected Areas Database Chat")
16
-
17
- ## Database connection, reading directly from remote parquet file
18
- from sqlalchemy import create_engine
19
- from langchain.sql_database import SQLDatabase
20
- db_uri = "duckdb:///:memory:"
21
- parquet = "https://huggingface.co/datasets/boettiger-lab/pad-us-3/resolve/main/pad-stats.parquet"
22
- engine = create_engine(db_uri) #connect_args={'read_only': True})
23
- con = engine.connect()
24
- con.execute("install spatial; load spatial;")
25
- h = con.execute(f"create or replace view pad as select * from read_parquet('{parquet}');")
26
- h.fetchall()
27
- db = SQLDatabase(engine, view_support=True)
28
-
29
-
30
- @st.cache_data
31
- def query_database(response):
32
- # con.sql(response).to_pandas().head(25) # uses ibis connection
33
- # instead, use direct sqlAlchemy connection
34
- z = con.execute(response).fetchall()
35
- return pd.DataFrame(z).head(25)
36
-
37
-
38
- query_database("select * from pad limit 1")
39
-
40
-
41
- @st.cache_data
42
- def get_geom(tbl):
43
- tbl['geometry'] = tbl['geometry'].apply(wkb.loads)
44
- gdf = gpd.GeoDataFrame(tbl, geometry='geometry')
45
- return gdf
46
-
47
-
48
 
49
  # Helper plotting functions
50
  import pydeck as pdk
@@ -75,20 +39,41 @@ def deck_map(gdf):
75
  )
76
  )
77
 
78
- import leafmap.foliumap as leafmap
79
  def leaf_map(gdf):
80
  m = leafmap.Map(center=[35, -100], zoom=4, layers_control=True)
81
  m.add_gdf(gdf)
82
  return m.to_streamlit()
83
 
84
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
 
86
  ## ChatGPT Connection
87
  from langchain_openai import ChatOpenAI
 
88
  # Requires ollama server running locally
89
  from langchain_community.llms import Ollama
90
 
91
- # # should we use ChatOllama instead?
92
  # from langchain_community.llms import ChatOllama
93
 
94
  models = {"chatgpt3.5": ChatOpenAI(model="gpt-3.5-turbo", temperature=0, api_key=st.secrets["OPENAI_API_KEY"])}
@@ -107,7 +92,8 @@ other_models = {
107
  }
108
 
109
 
110
-
 
111
 
112
  map_tool = {"leafmap": leaf_map,
113
  "deckgl": deck_map
@@ -129,16 +115,7 @@ main = st.container()
129
  with main:
130
 
131
  '''
132
- The Protected Areas Database of the United States (PAD-US) is the official national inventory of
133
- America’s parks and other protected lands, and is published by the USGS Gap Analysis Project,
134
- [https://doi.org/10.5066/P9Q9LQ4B.](https://doi.org/10.5066/P9Q9LQ4B).
135
 
136
- This interactive tool allows users to explore the dataset, as well as a range of biodiversity
137
- and climate indicators associated with each protected area. These indicators are integrated into
138
- a single table format shown below. The chatbot assistant can turn natural language queries into
139
- SQL queries based on the table schema.
140
-
141
- See our [Protected Areas Explorer](https://huggingface.co/spaces/boettiger-lab/pad-us) for a companion non-chat-based tool.
142
 
143
  ##### Example Queries returning summary tables
144
 
@@ -196,3 +173,12 @@ Experimental prototype.
196
 
197
 
198
  '''
 
 
 
 
 
 
 
 
 
 
7
 
8
  import streamlit as st
9
  import geopandas as gpd
 
10
  from shapely import wkb
11
+ import leafmap.foliumap as leafmap
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
  # Helper plotting functions
14
  import pydeck as pdk
 
39
  )
40
  )
41
 
 
42
  def leaf_map(gdf):
43
  m = leafmap.Map(center=[35, -100], zoom=4, layers_control=True)
44
  m.add_gdf(gdf)
45
  return m.to_streamlit()
46
 
47
 
48
+ @st.cache_data
49
+ def query_database(response):
50
+ return con.sql(response).to_pandas().head(25)
51
+
52
+ @st.cache_data
53
+ def get_geom(tbl):
54
+ tbl['geometry'] = tbl['geometry'].apply(wkb.loads)
55
+ gdf = gpd.GeoDataFrame(tbl, geometry='geometry')
56
+ return gdf
57
+
58
+
59
+ ## Database connection
60
+ from sqlalchemy import create_engine
61
+ from langchain.sql_database import SQLDatabase
62
+ db_uri = "duckdb:///pad.duckdb"
63
+ engine = create_engine(db_uri, connect_args={'read_only': True})
64
+ db = SQLDatabase(engine, view_support=True)
65
+
66
+ import ibis
67
+ con = ibis.connect("duckdb://pad.duckdb", read_only=True)
68
+ con.load_extension("spatial")
69
 
70
  ## ChatGPT Connection
71
  from langchain_openai import ChatOpenAI
72
+
73
  # Requires ollama server running locally
74
  from langchain_community.llms import Ollama
75
 
76
+ ## should we use ChatOllama instead?
77
  # from langchain_community.llms import ChatOllama
78
 
79
  models = {"chatgpt3.5": ChatOpenAI(model="gpt-3.5-turbo", temperature=0, api_key=st.secrets["OPENAI_API_KEY"])}
 
92
  }
93
 
94
 
95
+ st.set_page_config(page_title="Protected Areas Database Chat", page_icon="🦜", layout="wide")
96
+ st.title("Protected Areas Database Chat")
97
 
98
  map_tool = {"leafmap": leaf_map,
99
  "deckgl": deck_map
 
115
  with main:
116
 
117
  '''
 
 
 
118
 
 
 
 
 
 
 
119
 
120
  ##### Example Queries returning summary tables
121
 
 
173
 
174
 
175
  '''
176
+
177
+ # duckdb_sql fails but chatgpt3.5 succeeds with a query like:
178
+ # use the st_area function and st_GeomFromWKB functions to compute the area of the Shape column in the fee table, and then use that to compute the total area under each GAP_Sts category
179
+
180
+ # For most queries, duckdb_sql does much better than alternative open models though
181
+
182
+ # Federal agencies are identified as 'FED' in the Mang_Type column in the 'combined' data table. The Mang_Name column indicates the different agencies. Which federal agencies manage the greatest area of GAP_Sts 1 or 2 land?
183
+
184
+ # Federal agencies are identified as 'FED' in the Mang_Type column in the table named "fee". The Mang_Name column indicates the different agencies. List which managers manage the largest total areas that identified as GAP_Sts '1' or '2' ?
pages/2_πŸ“Š_Chart_Demo.py ADDED
@@ -0,0 +1,207 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This example does not use a langchain agent,
2
+ # The langchain sql chain has knowledge of the database, but doesn't interact with it becond intialization.
3
+ # The output of the sql chain is parsed seperately and passed to `duckdb.sql()` by streamlit
4
+
5
+ import os
6
+ os.environ["WEBSOCKET_TIMEOUT_MS"] = "300000" # no effect
7
+
8
+ import streamlit as st
9
+ import geopandas as gpd
10
+ import pandas as pd
11
+ from shapely import wkb
12
+
13
+ st.set_page_config(page_title="Protected Areas Database Chat", page_icon="🦜", layout="wide")
14
+ st.title("Protected Areas Database Chat")
15
+
16
+ ## Database connection, reading directly from remote parquet file
17
+ from sqlalchemy import create_engine
18
+ from langchain.sql_database import SQLDatabase
19
+ db_uri = "duckdb:///my.duckdb"
20
+ parquet = "https://huggingface.co/datasets/boettiger-lab/pad-us-3/resolve/main/pad-stats.parquet"
21
+ stats = "../pad-us/pad-stats.parquet"
22
+ groups = "../pad-us/pad-groupings.parquet"
23
+ engine = create_engine(db_uri) #connect_args={'read_only': True})
24
+ con = engine.connect()
25
+ con.execute("install spatial; load spatial;")
26
+ # con.execute(f"create or replace view stats as select * from read_parquet('{stats}');").fetchall()
27
+ con.execute(f"create or replace table groups as select * from read_parquet('{groups}');").fetchall()
28
+
29
+ db = SQLDatabase(engine, view_support=True)
30
+
31
+
32
+ @st.cache_data
33
+ def query_database(response):
34
+ z = con.execute(response).fetchall()
35
+ return pd.DataFrame(z).head(25)
36
+
37
+ import ibis
38
+ from ibis import _
39
+ import ibis.selectors as s
40
+ import altair as alt
41
+ ibis_con = ibis.duckdb.connect("my.duckdb")
42
+ stats = ibis_con.read_parquet(stats)
43
+ us_lower_48_area_m2 = 7.8e+12
44
+
45
+
46
+
47
+
48
+ def summary_table(stats, query, column):
49
+ #z = con.execute(query).fetchall()
50
+ groups = ibis_con.table("groups").sql(query.replace(";", ""))
51
+
52
+ df = (stats
53
+ .inner_join(groups, "row_n")
54
+ .select(~s.contains("_right"))
55
+ .rename(area = "area_square_meters")
56
+ .group_by(_[column])
57
+ .aggregate(percent_protected = 100 * _.area.sum() / us_lower_48_area_m2,
58
+ hectares = _.area.sum() / 10000,
59
+ n = _.area.count(),
60
+ richness = (_.richness * _.area).sum() / _.area.sum(),
61
+ rsr = (_.rsr * _.area).sum() / _.area.sum(),
62
+ carbon_lost = (_.deforest_carbon * _.area).sum() / _.area.sum(),
63
+ crop_expansion = (_.crop_expansion * _.area).sum() / _.area.sum(),
64
+ human_impact = (_.human_impact * _.area).sum() / _.area.sum(),
65
+ )
66
+ .mutate(percent_protected = _.percent_protected.round(1))
67
+ )
68
+ return df.to_pandas()
69
+
70
+ def area_plot(df, column):
71
+ base = alt.Chart(df).encode(
72
+ alt.Theta("percent_protected:Q").stack(True),
73
+ alt.Color(column+":N").legend(None)
74
+ )
75
+
76
+ pie = base.mark_arc(innerRadius= 40, outerRadius=80)
77
+ text = base.mark_text(radius=120, size=20).encode(
78
+ text="percent_protected:Q"
79
+ )
80
+ plot = pie + text
81
+ return st.altair_chart(plot)
82
+
83
+ def bar_chart(df, x, y):
84
+ chart = alt.Chart(df).mark_bar().encode(
85
+ x=x,
86
+ y=y,
87
+ color=alt.Color(x).legend(None)
88
+ ).properties(width="container", height=300)
89
+ return chart
90
+
91
+
92
+ ## ChatGPT Connection
93
+ from langchain_openai import ChatOpenAI
94
+ from langchain_community.llms import Ollama
95
+ # from langchain_community.llms import ChatOllama
96
+
97
+ models = {"chatgpt3.5": ChatOpenAI(model="gpt-3.5-turbo", temperature=0, api_key=st.secrets["OPENAI_API_KEY"])}
98
+
99
+ other_models = {
100
+ "chatgpt4": ChatOpenAI(model="gpt-4", temperature=0, api_key=st.secrets["OPENAI_API_KEY"]),
101
+ "duckdb-nsql": Ollama(model="duckdb-nsql", temperature=0),
102
+ "command-r-plus": Ollama(model="command-r-plus", temperature=0),
103
+ "mixtral:8x22b": Ollama(model="mixtral:8x22b", temperature=0),
104
+ "wizardlm2:8x22b": Ollama(model="wizardlm2:8x22b", temperature=0),
105
+ "sqlcoder": Ollama(model="sqlcoder", temperature=0),
106
+ "zephyr": Ollama(model="zephyr", temperature=0),
107
+ "gemma:7b": Ollama(model="gemma:7b", temperature=0),
108
+ "codegemma": Ollama(model="codegemma", temperature=0),
109
+ "llama2": Ollama(model="llama2", temperature=0),
110
+ }
111
+
112
+ with st.sidebar:
113
+ choice = st.radio("Select an LLM:", models)
114
+ llm = models[choice]
115
+ column = st.text_input("grouping column", "labels")
116
+
117
+
118
+ ## A SQL Chain
119
+ from langchain.chains import create_sql_query_chain
120
+ chain = create_sql_query_chain(llm, db)
121
+
122
+
123
+ main = st.container()
124
+
125
+ ## Does not preserve history
126
+ with main:
127
+
128
+ '''
129
+ ##### Example Queries returning summary tables
130
+
131
+ - gap 1, 2, 3 are labelled 'conserved lands' and gap 4 is labeled 'other'
132
+ - exclude gap 4, include only Federal manager types, labelled by manager_name
133
+ - label gap 1, 2 as "permanently protected", label gap 3 as "additional conserved area", and gap 4 as other
134
+
135
+
136
+
137
+ '''
138
+
139
+ prefix = "construct a select query that creates a column called 'labels' that only contains rows that meet the following criteria:"
140
+ suffix = ". Do not use LIMIT. Always return all columns. Do not try to select specific columns."
141
+
142
+ st.markdown("Specify how data should be labelled, as in the examples above:")
143
+ chatbox = st.container()
144
+ with chatbox:
145
+ if prompt := st.chat_input(key="chain"):
146
+ st.chat_message("user").write(prompt)
147
+ with st.chat_message("assistant"):
148
+ response = chain.invoke({"question": prefix + prompt + suffix})
149
+ st.write(response)
150
+ df = summary_table(stats, response, column)
151
+
152
+ with st.container():
153
+ col1, col2, col3 = st.columns(3)
154
+ with col1:
155
+ total_percent = df.percent_protected.sum().round(1)
156
+ f"{total_percent}% Continental US Covered"
157
+ area_plot(df, column)
158
+
159
+ with col2:
160
+ "Species Richness"
161
+ st.altair_chart(bar_chart(df, column, "richness"), use_container_width=True)
162
+
163
+ with col3:
164
+ "Range-Size Rarity"
165
+ st.altair_chart(bar_chart(df, column, "rsr"), use_container_width=True)
166
+
167
+ with st.container():
168
+ col1b, col2b, col3b = st.columns(3)
169
+ with col1b:
170
+ "Carbon Lost ('02-'22)"
171
+ st.altair_chart(bar_chart(df, column, "carbon_lost"), use_container_width=True)
172
+
173
+ with col2b:
174
+ "Crop expansion"
175
+ st.altair_chart(bar_chart(df, column, "crop_expansion"), use_container_width=True)
176
+
177
+ with col3b:
178
+ "Human Impact"
179
+ st.altair_chart(bar_chart(df, column, "human_impact"), use_container_width=True)
180
+
181
+
182
+ st.divider()
183
+ st.dataframe(df)
184
+
185
+
186
+
187
+
188
+
189
+
190
+
191
+ #st.divider()
192
+ #with st.container():
193
+ # st.text("Database schema (top 3 rows)")
194
+ # tbl = tbl = query_database("select * from groups limit 3")
195
+ # st.dataframe(tbl)
196
+
197
+
198
+ st.divider()
199
+
200
+ '''
201
+ Experimental prototype.
202
+
203
+ - Author: [Carl Boettiger](https://carlboettiger.info)
204
+ - For data sources and processing, see: https://beta.source.coop/repositories/cboettig/pad-us-3/description/
205
+
206
+
207
+ '''