nniehaus commited on
Commit
5066bf1
Β·
verified Β·
1 Parent(s): fd1c160

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +64 -83
app.py CHANGED
@@ -1,7 +1,7 @@
1
  import streamlit as st
2
  from PIL import Image
3
  from io import BytesIO
4
- import openai
5
  import base64
6
  import time
7
  from datetime import datetime
@@ -28,13 +28,10 @@ st.markdown(
28
  unsafe_allow_html=True
29
  )
30
 
31
- # --- OpenAI SDK client caching ---
32
- @st.cache_resource
33
- def get_openai_client(api_key: str):
34
- openai.api_key = api_key
35
- return openai
36
 
37
- # --- Image encoding helper ---
38
  @st.cache_data
39
  def encode_image_to_b64(image: Image.Image) -> str:
40
  # Convert to RGB if needed
@@ -52,94 +49,78 @@ def encode_image_to_b64(image: Image.Image) -> str:
52
  image.save(buf, format='JPEG', quality=85)
53
  return base64.b64encode(buf.getvalue()).decode('utf-8')
54
 
55
- # --- Simple formatting fixes ---
56
  def fix_formatting(text: str) -> str:
57
  text = re.sub(r'(\d+)([A-Za-z])', r'\1 \2', text)
58
  text = re.sub(r'([.,])([A-Za-z0-9])', r'\1 \2', text)
59
  text = re.sub(r':([A-Za-z0-9])', r': \1', text)
60
  return text
61
 
62
- # --- System prompt ---
63
- SYSTEM_PROMPT = f"""
64
- You are an expert real estate advisor with deep knowledge of home selling strategies. You analyze home photos to provide EXTREMELY SPECIFIC, actionable recommendations that will maximize the property's selling price.
65
-
66
- ONLY make recommendations based on visible areas in the photos. Reference exact features, colors, materials, and conditions you can see.
67
-
68
- FORMAT:
69
- ### πŸ“‹ HOME VALUE MAXIMIZER SUMMARY
70
- - Start with exactly this header.
71
- - Then: "Below are the top improvements to maximize your home’s value..."
72
- - List 5 bullet points: **bold issue**, specific solution, estimated ROI.
73
-
74
- ### πŸ‘οΈ AREAS ANALYZED
75
- List which areas you see (e.g., Kitchen, Living Room).
76
-
77
- ### 🌟 TOP PRICE-MAXIMIZING PRIORITIES
78
- For the 3–4 biggest improvements: exact issue, precise recommendation, cost estimate, value impact, timeline.
79
-
80
- ### πŸ”¨ QUICK WINS (1–3 days)
81
- List 5–6 fast, high-ROI fixes for visible areas; include product names/colors/costs.
82
-
83
- ### πŸ“Š SPECIFIC PRICING STRATEGY
84
- - Precise price point and pricing psychology (spaces between numbers and text).
85
- - Exact timing: days/dates based on current date ({datetime.now().strftime('%B %d, %Y')}).
86
-
87
- ### πŸ“Έ DETAILED MARKETING PLAN
88
- List specific features to highlight, angles, staging items, virtual tools.
89
-
90
- ### πŸ“ SPECIFIC NEGOTIATION TACTICS
91
- Exact scripts, inspection strategies, contingency planning.
92
-
93
- ### ⚠️ CRITICAL ISSUES TO ADDRESS
94
- List 3 visible problems with exact fixes.
95
-
96
- ### πŸ“… DETAILED TIMELINE WITH DATES
97
- Provide calendar dates for each step, from today.
98
-
99
- ### 🚫 AREAS NOT VISIBLE
100
- Note any important areas you couldn’t see.
101
- """
102
-
103
- # --- Streamlit layout ---
104
  st.title("Home Value Maximizer 🏑")
105
- st.write("Upload photos, enter your timeline & budget, then click Analyze for detailed, hyper-specific advice.")
106
 
107
- # API key
108
  api_key = st.sidebar.text_input("OpenAI API Key", type="password")
109
- client = get_openai_client(api_key) if api_key else None
110
-
111
- # Upload images
112
- st.sidebar.header("πŸ“Έ Upload Home Photos")
113
- uploaded = st.sidebar.file_uploader("Images", type=["jpg","png","jpeg"], accept_multiple_files=True)
114
- images = []
115
- for file in uploaded:
116
- try:
117
- img = Image.open(file)
118
- images.append(img)
119
- except:
120
- st.sidebar.error(f"Failed to load {file.name}")
121
 
122
- # Inputs
123
  timeframe = st.sidebar.selectbox("Selling timeframe", ["Within 1 month","1–3 months","3–6 months","6–12 months",">12 months"])
124
  budget = st.sidebar.slider("Max improvement budget ($)", 1000, 50000, 10000, 1000)
125
- improve_focus = st.sidebar.multiselect("Focus areas (opt)", ["Curb appeal","Kitchen","Bathroom","Living Spaces","Outdoor","Storage","Energy","Marketing","Negotiation","Staging"], default=["Kitchen","Bathroom"])
126
 
127
- # Analyze button
128
- if st.button("πŸ” Analyze My Home"):
129
- if not client:
130
- st.error("Enter API key to analyze.")
131
- elif not images:
132
- st.error("Upload at least one photo.")
133
  else:
 
 
 
 
134
  with st.spinner("Analyzing..."):
