gbrabbit commited on
Commit
5257d62
ยท
1 Parent(s): 2d9acec

Auto commit at 23-2025-08 6:54:22

Browse files
lily_llm_api/app_v2.py CHANGED
@@ -62,6 +62,7 @@ from lily_llm_core.context_manager import get_context_manager, context_manager
62
 
63
  # ๊ณ„์ธต์  ๋ฉ”๋ชจ๋ฆฌ ์‹œ์Šคํ…œ ์ถ”๊ฐ€
64
  from lily_llm_core.integrated_memory_manager import integrated_memory_manager
 
65
 
66
  # ์ „์—ญ ๋ณ€์ˆ˜๋“ค
67
  current_model = None # ๐Ÿ”„ ํ˜„์žฌ ๋กœ๋“œ๋œ ๋ชจ๋ธ ์ธ์Šคํ„ด์Šค
@@ -580,207 +581,69 @@ def generate_sync(prompt: str, image_data_list: Optional[List[bytes]], max_lengt
580
 
581
  # 2. RAG ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์ปจํ…์ŠคํŠธ (PDF ๋‚ด์šฉ ํฌํ•จ)
582
  try:
583
- # ๐Ÿ”„ ์ƒˆ๋กœ์šด ๋ฉ”๋ชจ๋ฆฌ ์‹œ์Šคํ…œ์„ ์‚ฌ์šฉํ•œ RAG ์ปจํ…์ŠคํŠธ ๋กœ๋“œ
584
  rag_context = ""
585
 
586
- # ํ†ตํ•ฉ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์ž์—์„œ AI์šฉ ์ปจํ…์ŠคํŠธ ์ƒ์„ฑ
587
- ai_context = integrated_memory_manager.get_context_for_ai(
588
- user_id=user_id,
589
- room_id=room_id,
590
- session_id=session_id,
591
- include_user_memory=True,
592
- include_room_context=True,
593
- include_session_history=False # ํ˜„์žฌ ๋Œ€ํ™”๋Š” ๋ณ„๋„๋กœ ์ฒ˜๋ฆฌ
594
- )
595
-
596
- if ai_context:
597
- rag_context += f"\n\n๐Ÿ”— ๋ฉ”๋ชจ๋ฆฌ ์ปจํ…์ŠคํŠธ:\n{ai_context}\n"
598
- print(f"๐Ÿ” [DEBUG] ๋ฉ”๋ชจ๋ฆฌ ์ปจํ…์ŠคํŠธ ํฌํ•จ๋จ - ๊ธธ์ด: {len(ai_context)}")
599
 
600
- # ๊ธฐ์กด RAG ์‹œ์Šคํ…œ์—์„œ ๋ฌธ์„œ ๋‚ด์šฉ ๊ฐ€์ ธ์˜ค๊ธฐ (room_id ๊ธฐ๋ฐ˜)
601
- try:
602
- # ์ฑ„ํŒ…๋ฐฉ๋ณ„ ๋ฌธ์„œ ์ปจํ…์ŠคํŠธ ์กฐํšŒ
603
- room_context = integrated_memory_manager.room_context_manager.get_room_context(room_id)
604
- if room_context and room_context.documents:
605
- rag_context += "\n\n๐Ÿ“„ ์—…๋กœ๋“œ๋œ ๋ฌธ์„œ ๋ชฉ๋ก:\n"
606
- for doc in room_context.documents[-3:]: # ์ตœ๊ทผ 3๊ฐœ๋งŒ
607
- # ๋”•์…”๋„ˆ๋ฆฌ์™€ ๊ฐ์ฒด ๋ชจ๋‘ ์ฒ˜๋ฆฌ
608
- if isinstance(doc, dict):
609
- filename = doc.get('filename', 'unknown')
610
- doc_type = doc.get('document_type', 'unknown')
611
- page_count = doc.get('page_count', 0)
612
- else:
613
- filename = getattr(doc, 'filename', 'unknown')
614
- doc_type = getattr(doc, 'document_type', 'unknown')
615
- page_count = getattr(doc, 'page_count', 0)
616
-
617
- rag_context += f" - {filename} ({doc_type}, {page_count}ํŽ˜์ด์ง€)\n"
618
-
619
- print(f"๐Ÿ” [DEBUG] ์ฑ„ํŒ…๋ฐฉ {room_id}์˜ ๋ฌธ์„œ {len(room_context.documents)}๊ฐœ ๋ฐœ๊ฒฌ")
620
-
621
- except Exception as e:
622
- print(f"โš ๏ธ ์ฑ„ํŒ…๋ฐฉ ๋ฌธ์„œ ์ปจํ…์ŠคํŠธ ๋กœ๋“œ ์‹คํŒจ: {e}")
623
-
624
- # ์ƒˆ๋กœ์šด ๋ฉ”๋ชจ๋ฆฌ ์‹œ์Šคํ…œ ๊ธฐ๋ฐ˜ RAG ์ปจํ…์ŠคํŠธ ๋กœ๋“œ
625
- try:
626
- # ํ˜„์žฌ ์ฑ„ํŒ…๋ฐฉ์˜ ์ตœ์‹  ๋ฌธ์„œ ID ์‚ฌ์šฉ
627
- room_context = integrated_memory_manager.room_context_manager.get_room_context(room_id)
628
- if room_context and room_context.documents:
629
- # ๊ฐ€์žฅ ์ตœ๊ทผ์— ์—…๋กœ๋“œ๋œ ๋ฌธ์„œ ์‚ฌ์šฉ
630
- latest_doc = room_context.documents[-1]
631
-
632
- # ๋”•์…”๋„ˆ๋ฆฌ์™€ ๊ฐ์ฒด ๋ชจ๋‘ ์ฒ˜๋ฆฌ
633
- if isinstance(latest_doc, dict):
634
- latest_doc_id = latest_doc.get('document_id', 'unknown')
635
- latest_user_id = latest_doc.get('uploaded_by', 'unknown')
636
- else:
637
- latest_doc_id = getattr(latest_doc, 'document_id', 'unknown')
638
- latest_user_id = getattr(latest_doc, 'uploaded_by', 'unknown')
639
-
640
- print(f"๐Ÿ” [DEBUG] ์ƒˆ๋กœ์šด RAG ์ปจํ…์ŠคํŠธ ๊ฒ€์ƒ‰: ์ฑ„ํŒ…๋ฐฉ={room_id}, ์‚ฌ์šฉ์ž={latest_user_id}, ๋ฌธ์„œ={latest_doc_id}")
641
-
642
- # vector_stores ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ํ•ด๋‹น ๋ฌธ์„œ ๋‚ด์šฉ ์ฝ๊ธฐ
643
- import os
644
- import json
645
-
646
- vector_store_dir = "vector_stores"
647
- if os.path.exists(vector_store_dir):
648
- user_path = os.path.join(vector_store_dir, latest_user_id)
649
- if os.path.exists(user_path):
650
- doc_path = os.path.join(user_path, latest_doc_id)
651
- if os.path.exists(doc_path):
652
-
653
- # ๋ฌธ์„œ ๋‚ด์šฉ ํŒŒ์ผ ์ง์ ‘ ์ฝ๊ธฐ (pickle ํŒŒ์ผ ์ง€์›)
654
- if os.path.exists(doc_path):
655
- # ๐Ÿ”„ pickle ํŒŒ์ผ์—์„œ ๋‚ด์šฉ ์ฝ๊ธฐ (์šฐ์„ )
656
- pickle_file = os.path.join(doc_path, "simple_vector_store.pkl")
657
- if os.path.exists(pickle_file):
658
- try:
659
- import pickle
660
- with open(pickle_file, 'rb') as f:
661
- vector_store_data = pickle.load(f)
662
-
663
- # vector store์—์„œ ๋ฌธ์„œ ๋‚ด์šฉ ์ถ”์ถœ (dict ๊ตฌ์กฐ)
664
- if isinstance(vector_store_data, dict) and 'documents' in vector_store_data:
665
- documents_data = vector_store_data['documents']
666
- if documents_data and len(documents_data) > 0:
667
- rag_context = "\n\n๐Ÿ“„ ์—…๋กœ๋“œ๋œ ๋ฌธ์„œ ๋‚ด์šฉ:\n"
668
-
669
- # ๐Ÿš€ ์‹ค๋ฌด ์ˆ˜์ค€ ๊ตฌ์กฐํ™”๋œ PDF ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ
670
- extracted_images = []
671
- for i, doc in enumerate(documents_data[:2]): # ์ตœ๋Œ€ 2๊ฐœ ์ฒญํฌ
672
- if hasattr(doc, 'page_content'):
673
- content = doc.page_content.strip()
674
- if content and len(content) > 30:
675
- # ๊ตฌ์กฐํ™”๋œ ์ปจํ…์ธ ์ธ์ง€ ํ™•์ธ
676
- if "=== ํŽ˜์ด์ง€" in content and "[ํ…์ŠคํŠธ ๋ธ”๋ก" in content:
677
- # ์‹ค๋ฌด ์ˆ˜์ค€ ๊ตฌ์กฐํ™”๋œ ์ปจํ…์ธ 
678
- truncated_content = content[:400] + "..." if len(content) > 400 else content
679
- rag_context += f"--- ๊ตฌ์กฐํ™”๋œ ํŽ˜์ด์ง€ {i+1} ---\n{truncated_content}\n\n"
680
- print(f"๐Ÿš€ [DEBUG] ๊ตฌ์กฐํ™”๋œ PDF ํŽ˜์ด์ง€ ๋ฐ์ดํ„ฐ ๋กœ๋“œ๋จ")
681
- else:
682
- # ๊ธฐ์กด ๋ฐฉ์‹
683
- truncated_content = content[:200] + "..." if len(content) > 200 else content
684
- rag_context += f"--- ์ฒญํฌ {i+1} ---\n{truncated_content}\n\n"
685
-
686
- # ๐Ÿš€ ๊ตฌ์กฐํ™”๋œ ์ด๋ฏธ์ง€ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ
687
- if hasattr(doc, 'metadata') and doc.metadata:
688
- metadata = doc.metadata
689
-
690
- # ์‹ค๋ฌด ์ˆ˜์ค€ ๊ตฌ์กฐํ™”๋œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํ™•์ธ
691
- if metadata.get('structured_analysis') and metadata.get('spatial_relationships'):
692
- print(f"๐Ÿš€ [DEBUG] ์‹ค๋ฌด ์ˆ˜์ค€ ๊ตฌ์กฐํ™”๋œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๋ฐœ๊ฒฌ")
693
-
694
- # ์ด๋ฏธ์ง€ ๋ธ”๋ก ์ •๋ณด ์ถœ๋ ฅ
695
- if 'image_blocks' in metadata:
696
- image_blocks = metadata['image_blocks']
697
- for ib in image_blocks:
698
- print(f"๐Ÿ–ผ๏ธ [DEBUG] ์ด๋ฏธ์ง€ ๋ธ”๋ก: {ib['block_id']}, "
699
- f"์œ„์น˜: ({ib['bbox']['x0']:.1f}, {ib['bbox']['y0']:.1f}), "
700
- f"๊ด€๋ จ ํ…์ŠคํŠธ: {ib['related_text_count']}๊ฐœ")
701
-
702
- # ์ด๋ฏธ์ง€ ๋ฐ์ดํ„ฐ ์ถ”์ถœ (๊ธฐ์กด ๋ฐฉ์‹ + ์ƒˆ๋กœ์šด ๋ฐฉ์‹ ๋ชจ๋‘ ์ง€์›)
703
- if metadata.get('multimodal_ready') and 'image_data_list' in metadata:
704
- image_data_list = metadata['image_data_list']
705
- if image_data_list and len(image_data_list) > 0:
706
- extracted_images.extend(image_data_list)
707
- print(f"๐Ÿ” [DEBUG] ์ฒญํฌ {i+1}์—์„œ ์ด๋ฏธ์ง€ {len(image_data_list)}๊ฐœ ์ถ”์ถœ๋จ")
708
-
709
- # ์ด๋ฏธ์ง€ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋„ ์ถœ๋ ฅ (๊ตฌ์กฐํ™”๋œ ๊ฒฝ์šฐ)
710
- if 'image_metadata' in metadata:
711
- for img_meta in metadata['image_metadata'][:2]:
712
- print(f"๐Ÿ–ผ๏ธ [DEBUG] ์ด๋ฏธ์ง€ ์ƒ์„ธ: {img_meta['block_id']}, "
713
- f"ํฌ๊ธฐ: {img_meta['size']}, "
714
- f"๊ด€๋ จ ํ…์ŠคํŠธ: {len(img_meta.get('related_texts', []))}๊ฐœ")
715
-
716
- if len(rag_context) > 30:
717
- context_prompt += rag_context
718
- print(f"๐Ÿ” [DEBUG] RAG ์ปจํ…์ŠคํŠธ ํฌํ•จ๋จ - ๊ธธ์ด: {len(rag_context)}")
719
- print(f"๐Ÿ” [DEBUG] RAG ์ปจํ…์ŠคํŠธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ: {rag_context[:100]}...")
720
-
721
- # ๐Ÿ”„ ์ถ”์ถœ๋œ ์ด๋ฏธ์ง€๊ฐ€ ์žˆ์œผ๋ฉด ๋กœ๊ทธ ์ถœ๋ ฅ
722
- if extracted_images:
723
- print(f"๐Ÿ” [DEBUG] ์ด {len(extracted_images)}๊ฐœ ์ด๋ฏธ์ง€ ๋ฐ์ดํ„ฐ ์ถ”์ถœ ์™„๋ฃŒ")
724
- else:
725
- print(f"๐Ÿ” [DEBUG] ์ถ”์ถœ๋œ ์ด๋ฏธ์ง€ ์—†์Œ")
726
- else:
727
- print(f"โš ๏ธ [DEBUG] RAG ์ปจํ…์ŠคํŠธ๊ฐ€ ๋„ˆ๋ฌด ์งง์Œ: {len(rag_context)}")
728
- else:
729
- print(f"โš ๏ธ [DEBUG] pickle ํŒŒ์ผ์— ๋ฌธ์„œ ๋ฐ์ดํ„ฐ ์—†์Œ")
730
- else:
731
- print(f"โš ๏ธ [DEBUG] pickle ํŒŒ์ผ์— documents ํ‚ค ์—†์Œ: {list(vector_store_data.keys()) if isinstance(vector_store_data, dict) else 'Not a dict'}")
732
- except Exception as e:
733
- print(f"โš ๏ธ [DEBUG] pickle ํŒŒ์ผ ์ฝ๊ธฐ ์‹คํŒจ: {e}")
734
-
735
- # ๐Ÿ”„ fallback: documents.json ํŒŒ์ผ ์‹œ๋„
736
- docs_file = os.path.join(doc_path, "documents.json")
737
- if os.path.exists(docs_file):
738
- try:
739
- with open(docs_file, 'r', encoding='utf-8') as f:
740
- documents_data = json.load(f)
741
-
742
- if documents_data and len(documents_data) > 0:
743
- rag_context = "\n\n๐Ÿ“„ ์—…๋กœ๋“œ๋œ ๋ฌธ์„œ ๋‚ด์šฉ:\n"
744
- for i, doc in enumerate(documents_data[:2]): # ์ตœ๋Œ€ 2๊ฐœ ์ฒญํฌ
745
- if 'page_content' in doc:
746
- content = doc['page_content'].strip()
747
- if content and len(content) > 30:
748
- # ๋‚ด์šฉ์„ 200์ž๋กœ ์ œํ•œ
749
- truncated_content = content[:200] + "..." if len(content) > 200 else content
750
- rag_context += f"--- ์ฒญํฌ {i+1} ---\n{truncated_content}\n\n"
751
-
752
- if len(rag_context) > 30:
753
- context_prompt += rag_context
754
- print(f"๐Ÿ” [DEBUG] RAG ์ปจํ…์ŠคํŠธ ํฌํ•จ๋จ (JSON fallback) - ๊ธธ์ด: {len(rag_context)}")
755
- print(f"๐Ÿ” [DEBUG] RAG ์ปจํ…์ŠคํŠธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ: {rag_context[:100]}...")
756
- else:
757
- print(f"โš ๏ธ [DEBUG] RAG ์ปจํ…์ŠคํŠธ๊ฐ€ ๋„ˆ๋ฌด ์งง์Œ: {len(rag_context)}")
758
- else:
759
- print(f"โš ๏ธ [DEBUG] documents.json ๋ฐ์ดํ„ฐ ์—†์Œ")
760
- except Exception as e:
761
- print(f"โš ๏ธ [DEBUG] documents.json ์ฝ๊ธฐ ์‹คํŒจ: {e}")
762
- else:
763
- print(f"โš ๏ธ [DEBUG] documents.json ํŒŒ์ผ ์—†์Œ: {docs_file}")
764
- else:
765
- print(f"โš ๏ธ [DEBUG] pickle ํŒŒ์ผ ์—†์Œ: {pickle_file}")
766
- else:
767
- print(f"โš ๏ธ [DEBUG] ๋ฌธ์„œ ๊ฒฝ๋กœ ์—†์Œ: {doc_path}")
768
  else:
769
- print(f"โš ๏ธ [DEBUG] ๋ฌธ์„œ ๋””๋ ‰ํ† ๋ฆฌ ์—†์Œ: {user_path}")
770
- else:
771
- print(f"โš ๏ธ [DEBUG] ์‚ฌ์šฉ์ž ๊ฒฝ๋กœ ์—†์Œ: {user_path}")
772
- else:
773
- print(f"โš ๏ธ [DEBUG] ์‚ฌ์šฉ์ž ๋””๋ ‰ํ† ๋ฆฌ ์—†์Œ: {vector_store_dir}")
774
- else:
775
- print(f"โš ๏ธ [DEBUG] vector_stores ๋””๋ ‰ํ† ๋ฆฌ ์—†์Œ")
776
- except Exception as e:
777
- print(f"โš ๏ธ [DEBUG] RAG ์ปจํ…์ŠคํŠธ ํŒŒ์ผ ์ฝ๊ธฐ ์‹คํŒจ: {e}")
 
 
 
 
 
 
 
 
 
 
778
 
779
  except Exception as e:
780
  print(f"โš ๏ธ [DEBUG] RAG ์ปจํ…์ŠคํŠธ ์ฒ˜๋ฆฌ ์‹คํŒจ: {e}")
781
 
782
  if not context_prompt:
783
- print(f"๐Ÿ” [DEBUG] ์ปจํ…์ŠคํŠธ ์—†์Œ ๋˜๋Š” ๋น„์–ด์žˆ์Œ (์„ธ์…˜: {session_id})")
784
 
785
  except Exception as e:
786
  print(f"โš ๏ธ [DEBUG] ์ปจํ…์ŠคํŠธ ๋กœ๋“œ ์‹คํŒจ: {e} (์„ธ์…˜: {session_id})")
@@ -1822,6 +1685,7 @@ async def upload_document(
1822
  ):
1823
  """๋ฌธ์„œ ์—…๋กœ๋“œ ๋ฐ RAG ์ฒ˜๋ฆฌ"""
1824
  start_time = time.time()
 
1825
 
1826
  try:
1827
  # ๋ฌธ์„œ ID ์ƒ์„ฑ (์ œ๊ณต๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ)
@@ -1909,6 +1773,162 @@ async def upload_document(
1909
  error=str(e)
1910
  )
1911
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1912
  @app.post("/rag/generate", response_model=RAGResponse)
1913
  async def generate_rag_response(
1914
  query: str = Form(...),
@@ -4330,3 +4350,119 @@ async def advanced_context_health_check():
4330
  }
4331
  except Exception as e:
4332
  return {"status": "error", "message": str(e)}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
  # ๊ณ„์ธต์  ๋ฉ”๋ชจ๋ฆฌ ์‹œ์Šคํ…œ ์ถ”๊ฐ€
64
  from lily_llm_core.integrated_memory_manager import integrated_memory_manager
65
+ from lily_llm_core.text_summarizer import text_summarizer, SummaryConfig
66
 
67
  # ์ „์—ญ ๋ณ€์ˆ˜๋“ค
68
  current_model = None # ๐Ÿ”„ ํ˜„์žฌ ๋กœ๋“œ๋œ ๋ชจ๋ธ ์ธ์Šคํ„ด์Šค
 
581
 
582
  # 2. RAG ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์ปจํ…์ŠคํŠธ (PDF ๋‚ด์šฉ ํฌํ•จ)
583
  try:
584
+ # ๏ฟฝ๏ฟฝ ์ƒˆ๋กœ์šด ๋ฉ”๋ชจ๋ฆฌ ์‹œ์Šคํ…œ์„ ์‚ฌ์šฉํ•œ RAG ์ปจํ…์ŠคํŠธ ๋กœ๋“œ
585
  rag_context = ""
586
 
587
+ # ๐Ÿ”’ ์‚ฌ์šฉ์ž ์„ค์ • ํ™•์ธ
588
+ from lily_llm_core.user_memory_manager import user_memory_manager
589
+ keep_memory = user_memory_manager.get_memory_setting(user_id, "keep_memory_on_room_change")
 
 
 
 
 
 
 
 
 
 
590
 
591
+ if keep_memory:
592
+ # ๋ฉ”๋ชจ๋ฆฌ ์œ ์ง€ ๋ชจ๋“œ - ๊ธฐ์กด ๋กœ์ง ์‹คํ–‰
593
+ print(f"๐Ÿ”„ [DEBUG] ์‚ฌ์šฉ์ž {user_id} ๋ฉ”๋ชจ๋ฆฌ ์œ ์ง€ ๋ชจ๋“œ - RAG ์ปจํ…์ŠคํŠธ ๋กœ๋“œ")
594
+
595
+ # ํ†ตํ•ฉ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์ž์—์„œ AI์šฉ ์ปจํ…์ŠคํŠธ ์ƒ์„ฑ
596
+ ai_context = integrated_memory_manager.get_context_for_ai(
597
+ user_id=user_id,
598
+ room_id=room_id,
599
+ session_id=session_id,
600
+ include_user_memory=True,
601
+ include_room_context=True,
602
+ include_session_history=False # ํ˜„์žฌ ๋Œ€ํ™”๋Š” ๋ณ„๋„๋กœ ์ฒ˜๋ฆฌ
603
+ )
604
+
605
+ if ai_context:
606
+ rag_context += f"\n\n๐Ÿ”— ๋ฉ”๋ชจ๋ฆฌ ์ปจํ…์ŠคํŠธ:\n{ai_context}\n"
607
+ print(f"๐Ÿ” [DEBUG] ๋ฉ”๋ชจ๋ฆฌ ์ปจํ…์ŠคํŠธ ํฌํ•จ๋จ - ๊ธธ์ด: {len(ai_context)}")
608
+
609
+ # ๊ธฐ์กด RAG ์‹œ์Šคํ…œ์—์„œ ๋ฌธ์„œ ๋‚ด์šฉ ๊ฐ€์ ธ์˜ค๊ธฐ (room_id ๊ธฐ๋ฐ˜)
610
+ try:
611
+ # ์ฑ„ํŒ…๋ฐฉ๋ณ„ ๋ฌธ์„œ ์ปจํ…์ŠคํŠธ ์กฐํšŒ
612
+ room_context = integrated_memory_manager.room_context_manager.get_room_context(room_id)
613
+ if room_context and room_context.documents:
614
+ rag_context += "\n\n๐Ÿ“„ ์—…๋กœ๋“œ๋œ ๋ฌธ์„œ ๋ชฉ๋ก:\n"
615
+ for doc in room_context.documents[-3:]: # ์ตœ๊ทผ 3๊ฐœ๋งŒ
616
+ # ๋”•์…”๋„ˆ๋ฆฌ์™€ ๊ฐ์ฒด ๋ชจ๋‘ ์ฒ˜๋ฆฌ
617
+ if isinstance(doc, dict):
618
+ filename = doc.get('filename', 'unknown')
619
+ doc_type = doc.get('document_type', 'unknown')
620
+ page_count = doc.get('page_count', 0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
621
  else:
622
+ filename = getattr(doc, 'filename', 'unknown')
623
+ doc_type = getattr(doc, 'document_type', 'unknown')
624
+ page_count = getattr(doc, 'page_count', 0)
625
+
626
+ rag_context += f" - {filename} ({doc_type}, {page_count}ํŽ˜์ด์ง€)\n"
627
+
628
+ print(f"๐Ÿ” [DEBUG] ์ฑ„ํŒ…๋ฐฉ {room_id}์˜ ๋ฌธ์„œ {len(room_context.documents)}๊ฐœ ๋ฐœ๊ฒฌ")
629
+
630
+ except Exception as e:
631
+ print(f"โš ๏ธ ์ฑ„ํŒ…๋ฐฉ ๋ฌธ์„œ ์ปจํ…์ŠคํŠธ ๋กœ๋“œ ์‹คํŒจ: {e}")
632
+
633
+ # ๐Ÿ”’ ๋ฌธ์„œ ๋‚ด์šฉ ์ž์ฒด๋Š” ๋กœ๋“œํ•˜์ง€ ์•Š์Œ (ํ„ด๋ณ„ ์ดˆ๊ธฐํ™”)
634
+ # ์ด์ „ ํ„ด์—์„œ ์ฒจ๋ถ€๋œ ๋ฌธ์„œ์˜ ์‹ค์ œ ๋‚ด์šฉ์€ AI ์ปจํ…์ŠคํŠธ์— ํฌํ•จํ•˜์ง€ ์•Š์Œ
635
+ print(f"๏ฟฝ๏ฟฝ [DEBUG] ๋ฌธ์„œ ๋‚ด์šฉ ๋กœ๋“œ ๊ฑด๋„ˆ๋›ฐ๊ธฐ - ํ„ด๋ณ„ ์ดˆ๊ธฐํ™” ์ ์šฉ")
636
+
637
+ # ๏ฟฝ๏ฟฝ ํ˜„์žฌ ํ„ด์—์„œ๋งŒ ๋ฌธ์„œ ์ •๋ณด ํ‘œ์‹œ (์‹ค์ œ ๋‚ด์šฉ์€ ๋กœ๋“œํ•˜์ง€ ์•Š์Œ)
638
+ if rag_context:
639
+ context_prompt += rag_context
640
+ print(f"๐Ÿ” [DEBUG] ๋ฌธ์„œ ๋ชฉ๋ก๋งŒ ํ‘œ์‹œ - ์‹ค์ œ ๋‚ด์šฉ ๋กœ๋“œ ์•ˆํ•จ (ํ„ด๋ณ„ ์ดˆ๊ธฐํ™”)")
641
 
642
  except Exception as e:
643
  print(f"โš ๏ธ [DEBUG] RAG ์ปจํ…์ŠคํŠธ ์ฒ˜๋ฆฌ ์‹คํŒจ: {e}")
644
 
645
  if not context_prompt:
646
+ print(f"๏ฟฝ๏ฟฝ [DEBUG] ์ปจํ…์ŠคํŠธ ์—†์Œ ๋˜๋Š” ๋น„์–ด์žˆ์Œ (์„ธ์…˜: {session_id})")
647
 
648
  except Exception as e:
649
  print(f"โš ๏ธ [DEBUG] ์ปจํ…์ŠคํŠธ ๋กœ๋“œ ์‹คํŒจ: {e} (์„ธ์…˜: {session_id})")
 
1685
  ):
1686
  """๋ฌธ์„œ ์—…๋กœ๋“œ ๋ฐ RAG ์ฒ˜๋ฆฌ"""
1687
  start_time = time.time()
1688
+ # document_id = None
1689
 
1690
  try:
1691
  # ๋ฌธ์„œ ID ์ƒ์„ฑ (์ œ๊ณต๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ)
 
1773
  error=str(e)
1774
  )
