From c76668195d6731f1511f1b15e8d4c00012ecc8d1 Mon Sep 17 00:00:00 2001 From: hw-ani Date: Wed, 9 Oct 2024 16:05:52 +0900 Subject: [PATCH 01/12] =?UTF-8?q?Feat:=20=EA=B0=84=EB=8B=A8=ED=95=9C=20API?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - GET /conversations/id-list - GET /conversations/{conversation_id} - POST /conversations - DB 없이 우선 메모리에 구현 --- main.py | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 main.py diff --git a/main.py b/main.py new file mode 100644 index 0000000..068ef0f --- /dev/null +++ b/main.py @@ -0,0 +1,70 @@ +from flask import Flask, request, jsonify, Response +import time +import json +from datetime import datetime + +app = Flask(__name__) + +# Memory DB +conversations = {} +conversation_id_list = [] +new_conversation_id = 0 + +# GET /conversations/id-list +@app.route('/conversations/id-list', methods=['GET']) +def get_id_list(): + return jsonify({"list": conversation_id_list}) + +# GET /conversations/{conversation_id} +@app.route('/conversations/', methods=['GET']) +def get_conversation(conversation_id): + conversation = conversations.get(conversation_id) + if conversation: + return jsonify(conversation) + else: + return jsonify({"error": "Conversation not found"}), 404 + +# POST /conversations +@app.route('/conversations', methods=['POST']) +def create_conversation(): + data = request.get_json() + + # 요청으로부터 필요 데이터 추출 + conversation_id = 0 + conversation_id = data.get('data', {}).get('conversation_id', None) + question = data.get('data', {}).get('question', None) + + # 기존 대화가 없으면 새로 생성 + if conversation_id is None: + global new_conversation_id + conversation_id = new_conversation_id + new_conversation_id += 1 + conversation_id_list.append(conversation_id) + conversations[conversation_id] = { + "title": '${conversation_id}', # 일단 대화 id로 지정 + "engine": "Gemini", + "create_time": datetime.now(), + "update_time": datetime.now(), + "pairing": [] + } + + # 답변 생성 및 저장 + response_data = { + 'data': { + 'answer': "세종대왕은 한글을 창제하셨습니다." + } + } + + # 요청 메시지와 응답 메시지 저장 + conversation_data = { + "id": len(conversations[conversation_id]['pairing']), + "request_message": question, + "response_message": response_data, # 아직 응답은 없으므로 빈 문자열 + "create_time": datetime.now() + } + conversations[conversation_id]['pairing'].append(conversation_data) + + return jsonify(response_data) + +if __name__ == '__main__': + app.run(debug=True) From 1a9d5fc41c5310b361a06dd46b3a34e7a9938d1d Mon Sep 17 00:00:00 2001 From: hw-ani Date: Wed, 9 Oct 2024 20:25:39 +0900 Subject: [PATCH 02/12] =?UTF-8?q?Fix:=20API=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - conversation API 요청에 engine 추가 - conversation API 응답에 title 추가 --- main.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/main.py b/main.py index 068ef0f..7d98a7f 100644 --- a/main.py +++ b/main.py @@ -33,6 +33,11 @@ def create_conversation(): conversation_id = 0 conversation_id = data.get('data', {}).get('conversation_id', None) question = data.get('data', {}).get('question', None) + engine = data.get('data', {}).get('engine', None) + + # error + if (engine is None): + return jsonify({"error": "Engine is not specified"}), 404 # 기존 대화가 없으면 새로 생성 if conversation_id is None: @@ -42,16 +47,21 @@ def create_conversation(): conversation_id_list.append(conversation_id) conversations[conversation_id] = { "title": '${conversation_id}', # 일단 대화 id로 지정 - "engine": "Gemini", + "engine": engine, "create_time": datetime.now(), "update_time": datetime.now(), "pairing": [] } + elif conversation_id not in conversations: + return jsonify({"error": "Conversation not found"}), 404 # 답변 생성 및 저장 + answer = "세종대왕은 한글을 창제하셨습니다." # 여기를 우리가 만든 모델에서 받아오게 추후 수정 response_data = { 'data': { - 'answer': "세종대왕은 한글을 창제하셨습니다." + 'conversation_id': conversation_id, + 'title': conversations[conversation_id]['title'], + 'answer': answer } } @@ -59,7 +69,7 @@ def create_conversation(): conversation_data = { "id": len(conversations[conversation_id]['pairing']), "request_message": question, - "response_message": response_data, # 아직 응답은 없으므로 빈 문자열 + "response_message": answer, "create_time": datetime.now() } conversations[conversation_id]['pairing'].append(conversation_data) From 3d36b1ef6801ac3d58110402f08d9865e71e86b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=ED=9D=AC=EC=A4=91?= Date: Fri, 11 Oct 2024 16:12:35 +0900 Subject: [PATCH 03/12] =?UTF-8?q?feat:=20vertexai=EB=A5=BC=20=EC=9D=B4?= =?UTF-8?q?=EC=9A=A9=ED=95=9C=20pdf=20search=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 0 main.py => app.py | 0 requirements.txt | 0 src/config.py | 0 src/rag.py | 0 src/vertex_ai_search.py | 0 6 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 .gitignore rename main.py => app.py (100%) create mode 100644 requirements.txt create mode 100644 src/config.py create mode 100644 src/rag.py create mode 100644 src/vertex_ai_search.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/main.py b/app.py similarity index 100% rename from main.py rename to app.py diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/config.py b/src/config.py new file mode 100644 index 0000000..e69de29 diff --git a/src/rag.py b/src/rag.py new file mode 100644 index 0000000..e69de29 diff --git a/src/vertex_ai_search.py b/src/vertex_ai_search.py new file mode 100644 index 0000000..e69de29 From c49a8a8151f7fd76b67b9d49b0f34d504ea936b7 Mon Sep 17 00:00:00 2001 From: heej-ng Date: Fri, 11 Oct 2024 16:36:22 +0900 Subject: [PATCH 04/12] =?UTF-8?q?feat:=20vertexai=EB=A5=BC=20=EC=9D=B4?= =?UTF-8?q?=EC=9A=A9=ED=95=9C=20pdf=20search=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=802?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + src/config.py | 4 ++ src/rag.py | 82 ++++++++++++++++++++++++ src/vertex_ai_search.py | 135 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 223 insertions(+) diff --git a/.gitignore b/.gitignore index e69de29..68104c8 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,2 @@ +# Ignore config.py in the src directory +src/config.py \ No newline at end of file diff --git a/src/config.py b/src/config.py index e69de29..3debb92 100644 --- a/src/config.py +++ b/src/config.py @@ -0,0 +1,4 @@ +PROJECT_ID = "" +REGION="asia-northeast3" +MODEL = "gemini-1.5-pro-001" +SEARCH_URL = "" diff --git a/src/rag.py b/src/rag.py index e69de29..a3043a2 100644 --- a/src/rag.py +++ b/src/rag.py @@ -0,0 +1,82 @@ +import requests +from vertexai.generative_models import ( + FunctionDeclaration, + GenerationConfig, + GenerativeModel, + Part, + Tool, +) +import vertex_ai_search + +def tool_declarate() -> Tool: + # 항공 운임표 정보를 조회하는 기능 + get_flight_fare_info = FunctionDeclaration( + name="get_flight_fare_info", + description="Retrieve flight fare information from a PDF based on departure and destination", + parameters={ + "type": "object", + "properties": { + "departure": {"type": "string", "description": "Departure city"}, + "destination": {"type": "string", "description": "Destination city"}, + }, + "required": ["departure", "destination"] + }, + ) + + + # 여객 운송 약관(탑승 수속, 수하물 규정 등)을 조회하는 기능 + get_transport_policy_info = FunctionDeclaration( + name="get_transport_policy_info", + description="Retrieve transportation policy information such as check-in and baggage rules from a PDF", + parameters={ + "type": "object", + "properties": { + "policy_type": {"type": "string", "description": "Type of policy, e.g., check-in, baggage rules"}, + }, + "required": ["policy_type"] + }, + ) + + # # 항공편 정보 조회하는 기능 + # get_flight_info = FunctionDeclaration( + # name="get_transport_policy_info", + # ) + + flight_tool = Tool( + function_declarations=[ + get_flight_fare_info, + get_transport_policy_info, + # get_flight_info, + ], + ) + return flight_tool + +def send_chat_message(prompt:str) -> str: + # tools=[tool_declarate()] + + # model = GenerativeModel( + # "gemini-1.5-pro-001", + # generation_config=GenerationConfig(temperature=0), + # tools=tools, + # ) + # chat = model.start_chat() + + # print("prompt: " + prompt + "\n") + # prompt += """ + # Give a concise, high-level summary. Only use information that you learn from + # the API responses. + # """ + + # # Gemini로 채팅 메시지 보내기 + # response = chat.send_message(prompt) + + # # 함수 호출의 응답에서 값 추출 + # function_call = response.candidates[0].content.parts[0].function_call + + # # Gemini가 판단하여 호출한 함수 + # selected_function_name = function_call.name + # print("selected_function_name: " + selected_function_name, "\n") + answer_response = vertex_ai_search.search_pdf(prompt) + return answer_response + + \ No newline at end of file diff --git a/src/vertex_ai_search.py b/src/vertex_ai_search.py index e69de29..e44ebd4 100644 --- a/src/vertex_ai_search.py +++ b/src/vertex_ai_search.py @@ -0,0 +1,135 @@ +import vertexai +import google +import google.oauth2.credentials +from google.auth import compute_engine +import google.auth.transport.requests +import requests +import json +import os +from langchain_google_vertexai.llms import VertexAI +from langchain.prompts import PromptTemplate +from langchain.chains import LLMChain +import config + +def retrieve_vertex_ai_search(question:str, search_url:str, page_size:int) -> str: + stream = os.popen('gcloud auth print-access-token') + credential_token = stream.read().strip() + + """ retrieve information from enterprise search ( discovery engine )""" + + # Create a credentials token to call a REST API + headers = { + "Authorization": "Bearer "+ credential_token, + "Content-Type": "application/json" + } + + + query_dic ={ + "query": question, + "page_size": str(page_size), + "offset": 0, + "contentSearchSpec":{ + # "snippetSpec": {"maxSnippetCount": 5, + # }, + # "summarySpec": { "summaryResultCount": 5, + # "includeCitations": True}, + "extractiveContentSpec":{ + #"maxExtractiveAnswerCount": 3, + "maxExtractiveSegmentCount": 2, + "num_previous_segments" : 1, + "num_next_segments" : 1, + "return_extractive_segment_score" : True + } + }, + # "queryExpansionSpec":{"condition":"AUTO"} + } + + data = json.dumps(query_dic) + + # Encode data as UTF8 + data=data.encode("utf8") + + response = requests.post(search_url,headers=headers, data=data) + + print(response.text) + return response.text + +def parse_discovery_results(response_text: str) -> dict: + """Parse response to build a context to be sent to LLM.""" + + # JSON 문자열을 파이썬 객체로 변환 + dict_results = json.loads(response_text) + + result_index = 0 + searched_ctx_dic = {} + + # 결과가 있는지 확인 + if dict_results.get('results'): + for result in dict_results['results']: + answer_ctx = "" # 답변 내용을 저장할 변수 + segments_ctx = "" # 세그먼트 내용을 저장할 변수 + + # 문서 링크 가져오기 + reference = result['document']['derivedStructData']['link'] + derivedStructData = result['document']['derivedStructData'] + + # 'extractive_answers'가 존재하는지 확인하고, 답변을 추출 + if 'extractive_answers' in derivedStructData and derivedStructData['extractive_answers']: + for answer in derivedStructData['extractive_answers']: + answer_ctx += answer.get('content', '') # 안전하게 내용 추가 + + # 'extractive_segments'가 존재하는지 확인하고, 세그먼트를 추출 + if 'extractive_segments' in derivedStructData and derivedStructData['extractive_segments']: + for segment in derivedStructData['extractive_segments']: + segments_ctx += segment.get('content', '') # 안전하게 내용 추가 + + # HTML 태그 및 인코딩 제거 + answer_ctx = answer_ctx.replace("", "").replace("", "").replace(""", "") + segments_ctx = segments_ctx.replace("", "").replace("", "").replace(""", "") + + # Google Cloud Storage 링크로 변환 + reference_link = reference.replace("gs://", "https://storage.cloud.google.com/") + + # 결과를 딕셔너리에 저장 + item = { + 'answer_ctx': answer_ctx, + 'segments_ctx': segments_ctx, + 'reference_link': reference_link + } + + searched_ctx_dic[f"Searched Context {result_index}"] = item + result_index += 1 + + return searched_ctx_dic + +def search_pdf(question:str, SEARCH_URL:str) -> str: + gemini_pro = VertexAI( model_name = config.MODEL, + project=config.PROJECT_ID, + location=config.REGION, + verbose=True, + streaming=False, + temperature = 0.2, + top_p = 1, + top_k = 40 + ) + + page_size = 5 + + searched_ctx = retrieve_vertex_ai_search(question, SEARCH_URL, page_size) + context = parse_discovery_results(searched_ctx) + + prompt = PromptTemplate.from_template(""" + + 당신은 항공사 CS AI 어시스턴트입니다. + 아래 Question 에 대해서 반드시 Context에 있는 개별 내용을 기반으로 단계적으로 추론해서 근거를 설명하고 답변해주세요. + Context : {context} + Question : {question} + + """) + + prompt = prompt.format(context=context, question=question) + + print(f"Prompt : {prompt}") + + response = gemini_pro.invoke(prompt) + return response \ No newline at end of file From be4a8f0666896046db1e08a24f80339de8013a42 Mon Sep 17 00:00:00 2001 From: heej-ng Date: Fri, 11 Oct 2024 16:42:08 +0900 Subject: [PATCH 05/12] ignore --- src/config.py | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 src/config.py diff --git a/src/config.py b/src/config.py deleted file mode 100644 index 3debb92..0000000 --- a/src/config.py +++ /dev/null @@ -1,4 +0,0 @@ -PROJECT_ID = "" -REGION="asia-northeast3" -MODEL = "gemini-1.5-pro-001" -SEARCH_URL = "" From c204d22910ca2b0f26eb917b24bcd016b9e95cf6 Mon Sep 17 00:00:00 2001 From: heej-ng Date: Fri, 11 Oct 2024 17:01:40 +0900 Subject: [PATCH 06/12] feat: mvp post api --- app.py | 30 ++++++++++++++++ requirements.txt | 5 +++ src/__init__.py | 0 src/rag.py | 90 ++++++++++++++++++++++++------------------------ 4 files changed, 80 insertions(+), 45 deletions(-) create mode 100644 src/__init__.py diff --git a/app.py b/app.py index 7d98a7f..f959f28 100644 --- a/app.py +++ b/app.py @@ -2,6 +2,7 @@ import time import json from datetime import datetime +from src.rag import send_chat_message app = Flask(__name__) @@ -76,5 +77,34 @@ def create_conversation(): return jsonify(response_data) +@app.route('/mvp/conversations', methods=['POST']) +def create_conversation(): + data = request.get_json() + + # 요청으로부터 필요 데이터 추출 + conversation_id = data.get('data', {}).get('conversation_id', 0) + question = data.get('data', {}).get('question', None) + + # 답변 생성 및 저장 + answer = send_chat_message(question) # 여기를 우리가 만든 모델에서 받아오게 추후 수정 + response_data = { + 'data': { + 'conversation_id': conversation_id, + 'title': "", + 'answer': answer + } + } + + # 요청 메시지와 응답 메시지 저장 + conversation_data = { + "id": len(conversations[conversation_id]['pairing']), + "request_message": question, + "response_message": answer, + "create_time": datetime.now() + } + conversations[conversation_id]['pairing'].append(conversation_data) + + return jsonify(response_data) + if __name__ == '__main__': app.run(debug=True) diff --git a/requirements.txt b/requirements.txt index e69de29..638e503 100644 --- a/requirements.txt +++ b/requirements.txt @@ -0,0 +1,5 @@ +requests +google-auth +google-auth-oauthlib +google-cloud-aiplatform +langchain \ No newline at end of file diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/rag.py b/src/rag.py index a3043a2..d31d001 100644 --- a/src/rag.py +++ b/src/rag.py @@ -1,55 +1,55 @@ import requests -from vertexai.generative_models import ( - FunctionDeclaration, - GenerationConfig, - GenerativeModel, - Part, - Tool, -) +# from vertexai.generative_models import ( +# FunctionDeclaration, +# GenerationConfig, +# GenerativeModel, +# Part, +# Tool, +# ) import vertex_ai_search -def tool_declarate() -> Tool: - # 항공 운임표 정보를 조회하는 기능 - get_flight_fare_info = FunctionDeclaration( - name="get_flight_fare_info", - description="Retrieve flight fare information from a PDF based on departure and destination", - parameters={ - "type": "object", - "properties": { - "departure": {"type": "string", "description": "Departure city"}, - "destination": {"type": "string", "description": "Destination city"}, - }, - "required": ["departure", "destination"] - }, - ) +# def tool_declarate() -> Tool: +# # 항공 운임표 정보를 조회하는 기능 +# get_flight_fare_info = FunctionDeclaration( +# name="get_flight_fare_info", +# description="Retrieve flight fare information from a PDF based on departure and destination", +# parameters={ +# "type": "object", +# "properties": { +# "departure": {"type": "string", "description": "Departure city"}, +# "destination": {"type": "string", "description": "Destination city"}, +# }, +# "required": ["departure", "destination"] +# }, +# ) - # 여객 운송 약관(탑승 수속, 수하물 규정 등)을 조회하는 기능 - get_transport_policy_info = FunctionDeclaration( - name="get_transport_policy_info", - description="Retrieve transportation policy information such as check-in and baggage rules from a PDF", - parameters={ - "type": "object", - "properties": { - "policy_type": {"type": "string", "description": "Type of policy, e.g., check-in, baggage rules"}, - }, - "required": ["policy_type"] - }, - ) +# # 여객 운송 약관(탑승 수속, 수하물 규정 등)을 조회하는 기능 +# get_transport_policy_info = FunctionDeclaration( +# name="get_transport_policy_info", +# description="Retrieve transportation policy information such as check-in and baggage rules from a PDF", +# parameters={ +# "type": "object", +# "properties": { +# "policy_type": {"type": "string", "description": "Type of policy, e.g., check-in, baggage rules"}, +# }, +# "required": ["policy_type"] +# }, +# ) - # # 항공편 정보 조회하는 기능 - # get_flight_info = FunctionDeclaration( - # name="get_transport_policy_info", - # ) +# # # 항공편 정보 조회하는 기능 +# # get_flight_info = FunctionDeclaration( +# # name="get_transport_policy_info", +# # ) - flight_tool = Tool( - function_declarations=[ - get_flight_fare_info, - get_transport_policy_info, - # get_flight_info, - ], - ) - return flight_tool +# flight_tool = Tool( +# function_declarations=[ +# get_flight_fare_info, +# get_transport_policy_info, +# # get_flight_info, +# ], +# ) +# return flight_tool def send_chat_message(prompt:str) -> str: # tools=[tool_declarate()] From c72e3a33a478dfe6e62190b1967c1abd6d71d6d7 Mon Sep 17 00:00:00 2001 From: heej-ng Date: Fri, 11 Oct 2024 17:39:16 +0900 Subject: [PATCH 07/12] =?UTF-8?q?fix.=20import=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/rag.py | 4 ++-- src/vertex_ai_search.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rag.py b/src/rag.py index d31d001..88f5c9b 100644 --- a/src/rag.py +++ b/src/rag.py @@ -6,7 +6,7 @@ # Part, # Tool, # ) -import vertex_ai_search +from .vertex_ai_search import search_pdf # def tool_declarate() -> Tool: # # 항공 운임표 정보를 조회하는 기능 @@ -76,7 +76,7 @@ def send_chat_message(prompt:str) -> str: # # Gemini가 판단하여 호출한 함수 # selected_function_name = function_call.name # print("selected_function_name: " + selected_function_name, "\n") - answer_response = vertex_ai_search.search_pdf(prompt) + answer_response = search_pdf(prompt) return answer_response \ No newline at end of file diff --git a/src/vertex_ai_search.py b/src/vertex_ai_search.py index e44ebd4..2c443e0 100644 --- a/src/vertex_ai_search.py +++ b/src/vertex_ai_search.py @@ -9,7 +9,7 @@ from langchain_google_vertexai.llms import VertexAI from langchain.prompts import PromptTemplate from langchain.chains import LLMChain -import config +from . import config def retrieve_vertex_ai_search(question:str, search_url:str, page_size:int) -> str: stream = os.popen('gcloud auth print-access-token') From f61df82f18df03f6c4183d6634186ca543e93c90 Mon Sep 17 00:00:00 2001 From: heej-ng Date: Fri, 11 Oct 2024 17:46:32 +0900 Subject: [PATCH 08/12] =?UTF-8?q?=ED=95=A8=EC=88=98=EB=AA=85=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.py | 2 +- requirements.txt | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app.py b/app.py index f959f28..00a591e 100644 --- a/app.py +++ b/app.py @@ -78,7 +78,7 @@ def create_conversation(): return jsonify(response_data) @app.route('/mvp/conversations', methods=['POST']) -def create_conversation(): +def mvp_create_conversation(): data = request.get_json() # 요청으로부터 필요 데이터 추출 diff --git a/requirements.txt b/requirements.txt index 638e503..b9c7beb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,6 @@ requests google-auth google-auth-oauthlib google-cloud-aiplatform -langchain \ No newline at end of file +langchain +flask +langchain_google_vertexai \ No newline at end of file From 42badc69787f1f15cd61ac7a0c0edf09d71963a7 Mon Sep 17 00:00:00 2001 From: hw-ani Date: Fri, 11 Oct 2024 21:10:51 +0900 Subject: [PATCH 09/12] Fix: fix to work --- app.py => main.py | 21 +++++++++++++++++++++ src/vertex_ai_search.py | 22 ++++++++++++++++------ 2 files changed, 37 insertions(+), 6 deletions(-) rename app.py => main.py (82%) diff --git a/app.py b/main.py similarity index 82% rename from app.py rename to main.py index 00a591e..76aa401 100644 --- a/app.py +++ b/main.py @@ -84,6 +84,27 @@ def mvp_create_conversation(): # 요청으로부터 필요 데이터 추출 conversation_id = data.get('data', {}).get('conversation_id', 0) question = data.get('data', {}).get('question', None) + engine = data.get('data', {}).get('engine', None) + + # error + if (engine is None): + return jsonify({"error": "Engine is not specified"}), 404 + + # 기존 대화가 없으면 새로 생성 + if conversation_id is None: + global new_conversation_id + conversation_id = new_conversation_id + new_conversation_id += 1 + conversation_id_list.append(conversation_id) + conversations[conversation_id] = { + "title": '${conversation_id}', # 일단 대화 id로 지정 + "engine": engine, + "create_time": datetime.now(), + "update_time": datetime.now(), + "pairing": [] + } + elif conversation_id not in conversations: + return jsonify({"error": "Conversation not found"}), 404 # 답변 생성 및 저장 answer = send_chat_message(question) # 여기를 우리가 만든 모델에서 받아오게 추후 수정 diff --git a/src/vertex_ai_search.py b/src/vertex_ai_search.py index 2c443e0..c759337 100644 --- a/src/vertex_ai_search.py +++ b/src/vertex_ai_search.py @@ -9,7 +9,17 @@ from langchain_google_vertexai.llms import VertexAI from langchain.prompts import PromptTemplate from langchain.chains import LLMChain -from . import config +#from .config import PROJECT_ID, REGION, MODEL, SEARCH_URL +PROJECT_ID = "" +REGION="asia-northeast3" +MODEL = "gemini-1.5-pro-001" +SEARCH_URL = "" +import google.auth.transport.requests +import google.oauth2.id_token +auth_req = google.auth.transport.requests.Request() +audience = "" +id_token = google.oauth2.id_token.fetch_id_token(auth_req, audience) + def retrieve_vertex_ai_search(question:str, search_url:str, page_size:int) -> str: stream = os.popen('gcloud auth print-access-token') @@ -19,7 +29,7 @@ def retrieve_vertex_ai_search(question:str, search_url:str, page_size:int) -> st # Create a credentials token to call a REST API headers = { - "Authorization": "Bearer "+ credential_token, + "Authorization": "Bearer "+ id_token, "Content-Type": "application/json" } @@ -102,10 +112,10 @@ def parse_discovery_results(response_text: str) -> dict: return searched_ctx_dic -def search_pdf(question:str, SEARCH_URL:str) -> str: - gemini_pro = VertexAI( model_name = config.MODEL, - project=config.PROJECT_ID, - location=config.REGION, +def search_pdf(question:str, SEARCH_URL:str = SEARCH_URL) -> str: + gemini_pro = VertexAI( model_name = MODEL, + project=PROJECT_ID, + location=REGION, verbose=True, streaming=False, temperature = 0.2, From a8308199e37efc2aac25164c6a23140bb6de558e Mon Sep 17 00:00:00 2001 From: hw-ani Date: Fri, 11 Oct 2024 22:47:48 +0900 Subject: [PATCH 10/12] Fix: credential --- src/vertex_ai_search.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/vertex_ai_search.py b/src/vertex_ai_search.py index c759337..564b6b1 100644 --- a/src/vertex_ai_search.py +++ b/src/vertex_ai_search.py @@ -14,16 +14,18 @@ REGION="asia-northeast3" MODEL = "gemini-1.5-pro-001" SEARCH_URL = "" + +import google.auth import google.auth.transport.requests -import google.oauth2.id_token +creds, project = google.auth.default() auth_req = google.auth.transport.requests.Request() -audience = "" -id_token = google.oauth2.id_token.fetch_id_token(auth_req, audience) +creds.refresh(auth_req) +id_token = creds.token def retrieve_vertex_ai_search(question:str, search_url:str, page_size:int) -> str: - stream = os.popen('gcloud auth print-access-token') - credential_token = stream.read().strip() + # stream = os.popen('gcloud auth print-access-token') + # credential_token = stream.read().strip() """ retrieve information from enterprise search ( discovery engine )""" From 6dd7daed87402b06870d46402690e15e9187f7e8 Mon Sep 17 00:00:00 2001 From: hw-ani Date: Sat, 12 Oct 2024 13:22:25 +0900 Subject: [PATCH 11/12] =?UTF-8?q?Fix:=20api=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 임시로 사용했던 /mvp/conversations 을 /conversations로 변경 --- main.py | 102 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/main.py b/main.py index 76aa401..ae736e2 100644 --- a/main.py +++ b/main.py @@ -26,58 +26,58 @@ def get_conversation(conversation_id): return jsonify({"error": "Conversation not found"}), 404 # POST /conversations -@app.route('/conversations', methods=['POST']) -def create_conversation(): - data = request.get_json() - - # 요청으로부터 필요 데이터 추출 - conversation_id = 0 - conversation_id = data.get('data', {}).get('conversation_id', None) - question = data.get('data', {}).get('question', None) - engine = data.get('data', {}).get('engine', None) - - # error - if (engine is None): - return jsonify({"error": "Engine is not specified"}), 404 - - # 기존 대화가 없으면 새로 생성 - if conversation_id is None: - global new_conversation_id - conversation_id = new_conversation_id - new_conversation_id += 1 - conversation_id_list.append(conversation_id) - conversations[conversation_id] = { - "title": '${conversation_id}', # 일단 대화 id로 지정 - "engine": engine, - "create_time": datetime.now(), - "update_time": datetime.now(), - "pairing": [] - } - elif conversation_id not in conversations: - return jsonify({"error": "Conversation not found"}), 404 - - # 답변 생성 및 저장 - answer = "세종대왕은 한글을 창제하셨습니다." # 여기를 우리가 만든 모델에서 받아오게 추후 수정 - response_data = { - 'data': { - 'conversation_id': conversation_id, - 'title': conversations[conversation_id]['title'], - 'answer': answer - } - } +# @app.route('/conversations', methods=['POST']) +# def create_conversation(): +# data = request.get_json() + +# # 요청으로부터 필요 데이터 추출 +# conversation_id = 0 +# conversation_id = data.get('data', {}).get('conversation_id', None) +# question = data.get('data', {}).get('question', None) +# engine = data.get('data', {}).get('engine', None) + +# # error +# if (engine is None): +# return jsonify({"error": "Engine is not specified"}), 404 + +# # 기존 대화가 없으면 새로 생성 +# if conversation_id is None: +# global new_conversation_id +# conversation_id = new_conversation_id +# new_conversation_id += 1 +# conversation_id_list.append(conversation_id) +# conversations[conversation_id] = { +# "title": '${conversation_id}', # 일단 대화 id로 지정 +# "engine": engine, +# "create_time": datetime.now(), +# "update_time": datetime.now(), +# "pairing": [] +# } +# elif conversation_id not in conversations: +# return jsonify({"error": "Conversation not found"}), 404 + +# # 답변 생성 및 저장 +# answer = "세종대왕은 한글을 창제하셨습니다." # 여기를 우리가 만든 모델에서 받아오게 추후 수정 +# response_data = { +# 'data': { +# 'conversation_id': conversation_id, +# 'title': conversations[conversation_id]['title'], +# 'answer': answer +# } +# } + +# # 요청 메시지와 응답 메시지 저장 +# conversation_data = { +# "id": len(conversations[conversation_id]['pairing']), +# "request_message": question, +# "response_message": answer, +# "create_time": datetime.now() +# } +# conversations[conversation_id]['pairing'].append(conversation_data) + +# return jsonify(response_data) - # 요청 메시지와 응답 메시지 저장 - conversation_data = { - "id": len(conversations[conversation_id]['pairing']), - "request_message": question, - "response_message": answer, - "create_time": datetime.now() - } - conversations[conversation_id]['pairing'].append(conversation_data) - - return jsonify(response_data) - -@app.route('/mvp/conversations', methods=['POST']) +@app.route('/conversations', methods=['POST']) def mvp_create_conversation(): data = request.get_json() From 547d69c88a643251d99ff5c86c8f0fb637439d86 Mon Sep 17 00:00:00 2001 From: hw-ani Date: Sat, 12 Oct 2024 17:13:47 +0900 Subject: [PATCH 12/12] =?UTF-8?q?Fix:=20CORS=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.py | 2 ++ requirements.txt | 1 + 2 files changed, 3 insertions(+) diff --git a/main.py b/main.py index ae736e2..9879a85 100644 --- a/main.py +++ b/main.py @@ -1,10 +1,12 @@ from flask import Flask, request, jsonify, Response +from flask_cors import CORS import time import json from datetime import datetime from src.rag import send_chat_message app = Flask(__name__) +CORS(app) # Memory DB conversations = {} diff --git a/requirements.txt b/requirements.txt index b9c7beb..c4edea7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,5 @@ google-auth-oauthlib google-cloud-aiplatform langchain flask +flask-cors langchain_google_vertexai \ No newline at end of file