skshimada commited on
Commit
43779e4
·
verified ·
1 Parent(s): 33c5c81

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +33 -28
app.py CHANGED
@@ -7,10 +7,9 @@ from PIL import Image
7
  from transformers import pipeline
8
  from langchain_chroma import Chroma
9
  from langchain_community.document_loaders import PyPDFLoader, TextLoader
10
- from langchain_text_splitters import RecursiveCharacterTextSplitter
11
  from langchain_core.documents import Document
12
  from langchain_huggingface import HuggingFaceEmbeddings
13
- from ultralytics import YOLO
14
 
15
  # --- CONFIGURATION ---
16
  CHROMA_PATH = "/tmp/chroma_db"
@@ -75,7 +74,7 @@ def get_bottle_crops(image_path):
75
  except:
76
  return []
77
 
78
- # --- RECIPE INGESTION (NOW WITH SCISSORS!) ---
79
  def ingest_recipes(files):
80
  if not files: return "❌ No files uploaded."
81
 
@@ -93,27 +92,37 @@ def ingest_recipes(files):
93
 
94
  if not docs: return "❌ Could not extract text."
95
 
96
- # --- THE FIX: SPLIT TEXT INTO RECIPES ---
97
- # We split by "Recipe:" or newlines to ensure each drink is its own 'chunk'
98
- text_splitter = RecursiveCharacterTextSplitter(
99
- chunk_size=600, # Approximate size of one recipe
100
- chunk_overlap=50, # Slight overlap to don't cut words
101
- separators=["\nRecipe:", "Recipe:", "\n\n", "\n"] # Priority splitters
102
- )
103
- splits = text_splitter.split_documents(docs)
104
-
105
- vector_store = Chroma.from_documents(
106
- documents=splits, # We ingest the SPLITS, not the whole doc
107
- embedding=embed_model,
108
- persist_directory=CHROMA_PATH
109
- )
110
- return f"✅ Bar library updated. Split into {len(splits)} individual recipes."
 
 
 
 
 
 
 
 
 
 
 
111
 
112
  # --- BARTENDER LOGIC ---
113
  def bartend(message, history, img_path, inventory):
114
  debug_images = []
115
 
116
- # 1. Vision Scanning
117
  if img_path:
118
  crops = get_bottle_crops(img_path)
119
  debug_images = crops
@@ -122,7 +131,6 @@ def bartend(message, history, img_path, inventory):
122
  def identify_spirit(image_input):
123
  if image_input.mode != "RGB": image_input = image_input.convert("RGB")
124
  prompt = "User: <image>\nRead the label. What is the specific brand and type of alcohol? Be precise.\nAssistant:"
125
- # Positional argument fix
126
  out = vision_pipe(image_input, prompt, generate_kwargs={"max_new_tokens": 50})
127
  text = out[0]['generated_text']
128
  if "Assistant:" in text: return text.split("Assistant:")[-1].strip()
@@ -133,7 +141,6 @@ def bartend(message, history, img_path, inventory):
133
  inventory = re.sub(r'<.*?>', '', inventory).strip().split('.')[0]
134
  print(f"🔍 Pass 1 Result: {inventory}")
135
 
136
- # Generic Fallback
137
  generic_terms = ["vodka", "gin", "rum", "tequila", "whiskey", "whisky", "bourbon", "brandy", "alcohol", "liquor", "spirit", "bottle", "drink"]
138
  if inventory.lower() in generic_terms or len(inventory) < 4:
139
  print("⚠️ Result too generic. Trying FULL IMAGE...")
@@ -147,7 +154,6 @@ def bartend(message, history, img_path, inventory):
147
  print(f"❌ Vision Failed: {e}")
148
  inventory = "Unknown Spirit"
149
 
150
- # 2. RAG (Recipe Search)
151
  recipe_context = ""
152
  if inventory and inventory not in ["Empty Shelf", "Unknown Spirit", ""]:
153
  try:
@@ -155,17 +161,16 @@ def bartend(message, history, img_path, inventory):
155
  vs = Chroma(persist_directory=CHROMA_PATH, embedding_function=embed_model)
156
  search_query = f"Cocktail recipe using {inventory}"
157
 
158
- # INCREASED K to 5 to give you more options
159
- results = vs.similarity_search(search_query, k=5)
160
- recipe_context = "\n---\n".join([d.page_content for d in results])
161
  except Exception as e:
162
  print(f"Search error: {e}")
163
 
164
- # 3. Create Response
165
  if inventory == "Unknown Spirit":
166
  response = "I'm having trouble reading that label. Check the 'Vision Debug' gallery below—is the crop clear?"
167
  elif recipe_context:
168
- response = f"I see you have **{inventory}**. Here are some recipes from your collection:\n\n{recipe_context}"
169
  else:
170
  response = f"I see you have **{inventory}**! I don't have a specific recipe for that in the current library. Should I suggest a classic drink?"
171
 
@@ -188,7 +193,7 @@ with gr.Blocks() as demo:
188
  gr.Markdown("---")
