커뮤니티
포인트
쿠폰
내 강의실
국비 신청 내역
증명서
계정
로그아웃
학습 질문
개발 일지
나의 활동
답변 완료
챕터 5 숙제 문제 풀이중에서 발생한 오류 관련 문의
AI가 처음이어도 쉽게 배우는 생성형 AI A to Z
챕터 5
북마크
전*음
댓글
1
추천
0
조회수
12
조회수
12
답변 완료

* 겪고 있는 문제 상황을 최대한 자세하게 작성해주세요.

* 문제 해결을 위해 어떤 시도를 해보았는지 구체적으로 함께 알려주세요.


챕터 5 숙제 문제 풀이중에서 발생한 오류 관련 문의 합니다.

코드 수정후 pdf파일 업로더 후 Submit을 누를때 첨부된 파일 처럼 계속 오류가 나고 있는데 기본코드에서 수정하지 않는 부분에서 오류가 발생하는 것 같아 문의 드립니다.


작성한 코드는 아래와 같습니다.

# 기본 뼈대 코드


import gradio as gr

from sentence_transformers import SentenceTransformer

import openai

import os

import pdfplumber

import numpy as np

import faiss

import tiktoken


# Import necessary libraries

from pdf2image import convert_from_path

from azure.cognitiveservices.vision.computervision import ComputerVisionClient

from azure.cognitiveservices.vision.computervision.models import OperationStatusCodes

from msrest.authentication import CognitiveServicesCredentials

import cv2

import io

import time


# Azure API 인증 정보 설정

SUBSCRIPTION_KEY = ""

ENDPOINT_URL = ""

computervision_client = ComputerVisionClient(ENDPOINT_URL, CognitiveServicesCredentials(SUBSCRIPTION_KEY))


# OpenAI 인증 정보 설정

API_KEY = ""

openai_client = openai.Client(api_key=API_KEY)



embedder = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')


chat_history = []

chunks = []

index = None


# OCR

def detect_text_from_image(image_path):


    image_data = open(image_path, "rb").read()

    sbuf = io.BytesIO(image_data)


    # Call the API to process the image

    response = computervision_client.read_in_stream(sbuf, raw=True)

    operation_location = response.headers["Operation-Location"]

    operation_id = operation_location.split("/")[-1]


    # Polling the API until the operation completes

    while True:

        read_result = computervision_client.get_read_result(operation_id)

        if read_result.status not in ['notStarted', 'running']:

            break

        time.sleep(1)


    raw_text = ""

    if read_result.status == OperationStatusCodes.succeeded:

        for result in read_result.analyze_result.read_results:

            for line in result.lines:

                raw_text += line.text + "\n"


    return raw_text


# PDF

def extract_text_from_pdf(file_path):

    text = ""

    # First, try to extract text-based content using pdfplumber

    try:

        with pdfplumber.open(file_path) as pdf:

            for page in pdf.pages:

                page_text = page.extract_text(layout=True)

                if page_text:  # Check if any text was extracted

                    text += page_text

    except Exception as e:

        print(f"Error using pdfplumber: {e}")


    # If no text is extracted (indicating it might be image-based), use OCR

    if not text.strip():  # If no text was extracted, fall back to OCR

        print("No text found with pdfplumber, switching to OCR...")

        images = convert_from_path(file_path)


        for i, image in enumerate(images):

            image_path = f"page_{i + 1}.jpg"

            image.save(image_path, "JPEG")

            text += detect_text_from_image(image_path)

            os.remove(image_path)  # Clean up the saved image after processing


    return text


def chunk_text(text, chunk_size = 128, overlap = 64):

  words = text.split()

  local_chunks = []

  for i in range(0, len(words), chunk_size - overlap):

    chunk = ' '.join(words[i:i+chunk_size])

    local_chunks.append(chunk)


  return local_chunks



# 임베딩

def create_embeddings(chunks):

  embeddings = embedder.encode(chunks, convert_to_tensor = False)

  return np.array(embeddings)


# -- FAISS 알고리즘 구현 함수에서 빈칸을 채워주세요 -- #

