IBHS commited on
Commit
851b838
·
verified ·
1 Parent(s): a04dd43

Upload 5 files

Browse files
Files changed (5) hide show
  1. app.py +44 -0
  2. config.py +37 -0
  3. constants.py +60 -0
  4. llms.py +55 -0
  5. requirements.txt +18 -0
app.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from config import settings
3
+ import constants
4
+ from llms import Agents
5
+ import datetime
6
+
7
+ agents = Agents(model="gpt-4o", model_type="openai", temperature=0.5, is_structured=False)
8
+
9
+
10
+ def get_county_info(county_name):
11
+ today = datetime.datetime.today().strftime("%Y-%m-%d")
12
+ user_input = {"county": county_name, "today": today}
13
+ response = agents.generate_tavily_search(f"{user_input}")
14
+ return response["output"], gr.update(visible=False)
15
+ # return "## 👇 Please select a county and click submit."
16
+
17
+
18
+ # A list of county names for the dropdown.
19
+ county_choices = constants.county_list
20
+
21
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
22
+ gr.Markdown("# IBHS County Profiler")
23
+ gr.Markdown("#### A specialized research agent that gather up-to-date, authoritative information on residential risk for a county.")
24
+ gr.Markdown("Select a county from the list and click 'Submit' to see the details.")
25
+
26
+ with gr.Column():
27
+ county_dropdown = gr.Dropdown(
28
+ choices=county_choices,
29
+ label="Select a County"
30
+ )
31
+ submit_button = gr.Button("Submit")
32
+ progress = gr.Textbox(label="Progress bar", value="Status: Waiting for input...", interactive=False)
33
+
34
+ output_markdown = gr.Markdown()
35
+
36
+ # The click event of the button now triggers the function
37
+ submit_button.click(
38
+ fn=get_county_info,
39
+ inputs=county_dropdown,
40
+ outputs=[output_markdown, progress]
41
+ )
42
+
43
+ if __name__ == "__main__":
44
+ demo.launch()
config.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic_settings import BaseSettings
2
+
3
+
4
+ class Settings(BaseSettings):
5
+
6
+ COUNTY_RISK_ANALYSIS_PROMPT: str = """
7
+ You are “SafeHaven Analyst,” a specialized research agent that uses the Tavily search API to gather up-to-date, authoritative information on residential risk for a single U.S. county.
8
+
9
+ ⮞ **Inputs provided by the user as a dictionary with following items**
10
+ - `county`: full county name plus state abbreviation (e.g., “San Bernardino County, CA”).
11
+ - `today`: ISO date string (YYYY-MM-DD) representing “today.”
12
+
13
+ ⮞ **Your task**
14
+ 1. Run focused Tavily searches (news, government, academic, and insurer sources) published **within the last 3 years** that mention (`county` AND key terms below).
15
+ - Key terms: *storm*, *flood*, *wildfire*, *hail*, *tornado*, *hurricane*, *drought*, *extreme heat*, *seismic*, *landslide*, *insurance claims*, *roof damage cost*, *window replacement cost*, *door replacement cost*, *home repair cost*.
16
+ 2. Analyse the top credible sources to extract:
17
+ **a. Weather & Natural Hazard Landscape** – List the *current* primary hazards (likelihood + seasonal timing).
18
+ **b. Damage-Cost Benchmarks** – Typical 2024-25 cost ranges (USD) in this county for repairing/replacing: roof, exterior doors, windows. Cite the source or methodology briefly in parentheses.
19
+ **c. Overall Residential Risk Profile** – Concise narrative (≈120 words) rating risk *Low / Moderate / High* and explaining drivers (age of local housing stock, hazard frequency, rebuild costs, insurance availability, etc.).
20
+ 3. Prioritize clarity: synthesize, do not paste source snippets. If data is scarce, state that and default to statewide or regional averages, labelling them clearly.
21
+ 4. **Inline-cite every numeric or factual claim** with a markdown link:
22
+ - Format: `**[$12 k–$18 k, [HomeAdvisor 05/2025](https://source-url.com)]**` – one citation per sentence.
23
+ - Use the article/site name and month/year; the link must point to the live URL returned by Tavily.
24
+ 5. Total report length ≤ 300 words, using these headings exactly:
25
+ **Weather & Hazard Snapshot**
26
+ **Damage-Cost Benchmarks (USD)**
27
+ **County Home Risk Profile**
28
+
29
+ ⮞ **Style guidelines**
30
+ - Formal but readable business prose.
31
+ - Use bullet lists only inside the two first sections; profile section is paragraph form.
32
+ - No markdown code fences or JSON—return plain text with the three headings only.
33
+ """
34
+
35
+
36
+ settings = Settings()
37
+
constants.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ county_list =[
2
+ "Alameda County, CA",
3
+ "Alpine County, CA",
4
+ "Amador County, CA",
5
+ "Butte County, CA",
6
+ "Calaveras County, CA",
7
+ "Colusa County, CA",
8
+ "Contra Costa County, CA",
9
+ "Del Norte County, CA",
10
+ "El Dorado County, CA",
11
+ "Fresno County, CA",
12
+ "Glenn County, CA",
13
+ "Humboldt County, CA",
14
+ "Imperial County, CA",
15
+ "Inyo County, CA",
16
+ "Kern County, CA",
17
+ "Kings County, CA",
18
+ "Lake County, CA",
19
+ "Lassen County, CA",
20
+ "Los Angeles County, CA",
21
+ "Madera County, CA",
22
+ "Marin County, CA",
23
+ "Mariposa County, CA",
24
+ "Mendocino County, CA",
25
+ "Merced County, CA",
26
+ "Modoc County, CA",
27
+ "Mono County, CA",
28
+ "Monterey County, CA",
29
+ "Napa County, CA",
30
+ "Nevada County, CA",
31
+ "Orange County, CA",
32
+ "Placer County, CA",
33
+ "Plumas County, CA",
34
+ "Riverside County, CA",
35
+ "Sacramento County, CA",
36
+ "San Benito County, CA",
37
+ "San Bernardino County, CA",
38
+ "San Diego County, CA",
39
+ "San Francisco County, CA",
40
+ "San Joaquin County, CA",
41
+ "San Luis Obispo County, CA",
42
+ "San Mateo County, CA",
43
+ "Santa Barbara County, CA",
44
+ "Santa Clara County, CA",
45
+ "Santa Cruz County, CA",
46
+ "Shasta County, CA",
47
+ "Sierra County, CA",
48
+ "Siskiyou County, CA",
49
+ "Solano County, CA",
50
+ "Sonoma County, CA",
51
+ "Stanislaus County, CA",
52
+ "Sutter County, CA",
53
+ "Tehama County, CA",
54
+ "Trinity County, CA",
55
+ "Tulare County, CA",
56
+ "Tuolumne County, CA",
57
+ "Ventura County, CA",
58
+ "Yolo County, CA",
59
+ "Yuba County, CA"
60
+ ]
llms.py ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import datetime
2
+
3
+ from langchain.agents import create_openai_tools_agent, AgentExecutor
4
+ from langchain.chat_models import init_chat_model
5
+ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
6
+ from langchain_openai import ChatOpenAI
7
+ from langchain_tavily import TavilySearch
8
+ from langchain.schema import HumanMessage, SystemMessage
9
+ from langchain_core.prompts import PromptTemplate
10
+ from langchain_openai import ChatOpenAI
11
+ from langchain_anthropic import ChatAnthropic
12
+ from pydantic import BaseModel, Field
13
+ from typing import List
14
+ from enum import Enum
15
+ from langchain_core.output_parsers import PydanticOutputParser
16
+ from langchain_core.output_parsers import JsonOutputParser
17
+ import os
18
+ from dotenv import load_dotenv
19
+ load_dotenv()
20
+
21
+ from config import settings
22
+
23
+
24
+ class Agents:
25
+ def __init__(self, temperature: float = 0.3, model: str = "gpt-4.1", model_type: str = "openai",
26
+ is_structured: bool = True):
27
+ """
28
+ Initializes the UserSummaryGenerator with necessary settings and model configuration.
29
+ """
30
+
31
+ self.settings = settings
32
+ self.model_type = model_type
33
+
34
+ self.llm_tavily = init_chat_model(model="gpt-4o", model_provider="openai", temperature=0)
35
+
36
+ self.tavily_search_tool = TavilySearch(max_results=5, topic="general")
37
+
38
+ self.tavily_prompt = ChatPromptTemplate.from_messages([
39
+ ("system", self.settings.COUNTY_RISK_ANALYSIS_PROMPT),
40
+ MessagesPlaceholder(variable_name="messages"),
41
+ MessagesPlaceholder(variable_name="agent_scratchpad"), # Required for tool calls
42
+ ])
43
+
44
+ self.tavily_agent = create_openai_tools_agent(
45
+ llm=self.llm_tavily,
46
+ tools=[self.tavily_search_tool],
47
+ prompt=self.tavily_prompt
48
+ )
49
+
50
+ self.agent_executor = AgentExecutor(agent=self.tavily_agent, tools=[self.tavily_search_tool], verbose=False)
51
+
52
+
53
+ def generate_tavily_search(self, user_input: str) -> str:
54
+ response = self.agent_executor.invoke({"messages": [HumanMessage(content=user_input)]},)
55
+ return response
requirements.txt ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ pandas
2
+ openpyxl
3
+ pandas
4
+ pyarrow
5
+ langchain
6
+ langchain_core
7
+ python-dotenv
8
+ langchain-openai
9
+ gradio
10
+ pydantic-settings
11
+ pyreadstat
12
+ plotly
13
+ kaleido
14
+ chardet
15
+ charset-normalizer
16
+ pandas-stubs==2.2.3.250527
17
+ langchain_anthropic
18
+ langchain-tavily