1775
 
1776
+ @app.post("/summarize/conversation")
1777
+ async def summarize_conversation(
1778
+ room_id: str = Form("default"),
1779
+ user_id: str = Form("anonymous"),
1780
+ max_length: int = Form(300)
1781
+ ):
1782
+ """๐Ÿ”„ summarizers๋ฅผ ํ™œ์šฉํ•œ ๋Œ€ํ™” ์š”์•ฝ ์ƒ์„ฑ"""
1783
+ try:
1784
+ if not text_summarizer.is_available():
1785
+ return {
1786
+ "success": False,
1787
+ "message": "summarizers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."
1788
+ }
1789
+
1790
+ # ์Šค๋งˆํŠธ ๋Œ€ํ™” ์š”์•ฝ ์ƒ์„ฑ
1791
+ success = integrated_memory_manager.create_smart_conversation_summary(
1792
+ room_id, max_length
1793
+ )
1794
+
1795
+ if success:
1796
+ # ์—…๋ฐ์ดํŠธ๋œ ์ปจํ…์ŠคํŠธ ์กฐํšŒ
1797
+ room_context = integrated_memory_manager.room_context_manager.get_room_context(room_id)
1798
+
1799
+ return {
1800
+ "success": True,
1801
+ "message": "๋Œ€ํ™” ์š”์•ฝ ์ƒ์„ฑ ์™„๋ฃŒ",
1802
+ "summary": room_context.conversation_summary if room_context else "",
1803
+ "key_topics": room_context.key_topics if room_context else [],
1804
+ "room_id": room_id
1805
+ }
1806
+ else:
1807
+ return {
1808
+ "success": False,
1809
+ "message": "๋Œ€ํ™” ์š”์•ฝ ์ƒ์„ฑ ์‹คํŒจ"
1810
+ }
1811
+
1812
+ except Exception as e:
1813
+ logger.error(f"โŒ ๋Œ€ํ™” ์š”์•ฝ ์ƒ์„ฑ ์‹คํŒจ: {e}")
1814
+ return {
1815
+ "success": False,
1816
+ "message": f"๋Œ€ํ™” ์š”์•ฝ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
1817
+ }
1818
+
1819
+ @app.post("/summarize/text")
1820
+ async def summarize_text(
1821
+ text: str = Form(...),
1822
+ max_length: int = Form(200),
1823
+ model_name: str = Form("kobart")
1824
+ ):
1825
+ """๐Ÿ”„ summarizers๋ฅผ ํ™œ์šฉํ•œ ํ…์ŠคํŠธ ์š”์•ฝ"""
1826
+ try:
1827
+ if not text_summarizer.is_available():
1828
+ return {
1829
+ "success": False,
1830
+ "message": "summarizers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."
1831
+ }
1832
+
1833
+ if not text or len(text.strip()) < 50:
1834
+ return {
1835
+ "success": False,
1836
+ "message": "์š”์•ฝํ•  ํ…์ŠคํŠธ๊ฐ€ ๋„ˆ๋ฌด ์งง์Šต๋‹ˆ๋‹ค (์ตœ์†Œ 50์ž ํ•„์š”)"
1837
+ }
1838
+
1839
+ # ์š”์•ฝ ์„ค์ •
1840
+ config = SummaryConfig(
1841
+ max_length=max_length,
1842
+ min_length=max_length // 2,
1843
+ do_sample=False,
1844
+ temperature=0.7,
1845
+ top_p=0.9
1846
+ )
1847
+
1848
+ # ์š”์•ฝ ์ˆ˜ํ–‰
1849
+ summary = text_summarizer.summarize_text(text, model_name, config)
1850
+
1851
+ if summary:
1852
+ compression_ratio = len(summary) / len(text)
1853
+ return {
1854
+ "success": True,
1855
+ "message": "ํ…์ŠคํŠธ ์š”์•ฝ ์™„๋ฃŒ",
1856
+ "original_length": len(text),
1857
+ "summary_length": len(summary),
1858
+ "compression_ratio": round(compression_ratio, 2),
1859
+ "summary": summary,
1860
+ "model_used": model_name
1861
+ }
1862
+ else:
1863
+ return {
1864
+ "success": False,
1865
+ "message": "์š”์•ฝ ์ƒ์„ฑ ์‹คํŒจ"
1866
+ }
1867
+
1868
+ except Exception as e:
1869
+ logger.error(f"โŒ ํ…์ŠคํŠธ ์š”์•ฝ ์‹คํŒจ: {e}")
1870
+ return {
1871
+ "success": False,
1872
+ "message": f"ํ…์ŠคํŠธ ์š”์•ฝ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
1873
+ }
1874
+
1875
+ @app.post("/compress/context")
1876
+ async def compress_context(
1877
+ room_id: str = Form("default"),
1878
+ target_length: int = Form(800)
1879
+ ):
1880
+ """๐Ÿ”„ ์ฑ„ํŒ…๋ฐฉ ์ปจํ…์ŠคํŠธ ์••์ถ•"""
1881
+ try:
1882
+ if not text_summarizer.is_available():
1883
+ return {
1884
+ "success": False,
1885
+ "message": "summarizers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."
1886
+ }
1887
+
1888
+ # ์ปจํ…์ŠคํŠธ ์••์ถ• ์ˆ˜ํ–‰
1889
+ success = integrated_memory_manager.compress_room_context(room_id, target_length)
1890
+
1891
+ if success:
1892
+ return {
1893
+ "success": True,
1894
+ "message": "์ปจํ…์ŠคํŠธ ์••์ถ• ์™„๋ฃŒ",
1895
+ "room_id": room_id,
1896
+ "target_length": target_length
1897
+ }
1898
+ else:
1899
+ return {
1900
+ "success": False,
1901
+ "message": "์ปจํ…์ŠคํŠธ ์••์ถ• ์‹คํŒจ"
1902
+ }
1903
+
1904
+ except Exception as e:
1905
+ logger.error(f"โŒ ์ปจํ…์ŠคํŠธ ์••์ถ• ์‹คํŒจ: {e}")
1906
+ return {
1907
+ "success": False,
1908
+ "message": f"์ปจํ…์ŠคํŠธ ์••์ถ• ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
1909
+ }
1910
+
1911
+ @app.get("/summarizer/status")
1912
+ async def get_summarizer_status():
1913
+ """๐Ÿ”„ summarizers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ƒํƒœ ํ™•์ธ"""
1914
+ try:
1915
+ available = text_summarizer.is_available()
1916
+ models = text_summarizer.get_available_models() if available else []
1917
+
1918
+ return {
1919
+ "success": True,
1920
+ "summarizers_available": available,
1921
+ "available_models": models,
1922
+ "default_model": "hyunwoongko/kobart" if available else None
1923
+ }
1924
+
1925
+ except Exception as e:
1926
+ logger.error(f"โŒ summarizer ์ƒํƒœ ํ™•์ธ ์‹คํŒจ: {e}")
1927
+ return {
1928
+ "success": False,
1929
+ "message": f"์ƒํƒœ ํ™•์ธ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
1930
+ }
1931
+
1932
  @app.post("/rag/generate", response_model=RAGResponse)
