Anvit25 commited on
Commit
8dbca95
·
1 Parent(s): 0456f2e

Added Gradio app.py

Browse files
.gitattributes CHANGED
@@ -33,3 +33,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ *.png filter=lfs diff=lfs merge=lfs -text
37
+ *.jpg filter=lfs diff=lfs merge=lfs -text
38
+ *.jpeg filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ .env
app.py ADDED
@@ -0,0 +1,570 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # import json
2
+ # import os
3
+ # from pathlib import Path
4
+ # import numpy as np
5
+ # from fastapi import FastAPI, Query
6
+ # from fastapi.responses import FileResponse
7
+
8
+ # # Use a dedicated library for creating text embeddings
9
+ # from sentence_transformers import SentenceTransformer
10
+
11
+ # # --- 1. Load the Local Embedding Model ---
12
+ # # This line downloads (first time only) and loads a powerful, lightweight model
13
+ # # into memory. This is much more efficient than using an API for this task.
14
+ # print("Loading sentence-transformer model...")
15
+ # embedding_model = SentenceTransformer('all-MiniLM-L6-v2')
16
+ # print("Model loaded successfully.")
17
+
18
+ # # --- 2. Load Image Metadata ---
19
+ # try:
20
+ # with open("image.json", "r") as f:
21
+ # data = json.load(f)
22
+ # except FileNotFoundError:
23
+ # print("Error: image.json not found. Please make sure the file exists.")
24
+ # exit()
25
+
26
+ # image_list = []
27
+ # image_dir = Path("images")
28
+ # if not image_dir.exists():
29
+ # print(f"Error: The '{image_dir}' directory does not exist.")
30
+ # exit()
31
+
32
+ # # Prepare list of images and descriptions
33
+ # for page in data.get("pages", []):
34
+ # for img in page.get("images", []):
35
+ # description = img.get("description", "")
36
+ # if not description:
37
+ # continue
38
+ # # Match description to a file in the images folder
39
+ # for img_file in image_dir.iterdir():
40
+ # if img_file.is_file() and description.lower() in img_file.name.lower():
41
+ # image_list.append({"file": str(img_file), "description": description})
42
+ # break # Move to the next description once a match is found
43
+
44
+ # print(f"Found {len(image_list)} images with matching descriptions.")
45
+
46
+
47
+ # # --- 3. Function to Get Embeddings Locally ---
48
+ # def get_embedding(text: str) -> np.ndarray:
49
+ # """
50
+ # Generates an embedding for the given text using the local SentenceTransformer model.
51
+ # """
52
+ # # The model.encode() method directly returns a numpy array. It's fast and local.
53
+ # return embedding_model.encode(text)
54
+
55
+ # # --- 4. Precompute Embeddings for All Images ---
56
+ # print("Precomputing embeddings for all image descriptions...")
57
+ # for img in image_list:
58
+ # # Each description is converted into a numerical vector (embedding)
59
+ # img["embedding"] = get_embedding(img["description"])
60
+ # print("Embeddings precomputed.")
61
+
62
+
63
+ # # --- 5. FastAPI Application ---
64
+ # app = FastAPI(title="Semantic Image Search API")
65
+
66
+ # def cosine_similarity(vec1: np.ndarray, vec2: np.ndarray) -> float:
67
+ # """Calculates the cosine similarity between two vectors."""
68
+ # norm1 = np.linalg.norm(vec1)
69
+ # norm2 = np.linalg.norm(vec2)
70
+ # if norm1 == 0 or norm2 == 0:
71
+ # return 0.0
72
+ # return np.dot(vec1, vec2) / (norm1 * norm2)
73
+
74
+ # @app.get("/search_image/")
75
+ # async def search_image(query: str = Query(..., description="Search text")):
76
+ # # Convert the user's search query into an embedding
77
+ # query_emb = get_embedding(query)
78
+
79
+ # best_match = None
80
+ # highest_score = -1.0 # Cosine similarity ranges from -1 to 1
81
+
82
+ # # Compare the query embedding to all precomputed image description embeddings
83
+ # for img in image_list:
84
+ # score = cosine_similarity(query_emb, img["embedding"])
85
+ # if score > highest_score:
86
+ # highest_score = score
87
+ # best_match = img
88
+
89
+ # if best_match:
90
+ # print(f"Query: '{query}' -> Found best match: {best_match['file']} with score: {highest_score:.4f}")
91
+ # return FileResponse(best_match["file"])
92
+
93
+ # return {"error": "No matching image found"}
94
+
95
+
96
+
97
+ # import json
98
+ # import os
99
+ # from pathlib import Path
100
+ # import numpy as np
101
+ # import requests
102
+ # from typing import Optional, List, Tuple, Dict
103
+
104
+ # import gradio as gr
105
+ # from dotenv import load_dotenv
106
+ # from gradio_client import Client, handle_file
107
+ # from sentence_transformers import SentenceTransformer, util
108
+
109
+ # # --- 1. SETUP AND MODEL LOADING ---
110
+ # load_dotenv()
111
+ # GROQ_API_KEY = os.getenv("GROQ_API_KEY") # Still used for summarizing results
112
+
113
+ # if not GROQ_API_KEY:
114
+ # raise ValueError("GROQ_API_KEY not found. It's needed for summarizing analysis results.")
115
+
116
+ # print("Loading models and connecting to clients...")
117
+ # # Model for local intent classification and image search
118
+ # embedding_model = SentenceTransformer('all-MiniLM-L6-v2')
119
+ # try:
120
+ # chatbot_client = Client("Anvit25/LLM_chatbot2")
121
+ # audio_client = Client("Anvit25/new_audio")
122
+ # vision_client = Client("Anvit25/vision-classifier")
123
+ # print("All models and clients loaded successfully.")
124
+ # except Exception as e:
125
+ # print(f"FATAL: Failed to connect to a Gradio client: {e}")
126
+ # exit()
127
+
128
+ # # --- 2. LOAD & PRECOMPUTE DATA FOR LOCAL SEARCH & INTENT ---
129
+ # # Load local image data (same as before)
130
+ # image_list = []
131
+ # # ... (Your image loading and embedding logic is unchanged) ...
132
+
133
+ # # NEW: Load intents from JSON and pre-compute their embeddings
134
+ # intent_embeddings = {}
135
+ # try:
136
+ # with open("intents.json", "r") as f:
137
+ # intents_data = json.load(f)
138
+ # for intent, phrases in intents_data.items():
139
+ # intent_embeddings[intent] = {
140
+ # "phrases": phrases,
141
+ # "embeddings": embedding_model.encode(phrases)
142
+ # }
143
+ # print("Local intent classifier loaded successfully.")
144
+ # except FileNotFoundError:
145
+ # print("FATAL: intents.json not found. This file is required for the local intent classifier.")
146
+ # exit()
147
+
148
+ # # --- 3. HELPER FUNCTIONS ---
149
+
150
+ # def get_user_intent_local(user_query: str) -> dict:
151
+ # """
152
+ # Uses SentenceTransformer to classify user intent locally based on intents.json.
153
+ # """
154
+ # query_embedding = embedding_model.encode(user_query)
155
+ # best_match = {"intent": "chat", "score": 0.7, "query": user_query} # Default to chat
156
+
157
+ # for intent, data in intent_embeddings.items():
158
+ # # Calculate cosine similarity between user query and all trigger phrases for an intent
159
+ # scores = util.cos_sim(query_embedding, data["embeddings"])[0]
160
+ # max_score = max(scores)
161
+
162
+ # if max_score > best_match["score"]:
163
+ # best_match["score"] = max_score.item()
164
+ # best_match["intent"] = intent
165
+ # # Extract the subject by removing the trigger phrase
166
+ # best_phrase_index = np.argmax(scores)
167
+ # trigger_phrase = data["phrases"][best_phrase_index]
168
+ # subject = user_query.lower().replace(trigger_phrase.lower(), "").strip()
169
+ # best_match["query"] = subject if subject else user_query
170
+
171
+ # print(f"Local Intent Classifier Result: {best_match}")
172
+ # return best_match
173
+
174
+ # def summarize_analysis_with_groq(json_result: dict, context: str) -> str:
175
+ # """
176
+ # NEW: Takes a JSON/dict result and uses Groq to create a human-readable summary.
177
+ # """
178
+ # prompt = f"""
179
+ # You are a helpful assistant. Based on the following technical analysis from a specialized AI model, provide a friendly and concise summary for the user.
180
+ # Context: The user asked to '{context}'.
181
+ # AI Model's Raw JSON Output:
182
+ # ```json
183
+ # {json.dumps(json_result, indent=2)}
184
+ # ```
185
+ # Your friendly, easy-to-understand summary:
186
+ # """
187
+ # try:
188
+ # response = requests.post(
189
+ # "https://api.groq.com/openai/v1/chat/completions",
190
+ # headers={"Authorization": f"Bearer {GROQ_API_KEY}"},
191
+ # json={"messages": [{"role": "user", "content": prompt}], "model": "llama3-8b-8192"},
192
+ # )
193
+ # response.raise_for_status()
194
+ # return response.json()["choices"][0]["message"]["content"]
195
+ # except Exception as e:
196
+ # print(f"Groq summary error: {e}")
197
+ # return f"I finished the analysis, but had trouble summarizing it. Here is the raw data:\n`{json.dumps(json_result)}`"
198
+
199
+
200
+ # # ... (cosine_similarity and find_best_matching_image functions are unchanged) ...
201
+ # def find_best_matching_image(query: str) -> Optional[dict]: # ... (Identical) ...
202
+ # pass
203
+ # def generate_groq_narrative(user_query: str, search_result: Optional[dict]) -> str: # ... (Identical) ...
204
+ # pass
205
+
206
+ # # --- 4. CORE GRADIO LOGIC (UPDATED) ---
207
+
208
+ # def handle_image_analysis(file_path: str) -> str:
209
+ # """Analyzes an image and returns a text summary."""
210
+ # try:
211
+ # vision_result = vision_client.predict(image=handle_file(file_path), api_name="/predict")
212
+ # # NEW: Summarize the JSON result
213
+ # summary = summarize_analysis_with_groq(vision_result, "Analyze this image")
214
+ # return summary
215
+ # except Exception as e:
216
+ # return f"Sorry, I couldn't analyze the image. Error: {e}"
217
+
218
+ # def handle_audio_analysis(file_path: str) -> str:
219
+ # """Analyzes audio and returns a text summary."""
220
+ # try:
221
+ # prediction_text, _ = audio_client.predict(audio_filepath=handle_file(file_path), api_name="/predict")
222
+ # return f"The audio analysis result is: **{prediction_text}**"
223
+ # except Exception as e:
224
+ # return f"Sorry, I couldn't analyze the audio. Error: {e}"
225
+
226
+
227
+ # def chat_interface(user_input: dict, history: List[Tuple[str, str]]):
228
+ # """
229
+ # The main function that powers the Gradio chat interface.
230
+ # It now prioritizes file uploads over text for intent classification.
231
+ # """
232
+ # user_text = user_input["text"].strip()
233
+ # user_files = user_input["files"]
234
+ # new_history = history or []
235
+
236
+ # bot_message = ""
237
+
238
+ # # === Priority 1: Handle file uploads ===
239
+ # if user_files:
240
+ # file_path = user_files[0]
241
+ # # Display the uploaded file in the chat
242
+ # new_history.append(((file_path,), None))
243
+
244
+ # if file_path.lower().endswith(('.png', '.jpg', '.jpeg', '.webp')):
245
+ # bot_message = handle_image_analysis(file_path)
246
+ # elif file_path.lower().endswith(('.wav', '.mp3', '.flac')):
247
+ # bot_message = handle_audio_analysis(file_path)
248
+ # else:
249
+ # bot_message = "I'm not sure how to handle that file type."
250
+
251
+ # new_history[-1] = (new_history[-1][0], bot_message)
252
+ # return new_history, None
253
+
254
+ # # === Priority 2: Handle text-only queries if no files are uploaded ===
255
+ # if not user_text:
256
+ # return new_history, None
257
+
258
+ # new_history.append((user_text, None))
259
+ # intent_data = get_user_intent_local(user_text) # Use local classifier
260
+ # intent = intent_data.get("intent")
261
+ # query_subject = intent_data.get("query")
262
+
263
+ # if intent == "chat":
264
+ # prediction = chatbot_client.predict(user_input=query_subject, api_name="/chatbot_response")
265
+ # bot_message = prediction[-1]['content']
266
+
267
+ # elif intent == "search_local_image":
268
+ # found_image = find_best_matching_image(query_subject)
269
+ # bot_message = generate_groq_narrative(query_subject, found_image)
270
+ # new_history[-1] = (user_text, bot_message)
271
+ # if found_image:
272
+ # new_history.append((None, (found_image['file'],))) # Display image on new line
273
+ # return new_history, None
274
+
275
+ # # For these intents, we just prompt the user to upload a file
276
+ # elif intent == "request_image_analysis":
277
+ # bot_message = "Of course. Please upload the image you want me to analyze."
278
+ # elif intent == "request_audio_analysis":
279
+ # bot_message = "I'm ready. Please upload the audio file for analysis."
280
+ # else:
281
+ # bot_message = "I'm not sure how to handle that. Can you rephrase?"
282
+
283
+ # new_history[-1] = (user_text, bot_message)
284
+ # return new_history, None
285
+
286
+
287
+ # # --- 5. GRADIO UI DEFINITION ---
288
+ # with gr.Blocks(theme=gr.themes.Soft(), title="Multi-Modal AI Chatbot") as demo:
289
+ # gr.Markdown("# Multi-Modal AI Chatbot")
290
+ # gr.Markdown("I can chat, search for local images, or analyze images and audio you upload.")
291
+
292
+ # # CORRECTED LINE: The 'bubble_fn' argument is removed.
293
+ # chatbot_history = gr.Chatbot(height=600, show_copy_button=True, layout="bubble", render=False)
294
+
295
+ # with gr.Row():
296
+ # multimodal_textbox = gr.MultimodalTextbox(
297
+ # file_types=["image", "audio"],
298
+ # placeholder="Type your message or upload a file...",
299
+ # submit_btn="Send",
300
+ # render=False,
301
+ # autofocus=True
302
+ # )
303
+
304
+ # # Render components after defining the layout
305
+ # chatbot_history.render()
306
+ # multimodal_textbox.render()
307
+
308
+ # multimodal_textbox.submit(
309
+ # fn=chat_interface,
310
+ # inputs=[multimodal_textbox, chatbot_history],
311
+ # outputs=[chatbot_history, multimodal_textbox]
312
+ # )
313
+
314
+ # if __name__ == "__main__":
315
+ # demo.launch(debug=True)
316
+
317
+
318
+
319
+
320
+
321
+
322
+
323
+
324
+ import json
325
+ import os
326
+ from pathlib import Path
327
+ import numpy as np
328
+ import requests
329
+ from typing import Optional, List, Tuple, Dict
330
+
331
+ import gradio as gr
332
+ from dotenv import load_dotenv
333
+ from gradio_client import Client, handle_file
334
+ from sentence_transformers import SentenceTransformer
335
+
336
+ # --- 1. SETUP AND MODEL LOADING ---
337
+ load_dotenv()
338
+ GROQ_API_KEY = os.getenv("GROQ_API_KEY")
339
+
340
+ if not GROQ_API_KEY:
341
+ raise ValueError("GROQ_API_KEY not found. It's needed for summarizing analysis results.")
342
+
343
+ print("Loading models and connecting to clients...")
344
+ embedding_model = SentenceTransformer('all-MiniLM-L6-v2')
345
+ try:
346
+ chatbot_client = Client("Anvit25/LLM_chatbot2")
347
+ audio_client = Client("Anvit25/new_audio")
348
+ vision_client = Client("Anvit25/vision-classifier")
349
+ print("All models and clients loaded successfully.")
350
+ except Exception as e:
351
+ print(f"FATAL: Failed to connect to a Gradio client: {e}")
352
+ exit()
353
+
354
+ # --- 2. LOAD & PRECOMPUTE DATA FOR LOCAL SEARCH & INTENT ---
355
+ # Load local image data
356
+ image_list = []
357
+ try:
358
+ with open("image.json", "r") as f:
359
+ data = json.load(f)
360
+ image_dir = Path("images")
361
+ if image_dir.exists():
362
+ for page in data.get("pages", []):
363
+ for img in page.get("images", []):
364
+ description = img.get("description", "")
365
+ if not description: continue
366
+ for img_file in image_dir.iterdir():
367
+ if img_file.is_file() and description.lower() in img_file.name.lower():
368
+ image_list.append({"file": str(img_file), "description": description})
369
+ break
370
+ print(f"Found {len(image_list)} local images for semantic search.")
371
+ print("Precomputing embeddings for local images...")
372
+ for img in image_list:
373
+ img["embedding"] = embedding_model.encode(img["description"])
374
+ print("Embeddings precomputed.")
375
+ else:
376
+ print("Warning: 'images' directory not found.")
377
+ except FileNotFoundError:
378
+ print("Warning: image.json not found.")
379
+
380
+ # Load intents from JSON for the new rule-based classifier
381
+ try:
382
+ with open("intents.json", "r") as f:
383
+ intents_data = json.load(f)
384
+ print("Local intent classifier phrases loaded successfully.")
385
+ except FileNotFoundError:
386
+ print("FATAL: intents.json not found. This file is required.")
387
+ exit()
388
+
389
+ # --- 3. HELPER FUNCTIONS ---
390
+
391
+ def get_user_intent_local(user_query: str) -> dict:
392
+ """
393
+ CORRECTED: Uses a robust rule-based check to classify user intent.
394
+ This is much more reliable than the previous semantic search approach for intents.
395
+ """
396
+ lower_query = user_query.lower()
397
+
398
+ # Iterate through intents and their trigger phrases
399
+ for intent, phrases in intents_data.items():
400
+ for phrase in phrases:
401
+ if phrase.lower() in lower_query:
402
+ # If a trigger phrase is found, identify the intent
403
+ subject = lower_query.replace(phrase.lower(), "").strip()
404
+ result = {
405
+ "intent": intent,
406
+ "query": subject if subject else user_query
407
+ }
408
+ print(f"Local Intent Classifier Result: {result}")
409
+ return result
410
+
411
+ # If no specific trigger phrase is found, default to a general chat
412
+ result = {"intent": "chat", "query": user_query}
413
+ print(f"Local Intent Classifier Result: {result}")
414
+ return result
415
+
416
+ def summarize_analysis_with_groq(json_result: dict, context: str) -> str:
417
+ """Takes a JSON/dict result and uses Groq to create a human-readable summary."""
418
+ prompt = f"""
419
+ You are a helpful assistant. Based on the following technical analysis from a specialized AI model, provide a friendly and concise summary for the user.
420
+ Context: The user asked to '{context}'.
421
+ AI Model's Raw JSON Output:
422
+ ```json
423
+ {json.dumps(json_result, indent=2)}
424
+ ```
425
+ Your friendly, easy-to-understand summary:
426
+ """
427
+ try:
428
+ response = requests.post(
429
+ "https://api.groq.com/openai/v1/chat/completions",
430
+ headers={"Authorization": f"Bearer {GROQ_API_KEY}"},
431
+ json={"messages": [{"role": "user", "content": prompt}], "model": "llama-3.3-70b-versatile"},
432
+ )
433
+ response.raise_for_status()
434
+ return response.json()["choices"][0]["message"]["content"]
435
+ except Exception as e:
436
+ print(f"Groq summary error: {e}")
437
+ return f"I finished the analysis, but had trouble summarizing it. Here is the raw data:\n`{json.dumps(json_result)}`"
438
+
439
+ def cosine_similarity(vec1, vec2):
440
+ norm1 = np.linalg.norm(vec1)
441
+ norm2 = np.linalg.norm(vec2)
442
+ if norm1 == 0 or norm2 == 0: return 0.0
443
+ return np.dot(vec1, vec2) / (norm1 * norm2)
444
+
445
+ def find_best_matching_image(query: str) -> Optional[dict]:
446
+ if not image_list: return None
447
+ query_emb = embedding_model.encode(query)
448
+ best_match = max(image_list, key=lambda img: cosine_similarity(query_emb, img.get("embedding", [])))
449
+ highest_score = cosine_similarity(query_emb, best_match.get("embedding", []))
450
+ if best_match and highest_score > 0.4:
451
+ return best_match
452
+ return None
453
+
454
+ def generate_groq_narrative(user_query: str, search_result: Optional[dict]) -> str:
455
+ if search_result:
456
+ prompt = f"A user asked to find: '{user_query}'. You found an image described as: '{search_result['description']}'. Craft a short, friendly response."
457
+ else:
458
+ prompt = f"A user asked to find: '{user_query}'. You searched but couldn't find a match. Craft a short, polite response."
459
+ try:
460
+ response = requests.post(
461
+ "https://api.groq.com/openai/v1/chat/completions",
462
+ headers={"Authorization": f"Bearer {GROQ_API_KEY}"},
463
+ json={"messages": [{"role": "user", "content": prompt}], "model": "llama3-8b-8192"},
464
+ )
465
+ response.raise_for_status()
466
+ return response.json()["choices"][0]["message"]["content"]
467
+ except Exception as e:
468
+ print(f"Groq narrative error: {e}")
469
+ return "I had an issue describing the search result."
470
+
471
+ # --- 4. CORE GRADIO LOGIC ---
472
+
473
+ def handle_image_analysis(file_path: str) -> str:
474
+ try:
475
+ vision_result = vision_client.predict(image=handle_file(file_path), api_name="/predict")
476
+ summary = summarize_analysis_with_groq(vision_result, "Analyze this image")
477
+ return summary
478
+ except Exception as e:
479
+ return f"Sorry, I couldn't analyze the image. Error: {e}"
480
+
481
+ def handle_audio_analysis(file_path: str) -> str:
482
+ try:
483
+ prediction_text, _ = audio_client.predict(audio_filepath=handle_file(file_path), api_name="/predict")
484
+ return f"The audio analysis result is: **{prediction_text}**"
485
+ except Exception as e:
486
+ return f"Sorry, I couldn't analyze the audio. Error: {e}"
487
+
488
+ def chat_interface(user_input: dict, history: List[Tuple[str, str]]):
489
+ user_text = user_input["text"].strip()
490
+ user_files = user_input["files"]
491
+ new_history = history or []
492
+
493
+ # Priority 1: Handle file uploads
494
+ if user_files:
495
+ file_path = user_files[0]
496
+ new_history.append(((file_path,), None))
497
+
498
+ if file_path.lower().endswith(('.png', '.jpg', '.jpeg', '.webp')):
499
+ bot_message = handle_image_analysis(file_path)
500
+ elif file_path.lower().endswith(('.wav', '.mp3', '.flac')):
501
+ bot_message = handle_audio_analysis(file_path)
502
+ else:
503
+ bot_message = "I'm not sure how to handle that file type."
504
+
505
+ new_history[-1] = (new_history[-1][0], bot_message)
506
+ return new_history, None
507
+
508
+ # Priority 2: Handle text-only queries
509
+ if not user_text:
510
+ return new_history, None
511
+
512
+ new_history.append((user_text, None))
513
+ intent_data = get_user_intent_local(user_text) # Use the NEW, robust classifier
514
+ intent = intent_data.get("intent")
515
+ query_subject = intent_data.get("query")
516
+
517
+ if intent == "chat":
518
+ try:
519
+ prediction = chatbot_client.predict(user_input=query_subject, api_name="/chatbot_response")
520
+ bot_message = prediction[-1]['content']
521
+ except Exception as e:
522
+ print(f"Error calling chatbot client: {e}")
523
+ bot_message = "I'm sorry, I'm having trouble connecting to my chat brain right now. Please try again."
524
+
525
+ elif intent == "search_local_image":
526
+ found_image = find_best_matching_image(query_subject)
527
+ bot_message = generate_groq_narrative(query_subject, found_image)
528
+ new_history[-1] = (user_text, bot_message)
529
+ if found_image:
530
+ new_history.append((None, (found_image['file'],)))
531
+ return new_history, None
532
+
533
+ elif intent == "request_image_analysis":
534
+ bot_message = "Of course. Please upload the image you want me to analyze."
535
+ elif intent == "request_audio_analysis":
536
+ bot_message = "I'm ready. Please upload the audio file for analysis."
537
+ else:
538
+ bot_message = "I'm not sure how to handle that. Can you rephrase?"
539
+
540
+ new_history[-1] = (user_text, bot_message)
541
+ return new_history, None
542
+
543
+
544
+ # --- 5. GRADIO UI DEFINITION ---
545
+ with gr.Blocks(theme=gr.themes.Soft(), title="Multi-Modal AI Chatbot") as demo:
546
+ gr.Markdown("# Multi-Modal AI Chatbot")
547
+ gr.Markdown("I can chat, search for local images, or analyze images and audio you upload.")
548
+
549
+ chatbot_history = gr.Chatbot(height=600, show_copy_button=True, layout="bubble", render=False)
550
+
551
+ with gr.Row():
552
+ multimodal_textbox = gr.MultimodalTextbox(
553
+ file_types=["image", "audio"],
554
+ placeholder="Type your message or upload a file...",
555
+ submit_btn="Send",
556
+ render=False,
557
+ autofocus=True
558
+ )
559
+
560
+ chatbot_history.render()
561
+ multimodal_textbox.render()
562
+
563
+ multimodal_textbox.submit(
564
+ fn=chat_interface,
565
+ inputs=[multimodal_textbox, chatbot_history],
566
+ outputs=[chatbot_history, multimodal_textbox]
567
+ )
568
+
569
+ if __name__ == "__main__":
570
+ demo.launch(debug=True)
image.json ADDED
@@ -0,0 +1,315 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "document_title": "Samsung Washing Machine Service Manual (WF316LAW Series)",
3
+ "models_covered": [
4
+ "WF316LAW", "WF326***", "WF306***", "WF317***", "WF206***", "WF317AAW/XAA", "WF206BNW/XAA"
5
+ ],
6
+ "pages": [
7
+ {
8
+ "page_number": 1,
9
+ "title": "Cover Page",
10
+ "content_summary": "The cover page introduces the washing machine service manual, listing basic models, project names, and key product features.",
11
+ "images": [
12
+ {
13
+ "type": "product_photo",
14
+ "description": "Image of the silver Samsung WF316LAS washing machine."
15
+ },
16
+ {
17
+ "type": "product_photo",
18
+ "description": "Image of the champagne/beige Samsung WF316BAC washing machine."
19
+ },
20
+ {
21
+ "type": "product_photo",
22
+ "description": "Image of the white Samsung WF306LAW washing machine."
23
+ },
24
+ {
25
+ "type": "product_photo",
26
+ "description": "Image of the white Samsung WF206LNW washing machine."
27
+ }
28
+ ],
29
+ "structured_content": [
30
+ {
31
+ "type": "model_info",
32
+ "heading": "Model Information",
33
+ "data": {
34
+ "Basic Model": "WF316LAW",
35
+ "Model Name": ["<FRONTIER 1 PROJECT>", "WF326***", "WF306***", "WF316***", "WF317***", "<MARS 1 PROJECT>", "WF206***"],
36
+ "Model Code": ["WF317AAW/XAA (FRONTIER1)", "WF206BNW/XAA (MARS1)"]
37
+ }
38
+ },
39
+ {
40
+ "type": "feature_list",
41
+ "heading": "The Feature of Product",
42
+ "items": [
43
+ "SilverCare",
44
+ "SuperSize Capacity",
45
+ "Direct Drive Motor",
46
+ "Child Lock",
47
+ "My Cycle"
48
+ ]
49
+ }
50
+ ]
51
+ },
52
+ {
53
+ "page_number": 2,
54
+ "title": "Table of Contents (Page 1)",
55
+ "content_summary": "The first page of the table of contents, covering sections 1 through 7.",
56
+ "images": [],
57
+ "structured_content": [
58
+ {
59
+ "type": "table_of_contents",
60
+ "entries": [
61
+ {"section": "1. PRECAUTIONS", "page": "1-1"},
62
+ {"section": "2. PRODUCT SPECIFICATIONS", "page": "2-1"},
63
+ {"section": "3. OPERATING INSTRUCTIONS", "page": "3-1"},
64
+ {"section": "4. ALIGNMENT AND ADJUSTMENTS", "page": "4-1"},
65
+ {"section": "5. ASSEMBLY AND DISASSEMBLY", "page": "5-1"},
66
+ {"section": "6. TROUBLE SHOOTING", "page": "6-1"},
67
+ {"section": "7. EXPLODED VIEWS AND PARTS LIST", "page": "7-1"}
68
+ ]
69
+ }
70
+ ]
71
+ },
72
+ {
73
+ "page_number": 4,
74
+ "title": "1-1. Safety Precautions",
75
+ "content_summary": "A list of 19 critical safety precautions to be followed by service personnel before, during, and after servicing the appliance.",
76
+ "images": [],
77
+ "structured_content": [
78
+ {
79
+ "type": "safety_list",
80
+ "items": [
81
+ "Do not allow the customer to repair the product.",
82
+ "Disconnect power to the appliance before servicing.",
83
+ "Do not use multi-plug.",
84
+ "Check for any damage on power plug or power outlet.",
85
+ "Make sure to earth the product.",
86
+ "Do not clean the product with water."
87
+ ]
88
+ }
89
+ ]
90
+ },
91
+ {
92
+ "page_number": 5,
93
+ "title": "1-2. Precautions Upon Installation",
94
+ "content_summary": "Visual guide on how to remove shipping bolts and general precautions for installing the washing machine.",
95
+ "images": [
96
+ {
97
+ "type": "instructional_diagram",
98
+ "description": "A 4-step diagram showing how to remove shipping bolts and cover the holes."
99
+ },
100
+ {
101
+ "type": "instructional_diagram",
102
+ "description": "Illustrations depicting installation precautions: use two people to move, ensure a firm/level floor, avoid direct sunlight/humidity, provide easy outlet access, avoid freezing temperatures, and keep away from heat sources."
103
+ }
104
+ ],
105
+ "structured_content": []
106
+ },
107
+ {
108
+ "page_number": 10,
109
+ "title": "2-1. Specifications of Product",
110
+ "content_summary": "A table detailing the technical specifications of the front-loading washer, including dimensions, weight, capacity, power consumption, and spin speeds for various models.",
111
+ "images": [],
112
+ "structured_content": [
113
+ {
114
+ "type": "specification_table",
115
+ "data": [
116
+ {"Specification": "Height-Overall", "Value": "38 (96.5) Inches (cm)"},
117
+ {"Specification": "Width", "Value": "27 (68.6) Inches (cm)"},
118
+ {"Specification": "Depth", "Value": "30.25 (77.0) Inches (cm)"},
119
+ {"Specification": "Weight", "Value": "89.9 kg"},
120
+ {"Specification": "Capacity", "Value": "3.29 Cu.ft"},
121
+ {"Specification": "Power Consumption (Washing)", "Value": "226W"},
122
+ {"Specification": "Spin Revolution (WF326***)", "Value": "1200rpm"},
123
+ {"Specification": "Spin Revolution (WF306***)", "Value": "1000rpm"}
124
+ ]
125
+ }
126
+ ]
127
+ },
128
+ {
129
+ "page_number": 14,
130
+ "title": "3-1. Overview of the Control Panel",
131
+ "content_summary": "Description of the main control panel functions, including the digital display, temperature, spin, soil level, signal, and SilverCare buttons.",
132
+ "images": [
133
+ {
134
+ "type": "control_panel_diagram",
135
+ "description": "A detailed diagram of the washing machine's control panel with numbered callouts pointing to different buttons and the display."
136
+ }
137
+ ],
138
+ "structured_content": [
139
+ {
140
+ "type": "function_list",
141
+ "items": [
142
+ {"number": 1, "name": "Digital graphic display", "description": "Displays remaining wash time, wash information, and error messages."},
143
+ {"number": 2, "name": "Temperature selection button", "description": "Cycles through temperature options like Extra Hot/Cold, Hot/Cold, etc."},
144
+ {"number": 3, "name": "Spin selection button", "description": "Cycles through spin speed options like Extra High, High, Medium, Low, No Spin."},
145
+ {"number": 4, "name": "Soil Level selection button", "description": "Selects washing time based on soil level: Heavy, Normal, Light."},
146
+ {"number": 6, "name": "SilverCare button", "description": "Activates the silver ion sanitizing feature."}
147
+ ]
148
+ }
149
+ ]
150
+ },
151
+ {
152
+ "page_number": 24,
153
+ "title": "4-1. General Error Function",
154
+ "content_summary": "A comprehensive table listing all diagnostic and error codes, their descriptions, and the recommended corrective actions for troubleshooting.",
155
+ "images": [],
156
+ "structured_content": [
157
+ {
158
+ "type": "error_code_table",
159
+ "data": [
160
+ {"LED_Display": "nd", "Diagnostic_Code": 1, "Description": "The water level fails to drop below the Reset Water Level within 15 minutes.", "Corrective_Action": "Go to 'Will Not Drain' Troubleshooting Section."},
161
+ {"LED_Display": "LO", "Diagnostic_Code": 2, "Description": "Door fails to unlock after 3 attempts.", "Corrective_Action": "Go to 'Will Not Unlock' Troubleshooting Section."},
162
+ {"LED_Display": "nF", "Diagnostic_Code": 3, "Description": "Filling continues for more than 16 minutes or no change of water level for 3 minutes.", "Corrective_Action": "Go to 'No Water Fill' Troubleshooting Section."},
163
+ {"LED_Display": "LE", "Diagnostic_Code": 8, "Description": "Water Level Sensor Trouble.", "Corrective_Action": "Go to 'No Water Fill' Troubleshooting Section."},
164
+ {"LED_Display": "dc", "Diagnostic_Code": 10, "Description": "Unbalance or cabinet bump is detected during final spin.", "Corrective_Action": "Go to 'Wet Clothes' Troubleshooting Section."},
165
+ {"LED_Display": "tE", "Diagnostic_Code": 29, "Description": "Abnormal high/low temperature or resistance (Thermal sensor or PBA).", "Corrective_Action": "Check Water Temperature. Replace PCB or thermistor."},
166
+ {"LED_Display": "3E", "Diagnostic_Code": "3E", "Description": "Over-current is detected. Motor won’t turn.", "Corrective_Action": "Evaluate wire harness. Test Motor."},
167
+ {"LED_Display": "SUdS", "Diagnostic_Code": "-", "Description": "Suds is detected during the washing session.", "Corrective_Action": "Guide a user to reduce amount of detergent usage."}
168
+ ]
169
+ }
170
+ ]
171
+ },
172
+ {
173
+ "page_number": 35,
174
+ "title": "5-2. Disassembly",
175
+ "content_summary": "Step-by-step photographic guide for disassembling key components: Top Cover, MEMS Sensor, Water Level Sensor, and Ag Kit.",
176
+ "images": [
177
+ { "type": "disassembly_photo", "description": "Photo showing the removal of the Top Cover." },
178
+ { "type": "disassembly_photo", "description": "Photo showing the location and removal of the MEMS Sensor." },
179
+ { "type": "disassembly_photo", "description": "Photo showing the disconnection of the Water Level Sensor." },
180
+ { "type": "disassembly_photo", "description": "Photo showing the removal of the Ag (SilverCare) Kit." }
181
+ ],
182
+ "structured_content": [
183
+ {
184
+ "type": "disassembly_steps",
185
+ "part_name": "Top Cover",
186
+ "steps": ["Unplug the unit.", "Remove screws(2ea) at the back.", "Slide Top Cover back and lift it up."]
187
+ },
188
+ {
189
+ "type": "disassembly_steps",
190
+ "part_name": "Water Level Sensor",
191
+ "steps": ["Unplug the unit.", "Remove Top Cover.", "Remove the screw(1ea).", "Disconnect the wire harness.", "Take out Pressure Hose."]
192
+ }
193
+ ]
194
+ },
195
+ {
196
+ "page_number": 51,
197
+ "title": "7-2. THE CONTROL PARTS (WF317AAW/XAA)",
198
+ "content_summary": "Exploded view diagram of the control panel and dispenser assembly for model WF317AAW/XAA, with part callouts for identification.",
199
+ "images": [
200
+ {
201
+ "type": "exploded_view",
202
+ "description": "Exploded diagram showing the assembly of the main control panel, knobs, buttons, dispenser drawer, and housing, with labels like C0002, R0014, Y0170."
203
+ }
204
+ ],
205
+ "structured_content": []
206
+ },
207
+ {
208
+ "page_number": 52,
209
+ "title": "Parts List for Control Parts (WF317AAW/XAA)",
210
+ "content_summary": "A detailed parts list corresponding to the exploded view on the previous page, providing part numbers, descriptions, and specifications.",
211
+ "images": [],
212
+ "structured_content": [
213
+ {
214
+ "type": "parts_list_table",
215
+ "data": [
216
+ {"Location.No": "C0002", "CODE-NO": "DC97-10513R", "DESCRIPTION": "ASSY-S.PANEL CONTROL"},
217
+ {"Location.No": "C0029", "CODE-NO": "DC97-10511A", "DESCRIPTION": "ASSY-KNOB ENCODER"},
218
+ {"Location.No": "R0014", "CODE-NO": "DC97-10336A", "DESCRIPTION": "ASSY-DRAWER"},
219
+ {"Location.No": "Y0170", "CODE-NO": "MFS-WF317-T0", "DESCRIPTION": "ASSY-PCB PARTS"}
220
+ ]
221
+ }
222
+ ]
223
+ },
224
+ {
225
+ "page_number": 72,
226
+ "title": "8. BLOCK DIAGRAM",
227
+ "content_summary": "A high-level block diagram showing the electronic architecture of the washing machine, illustrating power flow (AC/DC) and signal paths between the Main PBA and other modules like the motor, sensors, and display.",
228
+ "images": [
229
+ {
230
+ "type": "block_diagram",
231
+ "description": "A diagram showing the main PBA connected to Input Voltage, Motor, Drive Circuit, and various other PBAs (Display, AG, MEMS)."
232
+ }
233
+ ],
234
+ "structured_content": []
235
+ },
236
+ {
237
+ "page_number": 74,
238
+ "title": "9-1. WIRING DIAGRAM",
239
+ "content_summary": "A complete wiring schematic of the washing machine, detailing all electrical connections between components.",
240
+ "images": [
241
+ {
242
+ "type": "schematic_diagram",
243
+ "description": "Full wiring diagram showing connections between the main and sub PCBs, motor, sensors, valves, heater, pump, door lock, etc."
244
+ }
245
+ ],
246
+ "structured_content": []
247
+ },
248
+ {
249
+ "page_number": 82,
250
+ "title": "11-1. MAIN PCB Schematic Diagram",
251
+ "content_summary": "A detailed, component-level electronic schematic for the Main Printed Circuit Board (PCB).",
252
+ "images": [
253
+ {
254
+ "type": "schematic_diagram",
255
+ "description": "A complex electronic circuit diagram showing microcontrollers, power circuits, relays, and connectors for the Main PBA."
256
+ }
257
+ ],
258
+ "structured_content": []
259
+ },
260
+ {
261
+ "page_number": 92,
262
+ "title": "13-1. Model Name Nomenclature",
263
+ "content_summary": "A flowchart diagram explaining how to decode the Samsung washing machine model numbers.",
264
+ "images": [
265
+ {
266
+ "type": "flowchart",
267
+ "description": "A diagram breaking down a model number like 'WF326LAS1/XAA' into its constituent parts: Product Type, Capacity, RPM, Year, Dealer, Features, Color, and Service Code."
268
+ }
269
+ ],
270
+ "structured_content": []
271
+ },
272
+ {
273
+ "page_number": 96,
274
+ "title": "13-5. Q & A",
275
+ "content_summary": "A Frequently Asked Questions (FAQ) section addressing common user queries about machine operation, such as door unlocking, error codes, and power failures.",
276
+ "images": [],
277
+ "structured_content": [
278
+ {
279
+ "type": "faq_table",
280
+ "data": [
281
+ {"Question": "How long does it take for the door to unlock?", "Answer": "It takes approximately 2-3 seconds for the door to unlock."},
282
+ {"Question": "What should I do when Information Code ('dc') lights up?", "Answer": "Press the Start/Pause dial and then restart the cycle."},
283
+ {"Question": "The washer door gets locked after a power failure. How can I open it?", "Answer": "The door will remain locked until power comes back on. The cycle will resume where it left off."}
284
+ ]
285
+ }
286
+ ]
287
+ },
288
+ {
289
+ "page_number": 104,
290
+ "title": "Back Cover / GSPN Information",
291
+ "content_summary": "The back cover of the manual, providing a list of websites for the Global Service Partner Network (GSPN) and copyright information.",
292
+ "images": [
293
+ {
294
+ "type": "logo",
295
+ "description": "Samsung company logo."
296
+ }
297
+ ],
298
+ "structured_content": [
299
+ {
300
+ "type": "weblink_table",
301
+ "heading": "GSPN (Global Service Partner Network)",
302
+ "data": [
303
+ {"Area": "North America", "Web Site": "http://service.samsungportal.com"},
304
+ {"Area": "Europe", "Web Site": "http://europe.samsungportal.com"},
305
+ {"Area": "Asia", "Web Site": "http://asia.samsungportal.com"}
306
+ ]
307
+ },
308
+ {
309
+ "type": "legal_notice",
310
+ "text": "© 2007 Samsung Electronics Co.,Ltd. All rights reserved. Code No.: DC68-02631A-00"
311
+ }
312
+ ]
313
+ }
314
+ ]
315
+ }
images/104_Samsung company logo.png ADDED

