허깅페이스 스페이스에 만든 앱에 있는 다음의 app.py에

* Custom 선택시 시작 패턴이나 종료 패턴에 각기 찾아보기 버튼을 추가해주시고, 버튼 앞에 몇번째를 표시해주며 입력도 가능한 상자를 추가해주세요.

* [사용자가 끝부분을 잘 모르더라도] 시작패턴이나 종료패턴 입력상자에 텍스트를 타이핑하고 찾아보기 버튼을 클릭하면, 위에 붙여놓은 mht 파일의 내용에서 그 부분이 드래그 표시된 텍스트로 나타남과 동시에 그것이 몇번째인지를 기억할 수 있게 표시해주는 것이고, 나중에는 그 발생 번호만 입력해도 될 수 있게 하려는 거예요.

* 채팅 대화에 포함된 똑같은 수많은 HTML 태그 등에 의해 짝을 못찾아, 짤리는 일을, 사용자가 선택할 수 있게 해서 올바른 문서로 다운로드 받을 수 있게 하려는 거고요.

* 같은 것이 무수히 많을 경우에도, 찾아보기 발생번호에 임의의 숫자를 입력하면 대략적인 위치를 파악할 것이므로 사용자가 쉽게 그 주위에서 찾아볼 수 있어 편리할 것도 같아서요.

(여기에서는 새로고침이 쉽게 발생되므로 실제로 실행하며 오류를 보고해서 수정해가는 작업은 OpenAI ChatGPT4o-mini Online AI와 하게 될 거예요. 사실 이 코드도 OprnAI o1이 제공한 코드를 OpenAI ChatGPT4o-mini Online AI이 업그레이드된 Gradio 등에 따라 보고된 오류들을 수정했던 것임.)

==========

import gradio as gr
import re
import tempfile

def extract_html_from_mht(mht_content, choice, start_pattern, end_pattern, occurrence='1'):
    # 사용자의 선택에 따라 정규식 패턴 결정
    if choice == "<!DOCTYPE html><html":
        pattern = r'<!DOCTYPE html><html.*?</html>'
    elif choice == "<!DOCTYPE html><html lang=":
        pattern = r'<!DOCTYPE html><html lang=".*?".*?</html>'
    elif choice == "Custom":
        if not start_pattern or not end_pattern:
            return ("시작 패턴과 종료 패턴을 모두 입력해주세요.", None)
        # 정규식 특수 문자를 이스케이프 처리
        start_pattern_escaped = re.escape(start_pattern)
        end_pattern_escaped = re.escape(end_pattern)
        pattern = start_pattern_escaped + r'.*?' + end_pattern_escaped
    else:
        return ("올바르지 않은 선택입니다.", None)

    # 정규 표현식을 사용하여 모든 일치하는 HTML 문서 찾기
    matches = re.finditer(pattern, mht_content, re.DOTALL)
    matches_list = list(matches)

    if matches_list:
        # occurrence에 기반하여 특정 HTML 문서 선택
        try:
            index = int(occurrence) - 1
            if index >= 0 and index < len(matches_list):
                html_content = matches_list[index].group(0)
            else:
                return ("올바르지 않은 발생 번호입니다.", None)
        except ValueError:
            return ("발생 번호는 숫자여야 합니다.", None)

        # 추출된 HTML 내용을 저장할 임시 파일 생성
        with tempfile.NamedTemporaryFile(delete=False, suffix=".html", mode='w', encoding='utf-8') as temp_file:
            temp_file.write(html_content)
            temp_file_path = temp_file.name

        # 임시 파일의 경로 반환
        return (None, temp_file_path)
    else:
        # HTML 문서를 찾을 수 없는 경우 에러 메시지 반환
        return ("MHT 파일에서 유효한 HTML 내용을 찾을 수 없습니다.", None)

def update_pattern_fields(choice):
    # 'Custom'을 선택하면 시작/종료 패턴 필드를 보이게 함
    if choice == "Custom":
        return [gr.update(visible=True), gr.update(visible=True)]
    else:
        return [gr.update(visible=False), gr.update(visible=False)]

with gr.Blocks() as block:
    gr.Markdown("""
    <h4>이 앱은 기본적으로는 MHT 내용에서 추출할 HTML 태그 패턴을 선택할 수 있도록 도와줍니다.</h4>
    <p>기본 패턴이 아닌 다른 것을 원한다면(— 다른 문서도 가능할 수 있음), 'Custom'을 선택하고 시작 및 종료 패턴을 직접 입력할 수 있습니다.</p>
    <p>HTML 태그와 포함된 내용 등이 복잡한 경우, 정확한 추출을 위해 고유하고 구별되는 시작 및 종료 패턴을 제공해야 합니다.</p>
    """)

    mht_input = gr.Textbox(label="MHT 내용을 여기에 붙여넣기", lines=20, placeholder="MHT 파일의 내용을 여기에 붙여넣으세요")
    
    # 드롭다운에서 구체적인 시작 태그를 선택하게 수정
    choice_dropdown = gr.Dropdown(
        label="HTML 시작 태그 선택", 
        choices=["<!DOCTYPE html><html", "<!DOCTYPE html><html lang=","Custom"], 
        value="<!DOCTYPE html><html"
    )
    
    # 사용자 지정 시작 및 종료 패턴 입력 창을 추가
    start_pattern_input = gr.Textbox(label="사용자 지정 시작 패턴", visible=False)
    end_pattern_input = gr.Textbox(label="사용자 지정 종료 패턴", visible=False)
    
    occurrence_input = gr.Textbox(label="추출할 발생 번호 입력 (숫자): 같은 것이 여럿 있을 때 ?번째", value="1")
    
    convert_button = gr.Button("MHT에서 HTML 추출")
    error_output = gr.Textbox(label="에러 메시지", interactive=False)
    download_output = gr.File(label="HTML 파일 다운로드")

    # 사용자의 선택에 따라 사용자 지정 패턴 필드의 가시성 업데이트
    choice_dropdown.change(fn=update_pattern_fields, inputs=choice_dropdown, outputs=[start_pattern_input, end_pattern_input])

    # 버튼 클릭 이벤트 정의
    convert_button.click(
        fn=extract_html_from_mht, 
        inputs=[mht_input, choice_dropdown, start_pattern_input, end_pattern_input, occurrence_input], 
        outputs=[error_output, download_output]
    )

block.launch()