Spaces:
Paused
Paused
Create app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import time
|
| 3 |
+
import json
|
| 4 |
+
import psycopg2
|
| 5 |
+
from typing import Dict, List
|
| 6 |
+
# from dotenv import load_dotenv
|
| 7 |
+
|
| 8 |
+
# FastAPI λ° slowapi κ΄λ ¨ λͺ¨λ
|
| 9 |
+
from fastapi import FastAPI, Request
|
| 10 |
+
from slowapi import Limiter, _rate_limit_exceeded_handler
|
| 11 |
+
from slowapi.util import get_remote_address
|
| 12 |
+
from slowapi.errors import RateLimitExceeded
|
| 13 |
+
from fastapi.middleware.cors import CORSMiddleware
|
| 14 |
+
|
| 15 |
+
# Pydantic λͺ¨λΈ
|
| 16 |
+
from pydantic import BaseModel
|
| 17 |
+
|
| 18 |
+
# LangChain κ΄λ ¨ λͺ¨λ
|
| 19 |
+
from langchain_google_genai import ChatGoogleGenerativeAI
|
| 20 |
+
from langchain_community.embeddings import HuggingFaceEmbeddings
|
| 21 |
+
from langchain_community.vectorstores import PGVector
|
| 22 |
+
from langchain_core.messages import SystemMessage
|
| 23 |
+
from langchain.chains import ConversationalRetrievalChain
|
| 24 |
+
from langchain.memory import ConversationBufferMemory
|
| 25 |
+
from langchain_core.documents import Document # Document νμ
ννΈμ©μΌλ‘ μΆκ°
|
| 26 |
+
# from pdf_importer import create_vector_store, CONNECTION_STRING, COLLECTION_NAME
|
| 27 |
+
|
| 28 |
+
# νκ²½ λ³μ λ‘λ (Hugging Face Secretsμμ κ°μ Έμ΄)
|
| 29 |
+
POSTGRES_USER = os.getenv('POSTGRES_USER')
|
| 30 |
+
POSTGRES_PASSWORD = os.getenv('POSTGRES_PASSWORD')
|
| 31 |
+
POSTGRES_HOST = os.getenv('POSTGRES_HOST')
|
| 32 |
+
POSTGRES_PORT = os.getenv('POSTGRES_PORT')
|
| 33 |
+
POSTGRES_DB = os.getenv('POSTGRES_DB')
|
| 34 |
+
GOOGLE_API_KEY = os.getenv('GOOGLE_API_KEY')
|
| 35 |
+
|
| 36 |
+
COLLECTION_NAME = "homepage_pdfplumner_1st"
|
| 37 |
+
|
| 38 |
+
# 2. νμ νκ²½ λ³μκ° λͺ¨λ μ‘΄μ¬νλμ§ νμΈν©λλ€.
|
| 39 |
+
if not all([POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_HOST, POSTGRES_PORT, POSTGRES_DB, COLLECTION_NAME, GOOGLE_API_KEY]):
|
| 40 |
+
raise ValueError("νμ νκ²½ λ³μλ€μ΄ μ€μ λμ§ μμμ΅λλ€. Hugging Face Secretsλ₯Ό νμΈνμΈμ.")
|
| 41 |
+
|
| 42 |
+
# νκ²½ λ³μλ₯Ό μ‘°ν©νμ¬ CONNECTION_STRINGμ μμ±
|
| 43 |
+
CONNECTION_STRING = f"postgresql+psycopg2://{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_HOST}:{POSTGRES_PORT}/{POSTGRES_DB}"
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
# load_dotenv()
|
| 47 |
+
app = FastAPI()
|
| 48 |
+
limiter = Limiter(key_func=get_remote_address)
|
| 49 |
+
app.state.limiter = limiter
|
| 50 |
+
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
|
| 51 |
+
|
| 52 |
+
app.add_middleware(
|
| 53 |
+
CORSMiddleware,
|
| 54 |
+
allow_origins=["*"],
|
| 55 |
+
allow_credentials=True,
|
| 56 |
+
allow_methods=["*"],
|
| 57 |
+
allow_headers=["*"],
|
| 58 |
+
)
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
# RAG κ΅¬μ± μμλ₯Ό νλ‘κ·Έλ¨ μμ μ ν λ²λ§ μ΄κΈ°ν
|
| 62 |
+
embeddings = HuggingFaceEmbeddings(
|
| 63 |
+
model_name='nlpai-lab/KURE-v1',
|
| 64 |
+
model_kwargs={'device': 'cpu'}
|
| 65 |
+
)
|
| 66 |
+
|
| 67 |
+
try:
|
| 68 |
+
vector_store = PGVector(
|
| 69 |
+
collection_name=COLLECTION_NAME,
|
| 70 |
+
connection_string=CONNECTION_STRING,
|
| 71 |
+
embedding_function=embeddings
|
| 72 |
+
)
|
| 73 |
+
print("Vector store loaded from PostgreSQL.")
|
| 74 |
+
except Exception as e:
|
| 75 |
+
print(f"Error connecting to PostgreSQL: {e}")
|
| 76 |
+
import sys
|
| 77 |
+
sys.exit(1)
|
| 78 |
+
|
| 79 |
+
llm = ChatGoogleGenerativeAI(
|
| 80 |
+
# model="gemini-1.5-flash-8b",
|
| 81 |
+
model="gemini-2.5-flash-lite",
|
| 82 |
+
model_kwargs={
|
| 83 |
+
"system_instruction": SystemMessage(
|
| 84 |
+
content=
|
| 85 |
+
# """λΉμ μ νκ΅μΈκ΅μ΄λνκ΅(μμΈ) νμ¬ μ λ¬Έκ°μ
λλ€. λ΅λ³ μμΉ: 1. νκ΅μΈκ΅μ΄λνκ΅(μμΈ) κ΄λ ¨ μ§λ¬Έμ μ νν λ΅λ³ν©λλ€. 2. μ΄μ λν λ§₯λ½μ κΈ°μ΅νκ³ μ μ°νκ² μλ΅ν©λλ€. 3. μΉμ νκ³ μ΄ν΄νκΈ° μ¬μ΄ λ§ν¬λ₯Ό μ¬μ©νλ©°, λ°λμ μμ ν λ¬Έμ₯μΌλ‘ λ΅λ³ν©λλ€. 4. μ°Έκ³ μ 보μ μλ λ΄μ©μ μ λ μΆμΈ‘νκ±°λ μμλ‘ λ΅λ³νμ§ μμ΅λλ€. λ΅λ³ κ·μΉ: - νκ΅μΈκ΅μ΄λνκ΅(μμΈ)κ³Ό κ΄λ ¨ μλ μ§λ¬Έ: "μ£μ‘ν©λλ€. νκ΅μΈκ΅μ΄λνκ΅(μμΈ) κ΄λ ¨ μ§λ¬Έμλ§ λ΅λ³λ릴 μ μμ΅λλ€."λΌκ³ λ΅λ³νμΈμ. - μ¬μ©μμ μ§λ¬Έκ³Ό κ΄λ ¨λ μ λ³΄κ° μ°Έκ³ λ¬Έμμ λͺ
ννκ² μ‘΄μ¬νμ§ μλ κ²½μ°, μ΄λ€ λ΄μ©λ μΆλ‘ νκ±°λ λ§λΆμ΄μ§ λ§κ³ 무쑰건 "μ£μ‘ν©λλ€. ν΄λΉ μ 보λ₯Ό νμΈν μ μμ΅λλ€."λΌκ³ λ΅λ³νμΈμ."""
|
| 86 |
+
"""
|
| 87 |
+
|
| 88 |
+
λΉμ μ νκ΅μΈκ΅μ΄λνκ΅(μμΈ)μ **'νμ¬ μν AI μ΄λλ°μ΄μ '**μ
λλ€. λΉμ μ μ§μμ μ£Όμ΄μ§ [νμ¬ κ·μ ]κ³Ό [μ£Όλ³ μκΆ μ 보] λ¬Έμλ‘ νμ λ©λλ€. λΉμ μ μ무λ μ΄ μ§μ λ΄μμ νμλ€μ μ§λ¬Έμ λͺ
ννκ³ μΉμ ν μ λ¬Έκ°μ μ΄μ‘°λ‘ λ΅λ³νλ κ²μ
λλ€.
|
| 89 |
+
|
| 90 |
+
[λ΅λ³ μμΉ]
|
| 91 |
+
|
| 92 |
+
1. μ νμ±: λ°λμ μ£Όμ΄μ§ μ°Έκ³ λ¬Έμμ λ΄μ©μλ§ κ·Όκ±°νμ¬ λ΅λ³ν©λλ€.
|
| 93 |
+
|
| 94 |
+
2. μΉμ ν¨: νμ μΉμ νκ³ μ΄ν΄νκΈ° μ¬μ΄ μμ ν λ¬Έμ₯μΌλ‘ λ΅λ³ν©λλ€.
|
| 95 |
+
|
| 96 |
+
3. λ§₯λ½ μ΄ν΄: μ΄μ λν λ΄μ©μ κΈ°μ΅νμ¬ μμ°μ€λ¬μ΄ λνλ₯Ό μ΄μ΄κ°λλ€.
|
| 97 |
+
|
| 98 |
+
4. μ§μ λ΄μ¬ν: λΉμ μ λ¬Έμλ₯Ό λ¨μν μ λ¬νλ λ‘λ΄μ΄ μλλλ€. μ£Όμ΄μ§ μ°Έκ³ λ¬Έμλ λΉμ μ 'μ§μ'μ
λλ€. λ΅λ³ μ, 'μ 곡λ μ 보', 'μ°Έκ³ λ¬Έμ', 'μ£Όμ΄μ§ ν
μ€νΈ', 'ν', 'λ¬Έλ¨' λ± λΉμ μ΄ μ 보λ₯Ό μ΄λ»κ² μ»μλμ§ μμνλ κ·Έ μ΄λ€ λ¨μ΄λ μ λ μ¬μ©νμ§ λ§μΈμ. κ²μλ λͺ¨λ μ 보λ₯Ό μμ ν μμ μ μ§μμΈ κ²μ²λΌ μ’
ν©νκ³ μμ°μ€λ½κ² μ¬κ΅¬μ±νμ¬, λ§μΉ μλλΆν° μκ³ μμλ κ²μ²λΌ μ¬μ©μμκ² μ§μ μ€λͺ
ν΄μΌ ν©λλ€.
|
| 99 |
+
|
| 100 |
+
5. νκ΅μ΄ μ¬οΏ½οΏ½: λͺ¨λ λ΅λ³μ λ°λμ μλ²½ν νκ΅μ΄λ‘λ§ μμ±ν΄μΌ ν©λλ€.
|
| 101 |
+
|
| 102 |
+
[λ΅λ³ κ·μΉ]
|
| 103 |
+
|
| 104 |
+
1. μκΈ°μκ°: λ§μ½ μ¬μ©μκ° λΉμ μ μ 체μ±μ λν΄ λ¬»λλ€λ©΄(μ: "λλ λꡬμΌ?", "μ΄λ¦μ΄ λμΌ?"), "μλ
νμΈμ! μ λ νκ΅μΈκ΅μ΄λνκ΅ νμλ€μ μΊ νΌμ€ μνμ λκΈ° μν΄ λ§λ€μ΄μ§ 'νμ¬ μν AI μ΄λλ°μ΄μ 'μ
λλ€. νμ¬ μ 보λ νκ΅ μνμ λν΄ κΆκΈν μ μ΄ μλ€λ©΄ 무μμ΄λ λ¬Όμ΄λ³΄μΈμ." λΌκ³ μ νν μκ°ν΄μΌ ν©λλ€. μ λλ‘ 'Googleμ μΈμ΄ λͺ¨λΈ'μ΄λ λ§μ€μ½νΈ 'λΆ(Boo)'λΌκ³ μμ μ μκ°ν΄μλ μ λ©λλ€.
|
| 105 |
+
|
| 106 |
+
1. λ²μ μΈ μ§λ¬Έ νλ¨: λΉμ μ μ§μ λ²μ(νμ¬, μ£Όλ³ λ§μ§)μ λͺ
λ°±ν κ΄λ ¨ μλ μ§λ¬Έ(μ: κΈμ΅, μ€ν¬μΈ )μλ "μ£μ‘ν©λλ€. μ λ νκ΅μΈκ΅μ΄λνκ΅ νμ¬ λ° μΊ νΌμ€ μν μ 보μ λν΄μλ§ λ΅λ³ν μ μμ΅λλ€." λΌκ³ λ΅λ³νμΈμ. 'μ 곡λ μ 보μ μλ€'λ μμ λΆμ° μ€λͺ
μ μ λ λ§λΆμ΄μ§ λ§μΈμ.
|
| 107 |
+
|
| 108 |
+
2. μ 보 μ°μ μμ νλ³: μ¬λ¬ κ°μ μ°Έκ³ λ¬Έμκ° μ£Όμ΄μ§λ©΄, κ·Έμ€μμ μ¬μ©μμ μ§λ¬Έμ κ°μ₯ μ§μ μ μΌλ‘ λ΅ν μ μλ ν΅μ¬ μ 보λ₯Ό λ¨Όμ μλ³νμΈμ. κ΄λ ¨μ±μ΄ λ¨μ΄μ§κ±°λ λΆμ°¨μ μΈ μ 보λ λ΅λ³μ ν¬ν¨νμ§ μκ±°λ, κΌ νμν κ²½μ°μλ§ κ°λ΅νκ² λ§λΆμ¬ μ€λͺ
νμΈμ.
|
| 109 |
+
|
| 110 |
+
3. ν(Table) λΆμ: μ°Έκ³ λ¬Έμμ νκ° ν¬ν¨λ κ²½μ°, λΉμ μ ν λΆμ μ λ¬Έκ°λ‘μ νκ³Ό μ΄μ κ΄κ³λ₯Ό μ νν ν΄μνμ¬ λ΅λ³ν΄μΌ ν©λλ€.
|
| 111 |
+
|
| 112 |
+
4. μ‘°κ±΄λΆ λ΅λ³: λ§μ½ νλ ν
μ€νΈμ νκ³Ό, νλ² λ± μΈλΆ μ‘°κ±΄μ΄ λͺ
μλμ΄ μμ§ μλ€λ©΄, "μ μλ μλ£μ λ°λ₯΄λ©΄ μΌλ°μ μΌλ‘" λλ "2025νλ
λ κΈ°μ€μΌλ‘λ" κ³Ό κ°μ΄ μ 보μ μΆμ²λ κΈ°μ€μ λͺ
νν λ°νλ©° λ΅λ³νμΈμ.
|
| 113 |
+
|
| 114 |
+
5. λ€μ€ μ 보 μ²λ¦¬: λ§μ½ μ¬μ©μμ μ§λ¬Έμ λν΄ μ¬λ¬ λ¬Έμμμ μλ‘ λ€λ₯Έ μ λ³΄κ° κ²μλ κ²½μ°, νλμ μ λ³΄λ§ μ ννμ§ λ§μΈμ. λμ , κ°κ°μ 쑰건과 λ΄μ©μ λͺ
νν ꡬλΆνμ¬ λͺ¨λ μ 보λ₯Ό μ’
ν©μ μΌλ‘ μλ΄ν΄μΌ ν©λλ€.
|
| 115 |
+
|
| 116 |
+
6. μμΈ κ°λ₯μ± μΈμ§: νμ¬ κ·μ μ λ¨κ³Όλν, νκ³Ό, νλ²λ³λ‘ μμΈ κ·μΉμ΄ μ‘΄μ¬ν μ μλ€λ μ¬μ€μ νμ μΈμ§νμΈμ. λ§μ½ μΌλ°μ μΈ κ·μΉμ μ°ΎμλλΌλ, "μΌλ°μ μΌλ‘λ OOνμ μ΄ νμνμ§λ§, μμ λ¨κ³Όλνμ΄λ νκ³Όμ λ°λΌ λ€λ₯Ό μ μμΌλ μ νν μ 보λ νκ΅ κ³΅μ λ¬Έμλ₯Ό νμΈνμκ±°λ νκ³Ό μ¬λ¬΄μ€μ λ¬Έμνλ κ²μ κΆμ₯ν©λλ€" μ κ°μ΄ λ΅λ³μ 'μ£Όμμ¬ν'κ³Ό 'νκ³'λ₯Ό λͺ
μνμΈμ.
|
| 117 |
+
|
| 118 |
+
7. μ 보 λΆμ¬ μ: μμ λͺ¨λ λ
Έλ ₯μλ λΆκ΅¬νκ³ μ§λ¬Έμ λν λ΅λ³μ μ°Έκ³ λ¬Έμμμ μ°Ύμ μ μλ κ²½μ°μλ§, "μ£μ‘ν©λλ€. λ¬Έμνμ λ΄μ©μ λν μ 보λ μ κ° κ°μ§ μλ£μμ νμΈν μ μμ΅λλ€."λΌκ³ λ΅λ³νμΈμ.
|
| 119 |
+
|
| 120 |
+
"""
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
),
|
| 124 |
+
}
|
| 125 |
+
)
|
| 126 |
+
|
| 127 |
+
retriever = vector_store.as_retriever(search_kwargs={"k": 3})
|
| 128 |
+
|
| 129 |
+
# retriever = MultiQueryRetriever.from_llm(
|
| 130 |
+
# retriever=vector_store.as_retriever(search_kwargs={"k": 5}),
|
| 131 |
+
# llm=llm
|
| 132 |
+
# )
|
| 133 |
+
|
| 134 |
+
# μ¬μ©μ μΈμ
λ³ λν 체μΈμ μ μ₯ν λμ
λ리
|
| 135 |
+
chat_sessions: Dict[str, ConversationalRetrievalChain] = {}
|
| 136 |
+
|
| 137 |
+
def get_or_create_chain(session_id: str) -> ConversationalRetrievalChain:
|
| 138 |
+
if session_id not in chat_sessions:
|
| 139 |
+
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True,
|
| 140 |
+
input_key="question", # <-- μΆκ°
|
| 141 |
+
output_key="answer" )
|
| 142 |
+
new_chain = ConversationalRetrievalChain.from_llm(
|
| 143 |
+
llm=llm,
|
| 144 |
+
retriever=retriever,
|
| 145 |
+
memory=memory,
|
| 146 |
+
return_source_documents=True, # μ°Έκ³ λ¬Έμ λ°ν νμ±ν
|
| 147 |
+
output_key="answer"
|
| 148 |
+
)
|
| 149 |
+
chat_sessions[session_id] = new_chain
|
| 150 |
+
print(f"μλ‘μ΄ μΈμ
ID μμ±: {session_id}")
|
| 151 |
+
return chat_sessions[session_id]
|
| 152 |
+
|
| 153 |
+
|
| 154 |
+
class ChatMessage(BaseModel):
|
| 155 |
+
message: str
|
| 156 |
+
session_id: str
|
| 157 |
+
user_id: str # μ¬μ©μ μλ³μ μν΄ μΆκ°
|
| 158 |
+
|
| 159 |
+
class ChatResponse(BaseModel):
|
| 160 |
+
response: str
|
| 161 |
+
success: bool
|
| 162 |
+
# source_documents νλλ₯Ό μΆκ°νμ¬ νλ‘ νΈμλλ‘λ λ³΄λΌ μ μλλ‘ μ€λΉ
|
| 163 |
+
source_documents: List[Dict[str, str]] = [] # λ¬Έμ λ΄μ©κ³Ό λ©νλ°μ΄ν° μ μ₯
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
@app.post("/api/chat", response_model=ChatResponse)
|
| 170 |
+
@limiter.limit("15/minute")
|
| 171 |
+
async def chat_with_gemini(request: Request):
|
| 172 |
+
start_time = time.time()
|
| 173 |
+
|
| 174 |
+
try:
|
| 175 |
+
|
| 176 |
+
# JSON bodyλ₯Ό μ§μ νμ±
|
| 177 |
+
body = await request.json()
|
| 178 |
+
chat_message = ChatMessage(**body)
|
| 179 |
+
|
| 180 |
+
# qa_chain = get_or_create_chain(request.session_id)
|
| 181 |
+
# result = qa_chain.invoke({"question": request.message})
|
| 182 |
+
qa_chain = get_or_create_chain(chat_message.session_id)
|
| 183 |
+
result = qa_chain.invoke({"question": chat_message.message})
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
# μ°Έκ³ λ¬Έμ μΆμΆ λ° λ‘κ·Έ μΆλ ₯
|
| 187 |
+
source_documents_for_response: List[Dict[str, str]] = []
|
| 188 |
+
if 'source_documents' in result and result['source_documents']:
|
| 189 |
+
print("\n--- μ°Έκ³ λ¬Έμ ---")
|
| 190 |
+
for i, doc in enumerate(result['source_documents']):
|
| 191 |
+
print(f"λ¬Έμ {i+1}:")
|
| 192 |
+
print(f" μμ€: {doc.metadata.get('source', 'μ μ μμ')}")
|
| 193 |
+
print(f" λ΄μ© (μΌλΆ): {doc.page_content[:200]}...") # λ΄μ©μ μΌλΆλ§ μΆλ ₯
|
| 194 |
+
# νλ‘ νΈμλ μλ΅μ μν΄ μ μ₯
|
| 195 |
+
source_documents_for_response.append({
|
| 196 |
+
"source": doc.metadata.get('source', 'μ μ μμ'),
|
| 197 |
+
"content": doc.page_content # μ 체 λ΄μ©μ λ³΄λΌ μλ μμ
|
| 198 |
+
})
|
| 199 |
+
print("---------------\n")
|
| 200 |
+
# ==========================================================
|
| 201 |
+
# βΌβΌβΌβΌβΌβΌβΌβΌβΌβΌβΌβΌβΌβΌβΌβΌβΌβΌ μ΄ λΆλΆλ§ μΆκ° βΌβΌβΌβΌβΌβΌβΌβΌβΌβΌβΌβΌβΌβΌβΌβΌβΌβΌ
|
| 202 |
+
# ==========================================================
|
| 203 |
+
|
| 204 |
+
response_time_ms = int((time.time() - start_time) * 1000)
|
| 205 |
+
|
| 206 |
+
# DBμ λ‘κ·Έ μ μ₯
|
| 207 |
+
try:
|
| 208 |
+
db_conn_str = CONNECTION_STRING.replace("postgresql+psycopg2", "postgresql")
|
| 209 |
+
conn = psycopg2.connect(db_conn_str)
|
| 210 |
+
cur = conn.cursor()
|
| 211 |
+
cur.execute(
|
| 212 |
+
"""
|
| 213 |
+
INSERT INTO chat_logs (session_id, user_id, user_question, bot_answer, retrieved_sources, response_time_ms)
|
| 214 |
+
VALUES (%s, %s, %s, %s, %s, %s);
|
| 215 |
+
""",
|
| 216 |
+
(chat_message.session_id, chat_message.user_id, chat_message.message, result['answer'], json.dumps(source_documents_for_response), response_time_ms)
|
| 217 |
+
)
|
| 218 |
+
conn.commit()
|
| 219 |
+
cur.close()
|
| 220 |
+
conn.close()
|
| 221 |
+
except Exception as db_error:
|
| 222 |
+
print(f"DB λ‘κ·Έ μ μ₯ μ€ν¨: {db_error}")
|
| 223 |
+
|
| 224 |
+
# ==========================================================
|
| 225 |
+
# β²β²β²β²β²β²β²β²β²β²β²β²β²β²β²β²β²β² μ΄ λΆλΆλ§ μΆκ° β²β²β²β²β²β²β²β²β²β²β²β²β²β²β²β²β²β²
|
| 226 |
+
# ==========================================================
|
| 227 |
+
|
| 228 |
+
|
| 229 |
+
|
| 230 |
+
|
| 231 |
+
return ChatResponse(
|
| 232 |
+
response=result['answer'],
|
| 233 |
+
success=True,
|
| 234 |
+
source_documents=source_documents_for_response # μλ΅μ μ°Έκ³ λ¬Έμ μΆκ°
|
| 235 |
+
)
|
| 236 |
+
except Exception as e:
|
| 237 |
+
print(f"μ€λ₯ λ°μ: {str(e)}")
|
| 238 |
+
return ChatResponse(
|
| 239 |
+
response=f"μ€λ₯κ° λ°μνμ΅λλ€: {str(e)}",
|
| 240 |
+
success=False,
|
| 241 |
+
source_documents=[]
|
| 242 |
+
)
|
| 243 |
+
|
| 244 |
+
@app.get("/")
|
| 245 |
+
async def root():
|
| 246 |
+
return {"message": "νκ΅μΈκ΅μ΄λνκ΅(μμΈ) νμ¬ μ±λ΄ API"}
|
| 247 |
+
|
| 248 |
+
|