사용자 입력 자료 레퍼런스화 시키기
사용자가 txt, pdf, url 등의 형태로 자료를 업로드하면, 그 내용을 읽어와서 챗봇이 그 내용을 참조할 수 있게 하는 작업이 필요했다.
우선, 전처리와 url을 읽어오는 코드에 대해 저번 프로젝트에서 사용했던 전처리 파일을 참고했다. 저번 프로젝트에서는 스파르타 강의 노션 url을 읽어와서 전처리 작업 후 txt 파일로 변환하는 코드를 작성했었다. 그 코드에서 전처리 부분과, 노션 url을 읽어오는 코드 부분을 유용하게 이용할 수 있었다.
우선, 전처리 함수를 작성했다. 저번 프로젝트에서 작성했던 전처리 코드는 스파르타 강의 자료에 대한 전처리에 특화되어 있었다. 이번에는 어떤 url에서든지 전처리 함수를 적요할 수 있게, 포괄적으로 전처리함수를 작성했다.
# 전처리 함수 정의
def preprocess_text(txt):
txt = remove_html_tags(txt) # HTML 태그 제거
txt = re.sub(r'\[?스파르타코딩클럽\]?', '', txt) # 특정 텍스트 제거
txt = re.sub(r'Copyright.*$', '', txt) # 저작권 문구 제거
txt = txt.replace('\xa0', ' ') # 비공백 문자를 공백으로 변환
txt = re.sub(r'\\[a-zA-Z]+\{.*?\}', '', txt) # LaTeX 명령어 제거
# txt = re.sub(r'\\[a-zA-Z]+', '', txt) # LaTeX 명령어 제거
txt = re.sub(r'\s+', ' ', txt).strip() # 여러 공백을 하나로 축소하고 양옆 공백 제거
txt = re.sub(r'http[s]?://\S+', '', txt) # URL 제거
txt = re.sub(r'\S+@\S+', '', txt) # 이메일 주소 제거
return txt
# HTML 태그 제거 함수
def remove_html_tags(txt):
soup = BeautifulSoup(txt, 'html.parser')
return soup.get_text()
특히, HTML 태그 제거 함수를 추가해, 블로그나 나무위키 등 다른 url을 처리할 때 받아올 수 있는 불필요한 HTML 태그들에 대해 제거할 수 있도록 했다. 이모티콘도 제거하고 싶었지만, 무슨 이유에서인지 이모티콘을 제거하는 함수를 작성하면 너무 많은 양의 데이터가 사라졌다. 필요한 부분들도 모두 제거가 되는 것이었다. 이모티콘을 제거하는 함수에 대해 더 알아보고, 다른 조원분들에게 도움을 요청해야 겠다.
다음으로는 url을 처리하고 텍스트를 반환하는 함수를 작성했다. drf에서 모듈로 활용할 수 있도록 전처리 함수와 더불어 함수로 작성해주었다. 모듈화는 코드를 효율적으로 사용할 수 있게 하는 아주 좋은 방법이다.
노션에는 많은 토글들이 있는데, 이 토글들을 모두 열어서 데이터를 가져와야 했다. 처음에는 하나의 url 함수로 모든 url에 대해 처리할 수 있을 줄 알았다. 그래서 이전 프로젝트의 스파르타 강의 노션 url을 처리하는 함수에서 크게 수정하지 않고 코드를 실행해보았다. 다른 스파르타 강의 노션 url에 대해서는 제대로 동작을 했지만, 블로그나 나무위키 등의 url을 입력했을 때는 아무런 내용을 가져오지 못하거나, 아주 일부분의 내용만 가져오는 등 여러 문제가 발생했다.
따라서 노션 url과 다른 url들에 대해 다르게 설정을 해주어야 겠다는 생각이 들었다. 따라서 url에 notion이라는 단어가 들어간다면, 기존의 notion 토글을 모두 열어서 읽어오는 등의 로직이 담긴 url 처리 함수가 실행되게 했다. url에 notion이라는 글자가 들어가지 않는, 다른 url들에 대해서는 아래의 함수가 적용되게 했다.
def fetch_with_requests(self, url):
try:
response = requests.get(url)
response.raise_for_status() # HTTP 오류 발생 시 예외 발생
soup = BeautifulSoup(response.text, 'html.parser')
# 원하는 데이터 추출
return soup.prettify() # 예시로, prettify된 HTML 반환
except requests.exceptions.RequestException as e:
print(f"요청 중 오류 발생: {e}")
return None # 오류가 발생하면 None 반환
위의 함수는, requests와 BeautifulSoup를 활용하여 url을 처리하는 함수다.
아래와 같이 if문을 통해 notion이 들어가는 url과 그렇지 않은 url에 대해 다르게 처리되도록 작성해주었다.
def read_url(self, url):
try:
if "notion" in url.lower():
# Notion URL인 경우, pre_processing.py의 process_url 호출
return process_url(url)
else:
# Notion이 아닌 URL은 BeautifulSoup와 Requests로 처리
return self.fetch_with_requests(url)
except Exception as e:
raise Exception(f"Error reading URL: {e}")
또한 혹시 몰라서, 받아온 내용들을 json 파일로 저장하는 부분도 작성해두었다. json 파일의 형식은 아래와 같다.
{
"id": 1,
"content": "자료 내용"
},
데이터베이스에도 내용이 저장되게 할 필요가 있었다. 모델을 만들어주고, 데이터베이스에 저장하기 위해 시리얼라이저도 만들어주고, 데이터베이스에 사용자로부터 입력받은 데이터가 저장되게 하는 로직도 뷰에 추가해주었다.
models.py에 File 모델을 추가했다.
class File(models.Model):
file = models.FileField(null=True, blank=True)
url = models.URLField(null=True, blank=True)
content = models.TextField(null=True, blank=True)
uploaded_at = models.DateTimeField(auto_now_add=True)
serializers.py에 FileSerializer 시리얼라이저를 추가했다.
from rest_framework import serializers
from .models import File
class FileSerializer(serializers.ModelSerializer):
class Meta:
model = File
fields = ['file', 'url', 'content']
필요한 필드만 가지고 오기 위해서 fields에 'all'이 아닌, 필요한 필드들만 적어주었다.
그리고 serializer.save(content=content)
를 통해 데이터베이스에 저장되게 했다.