{ "cells": [ { "cell_type": "code", "execution_count": null, "id": "initial_id", "metadata": { "collapsed": true }, "outputs": [], "source": "#### 소비자보호원 서비스집단 분쟁조정 사례집 RAG" }, { "metadata": { "ExecuteTime": { "end_time": "2026-06-01T06:59:17.174441968Z", "start_time": "2026-06-01T06:59:17.163725951Z" } }, "cell_type": "code", "source": [ "from langchain_ibm import ChatWatsonx\n", "from langchain_core.prompts import PromptTemplate, ChatPromptTemplate\n", "from langchain_core.output_parsers import StrOutputParser, JsonOutputParser, PydanticOutputParser\n", "from dotenv import load_dotenv\n", "import os\n", "\n", "from langchain_community.document_loaders import PyPDFLoader\n", "from langchain_text_splitters import RecursiveCharacterTextSplitter\n", "from langchain_ibm import WatsonxEmbeddings\n", "from langchain_chroma import Chroma\n", "\n", "from pydantic import BaseModel, Field\n", "from langchain_core.runnables import RunnablePassthrough\n", "\n", "import re\n", "from pprint import pprint" ], "id": "89613f4fba03e277", "outputs": [], "execution_count": 2 }, { "metadata": { "ExecuteTime": { "end_time": "2026-06-01T06:59:53.576580670Z", "start_time": "2026-06-01T06:59:53.567626272Z" } }, "cell_type": "code", "source": [ "# .env 내용 가져오기\n", "load_dotenv()\n", "\n", "apikey = os.getenv(\"WATSONX_API_KEY\")\n", "project_id = os.getenv(\"WATSONX_PROJECT_ID\")\n", "watsonx_ai_url = os.getenv(\"WATSONX_URL\")" ], "id": "d17eeb20eda6afa3", "outputs": [], "execution_count": 3 }, { "metadata": { "ExecuteTime": { "end_time": "2026-06-01T07:00:17.195193931Z", "start_time": "2026-06-01T07:00:12.976471076Z" } }, "cell_type": "code", "source": [ "watson_llm = ChatWatsonx(\n", " model_id=\"ibm/granite-4-h-small\",\n", " url = f\"{watsonx_ai_url}\",\n", " api_key = f\"{apikey}\",\n", " project_id=f\"{project_id}\",\n", " max_tokens = 2000,\n", " params = {\n", " \"temperature\":0\n", " }\n", ")\n", "\n", "watson_embedding = WatsonxEmbeddings(\n", " model_id=\"ibm/granite-embedding-278m-multilingual\",\n", " url = f\"{watsonx_ai_url}\",\n", " api_key = f\"{apikey}\",\n", " project_id=f\"{project_id}\"\n", ")" ], "id": "f132cf54f019bcfa", "outputs": [], "execution_count": 4 }, { "metadata": {}, "cell_type": "markdown", "source": "### 1. 문서 로드", "id": "3f5ffbefabd51421" }, { "metadata": { "ExecuteTime": { "end_time": "2026-06-01T07:04:30.219884334Z", "start_time": "2026-06-01T07:04:25.149502303Z" } }, "cell_type": "code", "source": [ "pdf_path = \"./data/2018 서비스·집단 분쟁조정 사례집.pdf\"\n", "\n", "# loader 선택 - pdf loader 선택 가능\n", "loader = PyPDFLoader(pdf_path)\n", "docs = loader.load()\n", "len(docs)" ], "id": "30842892e90d6b3f", "outputs": [ { "data": { "text/plain": [ "200" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "execution_count": 6 }, { "metadata": { "ExecuteTime": { "end_time": "2026-06-01T07:06:54.314061593Z", "start_time": "2026-06-01T07:06:54.303104782Z" } }, "cell_type": "code", "source": [ "# page_content / metadata 확인\n", "\n", "pprint(docs[0].page_content)\n", "pprint(docs[0].metadata)" ], "id": "cec836d370caf7b5", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "'소비자분쟁조정위원회\\n2018\\n서비스·집단 \\n분쟁조정 사례집'\n", "{'author': 'PC_A2',\n", " 'creationdate': '2019-06-05T11:33:24+09:00',\n", " 'creator': 'PScript5.dll Version 5.2.2',\n", " 'moddate': '2019-06-05T11:58:31+09:00',\n", " 'page': 0,\n", " 'page_label': '1',\n", " 'producer': 'Acrobat Distiller 9.0.0 (Windows)',\n", " 'source': './data/2018 서비스·집단 분쟁조정 사례집.pdf',\n", " 'title': '<32303139303630355FBCD2BAF1C0DABFF820BBE7B7CAC1FD5BBCADBAF1BDBA5D5FB3BBC1F65FC6EDC1FDBABB76657231312E687770>',\n", " 'total_pages': 200}\n" ] } ], "execution_count": 9 }, { "metadata": { "ExecuteTime": { "end_time": "2026-06-01T07:07:22.227432695Z", "start_time": "2026-06-01T07:07:22.209750745Z" } }, "cell_type": "code", "source": [ "# 첫번째 사건 가져오기\n", "pprint(docs[10].page_content)\n", "pprint(docs[10].metadata)" ], "id": "1b72feac194a7a49", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "('제1장\\n'\n", " '일\\n'\n", " '반\\n'\n", " '분\\n'\n", " '쟁\\n'\n", " '조\\n'\n", " '정\\n'\n", " ' 사\\n'\n", " '례 (\\n'\n", " '서\\n'\n", " '비\\n'\n", " '스 )\\n'\n", " '제1장 일반분쟁조정 사례(서비스) ● 3\\n'\n", " '사\\n'\n", " '례 01 사건번호 2018일나565 | 결정일자 2018. 8. 7.\\n'\n", " '세탁 후 갑피 마모 및 경화된 가죽 \\n'\n", " '운동화에 대한 손해배상 요구\\n'\n", " '주 문\\n'\n", " '1. 신청인은 2018. 10. 16.까지 피신청인에게 이 사건 제품(제품명 : ○○○○ 가죽 \\n'\n", " '운동화, 색상 : 흰색) 1켤레를 반환한다. \\n'\n", " '2. 피신청인은 신청인으로부터 제1항 제품을 반환받음과 동시에 신청인에게 71,000원\\n'\n", " '을 지급한다.\\n'\n", " '이 유\\n'\n", " '1. 기초사실\\n'\n", " '가. 신청인은 2017. 6. 6. 가죽 운동화(제품명 : ○○○○ 가죽 운동화, 색상 : 흰색, \\n'\n", " '이하 ‘이 사건 제품’) 1켤레를 160,200원에 구매하여 착화하였고, 2018. 1. 10. \\n'\n", " '피신청인에게 이 사건 제품의 세탁을 의뢰(세탁비 4,000원)하였는데 수령 후 갑피 \\n'\n", " '마모 및 경화된 사실(이하 ‘이 사건 현상’)을 확인하여 피신청인이 재세탁을 하였\\n'\n", " '으나, 이후에도 경화현상만 다소 개선될 뿐 갑피 마모 현상이 개선되지 않아 피신\\n'\n", " '청인에게 손해배상(세탁비 환급 포함)을 요구하였으며, 피신청인은 세탁과실이 없\\n'\n", " '다는 이유로 이를 거부하였다.\\n'\n", " '나. 한국소비자원 신발제품심의위원회 심의 결과는 다음과 같다.\\n'\n", " ' \\n'\n", " '신청인이 주장하는 갑피 벗겨짐(스크래치 등) 증상은 관찰되나 현 제품 상태만\\n'\n", " '으로는 제품 훼손의 원인이 세탁 과정상 발생한 것인지 착화 환경에 따른 문제\\n'\n", " '인지 단정하기 어려운바, 판단 불가하다.')\n", "{'author': 'PC_A2',\n", " 'creationdate': '2019-06-05T11:33:24+09:00',\n", " 'creator': 'PScript5.dll Version 5.2.2',\n", " 'moddate': '2019-06-05T11:58:31+09:00',\n", " 'page': 10,\n", " 'page_label': '11',\n", " 'producer': 'Acrobat Distiller 9.0.0 (Windows)',\n", " 'source': './data/2018 서비스·집단 분쟁조정 사례집.pdf',\n", " 'title': '<32303139303630355FBCD2BAF1C0DABFF820BBE7B7CAC1FD5BBCADBAF1BDBA5D5FB3BBC1F65FC6EDC1FDBABB76657231312E687770>',\n", " 'total_pages': 200}\n" ] } ], "execution_count": 10 }, { "metadata": {}, "cell_type": "markdown", "source": [ "### 전처리\n", "- 정규식을 이용한 내용 추출" ], "id": "ae4c70c9333416ce" }, { "metadata": { "ExecuteTime": { "end_time": "2026-06-01T07:16:39.554724455Z", "start_time": "2026-06-01T07:16:39.540073666Z" } }, "cell_type": "code", "source": [ "pattern = (r\"사\\n례\\s*\\d+.*사건번호.*결정일자.*\\d{4}\\.\\s?\\d{1,2}\\.\\s?\\d{1,2}\\.\")\n", "\n", "split_text = re.findall(pattern, \"\".join(docs[10].page_content))\n", "split_text" ], "id": "a785b6b9de3621b8", "outputs": [ { "data": { "text/plain": [ "['사\\n례 01 사건번호 2018일나565 | 결정일자 2018. 8. 7.']" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "execution_count": 12 }, { "metadata": { "ExecuteTime": { "end_time": "2026-06-01T07:19:05.532627365Z", "start_time": "2026-06-01T07:19:05.519326765Z" } }, "cell_type": "code", "source": [ "# 패턴이 존재한다면 패턴을 기준으로 문서를 분리\n", "if split_text:\n", " parts = re.split(pattern, \"\".join(docs[10].page_content))\n", "\n", "parts" ], "id": "c99bf389a324e659", "outputs": [ { "data": { "text/plain": [ "['제1장\\n일\\n반\\n분\\n쟁\\n조\\n정\\n 사\\n례 (\\n서\\n비\\n스 )\\n제1장 일반분쟁조정 사례(서비스) ● 3\\n',\n", " '\\n세탁 후 갑피 마모 및 경화된 가죽 \\n운동화에 대한 손해배상 요구\\n주 문\\n1. 신청인은 2018. 10. 16.까지 피신청인에게 이 사건 제품(제품명 : ○○○○ 가죽 \\n운동화, 색상 : 흰색) 1켤레를 반환한다. \\n2. 피신청인은 신청인으로부터 제1항 제품을 반환받음과 동시에 신청인에게 71,000원\\n을 지급한다.\\n이 유\\n1. 기초사실\\n가. 신청인은 2017. 6. 6. 가죽 운동화(제품명 : ○○○○ 가죽 운동화, 색상 : 흰색, \\n이하 ‘이 사건 제품’) 1켤레를 160,200원에 구매하여 착화하였고, 2018. 1. 10. \\n피신청인에게 이 사건 제품의 세탁을 의뢰(세탁비 4,000원)하였는데 수령 후 갑피 \\n마모 및 경화된 사실(이하 ‘이 사건 현상’)을 확인하여 피신청인이 재세탁을 하였\\n으나, 이후에도 경화현상만 다소 개선될 뿐 갑피 마모 현상이 개선되지 않아 피신\\n청인에게 손해배상(세탁비 환급 포함)을 요구하였으며, 피신청인은 세탁과실이 없\\n다는 이유로 이를 거부하였다.\\n나. 한국소비자원 신발제품심의위원회 심의 결과는 다음과 같다.\\n \\n신청인이 주장하는 갑피 벗겨짐(스크래치 등) 증상은 관찰되나 현 제품 상태만\\n으로는 제품 훼손의 원인이 세탁 과정상 발생한 것인지 착화 환경에 따른 문제\\n인지 단정하기 어려운바, 판단 불가하다.']" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "execution_count": 14 }, { "metadata": { "ExecuteTime": { "end_time": "2026-06-01T07:22:27.264658276Z", "start_time": "2026-06-01T07:22:27.257468833Z" } }, "cell_type": "code", "source": [ "# metadata 로 사용할 정보 추출\n", "# 사례번호, 사건번호, 결정일자 추출\n", "\n", "split_text[0]\n", "\n", "# 사례번호\n", "re.findall(r\"례\\s?(\\d+)\\s?사건번호\",split_text[0])[0]\n" ], "id": "ce6951444d08f2b6", "outputs": [ { "data": { "text/plain": [ "'01'" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "execution_count": 21 }, { "metadata": { "ExecuteTime": { "end_time": "2026-06-01T07:52:06.045867563Z", "start_time": "2026-06-01T07:52:06.002473096Z" } }, "cell_type": "code", "source": [ "# 사건번호, 결정일자 추출\n", "class CaseMetadata(BaseModel):\n", " case_number:str = Field(description=\"사건번호 예 : 2018일나565\")\n", " decision_data:str = Field(description=\"결정일자 예 : 2018. 8. 7.\")" ], "id": "3307d7b5484784ad", "outputs": [], "execution_count": 22 }, { "metadata": { "ExecuteTime": { "end_time": "2026-06-01T07:59:40.356630127Z", "start_time": "2026-06-01T07:59:38.540410130Z" } }, "cell_type": "code", "source": [ "metadata_prompt = PromptTemplate.from_template(\n", " \"\"\"\\\n", "다음은 분쟁 조정 사례에 대한 텍스트입니다.\\n\\n\n", "- case_number : 사건번호\n", "- decision_data : 결정일자\n", "\n", "반드시 Json 으로만 반환하세요\n", "{case_text}\n", " \"\"\"\n", ")\n", "\n", "structed_llm = watson_llm.with_structured_output(CaseMetadata)\n", "\n", "chain = metadata_prompt | structed_llm\n", "\n", "case_metadata = chain.invoke({\"case_text\":split_text[0]})\n", "print(case_metadata)\n", "print(dict(case_metadata))" ], "id": "4e881737f5b80b60", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "case_number='2018일나565' decision_data='2018. 8. 7.'\n", "{'case_number': '2018일나565', 'decision_data': '2018. 8. 7.'}\n" ] } ], "execution_count": 24 }, { "metadata": {}, "cell_type": "markdown", "source": "#### page_content 내용 추출", "id": "12f8b3079b5aaa19" }, { "metadata": { "ExecuteTime": { "end_time": "2026-06-01T08:04:16.872277043Z", "start_time": "2026-06-01T08:04:16.863977311Z" } }, "cell_type": "code", "source": [ "# 주 문 ~~~~\n", "parts[1]\n", "\n", "# 주 문 위치 찾기\n", "re.search(r\"주 문\\n\",parts[1]).span()\n", "\n", "# 제목 추출\n", "title = parts[1][:re.search(r\"주 문\\n\",parts[1]).span()[0]].strip()\n", "# 내용 추출\n", "content = parts[1][re.search(r\"주 문\\n\",parts[1]).span()[0]:].strip()" ], "id": "9f78f350f0583c6b", "outputs": [], "execution_count": 40 }, { "metadata": { "ExecuteTime": { "end_time": "2026-06-01T08:06:05.158453784Z", "start_time": "2026-06-01T08:06:05.144784923Z" } }, "cell_type": "code", "source": [ "pprint(title)\n", "pprint(content)" ], "id": "b460a6f62007935a", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "'세탁 후 갑피 마모 및 경화된 가죽 \\n운동화에 대한 손해배상 요구'\n", "('주 문\\n'\n", " '1. 신청인은 2018. 10. 16.까지 피신청인에게 이 사건 제품(제품명 : ○○○○ 가죽 \\n'\n", " '운동화, 색상 : 흰색) 1켤레를 반환한다. \\n'\n", " '2. 피신청인은 신청인으로부터 제1항 제품을 반환받음과 동시에 신청인에게 71,000원\\n'\n", " '을 지급한다.\\n'\n", " '이 유\\n'\n", " '1. 기초사실\\n'\n", " '가. 신청인은 2017. 6. 6. 가죽 운동화(제품명 : ○○○○ 가죽 운동화, 색상 : 흰색, \\n'\n", " '이하 ‘이 사건 제품’) 1켤레를 160,200원에 구매하여 착화하였고, 2018. 1. 10. \\n'\n", " '피신청인에게 이 사건 제품의 세탁을 의뢰(세탁비 4,000원)하였는데 수령 후 갑피 \\n'\n", " '마모 및 경화된 사실(이하 ‘이 사건 현상’)을 확인하여 피신청인이 재세탁을 하였\\n'\n", " '으나, 이후에도 경화현상만 다소 개선될 뿐 갑피 마모 현상이 개선되지 않아 피신\\n'\n", " '청인에게 손해배상(세탁비 환급 포함)을 요구하였으며, 피신청인은 세탁과실이 없\\n'\n", " '다는 이유로 이를 거부하였다.\\n'\n", " '나. 한국소비자원 신발제품심의위원회 심의 결과는 다음과 같다.\\n'\n", " ' \\n'\n", " '신청인이 주장하는 갑피 벗겨짐(스크래치 등) 증상은 관찰되나 현 제품 상태만\\n'\n", " '으로는 제품 훼손의 원인이 세탁 과정상 발생한 것인지 착화 환경에 따른 문제\\n'\n", " '인지 단정하기 어려운바, 판단 불가하다.')\n" ] } ], "execution_count": 42 }, { "metadata": { "ExecuteTime": { "end_time": "2026-06-01T08:43:23.992589505Z", "start_time": "2026-06-01T08:43:23.973999681Z" } }, "cell_type": "code", "source": [ "# 사례번호, 사건번호, 결정일자, 제목은 metadata로 추가\n", "# 내용은 page_content update\n", "\n", "pdf_docs = []\n", "case_metadata = {}\n", "\n", "# 사건이 시작되는 페이지 ~ 마지막에서 -2 페이지까지 반복\n", "for doc in docs[10:-2]:\n", "\n", " split_text = re.findall(pattern, \"\".join(doc.page_content))\n", "\n", " if split_text:\n", " # 사례번호 추출\n", " case_metadata[\"case_id\"] = re.findall(r\"례\\s?(\\d+)\\s?사건번호\",split_text[0])[0]\n", "\n", " # 패턴 기준으로 텍스트 분할\n", " parts = re.split(pattern, \"\".join(doc.page_content))\n", "\n", " if re.search(r\"주 문\\n\",parts[1]):\n", " # 제목 추출\n", " case_metadata[\"title\"] = parts[1][:re.search(r\"주 문\\n\",parts[1]).span()[0]].replace(\"\\n\",\"\").strip()\n", " # 내용 추출 후 기존 내용 업데이트\n", " doc.page_content = parts[1][re.search(r\"주 문\\n\",parts[1]).span()[0]:].strip()\n", " else:\n", " case_metadata[\"title\"] = \"\"\n", "\n", " i = 0\n", " while i < 10:\n", " try:\n", " # 사건번호, 결정일자 추출\n", " response = chain.invoke({\"case_text\":split_text[0]})\n", " for k, v in dict(response).items():\n", " case_metadata[k] = v.replace(\"\\n\",\"\").replace(\" \",\"\")\n", " break\n", "\n", " except:\n", " i += 1\n", " continue\n", "\n", " doc.metadata.update(case_metadata)\n", "\n", " pdf_docs.append(doc)\n", " else:\n", " doc.metadata.update(case_metadata)\n", " pdf_docs.append(doc)\n", "\n", "len(pdf_docs)\n" ], "id": "373a5284a8b88e6b", "outputs": [ { "data": { "text/plain": [ "188" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "execution_count": 68 }, { "metadata": { "ExecuteTime": { "end_time": "2026-06-01T08:43:27.932428458Z", "start_time": "2026-06-01T08:43:27.925707032Z" } }, "cell_type": "code", "source": [ "pdf_docs[10].metadata\n", "pprint(pdf_docs[9].page_content)" ], "id": "66a5877582de43f3", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "('주 문\\n'\n", " '신청인과 피신청인 사이의 이 사건 분쟁조정 신청에 대하여는 조정하지 아니한다.\\n'\n", " '이 유\\n'\n", " '1. 기초사실\\n'\n", " '신청인은 피신청인의 인천-도쿄 왕복항공권 4매(탑승객 : 이○○, 오○○, 이 ∆∆, 이\\n'\n", " '□□, 2017. 12. 18. 10:10 ○○703편 인천 출발, 2017. 12. 21. 17:00 ○○002 편 \\n'\n", " '도쿄 출발)를 628,200원에 구입하였고, 2018. 12. 18. 10:10 출발 예정이던 출국 항\\n'\n", " '공편(이하 ‘이 사건 항공편’이라고 함)이 기상악화로 인하여 지연되어 도착예정시간 \\n'\n", " '12:30보다 4시간 10분 지연된 16:40 도쿄에 도착하였다.\\n'\n", " '2 . 판 단\\n'\n", " '신청인은 이 사건 항공편이 4시간 이상 지연되었고, 이 사건 항공편보다 늦게 출발이 \\n'\n", " '예정되어 있는 항공기(오사카, 나고야행 등)가 먼저 출발하는 것을 확인하였으며, 기상\\n'\n", " '상황으로 인한 연결편 연착에 따른 지연이라는 피신청인의 주장을 납득할 수 없는바, \\n'\n", " '관련 법률에 따른 손해배상을 요구한다.\\n'\n", " '이에 대하여 피신청인은 이 사건 항공편 운송지연의 원인이 당시 인천공항에 강설로 \\n'\n", " '인한 극심한 혼잡과 제빙작업에 의한 것으로, 이는 기상상황으로 인한 지연에 해당하\\n'\n", " '여 「소비자분쟁해결기준」상 손해배상 사유에서 제외되는바, 신청인의 요구를 수용할 \\n'\n", " '수 없다고 주장한다.')\n" ] } ], "execution_count": 69 }, { "metadata": {}, "cell_type": "markdown", "source": "#### 2. 분할", "id": "824f2e5d6e5c66e9" }, { "metadata": { "ExecuteTime": { "end_time": "2026-06-01T08:46:16.624643520Z", "start_time": "2026-06-01T08:46:16.607920862Z" } }, "cell_type": "code", "source": [ "# 500 / 50\n", "\n", "splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)\n", "splite_docs = splitter.split_documents(docs)\n", "\n", "print(splite_docs[0].page_content)" ], "id": "baa5c4785395d7cb", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "소비자분쟁조정위원회\n", "2018\n", "서비스·집단 \n", "분쟁조정 사례집\n" ] } ], "execution_count": 74 }, { "metadata": { "ExecuteTime": { "end_time": "2026-06-01T08:47:24.940997646Z", "start_time": "2026-06-01T08:47:24.928360960Z" } }, "cell_type": "code", "source": "print(splite_docs[1].page_content)", "id": "b398473d9c9a0655", "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2018 분쟁조정 사례집\n", "소비자 관련 분쟁은 소액이라는 특징 때문에 법원의 소송으로 해결하기 어려운 면이 있습니다. 이러한 점 때문에 \n", "소송 외 분쟁해결기구로서 설립된 소비자분쟁조정위원회는 원만한 합의가 이루어지지 않은 소비자와 사업자에게 \n", "객관적이고 공정한 조정안을 제시함으로써 분쟁이 합리적이고 원활히 해결될 수 있도록 노력하고 있습니다.\n", "소비자기본법에 근거하여 1987년 설립된 소비자분쟁조정위원회는 설립 첫 해 20건의 사건 조정을 시작으로, 2004년 \n", "이후부터는 매년 1,000건이 넘는 사건을 조정하였으며, 2018년에는 3,080여건을 처리하는 등 그 역할을 충실히 \n", "수행하고 있습니다.\n", "특히, 분쟁조정 사건을 신속하고 공정하게 처리하기 위해 2017년에는 소비자기본법 개정을 통해 조정위원을 50명\n", "에서 150명으로 확대하는 등 관련 법·제도 개선으로 소비자권익증진에 기여하고 있습니다.\n" ] } ], "execution_count": 76 }, { "metadata": { "ExecuteTime": { "end_time": "2026-06-01T08:51:45.142963478Z", "start_time": "2026-06-01T08:51:45.132501776Z" } }, "cell_type": "code", "source": [ "# 마침표 뒤에 나오는 줄바꿈 문자는 그대로 두고 나머지 줄바꿈 문자만 제거\n", "pprint(splite_docs[18].page_content)\n", "\n", "text = splite_docs[18].page_content\n", "text = re.sub(r'(?