189
  img = gr.Image(type="filepath", label="2. Photo of your Bottle")
190
 
191
- with gr.Accordion("🔍 Vision Debug (See what the AI sees)", open=True):
192
  debug_gallery = gr.Gallery(label="YOLO Crops", columns=2, height="auto")
193
 
194
  with gr.Column(scale=2):
 
7
  from transformers import pipeline
8
  from langchain_chroma import Chroma
9
  from langchain_community.document_loaders import PyPDFLoader, TextLoader
 
10
  from langchain_core.documents import Document
11
  from langchain_huggingface import HuggingFaceEmbeddings
12
+ from ultrultralytics import YOLO
13
 
14
  # --- CONFIGURATION ---
15
  CHROMA_PATH = "/tmp/chroma_db"
 
74
  except:
75
  return []
76
 
77
+ # --- RECIPE INGESTION (THE "HARD CUT" FIX) ---
78
  def ingest_recipes(files):
79
  if not files: return "❌ No files uploaded."
80
 
 
92
 
93
  if not docs: return "❌ Could not extract text."
94
 
95
+ # 1. Combine all pages/files into one massive text block
96
+ full_text = "\n".join([d.page_content for d in docs])
97
+
98
+ # 2. Strict Split: Cut exactly at the start of any line that says "Recipe:"
99
+ # (?m)^ means "look at the start of a line"
100
+ raw_chunks = re.split(r'(?m)^(?=Recipe:)', full_text)
101
+
102
+ split_docs = []
103
+ for chunk in raw_chunks:
104
+ # Clean out those long '⸻' separator lines
105
+ clean_chunk = re.sub(r'⸻+', '', chunk).strip()
106
+
107
+ # If the chunk actually has text in it, save it as a standalone recipe
108
+ if len(clean_chunk) > 20:
109
+ split_docs.append(Document(page_content=clean_chunk))
110
+
111
+ # 3. Save to Database
112
+ try:
113
+ vector_store = Chroma.from_documents(
114
+ documents=split_docs,
115
+ embedding=embed_model,
116
+ persist_directory=CHROMA_PATH
117
+ )
118
+ return f"✅ Bar library updated. Strictly split into {len(split_docs)} individual recipes."
119
+ except Exception as e:
120
+ return f"❌ Database Error: {e}"
121
 
122
  # --- BARTENDER LOGIC ---
123
  def bartend(message, history, img_path, inventory):
124
  debug_images = []
125
 
 
126
  if img_path:
127
  crops = get_bottle_crops(img_path)
128
  debug_images = crops
 
131
  def identify_spirit(image_input):
132
  if image_input.mode != "RGB": image_input = image_input.convert("RGB")
133
  prompt = "User: <image>\nRead the label. What is the specific brand and type of alcohol? Be precise.\nAssistant:"
 
134
  out = vision_pipe(image_input, prompt, generate_kwargs={"max_new_tokens": 50})
135
  text = out[0]['generated_text']
136
  if "Assistant:" in text: return text.split("Assistant:")[-1].strip()
 
141
  inventory = re.sub(r'<.*?>', '', inventory).strip().split('.')[0]
142
  print(f"🔍 Pass 1 Result: {inventory}")
143
 
 
144
  generic_terms = ["vodka", "gin", "rum", "tequila", "whiskey", "whisky", "bourbon", "brandy", "alcohol", "liquor", "spirit", "bottle", "drink"]
145
  if inventory.lower() in generic_terms or len(inventory) < 4:
146
  print("⚠️ Result too generic. Trying FULL IMAGE...")
 
154
  print(f"❌ Vision Failed: {e}")
155
  inventory = "Unknown Spirit"
156
 
 
157
  recipe_context = ""
158
  if inventory and inventory not in ["Empty Shelf", "Unknown Spirit", ""]:
159
  try:
 
161
  vs = Chroma(persist_directory=CHROMA_PATH, embedding_function=embed_model)
162
  search_query = f"Cocktail recipe using {inventory}"
163
 
164
+ # Retrieve the top 4 closest matching recipes
165
+ results = vs.similarity_search(search_query, k=4)
166
+ recipe_context = "\n\n---\n\n".join([d.page_content for d in results])
167
  except Exception as e:
168
  print(f"Search error: {e}")
169
 
 
170
  if inventory == "Unknown Spirit":
171
  response = "I'm having trouble reading that label. Check the 'Vision Debug' gallery below—is the crop clear?"
172
  elif recipe_context:
173
+ response = f"I see you have **{inventory}**. Here are a few options from your collection:\n\n{recipe_context}"
174
  else:
175
  response = f"I see you have **{inventory}**! I don't have a specific recipe for that in the current library. Should I suggest a classic drink?"
176
 
 
193
  gr.Markdown("---")
194
  img = gr.Image(type="filepath", label="2. Photo of your Bottle")
195
 
196
+ with gr.Accordion("🔍 Vision Debug", open=True):
197
  debug_gallery = gr.Gallery(label="YOLO Crops", columns=2, height="auto")
198
 
199
  with gr.Column(scale=2):