Initial commit

This commit is contained in:
Aherobo Ovie Victor
2025-07-19 11:55:09 +01:00
commit 49c82456c9
19 changed files with 36092 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
venv/
backend/__pycache__
+326
View File
@@ -0,0 +1,326 @@
from flask import Flask, request, jsonify, render_template
import os
from PIL import Image
os.environ["OMP_NUM_THREADS"] = "1"
os.environ["OPENBLAS_NUM_THREADS"] = "1"
os.environ["MKL_NUM_THREADS"] = "1"
os.environ["VECLIB_MAXIMUM_THREADS"] = "1"
os.environ["NUMEXPR_NUM_THREADS"] = "1"
import torch
try:
torch.set_num_threads(1)
except Exception as e:
print("Could not set torch num threads:", e)
import json
import numpy as np
from image_utils import download_image
from tag_identification import TagIdentification
from tag_match import get_best_match
from data_utils import load_tag_guides, load_expert_data, load_community_data
from image_similarity import load_index, search_similar_images, transform_image
from result_aggregation import aggregate_results
from llm_tag_similarity import LLMTagSimilarity
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
app = Flask(__name__, template_folder='templates')
# Paths
DATA_DIR = os.path.join(os.path.dirname(__file__), '../data')
INDEX_PATH = os.path.join(os.path.dirname(__file__), 'front_tag_embeddings.index')
TAG_GUIDES_PATH = os.path.join(DATA_DIR, 'tag_guides_clean.json')
EXPERT_DATA_PATH = os.path.join(DATA_DIR, 'expert_data.csv')
COMMUNITY_DATA_PATH = os.path.join(DATA_DIR, 'community_data.csv')
# Global variables for lazy loading
_index = None
_tag_identifier = None
_llm_analyzer = None
def get_index():
global _index
if _index is None:
_index = load_index(INDEX_PATH)
return _index
def get_tag_identifier():
global _tag_identifier
if _tag_identifier is None:
_tag_identifier = TagIdentification(endpoint_id="22mdrm9fckjera")
return _tag_identifier
def get_llm_analyzer():
global _llm_analyzer
if _llm_analyzer is None:
_llm_analyzer = LLMTagSimilarity()
return _llm_analyzer
def get_temp_image_path():
return os.path.join(DATA_DIR, 'downloaded_image.jpg')
def get_score_front_tag_simple(indices_expert_front_tag, expert_data):
"""
Simplified version of get_score_front_tag that works with our data structure
"""
# For now, just return the first N images from expert_data
# In a full implementation, you'd map indices to actual image URLs
similar_images = expert_data['front_tag'].dropna().tolist()[:30]
appraisal_values = expert_data['appraisal_value'].dropna().tolist()[:30]
keys = expert_data['key'].dropna().tolist()[:30]
statuses = expert_data['status'].dropna().tolist()[:30]
return {
"results": [
{
"similar images": {
"front_tag": similar_images
},
"appraisal_value": appraisal_values,
"keys": keys,
"predictions": [1.0] * len(similar_images) # Default prediction
}
]
}
def process_images_list_batch(images_list, query_image):
"""
Process historical images from tag_guides and return sorted scores
"""
# Simplified version - in full implementation, you'd compute actual similarity scores
if not images_list:
return []
# For now, just return the first image with a default score
return [(images_list[0].get('year', 'Unknown'), 1.0)]
@app.route('/')
def index():
return render_template('index.html')
@app.route('/health', methods=['GET'])
def health():
return jsonify({'status': 'healthy', 'message': 'Tag scan app is running!'})
@app.route('/get_tag', methods=['POST'])
def get_tag():
try:
data = request.json
image_url = data.get('image_url')
use_llm = data.get('use_llm', False)
if not image_url:
return jsonify({'error': 'No image_url provided'}), 400
# Download image
img_path = get_temp_image_path()
download_image(image_url, img_path)
query_image = Image.open(img_path)
# Tag identification
tag_identifier = get_tag_identifier()
tag = tag_identifier.identify_tag(image_url)
text = tag['response'] if tag and 'response' in tag else None
if not text:
return jsonify({'error': 'No tag identified'}), 404
# Load tag guides
loaded_data = load_tag_guides(TAG_GUIDES_PATH)
# Text matching
best_match = get_best_match(text, tag_guides_path=TAG_GUIDES_PATH, top_n=1)
if not best_match or best_match[0]['similarity_score'] == 0.0:
return jsonify({'message': 'Invalid Tag', 'similar images': []}), 404
extracted_text = best_match[0]['matched_data']['name']
print("Extracted Tag: ", extracted_text)
# Load data
expert_data = load_expert_data(EXPERT_DATA_PATH)
community_data = load_community_data(COMMUNITY_DATA_PATH)
# Image similarity search
index = get_index()
distances_expert_front_tag, indices_expert_front_tag = search_similar_images(
query_image, index, top_k=30)
# Get predictions and scores (simplified version)
result_dict = get_score_front_tag_simple(indices_expert_front_tag, expert_data)
initial_similar_images = result_dict['results'][0]['similar images']['front_tag']
# Efficient text processing (as in main app)
community_titles = set(community_data['brand_name'].dropna())
expert_titles = set(expert_data['brand_name'].dropna())
all_titles = list(community_titles.union(expert_titles))
print(f"Total titles found: {len(all_titles)}")
print(f"Sample titles: {all_titles[:5]}")
# Vectorize texts efficiently
tag_name = best_match[0]['matched_data']['name']
print(f"Looking for matches to: '{tag_name}'")
# Extract the main brand name (e.g., "Jerzees" from "Jerzees T-Shirt Tags")
main_brand = tag_name.split()[0] if tag_name else ""
print(f"Main brand: '{main_brand}'")
# Ensure we have some titles to compare against
if len(all_titles) == 0:
print("No titles found in data, using fallback")
similar_images = expert_data['front_tag'].dropna().tolist()[:30]
appraisal_values = expert_data['appraisal_value'].dropna().tolist()[:30]
statuses = expert_data['status'].dropna().tolist()[:30]
years = ["Unknown"]
response = {
'results': [
{
'tag': extracted_text,
'similar_images': similar_images,
'appraisal_value': appraisal_values,
'years': years,
'status': statuses
}
]
}
print("Final response (fallback):", response)
return jsonify(response)
# Try to find exact or partial matches first
exact_matches = [title for title in all_titles if main_brand.lower() in title.lower()]
print(f"Exact matches found: {len(exact_matches)}")
if exact_matches:
print(f"Sample exact matches: {exact_matches[:3]}")
# If we have exact matches, use them
if exact_matches:
top_titles = [(title, 1.0) for title in exact_matches[:10]]
else:
# Fall back to TF-IDF similarity
try:
vectorizer = TfidfVectorizer()
vectors = vectorizer.fit_transform([tag_name] + all_titles)
similarities = cosine_similarity(vectors[0:1], vectors[1:])[0]
print("Similarities: ", similarities)
print(f"Max similarity: {np.max(similarities)}")
print(f"Min similarity: {np.min(similarities)}")
# Get top similar titles with a lower threshold
top_indices = np.argsort(similarities)[-10:][::-1] # Get top 10 instead of 5
top_titles = [(all_titles[i], similarities[i]) for i in top_indices if similarities[i] >= 0.1] # Lower threshold
print(f"Top titles found: {top_titles}")
# If no titles meet the threshold, use the top 5 anyway
if not top_titles:
print("No titles meet threshold, using top 5 anyway")
top_titles = [(all_titles[i], similarities[i]) for i in top_indices[:5]]
except Exception as e:
print(f"TF-IDF processing failed: {e}")
# Use fallback - just take some random titles
top_titles = [(title, 0.5) for title in all_titles[:10]]
# Process similar images efficiently (as in main app)
try:
similar_data = []
for title, score in top_titles:
community_items = community_data[community_data['brand_name'] == title]
expert_items = expert_data[expert_data['brand_name'] == title]
for items in [community_items, expert_items]:
if not items.empty:
similar_data.extend(items[['front_tag', 'appraisal_value', 'key', 'status']].to_dict('records'))
# Remove duplicates while preserving order
seen_keys = set()
unique_data = []
for item in similar_data:
if item['key'] not in seen_keys:
seen_keys.add(item['key'])
unique_data.append(item)
# Prepare results
similar_images = [item['front_tag'] for item in unique_data]
similar_images = similar_images[:30]
print("Similar Images: ", similar_images)
appraisal_values = [item['appraisal_value'] for item in unique_data]
keys = [item['key'] for item in unique_data]
statuses = [item['status'] for item in unique_data]
except Exception as e:
print(f"Data processing failed: {e}")
# Fallback to using expert data directly
similar_images = expert_data['front_tag'].dropna().tolist()[:30]
appraisal_values = expert_data['appraisal_value'].dropna().tolist()[:30]
statuses = expert_data['status'].dropna().tolist()[:30]
keys = expert_data['key'].dropna().tolist()[:30]
# Process historical images (as in main app)
images_list = []
for tag in loaded_data["tag_guides"]:
if extracted_text == tag["name"]:
print("Got it")
print("Extracted Text : ", extracted_text)
images_list = tag["images"]
break
print("Images List: ", images_list)
try:
sorted_scores = process_images_list_batch(images_list, query_image)
print("Sorted Scores: ", sorted_scores)
years = [year for year, _ in sorted_scores]
print("Extracted years:", years)
except Exception as e:
print("Error during process_images_list_batch or years extraction:", e)
import traceback; traceback.print_exc()
sorted_scores = []
years = []
# Continue with the rest of the logic even if this fails
if extracted_text == "Fruit of the Loom ":
years = ["1970"]
response = {"message": 'No result found'}
print("Final response (no result):", response)
return jsonify(response)
# LLM similarity filter (only if use_llm is True)
if use_llm:
llm_analyzer = get_llm_analyzer()
llm_results = llm_analyzer.filter_similar_tags(image_url, similar_images, similarity_threshold=75.0)
similar_images_final = [item.get('original_url') for item in llm_results if item.get('original_url')]
if not similar_images_final:
similar_images_final = similar_images
else:
similar_images_final = similar_images
# Filter other fields to match LLM-selected images
def filter_by_images(images_final, images_all, *fields_all):
image_to_index = {img: idx for idx, img in enumerate(images_all)}
filtered_fields = []
for field in fields_all:
filtered = [field[image_to_index[img]] for img in images_final if img in image_to_index]
filtered_fields.append(filtered)
return filtered_fields
appraisal_values_final, keys_final, statuses_final = filter_by_images(
similar_images_final, similar_images, appraisal_values, keys, statuses
)
# Prepare response (matching main app format)
response = {
'results': [
{
'tag': extracted_text,
'similar_images': similar_images_final,
'appraisal_value': appraisal_values_final,
'status': statuses_final
}
]
}
print("Final response:", response)
return jsonify(response)
except Exception as e:
print("Fatal error in /get_tag:", e)
import traceback; traceback.print_exc()
return jsonify({"error": str(e)}), 500
if __name__ == '__main__':
app.run(debug=True, port=8000)
+19
View File
@@ -0,0 +1,19 @@
import json
import os
import pandas as pd
def load_tag_guides(path=None):
if path is None:
path = os.path.join(os.path.dirname(__file__), '../data/tag_guides_clean.json')
with open(path, 'r') as f:
return json.load(f)
def load_expert_data(path=None):
if path is None:
path = os.path.join(os.path.dirname(__file__), '../data/expert_data.csv')
return pd.read_csv(path)
def load_community_data(path=None):
if path is None:
path = os.path.join(os.path.dirname(__file__), '../data/community_data.csv')
return pd.read_csv(path)
Binary file not shown.
+48
View File
@@ -0,0 +1,48 @@
import os
import numpy as np
import faiss
import torch
from PIL import Image
from transformers import CLIPModel
from torchvision import transforms
# Device setup
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# Global variable for lazy loading
_model = None
_preprocess = None
def get_model():
global _model
if _model is None:
_model = CLIPModel.from_pretrained('openai/clip-vit-base-patch16').to(device)
_model.eval()
return _model
def get_preprocess():
global _preprocess
if _preprocess is None:
_preprocess = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
return _preprocess
def transform_image(image):
model = get_model()
preprocess = get_preprocess()
image = preprocess(image).unsqueeze(0).to(device)
with torch.no_grad():
features = model.get_image_features(pixel_values=image)
return features.squeeze().cpu().numpy().astype(np.float32)
def load_index(index_file):
return faiss.read_index(index_file)
def search_similar_images(query_image, index, top_k=5):
query_embedding = transform_image(query_image)
query_embedding_normalized = query_embedding / np.linalg.norm(query_embedding)
distances, indices = index.search(np.array([query_embedding_normalized]), top_k)
return distances[0][:top_k], indices[0][:top_k]
+16
View File
@@ -0,0 +1,16 @@
import requests
from PIL import Image
from io import BytesIO
def download_image(image_url: str, save_path: str) -> None:
"""
Download an image from a URL and save it to a local path.
Args:
image_url (str): The URL of the image to download.
save_path (str): The local file path to save the image.
"""
response = requests.get(image_url)
response.raise_for_status()
image = Image.open(BytesIO(response.content))
image.save(save_path)
+124
View File
@@ -0,0 +1,124 @@
import openai
import json
import base64
from PIL import Image
import io
import requests
from typing import List, Dict
import os
class LLMTagSimilarity:
def __init__(self, api_key: str = None, model: str = "gpt-4o"):
"""
Initialize LLM-based tag similarity analyzer
Args:
api_key: OpenAI API key (if None, will use OPENAI_API_KEY env var)
model: Model to use for analysis
"""
if api_key is None:
api_key = os.getenv("OPENAI_API_KEY")
self.client = openai.OpenAI(api_key=api_key)
self.model = model
def encode_image_to_base64(self, image_url: str) -> str:
"""Convert image URL to base64 for API"""
try:
response = requests.get(image_url)
image = Image.open(io.BytesIO(response.content))
buffer = io.BytesIO()
image.save(buffer, format='JPEG')
img_str = base64.b64encode(buffer.getvalue()).decode()
return img_str
except Exception as e:
print(f"Error encoding image {image_url}: {e}")
return None
def analyze_tag_similarity(self, query_image_url: str, candidate_images: List[str], max_candidates: int = 30) -> List[Dict]:
"""
Use LLM to analyze similarity between query tag and candidate tags
Args:
query_image_url: URL of the query tag image
candidate_images: List of candidate tag image URLs
max_candidates: Maximum number of candidates to analyze
Returns:
List of candidates with similarity scores and explanations
"""
candidates = candidate_images[:max_candidates]
query_base64 = self.encode_image_to_base64(query_image_url)
if not query_base64:
return []
candidate_base64s = []
for img_url in candidates:
base64_img = self.encode_image_to_base64(img_url)
if base64_img:
candidate_base64s.append(base64_img)
prompt = """
You are an expert in t-shirt tag authentication. Your job is to strictly assess visual authenticity between a query tag and several candidate tags.
For each candidate, return:
1. similarity_score (0-100): Based on **visual design fidelity** (not just text). How visually similar the tag looks. not just a color combination but color is very important. for example, a tag could have a whilte background a blue text and a red stripe is not similar at all to the same kind of tag with same white background and same text style and everything but has a red text with blue stripe. Also text colors are very important, two tags can look alike but text color are different... they are not similar. color is simple... for example, sky blue, navy blue is all blue... red, wine, is all the same. then focus on the overall style of the tag.. could be the same brand or name but diffrent style isnt similar. background color and text color is very important. so for example, if a tag background is black, similar tags are tags that are visiually similar and have black background as well. if a tag background is white, similar tags are tags that are visiually similar and have white background and so on.
Output a JSON array of objects like:
{
"candidate_index": 0,
"similarity_score": 42,
}
"""
content = [
{"type": "text", "text": prompt},
{
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{query_base64}",
"detail": "high"
}
}
]
for i, base64_img in enumerate(candidate_base64s):
content.append({"type": "text", "text": f"Candidate {i+1}:"})
content.append({
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{base64_img}",
"detail": "high"
}
})
try:
response = self.client.chat.completions.create(
model=self.model,
messages=[{"role": "user", "content": content}],
max_tokens=2000,
temperature=0.1
)
analysis_text = response.choices[0].message.content
try:
start_idx = analysis_text.find('[')
end_idx = analysis_text.rfind(']') + 1
json_str = analysis_text[start_idx:end_idx]
results = json.loads(json_str)
for i, result in enumerate(results):
result['original_url'] = candidates[i]
return results
except json.JSONDecodeError as e:
print(f"Error parsing LLM response: {e}")
print(f"Response: {analysis_text}")
return []
except Exception as e:
print(f"Error calling LLM API: {e}")
return []
def filter_similar_tags(self, query_image_url: str, candidate_images: List[str], similarity_threshold: float = 70.0) -> List[Dict]:
"""
Filter candidates based on LLM similarity analysis
Args:
query_image_url: URL of the query tag image
candidate_images: List of candidate tag image URLs
similarity_threshold: Minimum similarity score to include
Returns:
Filtered list of similar tags with scores
"""
analysis_results = self.analyze_tag_similarity(query_image_url, candidate_images)
filtered_results = [
result for result in analysis_results
if result.get('similarity_score', 0) >= similarity_threshold
]
filtered_results.sort(key=lambda x: x.get('similarity_score', 0), reverse=True)
return filtered_results
+12
View File
@@ -0,0 +1,12 @@
flask
pillow
requests
pandas
scikit-learn
torch==2.2.2
transformers==4.39.3
faiss-cpu
openai
torchvision
runpod
numpy<2
+58
View File
@@ -0,0 +1,58 @@
import pandas as pd
def aggregate_results(matched_names, expert_data, community_data, max_results=30):
"""
Aggregate similar images, appraisal values, years, and status for matched tag names.
Args:
matched_names (list): List of tag names to match.
expert_data (pd.DataFrame): Expert dataset.
community_data (pd.DataFrame): Community dataset.
max_results (int): Maximum number of results to return.
Returns:
dict: Aggregated results with images, appraisal values, years, and status.
"""
similar_data = []
for title in matched_names:
# Handle expert data (no 'year' column)
community_items = community_data[community_data['brand_name'] == title]
expert_items = expert_data[expert_data['brand_name'] == title]
# Process community data (has 'year' column)
if not community_items.empty:
# Use 'year' column if it exists, otherwise use 'year_start'
year_col = 'year' if 'year' in community_items.columns else 'year_start'
community_records = community_items[['front_tag', 'appraisal_value', 'key', 'status', year_col]].to_dict('records')
# Rename year column to 'year' for consistency
for record in community_records:
record['year'] = record.pop(year_col) if year_col in record else None
similar_data.extend(community_records)
# Process expert data (no 'year' column)
if not expert_items.empty:
expert_records = expert_items[['front_tag', 'appraisal_value', 'key', 'status']].to_dict('records')
# Add None for year since expert data doesn't have it
for record in expert_records:
record['year'] = None
similar_data.extend(expert_records)
# Remove duplicates by key, preserving order
seen_keys = set()
unique_data = []
for item in similar_data:
if item['key'] not in seen_keys:
seen_keys.add(item['key'])
unique_data.append(item)
# Prepare results
similar_images = [item['front_tag'] for item in unique_data][:max_results]
appraisal_values = [item['appraisal_value'] for item in unique_data][:max_results]
years = [item.get('year') for item in unique_data][:max_results]
statuses = [item['status'] for item in unique_data][:max_results]
return {
'similar_images': similar_images,
'appraisal_values': appraisal_values,
'years': years,
'statuses': statuses
}
+150
View File
@@ -0,0 +1,150 @@
import runpod
import time
import os
import json
from dotenv import load_dotenv
load_dotenv()
runpod.api_key = os.getenv('RUNPOD_API_KEY')
class TagIdentification:
_instance = None
_cache = {}
_cache_file = os.path.join(os.path.dirname(__file__), 'tag_identification_cache.json')
_is_cache_loaded = False
def __new__(cls, endpoint_id):
if cls._instance is None:
cls._instance = super(TagIdentification, cls).__new__(cls)
cls._instance.endpoint_id = endpoint_id
cls._instance.endpoint = runpod.Endpoint(endpoint_id)
cls._instance._load_cache()
return cls._instance
def __init__(self, endpoint_id):
# Initialization already done in __new__
pass
def _load_cache(self):
"""Load the tag identification cache from file."""
if self._is_cache_loaded:
return
if os.path.exists(self._cache_file):
try:
with open(self._cache_file, 'r') as f:
self._cache = json.load(f)
print(f"Loaded {len(self._cache)} cached tag identifications")
except Exception as e:
print(f"Error loading cache: {e}")
self._cache = {}
self._is_cache_loaded = True
def _save_cache(self):
"""Save the tag identification cache to file."""
try:
with open(self._cache_file, 'w') as f:
json.dump(self._cache, f)
print(f"Saved {len(self._cache)} cached tag identifications")
except Exception as e:
print(f"Error saving cache: {e}")
def preload_tags(self, image_urls):
"""
Preload tag identifications for a list of image URLs.
Args:
image_urls: List of image URLs to preload
"""
print(f"Preloading {len(image_urls)} tag identifications...")
for i, url in enumerate(image_urls):
if url in self._cache:
continue
try:
result = self._identify_tag_api(url)
if result:
self._cache[url] = result
# Save cache periodically
if (i + 1) % 10 == 0:
self._save_cache()
print(f"Preloaded {i+1}/{len(image_urls)} tags")
except Exception as e:
print(f"Error preloading tag for {url}: {e}")
# Final save
self._save_cache()
print(f"Completed preloading {len(image_urls)} tags")
def identify_tag(self, image_url):
"""
Identify tag from image URL, using cache if available.
Args:
image_url: URL of the image to identify
Returns:
Tag identification result
"""
# Check cache first
if image_url in self._cache:
print(f"Cache hit for {image_url}")
return self._cache[image_url]
# Call API if not in cache
result = self._identify_tag_api(image_url)
# Cache the result
if result:
self._cache[image_url] = result
self._save_cache()
return result
def _identify_tag_api(self, image_url):
"""Make the actual API call to identify the tag."""
prompt = """
You will tell me which tag it belongs to:
1. Alstyle Apparel & Activewear T-Shirt Tags 1995-2006
2. Anvil T-Shirt Tags 1989-2007
3. Ched and Anvil T-Shirt Tags 1976-1988
4. Delta T-Shirt Tags 1988-2014
5. Fruit of the Loom 1970-1998
6. Giant T-Shirt Tags 1991-1996
7. Gildan T-Shirt Tags 1995-2002
8. Hanes T-Shirt Tags 1989-1997
9. Jerzees T-Shirt Tags 1985-1998
10. Oneita T-Shirt Tags 1984-1999
11. Screen Stars T-Shirt Tags 1980-1994
12. Signal T-Shirt Tags 1977-1994
13. Sportswear T-Shirt Tags 1968 1990
14. Stedman & Hi Cru T-Shirt Tags 1971-1997
15. Tennessee River T-Shirt Tags 1984-2010
16. Wild Oats T-Shirt Tags 1984-1997
17. Winterland T-Shirt Tags 1982-2008
18. Others
Just Give me the Tag only(Don't add anything)
"""
payload = {
"input": {
"input_image_url": image_url,
"vlm_prompt": "What is the tag of the t-shirt? Just give me the name of the tag nothing else",
"max_new_tokens": 20
}
}
# Send the request to the endpoint and get the response
run_request = self.endpoint.run(payload)
# Check the status of the endpoint run request in a loop until completed or an error occurs
while True:
status = run_request.status()
if status == 'COMPLETED':
return run_request.output()
elif status == 'FAILED':
print("Request failed.")
return None
time.sleep(1)
return None
File diff suppressed because one or more lines are too long
+35
View File
@@ -0,0 +1,35 @@
import json
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import os
def get_best_match(tag_response, tag_guides_path=None, top_n=1):
"""
Find the best match for a tag_response using cosine similarity on local tag_guides_clean.json.
Args:
tag_response (str): The input tag to be matched.
tag_guides_path (str): Path to the local tag_guides_clean.json file.
top_n (int): Number of top matches to return (default is 1).
Returns:
list: A list of top_n best matches with similarity scores and matched data.
"""
if tag_guides_path is None:
tag_guides_path = os.path.join(os.path.dirname(__file__), '../data/tag_guides_clean.json')
with open(tag_guides_path, 'r') as f:
data = json.load(f)
names = [item['name'] for item in data['tag_guides']]
vectorizer = TfidfVectorizer().fit(names + [tag_response])
name_vectors = vectorizer.transform(names)
response_vector = vectorizer.transform([tag_response])
cosine_similarities = cosine_similarity(response_vector, name_vectors).flatten()
top_indices = cosine_similarities.argsort()[-top_n:][::-1]
best_matches = []
for index in top_indices:
best_matches.append({
'matched_name': data['tag_guides'][index]['name'],
'similarity_score': round(cosine_similarities[index], 4),
'matched_data': data['tag_guides'][index]
})
return best_matches
+138
View File
@@ -0,0 +1,138 @@
<!DOCTYPE html>
<html>
<head>
<title>Tag Scan Demo</title>
<style>
body { font-family: 'Segoe UI', Arial, sans-serif; margin: 2em; background: #f8fafc; color: #222; }
h2 { color: #2a72d4; }
form { background: #fff; padding: 1.5em 2em; border-radius: 10px; box-shadow: 0 2px 12px #0002; max-width: 600px; margin-bottom: 2em; }
input[type="text"] { width: 100%; padding: 0.7em; border: 1px solid #bbb; border-radius: 6px; font-size: 1.1em; transition: border 0.2s; }
input[type="text"]:focus { border: 1.5px solid #2a72d4; outline: none; }
button { background: linear-gradient(90deg, #2a72d4 60%, #1a4e96 100%); color: #fff; border: none; padding: 0.8em 2em; border-radius: 6px; font-size: 1.1em; cursor: pointer; margin-top: 1em; box-shadow: 0 2px 8px #0001; transition: background 0.2s; }
button:hover { background: linear-gradient(90deg, #1a4e96 60%, #2a72d4 100%); }
label { display: block; margin: 1em 0 0.5em; }
#result { background: #fff; padding: 2em 2.5em; border-radius: 12px; box-shadow: 0 2px 12px #0002; max-width: 900px; margin-top: 2em; }
.images-grid { display: flex; flex-wrap: wrap; gap: 1em; margin: 1.5em 0; }
.images-grid a { display: block; border-radius: 8px; overflow: hidden; box-shadow: 0 1px 6px #0002; transition: box-shadow 0.2s, transform 0.2s; background: #f4f4f4; }
.images-grid a:hover { box-shadow: 0 6px 24px #0003; transform: scale(1.04); }
.images-grid img { display: block; width: 120px; height: 120px; object-fit: cover; background: #eee; transition: filter 0.2s; }
.meta { font-size: 1.05em; color: #444; margin-bottom: 0.7em; }
.json-toggle { color: #2a72d4; cursor: pointer; text-decoration: underline; font-size: 1em; margin-bottom: 1em; display: inline-block; }
pre { background: #f4f4f4; padding: 1em; border-radius: 7px; overflow-x: auto; }
.query-preview { display: flex; align-items: center; gap: 1.5em; margin-bottom: 1.5em; }
.query-preview img { width: 140px; height: 140px; object-fit: cover; border-radius: 10px; box-shadow: 0 2px 8px #0002; border: 2px solid #e0e7ef; background: #f4f4f4; }
.query-preview .url { font-size: 0.98em; color: #2a72d4; word-break: break-all; }
@media (max-width: 700px) {
#result, form { padding: 1em; }
.query-preview img { width: 90px; height: 90px; }
.images-grid img { width: 80px; height: 80px; }
}
</style>
</head>
<body>
<h2>Tag Scan Demo</h2>
<form id="scanForm">
<label>Image URL:<br>
<input type="text" id="imageUrl" size="60" required placeholder="Paste a tag image URL here">
</label>
<label>
<input type="checkbox" id="useLlm"> Use LLM Similarity
</label>
<button type="submit">Scan Tag</button>
</form>
<h3>Result:</h3>
<div id="result">
<div class="query-preview" id="queryPreview" style="display:none;">
<img id="queryImg" src="" alt="Query tag preview">
<div class="url" id="queryUrl"></div>
</div>
<div id="meta"></div>
<div class="images-grid" id="imagesGrid"></div>
<span class="json-toggle" id="toggleJson" style="display:none;">Show raw JSON</span>
<pre id="jsonResult" style="display:none;"></pre>
</div>
<script>
function renderResults(data, imageUrl) {
const res = data.results && data.results[0] ? data.results[0] : null;
const metaDiv = document.getElementById('meta');
const imagesGrid = document.getElementById('imagesGrid');
const jsonResult = document.getElementById('jsonResult');
const toggleJson = document.getElementById('toggleJson');
const queryPreview = document.getElementById('queryPreview');
const queryImg = document.getElementById('queryImg');
const queryUrl = document.getElementById('queryUrl');
metaDiv.innerHTML = '';
imagesGrid.innerHTML = '';
jsonResult.style.display = 'none';
toggleJson.style.display = 'none';
// Show query image preview
if (imageUrl) {
queryPreview.style.display = 'flex';
queryImg.src = imageUrl;
queryUrl.innerHTML = `<b>Query Image:</b><br><a href="${imageUrl}" target="_blank">${imageUrl}</a>`;
} else {
queryPreview.style.display = 'none';
}
if (!res) {
metaDiv.textContent = 'No results.';
return;
}
metaDiv.innerHTML = `<b>Tag:</b> ${res.tag || ''}`;
if (res.years && res.years.length > 0) {
metaDiv.innerHTML += ` &nbsp; <b>Years:</b> ${res.years.filter(Boolean).join(', ')}`;
}
if (res.appraisal_value && res.appraisal_value.length > 0) {
metaDiv.innerHTML += `<br><b>Appraisal Values:</b> ${res.appraisal_value.filter(Boolean).join(', ')}`;
}
if (res.status && res.status.length > 0) {
metaDiv.innerHTML += `<br><b>Status:</b> ${res.status.filter(Boolean).join(', ')}`;
}
// Show images as thumbnails
if (res.similar_images && res.similar_images.length > 0) {
res.similar_images.forEach(url => {
if (url) {
const a = document.createElement('a');
a.href = url;
a.target = '_blank';
const img = document.createElement('img');
img.src = url;
img.alt = 'Tag image';
a.appendChild(img);
imagesGrid.appendChild(a);
}
});
} else {
imagesGrid.innerHTML = '<i>No similar images found.</i>';
}
// Show JSON toggle
toggleJson.style.display = 'inline-block';
jsonResult.textContent = JSON.stringify(data, null, 2);
toggleJson.onclick = function() {
jsonResult.style.display = jsonResult.style.display === 'none' ? 'block' : 'none';
toggleJson.textContent = jsonResult.style.display === 'none' ? 'Show raw JSON' : 'Hide raw JSON';
};
}
document.getElementById('scanForm').onsubmit = async function(e) {
e.preventDefault();
const imageUrl = document.getElementById('imageUrl').value;
const useLlm = document.getElementById('useLlm').checked;
document.getElementById('meta').textContent = '';
document.getElementById('imagesGrid').innerHTML = '';
document.getElementById('jsonResult').style.display = 'none';
document.getElementById('toggleJson').style.display = 'none';
document.getElementById('meta').textContent = 'Loading...';
try {
const res = await fetch('/get_tag', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ image_url: imageUrl, use_llm: useLlm })
});
const data = await res.json();
renderResults(data, imageUrl);
} catch (err) {
document.getElementById('meta').textContent = 'Error: ' + err;
}
};
</script>
</body>
</html>
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

+2277
View File
File diff suppressed because it is too large Load Diff
+854
View File
@@ -0,0 +1,854 @@
{
"success": true,
"tag_guides": [
{
"id": 1,
"name": "Alstyle Apparel & Activewear T-Shirt Tags",
"year_start": "1995",
"year_end": "2006",
"category": null,
"brand_id": null,
"status": 1,
"created_at": "2024-12-09T16:55:26.000Z",
"updated_at": "2024-12-09T16:55:26.000Z",
"images_and_years": "https://s3.amazonaws.com/com.images.legiteem8/alstyle/alstyle-1.jpg==1995;;https://s3.amazonaws.com/com.images.legiteem8/alstyle/alstyle-2.jpg==1997;;https://s3.amazonaws.com/com.images.legiteem8/alstyle/alstyle-3.jpg==1998;;https://s3.amazonaws.com/com.images.legiteem8/alstyle/alstyle-4.jpg==1999;;https://s3.amazonaws.com/com.images.legiteem8/alstyle/alstyle-5.jpg==2000;;https://s3.amazonaws.com/com.images.legiteem8/alstyle/alstyle-6.jpg==2002;;https://s3.amazonaws.com/com.images.legiteem8/alstyle/alstyle-7.jpg==2006;;https://s3.amazonaws.com/com.images.legiteem8/alstyle/alstyle-8.jpg==-",
"images": [
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/alstyle/alstyle-1.jpg",
"year": "1995"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/alstyle/alstyle-2.jpg",
"year": "1997"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/alstyle/alstyle-3.jpg",
"year": "1998"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/alstyle/alstyle-4.jpg",
"year": "1999"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/alstyle/alstyle-5.jpg",
"year": "2000"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/alstyle/alstyle-6.jpg",
"year": "2002"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/alstyle/alstyle-7.jpg",
"year": "2006"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/alstyle/alstyle-8.jpg",
"year": "-"
}
]
},
{
"id": 2,
"name": "Anvil T-Shirt Tags",
"year_start": "1989",
"year_end": "2007",
"category": null,
"brand_id": 69,
"status": 1,
"created_at": "2024-12-09T13:13:02.000Z",
"updated_at": "2024-12-09T13:13:02.000Z",
"images_and_years": "https://s3.amazonaws.com/com.images.legiteem8/anvil/anvil-1.jpg==1989-1993;;https://s3.amazonaws.com/com.images.legiteem8/anvil/anvil-2.jpg==1991-1997;;https://s3.amazonaws.com/com.images.legiteem8/anvil/anvil-3.jpg==1992-1999;;https://s3.amazonaws.com/com.images.legiteem8/anvil/anvil-4.jpg==1993-1994;;https://s3.amazonaws.com/com.images.legiteem8/anvil/anvil-5.jpg==1994-1996;;https://s3.amazonaws.com/com.images.legiteem8/anvil/anvil-6.jpg==1994-1997;;https://s3.amazonaws.com/com.images.legiteem8/anvil/anvil-7.jpg==1995-1999;;https://s3.amazonaws.com/com.images.legiteem8/anvil/anvil-8.jpg==1996-2004;;https://s3.amazonaws.com/com.images.legiteem8/anvil/anvil-9.jpg==1994;;https://s3.amazonaws.com/com.images.legiteem8/anvil/anvil-10.jpg==1996;;https://s3.amazonaws.com/com.images.legiteem8/anvil/anvil-11.jpg==1998",
"images": [
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/anvil/anvil-1.jpg",
"year": "1989-1993"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/anvil/anvil-2.jpg",
"year": "1991-1997"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/anvil/anvil-3.jpg",
"year": "1992-1999"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/anvil/anvil-4.jpg",
"year": "1993-1994"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/anvil/anvil-5.jpg",
"year": "1994-1996"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/anvil/anvil-6.jpg",
"year": "1994-1997"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/anvil/anvil-7.jpg",
"year": "1995-1999"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/anvil/anvil-8.jpg",
"year": "1996-1998"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/anvil/anvil-9.jpg",
"year": "1994"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/anvil/anvil-10.jpg",
"year": "1996"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/anvil/anvil-11.jpg",
"year": "1998"
}
]
},
{
"id": 3,
"name": "Ched and Anvil T-Shirt Tags",
"year_start": "1976",
"year_end": "1988",
"category": null,
"brand_id": 212,
"status": 1,
"created_at": "2024-12-10T13:21:49.000Z",
"updated_at": "2024-12-10T13:21:49.000Z",
"images_and_years": "https://s3.amazonaws.com/com.images.legiteem8/ched/ched-1.jpg==1976-1977;;https://s3.amazonaws.com/com.images.legiteem8/ched/ched-2.jpg==1976-1979;;https://s3.amazonaws.com/com.images.legiteem8/ched/ched-3.jpg==1979-1988;;https://s3.amazonaws.com/com.images.legiteem8/ched/ched-4.jpg==1984-1988;;https://s3.amazonaws.com/com.images.legiteem8/ched/ched-5.jpg==1976-1985;;https://s3.amazonaws.com/com.images.legiteem8/ched/ched-6.jpg==1979-1983;;https://s3.amazonaws.com/com.images.legiteem8/ched/ched-7.jpg==1985-1989;;https://s3.amazonaws.com/com.images.legiteem8/ched/ched-8.jpg==1986-1990;;https://s3.amazonaws.com/com.images.legiteem8/ched/ched-9.jpg==1988-1990",
"images": [
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/ched/ched-1.jpg",
"year": "1976-1977"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/ched/ched-2.jpg",
"year": "1976-1979"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/ched/ched-3.jpg",
"year": "1979-1988"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/ched/ched-4.jpg",
"year": "1976-1985"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/ched/ched-5.jpg",
"year": "1979-1983"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/ched/ched-6.jpg",
"year": "1984-1988"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/ched/ched-7.jpg",
"year": "1985-1989"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/ched/ched-8.jpg",
"year": "1986-1990"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/ched/ched-9.jpg",
"year": "1988-1990"
}
]
},
{
"id": 4,
"name": "Delta T-Shirt Tags",
"year_start": "1988",
"year_end": "2014",
"category": null,
"brand_id": null,
"status": 1,
"created_at": "2024-12-10T13:22:19.000Z",
"updated_at": "2024-12-10T13:22:19.000Z",
"images_and_years": "https://s3.amazonaws.com/com.images.legiteem8/delta/delta-1.jpg==1988;;https://s3.amazonaws.com/com.images.legiteem8/delta/delta-2.jpg==1988;;https://s3.amazonaws.com/com.images.legiteem8/delta/delta-3.jpg==1991;;https://s3.amazonaws.com/com.images.legiteem8/delta/delta-4.jpg==1993;;https://s3.amazonaws.com/com.images.legiteem8/delta/delta-5.jpg==1996;;https://s3.amazonaws.com/com.images.legiteem8/delta/delta-6.jpg==1996;;https://s3.amazonaws.com/com.images.legiteem8/delta/delta-7.jpg==2001;;https://s3.amazonaws.com/com.images.legiteem8/delta/delta-8.jpg==2002;;https://s3.amazonaws.com/com.images.legiteem8/delta/delta-9.jpg==2002;;https://s3.amazonaws.com/com.images.legiteem8/delta/delta-10.jpg==2004;;https://s3.amazonaws.com/com.images.legiteem8/delta/delta-11.jpg==2004;;https://s3.amazonaws.com/com.images.legiteem8/delta/delta-12.jpg==2009;;https://s3.amazonaws.com/com.images.legiteem8/delta/delta-13.jpg==2009;;https://s3.amazonaws.com/com.images.legiteem8/delta/delta-14.jpg==2013;;https://s3.amazonaws.com/com.images.legiteem8/delta/delta-15.jpg==2013",
"images": [
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/delta/delta-1.jpg",
"year": "1988"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/delta/delta-2.jpg",
"year": "1988"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/delta/delta-3.jpg",
"year": "1991"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/delta/delta-4.jpg",
"year": "1993"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/delta/delta-5.jpg",
"year": "1996"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/delta/delta-6.jpg",
"year": "1996"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/delta/delta-7.jpg",
"year": "2001"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/delta/delta-8.jpg",
"year": "2002"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/delta/delta-9.jpg",
"year": "2004"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/delta/delta-10.jpg",
"year": "2002"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/delta/delta-11.jpg",
"year": "2002"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/delta/delta-12.jpg",
"year": "2004"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/delta/delta-13.jpg",
"year": "2004"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/delta/delta-14.jpg",
"year": "-"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/delta/delta-15.jpg",
"year": "2009"
}
]
},
{
"id": 5,
"name": "Fruit of the Loom ",
"year_start": "1970",
"year_end": "1998",
"category": null,
"brand_id": 396,
"status": 1,
"created_at": "2024-12-10T13:22:52.000Z",
"updated_at": "2024-12-10T13:22:52.000Z",
"images_and_years": null,
"images": []
},
{
"id": 6,
"name": "Giant T-Shirt Tags",
"year_start": "1991",
"year_end": "1996",
"category": null,
"brand_id": 425,
"status": 1,
"created_at": "2024-12-10T13:23:37.000Z",
"updated_at": "2024-12-10T13:23:37.000Z",
"images_and_years": "https://s3.amazonaws.com/com.images.legiteem8/giant/giant-1.jpg==1991;;https://s3.amazonaws.com/com.images.legiteem8/giant/giant-2.jpg==1991;;https://s3.amazonaws.com/com.images.legiteem8/giant/giant-3.jpg==1993;;https://s3.amazonaws.com/com.images.legiteem8/giant/giant-4.jpg==1994;;https://s3.amazonaws.com/com.images.legiteem8/giant/giant-5.jpg==1994;;https://s3.amazonaws.com/com.images.legiteem8/giant/giant-6.jpg==1996;;https://s3.amazonaws.com/com.images.legiteem8/giant/giant-7.jpg==1996",
"images": [
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/giant/giant-1.jpg",
"year": "1991"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/giant/giant-2.jpg",
"year": "1991"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/giant/giant-3.jpg",
"year": "1993"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/giant/giant-4.jpg",
"year": "1994"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/giant/giant-5.jpg",
"year": "1996"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/giant/giant-6.jpg",
"year": "1994"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/giant/giant-7.jpg",
"year": "1996"
}
]
},
{
"id": 7,
"name": "Gildan T-Shirt Tags",
"year_start": "1995",
"year_end": "2002",
"category": null,
"brand_id": 425,
"status": 1,
"created_at": "2024-12-10T13:24:04.000Z",
"updated_at": "2024-12-10T13:24:04.000Z",
"images_and_years": "https://s3.amazonaws.com/com.images.legiteem8/gildan/gildan-1.jpg==1995;;https://s3.amazonaws.com/com.images.legiteem8/gildan/gildan-2.jpg==1996;;https://s3.amazonaws.com/com.images.legiteem8/gildan/gildan-3.jpg==1997;;https://s3.amazonaws.com/com.images.legiteem8/gildan/gildan-4.jpg==1997;;https://s3.amazonaws.com/com.images.legiteem8/gildan/gildan-5.jpg==1998;;https://s3.amazonaws.com/com.images.legiteem8/gildan/gildan-6.jpg==1999;;https://s3.amazonaws.com/com.images.legiteem8/gildan/gildan-7.jpg==2000;;https://s3.amazonaws.com/com.images.legiteem8/gildan/gildan-8.jpg==2001;;https://s3.amazonaws.com/com.images.legiteem8/gildan/gildan-9.jpg==2002",
"images": [
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/gildan/gildan-1.jpg",
"year": "1995"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/gildan/gildan-2.jpg",
"year": "1997"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/gildan/gildan-3.jpg",
"year": "1996"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/gildan/gildan-4.jpg",
"year": "1997"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/gildan/gildan-5.jpg",
"year": "1998"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/gildan/gildan-6.jpg",
"year": "1999"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/gildan/gildan-7.jpg",
"year": "2000"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/gildan/gildan-8.jpg",
"year": "2001"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/gildan/gildan-9.jpg",
"year": "2002"
}
]
},
{
"id": 8,
"name": "Hanes T-Shirt Tags ",
"year_start": "1989",
"year_end": "1997",
"category": null,
"brand_id": 466,
"status": 1,
"created_at": "2024-12-10T13:24:34.000Z",
"updated_at": "2024-12-10T13:24:34.000Z",
"images_and_years": "https://s3.amazonaws.com/com.images.legiteem8/hanes/hanes-1.jpg==1989;;https://s3.amazonaws.com/com.images.legiteem8/hanes/hanes-2.jpg==1990;;https://s3.amazonaws.com/com.images.legiteem8/hanes/hanes-3.jpg==1991;;https://s3.amazonaws.com/com.images.legiteem8/hanes/hanes-4.jpg==1992;;https://s3.amazonaws.com/com.images.legiteem8/hanes/hanes-5.jpg==1993;;https://s3.amazonaws.com/com.images.legiteem8/hanes/hanes-6.jpg==1994;;https://s3.amazonaws.com/com.images.legiteem8/hanes/hanes-7.jpg==1995;;https://s3.amazonaws.com/com.images.legiteem8/hanes/hanes-8.jpg==1996;;https://s3.amazonaws.com/com.images.legiteem8/hanes/hanes-9.jpg==1997",
"images": [
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/hanes/hanes-1.jpg",
"year": "1989"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/hanes/hanes-2.jpg",
"year": "1990"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/hanes/hanes-3.jpg",
"year": "1991"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/hanes/hanes-4.jpg",
"year": "1992"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/hanes/hanes-5.jpg",
"year": "1993"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/hanes/hanes-6.jpg",
"year": "1994"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/hanes/hanes-7.jpg",
"year": "1995"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/hanes/hanes-8.jpg",
"year": "1997"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/hanes/hanes-9.jpg",
"year": "1996"
}
]
},
{
"id": 9,
"name": "Jerzees T-Shirt Tags",
"year_start": "1985",
"year_end": "1998",
"category": null,
"brand_id": null,
"status": 1,
"created_at": "2024-12-10T13:25:12.000Z",
"updated_at": "2024-12-10T13:25:12.000Z",
"images_and_years": "https://s3.amazonaws.com/com.images.legiteem8/jerzees/jerzees-1.jpg==1985;;https://s3.amazonaws.com/com.images.legiteem8/jerzees/jerzees-2.jpg==1985;;https://s3.amazonaws.com/com.images.legiteem8/jerzees/jerzees-3.jpg==1987;;https://s3.amazonaws.com/com.images.legiteem8/jerzees/jerzees-4.jpg==1991;;https://s3.amazonaws.com/com.images.legiteem8/jerzees/jerzees-5.jpg==1992;;https://s3.amazonaws.com/com.images.legiteem8/jerzees/jerzees-6.jpg==1995;;https://s3.amazonaws.com/com.images.legiteem8/jerzees/jerzees-7.jpg==1996;;https://s3.amazonaws.com/com.images.legiteem8/jerzees/jerzees-8.jpg==1997;;https://s3.amazonaws.com/com.images.legiteem8/jerzees/jerzees-9.jpg==1998",
"images": [
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/jerzees/jerzees-1.jpg",
"year": "1985"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/jerzees/jerzees-2.jpg",
"year": "1985"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/jerzees/jerzees-3.jpg",
"year": "1987"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/jerzees/jerzees-4.jpg",
"year": "1991"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/jerzees/jerzees-5.jpg",
"year": "1992"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/jerzees/jerzees-6.jpg",
"year": "1995"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/jerzees/jerzees-7.jpg",
"year": "1996"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/jerzees/jerzees-8.jpg",
"year": "1997"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/jerzees/jerzees-9.jpg",
"year": "1998"
}
]
},
{
"id": 10,
"name": "Oneita T-Shirt Tags",
"year_start": "1984",
"year_end": "1989",
"category": null,
"brand_id": null,
"status": 1,
"created_at": "2024-12-10T13:25:37.000Z",
"updated_at": "2024-12-10T13:25:37.000Z",
"images_and_years": "https://s3.amazonaws.com/com.images.legiteem8/oneita/oneita-1.jpg==1984;;https://s3.amazonaws.com/com.images.legiteem8/oneita/oneita-2.jpg==1985;;https://s3.amazonaws.com/com.images.legiteem8/oneita/oneita-3.jpg==1987;;https://s3.amazonaws.com/com.images.legiteem8/oneita/oneita-4.jpg==1988;;https://s3.amazonaws.com/com.images.legiteem8/oneita/oneita-5.jpg==1993;;https://s3.amazonaws.com/com.images.legiteem8/oneita/oneita-6.jpg==1996;;https://s3.amazonaws.com/com.images.legiteem8/oneita/oneita-7.jpg==1996;;https://s3.amazonaws.com/com.images.legiteem8/oneita/oneita-8.jpg==1999;;https://s3.amazonaws.com/com.images.legiteem8/oneita/oneita-9.jpg==1999",
"images": [
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/oneita/oneita-1.jpg",
"year": "1984"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/oneita/oneita-2.jpg",
"year": "1985"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/oneita/oneita-3.jpg",
"year": "1987"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/oneita/oneita-4.jpg",
"year": "1988"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/oneita/oneita-5.jpg",
"year": "1993"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/oneita/oneita-6.jpg",
"year": "1996"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/oneita/oneita-7.jpg",
"year": "1996"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/oneita/oneita-8.jpg",
"year": "1999"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/oneita/oneita-9.jpg",
"year": "1999"
}
]
},
{
"id": 11,
"name": "Screen Stars T-Shirt Tags",
"year_start": "1980",
"year_end": "1994",
"category": null,
"brand_id": null,
"status": 1,
"created_at": "2024-12-10T13:26:14.000Z",
"updated_at": "2024-12-10T13:26:14.000Z",
"images_and_years": "https://s3.amazonaws.com/com.images.legiteem8/stars/stars-1.jpg==1980;;https://s3.amazonaws.com/com.images.legiteem8/stars/stars-2.jpg==1980;;https://s3.amazonaws.com/com.images.legiteem8/stars/stars-3.jpg==1981;;https://s3.amazonaws.com/com.images.legiteem8/stars/stars-4.jpg==1982;;https://s3.amazonaws.com/com.images.legiteem8/stars/stars-5.jpg==1987;;https://s3.amazonaws.com/com.images.legiteem8/stars/stars-6.jpg==1987;;https://s3.amazonaws.com/com.images.legiteem8/stars/stars-7.jpg==1990;;https://s3.amazonaws.com/com.images.legiteem8/stars/stars-8.jpg==1994;;https://s3.amazonaws.com/com.images.legiteem8/stars/stars-9.jpg==1994",
"images": [
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/stars/stars-1.jpg",
"year": "1980"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/stars/stars-2.jpg",
"year": "1981"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/stars/stars-3.jpg",
"year": "1990"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/stars/stars-4.jpg",
"year": "1994"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/stars/stars-5.jpg",
"year": "1982"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/stars/stars-6.jpg",
"year": "1987"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/stars/stars-7.jpg",
"year": "1987"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/stars/stars-8.jpg",
"year": "1994"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/stars/stars-9.jpg",
"year": "1980"
}
]
},
{
"id": 12,
"name": "Signal T-Shirt Tags",
"year_start": "1977",
"year_end": "1994",
"category": null,
"brand_id": null,
"status": 1,
"created_at": "2024-12-10T13:27:40.000Z",
"updated_at": "2024-12-10T13:27:40.000Z",
"images_and_years": "https://s3.amazonaws.com/com.images.legiteem8/signal/signal-1.jpg==1977;;https://s3.amazonaws.com/com.images.legiteem8/signal/signal-2.jpg==1979;;https://s3.amazonaws.com/com.images.legiteem8/signal/signal-3.jpg==1980;;https://s3.amazonaws.com/com.images.legiteem8/signal/signal-4.jpg==1984;;https://s3.amazonaws.com/com.images.legiteem8/signal/signal-5.jpg==1991;;https://s3.amazonaws.com/com.images.legiteem8/signal/signal-6.jpg==1992;;https://s3.amazonaws.com/com.images.legiteem8/signal/signal-7.jpg==1992;;https://s3.amazonaws.com/com.images.legiteem8/signal/signal-8.jpg==1994;;https://s3.amazonaws.com/com.images.legiteem8/signal/signal-9.jpg==1994",
"images": [
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/signal/signal-1.jpg",
"year": "1977"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/signal/signal-2.jpg",
"year": "1980"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/signal/signal-3.jpg",
"year": "1992"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/signal/signal-4.jpg",
"year": "1994"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/signal/signal-5.jpg",
"year": "1984"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/signal/signal-6.jpg",
"year": "1991"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/signal/signal-7.jpg",
"year": "1992"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/signal/signal-8.jpg",
"year": "1979"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/signal/signal-9.jpg",
"year": "1994"
}
]
},
{
"id": 13,
"name": "Sportswear T-Shirt Tags",
"year_start": "1968",
"year_end": "1990",
"category": null,
"brand_id": null,
"status": 1,
"created_at": "2024-12-10T13:28:06.000Z",
"updated_at": "2024-12-10T13:28:06.000Z",
"images_and_years": "https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-1.jpg==1968;;https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-2.jpg==1974;;https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-3.jpg==1975;;https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-4.jpg==1978;;https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-5.jpg==1978;;https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-6.jpg==1980;;https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-7.jpg==1980;;https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-8.jpg==1981;;https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-9.jpg==1981;;https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-10.jpg==1982;;https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-11.jpg==1983;;https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-12.jpg==1984;;https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-13.jpg==1984;;https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-14.jpg==1985;;https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-15.jpg==1985;;https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-16.jpg==1990",
"images": [
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-1.jpg",
"year": "1981"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-2.jpg",
"year": "1982"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-3.jpg",
"year": "1983"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-4.jpg",
"year": "1984"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-5.jpg",
"year": "1984"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-6.jpg",
"year": "1985"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-7.jpg",
"year": "1985"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-8.jpg",
"year": "1990"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-9.jpg",
"year": "1981"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-10.jpg",
"year": "1968"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-11.jpg",
"year": "1974"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-12.jpg",
"year": "1975"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-13.jpg",
"year": "1978"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-14.jpg",
"year": "1978"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-15.jpg",
"year": "1980"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/sportswear/sportswear-16.jpg",
"year": "1980"
}
]
},
{
"id": 14,
"name": "Stedman & Hi Cru T-Shirt Tags ",
"year_start": "1971",
"year_end": "1997",
"category": null,
"brand_id": null,
"status": 1,
"created_at": "2024-12-10T13:28:36.000Z",
"updated_at": "2024-12-10T13:28:36.000Z",
"images_and_years": "https://s3.amazonaws.com/com.images.legiteem8/stedman/stedman-1.jpg==1971;;https://s3.amazonaws.com/com.images.legiteem8/stedman/stedman-2.jpg==1974;;https://s3.amazonaws.com/com.images.legiteem8/stedman/stedman-3.jpg==1977;;https://s3.amazonaws.com/com.images.legiteem8/stedman/stedman-4.jpg==1978;;https://s3.amazonaws.com/com.images.legiteem8/stedman/stedman-5.jpg==1981;;https://s3.amazonaws.com/com.images.legiteem8/stedman/stedman-6.jpg==1985;;https://s3.amazonaws.com/com.images.legiteem8/stedman/stedman-7.jpg==1988;;https://s3.amazonaws.com/com.images.legiteem8/stedman/stedman-8.jpg==1989;;https://s3.amazonaws.com/com.images.legiteem8/stedman/stedman-9.jpg==1990",
"images": [
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/stedman/stedman-1.jpg",
"year": "1971"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/stedman/stedman-2.jpg",
"year": "1974"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/stedman/stedman-3.jpg",
"year": "1977"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/stedman/stedman-4.jpg",
"year": "1978"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/stedman/stedman-5.jpg",
"year": "1981"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/stedman/stedman-6.jpg",
"year": "1985"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/stedman/stedman-7.jpg",
"year": "1988"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/stedman/stedman-8.jpg",
"year": "1989"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/stedman/stedman-9.jpg",
"year": "1997"
}
]
},
{
"id": 15,
"name": "Tennessee River T-Shirt Tags",
"year_start": "1984",
"year_end": "2010",
"category": null,
"brand_id": null,
"status": 1,
"created_at": "2024-12-10T13:29:19.000Z",
"updated_at": "2024-12-10T13:29:19.000Z",
"images_and_years": "https://s3.amazonaws.com/com.images.legiteem8/tennessee/tennessee-1.jpg==1984-1992;;https://s3.amazonaws.com/com.images.legiteem8/tennessee/tennessee-2.jpg==1988-1993;;https://s3.amazonaws.com/com.images.legiteem8/tennessee/tennessee-3.jpg==1988-1994;;https://s3.amazonaws.com/com.images.legiteem8/tennessee/tennessee-4.jpg==1993-1998;;https://s3.amazonaws.com/com.images.legiteem8/tennessee/tennessee-5.jpg==1993-2000;;https://s3.amazonaws.com/com.images.legiteem8/tennessee/tennessee-6.jpg==1997-2001;;https://s3.amazonaws.com/com.images.legiteem8/tennessee/tennessee-7.jpg==1999-2001;;https://s3.amazonaws.com/com.images.legiteem8/tennessee/tennessee-8.jpg==2000-2010",
"images": [
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/tennessee/tennessee-1.jpg",
"year": "1984-1992"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/tennessee/tennessee-2.jpg",
"year": "1988-1993"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/tennessee/tennessee-3.jpg",
"year": "1988-1994"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/tennessee/tennessee-4.jpg",
"year": "1993-2000"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/tennessee/tennessee-5.jpg",
"year": "1993-1998"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/tennessee/tennessee-6.jpg",
"year": "1997-2001"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/tennessee/tennessee-7.jpg",
"year": "1999-2001"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/tennessee/tennessee-8.jpg",
"year": "2000-2010"
}
]
},
{
"id": 16,
"name": "Wild Oats T-Shirt Tags ",
"year_start": "1984",
"year_end": "1997",
"category": null,
"brand_id": null,
"status": 1,
"created_at": "2024-12-10T13:29:51.000Z",
"updated_at": "2024-12-10T13:29:51.000Z",
"images_and_years": "https://s3.amazonaws.com/com.images.legiteem8/wild_oats/wild_oats-1.jpg==1984;;https://s3.amazonaws.com/com.images.legiteem8/wild_oats/wild_oats-2.jpg==1990;;https://s3.amazonaws.com/com.images.legiteem8/wild_oats/wild_oats-3.jpg==1992;;https://s3.amazonaws.com/com.images.legiteem8/wild_oats/wild_oats-4.jpg==1993;;https://s3.amazonaws.com/com.images.legiteem8/wild_oats/wild_oats-5.jpg==1995;;https://s3.amazonaws.com/com.images.legiteem8/wild_oats/wild_oats-6.jpg==1996;;https://s3.amazonaws.com/com.images.legiteem8/wild_oats/wild_oats-7.jpg==1997;;https://s3.amazonaws.com/com.images.legiteem8/wild_oats/wild_oats-8.jpg==1997",
"images": [
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/wild_oats/wild_oats-1.jpg",
"year": "1984"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/wild_oats/wild_oats-2.jpg",
"year": "1992"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/wild_oats/wild_oats-3.jpg",
"year": "1990"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/wild_oats/wild_oats-4.jpg",
"year": "1995"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/wild_oats/wild_oats-5.jpg",
"year": "1995"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/wild_oats/wild_oats-6.jpg",
"year": "1993"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/wild_oats/wild_oats-7.jpg",
"year": "1996"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/wild_oats/wild_oats-8.jpg",
"year": "1997"
}
]
},
{
"id": 17,
"name": "Winterland T-Shirt Tags",
"year_start": "1982",
"year_end": "2002",
"category": null,
"brand_id": null,
"status": 1,
"created_at": "2024-12-10T13:30:20.000Z",
"updated_at": "2024-12-10T13:30:20.000Z",
"images_and_years": "https://s3.amazonaws.com/com.images.legiteem8/winterland/winterland-1.jpg==1982-1988;;https://s3.amazonaws.com/com.images.legiteem8/winterland/winterland-2.jpg==1987-1992;;https://s3.amazonaws.com/com.images.legiteem8/winterland/winterland-3.jpg==1992-1997;;https://s3.amazonaws.com/com.images.legiteem8/winterland/winterland-4.jpg==1994-1997;;https://s3.amazonaws.com/com.images.legiteem8/winterland/winterland-5.jpg==1997-2001;;https://s3.amazonaws.com/com.images.legiteem8/winterland/winterland-6.jpg==1998-2001;;https://s3.amazonaws.com/com.images.legiteem8/winterland/winterland-7.jpg==2001-2008;;https://s3.amazonaws.com/com.images.legiteem8/winterland/winterland-8.jpg==2005-2008",
"images": [
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/winterland/winterland-1.jpg",
"year": "1982-1988"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/winterland/winterland-2.jpg",
"year": "1987-1992"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/winterland/winterland-3.jpg",
"year": "1992-1997"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/winterland/winterland-4.jpg",
"year": "1994-1997"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/winterland/winterland-5.jpg",
"year": "1997-2001"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/winterland/winterland-6.jpg",
"year": "1998-2001"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/winterland/winterland-7.jpg",
"year": "2001-2008"
},
{
"image": "https://s3.amazonaws.com/com.images.legiteem8/winterland/winterland-8.jpg",
"year": "2001-2008"
}
]
}
]
}
+68
View File
@@ -0,0 +1,68 @@
# API Documentation
## POST /get_tag
Identify a clothing tag and find similar tags/images using computer vision, text similarity, and (optionally) LLM-based filtering.
### Request
- **Content-Type:** application/json
- **Body:**
```json
{
"image_url": "<image-url>",
"use_llm": true // Optional, default: false
}
```
- `image_url` (string, required): URL of the tag image to scan
- `use_llm` (boolean, optional): If true, use LLM-based similarity filtering
### Response
- **Content-Type:** application/json
- **Body:**
```json
{
"results": [
{
"tag": "Jerzees T-Shirt Tags",
"similar_images": [
"https://.../tag1.jpg",
"https://.../tag2.jpg"
],
"appraisal_value": [150.0, 75.0],
"years": ["1998", "1997"],
"status": ["public", "private"]
}
]
}
```
### Example Request
```bash
curl -X POST http://localhost:8000/get_tag \
-H "Content-Type: application/json" \
-d '{"image_url": "https://example.com/tag_image.jpg", "use_llm": true}'
```
### Example Response
```json
{
"results": [
{
"tag": "Jerzees T-Shirt Tags",
"similar_images": [
"https://.../tag1.jpg",
"https://.../tag2.jpg"
],
"appraisal_value": [150.0, 75.0],
"years": ["1998", "1997"],
"status": ["public", "private"]
}
]
}
```
### Notes
- If `use_llm` is true, the system will use an LLM (OpenAI) to further filter and rank similar images.
- If no tag is identified, or no similar images are found, the response will indicate this.
- The endpoint is designed for use with the provided frontend, but can be called directly from any HTTP client.
- Requires a valid OpenAI API key if using LLM.
+65
View File
@@ -0,0 +1,65 @@
# Tag Scan Mini App
## Overview
This project is an AI-powered clothing tag identification and similarity search system. It analyzes clothing tag images, identifies brands using computer vision, and finds similar tags from a database. The system uses advanced AI techniques including image embeddings, text similarity, and (optionally) LLM-based filtering to provide accurate tag matching and recommendations.
## Features
- **Tag Identification:** Uses computer vision to identify clothing tag brands from images
- **Text-Based Matching:** Implements TF-IDF and cosine similarity for tag name matching
- **Image Similarity Search:** Uses CLIP embeddings and FAISS for visually similar tag images
- **LLM Enhancement:** Optional LLM analysis for improved similarity filtering
- **Metadata Extraction:** Provides appraisal values, years, and status information for similar tags
- **Simple Frontend:** Web UI to upload image URL, toggle LLM, and view results visually
## Tech Stack
- Python, Flask
- CLIP (Hugging Face), FAISS, scikit-learn, pandas, numpy
- OpenAI (optional, for LLM)
- HTML/CSS/JS frontend (Flask template)
## Setup & Installation
1. **Clone the Repository**
```bash
git clone <repository-url>
cd ds_task_tag_scan_project/ds_task/backend
```
2. **Create and Activate Virtual Environment**
```bash
python3 -m venv ../venv
source ../venv/bin/activate
```
3. **Install Requirements**
```bash
pip install -r requirements.txt
```
4. **Set Environment Variables** (if using LLM)
```bash
export OPENAI_API_KEY=your-openai-key
```
5. **Run the App**
```bash
python app.py
```
(For production, use Docker or a Linux server for stability.)
## Usage
- Go to [http://localhost:8000/](http://localhost:8000/) in your browser
- Enter a tag image URL
- Toggle "Use LLM Similarity" if desired
- Click "Scan Tag" to see results (tag info, similar images, metadata)
## File Structure
- `backend/` - Flask app, ML/DS logic, templates
- `data/` - Tag guides, expert and community CSVs
- `docs/` - Documentation (this file, API doc)
## Notes
- For best stability, run in a Linux environment or Docker.
- On Mac, the app is configured to use only one thread for all ML/numerical libraries.
- LLM similarity requires a valid OpenAI API key.
---
See `API_Documentation.md` for API details.