Initial commit
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
venv/
|
||||||
|
backend/__pycache__
|
||||||
+326
@@ -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)
|
||||||
@@ -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.
@@ -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]
|
||||||
@@ -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)
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
@@ -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
|
||||||
@@ -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 += ` <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>
|
||||||
+31899
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 132 KiB |
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -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.
|
||||||
@@ -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.
|
||||||
Reference in New Issue
Block a user