Aigenthix commited on
Commit
af97d31
·
verified ·
1 Parent(s): 261f314

Upload 2580 files

Browse files
Files changed (1) hide show
  1. app_docker.py +172 -87
app_docker.py CHANGED
@@ -24,6 +24,8 @@ from app.core.constants import RAG_MODES, GROQ_MODELS, EMBEDDING_MODELS
24
 
25
  app = Flask(__name__)
26
  app.config['MAX_CONTENT_LENGTH'] = 50 * 1024 * 1024 # 50MB max upload
 
 
27
 
28
  # Global state
29
  services = {
@@ -540,15 +542,19 @@ HTML_TEMPLATE = """
540
  // Direct Chat - No documents needed
541
  function submitChat() {
542
  const message = document.getElementById('chatInput').value;
543
- if (!message) {
544
  showStatus('Please enter a message', 'warning');
545
  return;
546
  }
547
- showStatus('<div class="loading"></div> Chatting...', 'warning');
548
 
549
- // Add user message to chat
550
  addChatMessage(message, 'user');
551
  document.getElementById('chatInput').value = '';
 
 
 
 
 
552
 
553
  fetch('/chat', {
554
  method: 'POST',
@@ -556,20 +562,36 @@ HTML_TEMPLATE = """
556
  body: JSON.stringify({
557
  message: message,
558
  model: document.getElementById('chatModel').value,
559
- temperature: parseFloat(document.getElementById('chatTemperature').value)
560
- })
 
 
 
 
 
 
561
  })
562
- .then(r => r.json())
563
  .then(data => {
564
  if (data.success) {
565
  addChatMessage(data.result.answer, 'assistant');
566
- showStatus('', '');
 
567
  } else {
568
- addChatMessage('❌ Error: ' + data.error, 'error');
 
 
569
  }
570
  })
571
  .catch(e => {
572
- addChatMessage('❌ Error: ' + e, 'error');
 
 
 
 
 
 
 
 
573
  });
574
  }
575
 