1933
  async def generate_rag_response(
1934
  query: str = Form(...),
 
4350
  }
4351
  except Exception as e:
4352
  return {"status": "error", "message": str(e)}
4353
+ ""
4354
+
4355
+ # ============================================================================
4356
+ # ์‚ฌ์šฉ์ž ๋ฉ”๋ชจ๋ฆฌ ์„ค์ • ๊ด€๋ฆฌ API
4357
+ # ============================================================================
4358
+
4359
+ @app.get("/user/memory/settings/{user_id}")
4360
+ async def get_user_memory_settings(user_id: str):
4361
+ """์‚ฌ์šฉ์ž ๋ฉ”๋ชจ๋ฆฌ ์„ค์ • ์กฐํšŒ"""
4362
+ try:
4363
+ from lily_llm_core.user_memory_manager import user_memory_manager
4364
+
4365
+ # ๊ธฐ๋ณธ ์„ค์ • ์กฐํšŒ
4366
+ keep_memory = user_memory_manager.get_memory_setting(user_id, "keep_memory_on_room_change")
4367
+
4368
+ return {
4369
+ "status": "success",
4370
+ "user_id": user_id,
4371
+ "settings": {
4372
+ "keep_memory_on_room_change": keep_memory if keep_memory is not None else True
4373
+ }
4374
+ }
4375
+ except Exception as e:
4376
+ return {"status": "error", "message": str(e)}
4377
+
4378
+ @app.post("/user/memory/settings/{user_id}")
4379
+ async def update_user_memory_settings(
4380
+ user_id: str,
4381
+ keep_memory_on_room_change: bool = Form(True)
4382
+ ):
4383
+ """์‚ฌ์šฉ์ž ๋ฉ”๋ชจ๋ฆฌ ์„ค์ • ์—…๋ฐ์ดํŠธ"""
4384
+ try:
4385
+ from lily_llm_core.user_memory_manager import user_memory_manager
4386
+
4387
+ # ์„ค์ • ์—…๋ฐ์ดํŠธ
4388
+ success = user_memory_manager.update_memory_setting(
4389
+ user_id, "keep_memory_on_room_change", keep_memory_on_room_change
4390
+ )
4391
+
4392
+ if success:
4393
+ return {
4394
+ "status": "success",
4395
+ "message": f"์‚ฌ์šฉ์ž {user_id} ๋ฉ”๋ชจ๋ฆฌ ์„ค์ • ์—…๋ฐ์ดํŠธ ์™„๋ฃŒ",
4396
+ "settings": {
4397
+ "keep_memory_on_room_change": keep_memory_on_room_change
4398
+ }
4399
+ }
4400
+ else:
4401
+ return {"status": "error", "message": "์„ค์ • ์—…๋ฐ์ดํŠธ ์‹คํŒจ"}
4402
+ except Exception as e:
4403
+ return {"status": "error", "message": str(e)}
4404
+
4405
+ @app.post("/user/memory/room-change/{user_id}")
4406
+ async def handle_room_change(user_id: str, new_room_id: str = Form(...)):
4407
+ """Room ๋ณ€๊ฒฝ ์‹œ ๋ฉ”๋ชจ๋ฆฌ ์ฒ˜๋ฆฌ"""
4408
+ try:
4409
+ from lily_llm_core.user_memory_manager import user_memory_manager
4410
+ from lily_llm_core.integrated_memory_manager import integrated_memory_manager
4411
+
4412
+ # ์‚ฌ์šฉ์ž ์„ค์ • ํ™•์ธ
4413
+ keep_memory = user_memory_manager.get_memory_setting(user_id, "keep_memory_on_room_change")
4414
+
4415
+ if keep_memory:
4416
+ # ๋ฉ”๋ชจ๋ฆฌ ์œ ์ง€ (๊ธฐ๋ณธ ๋™์ž‘)
4417
+ logger.info(f"๐Ÿ”„ ์‚ฌ์šฉ์ž {user_id}๊ฐ€ room {new_room_id}๋กœ ์ด๋™ - ๋ฉ”๋ชจ๋ฆฌ ์œ ์ง€")
4418
+ return {
4419
+ "status": "success",
4420
+ "message": f"Room {new_room_id}๋กœ ์ด๋™ - ๋ฉ”๋ชจ๋ฆฌ ์œ ์ง€๋จ",
4421
+ "memory_preserved": True
4422
+ }
4423
+ else:
4424
+ # ๋ฉ”๋ชจ๋ฆฌ ์ดˆ๊ธฐํ™”
4425
+ logger.info(f"๐Ÿ”„ ์‚ฌ์šฉ์ž {user_id}๊ฐ€ room {new_room_id}๋กœ ์ด๋™ - ๋ฉ”๋ชจ๋ฆฌ ์ดˆ๊ธฐํ™”")
4426
+
4427
+ # ์„ธ์…˜ ์ปจํ…์ŠคํŠธ ์ดˆ๊ธฐํ™”
4428
+ if context_manager:
4429
+ # ์‚ฌ์šฉ์ž ๊ด€๋ จ ์„ธ์…˜๋“ค ์ฐพ์•„์„œ ์ดˆ๊ธฐํ™”
4430
+ user_sessions = [
4431
+ session_id for session_id in context_manager.session_conversations.keys()
4432
+ if f"user_{user_id}" in session_id
4433
+ ]
4434
+
4435
+ for session_id in user_sessions:
4436
+ context_manager.clear_session_context(session_id)
4437
+ logger.info(f"๐Ÿ—‘๏ธ ์„ธ์…˜ ์ปจํ…์ŠคํŠธ ์ดˆ๊ธฐํ™”: {session_id}")
4438
+
4439
+ # Room ์ปจํ…์ŠคํŠธ ์ดˆ๊ธฐํ™” (์‚ฌ์šฉ์ž ๊ด€๋ จ ๋ฌธ์„œ ์ œ๊ฑฐ)
4440
+ try:
4441
+ room_context = integrated_memory_manager.room_context_manager.get_room_context(new_room_id)
4442
+ if room_context and room_context.documents:
4443
+ # ์‚ฌ์šฉ์ž๊ฐ€ ์—…๋กœ๋“œํ•œ ๋ฌธ์„œ๋“ค ์ œ๊ฑฐ
4444
+ original_count = len(room_context.documents)
4445
+ room_context.documents = [
4446
+ doc for doc in room_context.documents
4447
+ if (isinstance(doc, dict) and doc.get('uploaded_by') != user_id) or
4448
+ (hasattr(doc, 'uploaded_by') and getattr(doc, 'uploaded_by') != user_id)
4449
+ ]
4450
+
4451
+ # ๋ณ€๊ฒฝ์‚ฌํ•ญ ์ €์žฅ
4452
+ integrated_memory_manager.room_context_manager.save_room_context(new_room_id, room_context)
4453
+
4454
+ removed_count = original_count - len(room_context.documents)
4455
+ logger.info(f"๏ฟฝ๏ฟฝ๏ธ Room {new_room_id}์—์„œ ์‚ฌ์šฉ์ž {user_id} ๋ฌธ์„œ {removed_count}๊ฐœ ์ œ๊ฑฐ")
4456
+ except Exception as e:
4457
+ logger.warning(f"โš ๏ธ Room ์ปจํ…์ŠคํŠธ ์ดˆ๊ธฐํ™” ์‹คํŒจ: {e}")
4458
+
4459
+ return {
4460
+ "status": "success",
4461
+ "message": f"Room {new_room_id}๋กœ ์ด๋™ - ๋ฉ”๋ชจ๋ฆฌ ์ดˆ๊ธฐํ™”๋จ",
4462
+ "memory_preserved": False,
4463
+ "context_cleared": True
4464
+ }
4465
+
4466
+ except Exception as e:
4467
+ logger.error(f"โŒ Room ๋ณ€๊ฒฝ ์ฒ˜๋ฆฌ ์‹คํŒจ: {e}")
4468
+ return {"status": "error", "message": str(e)}
lily_llm_core/context_manager.py CHANGED
@@ -12,6 +12,8 @@ from collections import deque
12
  import json