Git LFS Details

  • SHA256: 51cfd172586712758668fd8f2c56d5f32059d3650ca2b4711a245c40bae1b4ec
  • Pointer size: 129 Bytes
  • Size of remote file: 3.83 kB
images/14_A detailed diagram.png ADDED

Git LFS Details

  • SHA256: 45fe906d3dde43806e6af9a6b4c135dfefa65bea9cb1e34ff98cdd9d17e520c4
  • Pointer size: 131 Bytes
  • Size of remote file: 115 kB
images/1_Image of the champagnebeige.png ADDED

Git LFS Details

  • SHA256: e7395cff6dc735cd2fe4a0ff1fc7fd18b9e25bea1d21c34bb710265d9fd563ae
  • Pointer size: 131 Bytes
  • Size of remote file: 100 kB
images/1_Image of the silver.png ADDED

Git LFS Details

  • SHA256: 2767d44f8e781f843214e8ebaf43686047b823ba2455935f33368ed02241d65f
  • Pointer size: 131 Bytes
  • Size of remote file: 166 kB
images/1_Image of the white Samsung.png ADDED

Git LFS Details

  • SHA256: 6757d7475bc9cd88152ce7443a504748d861d44c671ff4534a99d2eed1b38def
  • Pointer size: 130 Bytes
  • Size of remote file: 91.8 kB