def create_faiss_index(embeddings, base_algorithm="Flat"):


    dimension = embeddings.shape[1]  # 임베딩의 차원 수

    num_embeddings = embeddings.shape[0]  # 임베딩의 개수

    nlist = min(num_embeddings // 10, 100)  # nlist 값 동적으로 설정, 최대 100으로 제한

    global index  # 전역 변수로 인덱스 선언


    if base_algorithm in ("", None):  # 알고리즘이 지정되지 않았을 경우 기본값 설정

      base_algorithm = "Flat"


    # 코사인 유사도를 위해 임베딩을 정규화 (IndexFlatIP에만 필요)

    if base_algorithm in ["Flat", "IVF"]:

        faiss.normalize_L2(embeddings)


    if base_algorithm == "Flat":

        # 코사인 유사도를 위한 내적 방식의 Flat 인덱스 사용

        index = faiss.IndexFlatIP(dimension)  # 내적 기반 (코사인 유사도) Flat 인덱스 생성


    elif base_algorithm == "PQ":

        # 대규모 데이터셋을 위한 Product Quantization (PQ)

        # m (서브벡터 수) 값 동적 설정, 최대 64로 제한

        m = 8

        nbits = 8  # 서브벡터 당 비트 수

        quantizer = faiss.IndexFlatL2(dimension)  # L2 기반 PQ를 위한 양자화기 생성

        index = faiss.IndexIVFPQ(quantizer, dimension, nlist, m, nbits)  # IVF + PQ, 서브벡터당 8비트

        index.train(embeddings)  # PQ는 데이터셋을 기반으로 훈련 필요


    elif base_algorithm == "IVF":

        # 대규모 데이터셋에서 빠른 검색을 위한 Inverted File Index (IVF) 사용

        quantizer = faiss.IndexFlatIP(dimension)  # IVF 검색을 위한 내적 방식 사용

        index = faiss.IndexIVFFlat(quantizer, dimension, nlist, faiss.METRIC_INNER_PRODUCT)

        index.train(embeddings)  # IVF는 데이터셋을 기반으로 훈련 필요


    elif base_algorithm == "HNSW":

        # 계층적 탐색 가능한 소규모 세계 그래프(HNSW) 기반 인덱스

        index = faiss.IndexHNSWFlat(dimension, 32)  # 그래프에서 각 노드당 32개의 이웃 사용


    else:

        # 지원되지 않는 알고리즘 이름에 대한 예외 처리

        raise ValueError(f"Unknown base_algorithm: {base_algorithm}. Choose from 'Flat', 'PQ', 'IVF', 'HNSW'.")


    # 인덱스에 임베딩 추가

    index.add(embeddings)

    print(f"{base_algorithm}를 사용한 FAISS index가 만들어졌습니다.")

    print(index)

    print(f"인덱스에 저장된 벡터의 갯수: {index.ntotal}")  # 저장된 벡터 개수

    print(f"인덱스 벡터의 차원: {dimension}")              # 벡터 차원


def retrieve_relevant_chunks(query, top_k = 5):

  query_embedding = embedder.encode(query, convert_to_tensor = False)

  query_embedding = np.array([query_embedding])


  global index


  faiss.normalize_L2(query_embedding)


  distances, indices = index.search(query_embedding, top_k)

  relevant_chunks = [chunks[i] for i in indices[0]]


  return '\n\n'.join(relevant_chunks)




# 챗봇 페르소나 설정

def generate_answer(relevant_text, query, chat_history):

  persona = """ 제품에 대한 고객의 질문에 친절하게 대답해주는 챗봇입니다."""


  system_prompt = f"""You are knowledge based chatbot.


  #follow these instructions.

  1. Answer any asked questions based on given knowledge text.

  2. Ask a question related to the currently on-going conversation.

  3. Able to utilize outside information, however priority is knowledge based on given text.

  4. generate answer that aligns with given persona of chatbot, in Korean


  #Persona of chatbot

  {persona}

  """


  chat_history.append({'role':'system', 'content':system_prompt})

  chat_history.append({'role':'user', 'content':f"Based on the following text:\n\n{relevant_text}\n\nAnswer the question: {query}"})



  response = openai_client.chat.completions.create(

      model = 'gpt-4o',

      messages = chat_history,

      max_tokens = 1024

  )


  answer = response.choices[0].message.content

  return answer



def process_pdf(pdf_file):

  global chunks

  text = extract_text_from_pdf(pdf_file)

  chunks = chunk_text(text)

  embeddings = create_embeddings(chunks)


  create_faiss_index(embeddings)


  return f"PDF processed and FAISS index created using"


def answer_question(query, history):

  relevant_text = retrieve_relevant_chunks(query)


  global chat_history


  for human, assistant in history:

    chat_history.append({"role":"user", "content":human})

    chat_history.append({"role":"assistant", "content":assistant})


  answer = generate_answer(relevant_text, query, chat_history)

  return answer




# Gradio UI 부분

pdf_input = gr.File(label = 'upload your pdf', type = 'filepath')


with gr.Blocks() as demo:

    gr.Markdown("## 제품 문의 챗봇")


    with gr.Tab("Step 1: Upload PDF and Extract Text"):

        pdf_interface = gr.Interface(

            fn=process_pdf,

            inputs=[pdf_input],

            outputs="text",

            description="Upload a PDF and extract its text chunks and embeddings."

        )


    with gr.Tab("Step 2: Chatbot based on pdf"):

        question_interface = gr.ChatInterface(

            fn=answer_question,

            textbox = gr.Textbox(placeholder = "질문이 있으신가요?",

                                 container = False,

                                 scale = 7)

        ).queue()


demo.launch(share = True, debug=True)





스파르타 즉문즉답

오류 나는 위치가

def create_embeddings(chunks):

  embeddings = embedder.encode(chunks, convert_to_tensor = False)

  return np.array(embeddings)


def retrieve_relevant_chunks(query, top_k = 5):

  query_embedding = embedder.encode(query, convert_to_tensor = False)

  query_embedding = np.array([query_embedding])

위의 2군데로 보이는데 제가 잘 파악하고 있는지 모르겠네요

확인 부탁드립니다.





취소
 공유
취소
댓글 0
댓글 알림
나의얼굴