13
  import re
14
 
 
 
15
  logger = logging.getLogger(__name__)
16
 
17
  @dataclass
@@ -911,10 +913,37 @@ class AdvancedContextManager:
911
  return summary
912
 
913
  def _smart_summarize(self, content: str, role: str) -> str:
914
- """์Šค๋งˆํŠธ ์š”์•ฝ - ๋ฌธ์žฅ ๋‹จ์œ„๋กœ ์š”์•ฝ"""
915
  if len(content) <= 150:
916
  return content
917
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
918
  # ๋ฌธ์žฅ ๋‹จ์œ„๋กœ ๋ถ„๋ฆฌ
919
  sentences = re.split(r'[.!?]+', content)
920
  sentences = [s.strip() for s in sentences if s.strip()]
 
12
  import json
13
  import re
14
 
15
+ from .text_summarizer import text_summarizer, SummaryConfig
16
+
17
  logger = logging.getLogger(__name__)
18
 
19
  @dataclass
 
913
  return summary
914
 
915
  def _smart_summarize(self, content: str, role: str) -> str:
916
+ """์Šค๋งˆํŠธ ์š”์•ฝ - summarizers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ธฐ๋ฐ˜ ๊ณ ํ’ˆ์งˆ ์š”์•ฝ"""
917
  if len(content) <= 150:
918
  return content
919
 
920
+ # ๐Ÿ”„ summarizers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ธฐ๋ฐ˜ ์š”์•ฝ ์‹œ๋„
921
+ if text_summarizer.is_available():
922
+ try:
923
+ # ์š”์•ฝ ์„ค์ •
924
+ config = SummaryConfig(
925
+ max_length=200, # ์š”์•ฝ ๊ธธ์ด ์ œํ•œ
926
+ min_length=50,
927
+ do_sample=False, # ์ผ๊ด€์„ฑ ์œ ์ง€
928
+ temperature=0.7, # ์ ๋‹นํ•œ ์ฐฝ์˜์„ฑ
929
+ top_p=0.9
930
+ )
931
+
932
+ # summarizers๋ฅผ ์‚ฌ์šฉํ•œ ์š”์•ฝ
933
+ summary = text_summarizer.summarize_text(content, config=config)
934
+
935
+ if summary and len(summary.strip()) > 0:
936
+ logger.debug(f"โœ… summarizers ๊ธฐ๋ฐ˜ ์Šค๋งˆํŠธ ์š”์•ฝ ์™„๋ฃŒ: {len(content)} โ†’ {len(summary)} ๋ฌธ์ž")
937
+ return summary.strip()
938
+ else:
939
+ logger.debug("summarizers ์š”์•ฝ ์‹คํŒจ, ๊ธฐ๋ณธ ์š”์•ฝ ์‚ฌ์šฉ")
940
+
941
+ except Exception as e:
942
+ logger.debug(f"summarizers ์š”์•ฝ ์‹คํŒจ: {e}, ๊ธฐ๋ณธ ์š”์•ฝ ์‚ฌ์šฉ")
943
+ else:
944
+ logger.debug("summarizers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ์š”์•ฝ ์‚ฌ์šฉ")
945
+
946
+ # ๐Ÿ”„ ๊ธฐ๋ณธ ์š”์•ฝ (summarizers ์‹คํŒจ ์‹œ)
947
  # ๋ฌธ์žฅ ๋‹จ์œ„๋กœ ๋ถ„๋ฆฌ