135
- user_details = f"Budget: ${budget}. Focus: {', '.join(improve_focus)}"
136
- analysis = analyze_home_photos(images, timeframe, user_details, client)
137
- st.success("Analysis complete!")
138
- st.markdown(f"<div style='background:#e3f2fd;padding:1rem;border-left:4px solid #1f77b4;'>{analysis}</div>", unsafe_allow_html=True)
139
- # Cost
140
- usage = client.api_usage if hasattr(client, 'api_usage') else {}
141
- cost = calculate_cost(usage)
142
- st.metric("πŸ’² Estimated Cost", f"${cost:.2f}")
143
-
144
- else:
145
- st.info("Submit images & API key to generate recommendations.")
 
1
  import streamlit as st
2
  from PIL import Image
3
  from io import BytesIO
4
+ import requests
5
  import base64
6
  import time
7
  from datetime import datetime
 
28
  unsafe_allow_html=True
29
  )
30
 
31
+ # --- Configuration ---
32
+ API_URL = "https://api.openai.com/v1/chat/completions"
 
 
 
33
 
34
+ # --- Cache utilities ---
35
  @st.cache_data
36
  def encode_image_to_b64(image: Image.Image) -> str:
37
  # Convert to RGB if needed
 
49
  image.save(buf, format='JPEG', quality=85)
50
  return base64.b64encode(buf.getvalue()).decode('utf-8')
51
 
 
52
  def fix_formatting(text: str) -> str:
53
  text = re.sub(r'(\d+)([A-Za-z])', r'\1 \2', text)
54
  text = re.sub(r'([.,])([A-Za-z0-9])', r'\1 \2', text)
55
  text = re.sub(r':([A-Za-z0-9])', r': \1', text)
56
  return text
57
 
58
+ # --- Analysis function via requests ---
59
+ def analyze_home_photos(images, timeframe, details, api_key):
60
+ if not api_key:
61
+ return "Error: API key is required."
62
+ headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
63
+ # Build system prompt
64
+ system_prompt = (
65
+ f"You are a real estate advisor. Today's date is {datetime.now().strftime('%B %d, %Y')}. "
66
+ "Analyze only visible areas in the images and give hyper-specific recommendations."
67
+ )
68
+ # Build user content with embedded images
69
+ user_content = f"Sell within {timeframe}. {details}\n\n"
70
+ for img in images:
71
+ b64 = encode_image_to_b64(img)
72
+ user_content += f"![photo](data:image/jpeg;base64,{b64})\n\n"
73
+ payload = {
74
+ "model": "gpt-4o",
75
+ "messages": [
76
+ {"role": "system", "content": system_prompt},
77
+ {"role": "user", "content": user_content}
78
+ ],
79
+ "max_tokens": 2000
80
+ }
81
+ resp = requests.post(API_URL, headers=headers, json=payload, timeout=90)
82
+ if resp.status_code == 200:
83
+ data = resp.json()
84
+ text = data['choices'][0]['message']['content']
85
+ return fix_formatting(text)
86
+ return f"API Error {resp.status_code}: {resp.text[:200]}"
87
+
88
+ # --- Cost calculation ---
89
+ def calculate_cost(usage):
90
+ if not usage:
91
+ return 0.0
92
+ in_tok = usage.get('prompt_tokens',0)
93
+ out_tok = usage.get('completion_tokens',0)
94
+ cost = in_tok/1e6*3 + out_tok/1e6*10
95
+ return cost
96
+
97
+ # --- App layout ---
 
 
98
  st.title("Home Value Maximizer 🏑")
 
99
 
100
+ # Sidebar inputs
101
  api_key = st.sidebar.text_input("OpenAI API Key", type="password")
102
+ uploaded = st.sidebar.file_uploader("Upload home photos", accept_multiple_files=True, type=["jpg","png","jpeg"])
 
 
 
 
 
 
 
 
 
 
 
103
 
 
104
  timeframe = st.sidebar.selectbox("Selling timeframe", ["Within 1 month","1–3 months","3–6 months","6–12 months",">12 months"])
105
  budget = st.sidebar.slider("Max improvement budget ($)", 1000, 50000, 10000, 1000)
106
+ focus = st.sidebar.multiselect("Focus areas", ["Curb appeal","Kitchen","Bathroom","Living Spaces","Outdoor","Storage"], default=["Kitchen","Bathroom"])
107
 
108
+ if st.sidebar.button("πŸ” Analyze My Home"):
109
+ if not api_key:
110
+ st.sidebar.error("Enter API key.")
111
+ elif not uploaded:
112
+ st.sidebar.error("Upload at least one photo.")
 
113
  else:
114
+ images = []
115
+ for f in uploaded:
116
+ try: images.append(Image.open(f))
117
+ except: pass
118
  with st.spinner("Analyzing..."):
119
+ result = analyze_home_photos(images, timeframe, f"Budget ${budget}. Focus: {', '.join(focus)}", api_key)
120
+ st.markdown(f"<div style='background:#e3f2fd;padding:1rem;border-left:4px solid #1f77b4;'>{result}</div>", unsafe_allow_html=True)
121
+ # Cost display
122
+ # Note: HF Spaces does not return usage, so this may be blank
123
+ usage = {} # placeholder
124
+ cost = calculate_cost(usage)
125
+ st.metric("πŸ’² Estimated cost", f"${cost:.2f}")
126
+ ```