@@ -662,33 +684,44 @@ HTML_TEMPLATE = """
662
  progressDiv.style.display = 'block';
663
 
664
  const formData = new FormData();
665
- let totalFiles = files.length;
666
- let processedFiles = 0;
667
-
668
  for (let file of files) {
669
  formData.append('files', file);
670
  }
671
 
672
- // Simulate progress
673
  let progress = 0;
674
  const progressInterval = setInterval(() => {
675
- if (progress < 90) {
676
- progress += Math.random() * 30;
677
- updateProgress(Math.min(progress, 90));
678
  }
679
- }, 500);
680
 
681
- fetch('/upload', {method: 'POST', body: formData})
682
- .then(r => r.json())
683
- .then(d => {
 
 
 
684
  clearInterval(progressInterval);
 
 
 
685
  updateProgress(100);
686
  setTimeout(() => {
687
  progressDiv.style.display = 'none';
688
  showStatus(d.message, d.success ? 'success' : 'error');
689
  updateDocumentsList();
690
  document.getElementById('fileInput').value = '';
 
691
  }, 1000);
 
 
 
 
 
 
 
692
  });
693
  });
694
 
@@ -738,61 +771,106 @@ def get_documents():
738
  @app.route('/upload', methods=['POST'])
739
  def upload_files():
740
  files = request.files.getlist('files')
741
- if not files:
742
- return jsonify({'success': False, 'message': 'No files uploaded'})
743
 
744
  try:
745
  successful = 0
746
  failed = 0
 
747
 
748
  for file in files:
749
- if not file.filename:
750
  continue
751
 
752
- file_content = file.read()
753
- doc_type = 'pdf' if file.filename.endswith('.pdf') else 'csv'
754
-
755
  try:
 
 
 
 
 
 
 
 
 
 
 
 
756
  # Update status: processing
757
- documents[file.filename] = {
758
  'type': doc_type,
759
  'size': len(file_content),
760
  'status': 'processing',
761
  'uploaded_at': str(__import__('datetime').datetime.now())
762
  }
763
 
764
- # Process file
765
  import tempfile
 
 
766
  with tempfile.NamedTemporaryFile(delete=False, suffix=f".{doc_type}") as f:
 
767
  f.write(file_content)
 
 
 
768
  if doc_type == 'pdf':
769
- text = PDFProcessor.extract_text(f.name)
770
  else:
771
- text = CSVProcessor.extract_text(f.name)
772
 
773
- # Chunk and embed
774
- chunker = ChunkerService(512, 50)
775
- chunks = chunker.chunk_text(text, {"doc_id": file.filename})
776
- embedded_chunks = services['embedding_service'].embed_chunks(chunks)
777
- services['vector_db_service'].add_chunks(embedded_chunks)
778
 
779
- # Update status: ready
780
- documents[file.filename]['status'] = 'ready'
781
- documents[file.filename]['chunks'] = len(chunks)
782
- successful += 1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
783
 
784
  except Exception as file_error:
785
- documents[file.filename]['status'] = 'error'
786
- documents[file.filename]['error'] = str(file_error)
 
 
 
 
 
787
  failed += 1
788
 
 
789
  message = f'✅ Processed {successful} file(s)'
790
  if failed > 0:
791
  message += f', ❌ Failed {failed} file(s)'
792
-
793
- return jsonify({'success': failed == 0, 'message': message})
 
 
 
 
 
 
 
794
  except Exception as e:
795
- return jsonify({'success': False, 'message': f'❌ Error: {str(e)}'})
 
796
 
797
  @app.route('/query', methods=['POST'])
798
  def query():
@@ -834,59 +912,66 @@ def query():
834
  @app.route('/chat', methods=['POST'])
835
  def chat():
836
  """Direct Chat - without document retrieval"""
837
- initialize_groq_from_env()
 
838
 
839
- if not services['retrieval_service']:
840
- return jsonify({'success': False, 'error': 'GROQ_API_KEY not configured in Hugging Face Spaces secrets'})
841
 
842
- data = request.json
843
- message = data.get('message', '')
844
- if not message:
845
- return jsonify({'success': False, 'error': 'Message is required'})
846
 
847
- try:
848
  model = data.get('model', 'llama-3.1-8b-instant')
849
- temperature = data.get('temperature', 0.7)
850
- max_tokens = data.get('max_tokens', 1024)
851
 
852
  start_time = __import__('time').time()
853
 
854
  # Direct LLM call without document retrieval
855
- groq_client = services['retrieval_service'].groq_client
856
- response = groq_client.create_chat_completion(
857
- model=model,
858
- messages=[
859
- {
860
- "role": "system",
861
- "content": "You are a helpful AI assistant. Provide clear, concise, and accurate answers."
862
- },
863
- {
864
- "role": "user",
865
- "content": message
866
- }
867
- ],
868
- temperature=temperature,
869
- max_tokens=max_tokens
870
- )
871
-
872
- answer = response['choices'][0]['message']['content']
873
- response_time_ms = (__import__('time').time() - start_time) * 1000
874
-
875
- tokens_used = {
876
- 'prompt': response['usage'].get('prompt_tokens', 0),
877
- 'completion': response['usage'].get('completion_tokens', 0),
878
- 'total': response['usage'].get('total_tokens', 0)
879
- }
 
880
 
881
- return jsonify({'success': True, 'result': {
882
- 'answer': answer,
883
- 'model': model,
884
- 'tokens_used': tokens_used,
885
- 'response_time_ms': response_time_ms,
886
- 'mode': 'direct_chat'
887
- }})
 
 
 
 
888
  except Exception as e:
889
- return jsonify({'success': False, 'error': str(e)})
 
 
890
 
891
  if __name__ == '__main__':
892
  os.makedirs('./data/uploads', exist_ok=True)
 
24
 
25
  app = Flask(__name__)
26
  app.config['MAX_CONTENT_LENGTH'] = 50 * 1024 * 1024 # 50MB max upload
27
+ app.config['UPLOAD_FOLDER'] = './data/uploads'
28
+ app.config['SESSION_TIMEOUT'] = 600 # 10 minutes
29
 
30
  # Global state
31
  services = {
 
542
  // Direct Chat - No documents needed
543
  function submitChat() {
544
  const message = document.getElementById('chatInput').value;
545
+ if (!message || message.trim() === '') {
546
  showStatus('Please enter a message', 'warning');
547
  return;
548
  }
 
549
 
550
+ const chatDiv = document.getElementById('chatMessages');
551
  addChatMessage(message, 'user');
552
  document.getElementById('chatInput').value = '';
553
+ showStatus('<div class="loading"></div> Waiting for response... (may take up to 30 seconds)', 'warning');
554
+
555
+ const timeout = 60000; // 60 second timeout
556
+ const controller = new AbortController();
557
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
558
 
559
  fetch('/chat', {
560
  method: 'POST',
 
562
  body: JSON.stringify({
563
  message: message,
564
  model: document.getElementById('chatModel').value,
565
+ temperature: parseFloat(document.getElementById('chatTemperature').value),
566
+ max_tokens: 1024
567
+ }),
568
+ signal: controller.signal
569
+ })
570
+ .then(r => {
571
+ clearTimeout(timeoutId);
572
+ return r.json();
573
  })
 
574
  .then(data => {
575
  if (data.success) {
576
  addChatMessage(data.result.answer, 'assistant');
577
+ showStatus('✅ Response received', 'success');
578
+ setTimeout(() => showStatus('', ''), 3000);
579
  } else {
580
+ const errorMsg = data.error || 'Unknown error';
581
+ addChatMessage('❌ ' + errorMsg, 'error');
582
+ showStatus('❌ ' + errorMsg, 'error');
583
  }
584
  })
585
  .catch(e => {
586
+ clearTimeout(timeoutId);
587
+ let errorMsg = 'Request failed';
588
+ if (e.name === 'AbortError') {
589
+ errorMsg = 'Request timeout - took too long';
590
+ } else {
591
+ errorMsg = e.message || 'Network error';
592
+ }
593
+ addChatMessage('❌ ' + errorMsg, 'error');
594
+ showStatus('❌ ' + errorMsg, 'error');
595
  });
596
  }
597
 
 
684
  progressDiv.style.display = 'block';
685
 
686
  const formData = new FormData();
 
 
 
687
  for (let file of files) {
688
  formData.append('files', file);
689
  }
690
 
691
+ // Better progress tracking
692
  let progress = 0;
693
  const progressInterval = setInterval(() => {
694
+ if (progress < 85) {
695
+ progress += Math.random() * 25;
696
+ updateProgress(Math.min(progress, 85));
697
  }
698
+ }, 300);
699
 
700
+ fetch('/upload', {
701
+ method: 'POST',
702
+ body: formData,
703
+ timeout: 300000 // 5 minute timeout
704
+ })
705
+ .then(r => {
706
  clearInterval(progressInterval);
707
+ return r.json();
708
+ })
709
+ .then(d => {
710
  updateProgress(100);
711
  setTimeout(() => {
712
  progressDiv.style.display = 'none';
713
  showStatus(d.message, d.success ? 'success' : 'error');
714
  updateDocumentsList();
715
  document.getElementById('fileInput').value = '';
716
+ progress = 0;
717
  }, 1000);
718
+ })
719
+ .catch(e => {
720
+ clearInterval(progressInterval);
721
+ progressDiv.style.display = 'none';
722
+ showStatus('❌ Upload failed: ' + e.message, 'error');
723
+ document.getElementById('fileInput').value = '';
724
+ progress = 0;
725
  });
726
  });
727
 
 
771
  @app.route('/upload', methods=['POST'])
772
  def upload_files():
773
  files = request.files.getlist('files')
774
+ if not files or len(files) == 0:
775
+ return jsonify({'success': False, 'message': '❌ No files uploaded'})
776
 
777
  try:
778
  successful = 0
779
  failed = 0
780
+ errors = []
781
 
782
  for file in files:
783
+ if not file or not file.filename:
784
  continue
785
 
786
+ filename = file.filename
 
 
787
  try:
788
+ file_content = file.read()
789
+ if not file_content:
790
+ documents[filename] = {'status': 'error', 'error': 'Empty file'}
791
+ failed += 1
792
+ continue
793
+
794
+ doc_type = 'pdf' if filename.endswith('.pdf') else 'csv' if filename.endswith('.csv') else None
795
+ if not doc_type:
796
+ documents[filename] = {'status': 'error', 'error': 'Invalid file type'}
797
+ failed += 1
798
+ continue
799
+
800
  # Update status: processing
801
+ documents[filename] = {
802
  'type': doc_type,
803
  'size': len(file_content),
804
  'status': 'processing',
805
  'uploaded_at': str(__import__('datetime').datetime.now())
806
  }
807
 
808
+ # Process file in temp location
809
  import tempfile
810
+ import os as os_module
811
+
812
  with tempfile.NamedTemporaryFile(delete=False, suffix=f".{doc_type}") as f:
813
+ temp_path = f.name
814
  f.write(file_content)
815
+
816
+ try:
817
+ # Extract text
818
  if doc_type == 'pdf':
819
+ text = PDFProcessor.extract_text(temp_path)
820
  else:
821
+ text = CSVProcessor.extract_text(temp_path)
822
 
823
+ if not text or len(text.strip()) == 0:
824
+ raise Exception('No text extracted from file')
 
 
 
825
 
826
+ # Chunk and embed
827
+ chunker = ChunkerService(512, 50)
828
+ chunks = chunker.chunk_text(text, {"doc_id": filename})
829
+
830
+ if not chunks:
831
+ raise Exception('No chunks created from text')
832
+
833
+ embedded_chunks = services['embedding_service'].embed_chunks(chunks)
834
+ services['vector_db_service'].add_chunks(embedded_chunks)
835
+
836
+ # Update status: ready
837
+ documents[filename]['status'] = 'ready'
838
+ documents[filename]['chunks'] = len(chunks)
839
+ successful += 1
840
+
841
+ finally:
842
+ # Clean up temp file
843
+ try:
844
+ os_module.unlink(temp_path)
845
+ except:
846
+ pass
847
 
848
  except Exception as file_error:
849
+ error_msg = str(file_error)[:100]
850
+ documents[filename] = {
851
+ 'type': 'unknown',
852
+ 'status': 'error',
853
+ 'error': error_msg
854
+ }
855
+ errors.append(f"{filename}: {error_msg}")
856
  failed += 1
857
 
858
+ # Build response message
859
  message = f'✅ Processed {successful} file(s)'
860
  if failed > 0:
861
  message += f', ❌ Failed {failed} file(s)'
862
+ if errors and len(errors) <= 3:
863
+ message += f"\n{'; '.join(errors)}"
864
+
865
+ return jsonify({
866
+ 'success': failed == 0,
867
+ 'message': message,
868
+ 'successful': successful,
869
+ 'failed': failed
870
+ })
871
  except Exception as e:
872
+ error_msg = str(e)[:200]
873
+ return jsonify({'success': False, 'message': f'❌ Upload error: {error_msg}'})
874
 
875
  @app.route('/query', methods=['POST'])
876
  def query():
 
912
  @app.route('/chat', methods=['POST'])
913
  def chat():
914
  """Direct Chat - without document retrieval"""
915
+ try:
916
+ initialize_groq_from_env()
917
 
918
+ if not services['retrieval_service']:
919
+ return jsonify({'success': False, 'error': 'GROQ_API_KEY not configured. Go to HF Secrets and add GROQ_API_KEY'})
920
 
921
+ data = request.json
922
+ message = data.get('message', '')
923
+ if not message:
924
+ return jsonify({'success': False, 'error': 'Message is required'})
925
 
 
926
  model = data.get('model', 'llama-3.1-8b-instant')
927
+ temperature = float(data.get('temperature', 0.7))
928
+ max_tokens = int(data.get('max_tokens', 1024))
929
 
930
  start_time = __import__('time').time()
931
 
932
  # Direct LLM call without document retrieval
933
+ try:
934
+ groq_client = services['retrieval_service'].groq_client
935
+ response = groq_client.create_chat_completion(
936
+ model=model,
937
+ messages=[
938
+ {
939
+ "role": "system",
940
+ "content": "You are a helpful AI assistant. Provide clear, concise, and accurate answers."
941
+ },
942
+ {
943
+ "role": "user",
944
+ "content": message
945
+ }
946
+ ],
947
+ temperature=temperature,
948
+ max_tokens=max_tokens
949
+ )
950
+
951
+ answer = response['choices'][0]['message']['content']
952
+ response_time_ms = (__import__('time').time() - start_time) * 1000
953
+
954
+ tokens_used = {
955
+ 'prompt': response['usage'].get('prompt_tokens', 0),
956
+ 'completion': response['usage'].get('completion_tokens', 0),
957
+ 'total': response['usage'].get('total_tokens', 0)
958
+ }
959
 
960
+ return jsonify({'success': True, 'result': {
961
+ 'answer': answer,
962
+ 'model': model,
963
+ 'tokens_used': tokens_used,
964
+ 'response_time_ms': response_time_ms,
965
+ 'mode': 'direct_chat'
966
+ }})
967
+ except __import__('requests').exceptions.Timeout:
968
+ return jsonify({'success': False, 'error': 'Request timeout - Groq API is taking too long. Try again.'})
969
+ except __import__('requests').exceptions.ConnectionError:
970
+ return jsonify({'success': False, 'error': 'Connection error - Unable to reach Groq API. Check internet.'})
971
  except Exception as e:
972
+ import traceback
973
+ __import__('logging').error(f"Chat error: {str(e)}\n{traceback.format_exc()}")
974
+ return jsonify({'success': False, 'error': f'Error: {str(e)[:100]}'})
975
 
976
  if __name__ == '__main__':
977
  os.makedirs('./data/uploads', exist_ok=True)