948
  sentences = re.split(r'[.!?]+', content)
949
  sentences = [s.strip() for s in sentences if s.strip()]
lily_llm_core/integrated_memory_manager.py CHANGED
@@ -12,6 +12,7 @@ from dataclasses import dataclass
12
  from .user_memory_manager import user_memory_manager, UserMemory
13
  from .room_context_manager import room_context_manager, RoomContext
14
  from .context_manager import AdvancedContextManager
 
15
 
16
  logger = logging.getLogger(__name__)
17
 
@@ -156,6 +157,148 @@ class IntegratedMemoryManager:
156
  logger.error(f"โŒ ๋Œ€ํ™” ๊ธฐ๋ก ์‹คํŒจ: {user_id}/{room_id} - {e}")
157
  return False
158
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  def get_context_for_ai(self, user_id: str, room_id: str, session_id: str,
160
  include_user_memory: bool = True,
161
  include_room_context: bool = True,
 
12
  from .user_memory_manager import user_memory_manager, UserMemory
13
  from .room_context_manager import room_context_manager, RoomContext
14
  from .context_manager import AdvancedContextManager
15
+ from .text_summarizer import text_summarizer, SummaryConfig
16
 
17
  logger = logging.getLogger(__name__)
18
 
 
157
  logger.error(f"โŒ ๋Œ€ํ™” ๊ธฐ๋ก ์‹คํŒจ: {user_id}/{room_id} - {e}")
158
  return False
159
 
160
+ def update_conversation_summary(self, room_id: str, summary: str, topics: List[str] = None) -> bool:
161
+ """๋Œ€ํ™” ์š”์•ฝ ์—…๋ฐ์ดํŠธ"""
162
+ try:
163
+ success = self.room_context_manager.update_conversation_summary(room_id, summary, topics)
164
+
165
+ if success:
166
+ logger.info(f"โœ… ๋Œ€ํ™” ์š”์•ฝ ์—…๋ฐ์ดํŠธ: {room_id} - {len(summary)} ๋ฌธ์ž")
167
+
168
+ return success
169
+
170
+ except Exception as e:
171
+ logger.error(f"โŒ ๋Œ€ํ™” ์š”์•ฝ ์—…๋ฐ์ดํŠธ ์‹คํŒจ: {room_id} - {e}")
172
+ return False
173
+
174
+ def create_smart_conversation_summary(self, room_id: str, max_length: int = 300) -> bool:
175
+ """๐Ÿ”„ summarizers๋ฅผ ํ™œ์šฉํ•œ ์Šค๋งˆํŠธ ๋Œ€ํ™” ์š”์•ฝ ์ƒ์„ฑ"""
176
+ try:
177
+ if not text_summarizer.is_available():
178
+ logger.warning("summarizers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
179
+ return False
180
+
181
+ # ์ฑ„ํŒ…๋ฐฉ ์ปจํ…์ŠคํŠธ ์กฐํšŒ
182
+ room_context = self.room_context_manager.get_room_context(room_id)
183
+ if not room_context:
184
+ logger.warning(f"์ฑ„ํŒ…๋ฐฉ ์ปจํ…์ŠคํŠธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {room_id}")
185
+ return False
186
+
187
+ # ๋Œ€ํ™” ๋‚ด์šฉ ์ˆ˜์ง‘ (์ตœ๊ทผ ๋ฉ”์‹œ์ง€๋“ค)
188
+ conversation_text = ""
189
+ if hasattr(room_context, 'conversation_summary') and room_context.conversation_summary:
190
+ conversation_text += f"์ด์ „ ์š”์•ฝ: {room_context.conversation_summary}\n"
191
+
192
+ # ์ฐธ๊ฐ€์ž ์ •๋ณด
193
+ if hasattr(room_context, 'participants') and room_context.participants:
194
+ conversation_text += f"์ฐธ๊ฐ€์ž: {', '.join(room_context.participants)}\n"
195
+
196
+ # ๋ฌธ์„œ ์ •๋ณด
197
+ if hasattr(room_context, 'documents') and room_context.documents:
198
+ doc_names = []
199
+ for doc in room_context.documents[-3:]:
200
+ if isinstance(doc, dict):
201
+ filename = doc.get('filename', 'unknown')
202
+ else:
203
+ filename = getattr(doc, 'filename', 'unknown')
204
+ doc_names.append(filename)
205
+
206
+ conversation_text += f"์—…๋กœ๋“œ๋œ ๋ฌธ์„œ: {', '.join(doc_names)}\n"
207
+
208
+ if len(conversation_text.strip()) < 50:
209
+ logger.debug("์š”์•ฝํ•  ๋‚ด์šฉ์ด ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")
210
+ return False
211
+
212
+ # ์š”์•ฝ ์„ค์ •
213
+ config = SummaryConfig(
214
+ max_length=max_length,
215
+ min_length=100,
216
+ do_sample=False,
217
+ temperature=0.7,
218
+ top_p=0.9
219
+ )
220
+
221
+ # summarizers๋ฅผ ์‚ฌ์šฉํ•œ ์š”์•ฝ
222
+ summary = text_summarizer.summarize_text(conversation_text, config=config)
223
+
224
+ if summary and len(summary.strip()) > 0:
225
+ # ํ•ต์‹ฌ ์ฃผ์ œ ์ถ”์ถœ
226
+ key_topics = text_summarizer.extract_key_points(conversation_text, max_points=3)
227
+
228
+ # ์š”์•ฝ ์—…๋ฐ์ดํŠธ
229
+ success = self.room_context_manager.update_conversation_summary(
230
+ room_id, summary.strip(), key_topics
231
+ )
232
+
233
+ if success:
234
+ logger.info(f"โœ… ์Šค๋งˆํŠธ ๋Œ€ํ™” ์š”์•ฝ ์ƒ์„ฑ ์™„๋ฃŒ: {room_id} - {len(summary)} ๋ฌธ์ž")
235
+ return True
236
+ else:
237
+ logger.error("๋Œ€ํ™” ์š”์•ฝ ์—…๋ฐ์ดํŠธ ์‹คํŒจ")
238
+ return False
239
+ else:
240
+ logger.warning("์š”์•ฝ ์ƒ์„ฑ ์‹คํŒจ")
241
+ return False
242
+
243
+ except Exception as e:
244
+ logger.error(f"โŒ ์Šค๋งˆํŠธ ๋Œ€ํ™” ์š”์•ฝ ์ƒ์„ฑ ์‹คํŒจ: {room_id} - {e}")
245
+ return False
246
+
247
+ def compress_room_context(self, room_id: str, target_length: int = 800) -> bool:
248
+ """๐Ÿ”„ ์ฑ„ํŒ…๋ฐฉ ์ปจํ…์ŠคํŠธ ์••์ถ• (๋ฉ”๋ชจ๋ฆฌ ์ตœ์ ํ™”)"""
249
+ try:
250
+ if not text_summarizer.is_available():
251
+ logger.warning("summarizers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
252
+ return False
253
+
254
+ # ์ฑ„ํŒ…๋ฐฉ ์ปจํ…์ŠคํŠธ ์กฐํšŒ
255
+ room_context = self.room_context_manager.get_room_context(room_id)
256
+ if not room_context:
257
+ logger.warning(f"์ฑ„ํŒ…๋ฐฉ ์ปจํ…์ŠคํŠธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {room_id}")
258
+ return False
259
+
260
+ # ํ˜„์žฌ ์ปจํ…์ŠคํŠธ ์ •๋ณด ์ˆ˜์ง‘
261
+ context_parts = []
262
+
263
+ if hasattr(room_context, 'room_name') and room_context.room_name:
264
+ context_parts.append(f"์ฑ„ํŒ…๋ฐฉ: {room_context.room_name}")
265
+
266
+ if hasattr(room_context, 'description') and room_context.description:
267
+ context_parts.append(f"์„ค๋ช…: {room_context.description}")
268
+
269
+ if hasattr(room_context, 'conversation_summary') and room_context.conversation_summary:
270
+ context_parts.append(f"๋Œ€ํ™” ์š”์•ฝ: {room_context.conversation_summary}")
271
+
272
+ if hasattr(room_context, 'key_topics') and room_context.key_topics:
273
+ context_parts.append(f"์ฃผ์š” ์ฃผ์ œ: {', '.join(room_context.key_topics)}")
274
+
275
+ if not context_parts:
276
+ logger.debug("์••์ถ•ํ•  ์ปจํ…์ŠคํŠธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.")
277
+ return False
278
+
279
+ # ์ปจํ…์ŠคํŠธ๋ฅผ ํ•˜๋‚˜์˜ ํ…์ŠคํŠธ๋กœ ๊ฒฐํ•ฉ
280
+ full_context = "\n".join(context_parts)
281
+
282
+ if len(full_context) <= target_length:
283
+ logger.debug("์ปจํ…์ŠคํŠธ๊ฐ€ ์ด๋ฏธ ์ถฉ๋ถ„ํžˆ ์งง์Šต๋‹ˆ๋‹ค.")
284
+ return False
285
+
286
+ # ์••์ถ• ์ˆ˜ํ–‰
287
+ compressed = text_summarizer.compress_document_content(full_context, target_length)
288
+
289
+ if compressed and len(compressed) <= target_length:
290
+ # ์••์ถ•๋œ ์ปจํ…์ŠคํŠธ๋กœ ์—…๋ฐ์ดํŠธ
291
+ # (์‹ค์ œ๋กœ๋Š” ๋ณ„๋„ ํ•„๋“œ์— ์ €์žฅํ•˜๊ฑฐ๋‚˜ ์••์ถ• ํžˆ์Šคํ† ๋ฆฌ ๊ด€๋ฆฌ)
292
+ logger.info(f"โœ… ์ฑ„ํŒ…๋ฐฉ ์ปจํ…์ŠคํŠธ ์••์ถ• ์™„๋ฃŒ: {room_id} - {len(full_context)} โ†’ {len(compressed)} ๋ฌธ์ž")
293
+ return True
294
+ else:
295
+ logger.warning("์ปจํ…์ŠคํŠธ ์••์ถ• ์‹คํŒจ")
296
+ return False
297
+
298
+ except Exception as e:
299
+ logger.error(f"โŒ ์ฑ„ํŒ…๋ฐฉ ์ปจํ…์ŠคํŠธ ์••์ถ• ์‹คํŒจ: {room_id} - {e}")
300
+ return False
301
+
302
  def get_context_for_ai(self, user_id: str, room_id: str, session_id: str,
303
  include_user_memory: bool = True,
304
  include_room_context: bool = True,
lily_llm_core/text_summarizer.py ADDED
@@ -0,0 +1,265 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ ํ…์ŠคํŠธ ์š”์•ฝ ๋ฐ ์••์ถ• ๋ชจ๋“ˆ
4
+ summarizers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ปจํ…์ŠคํŠธ ๋ฉ”๋ชจ๋ฆฌ์™€ ๋ฌธ์„œ ๋‚ด์šฉ์„ ํšจ์œจ์ ์œผ๋กœ ์••์ถ•
5
+ """
6
+
7
+ import logging
8
+ import time
9
+ from typing import Dict, Any, List, Optional, Union
10
+ from dataclasses import dataclass
11
+
12
+ # ๐Ÿ”„ summarizers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ import ์‹œ๋„
13
+ SUMMARIZERS_AVAILABLE = False
14
+ Summarizers = None
15
+
16
+ try:
17
+ print("๐Ÿ” summarizers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ import ์‹œ๋„ ์ค‘...")
18
+ from summarizers import Summarizers
19
+ SUMMARIZERS_AVAILABLE = True
20
+ print("โœ… summarizers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ import ์„ฑ๊ณต!")
21
+ except ImportError as e:
22
+ print(f"โŒ summarizers import ์‹คํŒจ: {e}")
23
+ SUMMARIZERS_AVAILABLE = False
24
+ except Exception as e:
25
+ print(f"โš ๏ธ summarizers import ์ค‘ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์˜ค๋ฅ˜: {e}")
26
+ SUMMARIZERS_AVAILABLE = False
27
+
28
+ logger = logging.getLogger(__name__)
29
+
30
+ @dataclass
31
+ class SummaryConfig:
32
+ """์š”์•ฝ ์„ค์ •"""
33
+ max_length: int = 150 # ์ตœ๋Œ€ ์š”์•ฝ ๊ธธ์ด
34
+ min_length: int = 30 # ์ตœ์†Œ ์š”์•ฝ ๊ธธ์ด
35
+ do_sample: bool = False # ์ƒ˜ํ”Œ๋ง ์‚ฌ์šฉ ์—ฌ๋ถ€
36
+ temperature: float = 1.0 # ์˜จ๋„ (๋†’์„์ˆ˜๋ก ๋‹ค์–‘์„ฑ ์ฆ๊ฐ€)
37
+ top_p: float = 0.9 # top-p ์ƒ˜ํ”Œ๋ง
38
+ repetition_penalty: float = 1.0 # ๋ฐ˜๋ณต ํŒจ๋„ํ‹ฐ
39
+
40
+ class TextSummarizer:
41
+ """ํ…์ŠคํŠธ ์š”์•ฝ ๋ฐ ์••์ถ• ๊ด€๋ฆฌ์ž"""
42
+
43
+ def __init__(self):
44
+ self.summarizers: Dict[str, Any] = {}
45
+ self.default_model = "hyunwoongko/kobart" # ๊ธฐ๋ณธ ํ•œ๊ตญ์–ด ๋ชจ๋ธ
46
+
47
+ print(f"๐Ÿ” TextSummarizer ์ดˆ๊ธฐํ™” - SUMMARIZERS_AVAILABLE: {SUMMARIZERS_AVAILABLE}")
48
+
49
+ # ๐Ÿ”’ AI ๋ชจ๋ธ ๋กœ๋”ฉ ๋น„ํ™œ์„ฑํ™” (PyTorch ๋ฒ„์ „ ๋ฌธ์ œ๋กœ ์ธํ•ด)
50
+ # if SUMMARIZERS_AVAILABLE and Summarizers is not None:
51
+ # self._initialize_summarizers()
52
+ # else:
53
+ # logger.warning("summarizers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
54
+ # print("โš ๏ธ summarizers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
55
+
56
+ print("๐Ÿ”„ ๊ฐ„๋‹จํ•œ ๊ทœ์น™ ๊ธฐ๋ฐ˜ ์š”์•ฝ๋งŒ ์‚ฌ์šฉ (AI ๋ชจ๋ธ ๋กœ๋”ฉ ๋น„ํ™œ์„ฑํ™”)")
57
+ logger.info("๊ฐ„๋‹จํ•œ ๊ทœ์น™ ๊ธฐ๋ฐ˜ ์š”์•ฝ๋งŒ ์‚ฌ์šฉ (AI ๋ชจ๋ธ ๋กœ๋”ฉ ๋น„ํ™œ์„ฑํ™”)")
58
+
59
+ def _initialize_summarizers(self):
60
+ """์š”์•ฝ ๋ชจ๋ธ ์ดˆ๊ธฐํ™”"""
61
+ try:
62
+ print("๐Ÿ” ์š”์•ฝ ๋ชจ๋ธ ์ดˆ๊ธฐํ™” ์‹œ์ž‘...")
63
+
64
+ # ๊ธฐ๋ณธ ํ•œ๊ตญ์–ด ๋ชจ๋ธ (normal ํƒ€์ž… ์‚ฌ์šฉ)
65
+ print(f"๐Ÿ” KoBART ๋ชจ๋ธ ๋กœ๋”ฉ ์‹œ๋„: normal ํƒ€์ž…")
66
+ self.summarizers["kobart"] = Summarizers(type="normal", device="cpu")
67
+ logger.info(f"โœ… KoBART ์š”์•ฝ ๋ชจ๋ธ ์ดˆ๊ธฐํ™” ์™„๋ฃŒ: normal ํƒ€์ž…")
68
+ print(f"โœ… KoBART ์š”์•ฝ ๋ชจ๋ธ ์ดˆ๊ธฐํ™” ์™„๋ฃŒ: normal ํƒ€์ž…")
69
+
70
+ # ์ถ”๊ฐ€ ๋ชจ๋ธ๋“ค (ํ•„์š”์‹œ)
71
+ # self.summarizers["paper"] = Summarizers(type="paper", device="cpu")
72
+ # self.summarizers["patent"] = Summarizers(type="patent", device="cpu")
73
+
74
+ except Exception as e:
75
+ logger.error(f"โŒ ์š”์•ฝ ๋ชจ๋ธ ์ดˆ๊ธฐํ™” ์‹คํŒจ: {e}")
76
+ print(f"โŒ ์š”์•ฝ ๋ชจ๋ธ ์ดˆ๊ธฐํ™” ์‹คํŒจ: {e}")
77
+ print("โš ๏ธ PyTorch ๋ฒ„์ „ ๋ฌธ์ œ๋กœ ์ธํ•ด ๊ฐ„๋‹จํ•œ ์š”์•ฝ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.")
78
+ SUMMARIZERS_AVAILABLE = False
79
+
80
+ def _simple_summarize(self, text: str, max_length: int = 200) -> str:
81
+ """๊ฐ„๋‹จํ•œ ๊ทœ์น™ ๊ธฐ๋ฐ˜ ์š”์•ฝ (AI ๋ชจ๋ธ ์‹คํŒจ ์‹œ ์‚ฌ์šฉ)"""
82
+ if len(text) <= max_length:
83
+ return text
84
+
85
+ # ๋ฌธ์žฅ ๋‹จ์œ„๋กœ ๋ถ„๋ฆฌ
86
+ sentences = text.split('.')
87
+ sentences = [s.strip() for s in sentences if s.strip()]
88
+
89
+ if len(sentences) <= 2:
90
+ return text[:max_length] + "..." if len(text) > max_length else text
91
+
92
+ # ์ฒซ ๋ฒˆ์งธ์™€ ๋งˆ์ง€๋ง‰ ๋ฌธ์žฅ + ์ค‘๊ฐ„ ์š”์•ฝ
93
+ first_sentence = sentences[0]
94
+ last_sentence = sentences[-1] if sentences[-1] != first_sentence else ""
95
+
96
+ middle_summary = ""
97
+ if len(sentences) > 2:
98
+ middle_count = len(sentences) - 2
99
+ middle_summary = f"[์ค‘๊ฐ„ {middle_count}๊ฐœ ๋ฌธ์žฅ ์š”์•ฝ]"
100
+
101
+ summary_parts = [first_sentence]
102
+ if middle_summary:
103
+ summary_parts.append(middle_summary)
104
+ if last_sentence and last_sentence != first_sentence:
105
+ summary_parts.append(last_sentence)
106
+
107
+ summary = ". ".join(summary_parts)
108
+ return summary[:max_length] + "..." if len(summary) > max_length else summary
109
+
110
+ def summarize_text(self, text: str, model_name: str = "kobart",
111
+ config: Optional[SummaryConfig] = None) -> Optional[str]:
112
+ """ํ…์ŠคํŠธ ์š”์•ฝ ์ˆ˜ํ–‰"""
113
+ if not text or len(text.strip()) < 50:
114
+ logger.debug("ํ…์ŠคํŠธ๊ฐ€ ๋„ˆ๋ฌด ์งง์•„ ์š”์•ฝ์„ ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.")
115
+ return text
116
+
117
+ # ์„ค์ • ์ ์šฉ
118
+ if config is None:
119
+ config = SummaryConfig()
120
+
121
+ # ๐Ÿ”’ AI ๋ชจ๋ธ ๊ธฐ๋ฐ˜ ์š”์•ฝ ๋น„ํ™œ์„ฑํ™” (PyTorch ๋ฒ„์ „ ๋ฌธ์ œ๋กœ ์ธํ•ด)
122
+ # AI ๋ชจ๋ธ ๊ธฐ๋ฐ˜ ์š”์•ฝ ์‹œ๋„
123
+ # if SUMMARIZERS_AVAILABLE and model_name in self.summarizers:
124
+ # try:
125
+ # summarizer = self.summarizers[model_name]
126
+ #
127
+ # # ์š”์•ฝ ์ˆ˜ํ–‰ (Summarizers์˜ __call__ ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ)
128
+ # start_time = time.time()
129
+ # summary = summarizer(
130
+ # contents=text,
131
+ # num_beams=5,
132
+ # top_k=config.top_p * 100 if config.top_p else None,
133
+ # top_p=config.top_p,
134
+ # no_repeat_ngram_size=4,
135
+ # length_penalty=1.0,
136
+ # question_detection=False
137
+ # )
138
+ #
139
+ # processing_time = time.time() - start_time
140
+ #
141
+ # # ์š”์•ฝ ๊ฒฐ๊ณผ ๊ฒ€์ฆ
142
+ # if summary and len(summary.strip()) > 0:
143
+ # compression_ratio = len(summary) / len(summary)
144
+ # logger.info(f"โœ… AI ๋ชจ๋ธ ์š”์•ฝ ์™„๋ฃŒ: {len(text)} โ†’ {len(summary)} ๋ฌธ์ž "
145
+ # f"(์••์ถ•๋ฅ : {compression_ratio:.2f}, ์†Œ์š”์‹œ๊ฐ„: {processing_time:.2f}์ดˆ)")
146
+ # return summary.strip()
147
+ # else:
148
+ # logger.warning("AI ๋ชจ๋ธ ์š”์•ฝ ๊ฒฐ๊ณผ๊ฐ€ ๋น„์–ด์žˆ์Šต๋‹ˆ๋‹ค.")
149
+ #
150
+ # except Exception as e:
151
+ # logger.warning(f"AI ๋ชจ๋ธ ์š”์•ฝ ์‹คํŒจ: {e}, ๊ฐ„๋‹จํ•œ ์š”์•ฝ ๋ฐฉ๋ฒ• ์‚ฌ์šฉ")
152
+
153
+ # ๊ฐ„๋‹จํ•œ ์š”์•ฝ ๋ฐฉ๋ฒ• ์‚ฌ์šฉ (AI ๋ชจ๋ธ ๋น„ํ™œ์„ฑํ™”)
154
+ logger.info("๐Ÿ”„ ๊ฐ„๋‹จํ•œ ๊ทœ์น™ ๊ธฐ๋ฐ˜ ์š”์•ฝ ์‚ฌ์šฉ (AI ๋ชจ๋ธ ๋น„ํ™œ์„ฑํ™”)")
155
+ return self._simple_summarize(text, config.max_length)
156
+
157
+ def summarize_conversation(self, conversation_turns: List[Dict[str, Any]],
158
+ max_summary_length: int = 200) -> str:
159
+ """๋Œ€ํ™” ๋‚ด์šฉ ์š”์•ฝ"""
160
+ if not conversation_turns:
161
+ return ""
162
+
163
+ try:
164
+ # ๋Œ€ํ™” ๋‚ด์šฉ์„ ํ•˜๋‚˜์˜ ํ…์ŠคํŠธ๋กœ ๊ฒฐํ•ฉ
165
+ conversation_text = ""
166
+ for turn in conversation_turns[-10:]: # ์ตœ๊ทผ 10ํ„ด๋งŒ
167
+ if "user" in turn:
168
+ conversation_text += f"์‚ฌ์šฉ์ž: {turn['user']}\n"
169
+ if "assistant" in turn:
170
+ conversation_text += f"AI: {turn['assistant']}\n"
171
+
172
+ if len(conversation_text.strip()) < 100:
173
+ return conversation_text.strip()
174
+
175
+ # ์š”์•ฝ ์„ค์ •
176
+ config = SummaryConfig(
177
+ max_length=max_summary_length,
178
+ min_length=50,
179
+ do_sample=False,
180
+ temperature=0.7
181
+ )
182
+
183
+ # ์š”์•ฝ ์ˆ˜ํ–‰
184
+ summary = self.summarize_text(conversation_text, config=config)
185
+ return summary if summary else conversation_text[:max_summary_length] + "..."
186
+
187
+ except Exception as e:
188
+ logger.error(f"โŒ ๋Œ€ํ™” ์š”์•ฝ ์‹คํŒจ: {e}")
189
+ return conversation_text[:max_summary_length] + "..." if conversation_text else ""
190
+
191
+ def compress_document_content(self, content: str, target_length: int = 1000) -> str:
192
+ """๋ฌธ์„œ ๋‚ด์šฉ ์••์ถ• (RAG ์ปจํ…์ŠคํŠธ์šฉ)"""
193
+ if not content or len(content) <= target_length:
194
+ return content
195
+
196
+ try:
197
+ # ์••์ถ•๋ฅ  ๊ณ„์‚ฐ
198
+ compression_ratio = target_length / len(content)
199
+
200
+ # ์š”์•ฝ ์„ค์ • (์••์ถ•์— ์ตœ์ ํ™”)
201
+ config = SummaryConfig(
202
+ max_length=target_length,
203
+ min_length=target_length // 2,
204
+ do_sample=False,
205
+ temperature=0.5, # ์ผ๊ด€์„ฑ ์œ ์ง€
206
+ top_p=0.8
207
+ )
208
+
209
+ # ์š”์•ฝ ์ˆ˜ํ–‰
210
+ compressed = self.summarize_text(content, config=config)
211
+
212
+ if compressed and len(compressed) <= target_length:
213
+ logger.info(f"โœ… ๋ฌธ์„œ ์••์ถ• ์™„๋ฃŒ: {len(content)} โ†’ {len(compressed)} ๋ฌธ์ž "
214
+ f"(๋ชฉํ‘œ: {target_length}, ์••์ถ•๋ฅ : {compression_ratio:.2f})")
215
+ return compressed
216
+ else:
217
+ # ์š”์•ฝ์ด ์‹คํŒจํ•˜๊ฑฐ๋‚˜ ๋„ˆ๋ฌด ๊ธธ๋ฉด ๋‹จ์ˆœ ์ž๋ฅด๊ธฐ
218
+ logger.warning("์š”์•ฝ ์••์ถ• ์‹คํŒจ, ๋‹จ์ˆœ ์ž๋ฅด๊ธฐ ์‚ฌ์šฉ")
219
+ return content[:target_length] + "..."
220
+
221
+ except Exception as e:
222
+ logger.error(f"โŒ ๋ฌธ์„œ ์••์ถ• ์‹คํŒจ: {e}")
223
+ return content[:target_length] + "..."
224
+
225
+ def extract_key_points(self, text: str, max_points: int = 5) -> List[str]:
226
+ """ํ•ต์‹ฌ ํฌ์ธํŠธ ์ถ”์ถœ"""
227
+ if not text or len(text.strip()) < 100:
228
+ return []
229
+
230
+ try:
231
+ # ์งง์€ ์š”์•ฝ์œผ๋กœ ํ•ต์‹ฌ ํฌ์ธํŠธ ์ƒ์„ฑ
232
+ config = SummaryConfig(
233
+ max_length=100,
234
+ min_length=30,
235
+ do_sample=True,
236
+ temperature=0.8
237
+ )
238
+
239
+ summary = self.summarize_text(text, config=config)
240
+ if not summary:
241
+ return []
242
+
243
+ # ์š”์•ฝ๋ฌธ์„ ๋ฌธ์žฅ ๋‹จ์œ„๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ํ•ต์‹ฌ ํฌ์ธํŠธ๋กœ ์‚ฌ์šฉ
244
+ points = [s.strip() for s in summary.split('.') if s.strip()]
245
+ return points[:max_points]
246
+
247
+ except Exception as e:
248
+ logger.error(f"โŒ ํ•ต์‹ฌ ํฌ์ธํŠธ ์ถ”์ถœ ์‹คํŒจ: {e}")
249
+ return []
250
+
251
+ def get_available_models(self) -> List[str]:
252
+ """์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ชจ๋ธ ๋ชฉ๋ก ๋ฐ˜ํ™˜"""
253
+ return list(self.summarizers.keys())
254
+
255
+ def is_available(self) -> bool:
256
+ """์š”์•ฝ ๊ธฐ๋Šฅ ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์—ฌ๋ถ€"""
257
+ # ๐Ÿ”’ AI ๋ชจ๋ธ ๋น„ํ™œ์„ฑํ™”๋กœ ์ธํ•ด ๊ฐ„๋‹จํ•œ ์š”์•ฝ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
258
+ available = True # ๊ฐ„๋‹จํ•œ ์š”์•ฝ์€ ํ•ญ์ƒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
259
+ print(f"๐Ÿ” TextSummarizer.is_available() ํ˜ธ์ถœ - ๊ฒฐ๊ณผ: {available} (๊ฐ„๋‹จํ•œ ์š”์•ฝ๋งŒ)")
260
+ return available
261
+
262
+ # ์ „์—ญ ์ธ์Šคํ„ด์Šค
263
+ print("๐Ÿ” TextSummarizer ์ „์—ญ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ์ค‘...")
264
+ text_summarizer = TextSummarizer()
265
+ print(f"๐Ÿ” TextSummarizer ์ƒ์„ฑ ์™„๋ฃŒ - ์‚ฌ์šฉ ๊ฐ€๋Šฅ: {text_summarizer.is_available()}")
lily_llm_core/user_memory_manager.py CHANGED
@@ -45,6 +45,9 @@ class UserMemory:
45
  ai_personality: Optional[str] = None
46
  ai_response_style: Optional[str] = None
47
 
 
 
 
48
  def __post_init__(self):
49
  if self.preferences is None:
50
  self.preferences = {}
@@ -279,6 +282,47 @@ class UserMemoryManager:
279
  logger.error(f"โŒ ์‚ฌ์šฉ์ž ๋ชฉ๋ก ์กฐํšŒ ์‹คํŒจ: {e}")
280
  return []
281
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
282
  def delete_user_memory(self, user_id: str) -> bool:
283
  """์‚ฌ์šฉ์ž ๋ฉ”๋ชจ๋ฆฌ ์‚ญ์ œ"""
284
  try:
 
45
  ai_personality: Optional[str] = None
46
  ai_response_style: Optional[str] = None
47
 
48
+ # Room ์ด๋™ ์‹œ ๋ฉ”๋ชจ๋ฆฌ ์œ ์ง€ ์„ค์ •
49
+ keep_memory_on_room_change: bool = True # ๊ธฐ๋ณธ๊ฐ’: True (๋ฉ”๋ชจ๋ฆฌ ์œ ์ง€)
50
+
51
  def __post_init__(self):
52
  if self.preferences is None:
53
  self.preferences = {}
 
282
  logger.error(f"โŒ ์‚ฌ์šฉ์ž ๋ชฉ๋ก ์กฐํšŒ ์‹คํŒจ: {e}")
283
  return []
284
 
285
+ def update_memory_setting(self, user_id: str, setting_name: str, value: Any) -> bool:
286
+ """์‚ฌ์šฉ์ž ๋ฉ”๋ชจ๋ฆฌ ์„ค์ • ์—…๋ฐ์ดํŠธ"""
287
+ try:
288
+ memory = self.get_user_memory(user_id)
289
+
290
+ if hasattr(memory, setting_name):
291
+ setattr(memory, setting_name, value)
292
+ memory.last_updated = time.time()
293
+
294
+ # ํŒŒ์ผ์— ์ €์žฅ
295
+ self._save_memory_to_file(memory)
296
+
297
+ # ์บ์‹œ ์—…๋ฐ์ดํŠธ
298
+ if user_id in self.memory_cache:
299
+ self.memory_cache[user_id] = memory
300
+
301
+ logger.info(f"โœ… ๋ฉ”๋ชจ๋ฆฌ ์„ค์ • ์—…๋ฐ์ดํŠธ: {user_id} - {setting_name} = {value}")
302
+ return True
303
+ else:
304
+ logger.warning(f"โš ๏ธ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์„ค์ •: {setting_name}")
305
+ return False
306
+
307
+ except Exception as e:
308
+ logger.error(f"โŒ ๋ฉ”๋ชจ๋ฆฌ ์„ค์ • ์—…๋ฐ์ดํŠธ ์‹คํŒจ: {user_id} - {setting_name} - {e}")
309
+ return False
310
+
311
+ def get_memory_setting(self, user_id: str, setting_name: str) -> Any:
312
+ """์‚ฌ์šฉ์ž ๋ฉ”๋ชจ๋ฆฌ ์„ค์ • ์กฐํšŒ"""
313
+ try:
314
+ memory = self.get_user_memory(user_id)
315
+
316
+ if hasattr(memory, setting_name):
317
+ return getattr(memory, setting_name)
318
+ else:
319
+ logger.warning(f"โš ๏ธ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์„ค์ •: {setting_name}")
320
+ return None
321
+
322
+ except Exception as e:
323
+ logger.error(f"โŒ ๋ฉ”๋ชจ๋ฆฌ ์„ค์ • ์กฐํšŒ ์‹คํŒจ: {user_id} - {setting_name} - {e}")
324
+ return None
325
+
326
  def delete_user_memory(self, user_id: str) -> bool:
327
  """์‚ฌ์šฉ์ž ๋ฉ”๋ชจ๋ฆฌ ์‚ญ์ œ"""
328
  try:
requirements.txt CHANGED
@@ -52,4 +52,7 @@ psutil
52
  python-json-logger
53
  PyJWT
54
  einops
55
- timm
 
 
 
 
52
  python-json-logger
53
  PyJWT
54
  einops
55
+ timm
56
+
57
+ # summarizers
58
+ summarizers
requirements_full_lily_250823_0436_summarizers.txt ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ accelerate==1.10.0
2
+ aiofiles==24.1.0
3
+ aiohappyeyeballs==2.6.1
4
+ aiohttp==3.12.15
5
+ aiosignal==1.4.0
6
+ amqp==5.3.1
7
+ annotated-types==0.7.0
8
+ anyio==4.10.0
9
+ attrs==25.3.0
10
+ backoff==2.2.1
11
+ bcrypt==4.3.0
12
+ beautifulsoup4==4.13.4
13
+ billiard==4.2.1
14
+ bitsandbytes==0.47.0
15
+ celery==5.5.3
16
+ certifi==2025.8.3
17
+ cffi==1.17.1
18
+ charset-normalizer==3.4.3
19
+ click==8.2.1
20
+ click-didyoumean==0.3.1
21
+ click-plugins==1.1.1.2
22
+ click-repl==0.3.0
23
+ colorama==0.4.6
24
+ cryptography==45.0.6
25
+ dataclasses-json==0.6.7
26
+ easyocr==1.7.2
27
+ ecdsa==0.19.1
28
+ einops==0.8.1
29
+ emoji==2.14.1
30
+ faiss-cpu==1.12.0
31
+ fastapi==0.116.1
32
+ filelock==3.19.1
33
+ filetype==1.2.0
34
+ frozenlist==1.7.0
35
+ fsspec==2025.7.0
36
+ greenlet==3.2.4
37
+ h11==0.16.0
38
+ html5lib==1.1
39
+ httpcore==1.0.9
40
+ httptools==0.6.4
41
+ httpx==0.28.1
42
+ httpx-sse==0.4.1
43
+ huggingface-hub==0.34.4
44
+ idna==3.10
45
+ imageio==2.37.0
46
+ intel-openmp==2021.4.0
47
+ Jinja2==3.1.6
48
+ joblib==1.5.1
49
+ jsonpatch==1.33
50
+ jsonpointer==3.0.0
51
+ kombu==5.5.4
52
+ langchain==0.3.27
53
+ langchain-community==0.3.27
54
+ langchain-core==0.3.74
55
+ langchain-text-splitters==0.3.9
56
+ langdetect==1.0.9
57
+ langsmith==0.4.14
58
+ lazy_loader==0.4
59
+ lxml==6.0.0
60
+ markdown-it-py==3.0.0
61
+ MarkupSafe==3.0.2
62
+ marshmallow==3.26.1
63
+ mdurl==0.1.2
64
+ mkl==2021.4.0
65
+ mpmath==1.3.0
66
+ multidict==6.6.4
67
+ mypy_extensions==1.1.0
68
+ networkx==3.5
69
+ ninja==1.13.0
70
+ nltk==3.9.1
71
+ numpy==1.26.4
72
+ olefile==0.47
73
+ opencv-python-headless==4.11.0.86
74
+ orjson==3.11.2
75
+ packaging==25.0
76
+ pandas==2.3.1
77
+ passlib==1.7.4
78
+ peft==0.15.0
79
+ pillow==11.3.0
80
+ prompt_toolkit==3.0.51
81
+ propcache==0.3.2
82
+ psutil==7.0.0
83
+ pyasn1==0.6.1
84
+ pyclipper==1.3.0.post6
85
+ pycparser==2.22
86
+ pydantic==2.11.7
87
+ pydantic-settings==2.10.1
88
+ pydantic_core==2.33.2
89
+ PyJWT==2.10.1
90
+ PyMuPDF==1.26.3
91
+ pypdf==6.0.0
92
+ pytesseract==0.3.13
93
+ python-bidi==0.6.6
94
+ python-dateutil==2.9.0.post0
95
+ python-docx==1.2.0
96
+ python-dotenv==1.1.1
97
+ python-iso639==2025.2.18
98
+ python-jose==3.5.0
99
+ python-json-logger==3.3.0
100
+ python-magic==0.4.27
101
+ python-multipart==0.0.20
102
+ python-oxmsg==0.0.2
103
+ python-pptx==1.0.2
104
+ pytz==2025.2
105
+ PyYAML==6.0.2
106
+ RapidFuzz==3.13.0
107
+ redis==6.4.0
108
+ regex==2025.7.34
109
+ requests==2.32.5
110
+ requests-toolbelt==1.0.0
111
+ rsa==4.9.1
112
+ safetensors==0.6.2
113
+ scikit-image==0.25.2
114
+ scikit-learn==1.7.1
115
+ scipy==1.16.1
116
+ sentence-transformers==2.2.2
117
+ sentencepiece==0.2.1
118
+ shapely==2.1.1
119
+ six==1.17.0
120
+ sniffio==1.3.1
121
+ soupsieve==2.7
122
+ SQLAlchemy==2.0.43
123
+ starlette==0.47.2
124
+ summarizers==1.0.4
125
+ sympy==1.14.0
126
+ tbb==2021.13.1
127
+ tenacity==9.1.2
128
+ threadpoolctl==3.6.0
129
+ tifffile==2025.6.11
130
+ timm==1.0.19
131
+ tokenizers==0.21.4
132
+ torch==2.3.1
133
+ torchvision==0.18.1
134
+ tqdm==4.67.1
135
+ transformers==4.55.2
136
+ typing-inspect==0.9.0
137
+ typing-inspection==0.4.1
138
+ typing_extensions==4.14.1
139
+ tzdata==2025.2
140
+ unstructured==0.18.13
141
+ unstructured-client==0.42.3
142
+ urllib3==2.5.0
143
+ uvicorn==0.35.0
144
+ vine==5.1.0
145
+ watchfiles==1.1.0
146
+ wcwidth==0.2.13
147
+ webencodings==0.5.1
148
+ websockets==15.0.1
149
+ wrapt==1.17.3
150
+ xlsxwriter==3.2.5
151
+ yarl==1.20.1
152
+ zstandard==0.24.0
test_summarizers.py ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ summarizers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ…Œ์ŠคํŠธ ์Šคํฌ๋ฆฝํŠธ
4
+ """
5
+
6
+ import sys
7
+ import os
8
+
9
+ # ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ๋ฅผ Python ๊ฒฝ๋กœ์— ์ถ”๊ฐ€
10
+ sys.path.append(os.path.dirname(os.path.abspath(__file__)))
11
+
12
+ from lily_llm_core.text_summarizer import text_summarizer, SummaryConfig
13
+
14
+ def test_summarizers():
15
+ """summarizers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ธฐ๋ณธ ๊ธฐ๋Šฅ ํ…Œ์ŠคํŠธ"""
16
+ print("๐Ÿš€ summarizers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ…Œ์ŠคํŠธ ์‹œ์ž‘")
17
+ print("=" * 50)
18
+
19
+ # 1. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ƒํƒœ ํ™•์ธ
20
+ print("1. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ƒํƒœ ํ™•์ธ:")
21
+ available = text_summarizer.is_available()
22
+ print(f" - summarizers ์‚ฌ์šฉ ๊ฐ€๋Šฅ: {available}")
23
+
24
+ if available:
25
+ models = text_summarizer.get_available_models()
26
+ print(f" - ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ชจ๋ธ: {models}")
27
+ print(f" - ๊ธฐ๋ณธ ๋ชจ๋ธ: hyunwoongko/kobart")
28
+ else:
29
+ print(" โŒ summarizers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
30
+ return
31
+
32
+ print()
33
+
34
+ # 2. ๊ฐ„๋‹จํ•œ ํ…์ŠคํŠธ ์š”์•ฝ ํ…Œ์ŠคํŠธ
35
+ print("2. ๊ฐ„๋‹จํ•œ ํ…์ŠคํŠธ ์š”์•ฝ ํ…Œ์ŠคํŠธ:")
36
+ test_text = """
37
+ ์ธ๊ณต์ง€๋Šฅ(AI)์€ ์ปดํ“จํ„ฐ ์‹œ์Šคํ…œ์ด ์ธ๊ฐ„์˜ ํ•™์Šต๋Šฅ๋ ฅ๊ณผ ์ถ”๋ก ๋Šฅ๋ ฅ, ์ง€๊ฐ๋Šฅ๋ ฅ์„ ์ธ๊ณต์ ์œผ๋กœ ๊ตฌํ˜„ํ•œ ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค.
38
+ ๋จธ์‹ ๋Ÿฌ๋‹๊ณผ ๋”ฅ๋Ÿฌ๋‹์„ ํฌํ•จํ•˜์—ฌ ๋‹ค์–‘ํ•œ ๋ถ„์•ผ์—์„œ ํ™œ์šฉ๋˜๊ณ  ์žˆ์œผ๋ฉฐ,
39
+ ์ž์—ฐ์–ด ์ฒ˜๋ฆฌ, ์ปดํ“จํ„ฐ ๋น„์ „, ์Œ์„ฑ ์ธ์‹ ๋“ฑ์—์„œ ํ˜์‹ ์ ์ธ ์„ฑ๊ณผ๋ฅผ ๋ณด์—ฌ์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
40
+ ํŠนํžˆ ์ตœ๊ทผ์—๋Š” ๋Œ€ํ˜• ์–ธ์–ด ๋ชจ๋ธ(LLM)์˜ ๋ฐœ์ „์œผ๋กœ AI์˜ ํ™œ์šฉ ๋ฒ”์œ„๊ฐ€ ํฌ๊ฒŒ ํ™•์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
41
+ """
42
+
43
+ print(f" ์›๋ณธ ํ…์ŠคํŠธ ๊ธธ์ด: {len(test_text.strip())} ๋ฌธ์ž")
44
+
45
+ # ๊ธฐ๋ณธ ์š”์•ฝ
46
+ config = SummaryConfig(max_length=100, min_length=50)
47
+ summary = text_summarizer.summarize_text(test_text, config=config)
48
+
49
+ if summary:
50
+ print(f" ์š”์•ฝ ๊ฒฐ๊ณผ: {summary}")
51
+ print(f" ์š”์•ฝ ๊ธธ์ด: {len(summary)} ๋ฌธ์ž")
52
+ compression_ratio = len(summary) / len(test_text.strip())
53
+ print(f" ์••์ถ•๋ฅ : {compression_ratio:.2f}")
54
+ else:
55
+ print(" โŒ ์š”์•ฝ ์‹คํŒจ")
56
+
57
+ print()
58
+
59
+ # 3. ํ•ต์‹ฌ ํฌ์ธํŠธ ์ถ”์ถœ ํ…Œ์ŠคํŠธ
60
+ print("3. ํ•ต์‹ฌ ํฌ์ธํŠธ ์ถ”์ถœ ํ…Œ์ŠคํŠธ:")
61
+ key_points = text_summarizer.extract_key_points(test_text, max_points=3)
62
+
63
+ if key_points:
64
+ print(" ์ถ”์ถœ๋œ ํ•ต์‹ฌ ํฌ์ธํŠธ:")
65
+ for i, point in enumerate(key_points, 1):
66
+ print(f" {i}. {point}")
67
+ else:
68
+ print(" โŒ ํ•ต์‹ฌ ํฌ์ธํŠธ ์ถ”์ถœ ์‹คํŒจ")
69
+
70
+ print()
71
+
72
+ # 4. ๋ฌธ์„œ ์••์ถ• ํ…Œ์ŠคํŠธ
73
+ print("4. ๋ฌธ์„œ ์••์ถ• ํ…Œ์ŠคํŠธ:")
74
+ long_text = test_text * 3 # ๋” ๊ธด ํ…์ŠคํŠธ ์ƒ์„ฑ
75
+ print(f" ์›๋ณธ ํ…์ŠคํŠธ ๊ธธ์ด: {len(long_text)} ๋ฌธ์ž")
76
+
77
+ compressed = text_summarizer.compress_document_content(long_text, target_length=200)
78
+
79
+ if compressed:
80
+ print(f" ์••์ถ• ๊ฒฐ๊ณผ: {compressed}")
81
+ print(f" ์••์ถ• ๊ธธ์ด: {len(compressed)} ๋ฌธ์ž")
82
+ compression_ratio = len(compressed) / len(long_text)
83
+ print(f" ์••์ถ•๋ฅ : {compression_ratio:.2f}")
84
+ else:
85
+ print(" โŒ ์••์ถ• ์‹คํŒจ")
86
+
87
+ print()
88
+ print("โœ… ํ…Œ์ŠคํŠธ ์™„๋ฃŒ!")
89
+
90
+ if __name__ == "__main__":
91
+ test_summarizers()