images/1_Image of the white.png ADDED

Git LFS Details

  • SHA256: dfd60dd1b7f7eb9ab5f58014a8e7dae94d766fed806be682d60638f0c4336f97
  • Pointer size: 130 Bytes
  • Size of remote file: 87.6 kB
images/5_A 4-step diagram showing.png ADDED

Git LFS Details

  • SHA256: b196e1527457885579f7341b772ba57a3bd76652d33f1f63a2dd8db93aea57c3
  • Pointer size: 130 Bytes
  • Size of remote file: 99.9 kB
images/5_Illustrations depicting install.png ADDED

Git LFS Details

  • SHA256: 83266a19cb5bb31fe09c62b46da20d251ee215b5f4d21b5f048821923a2d0a10
  • Pointer size: 130 Bytes
  • Size of remote file: 96.8 kB
images/74_Full wiring.png ADDED

Git LFS Details

  • SHA256: 8681e553f075809d2bdf2cfe0686c5e93f02e45653c5c331650e24929123b758
  • Pointer size: 131 Bytes
  • Size of remote file: 182 kB
images/circuits, relays, and connectors for the Main PBA.png ADDED

Git LFS Details

  • SHA256: ddc37414fe6d49b5215e3c55570bf18a89131b255aae12c9fea16a1b130ddfe1
  • Pointer size: 131 Bytes
  • Size of remote file: 202 kB
