sunheycho commited on
Commit
56b6ee6
·
1 Parent(s): 3d0fd74

feat(llama-lora): add display names and defaults; add peft; rebuild static\n\n- UI: add baseName/loraName fields and send to backend; show names in results\n- Defaults: base=openlm-research/open_llama_3b, adapter=HGKo/openllama3b-lora-adapter\n- Backend deps: add peft to requirements.txt\n- Frontend: build CRA and sync artifacts to top-level static/

Browse files
api.py CHANGED
@@ -46,6 +46,12 @@ from flask_login import (
46
  login_fresh,
47
  )
48
 
 
 
 
 
 
 
49
  # Fix for SQLite3 version compatibility with ChromaDB
50
  try:
51
  import pysqlite3
@@ -779,6 +785,48 @@ def yolo_detect():
779
  result = process_yolo(image)
780
  return jsonify(result)
781
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
782
  @app.route('/api/detect/detr', methods=['POST'])
783
  @require_auth()
784
  def detr_detect():
@@ -1395,16 +1443,26 @@ def start_llama_lora_compare():
1395
  text = res.get('choices', [{}])[0].get('text', '').strip()
1396
  # Ensure we don't return an empty base output
1397
  base_output = text or "[empty]"
 
 
 
 
 
 
 
 
 
 
 
 
1398
  elif llm_model is not None and llm_tokenizer is not None:
1399
  inputs = llm_tokenizer(full_prompt, return_tensors='pt').to(device)
1400
  with torch.no_grad():
1401
  out = llm_model.generate(**inputs, max_new_tokens=128, temperature=0.7, top_p=0.9)
1402
  text = llm_tokenizer.decode(out[0], skip_special_tokens=True)
1403
- # Some models echo the prompt; only strip if there's meaningful content after
1404
  if text.startswith(full_prompt):
1405
  stripped = text[len(full_prompt):].strip()
1406
  text = stripped if stripped else text
1407
- # Provide a non-empty fallback
1408
  base_output = text or "[empty]"
1409
  else:
1410
  base_output = f"[mock] Base response for: {full_prompt[:80]}..."
@@ -1413,12 +1471,20 @@ def start_llama_lora_compare():
1413
  base_latency = int((time.time() - start_base) * 1000)
1414
  lora_add_message(session_id, f"Base inference done in {base_latency} ms")
1415
 
1416
- # Run LoRA inference (mock unless PEFT is integrated)
1417
  start_lora = time.time()
1418
  try:
1419
- if lora_path and llm_model is not None and llm_tokenizer is not None:
1420
- # Placeholder: in real integration, load LoRA via PEFT and run generate
1421
- lora_output = f"[mock-lora:{lora_path}] {base_output}"
 
 
 
 
 
 
 
 
1422
  else:
1423
  lora_output = f"[mock] LoRA response (no adapter) for: {full_prompt[:80]}..."
1424
  except Exception as e:
 
46
  login_fresh,
47
  )
48
 
49
+ try:
50
+ # PEFT for LoRA adapters (optional)
51
+ from peft import PeftModel
52
+ except Exception as _e:
53
+ PeftModel = None
54
+
55
  # Fix for SQLite3 version compatibility with ChromaDB
56
  try:
57
  import pysqlite3
 
785
  result = process_yolo(image)
786
  return jsonify(result)
787
 
788
+ # --- HF CausalLM + LoRA helper caches ---
789
+ hf_tokenizers = {}
790
+ hf_base_models = {}
791
+ hf_lora_models = {}
792
+
793
+ def _preferred_dtype():
794
+ try:
795
+ return torch.float16 if torch.cuda.is_available() else torch.float32
796
+ except Exception:
797
+ return torch.float32
798
+
799
+ def load_hf_base_and_tokenizer(base_id: str, tok_id: str = None):
800
+ """Load and cache base CausalLM and tokenizer. tok_id can point to adapter repo to use its tokenizer."""
801
+ global hf_tokenizers, hf_base_models
802
+ tok_key = tok_id or base_id
803
+ if tok_key not in hf_tokenizers:
804
+ hf_tokenizers[tok_key] = AutoTokenizer.from_pretrained(tok_key, use_fast=True)
805
+ if base_id not in hf_base_models:
806
+ hf_base_models[base_id] = AutoModelForCausalLM.from_pretrained(
807
+ base_id,
808
+ torch_dtype=_preferred_dtype(),
809
+ use_safetensors=False,
810
+ ).to(device)
811
+ return hf_tokenizers[tok_key], hf_base_models[base_id]
812
+
813
+ def load_hf_lora_model(base_id: str, adapter_id: str):
814
+ """Load and cache a PEFT-wrapped LoRA model from base + adapter. Returns model or raises if PEFT unavailable."""
815
+ if PeftModel is None:
816
+ raise RuntimeError("PEFT (peft) is not installed; cannot load LoRA adapter")
817
+ key = f"{base_id}::{adapter_id}"
818
+ if key in hf_lora_models:
819
+ return hf_lora_models[key]
820
+ # Create a fresh base to avoid mutating the cached base used for non-LoRA runs
821
+ base = AutoModelForCausalLM.from_pretrained(
822
+ base_id,
823
+ torch_dtype=_preferred_dtype(),
824
+ use_safetensors=False,
825
+ ).to(device)
826
+ lora_model = PeftModel.from_pretrained(base, adapter_id).eval().to(device)
827
+ hf_lora_models[key] = lora_model
828
+ return lora_model
829
+
830
  @app.route('/api/detect/detr', methods=['POST'])
831
  @require_auth()
832
  def detr_detect():
 
1443
  text = res.get('choices', [{}])[0].get('text', '').strip()
1444
  # Ensure we don't return an empty base output
1445
  base_output = text or "[empty]"
1446
+ elif '/' in base_model_id:
1447
+ # HF Transformers path (e.g., openlm-research/open_llama_3b)
1448
+ tok_id = lora_path or base_model_id # user expects tokenizer from adapter repo when provided
1449
+ tokenizer_hf, base_model_hf = load_hf_base_and_tokenizer(base_model_id, tok_id)
1450
+ inputs = tokenizer_hf(full_prompt, return_tensors='pt').to(device)
1451
+ with torch.no_grad():
1452
+ out = base_model_hf.generate(**inputs, max_new_tokens=128, temperature=0.7, top_p=0.9)
1453
+ text = tokenizer_hf.decode(out[0], skip_special_tokens=True)
1454
+ if text.startswith(full_prompt):
1455
+ stripped = text[len(full_prompt):].strip()
1456
+ text = stripped if stripped else text
1457
+ base_output = text or "[empty]"
1458
  elif llm_model is not None and llm_tokenizer is not None:
1459
  inputs = llm_tokenizer(full_prompt, return_tensors='pt').to(device)
1460
  with torch.no_grad():
1461
  out = llm_model.generate(**inputs, max_new_tokens=128, temperature=0.7, top_p=0.9)
1462
  text = llm_tokenizer.decode(out[0], skip_special_tokens=True)
 
1463
  if text.startswith(full_prompt):
1464
  stripped = text[len(full_prompt):].strip()
1465
  text = stripped if stripped else text
 
1466
  base_output = text or "[empty]"
1467
  else:
1468
  base_output = f"[mock] Base response for: {full_prompt[:80]}..."
 
1471
  base_latency = int((time.time() - start_base) * 1000)
1472
  lora_add_message(session_id, f"Base inference done in {base_latency} ms")
1473
 
1474
+ # Run LoRA inference (prefer HF+PEFT when adapter provided)
1475
  start_lora = time.time()
1476
  try:
1477
+ if lora_path and '/' in base_model_id:
1478
+ tokenizer_hf, _ = load_hf_base_and_tokenizer(base_model_id, lora_path)
1479
+ lora_model = load_hf_lora_model(base_model_id, lora_path)
1480
+ inputs = tokenizer_hf(full_prompt, return_tensors='pt').to(device)
1481
+ with torch.no_grad():
1482
+ out = lora_model.generate(**inputs, max_new_tokens=128, temperature=0.7, top_p=0.9)
1483
+ text = tokenizer_hf.decode(out[0], skip_special_tokens=True)
1484
+ if text.startswith(full_prompt):
1485
+ stripped = text[len(full_prompt):].strip()
1486
+ text = stripped if stripped else text
1487
+ lora_output = text or "[empty]"
1488
  else:
1489
  lora_output = f"[mock] LoRA response (no adapter) for: {full_prompt[:80]}..."
1490
  except Exception as e:
frontend/src/components/LlamaLoraCompare.js CHANGED
@@ -4,8 +4,10 @@ import { Box, Paper, Typography, Grid, TextField, Button, CircularProgress, Divi
4
  const LlamaLoraCompare = () => {
5
  const [prompt, setPrompt] = useState('Describe the image concisely.');
6
  const [imageFile, setImageFile] = useState(null);
7
- const [baseModel, setBaseModel] = useState('gguf:tinyllama-q4km');
8
- const [loraPath, setLoraPath] = useState('');
 
 
9
  const [results, setResults] = useState(null);
10
  const [isProcessing, setIsProcessing] = useState(false);
11
  const [logs, setLogs] = useState([]);
@@ -33,7 +35,9 @@ const LlamaLoraCompare = () => {
33
  const formData = new FormData();
34
  formData.append('prompt', prompt);
35
  formData.append('baseModel', baseModel);
 
36
  if (loraPath) formData.append('loraPath', loraPath);
 
37
  if (imageFile) formData.append('image', imageFile);
38
 
39
  try {
@@ -96,7 +100,9 @@ const LlamaLoraCompare = () => {
96
  <Grid item xs={12} md={6}>
97
  <Box display="flex" flexDirection="column" gridGap={12}>
98
  <TextField label="Base model id" value={baseModel} onChange={(e) => setBaseModel(e.target.value)} variant="outlined" fullWidth />
 
99
  <TextField label="LoRA path/ID (optional)" value={loraPath} onChange={(e) => setLoraPath(e.target.value)} variant="outlined" fullWidth />
 
100
  <input type="file" accept="image/*" onChange={(e) => setImageFile(e.target.files?.[0] || null)} />
101
  <Button color="primary" variant="contained" onClick={handleStart} disabled={isProcessing}>
102
  {isProcessing ? <CircularProgress size={22} /> : 'Run Comparison'}
@@ -130,9 +136,9 @@ const LlamaLoraCompare = () => {
130
  <Box>
131
  <Typography variant="subtitle2">Prompt</Typography>
132
  <Box style={{ whiteSpace: 'pre-wrap', marginBottom: 8 }}>{results.prompt}</Box>
133
- <Typography variant="subtitle2">Base Output</Typography>
134
  <Box style={{ whiteSpace: 'pre-wrap', marginBottom: 8 }}>{results.base?.output || '-'}</Box>
135
- <Typography variant="subtitle2">LoRA Output</Typography>
136
  <Box style={{ whiteSpace: 'pre-wrap', marginBottom: 8 }}>{results.lora?.output || '-'}</Box>
137
  <Typography variant="subtitle2">Latency</Typography>
138
  <Box>{`base: ${results.base?.latency_ms || 0} ms | lora: ${results.lora?.latency_ms || 0} ms`}</Box>
 
4
  const LlamaLoraCompare = () => {
5
  const [prompt, setPrompt] = useState('Describe the image concisely.');
6
  const [imageFile, setImageFile] = useState(null);
7
+ const [baseModel, setBaseModel] = useState('openlm-research/open_llama_3b');
8
+ const [loraPath, setLoraPath] = useState('HGKo/openllama3b-lora-adapter');
9
+ const [baseName, setBaseName] = useState('Base Model');
10
+ const [loraName, setLoraName] = useState('LoRA Adapter');
11
  const [results, setResults] = useState(null);
12
  const [isProcessing, setIsProcessing] = useState(false);
13
  const [logs, setLogs] = useState([]);
 
35
  const formData = new FormData();
36
  formData.append('prompt', prompt);
37
  formData.append('baseModel', baseModel);
38
+ if (baseName) formData.append('baseName', baseName);
39
  if (loraPath) formData.append('loraPath', loraPath);
40
+ if (loraName) formData.append('loraName', loraName);
41
  if (imageFile) formData.append('image', imageFile);
42
 
43
  try {
 
100
  <Grid item xs={12} md={6}>
101
  <Box display="flex" flexDirection="column" gridGap={12}>
102
  <TextField label="Base model id" value={baseModel} onChange={(e) => setBaseModel(e.target.value)} variant="outlined" fullWidth />
103
+ <TextField label="Base model name (display)" value={baseName} onChange={(e) => setBaseName(e.target.value)} variant="outlined" fullWidth />
104
  <TextField label="LoRA path/ID (optional)" value={loraPath} onChange={(e) => setLoraPath(e.target.value)} variant="outlined" fullWidth />
105
+ <TextField label="LoRA adapter name (display, optional)" value={loraName} onChange={(e) => setLoraName(e.target.value)} variant="outlined" fullWidth />
106
  <input type="file" accept="image/*" onChange={(e) => setImageFile(e.target.files?.[0] || null)} />
107
  <Button color="primary" variant="contained" onClick={handleStart} disabled={isProcessing}>
108
  {isProcessing ? <CircularProgress size={22} /> : 'Run Comparison'}
 
136
  <Box>
137
  <Typography variant="subtitle2">Prompt</Typography>
138
  <Box style={{ whiteSpace: 'pre-wrap', marginBottom: 8 }}>{results.prompt}</Box>
139
+ <Typography variant="subtitle2">{baseName || 'Base Output'}</Typography>
140
  <Box style={{ whiteSpace: 'pre-wrap', marginBottom: 8 }}>{results.base?.output || '-'}</Box>
141
+ <Typography variant="subtitle2">{loraName || 'LoRA Output'}</Typography>
142
  <Box style={{ whiteSpace: 'pre-wrap', marginBottom: 8 }}>{results.lora?.output || '-'}</Box>
143
  <Typography variant="subtitle2">Latency</Typography>
144
  <Box>{`base: ${results.base?.latency_ms || 0} ms | lora: ${results.lora?.latency_ms || 0} ms`}</Box>
requirements.txt CHANGED
@@ -52,6 +52,9 @@ langchain-openai>=0.1.16
52
  langchain-community>=0.2.6
53
  langchain-experimental>=0.0.60
54
 
 
 
 
55
  # llama.cpp bindings for loading local GGUF (quantized Q4) models — optional.
56
  # Removed from default install to avoid long native builds on Spaces.
57
  # llama-cpp-python>=0.2.90
 
52
  langchain-community>=0.2.6
53
  langchain-experimental>=0.0.60
54
 
55
+ # PEFT for LoRA
56
+ peft>=0.10.0
57
+
58
  # llama.cpp bindings for loading local GGUF (quantized Q4) models — optional.
59
  # Removed from default install to avoid long native builds on Spaces.
60
  # llama-cpp-python>=0.2.90
static/asset-manifest.json CHANGED
@@ -1,8 +1,8 @@
1
  {
2
  "files": {
3
  "main.css": "/static/css/main.3b4eede1.chunk.css",
4
- "main.js": "/static/js/main.2c1002fc.chunk.js",
5
- "main.js.map": "/static/js/main.2c1002fc.chunk.js.map",
6
  "runtime-main.js": "/static/js/runtime-main.1d79dee9.js",
7
  "runtime-main.js.map": "/static/js/runtime-main.1d79dee9.js.map",
8
  "static/js/2.933cba9a.chunk.js": "/static/js/2.933cba9a.chunk.js",
@@ -10,7 +10,7 @@
10
  "static/js/3.10abbce4.chunk.js": "/static/js/3.10abbce4.chunk.js",
11
  "static/js/3.10abbce4.chunk.js.map": "/static/js/3.10abbce4.chunk.js.map",
12
  "index.html": "/index.html",
13
- "precache-manifest.b122c3ac2cc3b905017a2fe31e239c0f.js": "/precache-manifest.b122c3ac2cc3b905017a2fe31e239c0f.js",
14
  "service-worker.js": "/service-worker.js",
15
  "static/css/main.3b4eede1.chunk.css.map": "/static/css/main.3b4eede1.chunk.css.map",
16
  "static/js/2.933cba9a.chunk.js.LICENSE.txt": "/static/js/2.933cba9a.chunk.js.LICENSE.txt"
@@ -19,6 +19,6 @@
19
  "static/js/runtime-main.1d79dee9.js",
20
  "static/js/2.933cba9a.chunk.js",
21
  "static/css/main.3b4eede1.chunk.css",
22
- "static/js/main.2c1002fc.chunk.js"
23
  ]
24
  }
 
1
  {
2
  "files": {
3
  "main.css": "/static/css/main.3b4eede1.chunk.css",
4
+ "main.js": "/static/js/main.be1003f9.chunk.js",
5
+ "main.js.map": "/static/js/main.be1003f9.chunk.js.map",
6
  "runtime-main.js": "/static/js/runtime-main.1d79dee9.js",
7
  "runtime-main.js.map": "/static/js/runtime-main.1d79dee9.js.map",
8
  "static/js/2.933cba9a.chunk.js": "/static/js/2.933cba9a.chunk.js",
 
10
  "static/js/3.10abbce4.chunk.js": "/static/js/3.10abbce4.chunk.js",
11
  "static/js/3.10abbce4.chunk.js.map": "/static/js/3.10abbce4.chunk.js.map",
12
  "index.html": "/index.html",
13
+ "precache-manifest.e677d30bd91056af61222e81dd6b30d3.js": "/precache-manifest.e677d30bd91056af61222e81dd6b30d3.js",
14
  "service-worker.js": "/service-worker.js",
15
  "static/css/main.3b4eede1.chunk.css.map": "/static/css/main.3b4eede1.chunk.css.map",
16
  "static/js/2.933cba9a.chunk.js.LICENSE.txt": "/static/js/2.933cba9a.chunk.js.LICENSE.txt"
 
19
  "static/js/runtime-main.1d79dee9.js",
20
  "static/js/2.933cba9a.chunk.js",
21
  "static/css/main.3b4eede1.chunk.css",
22
+ "static/js/main.be1003f9.chunk.js"
23
  ]
24
  }
static/index.html CHANGED
@@ -1 +1 @@
1
- <!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Multi-Model Object Detection Demo"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>Vision Web App</title><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/><link href="/static/css/main.3b4eede1.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,i,a=r[0],c=r[1],l=r[2],f=0,s=[];f<a.length;f++)i=a[f],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,l||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,a=1;a<t.length;a++){var c=t[a];0!==o[c]&&(n=!1)}n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={1:0},u=[];function i(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,i),t.l=!0,t.exports}i.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise((function(r,n){t=o[e]=[r,n]}));r.push(t[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+"static/js/"+({}[e]||e)+"."+{3:"10abbce4"}[e]+".chunk.js"}(e);var c=new Error;u=function(r){a.onerror=a.onload=null,clearTimeout(l);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:a})}),12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(r)},i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,function(r){return e[r]}.bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="/",i.oe=function(e){throw console.error(e),e};var a=this["webpackJsonpvision-web-app"]=this["webpackJsonpvision-web-app"]||[],c=a.push.bind(a);a.push=r,a=a.slice();for(var l=0;l<a.length;l++)r(a[l]);var p=c;t()}([])</script><script src="/static/js/2.933cba9a.chunk.js"></script><script src="/static/js/main.2c1002fc.chunk.js"></script></body></html>
 
1
+ <!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Multi-Model Object Detection Demo"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>Vision Web App</title><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"/><link href="/static/css/main.3b4eede1.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,i,a=r[0],c=r[1],l=r[2],f=0,s=[];f<a.length;f++)i=a[f],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,l||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,a=1;a<t.length;a++){var c=t[a];0!==o[c]&&(n=!1)}n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={1:0},u=[];function i(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,i),t.l=!0,t.exports}i.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise((function(r,n){t=o[e]=[r,n]}));r.push(t[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+"static/js/"+({}[e]||e)+"."+{3:"10abbce4"}[e]+".chunk.js"}(e);var c=new Error;u=function(r){a.onerror=a.onload=null,clearTimeout(l);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:a})}),12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(r)},i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,function(r){return e[r]}.bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="/",i.oe=function(e){throw console.error(e),e};var a=this["webpackJsonpvision-web-app"]=this["webpackJsonpvision-web-app"]||[],c=a.push.bind(a);a.push=r,a=a.slice();for(var l=0;l<a.length;l++)r(a[l]);var p=c;t()}([])</script><script src="/static/js/2.933cba9a.chunk.js"></script><script src="/static/js/main.be1003f9.chunk.js"></script></body></html>
static/{precache-manifest.b122c3ac2cc3b905017a2fe31e239c0f.js → precache-manifest.e677d30bd91056af61222e81dd6b30d3.js} RENAMED
@@ -1,10 +1,10 @@
1
  self.__precacheManifest = (self.__precacheManifest || []).concat([
2
  {
3
- "revision": "f1bad2b23dad084bbe2b9f32933cd096",
4
  "url": "/index.html"
5
  },
6
  {
7
- "revision": "f780ff4dddfa2065259b",
8
  "url": "/static/css/main.3b4eede1.chunk.css"
9
  },
10
  {
@@ -20,8 +20,8 @@ self.__precacheManifest = (self.__precacheManifest || []).concat([
20
  "url": "/static/js/3.10abbce4.chunk.js"
21
  },
22
  {
23
- "revision": "f780ff4dddfa2065259b",
24
- "url": "/static/js/main.2c1002fc.chunk.js"
25
  },
26
  {
27
  "revision": "154c4b0ed16fd7552969",
 
1
  self.__precacheManifest = (self.__precacheManifest || []).concat([
2
  {
3
+ "revision": "345dc438ab4c3d30cb74185f014bf900",
4
  "url": "/index.html"
5
  },
6
  {
7
+ "revision": "c644b449a961b4302219",
8
  "url": "/static/css/main.3b4eede1.chunk.css"
9
  },
10
  {
 
20
  "url": "/static/js/3.10abbce4.chunk.js"
21
  },
22
  {
23
+ "revision": "c644b449a961b4302219",
24
+ "url": "/static/js/main.be1003f9.chunk.js"
25
  },
26
  {
27
  "revision": "154c4b0ed16fd7552969",
static/service-worker.js CHANGED
@@ -14,7 +14,7 @@
14
  importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js");
15
 
16
  importScripts(
17
- "/precache-manifest.b122c3ac2cc3b905017a2fe31e239c0f.js"
18
  );
19
 
20
  self.addEventListener('message', (event) => {
 
14
  importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js");
15
 
16
  importScripts(
17
+ "/precache-manifest.e677d30bd91056af61222e81dd6b30d3.js"
18
  );
19
 
20
  self.addEventListener('message', (event) => {
static/static/js/main.2c1002fc.chunk.js.map DELETED
The diff for this file is too large to render. See raw diff
 
static/static/js/{main.2c1002fc.chunk.js → main.be1003f9.chunk.js} RENAMED
@@ -1,2 +1,2 @@
1
- (this["webpackJsonpvision-web-app"]=this["webpackJsonpvision-web-app"]||[]).push([[0],{104:function(e,a,t){},105:function(e,a,t){"use strict";t.r(a);var n=t(0),r=t.n(n),l=t(11),o=t.n(l),c=(t(99),t(79)),i=t(165),s=t(169),m=t(166),d=t(167),u=t(49),p=t(171),g=t(161),E=t(168),y=t(142),f=t(83),b=t(147),h=t(140),v=t(141),x=t(65),S=t.n(x),C=t(76),w=t.n(C),j=t(137);const O=Object(j.a)(e=>({paper:{padding:e.spacing(2),display:"flex",flexDirection:"column",alignItems:"center",height:"100%",minHeight:300,transition:"all 0.3s ease"},dragActive:{border:"2px dashed #3f51b5",backgroundColor:"rgba(63, 81, 181, 0.05)"},dragInactive:{border:"2px dashed #ccc",backgroundColor:"white"},uploadBox:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",height:"100%",width:"100%",cursor:"pointer"},uploadIcon:{fontSize:60,color:"#3f51b5",marginBottom:e.spacing(2)},supportText:{marginTop:e.spacing(2)},previewBox:{display:"flex",flexDirection:"column",alignItems:"center",width:"100%",height:"100%",position:"relative"},imageContainer:{position:"relative",width:"100%",height:"45vh",[e.breakpoints.down("sm")]:{height:"35vh"},display:"flex",justifyContent:"center",alignItems:"center",overflow:"hidden",marginTop:e.spacing(2)},deleteButton:{position:"absolute",top:0,right:0,backgroundColor:"rgba(255, 255, 255, 0.7)","&:hover":{backgroundColor:"rgba(255, 255, 255, 0.9)"}}}));var I=e=>{let{onImageUpload:a}=e;const t=O(),[l,o]=Object(n.useState)(null),[c,i]=Object(n.useState)(!1),m=Object(n.useRef)(null),d=e=>{e.preventDefault(),e.stopPropagation(),"dragenter"===e.type||"dragover"===e.type?i(!0):"dragleave"===e.type&&i(!1)},p=e=>{e.type.startsWith("image/")?(o(URL.createObjectURL(e)),a(e)):alert("Please upload an image file")};return r.a.createElement(f.a,{className:"".concat(t.paper," ").concat(c?t.dragActive:t.dragInactive),onDragEnter:d,onDragLeave:d,onDragOver:d,onDrop:e=>{e.preventDefault(),e.stopPropagation(),i(!1),e.dataTransfer.files&&e.dataTransfer.files[0]&&p(e.dataTransfer.files[0])}},r.a.createElement("input",{ref:m,type:"file",accept:"image/*",onChange:e=>{e.preventDefault(),e.target.files&&e.target.files[0]&&p(e.target.files[0])},style:{display:"none"}}),l?r.a.createElement(s.a,{className:t.previewBox},r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"Preview"),r.a.createElement(s.a,{className:t.imageContainer},r.a.createElement("img",{src:l,alt:"Preview",className:"preview-image",style:{maxWidth:"100%",maxHeight:"100%",width:"auto",height:"auto",objectFit:"contain",display:"block"}}),r.a.createElement(v.a,{"aria-label":"delete",className:t.deleteButton,onClick:()=>{o(null),a(null),m.current.value=""}},r.a.createElement(w.a,null)))):r.a.createElement(s.a,{className:t.uploadBox,onClick:()=>{m.current.click()}},r.a.createElement(S.a,{className:t.uploadIcon}),r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"Drag & Drop an image here"),r.a.createElement(u.a,{variant:"body2",color:"textSecondary",gutterBottom:!0},"or"),r.a.createElement(h.a,{variant:"contained",color:"primary",component:"span",startIcon:r.a.createElement(S.a,null)},"Browse Files"),r.a.createElement(u.a,{variant:"body2",color:"textSecondary",className:t.supportText},"Supported formats: JPG, PNG, GIF")))},P=t(143),B=t(144),N=t(176),T=t(145),k=t(66),A=t.n(k),R=t(77),D=t.n(R),F=t(78),L=t.n(F);const _=Object(j.a)(e=>({card:{height:"100%",display:"flex",flexDirection:"column"},selectedCard:{border:"2px solid #3f51b5"},unavailableCard:{opacity:.6},cardContent:{flexGrow:1},chipContainer:{marginBottom:e.spacing(1.5)},successChip:{backgroundColor:"#34C759",color:"#fff"},errorChip:{backgroundColor:"#FF3B3F",color:"#fff"},modelType:{marginTop:e.spacing(1)},processButton:{marginTop:e.spacing(3),textAlign:"center"}}));var z=e=>{let{onModelSelect:a,onProcess:t,isProcessing:n,modelsStatus:l,selectedModel:o,imageSelected:c}=e;const i=_(),m=[{id:"yolo",name:"YOLOv8",description:"Fast and accurate object detection",icon:r.a.createElement(A.a,null),available:l.yolo},{id:"detr",name:"DETR",description:"DEtection TRansformer for object detection",icon:r.a.createElement(A.a,null),available:l.detr},{id:"vit",name:"ViT",description:"Vision Transformer for image classification",icon:r.a.createElement(D.a,null),available:l.vit}],d=e=>{m.find(a=>a.id===e).available&&a(e)};return r.a.createElement(s.a,{sx:{p:2,height:"100%"}},r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"Select Model"),r.a.createElement(y.a,{container:!0,spacing:2},m.map(e=>r.a.createElement(y.a,{item:!0,xs:12,sm:4,key:e.id},r.a.createElement(P.a,{className:"\n ".concat(i.card," \n ").concat(o===e.id?i.selectedCard:""," \n ").concat(e.available?"":i.unavailableCard,"\n "),onClick:()=>d(e.id)},r.a.createElement(B.a,{className:i.cardContent},r.a.createElement(s.a,{sx:{mb:2,color:"primary"}},e.icon),r.a.createElement(u.a,{variant:"h5",component:"div",gutterBottom:!0},e.name),r.a.createElement("div",{className:i.chipContainer},e.available?r.a.createElement(N.a,{label:"Available",className:i.successChip,size:"small"}):r.a.createElement(N.a,{label:"Not Available",className:i.errorChip,size:"small"})),r.a.createElement(u.a,{variant:"body2",color:"textSecondary"},e.description)),r.a.createElement(T.a,null,r.a.createElement(h.a,{size:"small",onClick:()=>d(e.id),disabled:!e.available,color:o===e.id?"primary":"default",variant:o===e.id?"contained":"outlined",fullWidth:!0},o===e.id?"Selected":"Select")))))),r.a.createElement("div",{className:i.processButton},r.a.createElement(h.a,{variant:"contained",color:"primary",size:"large",startIcon:r.a.createElement(L.a,null),onClick:t,disabled:!o||!c||n},n?"Processing...":"Process Image")))},W=t(157),M=t(154),U=t(107),J=t(158),V=t(146),H=t(174),G=t(175),q=t(149),Y=t(150),Q=t(151),K=t(177),X=t(170),Z=t(155),$=t(179),ee=t(156),ae=t(173);const te=Object(j.a)(e=>({root:{marginTop:e.spacing(2),marginBottom:e.spacing(2),padding:e.spacing(2),backgroundColor:"#f5f5f5",borderRadius:e.shape.borderRadius},button:{marginRight:e.spacing(2)},searchDialog:{minWidth:"500px"},formControl:{marginBottom:e.spacing(2),minWidth:"100%"},searchResults:{marginTop:e.spacing(2)},resultCard:{marginBottom:e.spacing(2)},resultImage:{height:140,objectFit:"contain"},chip:{margin:e.spacing(.5)},similarityChip:{backgroundColor:e.palette.primary.main,color:"white"}}));var ne=e=>{let{results:a}=e;const t=te(),[l,o]=Object(n.useState)(!1),[c,i]=Object(n.useState)(!1),[m,d]=Object(n.useState)(null),[p,g]=Object(n.useState)(!1),[E,f]=Object(n.useState)("image"),[v,x]=Object(n.useState)(""),[S,C]=Object(n.useState)([]),[w,j]=Object(n.useState)(!1),[O,I]=Object(n.useState)(null),{model:T,data:k}=a,A=()=>{g(!1)},R=()=>"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(function(e){const a=16*Math.random()|0;return("x"===e?a:3&a|8).toString(16)}));return r.a.createElement(s.a,{className:t.root},r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"Vector Database Actions"),r.a.createElement(s.a,{display:"flex",alignItems:"center",mb:2},r.a.createElement(h.a,{variant:"contained",color:"primary",onClick:async()=>{o(!0),d(null);try{let e;if(e="vit"===T?await fetch("/api/add-to-collection",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({image:k.image,metadata:{model:"vit",classifications:k.classifications}})}):await fetch("/api/add-detected-objects",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({image:k.image,objects:k.detections,imageId:R()})}),!e.ok)throw new Error("HTTP error! Status: ".concat(e.status));const a=await e.json();if(a.error)throw new Error(a.error);i(!0),setTimeout(()=>i(!1),5e3)}catch(e){console.error("Error saving to vector DB:",e),d("Error saving to vector DB: ".concat(e.message))}finally{o(!1)}},disabled:l,className:t.button},l?r.a.createElement(r.a.Fragment,null,r.a.createElement(b.a,{size:20,color:"inherit",style:{marginRight:8}}),"Saving..."):"Save to Vector DB"),r.a.createElement(h.a,{variant:"outlined",color:"primary",onClick:()=>{g(!0),C([]),I(null)},className:t.button},"Search Similar")),m&&r.a.createElement(ae.a,{severity:"error",style:{marginTop:8}},m),r.a.createElement(H.a,{open:c,autoHideDuration:5e3,onClose:()=>i(!1)},r.a.createElement(ae.a,{severity:"success"},"vit"===T?"Image and classifications successfully saved to vector DB!":"Detected objects successfully saved to vector DB!")),r.a.createElement(G.a,{open:p,onClose:A,maxWidth:"md",fullWidth:!0},r.a.createElement(q.a,null,"Search Vector Database"),r.a.createElement(Y.a,null,r.a.createElement(Q.a,{className:t.formControl},r.a.createElement(K.a,{id:"search-type-label"},"Search Type"),r.a.createElement(X.a,{labelId:"search-type-label",id:"search-type",value:E,onChange:e=>{f(e.target.value),C([]),I(null)}},r.a.createElement(Z.a,{value:"image"},"Search by Current Image"),r.a.createElement(Z.a,{value:"class"},"Search by Class Name"))),"class"===E&&r.a.createElement(Q.a,{className:t.formControl},r.a.createElement($.a,{label:"Class Name",value:v,onChange:e=>{x(e.target.value)},placeholder:"e.g. person, car, dog...",fullWidth:!0})),O&&r.a.createElement(ae.a,{severity:"error",style:{marginBottom:16}},O),r.a.createElement(s.a,{className:t.searchResults},w?r.a.createElement(s.a,{display:"flex",justifyContent:"center",alignItems:"center",p:4},r.a.createElement(b.a,null),r.a.createElement(u.a,{variant:"body1",style:{marginLeft:16}},"Searching...")):r.a.createElement(r.a.Fragment,null,console.log("Search dialog render - searchResults:",S),S.length>0?(console.log("Rendering search results:",S),console.log("Search results length:",S.length),0===S.length?(console.log("No results to render"),r.a.createElement(u.a,{variant:"body1"},"No results found.")):r.a.createElement(y.a,{container:!0,spacing:2},S.map((e,a)=>{const n=100*(1-e.distance);return r.a.createElement(y.a,{item:!0,xs:12,sm:6,key:a},r.a.createElement(P.a,{className:t.resultCard},e.metadata&&e.metadata.image_data?r.a.createElement(V.a,{className:t.resultImage,component:"img",height:"200",image:"data:image/jpeg;base64,".concat(e.metadata.image_data),alt:e.metadata&&e.metadata.class?e.metadata.class:"Object"}):r.a.createElement(s.a,{className:t.resultImage,style:{backgroundColor:"#f0f0f0",display:"flex",alignItems:"center",justifyContent:"center",height:200}},r.a.createElement(u.a,{variant:"body2",color:"textSecondary"},e.metadata&&e.metadata.class?e.metadata.class:"Object"," Image")),r.a.createElement(B.a,null,r.a.createElement(s.a,{display:"flex",justifyContent:"space-between",alignItems:"center",mb:1},r.a.createElement(u.a,{variant:"subtitle1"},"Result #",a+1),r.a.createElement(N.a,{label:"Similarity: ".concat(n.toFixed(2),"%"),className:t.similarityChip,size:"small"})),r.a.createElement(u.a,{variant:"body2",color:"textSecondary"},r.a.createElement("strong",null,"Class:")," ",e.metadata.class||"N/A"),e.metadata.confidence&&r.a.createElement(u.a,{variant:"body2",color:"textSecondary"},r.a.createElement("strong",null,"Confidence:")," ",(100*e.metadata.confidence).toFixed(2),"%"),r.a.createElement(u.a,{variant:"body2",color:"textSecondary"},r.a.createElement("strong",null,"Object ID:")," ",e.id))))}))):r.a.createElement(u.a,{variant:"body1"},"No results found. Please try another search.")))),r.a.createElement(ee.a,null,r.a.createElement(h.a,{onClick:A,color:"default"},"Close"),r.a.createElement(h.a,{onClick:async()=>{j(!0),I(null);try{let e={};if("image"===E)e={searchType:"image",image:k.image,n_results:5};else{if(!v.trim())throw new Error("Please enter a class name");e={searchType:"class",class_name:v.trim(),n_results:5}}const a=await fetch("/api/search-similar-objects",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!a.ok)throw new Error("HTTP error! Status: ".concat(a.status));const t=await a.json();if(t.error)throw new Error(t.error);if(console.log("Search API response:",t),!t.success||!Array.isArray(t.results))throw console.error("Unexpected API response format:",t),new Error("Unexpected API response format");console.log("Setting search results array:",t.results),console.log("Results array length:",t.results.length),console.log("First result item:",t.results[0]),C(t.results)}catch(e){console.error("Error searching vector DB:",e),I("Error searching vector DB: ".concat(e.message))}finally{j(!1)}},color:"primary",variant:"contained",disabled:w||"class"===E&&!v.trim()},"Search"))))};const re=Object(j.a)(e=>({paper:{padding:e.spacing(2)},marginBottom:{marginBottom:e.spacing(2)},resultImage:{maxWidth:"100%",maxHeight:"400px",objectFit:"contain"},dividerMargin:{margin:"".concat(e.spacing(2),"px 0")},chipContainer:{display:"flex",gap:e.spacing(1),flexWrap:"wrap"}}));var le=e=>{let{results:a}=e;const t=re();if(!a)return null;const{model:n,data:l}=a;if(l.error)return r.a.createElement(f.a,{sx:{p:2,bgcolor:"#ffebee"}},r.a.createElement(u.a,{color:"error"},l.error));const o=()=>l.performance?r.a.createElement(s.a,{className:"performance-info"},r.a.createElement(W.a,{className:t.dividerMargin}),r.a.createElement(u.a,{variant:"body2"},"Inference time: ",(e=>{if(void 0===e||null===e||isNaN(e))return"-";const a=Number(e);return a<1e3?"".concat(a.toFixed(2)," ms"):"".concat((a/1e3).toFixed(2)," s")})(l.performance.inference_time)," on ",l.performance.device)):null;return"yolo"===n||"detr"===n?r.a.createElement(f.a,{className:t.paper},r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"yolo"===n?"YOLOv8":"DETR"," Detection Results"),r.a.createElement(y.a,{container:!0,spacing:3},r.a.createElement(y.a,{item:!0,xs:12,md:6},l.image&&r.a.createElement(s.a,{className:t.marginBottom},r.a.createElement(u.a,{variant:"subtitle1",gutterBottom:!0},"Detection Result"),r.a.createElement("img",{src:"data:image/png;base64,".concat(l.image),alt:"Detection Result",className:t.resultImage}))),r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement(s.a,{className:t.marginBottom},r.a.createElement(u.a,{variant:"subtitle1",gutterBottom:!0},"Detected Objects:"),l.detections&&l.detections.length>0?r.a.createElement(M.a,null,l.detections.map((e,a)=>r.a.createElement(r.a.Fragment,{key:a},r.a.createElement(U.a,null,r.a.createElement(J.a,{primary:r.a.createElement(s.a,{style:{display:"flex",alignItems:"center"}},r.a.createElement(u.a,{variant:"body1",component:"span"},e.class),r.a.createElement(N.a,{label:"".concat((100*e.confidence).toFixed(0),"%"),size:"small",color:"primary",style:{marginLeft:8}})),secondary:"Bounding Box: [".concat(e.bbox.join(", "),"]")})),a<l.detections.length-1&&r.a.createElement(W.a,null)))):r.a.createElement(u.a,{variant:"body1"},"No objects detected")))),o(),r.a.createElement(ne,{results:a})):"vit"===n?r.a.createElement(f.a,{className:t.paper},r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"ViT Classification Results"),r.a.createElement(u.a,{variant:"subtitle1",gutterBottom:!0},"Top Predictions:"),l.top_predictions&&l.top_predictions.length>0?r.a.createElement(M.a,null,l.top_predictions.map((e,a)=>r.a.createElement(r.a.Fragment,{key:a},r.a.createElement(U.a,null,r.a.createElement(J.a,{primary:r.a.createElement(s.a,{style:{display:"flex",alignItems:"center"}},r.a.createElement(u.a,{variant:"body1",component:"span"},e.rank,". ",e.class),r.a.createElement(N.a,{label:"".concat((100*e.probability).toFixed(1),"%"),size:"small",color:0===a?"primary":"default",style:{marginLeft:8}}))})),a<l.top_predictions.length-1&&r.a.createElement(W.a,null)))):r.a.createElement(u.a,{variant:"body1"},"No classifications available"),o(),r.a.createElement(ne,{results:a})):null};const oe=Object(j.a)(e=>({paper:{padding:e.spacing(2),marginTop:e.spacing(2)},marginBottom:{marginBottom:e.spacing(2)},dividerMargin:{margin:"".concat(e.spacing(2),"px 0")},responseBox:{padding:e.spacing(2),backgroundColor:"#f5f5f5",borderRadius:e.shape.borderRadius,marginTop:e.spacing(2),whiteSpace:"pre-wrap"},buttonProgress:{marginLeft:e.spacing(1)}}));var ce=e=>{let{visionResults:a,model:t}=e;const l=oe(),[o,c]=Object(n.useState)(""),[i,m]=Object(n.useState)(!1),[d,p]=Object(n.useState)(null),[g,E]=Object(n.useState)(null);return a?r.a.createElement(f.a,{className:l.paper},r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"Ask AI about the ","vit"===t?"Classification":"Detection"," Results"),r.a.createElement(u.a,{variant:"body2",className:l.marginBottom},"Ask a question about the detected objects or classifications to get an AI-powered analysis."),r.a.createElement($.a,{fullWidth:!0,label:"Your question about the image",variant:"outlined",value:o,onChange:e=>c(e.target.value),disabled:i,className:l.marginBottom,placeholder:"vit"===t?"E.g., What category does this image belong to?":"E.g., How many people are in this image?"}),r.a.createElement(h.a,{variant:"contained",color:"primary",onClick:async()=>{if(o.trim()){m(!0),E(null);try{const e=await fetch("/api/analyze",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({visionResults:a,userQuery:o})});if(!e.ok)throw new Error("HTTP error! Status: ".concat(e.status));const t=await e.json();t.error?E(t.error):p(t)}catch(e){console.error("Error analyzing with LLM:",e),E("Error analyzing with LLM: ".concat(e.message))}finally{m(!1)}}},disabled:i||!o.trim()},"Analyze with AI",i&&r.a.createElement(b.a,{size:24,className:l.buttonProgress})),g&&r.a.createElement(s.a,{mt:2},r.a.createElement(u.a,{color:"error"},g)),d&&r.a.createElement(r.a.Fragment,null,r.a.createElement(W.a,{className:l.dividerMargin}),r.a.createElement(u.a,{variant:"subtitle1",gutterBottom:!0},"AI Analysis:"),r.a.createElement(s.a,{className:l.responseBox},r.a.createElement(u.a,{variant:"body1"},d.response)),d.performance&&r.a.createElement(s.a,{mt:1},r.a.createElement(u.a,{variant:"body2",color:"textSecondary"},"Analysis time: ",(e=>{if(void 0===e||null===e||isNaN(e))return"-";const a=Number(e);return a<1e3?"".concat(a.toFixed(2)," ms"):"".concat((a/1e3).toFixed(2)," s")})(d.performance.inference_time)," on ",d.performance.device)))):null};var ie=function(e){let{imageBase64:a}=e;const[t,l]=Object(n.useState)(""),[o,c]=Object(n.useState)(""),[i,s]=Object(n.useState)(""),[m,d]=Object(n.useState)(!1),[p,g]=Object(n.useState)(""),[E,b]=Object(n.useState)("image"),[v,x]=Object(n.useState)(""),[S,C]=Object(n.useState)(""),[w,j]=Object(n.useState)(5);return r.a.createElement(f.a,{style:{padding:16}},r.a.createElement(u.a,{variant:"h5",gutterBottom:!0},"Vision RAG (LangChain)"),r.a.createElement(u.a,{variant:"body2",color:"textSecondary",gutterBottom:!0},"If OPENAI_API_KEY is set on the server, API Key is optional. Select a search type and send a question to get answers based on context retrieved from the vector DB."),r.a.createElement(y.a,{container:!0,spacing:2},r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement(Q.a,{fullWidth:!0,variant:"outlined",size:"small"},r.a.createElement(K.a,{id:"search-type-label"},"Search Type"),r.a.createElement(X.a,{labelId:"search-type-label",value:E,onChange:e=>b(e.target.value),label:"Search Type"},r.a.createElement(Z.a,{value:"image"},"image (current upload)"),r.a.createElement(Z.a,{value:"object"},"object (objectId)"),r.a.createElement(Z.a,{value:"class"},"class (class_name)")))),r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement($.a,{label:"OpenAI API Key (optional)",value:t,onChange:e=>l(e.target.value),fullWidth:!0,variant:"outlined",size:"small",type:"password",placeholder:"sk-..."})),"object"===E&&r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement($.a,{label:"objectId",value:v,onChange:e=>x(e.target.value),fullWidth:!0,variant:"outlined",size:"small"})),"class"===E&&r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement($.a,{label:"class_name",value:S,onChange:e=>C(e.target.value),fullWidth:!0,variant:"outlined",size:"small",placeholder:"e.g. person, car, dog"})),r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement($.a,{label:"n_results",value:w,onChange:e=>j(e.target.value),fullWidth:!0,variant:"outlined",size:"small",type:"number",inputProps:{min:1,max:50}})),r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement($.a,{label:"User Question",value:o,onChange:e=>c(e.target.value),fullWidth:!0,multiline:!0,rows:4,variant:"outlined",placeholder:"image"===E?"Answer based on the uploaded image":"Answer using the retrieved object context"})),p&&r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement(u.a,{color:"error"},p)),r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement("div",{style:{display:"flex",gap:8}},r.a.createElement(h.a,{color:"primary",variant:"contained",onClick:async()=>{g(""),s("");const e=(o||"").trim();if(!e)return void g("Please enter a question.");const n={userQuery:e,searchType:E,n_results:Number(w)||5};if(t&&(n.api_key=t),"image"===E){if(!a)return void g("Image is required. Please upload an image first.");n.image=a}else if("object"===E){if(!v.trim())return void g("Please enter an objectId.");n.objectId=v.trim()}else if("class"===E){if(!S.trim())return void g("Please enter a class_name.");n.class_name=S.trim()}d(!0);try{const e=await fetch("/api/vision-rag/query",{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify(n)});if(!e.ok){let a=await e.text();try{a=JSON.stringify(JSON.parse(a),null,2)}catch(r){}throw new Error(a)}const a=await e.json(),t="Model: ".concat(a.model||"-"," | Latency: ").concat(a.latency_sec||"-","s");let l="";a.retrieved&&a.retrieved.length>0&&(l="\n\nSearch Results:\n",a.retrieved.forEach((e,a)=>{l+="".concat(a+1,". ID: ").concat(e.id||"-","\n"),e.meta&&(l+=" Class: ".concat(e.meta.class||"-","\n"),l+=" Confidence: ".concat(e.meta.confidence||"-","\n")),l+=" Similarity: ".concat(e.distance?e.distance.toFixed(4):"-","\n")})),s((a.answer||"(No response)")+l+"\n\n---\n"+t)}catch(l){g("Error: "+l.message)}finally{d(!1)}},disabled:m},m?"Sending...":"Send Question"),r.a.createElement(h.a,{variant:"outlined",onClick:()=>{c(""),s(""),g("")}},"Clear"))),r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement(W.a,{style:{margin:"12px 0"}}),r.a.createElement(u.a,{variant:"subtitle2",color:"textSecondary"},"Response"),r.a.createElement("pre",{style:{whiteSpace:"pre-wrap",fontFamily:"ui-monospace, monospace"}},i))))},se=(t(80),t(159)),me=t(160),de=t(162),ue=t(163),pe=t(164);const ge=Object(j.a)(e=>({root:{marginTop:e.spacing(3),marginBottom:e.spacing(3)},imageContainer:{position:"relative",minHeight:"360px",display:"flex",justifyContent:"center",alignItems:"center",border:"2px dashed #ccc",borderRadius:"8px",margin:e.spacing(1),padding:e.spacing(1),backgroundColor:"#fafafa",overflow:"hidden"},progressLog:{marginTop:e.spacing(2),height:"200px",overflowY:"auto",backgroundColor:"#f8f9fa",padding:e.spacing(1),borderRadius:"4px",fontFamily:"monospace",fontSize:"0.9rem"},logEntry:{margin:"4px 0",padding:"2px 5px",borderLeft:"3px solid #ccc"},logEntryAgent:{borderLeft:"3px solid #2196f3"},logEntrySystem:{borderLeft:"3px solid #4caf50"},logEntryError:{borderLeft:"3px solid #f44336"},logTime:{color:"#666",fontSize:"0.8rem",marginRight:e.spacing(1)},imagePreview:{width:"100%",height:"auto",maxHeight:"60vh",objectFit:"contain"},uploadIcon:{fontSize:"3rem",color:"#aaa"},uploadInput:{display:"none"},deleteButton:{position:"absolute",top:"8px",right:"8px",backgroundColor:"rgba(255, 255, 255, 0.8)","&:hover":{backgroundColor:"rgba(255, 255, 255, 0.9)"}},tabPanel:{padding:e.spacing(2)},resultCard:{marginTop:e.spacing(2),marginBottom:e.spacing(2)},comparisonTable:{width:"100%",borderCollapse:"collapse","& th, & td":{border:"1px solid #ddd",padding:"8px",textAlign:"left"},"& th":{backgroundColor:"#f2f2f2"},"& tr:nth-child(even)":{backgroundColor:"#f9f9f9"}},loadingContainer:{display:"flex",flexDirection:"column",alignItems:"center",padding:e.spacing(4)},highlight:{backgroundColor:"#e3f2fd",padding:e.spacing(1),borderRadius:"4px",fontWeight:"bold"}}));var Ee=()=>{const e=ge(),[a,t]=Object(n.useState)([null,null]),[l,o]=Object(n.useState)([null,null]),[c,i]=Object(n.useState)(!1),[m,d]=Object(n.useState)(null),[E,x]=Object(n.useState)(null),[S,C]=Object(n.useState)(0),[w,j]=Object(n.useState)([]),O=Object(n.useRef)(null),I=function(e){let a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"info";const t=new Date,n=t.toLocaleTimeString(),r={time:n,message:e,type:a};j(e=>[...e,r])};Object(n.useEffect)(()=>{O.current&&O.current.scrollIntoView({behavior:"smooth"})},[w]);const N=e=>{const a=window.localStorage.getItem("auth_user_id"),t=window.localStorage.getItem("auth_username"),n=a&&t?"?uid=".concat(encodeURIComponent(a),"&uname=").concat(encodeURIComponent(t)):"",r=new EventSource("/api/product/compare/stream/".concat(e).concat(n));return r.onmessage=e=>{try{const a=JSON.parse(e.data);console.log("React SSE received:",a),a.message?I(a.message,a.agent||"info"):a.status?I("Status: ".concat(a.status),"system"):a.final_result?(console.log("Final result received:",a.final_result),d(a.final_result),i(!1),r.close()):a.error&&(I("Error: ".concat(a.error),"error"),i(!1),r.close())}catch(a){console.error("SSE parsing error:",a),I("Event processing error: ".concat(a.message),"error")}},r.onerror=e=>{I("Server connection lost. Please try again in a moment.","error"),r.close(),i(!1)},r},T=async function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;if(a[0]||a[1]){i(!0),x(null),j([]),I("Starting product analysis...","system");try{const t=new FormData;a[0]&&(t.append("image1",a[0]),I("Product A image uploaded.","info")),a[1]&&(t.append("image2",a[1]),I("Product B image uploaded.","info"));const n=["info","compare","value","recommend"],r=e||n[S];t.append("analysisType",r),I("Analysis type: ".concat("info"===r?"Product Information":"compare"===r?"Performance Comparison":"value"===r?"Value Analysis":"Purchase Recommendation"),"system"),I("Initializing analysis session...","system");for(let[e,a]of t.entries())console.log("FormData:",e,a);const l=await fetch("/api/product/compare/start",{method:"POST",body:t,credentials:"include"});if(console.log("Response status:",l.status),console.log("Response headers:",l.headers),!l.ok){const e=await l.text();throw console.error("Error response:",e),new Error("HTTP error! Status: ".concat(l.status," - ").concat(e))}const o=(await l.json()).session_id;if(!o)throw new Error("Failed to receive session ID");I("Analysis session started. (Session ID: ".concat(o.substring(0,8),"...)"),"system"),I("Agents are collaborating to analyze products. Please wait a moment...","system");const c=N(o);return()=>{c.close()}}catch(t){console.error("\uc81c\ud488 \ubd84\uc11d \uc624\ub958:",t),I("Error occurred: ".concat(t.message),"error"),x("Error during analysis: ".concat(t.message)),i(!1)}}else x("Please upload at least one product image for analysis")};return r.a.createElement(f.a,{className:e.root},r.a.createElement(s.a,{p:3},r.a.createElement(u.a,{variant:"h5",gutterBottom:!0},"Product Comparison Analysis"),r.a.createElement(u.a,{variant:"body1",paragraph:!0},"Upload product images to receive detailed information and comparison analysis. You can analyze various products including cars, smartphones, laptops, and more."),r.a.createElement(y.a,{container:!0,spacing:3},[0,1].map(n=>r.a.createElement(y.a,{item:!0,xs:12,md:6,key:n},r.a.createElement(s.a,{className:e.imageContainer},l[n]?r.a.createElement(r.a.Fragment,null,r.a.createElement("img",{src:l[n],alt:"Product ".concat(n+1),className:e.imagePreview}),r.a.createElement(v.a,{className:e.deleteButton,onClick:()=>(e=>{const n=[...a],r=[...l];n[e]=null,r[e]=null,t(n),o(r),d(null)})(n)},r.a.createElement(se.a,null))):r.a.createElement(r.a.Fragment,null,r.a.createElement("input",{accept:"image/*",className:e.uploadInput,id:"upload-image-".concat(n),type:"file",onChange:e=>((e,n)=>{const r=e.target.files[0];if(r){const e=new FileReader;e.onload=e=>{const a=[...l];a[n]=e.target.result,o(a)},e.readAsDataURL(r);const c=[...a];c[n]=r,t(c),d(null),x(null)}})(e,n)}),r.a.createElement("label",{htmlFor:"upload-image-".concat(n)},r.a.createElement(s.a,{display:"flex",flexDirection:"column",alignItems:"center"},r.a.createElement(me.a,{className:e.uploadIcon}),r.a.createElement(u.a,{variant:"body2",style:{marginTop:"8px"}},"Upload ",0===n?"Product A":"Product B"," Image"))))))),r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement("input",{accept:"image/*",className:e.uploadInput,id:"upload-both-images",type:"file",multiple:!0,onChange:e=>{const n=Array.from(e.target.files||[]);if(!n.length)return;const r=[...a],c=[...l];n.slice(0,2).forEach((e,a)=>{const t=a;r[t]=e;const n=new FileReader;n.onload=e=>{c[t]=e.target.result,o([...c])},n.readAsDataURL(e)}),t(r),d(null),x(null)}}),r.a.createElement("label",{htmlFor:"upload-both-images"},r.a.createElement(h.a,{variant:"text",color:"default",component:"span"},"Or select two files at once"))),r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement(f.a,null,r.a.createElement(p.a,{value:S,onChange:(e,a)=>{C(a)},indicatorColor:"primary",textColor:"primary",centered:!0},r.a.createElement(g.a,{icon:r.a.createElement(de.a,null),label:"Product Info"}),r.a.createElement(g.a,{icon:r.a.createElement(ue.a,null),label:"Performance",disabled:!a[0]||!a[1]}),r.a.createElement(g.a,{icon:r.a.createElement(pe.a,null),label:"Value Analysis"}),r.a.createElement(g.a,{label:"Recommendations"})),r.a.createElement(s.a,{p:2,display:"flex",justifyContent:"center",gridGap:12},r.a.createElement(h.a,{variant:"contained",color:"primary",onClick:()=>T(null),disabled:c||!a[0]&&!a[1],startIcon:c?r.a.createElement(b.a,{size:24}):null},c?"Analyzing...":"Start Analysis"),r.a.createElement(h.a,{variant:"outlined",color:"secondary",onClick:()=>T("compare"),disabled:c||!a[0]||!a[1],startIcon:r.a.createElement(ue.a,null)},"Compare Products")),E&&r.a.createElement(s.a,{p:2,bgcolor:"#ffebee",borderRadius:"4px",mb:2},r.a.createElement(u.a,{color:"error"},E)))),r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement(f.a,null,r.a.createElement(s.a,{p:2},r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"Analysis Progress"),r.a.createElement(s.a,{className:e.progressLog},0===w.length?r.a.createElement(u.a,{variant:"body2",color:"textSecondary",style:{padding:"10px"}},"Progress details will appear here when analysis starts."):w.map((a,t)=>r.a.createElement(s.a,{key:t,className:"".concat(e.logEntry," ").concat("agent"===a.type?e.logEntryAgent:"system"===a.type?e.logEntrySystem:"error"===a.type?e.logEntryError:"")},r.a.createElement("span",{className:e.logTime},"[",a.time,"]"),a.message)),r.a.createElement("div",{ref:O}))))),r.a.createElement(y.a,{item:!0,xs:12},c?r.a.createElement(s.a,{className:e.loadingContainer},r.a.createElement(b.a,null),r.a.createElement(u.a,{variant:"h6",style:{marginTop:"16px"}},"Analyzing Products..."),r.a.createElement(u.a,{variant:"body2",color:"textSecondary"},"Product recognition, information retrieval, and comparison analysis in progress.")):(()=>{if(!m)return null;switch(S){case 0:return r.a.createElement(P.a,{className:e.resultCard},r.a.createElement(B.a,null,r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"Product Information"),r.a.createElement(W.a,{style:{margin:"8px 0 16px"}}),m.productInfo&&r.a.createElement("div",null,Object.entries(m.productInfo).map((e,a)=>{let[t,n]=e;return r.a.createElement("div",{key:t,style:{marginBottom:"24px"}},r.a.createElement(u.a,{variant:"subtitle1",gutterBottom:!0},r.a.createElement("strong",null,"Product ",a+1," (",t,")")),r.a.createElement(u.a,{variant:"body1"},r.a.createElement("strong",null,"Type:")," ",n.product_type||"Unknown"),n.key_features&&n.key_features.length>0&&r.a.createElement("div",{style:{marginTop:"12px"}},r.a.createElement(u.a,{variant:"subtitle2"},"Key Features:"),r.a.createElement("ul",null,n.key_features.map((e,a)=>r.a.createElement("li",{key:a},r.a.createElement(u.a,{variant:"body2"},e))))),m.specifications&&m.specifications[t]&&r.a.createElement("div",{style:{marginTop:"12px"}},r.a.createElement(u.a,{variant:"subtitle2"},"Specifications:"),r.a.createElement("ul",null,Object.entries(m.specifications[t].specifications||{}).map(e=>{let[a,t]=e;return r.a.createElement("li",{key:a},r.a.createElement(u.a,{variant:"body2"},r.a.createElement("strong",null,a.replace("_"," "),":")," ",Array.isArray(t)?t.join(", "):t))}))))}))));case 1:return r.a.createElement(P.a,{className:e.resultCard},r.a.createElement(B.a,null,r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"Product Comparison Analysis"),r.a.createElement(W.a,{style:{margin:"8px 0 16px"}}),m.comparison&&r.a.createElement("div",null,r.a.createElement(u.a,{variant:"body1",style:{whiteSpace:"pre-line",marginBottom:"16px"}},"string"===typeof m.comparison?m.comparison:JSON.stringify(m.comparison,null,2)))));case 2:return r.a.createElement(P.a,{className:e.resultCard},r.a.createElement(B.a,null,r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"Price-to-Value Analysis"),r.a.createElement(W.a,{style:{margin:"8px 0 16px"}}),m.valueAnalysis&&r.a.createElement("div",null,r.a.createElement(u.a,{variant:"body1",style:{whiteSpace:"pre-line",marginBottom:"16px"}},"string"===typeof m.valueAnalysis?m.valueAnalysis:JSON.stringify(m.valueAnalysis,null,2)))));case 3:return r.a.createElement(P.a,{className:e.resultCard},r.a.createElement(B.a,null,r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"Purchase Recommendations"),r.a.createElement(W.a,{style:{margin:"8px 0 16px"}}),m.recommendation&&r.a.createElement("div",null,r.a.createElement(u.a,{variant:"body1",style:{whiteSpace:"pre-line",marginBottom:"16px"}},"string"===typeof m.recommendation?m.recommendation:JSON.stringify(m.recommendation,null,2))),!m.recommendation&&!m.valueAnalysis&&!m.comparison&&!m.productInfo&&r.a.createElement("div",null,r.a.createElement(u.a,{variant:"body1",style:{whiteSpace:"pre-line",marginBottom:"16px"}},JSON.stringify(m,null,2)))));default:return null}})()))))};var ye=()=>{var e,a,t,l;const[o,c]=Object(n.useState)("Describe the image concisely."),[i,m]=Object(n.useState)(null),[d,p]=Object(n.useState)("gguf:tinyllama-q4km"),[g,E]=Object(n.useState)(""),[v,x]=Object(n.useState)(null),[S,C]=Object(n.useState)(!1),[w,j]=Object(n.useState)([]),O=Object(n.useRef)(null);Object(n.useEffect)(()=>{O.current&&O.current.scrollIntoView({behavior:"smooth"})},[w]);const I=function(e){let a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"info";const t=(new Date).toLocaleTimeString();j(n=>[...n,{time:t,message:e,type:a}])},P=e=>{const a=window.localStorage.getItem("auth_user_id"),t=window.localStorage.getItem("auth_username"),n=a&&t?"?uid=".concat(encodeURIComponent(a),"&uname=").concat(encodeURIComponent(t)):"",r=new EventSource("/api/llama/compare/stream/".concat(e).concat(n));r.onmessage=e=>{try{const a=JSON.parse(e.data);a.message&&I(a.message,a.type||"info"),a.status&&I("Status: ".concat(a.status),"system"),a.final_result&&(x(a.final_result),C(!1),r.close()),a.error&&(I("Error: ".concat(a.error),"error"),C(!1),r.close())}catch(a){I("SSE parse error: ".concat(a.message),"error")}},r.onerror=()=>{I("SSE connection error.","error"),C(!1),r.close()}};return r.a.createElement(f.a,{style:{padding:16}},r.a.createElement(u.a,{variant:"h5",gutterBottom:!0},"LLM LoRA Compare (Base vs Fine-tuned)"),r.a.createElement(u.a,{variant:"body2",color:"textSecondary",gutterBottom:!0},"Compare outputs of a base LLaMA model and a LoRA fine-tuned adapter on the same prompt/image."),r.a.createElement(y.a,{container:!0,spacing:2},r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement($.a,{fullWidth:!0,label:"Prompt",value:o,onChange:e=>c(e.target.value),multiline:!0,rows:4,variant:"outlined"})),r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement(s.a,{display:"flex",flexDirection:"column",gridGap:12},r.a.createElement($.a,{label:"Base model id",value:d,onChange:e=>p(e.target.value),variant:"outlined",fullWidth:!0}),r.a.createElement($.a,{label:"LoRA path/ID (optional)",value:g,onChange:e=>E(e.target.value),variant:"outlined",fullWidth:!0}),r.a.createElement("input",{type:"file",accept:"image/*",onChange:e=>{var a;return m((null===(a=e.target.files)||void 0===a?void 0:a[0])||null)}}),r.a.createElement(h.a,{color:"primary",variant:"contained",onClick:async()=>{if(!o&&!i)return void I("Provide a prompt or upload an image.","error");C(!0),x(null),j([]);const e=new FormData;e.append("prompt",o),e.append("baseModel",d),g&&e.append("loraPath",g),i&&e.append("image",i);try{const a=await fetch("/api/llama/compare/start",{method:"POST",body:e,credentials:"include"});if(!a.ok)throw new Error("HTTP ".concat(a.status));const t=(await a.json()).session_id;I("Session started: ".concat(t.slice(0,8),"..."),"system"),P(t)}catch(a){I("Failed to start: ".concat(a.message),"error"),C(!1)}},disabled:S},S?r.a.createElement(b.a,{size:22}):"Run Comparison"))),r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement(W.a,{style:{margin:"8px 0 12px"}})),r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement(u.a,{variant:"h6"},"Logs"),r.a.createElement(s.a,{style:{height:200,overflow:"auto",background:"#f7f7f7",padding:8,borderRadius:4}},0===w.length?r.a.createElement(u.a,{variant:"body2",color:"textSecondary"},"Logs will appear here."):w.map((e,a)=>r.a.createElement(s.a,{key:a,style:{fontFamily:"monospace",fontSize:12,marginBottom:4}},r.a.createElement("span",{style:{color:"#666"}},"[",e.time,"]")," ",e.message)),r.a.createElement("div",{ref:O}))),r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement(u.a,{variant:"h6"},"Results"),v?r.a.createElement(s.a,null,r.a.createElement(u.a,{variant:"subtitle2"},"Prompt"),r.a.createElement(s.a,{style:{whiteSpace:"pre-wrap",marginBottom:8}},v.prompt),r.a.createElement(u.a,{variant:"subtitle2"},"Base Output"),r.a.createElement(s.a,{style:{whiteSpace:"pre-wrap",marginBottom:8}},(null===(e=v.base)||void 0===e?void 0:e.output)||"-"),r.a.createElement(u.a,{variant:"subtitle2"},"LoRA Output"),r.a.createElement(s.a,{style:{whiteSpace:"pre-wrap",marginBottom:8}},(null===(a=v.lora)||void 0===a?void 0:a.output)||"-"),r.a.createElement(u.a,{variant:"subtitle2"},"Latency"),r.a.createElement(s.a,null,"base: ".concat((null===(t=v.base)||void 0===t?void 0:t.latency_ms)||0," ms | lora: ").concat((null===(l=v.lora)||void 0===l?void 0:l.latency_ms)||0," ms"))):r.a.createElement(u.a,{variant:"body2",color:"textSecondary"},"Run a comparison to see outputs here."))),r.a.createElement(s.a,{marginTop:3},r.a.createElement(W.a,null),r.a.createElement(s.a,{marginTop:2},r.a.createElement(u.a,{variant:"subtitle1"},"How to fine-tune with LoRA (PEFT)"),r.a.createElement(u.a,{variant:"body2",color:"textSecondary"},"Use a small image+text dataset. Train with TRL/PEFT (LoRA/QLoRA). Upload your adapter and set the LoRA path above to compare."))))};t(104);const fe=Object(c.a)({palette:{primary:{main:"#3f51b5"},secondary:{main:"#f50057"}},typography:{fontFamily:"Roboto, Arial, sans-serif"}});var be=function(){const[e,a]=Object(n.useState)(null),[t,l]=Object(n.useState)(""),[o,c]=Object(n.useState)(""),[h,v]=Object(n.useState)(!1),[x,S]=Object(n.useState)(null),[C,w]=Object(n.useState)(null),[j,O]=Object(n.useState)({yolo:!1,detr:!1,vit:!1}),[P,B]=Object(n.useState)(0);return Object(n.useEffect)(()=>{fetch("/api/status").then(e=>e.json()).then(e=>{O(e.models)}).catch(e=>{console.error("Error checking API status:",e),w("Error connecting to the backend API. Please make sure the server is running.")})},[]),r.a.createElement(i.a,{theme:fe},r.a.createElement(s.a,{style:{flexGrow:1}},r.a.createElement(m.a,{position:"static"},r.a.createElement(d.a,null,r.a.createElement(u.a,{variant:"h6",style:{flexGrow:1}},"Vision LLM Multi-Agent System")),r.a.createElement(p.a,{value:P,onChange:(e,a)=>B(a),indicatorColor:"secondary",textColor:"inherit",centered:!0},r.a.createElement(g.a,{label:"Object Detection"}),r.a.createElement(g.a,{label:"Product Comparison"}),r.a.createElement(g.a,{label:"LLM LoRA Compare"}))),r.a.createElement(E.a,{maxWidth:"lg",style:{marginTop:fe.spacing(4),marginBottom:fe.spacing(4)}},0===P&&r.a.createElement(y.a,{container:!0,spacing:3},r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement(f.a,{style:{padding:fe.spacing(2)}},r.a.createElement(u.a,{variant:"h5",gutterBottom:!0},"Upload an image to see how each model performs!"),r.a.createElement(u.a,{variant:"body1",paragraph:!0},"This demo showcases three different object detection and image classification models:"),r.a.createElement(u.a,{variant:"body1",component:"div"},r.a.createElement("ul",null,r.a.createElement("li",null,r.a.createElement("strong",null,"YOLOv8"),": Fast and accurate object detection"),r.a.createElement("li",null,r.a.createElement("strong",null,"DETR"),": DEtection TRansformer for object detection"),r.a.createElement("li",null,r.a.createElement("strong",null,"ViT"),": Vision Transformer for image classification"))))),r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement(I,{onImageUpload:e=>{if(a(e),S(null),w(null),e instanceof File){const a=new FileReader;a.onload=()=>{const e=a.result;l("string"===typeof e?e:"")},a.onerror=()=>l(""),a.readAsDataURL(e)}else l("")}})),r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement(z,{onModelSelect:e=>{c(e),S(null),w(null)},onProcess:async()=>{if(!e||!o)return void w("Please select both an image and a model");v(!0),w(null);const a=new FormData;a.append("image",e);let t="";switch(o){case"yolo":t="/api/detect/yolo";break;case"detr":t="/api/detect/detr";break;case"vit":t="/api/classify/vit";break;default:return w("Invalid model selection"),void v(!1)}try{const e=await fetch(t,{method:"POST",body:a});if(!e.ok)throw new Error("HTTP error! Status: ".concat(e.status));const n=await e.json();S({model:o,data:n})}catch(n){console.error("Error processing image:",n),w("Error processing image: ".concat(n.message))}finally{v(!1)}},isProcessing:h,modelsStatus:j,selectedModel:o,imageSelected:!!e})),C&&r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement(f.a,{style:{padding:fe.spacing(2),backgroundColor:"#ffebee"}},r.a.createElement(u.a,{color:"error"},C))),h&&r.a.createElement(y.a,{item:!0,xs:12,style:{textAlign:"center",margin:"".concat(fe.spacing(4),"px 0")}},r.a.createElement(b.a,null),r.a.createElement(u.a,{variant:"h6",style:{marginTop:fe.spacing(2)}},"Processing image...")),x&&r.a.createElement(r.a.Fragment,null,r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement(le,{results:x})),r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement(ce,{visionResults:x.data,model:x.model}))),r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement(ie,{imageBase64:t}))),1===P&&r.a.createElement(Ee,null),2===P&&r.a.createElement(ye,null))))};var he=e=>{e&&e instanceof Function&&t.e(3).then(t.bind(null,181)).then(a=>{let{getCLS:t,getFID:n,getFCP:r,getLCP:l,getTTFB:o}=a;t(e),n(e),r(e),l(e),o(e)})};o.a.render(r.a.createElement(r.a.StrictMode,null,r.a.createElement(be,null)),document.getElementById("root")),he()},94:function(e,a,t){e.exports=t(105)},99:function(e,a,t){}},[[94,1,2]]]);
2
- //# sourceMappingURL=main.2c1002fc.chunk.js.map
 
1
+ (this["webpackJsonpvision-web-app"]=this["webpackJsonpvision-web-app"]||[]).push([[0],{104:function(e,a,t){},105:function(e,a,t){"use strict";t.r(a);var n=t(0),r=t.n(n),l=t(11),o=t.n(l),c=(t(99),t(79)),i=t(165),s=t(169),m=t(166),d=t(167),u=t(49),p=t(171),g=t(161),E=t(168),y=t(142),f=t(83),b=t(147),h=t(140),v=t(141),x=t(65),S=t.n(x),C=t(76),w=t.n(C),j=t(137);const O=Object(j.a)(e=>({paper:{padding:e.spacing(2),display:"flex",flexDirection:"column",alignItems:"center",height:"100%",minHeight:300,transition:"all 0.3s ease"},dragActive:{border:"2px dashed #3f51b5",backgroundColor:"rgba(63, 81, 181, 0.05)"},dragInactive:{border:"2px dashed #ccc",backgroundColor:"white"},uploadBox:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",height:"100%",width:"100%",cursor:"pointer"},uploadIcon:{fontSize:60,color:"#3f51b5",marginBottom:e.spacing(2)},supportText:{marginTop:e.spacing(2)},previewBox:{display:"flex",flexDirection:"column",alignItems:"center",width:"100%",height:"100%",position:"relative"},imageContainer:{position:"relative",width:"100%",height:"45vh",[e.breakpoints.down("sm")]:{height:"35vh"},display:"flex",justifyContent:"center",alignItems:"center",overflow:"hidden",marginTop:e.spacing(2)},deleteButton:{position:"absolute",top:0,right:0,backgroundColor:"rgba(255, 255, 255, 0.7)","&:hover":{backgroundColor:"rgba(255, 255, 255, 0.9)"}}}));var I=e=>{let{onImageUpload:a}=e;const t=O(),[l,o]=Object(n.useState)(null),[c,i]=Object(n.useState)(!1),m=Object(n.useRef)(null),d=e=>{e.preventDefault(),e.stopPropagation(),"dragenter"===e.type||"dragover"===e.type?i(!0):"dragleave"===e.type&&i(!1)},p=e=>{e.type.startsWith("image/")?(o(URL.createObjectURL(e)),a(e)):alert("Please upload an image file")};return r.a.createElement(f.a,{className:"".concat(t.paper," ").concat(c?t.dragActive:t.dragInactive),onDragEnter:d,onDragLeave:d,onDragOver:d,onDrop:e=>{e.preventDefault(),e.stopPropagation(),i(!1),e.dataTransfer.files&&e.dataTransfer.files[0]&&p(e.dataTransfer.files[0])}},r.a.createElement("input",{ref:m,type:"file",accept:"image/*",onChange:e=>{e.preventDefault(),e.target.files&&e.target.files[0]&&p(e.target.files[0])},style:{display:"none"}}),l?r.a.createElement(s.a,{className:t.previewBox},r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"Preview"),r.a.createElement(s.a,{className:t.imageContainer},r.a.createElement("img",{src:l,alt:"Preview",className:"preview-image",style:{maxWidth:"100%",maxHeight:"100%",width:"auto",height:"auto",objectFit:"contain",display:"block"}}),r.a.createElement(v.a,{"aria-label":"delete",className:t.deleteButton,onClick:()=>{o(null),a(null),m.current.value=""}},r.a.createElement(w.a,null)))):r.a.createElement(s.a,{className:t.uploadBox,onClick:()=>{m.current.click()}},r.a.createElement(S.a,{className:t.uploadIcon}),r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"Drag & Drop an image here"),r.a.createElement(u.a,{variant:"body2",color:"textSecondary",gutterBottom:!0},"or"),r.a.createElement(h.a,{variant:"contained",color:"primary",component:"span",startIcon:r.a.createElement(S.a,null)},"Browse Files"),r.a.createElement(u.a,{variant:"body2",color:"textSecondary",className:t.supportText},"Supported formats: JPG, PNG, GIF")))},B=t(143),N=t(144),P=t(176),T=t(145),A=t(66),k=t.n(A),R=t(77),D=t.n(R),F=t(78),L=t.n(F);const _=Object(j.a)(e=>({card:{height:"100%",display:"flex",flexDirection:"column"},selectedCard:{border:"2px solid #3f51b5"},unavailableCard:{opacity:.6},cardContent:{flexGrow:1},chipContainer:{marginBottom:e.spacing(1.5)},successChip:{backgroundColor:"#34C759",color:"#fff"},errorChip:{backgroundColor:"#FF3B3F",color:"#fff"},modelType:{marginTop:e.spacing(1)},processButton:{marginTop:e.spacing(3),textAlign:"center"}}));var z=e=>{let{onModelSelect:a,onProcess:t,isProcessing:n,modelsStatus:l,selectedModel:o,imageSelected:c}=e;const i=_(),m=[{id:"yolo",name:"YOLOv8",description:"Fast and accurate object detection",icon:r.a.createElement(k.a,null),available:l.yolo},{id:"detr",name:"DETR",description:"DEtection TRansformer for object detection",icon:r.a.createElement(k.a,null),available:l.detr},{id:"vit",name:"ViT",description:"Vision Transformer for image classification",icon:r.a.createElement(D.a,null),available:l.vit}],d=e=>{m.find(a=>a.id===e).available&&a(e)};return r.a.createElement(s.a,{sx:{p:2,height:"100%"}},r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"Select Model"),r.a.createElement(y.a,{container:!0,spacing:2},m.map(e=>r.a.createElement(y.a,{item:!0,xs:12,sm:4,key:e.id},r.a.createElement(B.a,{className:"\n ".concat(i.card," \n ").concat(o===e.id?i.selectedCard:""," \n ").concat(e.available?"":i.unavailableCard,"\n "),onClick:()=>d(e.id)},r.a.createElement(N.a,{className:i.cardContent},r.a.createElement(s.a,{sx:{mb:2,color:"primary"}},e.icon),r.a.createElement(u.a,{variant:"h5",component:"div",gutterBottom:!0},e.name),r.a.createElement("div",{className:i.chipContainer},e.available?r.a.createElement(P.a,{label:"Available",className:i.successChip,size:"small"}):r.a.createElement(P.a,{label:"Not Available",className:i.errorChip,size:"small"})),r.a.createElement(u.a,{variant:"body2",color:"textSecondary"},e.description)),r.a.createElement(T.a,null,r.a.createElement(h.a,{size:"small",onClick:()=>d(e.id),disabled:!e.available,color:o===e.id?"primary":"default",variant:o===e.id?"contained":"outlined",fullWidth:!0},o===e.id?"Selected":"Select")))))),r.a.createElement("div",{className:i.processButton},r.a.createElement(h.a,{variant:"contained",color:"primary",size:"large",startIcon:r.a.createElement(L.a,null),onClick:t,disabled:!o||!c||n},n?"Processing...":"Process Image")))},W=t(157),M=t(154),U=t(107),J=t(158),H=t(146),V=t(174),G=t(175),Y=t(149),q=t(150),K=t(151),Q=t(177),X=t(170),Z=t(155),$=t(179),ee=t(156),ae=t(173);const te=Object(j.a)(e=>({root:{marginTop:e.spacing(2),marginBottom:e.spacing(2),padding:e.spacing(2),backgroundColor:"#f5f5f5",borderRadius:e.shape.borderRadius},button:{marginRight:e.spacing(2)},searchDialog:{minWidth:"500px"},formControl:{marginBottom:e.spacing(2),minWidth:"100%"},searchResults:{marginTop:e.spacing(2)},resultCard:{marginBottom:e.spacing(2)},resultImage:{height:140,objectFit:"contain"},chip:{margin:e.spacing(.5)},similarityChip:{backgroundColor:e.palette.primary.main,color:"white"}}));var ne=e=>{let{results:a}=e;const t=te(),[l,o]=Object(n.useState)(!1),[c,i]=Object(n.useState)(!1),[m,d]=Object(n.useState)(null),[p,g]=Object(n.useState)(!1),[E,f]=Object(n.useState)("image"),[v,x]=Object(n.useState)(""),[S,C]=Object(n.useState)([]),[w,j]=Object(n.useState)(!1),[O,I]=Object(n.useState)(null),{model:T,data:A}=a,k=()=>{g(!1)},R=()=>"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(function(e){const a=16*Math.random()|0;return("x"===e?a:3&a|8).toString(16)}));return r.a.createElement(s.a,{className:t.root},r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"Vector Database Actions"),r.a.createElement(s.a,{display:"flex",alignItems:"center",mb:2},r.a.createElement(h.a,{variant:"contained",color:"primary",onClick:async()=>{o(!0),d(null);try{let e;if(e="vit"===T?await fetch("/api/add-to-collection",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({image:A.image,metadata:{model:"vit",classifications:A.classifications}})}):await fetch("/api/add-detected-objects",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({image:A.image,objects:A.detections,imageId:R()})}),!e.ok)throw new Error("HTTP error! Status: ".concat(e.status));const a=await e.json();if(a.error)throw new Error(a.error);i(!0),setTimeout(()=>i(!1),5e3)}catch(e){console.error("Error saving to vector DB:",e),d("Error saving to vector DB: ".concat(e.message))}finally{o(!1)}},disabled:l,className:t.button},l?r.a.createElement(r.a.Fragment,null,r.a.createElement(b.a,{size:20,color:"inherit",style:{marginRight:8}}),"Saving..."):"Save to Vector DB"),r.a.createElement(h.a,{variant:"outlined",color:"primary",onClick:()=>{g(!0),C([]),I(null)},className:t.button},"Search Similar")),m&&r.a.createElement(ae.a,{severity:"error",style:{marginTop:8}},m),r.a.createElement(V.a,{open:c,autoHideDuration:5e3,onClose:()=>i(!1)},r.a.createElement(ae.a,{severity:"success"},"vit"===T?"Image and classifications successfully saved to vector DB!":"Detected objects successfully saved to vector DB!")),r.a.createElement(G.a,{open:p,onClose:k,maxWidth:"md",fullWidth:!0},r.a.createElement(Y.a,null,"Search Vector Database"),r.a.createElement(q.a,null,r.a.createElement(K.a,{className:t.formControl},r.a.createElement(Q.a,{id:"search-type-label"},"Search Type"),r.a.createElement(X.a,{labelId:"search-type-label",id:"search-type",value:E,onChange:e=>{f(e.target.value),C([]),I(null)}},r.a.createElement(Z.a,{value:"image"},"Search by Current Image"),r.a.createElement(Z.a,{value:"class"},"Search by Class Name"))),"class"===E&&r.a.createElement(K.a,{className:t.formControl},r.a.createElement($.a,{label:"Class Name",value:v,onChange:e=>{x(e.target.value)},placeholder:"e.g. person, car, dog...",fullWidth:!0})),O&&r.a.createElement(ae.a,{severity:"error",style:{marginBottom:16}},O),r.a.createElement(s.a,{className:t.searchResults},w?r.a.createElement(s.a,{display:"flex",justifyContent:"center",alignItems:"center",p:4},r.a.createElement(b.a,null),r.a.createElement(u.a,{variant:"body1",style:{marginLeft:16}},"Searching...")):r.a.createElement(r.a.Fragment,null,console.log("Search dialog render - searchResults:",S),S.length>0?(console.log("Rendering search results:",S),console.log("Search results length:",S.length),0===S.length?(console.log("No results to render"),r.a.createElement(u.a,{variant:"body1"},"No results found.")):r.a.createElement(y.a,{container:!0,spacing:2},S.map((e,a)=>{const n=100*(1-e.distance);return r.a.createElement(y.a,{item:!0,xs:12,sm:6,key:a},r.a.createElement(B.a,{className:t.resultCard},e.metadata&&e.metadata.image_data?r.a.createElement(H.a,{className:t.resultImage,component:"img",height:"200",image:"data:image/jpeg;base64,".concat(e.metadata.image_data),alt:e.metadata&&e.metadata.class?e.metadata.class:"Object"}):r.a.createElement(s.a,{className:t.resultImage,style:{backgroundColor:"#f0f0f0",display:"flex",alignItems:"center",justifyContent:"center",height:200}},r.a.createElement(u.a,{variant:"body2",color:"textSecondary"},e.metadata&&e.metadata.class?e.metadata.class:"Object"," Image")),r.a.createElement(N.a,null,r.a.createElement(s.a,{display:"flex",justifyContent:"space-between",alignItems:"center",mb:1},r.a.createElement(u.a,{variant:"subtitle1"},"Result #",a+1),r.a.createElement(P.a,{label:"Similarity: ".concat(n.toFixed(2),"%"),className:t.similarityChip,size:"small"})),r.a.createElement(u.a,{variant:"body2",color:"textSecondary"},r.a.createElement("strong",null,"Class:")," ",e.metadata.class||"N/A"),e.metadata.confidence&&r.a.createElement(u.a,{variant:"body2",color:"textSecondary"},r.a.createElement("strong",null,"Confidence:")," ",(100*e.metadata.confidence).toFixed(2),"%"),r.a.createElement(u.a,{variant:"body2",color:"textSecondary"},r.a.createElement("strong",null,"Object ID:")," ",e.id))))}))):r.a.createElement(u.a,{variant:"body1"},"No results found. Please try another search.")))),r.a.createElement(ee.a,null,r.a.createElement(h.a,{onClick:k,color:"default"},"Close"),r.a.createElement(h.a,{onClick:async()=>{j(!0),I(null);try{let e={};if("image"===E)e={searchType:"image",image:A.image,n_results:5};else{if(!v.trim())throw new Error("Please enter a class name");e={searchType:"class",class_name:v.trim(),n_results:5}}const a=await fetch("/api/search-similar-objects",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!a.ok)throw new Error("HTTP error! Status: ".concat(a.status));const t=await a.json();if(t.error)throw new Error(t.error);if(console.log("Search API response:",t),!t.success||!Array.isArray(t.results))throw console.error("Unexpected API response format:",t),new Error("Unexpected API response format");console.log("Setting search results array:",t.results),console.log("Results array length:",t.results.length),console.log("First result item:",t.results[0]),C(t.results)}catch(e){console.error("Error searching vector DB:",e),I("Error searching vector DB: ".concat(e.message))}finally{j(!1)}},color:"primary",variant:"contained",disabled:w||"class"===E&&!v.trim()},"Search"))))};const re=Object(j.a)(e=>({paper:{padding:e.spacing(2)},marginBottom:{marginBottom:e.spacing(2)},resultImage:{maxWidth:"100%",maxHeight:"400px",objectFit:"contain"},dividerMargin:{margin:"".concat(e.spacing(2),"px 0")},chipContainer:{display:"flex",gap:e.spacing(1),flexWrap:"wrap"}}));var le=e=>{let{results:a}=e;const t=re();if(!a)return null;const{model:n,data:l}=a;if(l.error)return r.a.createElement(f.a,{sx:{p:2,bgcolor:"#ffebee"}},r.a.createElement(u.a,{color:"error"},l.error));const o=()=>l.performance?r.a.createElement(s.a,{className:"performance-info"},r.a.createElement(W.a,{className:t.dividerMargin}),r.a.createElement(u.a,{variant:"body2"},"Inference time: ",(e=>{if(void 0===e||null===e||isNaN(e))return"-";const a=Number(e);return a<1e3?"".concat(a.toFixed(2)," ms"):"".concat((a/1e3).toFixed(2)," s")})(l.performance.inference_time)," on ",l.performance.device)):null;return"yolo"===n||"detr"===n?r.a.createElement(f.a,{className:t.paper},r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"yolo"===n?"YOLOv8":"DETR"," Detection Results"),r.a.createElement(y.a,{container:!0,spacing:3},r.a.createElement(y.a,{item:!0,xs:12,md:6},l.image&&r.a.createElement(s.a,{className:t.marginBottom},r.a.createElement(u.a,{variant:"subtitle1",gutterBottom:!0},"Detection Result"),r.a.createElement("img",{src:"data:image/png;base64,".concat(l.image),alt:"Detection Result",className:t.resultImage}))),r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement(s.a,{className:t.marginBottom},r.a.createElement(u.a,{variant:"subtitle1",gutterBottom:!0},"Detected Objects:"),l.detections&&l.detections.length>0?r.a.createElement(M.a,null,l.detections.map((e,a)=>r.a.createElement(r.a.Fragment,{key:a},r.a.createElement(U.a,null,r.a.createElement(J.a,{primary:r.a.createElement(s.a,{style:{display:"flex",alignItems:"center"}},r.a.createElement(u.a,{variant:"body1",component:"span"},e.class),r.a.createElement(P.a,{label:"".concat((100*e.confidence).toFixed(0),"%"),size:"small",color:"primary",style:{marginLeft:8}})),secondary:"Bounding Box: [".concat(e.bbox.join(", "),"]")})),a<l.detections.length-1&&r.a.createElement(W.a,null)))):r.a.createElement(u.a,{variant:"body1"},"No objects detected")))),o(),r.a.createElement(ne,{results:a})):"vit"===n?r.a.createElement(f.a,{className:t.paper},r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"ViT Classification Results"),r.a.createElement(u.a,{variant:"subtitle1",gutterBottom:!0},"Top Predictions:"),l.top_predictions&&l.top_predictions.length>0?r.a.createElement(M.a,null,l.top_predictions.map((e,a)=>r.a.createElement(r.a.Fragment,{key:a},r.a.createElement(U.a,null,r.a.createElement(J.a,{primary:r.a.createElement(s.a,{style:{display:"flex",alignItems:"center"}},r.a.createElement(u.a,{variant:"body1",component:"span"},e.rank,". ",e.class),r.a.createElement(P.a,{label:"".concat((100*e.probability).toFixed(1),"%"),size:"small",color:0===a?"primary":"default",style:{marginLeft:8}}))})),a<l.top_predictions.length-1&&r.a.createElement(W.a,null)))):r.a.createElement(u.a,{variant:"body1"},"No classifications available"),o(),r.a.createElement(ne,{results:a})):null};const oe=Object(j.a)(e=>({paper:{padding:e.spacing(2),marginTop:e.spacing(2)},marginBottom:{marginBottom:e.spacing(2)},dividerMargin:{margin:"".concat(e.spacing(2),"px 0")},responseBox:{padding:e.spacing(2),backgroundColor:"#f5f5f5",borderRadius:e.shape.borderRadius,marginTop:e.spacing(2),whiteSpace:"pre-wrap"},buttonProgress:{marginLeft:e.spacing(1)}}));var ce=e=>{let{visionResults:a,model:t}=e;const l=oe(),[o,c]=Object(n.useState)(""),[i,m]=Object(n.useState)(!1),[d,p]=Object(n.useState)(null),[g,E]=Object(n.useState)(null);return a?r.a.createElement(f.a,{className:l.paper},r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"Ask AI about the ","vit"===t?"Classification":"Detection"," Results"),r.a.createElement(u.a,{variant:"body2",className:l.marginBottom},"Ask a question about the detected objects or classifications to get an AI-powered analysis."),r.a.createElement($.a,{fullWidth:!0,label:"Your question about the image",variant:"outlined",value:o,onChange:e=>c(e.target.value),disabled:i,className:l.marginBottom,placeholder:"vit"===t?"E.g., What category does this image belong to?":"E.g., How many people are in this image?"}),r.a.createElement(h.a,{variant:"contained",color:"primary",onClick:async()=>{if(o.trim()){m(!0),E(null);try{const e=await fetch("/api/analyze",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({visionResults:a,userQuery:o})});if(!e.ok)throw new Error("HTTP error! Status: ".concat(e.status));const t=await e.json();t.error?E(t.error):p(t)}catch(e){console.error("Error analyzing with LLM:",e),E("Error analyzing with LLM: ".concat(e.message))}finally{m(!1)}}},disabled:i||!o.trim()},"Analyze with AI",i&&r.a.createElement(b.a,{size:24,className:l.buttonProgress})),g&&r.a.createElement(s.a,{mt:2},r.a.createElement(u.a,{color:"error"},g)),d&&r.a.createElement(r.a.Fragment,null,r.a.createElement(W.a,{className:l.dividerMargin}),r.a.createElement(u.a,{variant:"subtitle1",gutterBottom:!0},"AI Analysis:"),r.a.createElement(s.a,{className:l.responseBox},r.a.createElement(u.a,{variant:"body1"},d.response)),d.performance&&r.a.createElement(s.a,{mt:1},r.a.createElement(u.a,{variant:"body2",color:"textSecondary"},"Analysis time: ",(e=>{if(void 0===e||null===e||isNaN(e))return"-";const a=Number(e);return a<1e3?"".concat(a.toFixed(2)," ms"):"".concat((a/1e3).toFixed(2)," s")})(d.performance.inference_time)," on ",d.performance.device)))):null};var ie=function(e){let{imageBase64:a}=e;const[t,l]=Object(n.useState)(""),[o,c]=Object(n.useState)(""),[i,s]=Object(n.useState)(""),[m,d]=Object(n.useState)(!1),[p,g]=Object(n.useState)(""),[E,b]=Object(n.useState)("image"),[v,x]=Object(n.useState)(""),[S,C]=Object(n.useState)(""),[w,j]=Object(n.useState)(5);return r.a.createElement(f.a,{style:{padding:16}},r.a.createElement(u.a,{variant:"h5",gutterBottom:!0},"Vision RAG (LangChain)"),r.a.createElement(u.a,{variant:"body2",color:"textSecondary",gutterBottom:!0},"If OPENAI_API_KEY is set on the server, API Key is optional. Select a search type and send a question to get answers based on context retrieved from the vector DB."),r.a.createElement(y.a,{container:!0,spacing:2},r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement(K.a,{fullWidth:!0,variant:"outlined",size:"small"},r.a.createElement(Q.a,{id:"search-type-label"},"Search Type"),r.a.createElement(X.a,{labelId:"search-type-label",value:E,onChange:e=>b(e.target.value),label:"Search Type"},r.a.createElement(Z.a,{value:"image"},"image (current upload)"),r.a.createElement(Z.a,{value:"object"},"object (objectId)"),r.a.createElement(Z.a,{value:"class"},"class (class_name)")))),r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement($.a,{label:"OpenAI API Key (optional)",value:t,onChange:e=>l(e.target.value),fullWidth:!0,variant:"outlined",size:"small",type:"password",placeholder:"sk-..."})),"object"===E&&r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement($.a,{label:"objectId",value:v,onChange:e=>x(e.target.value),fullWidth:!0,variant:"outlined",size:"small"})),"class"===E&&r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement($.a,{label:"class_name",value:S,onChange:e=>C(e.target.value),fullWidth:!0,variant:"outlined",size:"small",placeholder:"e.g. person, car, dog"})),r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement($.a,{label:"n_results",value:w,onChange:e=>j(e.target.value),fullWidth:!0,variant:"outlined",size:"small",type:"number",inputProps:{min:1,max:50}})),r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement($.a,{label:"User Question",value:o,onChange:e=>c(e.target.value),fullWidth:!0,multiline:!0,rows:4,variant:"outlined",placeholder:"image"===E?"Answer based on the uploaded image":"Answer using the retrieved object context"})),p&&r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement(u.a,{color:"error"},p)),r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement("div",{style:{display:"flex",gap:8}},r.a.createElement(h.a,{color:"primary",variant:"contained",onClick:async()=>{g(""),s("");const e=(o||"").trim();if(!e)return void g("Please enter a question.");const n={userQuery:e,searchType:E,n_results:Number(w)||5};if(t&&(n.api_key=t),"image"===E){if(!a)return void g("Image is required. Please upload an image first.");n.image=a}else if("object"===E){if(!v.trim())return void g("Please enter an objectId.");n.objectId=v.trim()}else if("class"===E){if(!S.trim())return void g("Please enter a class_name.");n.class_name=S.trim()}d(!0);try{const e=await fetch("/api/vision-rag/query",{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify(n)});if(!e.ok){let a=await e.text();try{a=JSON.stringify(JSON.parse(a),null,2)}catch(r){}throw new Error(a)}const a=await e.json(),t="Model: ".concat(a.model||"-"," | Latency: ").concat(a.latency_sec||"-","s");let l="";a.retrieved&&a.retrieved.length>0&&(l="\n\nSearch Results:\n",a.retrieved.forEach((e,a)=>{l+="".concat(a+1,". ID: ").concat(e.id||"-","\n"),e.meta&&(l+=" Class: ".concat(e.meta.class||"-","\n"),l+=" Confidence: ".concat(e.meta.confidence||"-","\n")),l+=" Similarity: ".concat(e.distance?e.distance.toFixed(4):"-","\n")})),s((a.answer||"(No response)")+l+"\n\n---\n"+t)}catch(l){g("Error: "+l.message)}finally{d(!1)}},disabled:m},m?"Sending...":"Send Question"),r.a.createElement(h.a,{variant:"outlined",onClick:()=>{c(""),s(""),g("")}},"Clear"))),r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement(W.a,{style:{margin:"12px 0"}}),r.a.createElement(u.a,{variant:"subtitle2",color:"textSecondary"},"Response"),r.a.createElement("pre",{style:{whiteSpace:"pre-wrap",fontFamily:"ui-monospace, monospace"}},i))))},se=(t(80),t(159)),me=t(160),de=t(162),ue=t(163),pe=t(164);const ge=Object(j.a)(e=>({root:{marginTop:e.spacing(3),marginBottom:e.spacing(3)},imageContainer:{position:"relative",minHeight:"360px",display:"flex",justifyContent:"center",alignItems:"center",border:"2px dashed #ccc",borderRadius:"8px",margin:e.spacing(1),padding:e.spacing(1),backgroundColor:"#fafafa",overflow:"hidden"},progressLog:{marginTop:e.spacing(2),height:"200px",overflowY:"auto",backgroundColor:"#f8f9fa",padding:e.spacing(1),borderRadius:"4px",fontFamily:"monospace",fontSize:"0.9rem"},logEntry:{margin:"4px 0",padding:"2px 5px",borderLeft:"3px solid #ccc"},logEntryAgent:{borderLeft:"3px solid #2196f3"},logEntrySystem:{borderLeft:"3px solid #4caf50"},logEntryError:{borderLeft:"3px solid #f44336"},logTime:{color:"#666",fontSize:"0.8rem",marginRight:e.spacing(1)},imagePreview:{width:"100%",height:"auto",maxHeight:"60vh",objectFit:"contain"},uploadIcon:{fontSize:"3rem",color:"#aaa"},uploadInput:{display:"none"},deleteButton:{position:"absolute",top:"8px",right:"8px",backgroundColor:"rgba(255, 255, 255, 0.8)","&:hover":{backgroundColor:"rgba(255, 255, 255, 0.9)"}},tabPanel:{padding:e.spacing(2)},resultCard:{marginTop:e.spacing(2),marginBottom:e.spacing(2)},comparisonTable:{width:"100%",borderCollapse:"collapse","& th, & td":{border:"1px solid #ddd",padding:"8px",textAlign:"left"},"& th":{backgroundColor:"#f2f2f2"},"& tr:nth-child(even)":{backgroundColor:"#f9f9f9"}},loadingContainer:{display:"flex",flexDirection:"column",alignItems:"center",padding:e.spacing(4)},highlight:{backgroundColor:"#e3f2fd",padding:e.spacing(1),borderRadius:"4px",fontWeight:"bold"}}));var Ee=()=>{const e=ge(),[a,t]=Object(n.useState)([null,null]),[l,o]=Object(n.useState)([null,null]),[c,i]=Object(n.useState)(!1),[m,d]=Object(n.useState)(null),[E,x]=Object(n.useState)(null),[S,C]=Object(n.useState)(0),[w,j]=Object(n.useState)([]),O=Object(n.useRef)(null),I=function(e){let a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"info";const t=new Date,n=t.toLocaleTimeString(),r={time:n,message:e,type:a};j(e=>[...e,r])};Object(n.useEffect)(()=>{O.current&&O.current.scrollIntoView({behavior:"smooth"})},[w]);const P=e=>{const a=window.localStorage.getItem("auth_user_id"),t=window.localStorage.getItem("auth_username"),n=a&&t?"?uid=".concat(encodeURIComponent(a),"&uname=").concat(encodeURIComponent(t)):"",r=new EventSource("/api/product/compare/stream/".concat(e).concat(n));return r.onmessage=e=>{try{const a=JSON.parse(e.data);console.log("React SSE received:",a),a.message?I(a.message,a.agent||"info"):a.status?I("Status: ".concat(a.status),"system"):a.final_result?(console.log("Final result received:",a.final_result),d(a.final_result),i(!1),r.close()):a.error&&(I("Error: ".concat(a.error),"error"),i(!1),r.close())}catch(a){console.error("SSE parsing error:",a),I("Event processing error: ".concat(a.message),"error")}},r.onerror=e=>{I("Server connection lost. Please try again in a moment.","error"),r.close(),i(!1)},r},T=async function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;if(a[0]||a[1]){i(!0),x(null),j([]),I("Starting product analysis...","system");try{const t=new FormData;a[0]&&(t.append("image1",a[0]),I("Product A image uploaded.","info")),a[1]&&(t.append("image2",a[1]),I("Product B image uploaded.","info"));const n=["info","compare","value","recommend"],r=e||n[S];t.append("analysisType",r),I("Analysis type: ".concat("info"===r?"Product Information":"compare"===r?"Performance Comparison":"value"===r?"Value Analysis":"Purchase Recommendation"),"system"),I("Initializing analysis session...","system");for(let[e,a]of t.entries())console.log("FormData:",e,a);const l=await fetch("/api/product/compare/start",{method:"POST",body:t,credentials:"include"});if(console.log("Response status:",l.status),console.log("Response headers:",l.headers),!l.ok){const e=await l.text();throw console.error("Error response:",e),new Error("HTTP error! Status: ".concat(l.status," - ").concat(e))}const o=(await l.json()).session_id;if(!o)throw new Error("Failed to receive session ID");I("Analysis session started. (Session ID: ".concat(o.substring(0,8),"...)"),"system"),I("Agents are collaborating to analyze products. Please wait a moment...","system");const c=P(o);return()=>{c.close()}}catch(t){console.error("\uc81c\ud488 \ubd84\uc11d \uc624\ub958:",t),I("Error occurred: ".concat(t.message),"error"),x("Error during analysis: ".concat(t.message)),i(!1)}}else x("Please upload at least one product image for analysis")};return r.a.createElement(f.a,{className:e.root},r.a.createElement(s.a,{p:3},r.a.createElement(u.a,{variant:"h5",gutterBottom:!0},"Product Comparison Analysis"),r.a.createElement(u.a,{variant:"body1",paragraph:!0},"Upload product images to receive detailed information and comparison analysis. You can analyze various products including cars, smartphones, laptops, and more."),r.a.createElement(y.a,{container:!0,spacing:3},[0,1].map(n=>r.a.createElement(y.a,{item:!0,xs:12,md:6,key:n},r.a.createElement(s.a,{className:e.imageContainer},l[n]?r.a.createElement(r.a.Fragment,null,r.a.createElement("img",{src:l[n],alt:"Product ".concat(n+1),className:e.imagePreview}),r.a.createElement(v.a,{className:e.deleteButton,onClick:()=>(e=>{const n=[...a],r=[...l];n[e]=null,r[e]=null,t(n),o(r),d(null)})(n)},r.a.createElement(se.a,null))):r.a.createElement(r.a.Fragment,null,r.a.createElement("input",{accept:"image/*",className:e.uploadInput,id:"upload-image-".concat(n),type:"file",onChange:e=>((e,n)=>{const r=e.target.files[0];if(r){const e=new FileReader;e.onload=e=>{const a=[...l];a[n]=e.target.result,o(a)},e.readAsDataURL(r);const c=[...a];c[n]=r,t(c),d(null),x(null)}})(e,n)}),r.a.createElement("label",{htmlFor:"upload-image-".concat(n)},r.a.createElement(s.a,{display:"flex",flexDirection:"column",alignItems:"center"},r.a.createElement(me.a,{className:e.uploadIcon}),r.a.createElement(u.a,{variant:"body2",style:{marginTop:"8px"}},"Upload ",0===n?"Product A":"Product B"," Image"))))))),r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement("input",{accept:"image/*",className:e.uploadInput,id:"upload-both-images",type:"file",multiple:!0,onChange:e=>{const n=Array.from(e.target.files||[]);if(!n.length)return;const r=[...a],c=[...l];n.slice(0,2).forEach((e,a)=>{const t=a;r[t]=e;const n=new FileReader;n.onload=e=>{c[t]=e.target.result,o([...c])},n.readAsDataURL(e)}),t(r),d(null),x(null)}}),r.a.createElement("label",{htmlFor:"upload-both-images"},r.a.createElement(h.a,{variant:"text",color:"default",component:"span"},"Or select two files at once"))),r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement(f.a,null,r.a.createElement(p.a,{value:S,onChange:(e,a)=>{C(a)},indicatorColor:"primary",textColor:"primary",centered:!0},r.a.createElement(g.a,{icon:r.a.createElement(de.a,null),label:"Product Info"}),r.a.createElement(g.a,{icon:r.a.createElement(ue.a,null),label:"Performance",disabled:!a[0]||!a[1]}),r.a.createElement(g.a,{icon:r.a.createElement(pe.a,null),label:"Value Analysis"}),r.a.createElement(g.a,{label:"Recommendations"})),r.a.createElement(s.a,{p:2,display:"flex",justifyContent:"center",gridGap:12},r.a.createElement(h.a,{variant:"contained",color:"primary",onClick:()=>T(null),disabled:c||!a[0]&&!a[1],startIcon:c?r.a.createElement(b.a,{size:24}):null},c?"Analyzing...":"Start Analysis"),r.a.createElement(h.a,{variant:"outlined",color:"secondary",onClick:()=>T("compare"),disabled:c||!a[0]||!a[1],startIcon:r.a.createElement(ue.a,null)},"Compare Products")),E&&r.a.createElement(s.a,{p:2,bgcolor:"#ffebee",borderRadius:"4px",mb:2},r.a.createElement(u.a,{color:"error"},E)))),r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement(f.a,null,r.a.createElement(s.a,{p:2},r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"Analysis Progress"),r.a.createElement(s.a,{className:e.progressLog},0===w.length?r.a.createElement(u.a,{variant:"body2",color:"textSecondary",style:{padding:"10px"}},"Progress details will appear here when analysis starts."):w.map((a,t)=>r.a.createElement(s.a,{key:t,className:"".concat(e.logEntry," ").concat("agent"===a.type?e.logEntryAgent:"system"===a.type?e.logEntrySystem:"error"===a.type?e.logEntryError:"")},r.a.createElement("span",{className:e.logTime},"[",a.time,"]"),a.message)),r.a.createElement("div",{ref:O}))))),r.a.createElement(y.a,{item:!0,xs:12},c?r.a.createElement(s.a,{className:e.loadingContainer},r.a.createElement(b.a,null),r.a.createElement(u.a,{variant:"h6",style:{marginTop:"16px"}},"Analyzing Products..."),r.a.createElement(u.a,{variant:"body2",color:"textSecondary"},"Product recognition, information retrieval, and comparison analysis in progress.")):(()=>{if(!m)return null;switch(S){case 0:return r.a.createElement(B.a,{className:e.resultCard},r.a.createElement(N.a,null,r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"Product Information"),r.a.createElement(W.a,{style:{margin:"8px 0 16px"}}),m.productInfo&&r.a.createElement("div",null,Object.entries(m.productInfo).map((e,a)=>{let[t,n]=e;return r.a.createElement("div",{key:t,style:{marginBottom:"24px"}},r.a.createElement(u.a,{variant:"subtitle1",gutterBottom:!0},r.a.createElement("strong",null,"Product ",a+1," (",t,")")),r.a.createElement(u.a,{variant:"body1"},r.a.createElement("strong",null,"Type:")," ",n.product_type||"Unknown"),n.key_features&&n.key_features.length>0&&r.a.createElement("div",{style:{marginTop:"12px"}},r.a.createElement(u.a,{variant:"subtitle2"},"Key Features:"),r.a.createElement("ul",null,n.key_features.map((e,a)=>r.a.createElement("li",{key:a},r.a.createElement(u.a,{variant:"body2"},e))))),m.specifications&&m.specifications[t]&&r.a.createElement("div",{style:{marginTop:"12px"}},r.a.createElement(u.a,{variant:"subtitle2"},"Specifications:"),r.a.createElement("ul",null,Object.entries(m.specifications[t].specifications||{}).map(e=>{let[a,t]=e;return r.a.createElement("li",{key:a},r.a.createElement(u.a,{variant:"body2"},r.a.createElement("strong",null,a.replace("_"," "),":")," ",Array.isArray(t)?t.join(", "):t))}))))}))));case 1:return r.a.createElement(B.a,{className:e.resultCard},r.a.createElement(N.a,null,r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"Product Comparison Analysis"),r.a.createElement(W.a,{style:{margin:"8px 0 16px"}}),m.comparison&&r.a.createElement("div",null,r.a.createElement(u.a,{variant:"body1",style:{whiteSpace:"pre-line",marginBottom:"16px"}},"string"===typeof m.comparison?m.comparison:JSON.stringify(m.comparison,null,2)))));case 2:return r.a.createElement(B.a,{className:e.resultCard},r.a.createElement(N.a,null,r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"Price-to-Value Analysis"),r.a.createElement(W.a,{style:{margin:"8px 0 16px"}}),m.valueAnalysis&&r.a.createElement("div",null,r.a.createElement(u.a,{variant:"body1",style:{whiteSpace:"pre-line",marginBottom:"16px"}},"string"===typeof m.valueAnalysis?m.valueAnalysis:JSON.stringify(m.valueAnalysis,null,2)))));case 3:return r.a.createElement(B.a,{className:e.resultCard},r.a.createElement(N.a,null,r.a.createElement(u.a,{variant:"h6",gutterBottom:!0},"Purchase Recommendations"),r.a.createElement(W.a,{style:{margin:"8px 0 16px"}}),m.recommendation&&r.a.createElement("div",null,r.a.createElement(u.a,{variant:"body1",style:{whiteSpace:"pre-line",marginBottom:"16px"}},"string"===typeof m.recommendation?m.recommendation:JSON.stringify(m.recommendation,null,2))),!m.recommendation&&!m.valueAnalysis&&!m.comparison&&!m.productInfo&&r.a.createElement("div",null,r.a.createElement(u.a,{variant:"body1",style:{whiteSpace:"pre-line",marginBottom:"16px"}},JSON.stringify(m,null,2)))));default:return null}})()))))};var ye=()=>{var e,a,t,l;const[o,c]=Object(n.useState)("Describe the image concisely."),[i,m]=Object(n.useState)(null),[d,p]=Object(n.useState)("openlm-research/open_llama_3b"),[g,E]=Object(n.useState)("HGKo/openllama3b-lora-adapter"),[v,x]=Object(n.useState)("Base Model"),[S,C]=Object(n.useState)("LoRA Adapter"),[w,j]=Object(n.useState)(null),[O,I]=Object(n.useState)(!1),[B,N]=Object(n.useState)([]),P=Object(n.useRef)(null);Object(n.useEffect)(()=>{P.current&&P.current.scrollIntoView({behavior:"smooth"})},[B]);const T=function(e){let a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"info";const t=(new Date).toLocaleTimeString();N(n=>[...n,{time:t,message:e,type:a}])},A=e=>{const a=window.localStorage.getItem("auth_user_id"),t=window.localStorage.getItem("auth_username"),n=a&&t?"?uid=".concat(encodeURIComponent(a),"&uname=").concat(encodeURIComponent(t)):"",r=new EventSource("/api/llama/compare/stream/".concat(e).concat(n));r.onmessage=e=>{try{const a=JSON.parse(e.data);a.message&&T(a.message,a.type||"info"),a.status&&T("Status: ".concat(a.status),"system"),a.final_result&&(j(a.final_result),I(!1),r.close()),a.error&&(T("Error: ".concat(a.error),"error"),I(!1),r.close())}catch(a){T("SSE parse error: ".concat(a.message),"error")}},r.onerror=()=>{T("SSE connection error.","error"),I(!1),r.close()}};return r.a.createElement(f.a,{style:{padding:16}},r.a.createElement(u.a,{variant:"h5",gutterBottom:!0},"LLM LoRA Compare (Base vs Fine-tuned)"),r.a.createElement(u.a,{variant:"body2",color:"textSecondary",gutterBottom:!0},"Compare outputs of a base LLaMA model and a LoRA fine-tuned adapter on the same prompt/image."),r.a.createElement(y.a,{container:!0,spacing:2},r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement($.a,{fullWidth:!0,label:"Prompt",value:o,onChange:e=>c(e.target.value),multiline:!0,rows:4,variant:"outlined"})),r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement(s.a,{display:"flex",flexDirection:"column",gridGap:12},r.a.createElement($.a,{label:"Base model id",value:d,onChange:e=>p(e.target.value),variant:"outlined",fullWidth:!0}),r.a.createElement($.a,{label:"Base model name (display)",value:v,onChange:e=>x(e.target.value),variant:"outlined",fullWidth:!0}),r.a.createElement($.a,{label:"LoRA path/ID (optional)",value:g,onChange:e=>E(e.target.value),variant:"outlined",fullWidth:!0}),r.a.createElement($.a,{label:"LoRA adapter name (display, optional)",value:S,onChange:e=>C(e.target.value),variant:"outlined",fullWidth:!0}),r.a.createElement("input",{type:"file",accept:"image/*",onChange:e=>{var a;return m((null===(a=e.target.files)||void 0===a?void 0:a[0])||null)}}),r.a.createElement(h.a,{color:"primary",variant:"contained",onClick:async()=>{if(!o&&!i)return void T("Provide a prompt or upload an image.","error");I(!0),j(null),N([]);const e=new FormData;e.append("prompt",o),e.append("baseModel",d),v&&e.append("baseName",v),g&&e.append("loraPath",g),S&&e.append("loraName",S),i&&e.append("image",i);try{const a=await fetch("/api/llama/compare/start",{method:"POST",body:e,credentials:"include"});if(!a.ok)throw new Error("HTTP ".concat(a.status));const t=(await a.json()).session_id;T("Session started: ".concat(t.slice(0,8),"..."),"system"),A(t)}catch(a){T("Failed to start: ".concat(a.message),"error"),I(!1)}},disabled:O},O?r.a.createElement(b.a,{size:22}):"Run Comparison"))),r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement(W.a,{style:{margin:"8px 0 12px"}})),r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement(u.a,{variant:"h6"},"Logs"),r.a.createElement(s.a,{style:{height:200,overflow:"auto",background:"#f7f7f7",padding:8,borderRadius:4}},0===B.length?r.a.createElement(u.a,{variant:"body2",color:"textSecondary"},"Logs will appear here."):B.map((e,a)=>r.a.createElement(s.a,{key:a,style:{fontFamily:"monospace",fontSize:12,marginBottom:4}},r.a.createElement("span",{style:{color:"#666"}},"[",e.time,"]")," ",e.message)),r.a.createElement("div",{ref:P}))),r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement(u.a,{variant:"h6"},"Results"),w?r.a.createElement(s.a,null,r.a.createElement(u.a,{variant:"subtitle2"},"Prompt"),r.a.createElement(s.a,{style:{whiteSpace:"pre-wrap",marginBottom:8}},w.prompt),r.a.createElement(u.a,{variant:"subtitle2"},v||"Base Output"),r.a.createElement(s.a,{style:{whiteSpace:"pre-wrap",marginBottom:8}},(null===(e=w.base)||void 0===e?void 0:e.output)||"-"),r.a.createElement(u.a,{variant:"subtitle2"},S||"LoRA Output"),r.a.createElement(s.a,{style:{whiteSpace:"pre-wrap",marginBottom:8}},(null===(a=w.lora)||void 0===a?void 0:a.output)||"-"),r.a.createElement(u.a,{variant:"subtitle2"},"Latency"),r.a.createElement(s.a,null,"base: ".concat((null===(t=w.base)||void 0===t?void 0:t.latency_ms)||0," ms | lora: ").concat((null===(l=w.lora)||void 0===l?void 0:l.latency_ms)||0," ms"))):r.a.createElement(u.a,{variant:"body2",color:"textSecondary"},"Run a comparison to see outputs here."))),r.a.createElement(s.a,{marginTop:3},r.a.createElement(W.a,null),r.a.createElement(s.a,{marginTop:2},r.a.createElement(u.a,{variant:"subtitle1"},"How to fine-tune with LoRA (PEFT)"),r.a.createElement(u.a,{variant:"body2",color:"textSecondary"},"Use a small image+text dataset. Train with TRL/PEFT (LoRA/QLoRA). Upload your adapter and set the LoRA path above to compare."))))};t(104);const fe=Object(c.a)({palette:{primary:{main:"#3f51b5"},secondary:{main:"#f50057"}},typography:{fontFamily:"Roboto, Arial, sans-serif"}});var be=function(){const[e,a]=Object(n.useState)(null),[t,l]=Object(n.useState)(""),[o,c]=Object(n.useState)(""),[h,v]=Object(n.useState)(!1),[x,S]=Object(n.useState)(null),[C,w]=Object(n.useState)(null),[j,O]=Object(n.useState)({yolo:!1,detr:!1,vit:!1}),[B,N]=Object(n.useState)(0);return Object(n.useEffect)(()=>{fetch("/api/status").then(e=>e.json()).then(e=>{O(e.models)}).catch(e=>{console.error("Error checking API status:",e),w("Error connecting to the backend API. Please make sure the server is running.")})},[]),r.a.createElement(i.a,{theme:fe},r.a.createElement(s.a,{style:{flexGrow:1}},r.a.createElement(m.a,{position:"static"},r.a.createElement(d.a,null,r.a.createElement(u.a,{variant:"h6",style:{flexGrow:1}},"Vision LLM Multi-Agent System")),r.a.createElement(p.a,{value:B,onChange:(e,a)=>N(a),indicatorColor:"secondary",textColor:"inherit",centered:!0},r.a.createElement(g.a,{label:"Object Detection"}),r.a.createElement(g.a,{label:"Product Comparison"}),r.a.createElement(g.a,{label:"LLM LoRA Compare"}))),r.a.createElement(E.a,{maxWidth:"lg",style:{marginTop:fe.spacing(4),marginBottom:fe.spacing(4)}},0===B&&r.a.createElement(y.a,{container:!0,spacing:3},r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement(f.a,{style:{padding:fe.spacing(2)}},r.a.createElement(u.a,{variant:"h5",gutterBottom:!0},"Upload an image to see how each model performs!"),r.a.createElement(u.a,{variant:"body1",paragraph:!0},"This demo showcases three different object detection and image classification models:"),r.a.createElement(u.a,{variant:"body1",component:"div"},r.a.createElement("ul",null,r.a.createElement("li",null,r.a.createElement("strong",null,"YOLOv8"),": Fast and accurate object detection"),r.a.createElement("li",null,r.a.createElement("strong",null,"DETR"),": DEtection TRansformer for object detection"),r.a.createElement("li",null,r.a.createElement("strong",null,"ViT"),": Vision Transformer for image classification"))))),r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement(I,{onImageUpload:e=>{if(a(e),S(null),w(null),e instanceof File){const a=new FileReader;a.onload=()=>{const e=a.result;l("string"===typeof e?e:"")},a.onerror=()=>l(""),a.readAsDataURL(e)}else l("")}})),r.a.createElement(y.a,{item:!0,xs:12,md:6},r.a.createElement(z,{onModelSelect:e=>{c(e),S(null),w(null)},onProcess:async()=>{if(!e||!o)return void w("Please select both an image and a model");v(!0),w(null);const a=new FormData;a.append("image",e);let t="";switch(o){case"yolo":t="/api/detect/yolo";break;case"detr":t="/api/detect/detr";break;case"vit":t="/api/classify/vit";break;default:return w("Invalid model selection"),void v(!1)}try{const e=await fetch(t,{method:"POST",body:a});if(!e.ok)throw new Error("HTTP error! Status: ".concat(e.status));const n=await e.json();S({model:o,data:n})}catch(n){console.error("Error processing image:",n),w("Error processing image: ".concat(n.message))}finally{v(!1)}},isProcessing:h,modelsStatus:j,selectedModel:o,imageSelected:!!e})),C&&r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement(f.a,{style:{padding:fe.spacing(2),backgroundColor:"#ffebee"}},r.a.createElement(u.a,{color:"error"},C))),h&&r.a.createElement(y.a,{item:!0,xs:12,style:{textAlign:"center",margin:"".concat(fe.spacing(4),"px 0")}},r.a.createElement(b.a,null),r.a.createElement(u.a,{variant:"h6",style:{marginTop:fe.spacing(2)}},"Processing image...")),x&&r.a.createElement(r.a.Fragment,null,r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement(le,{results:x})),r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement(ce,{visionResults:x.data,model:x.model}))),r.a.createElement(y.a,{item:!0,xs:12},r.a.createElement(ie,{imageBase64:t}))),1===B&&r.a.createElement(Ee,null),2===B&&r.a.createElement(ye,null))))};var he=e=>{e&&e instanceof Function&&t.e(3).then(t.bind(null,181)).then(a=>{let{getCLS:t,getFID:n,getFCP:r,getLCP:l,getTTFB:o}=a;t(e),n(e),r(e),l(e),o(e)})};o.a.render(r.a.createElement(r.a.StrictMode,null,r.a.createElement(be,null)),document.getElementById("root")),he()},94:function(e,a,t){e.exports=t(105)},99:function(e,a,t){}},[[94,1,2]]]);
2
+ //# sourceMappingURL=main.be1003f9.chunk.js.map
static/static/js/main.be1003f9.chunk.js.map ADDED
The diff for this file is too large to render. See raw diff