From b19fd8c0c9d91129eeb63d2e0f0a0a23bc8f797e Mon Sep 17 00:00:00 2001 From: zziminally Date: Sat, 29 Nov 2025 01:52:46 +0900 Subject: [PATCH] =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=EB=B6=84=ED=95=A0?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dstonylion/story/utils.py | 62 +++++++++++++++++++++++++++++++-------- Dstonylion/story/views.py | 54 ++++++++++++++++++++++++++++++++-- 2 files changed, 101 insertions(+), 15 deletions(-) diff --git a/Dstonylion/story/utils.py b/Dstonylion/story/utils.py index d96e048..a55ac23 100644 --- a/Dstonylion/story/utils.py +++ b/Dstonylion/story/utils.py @@ -1,26 +1,64 @@ #생성된 동화를 페이지별로 나누는 공통 로직 import re -def split_into_pages(text: str, sentences_per_page: int = 3): +def split_into_pages_classic(text: str): if not text: return [] - sentences = re.split(r'(?<=[.!?])\s+', text.strip()) + sentences = re.split(r'\n+', text.strip()) + sentences = [s.strip() for s in sentences if s.strip()] pages = [] buffer = [] + idx = 0 - for s in sentences: - if not s: - continue + while idx < len(sentences): + candidates = sentences[idx:idx+3] - buffer.append(s.strip()) + placed = False + for count in [3, 2, 1]: + if len(candidates) >= count: + chunk = " ".join(candidates[:count]) + if len(chunk) <= 70: + pages.append(chunk) + idx += count + placed = True + break - if len(buffer) == sentences_per_page: - pages.append(" ".join(buffer)) - buffer = [] - - if buffer: - pages.append(" ".join(buffer)) + if not placed: + pages.append(candidates[0]) + idx += 1 return pages + +def split_into_pages(text: str): + if not text: + return [] + + sentences = re.split(r'(?<=[.!?"]) +', text.strip()) + sentences = [s.strip() for s in sentences if s.strip()] + + pages = [] + idx = 0 + max_len = 70 + + while idx < len(sentences): + candidates = sentences[idx:idx+3] + placed = False + + for count in [3, 2, 1]: + if len(candidates) >= count: + chunk = " ".join(candidates[:count]) + + if len(chunk) <= max_len: + pages.append(chunk) + idx += count + placed = True + break + + if not placed: + single = candidates[0] + pages.append(single) + idx += 1 + + return pages \ No newline at end of file diff --git a/Dstonylion/story/views.py b/Dstonylion/story/views.py index 12d93f9..2c15c29 100644 --- a/Dstonylion/story/views.py +++ b/Dstonylion/story/views.py @@ -18,7 +18,7 @@ from rest_framework import viewsets, status from django.contrib.auth import get_user_model from django.shortcuts import get_object_or_404 -from story.utils import split_into_pages +from story.utils import * from dotenv import load_dotenv from django.utils.text import slugify @@ -458,6 +458,11 @@ def post(self, request): - 아래 초안을 참고하되, 내용은 부드럽게 재창작 - 초안을 그대로 복붙하지 말고 흐름을 자연스럽게 구성 - 마무리를 동화스럽게 교훈 키워드를 잘 활용 + + [문장 길이 규칙 - 강제] + - **한 문장은 공백 포함 35자 이상 70자 이하로 작성** + - 문장은 마침표/물음표/느낌표로 자연스럽게 끝나는 구조로 작성 + [사용자 초안] {draft} """ @@ -808,6 +813,14 @@ def get(self, request, story_id): serializer = StorySerializer(story) return Response(serializer.data, status=200) + def delete(self, request, story_id): + story = Story.objects.filter(id=story_id).first() + if not story: + return Response({"detail": "Story not found"}, status=404) + + story.delete() + return Response({"detail": "Story deleted successfully"}) + class StoryPageListView(APIView): def get(self, request, story_id): story = Story.objects.filter(id=story_id).first() @@ -878,6 +891,7 @@ def post(self, request): return Response({"story_id": story.id, "title": story.title}, status=201) import chardet +from django.core.files.base import ContentFile class ClassicStoryUploadView(APIView): def post(self, request): @@ -924,18 +938,52 @@ def post(self, request): created_at=timezone.now(), ) - pages = split_into_pages(raw_text) + pages = split_into_pages_classic(raw_text) + story_pages = [] for i, page_text in enumerate(pages, start=1): - StoryPage.objects.create( + sp = StoryPage.objects.create( story=story, page_number=i, text=page_text ) + story_pages.append(sp) story.page_count = len(pages) story.save() + #삽화 png 연결 + base_name = filename.replace(".txt", "") + illustration_dir = f"story_illustrations/{base_name}/" + + try: + all_files = default_storage.listdir(illustration_dir)[1] # files only + except FileNotFoundError: + all_files = [] + + #표지 이미지 처리 + cover_name = f"{base_name}_cover.png" + cover_path = illustration_dir + cover_name + + if cover_name in all_files and default_storage.exists(cover_path): + with default_storage.open(cover_path, "rb") as f: + story.cover.save(cover_name, ContentFile(f.read())) + story.save() + + #삽화 이미지 처리 + for sp in story_pages: + page_png = f"{base_name}_p{sp.page_number}.png" + png_path = illustration_dir + page_png + + if page_png in all_files and default_storage.exists(png_path): + with default_storage.open(png_path, "rb") as f: + img_bytes = f.read() + + Illustrations.objects.create( + story_page=sp, + image=ContentFile(img_bytes, name=page_png) + ) + return Response({ "story_id": story.id, "title": story.title,