images/housing, with labels like C0002.png ADDED

Git LFS Details

  • SHA256: fdce6b35defb966cfb57e77c27dff78aefb0ec4c39f67c6c61160c35fd83336c
  • Pointer size: 131 Bytes
  • Size of remote file: 186 kB
images/input Voltage, Motor, Drive Circuit, and various other PBAs (Display, AG, MEMS.png ADDED

Git LFS Details

  • SHA256: 7a4b6c95809e48802f805ced0890d76ada4ee86cc23523af8e7c75069da575ad
  • Pointer size: 130 Bytes
  • Size of remote file: 61 kB
images/its constituent parts Product Type, Capacity, RPM, Year, Dealer, Features, Color, and Service Code.png ADDED

Git LFS Details

  • SHA256: c2510644b3e0de7220e7115a052283603db288876c2cb007365a76dc47625774
  • Pointer size: 130 Bytes
  • Size of remote file: 32.7 kB
images/removal of the MEMS Sensor.png ADDED

Git LFS Details

  • SHA256: ee536934188181b9f8d3aff0e64d86ad21ac238895cb5cf7c5f1133a5ef6c836
  • Pointer size: 130 Bytes
  • Size of remote file: 77.1 kB
images/the disconnection of the Water Level Sensor.png ADDED

Git LFS Details

  • SHA256: 91fdfe069f01d6b9ebd301aa4ea6c97e51ff1564ef853c619eb513f0b237ecfe
  • Pointer size: 131 Bytes
  • Size of remote file: 140 kB
images/the removal of the Ag (SilverCare) Kit.png ADDED

Git LFS Details

  • SHA256: 93f9b79bb2a00b73f5f4344cf3bacde668a3e088b710b08de7784b940d8676a0
  • Pointer size: 131 Bytes
  • Size of remote file: 121 kB
images/the removal of the Top Cover.png ADDED

Git LFS Details

  • SHA256: cdb97f1771d2c0652008bbd256bc9f503ba4150aea0e4d3ad727f4e7d3c9293a
  • Pointer size: 130 Bytes
  • Size of remote file: 98.1 kB
intents.json ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "search_local_image": [
3
+ "show me a picture of",
4
+ "find an image of",
5
+ "can I see a photo of",
6
+ "search for a picture of",
7
+ "display a picture of"
8
+ ],
9
+ "request_image_analysis": [
10
+ "what do you see in this",
11
+ "can you analyze this picture",
12
+ "describe this photo for me",
13
+ "tell me about this image",
14
+ "what is in this picture"
15
+ ],
16
+ "request_audio_analysis": [
17
+ "what is this sound",
18
+ "identify this audio clip",
19
+ "can you listen to this",
20
+ "analyze this sound",
21
+ "what does this audio say"
22
+ ]
23
+ }
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ gradio
2
+ pydantic
3
+ python-dotenv
4
+ requests
5
+ sentence-transformers
6
+ torch
7
+ numpy
8
+ gradio_client
9
+ requests