소스 검색

Runnable Version. Experimental changes and new files.

SherryLiu 1 년 전
부모
커밋
40c0e98dea

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+Requirement already satisfied: setuptools in /opt/anaconda3/envs/choozemo-carbon/lib/python3.9/site-packages (70.1.1)

+ 8 - 5
Documents/web_url.csv

@@ -1,5 +1,5 @@
 from dotenv import load_dotenv
 from dotenv import load_dotenv
-load_dotenv()
+load_dotenv('environment.env')
 
 
 from langchain_openai import OpenAIEmbeddings
 from langchain_openai import OpenAIEmbeddings
 from langchain_community.embeddings import OllamaEmbeddings
 from langchain_community.embeddings import OllamaEmbeddings
@@ -38,14 +38,15 @@ from ragas.metrics import (
 import pandas as pd
 import pandas as pd
 import os
 import os
 import glob
 import glob
+import openai
 
 
-from dotenv import load_dotenv
-import os
-load_dotenv()
 URI = os.getenv("SUPABASE_URI")
 URI = os.getenv("SUPABASE_URI")
+openai_api_key = os.getenv("OPENAI_API_KEY")
+openai.api_key = openai_api_key
 
 
 from RAG_strategy import multi_query, naive_rag
 from RAG_strategy import multi_query, naive_rag
 
 
+
 def create_retriever(path='Documents', extension="pdf"):
 def create_retriever(path='Documents', extension="pdf"):
     txt_files = glob.glob(os.path.join(path, f"*.{extension}"))
     txt_files = glob.glob(os.path.join(path, f"*.{extension}"))
     
     
@@ -92,8 +93,10 @@ def create_retriever(path='Documents', extension="pdf"):
 
 
     # vectorstore
     # vectorstore
     # vectorstore = Chroma.from_texts(texts=docs, embedding=OpenAIEmbeddings())
     # vectorstore = Chroma.from_texts(texts=docs, embedding=OpenAIEmbeddings())
-    vectorstore = Chroma.from_documents(documents=docs, embedding=OpenAIEmbeddings())
+    # vectorstore = Chroma.from_documents(documents=docs, embedding=OpenAIEmbeddings(openai_api_key=openai_api_key))
     # vectorstore = Chroma.from_documents(documents=docs, embedding=OllamaEmbeddings(model="llama3", num_gpu=1))
     # vectorstore = Chroma.from_documents(documents=docs, embedding=OllamaEmbeddings(model="llama3", num_gpu=1))
+    vectorstore = Chroma.from_documents(documents=docs, embedding=OllamaEmbeddings(model="gemma2"))
+
     vectorstore.persist()
     vectorstore.persist()
 
 
     retriever = vectorstore.as_retriever()
     retriever = vectorstore.as_retriever()

+ 21 - 9
RAG_app.py

@@ -1,3 +1,6 @@
+from dotenv import load_dotenv
+load_dotenv('environment.env')
+
 from fastapi import FastAPI, Request, HTTPException, status, Body
 from fastapi import FastAPI, Request, HTTPException, status, Body
 # from fastapi.templating import Jinja2Templates
 # from fastapi.templating import Jinja2Templates
 from fastapi.middleware.cors import CORSMiddleware
 from fastapi.middleware.cors import CORSMiddleware
@@ -26,16 +29,17 @@ from RAG_strategy import multi_query, naive_rag, naive_rag_for_qapairs
 from Indexing_Split import create_retriever as split_retriever
 from Indexing_Split import create_retriever as split_retriever
 from Indexing_Split import gen_doc_from_database, gen_doc_from_history
 from Indexing_Split import gen_doc_from_database, gen_doc_from_history
 
 
-from dotenv import load_dotenv
 import os
 import os
 from langchain_community.vectorstores import SupabaseVectorStore
 from langchain_community.vectorstores import SupabaseVectorStore
 from langchain_openai import OpenAIEmbeddings
 from langchain_openai import OpenAIEmbeddings
 from supabase.client import Client, create_client
 from supabase.client import Client, create_client
-
-
 from add_vectordb import GetVectorStore
 from add_vectordb import GetVectorStore
+from langchain_community.cache import RedisSemanticCache  # 更新导入路径
+from langchain_core.prompts import PromptTemplate
+import openai
 
 
-load_dotenv()
+openai_api_key = os.getenv("OPENAI_API_KEY")
+openai.api_key = openai_api_key
 URI = os.getenv("SUPABASE_URI")
 URI = os.getenv("SUPABASE_URI")
 
 
 global_retriever = None
 global_retriever = None
@@ -50,12 +54,12 @@ async def lifespan(app: FastAPI):
     # global_retriever = raptor_retriever(path='../Documents', extension="txt")
     # global_retriever = raptor_retriever(path='../Documents', extension="txt")
     # global_retriever = unstructured_retriever(path='../Documents')
     # global_retriever = unstructured_retriever(path='../Documents')
 
 
-    supabase_url = os.environ.get("SUPABASE_URL")
-    supabase_key = os.environ.get("SUPABASE_KEY")
+    supabase_url = os.getenv("SUPABASE_URL")
+    supabase_key = os.getenv("SUPABASE_KEY")
     document_table = "documents"
     document_table = "documents"
     supabase: Client = create_client(supabase_url, supabase_key)
     supabase: Client = create_client(supabase_url, supabase_key)
 
 
-    embeddings = OpenAIEmbeddings()
+    embeddings = OpenAIEmbeddings(openai_api_key=openai_api_key)
     vector_store = GetVectorStore(embeddings, supabase, document_table)
     vector_store = GetVectorStore(embeddings, supabase, document_table)
     global_retriever = vector_store.as_retriever(search_kwargs={"k": 4})
     global_retriever = vector_store.as_retriever(search_kwargs={"k": 4})
 
 
@@ -180,7 +184,15 @@ async def get_history():
     result = loads(result)
     result = loads(result)
     return result.values()
     return result.values()
 
 
+@app.get("/")
+def read_root():
+    return {"message": "Welcome to the SYSTEX API"}
+
+
 if __name__ == "__main__":
 if __name__ == "__main__":
-    uvicorn.run("RAG_app:app", host='cmm.ai', port=8081, reload=True, ssl_keyfile="/etc/letsencrypt/live/cmm.ai/privkey.pem", 
-                ssl_certfile="/etc/letsencrypt/live/cmm.ai/fullchain.pem")
+    uvicorn.run("RAG_app:app", host='127.0.0.1', port=8081, reload=True)
+    
+# if __name__ == "__main__":
+#     uvicorn.run("RAG_app:app", host='cmm.ai', port=8081, reload=True, ssl_keyfile="/etc/letsencrypt/live/cmm.ai/privkey.pem", 
+#                 ssl_certfile="/etc/letsencrypt/live/cmm.ai/fullchain.pem")
 
 

+ 215 - 0
RAG_app_copy.py

@@ -0,0 +1,215 @@
+from dotenv import load_dotenv
+load_dotenv('environment.env')
+
+from fastapi import FastAPI, Request, HTTPException, status, Body
+# from fastapi.templating import Jinja2Templates
+from fastapi.middleware.cors import CORSMiddleware
+from fastapi.responses import FileResponse
+from fastapi import Depends
+from contextlib import asynccontextmanager
+from pydantic import BaseModel
+from typing import List, Optional
+import uvicorn
+
+import sqlparse
+from sqlalchemy import create_engine
+import pandas as pd
+#from retrying import retry
+import datetime
+import json
+from json import loads
+import time
+from langchain.callbacks import get_openai_callback
+
+from langchain_community.vectorstores import Chroma
+from langchain_openai import OpenAIEmbeddings
+from RAG_strategy import multi_query, naive_rag, naive_rag_for_qapairs
+from Indexing_Split import create_retriever as split_retriever
+from Indexing_Split import gen_doc_from_database, gen_doc_from_history
+
+import os
+from langchain_community.vectorstores import SupabaseVectorStore
+from langchain_openai import OpenAIEmbeddings
+from supabase.client import Client, create_client
+from add_vectordb import GetVectorStore
+from langchain_community.cache import RedisSemanticCache  # 更新导入路径
+from langchain_core.prompts import PromptTemplate
+import openai
+
+# Get API log
+import logging
+logger = logging.getLogger("uvicorn.error")
+
+openai_api_key = os.getenv("OPENAI_API_KEY")
+URI = os.getenv("SUPABASE_URI")
+openai.api_key = openai_api_key
+
+
+global_retriever = None
+
+# 定義FastAPI的生命週期管理器,在啟動和關閉時執行特定操作
+@asynccontextmanager
+async def lifespan(app: FastAPI):
+    global global_retriever
+    global vector_store
+    
+    start = time.time()
+    # global_retriever = split_retriever(path='./Documents', extension="docx")
+    # global_retriever = raptor_retriever(path='../Documents', extension="txt")
+    # global_retriever = unstructured_retriever(path='../Documents')
+
+    supabase_url = os.getenv("SUPABASE_URL")
+    supabase_key = os.getenv("SUPABASE_KEY")
+    URI = os.getenv("SUPABASE_URI")
+    document_table = "documents"
+    supabase: Client = create_client(supabase_url, supabase_key)
+
+    embeddings = OpenAIEmbeddings(openai_api_key=openai_api_key)
+    vector_store = GetVectorStore(embeddings, supabase, document_table)
+    global_retriever = vector_store.as_retriever(search_kwargs={"k": 4})
+
+    print(time.time() - start)
+    yield
+
+# 定義依賴注入函數,用於在請求處理過程中獲取全局變量
+def get_retriever():
+    return global_retriever
+
+
+def get_vector_store():
+    return vector_store
+
+# 創建FastAPI應用實例並配置以及中間件
+app = FastAPI(lifespan=lifespan)
+
+# templates = Jinja2Templates(directory="temp")
+app.add_middleware(
+    CORSMiddleware,
+    allow_origins=["*"],
+    allow_credentials=True,
+    allow_methods=["*"],
+    allow_headers=["*"],
+)
+
+
+# 定義API路由和處理函數
+# 處理傳入的問題並返回答案
+@app.get("/answer2")
+def multi_query_answer(question, retriever=Depends(get_retriever)):
+    try:
+        start = time.time()
+
+        with get_openai_callback() as cb:
+            # qa_doc = gen_doc_from_database()
+            # qa_history_doc = gen_doc_from_history()
+            # qa_doc.extend(qa_history_doc)
+            # vectorstore = Chroma.from_documents(documents=qa_doc, embedding=OpenAIEmbeddings(), collection_name="qa_pairs")
+            # retriever_qa = vectorstore.as_retriever(search_kwargs={"k": 3})
+            # final_answer, reference_docs = naive_rag_for_qapairs(question, retriever_qa)
+            final_answer = 'False'
+            if final_answer == 'False':
+                final_answer, reference_docs = multi_query(question, retriever, chat_history=[])
+
+        # print(CHAT_HISTORY)
+        
+        # with get_openai_callback() as cb:
+        #     final_answer, reference_docs = multi_query(question, retriever)
+        processing_time = time.time() - start
+        print(processing_time)
+        save_history(question, final_answer, reference_docs, cb, processing_time)
+
+        return {"Answer": final_answer}
+    except Exception as e:
+        logger.error(f"Error in /answer2 endpoint: {e}")
+        raise HTTPException(status_code=500, detail="Internal Server Error")
+
+class ChatHistoryItem(BaseModel):
+    q: str
+    a: str
+
+# 處理帶有歷史聊天紀錄的問題並返回答案
+@app.post("/answer_with_history")
+def multi_query_answer(question: Optional[str] = '', chat_history: List[ChatHistoryItem] = Body(...), retriever=Depends(get_retriever)):
+    start = time.time()
+    
+    chat_history = [(item.q, item.a) for item in chat_history if item.a != ""]
+    print(chat_history)
+
+    # TODO: similarity search
+    
+    with get_openai_callback() as cb:
+        final_answer, reference_docs = multi_query(question, retriever, chat_history)
+    processing_time = time.time() - start
+    print(processing_time)
+    save_history(question, final_answer, reference_docs, cb, processing_time)
+
+    return {"Answer": final_answer}
+
+# 處理帶有聊天歷史紀錄和文件名過濾的問題,並返回答案
+@app.post("/answer_with_history2")
+def multi_query_answer(question: Optional[str] = '', extension: Optional[str] = 'pdf', chat_history: List[ChatHistoryItem] = Body(...), retriever=Depends(get_retriever)):
+    start = time.time()
+
+    retriever = vector_store.as_retriever(search_kwargs={"k": 4,
+                                                         'filter': {'extension':extension}})
+    
+    chat_history = [(item.q, item.a) for item in chat_history if item.a != ""]
+    print(chat_history)
+
+    # TODO: similarity search
+    
+    with get_openai_callback() as cb:
+        final_answer, reference_docs = multi_query(question, retriever, chat_history)
+    processing_time = time.time() - start
+    print(processing_time)
+    save_history(question, final_answer, reference_docs, cb, processing_time)
+
+    return {"Answer": final_answer}
+
+# 保存歷史。將處理結果儲存到數據庫
+def save_history(question, answer, reference, cb, processing_time):
+    # reference = [doc.dict() for doc in reference]
+    record = {
+        'Question': [question],
+        'Answer': [answer],
+        'Total_Tokens': [cb.total_tokens],
+        'Total_Cost': [cb.total_cost],
+        'Processing_time': [processing_time],
+        'Contexts': [str(reference)]
+    }
+    df = pd.DataFrame(record)
+    engine = create_engine(URI)
+    df.to_sql(name='systex_records', con=engine, index=False, if_exists='append')
+
+class history_output(BaseModel):
+    Question: str
+    Answer: str
+    Contexts: str
+    Total_Tokens: int
+    Total_Cost: float
+    Processing_time: float
+    Time: datetime.datetime
+
+# 定義獲取歷史紀錄的路由
+@app.get('/history', response_model=List[history_output])
+async def get_history():
+    engine = create_engine(URI, echo=True)
+
+    df = pd.read_sql_table("systex_records", engine.connect())  
+    df.fillna('', inplace=True)
+    result = df.to_json(orient='index', force_ascii=False)
+    result = loads(result)
+    return result.values()
+
+@app.get("/")
+def read_root():
+    return {"message": "Welcome to the Carbon Chatbot API"}
+
+
+if __name__ == "__main__":
+    uvicorn.run("RAG_app_copy:app", host='127.0.0.1', port=8081, reload=True)
+    
+# if __name__ == "__main__":
+#     uvicorn.run("RAG_app:app", host='cmm.ai', port=8081, reload=True, ssl_keyfile="/etc/letsencrypt/live/cmm.ai/privkey.pem", 
+#                 ssl_certfile="/etc/letsencrypt/live/cmm.ai/fullchain.pem")
+

+ 74 - 14
RAG_strategy.py

@@ -30,20 +30,53 @@ from ragas.metrics import (
     context_precision,
     context_precision,
 )
 )
 from typing import List
 from typing import List
+import os
 from dotenv import load_dotenv
 from dotenv import load_dotenv
-load_dotenv()
+load_dotenv('environment.env')
 
 
 ########################################################################################################################
 ########################################################################################################################
 ########################################################################################################################
 ########################################################################################################################
 from langchain.cache import SQLiteCache
 from langchain.cache import SQLiteCache
-
 from langchain.cache import RedisSemanticCache
 from langchain.cache import RedisSemanticCache
 from langchain_openai import OpenAIEmbeddings
 from langchain_openai import OpenAIEmbeddings
-# set_llm_cache(SQLiteCache(database_path=".langchain.db"))
-set_llm_cache(RedisSemanticCache(redis_url="redis://localhost:6380", embedding=OpenAIEmbeddings(), score_threshold=0.0005))
+from langchain.globals import set_llm_cache
+
 ########################################################################################################################
 ########################################################################################################################
+import requests
+import openai
+openai_api_key = os.getenv("OPENAI_API_KEY")
+openai.api_key = openai_api_key
+URI = os.getenv("SUPABASE_URI")
+
+# 設置緩存,以減少對API的重複請求。使用Redis
+# set_llm_cache(SQLiteCache(database_path=".langchain.db"))
+# set_llm_cache(RedisSemanticCache(redis_url="redis://localhost:6380", embedding=OpenAIEmbeddings(openai_api_key=openai_api_key), score_threshold=0.0005))
+
+# # TAIDE model on Ollama https://ollama.com/jcai/llama3-taide-lx-8b-chat-alpha1
+# def interact_with_model(messages, api_url="http://localhost:11434/v1/chat/completions"):
+#     print("Using model: TAIDE")
+#     response = requests.post(api_url, json={"model": "jcai/llama3-taide-lx-8b-chat-alpha1:Q4_K_M", "messages": messages})
+#     return response.json()["choices"][0]["message"]["content"]
+
+# class CustomTAIDELLM(LLM):
+#     api_url: str = "http://localhost:11434/v1/chat/completions"
+    
+#     def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
+#         messages = [{"role": "user", "content": prompt}]
+#         response = requests.post(self.api_url, json={
+#             "model": "taide-local",  # Use your local model name
+#             "messages": messages
+#         })
+#         return response.json()["choices"][0]["message"]["content"]
+    
+#     @property
+#     def _llm_type(self) -> str:
+#         return "custom_taide"
 
 
+# # Create an instance of the custom LLM
+# taide_llm = CustomTAIDELLM()
 
 
+# 生成多個不同版本的問題,進行檢索,並返回答案和參考文檔
 def multi_query(question, retriever, chat_history):
 def multi_query(question, retriever, chat_history):
 
 
     def multi_query_chain():
     def multi_query_chain():
@@ -60,9 +93,18 @@ def multi_query(question, retriever, chat_history):
         Original question: {question}"""
         Original question: {question}"""
         prompt_perspectives = ChatPromptTemplate.from_template(template)
         prompt_perspectives = ChatPromptTemplate.from_template(template)
 
 
+        messages = [
+            {"role": "system", "content": template},
+            {"role": "user", "content": question},
+        ]
+        # generate_queries = interact_with_model(messages).split("\n")
+
         
         
-        llm = ChatOpenAI(temperature=0, model="gpt-4-1106-preview")
+        llm = ChatOpenAI(model="gpt-4-1106-preview")
         # llm = ChatOllama(model="llama3", num_gpu=1, temperature=0)
         # llm = ChatOllama(model="llama3", num_gpu=1, temperature=0)
+        # llm = ChatOllama(model="gemma2", temperature=0)
+        # llm = ChatOllama(model=model)
+
 
 
         generate_queries = (
         generate_queries = (
             prompt_perspectives 
             prompt_perspectives 
@@ -96,6 +138,7 @@ def multi_query(question, retriever, chat_history):
 
 
     return answer, docs
     return answer, docs
 
 
+# 根據檢索到的文檔和用戶問題生成最後答案
 def multi_query_rag_prompt(retrieval_chain, question):
 def multi_query_rag_prompt(retrieval_chain, question):
     # RAG
     # RAG
     template = """Answer the following question based on this context:
     template = """Answer the following question based on this context:
@@ -103,16 +146,20 @@ def multi_query_rag_prompt(retrieval_chain, question):
     {context}
     {context}
 
 
     Question: {question}
     Question: {question}
-    Output in user's language. If the question is in zh-tw, then the output will be in zh-tw. \n
+    Output in user's language. If the question is in zh-tw, then the output will be in zh-tw. If the question is in English, then the output will be in English\n
     You should not mention anything about "根據提供的文件內容" or other similar terms.
     You should not mention anything about "根據提供的文件內容" or other similar terms.
-    If you don't know the answer, just say that "很抱歉,目前我無法回答您的問題,請將您的詢問發送至 test@systex.com 以便獲得更進一步的幫助,謝謝。"
+    If you don't know the answer, just say that "很抱歉,目前我無法回答您的問題,請將您的詢問發送至 test@email.com 以便獲得更進一步的幫助,謝謝。I'm sorry I cannot answer your question. Please send your question to test@email.com for further assistance. Thank you."
     """
     """
 
 
     prompt = ChatPromptTemplate.from_template(template)
     prompt = ChatPromptTemplate.from_template(template)
+    context = retrieval_chain.invoke({"question": question})  # Ensure this returns the context
+
 
 
     # llm = ChatOpenAI(temperature=0)
     # llm = ChatOpenAI(temperature=0)
-    llm = ChatOpenAI(temperature=0, model="gpt-4-1106-preview")
+    llm = ChatOpenAI(model="gpt-4-1106-preview")
     # llm = ChatOllama(model="llama3", num_gpu=1, temperature=0)
     # llm = ChatOllama(model="llama3", num_gpu=1, temperature=0)
+    # llm = ChatOllama(model="gemma2", temperature=0)
+
 
 
     final_rag_chain = (
     final_rag_chain = (
         {"context": retrieval_chain, 
         {"context": retrieval_chain, 
@@ -121,8 +168,13 @@ def multi_query_rag_prompt(retrieval_chain, question):
         | llm
         | llm
         | StrOutputParser()
         | StrOutputParser()
     )
     )
-
-    # answer = final_rag_chain.invoke({"question":question})
+    messages = [
+        {"role": "system", "content": template},
+        {"role": "user", "content": question},
+        {"role": "assistant", "content": context}
+    ]
+    # answer = interact_with_model(messages)
+    answer = final_rag_chain.invoke({"question":question})
 
 
     answer = ""
     answer = ""
     for text in final_rag_chain.stream({"question":question}):
     for text in final_rag_chain.stream({"question":question}):
@@ -133,6 +185,7 @@ def multi_query_rag_prompt(retrieval_chain, question):
     return answer
     return answer
 ########################################################################################################################
 ########################################################################################################################
 
 
+# 將聊天紀錄個跟進問題轉化為獨立問題
 def get_search_query():
 def get_search_query():
     # Condense a chat history and follow-up question into a standalone question
     # Condense a chat history and follow-up question into a standalone question
     # 
     # 
@@ -185,7 +238,7 @@ def get_search_query():
                 chat_history=lambda x: _format_chat_history(x["chat_history"])
                 chat_history=lambda x: _format_chat_history(x["chat_history"])
             )
             )
             | CONDENSE_QUESTION_PROMPT
             | CONDENSE_QUESTION_PROMPT
-            | ChatOpenAI(temperature=0)
+            | ChatOpenAI()
             | StrOutputParser(),
             | StrOutputParser(),
         ),
         ),
         # Else, we have no chat history, so just pass through the question
         # Else, we have no chat history, so just pass through the question
@@ -194,6 +247,7 @@ def get_search_query():
 
 
     return _search_query
     return _search_query
 ########################################################################################################################
 ########################################################################################################################
+# 檢索文檔並生成答案
 def naive_rag(question, retriever):
 def naive_rag(question, retriever):
     #### RETRIEVAL and GENERATION ####
     #### RETRIEVAL and GENERATION ####
 
 
@@ -201,7 +255,7 @@ def naive_rag(question, retriever):
     prompt = hub.pull("rlm/rag-prompt")
     prompt = hub.pull("rlm/rag-prompt")
 
 
     # LLM
     # LLM
-    llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0)
+    llm = ChatOpenAI(model_name="gpt-3.5-turbo")
 
 
     # Post-processing
     # Post-processing
     def format_docs(docs):
     def format_docs(docs):
@@ -222,6 +276,7 @@ def naive_rag(question, retriever):
 
 
     return answer, reference
     return answer, reference
 ################################################################################################
 ################################################################################################
+# 處理question-answer pairs的檢索和生成答案
 def naive_rag_for_qapairs(question, retriever):
 def naive_rag_for_qapairs(question, retriever):
     #### RETRIEVAL and GENERATION ####
     #### RETRIEVAL and GENERATION ####
 
 
@@ -242,8 +297,10 @@ def naive_rag_for_qapairs(question, retriever):
     prompt = PromptTemplate.from_template(template)
     prompt = PromptTemplate.from_template(template)
 
 
     # LLM
     # LLM
-    llm = ChatOpenAI(model_name="gpt-4-0125-preview", temperature=0)
+    llm = ChatOpenAI(model_name="gpt-4-0125-preview")
     # llm = ChatOllama(model="llama3", num_gpu=1, temperature=0)
     # llm = ChatOllama(model="llama3", num_gpu=1, temperature=0)
+    # llm = ChatOllama(model="gemma2", num_gpu=1, temperature=0)
+
 
 
     # Post-processing
     # Post-processing
     def format_docs(docs):
     def format_docs(docs):
@@ -285,4 +342,7 @@ def rag_score(question, ground_truth, answer, reference_docs):
         ],
         ],
     )
     )
 
 
-    return result
+    result_df = result.to_pandas()
+    print(result_df.head())
+    result_df.to_csv('ragas_rag.csv')
+    return result

+ 6 - 3
add_vectordb.py

@@ -1,5 +1,5 @@
 from dotenv import load_dotenv
 from dotenv import load_dotenv
-load_dotenv()
+load_dotenv('environment.env')
 
 
 from langchain_openai import OpenAIEmbeddings
 from langchain_openai import OpenAIEmbeddings
 from langchain_community.vectorstores import Chroma
 from langchain_community.vectorstores import Chroma
@@ -10,6 +10,7 @@ from langchain_community.document_loaders import Docx2txtLoader
 
 
 import os
 import os
 import glob
 import glob
+import openai
 
 
 from langchain_community.vectorstores import SupabaseVectorStore
 from langchain_community.vectorstores import SupabaseVectorStore
 from langchain_openai import OpenAIEmbeddings
 from langchain_openai import OpenAIEmbeddings
@@ -156,16 +157,18 @@ if __name__ == "__main__":
     load_dotenv()
     load_dotenv()
     supabase_url = os.environ.get("SUPABASE_URL")
     supabase_url = os.environ.get("SUPABASE_URL")
     supabase_key = os.environ.get("SUPABASE_KEY")
     supabase_key = os.environ.get("SUPABASE_KEY")
+    openai_api_key = os.getenv("OPENAI_API_KEY")
+    openai.api_key = openai_api_key
     document_table = "documents"
     document_table = "documents"
     supabase: Client = create_client(supabase_url, supabase_key)
     supabase: Client = create_client(supabase_url, supabase_key)
 
 
-    embeddings = OpenAIEmbeddings()
+    embeddings = OpenAIEmbeddings(openai_api_key=openai_api_key)
 
 
     # get vector store
     # get vector store
     vector_store = GetVectorStore(embeddings, supabase, document_table)
     vector_store = GetVectorStore(embeddings, supabase, document_table)
 
 
     # update data (old + new / all new / all old)
     # update data (old + new / all new / all old)
-    path = "/home/mia/systex/Documents"
+    path = "/Documents"
     extension = "pdf"
     extension = "pdf"
     # file = None
     # file = None
 
 

BIN
chroma_db_ans_embedding/7838d8cb-5095-4375-9b13-12b88180bde3/data_level0.bin


BIN
chroma_db_ans_embedding/7838d8cb-5095-4375-9b13-12b88180bde3/header.bin


BIN
chroma_db_ans_embedding/7838d8cb-5095-4375-9b13-12b88180bde3/length.bin


+ 0 - 0
chroma_db_ans_embedding/7838d8cb-5095-4375-9b13-12b88180bde3/link_lists.bin


BIN
chroma_db_ans_embedding/chroma.sqlite3


BIN
chroma_db_carbon_questions/chroma.sqlite3


BIN
chroma_db_carbon_questions/d763afe8-0d8a-40c1-a761-ce87166384fb/data_level0.bin


BIN
chroma_db_carbon_questions/d763afe8-0d8a-40c1-a761-ce87166384fb/header.bin


BIN
chroma_db_carbon_questions/d763afe8-0d8a-40c1-a761-ce87166384fb/length.bin


+ 0 - 0
chroma_db_carbon_questions/d763afe8-0d8a-40c1-a761-ce87166384fb/link_lists.bin


+ 20 - 0
docker-compose.yml

@@ -0,0 +1,20 @@
+version: '3'
+services:
+  ollama:
+    image: ollama/ollama
+    volumes:
+      - ollama:/root/.ollama
+      - /Users/sherry/Documents/_Personal/ChoozeMo/notebooks/carbon/llm/ollama:/models
+    ports:
+      - "11434:11434"
+    mem_limit: 16g
+    cpus: 6
+    command: sh -c "ollama create taide-local -f /models/ide-7b-a.2-q4_k_m.gguf && ollama run taide-local"
+
+  redis:
+    image: redis:alpine
+    ports:
+      - "6379:6379"
+
+volumes:
+  ollama:

BIN
dump.rdb


+ 7 - 0
environment.env

@@ -0,0 +1,7 @@
+# Choozemo
+SUPABASE_URI = "postgresql://postgres:chuz8310xsystex@db.ptt.cx:5432/postgres"
+SUPABASE_URL = "http://db.ptt.cx:8000/"
+SUPABASE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q"
+OPENAI_API_KEY = "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"
+HF_API_KEY_7B = "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"
+HF_API_KEY_7B4BIT = "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"

+ 8 - 0
main.log

@@ -0,0 +1,8 @@
+[1719898830] Log start
+[1719898830] Cmd: /usr/local/Cellar/llama.cpp/3274/bin/llama-cli --hf-repo taide/TAIDE-LX-7B-Chat-4bit --hf-file /Users/sherryliu/Documents/_Personal/choozemo/notebooks/carbon/taide-7b-a.2-q4_k_m.gguf -p "I believe the meaning of life is" -n 128
+[1719898830] main: build = 3274 (49122a87)
+[1719898830] main: built with Apple clang version 15.0.0 (clang-1500.3.9.4) for x86_64-apple-darwin23.4.0
+[1719898830] main: seed  = 1719898830
+[1719898830] main: llama backend init
+[1719898830] main: load the model and apply lora adapter, if any
+[1719898830] main: error: unable to load model

+ 97 - 0
out.gv

@@ -0,0 +1,97 @@
+digraph G {
+concentrate=true;
+splines="ortho";
+rankdir="LR";
+subgraph legend{
+    rank = min;
+    label = "legend";
+    Legend [shape=none, margin=0, label = <
+        <table cellspacing="0" cellpadding="0" border="1"><tr><td>Code2flow Legend</td></tr><tr><td>
+        <table cellspacing="0">
+        <tr><td>Regular function</td><td width="50px" bgcolor='#cccccc'></td></tr>
+        <tr><td>Trunk function (nothing calls this)</td><td bgcolor='#966F33'></td></tr>
+        <tr><td>Leaf function (this calls nothing else)</td><td bgcolor='#6db33f'></td></tr>
+        <tr><td>Function call</td><td><font color='black'>&#8594;</font></td></tr>
+        </table></td></tr></table>
+        >];
+}node_7d4b4651 [label="47: lifespan()" name="RAG_app::lifespan" shape="rect" style="rounded,filled" fillcolor="#966F33" ];
+node_4fbd994f [label="116: multi_query_answer()" name="RAG_app::multi_query_answer" shape="rect" style="rounded,filled" fillcolor="#966F33" ];
+node_4c386252 [label="87: multi_query_answer()" name="RAG_app::multi_query_answer" shape="rect" style="rounded,filled" fillcolor="#966F33" ];
+node_9bfa629c [label="134: multi_query_answer()" name="RAG_app::multi_query_answer" shape="rect" style="rounded,filled" fillcolor="#966F33" ];
+node_71a3aeb0 [label="153: save_history()" name="RAG_app::save_history" shape="rect" style="rounded,filled" fillcolor="#6db33f" ];
+node_649e182e [label="147: get_search_query()" name="RAG_strategy::get_search_query" shape="rect" style="rounded,filled" fillcolor="#6db33f" ];
+node_7c28ff05 [label="58: multi_query()" name="RAG_strategy::multi_query" shape="rect" style="rounded,filled" fillcolor="#cccccc" ];
+node_fdd77cdf [label="110: multi_query_rag_prompt()" name="RAG_strategy::multi_query_rag_prompt" shape="rect" style="rounded,filled" fillcolor="#6db33f" ];
+node_4413d1fa [label="0: (global)()" name="add_vectordb::(global)" shape="rect" style="rounded,filled" fillcolor="#966F33" ];
+node_d7743d95 [label="132: __init__()" name="add_vectordb::GetVectorStore.__init__" shape="rect" style="rounded,filled" fillcolor="#cccccc" ];
+node_65de84e4 [label="141: delete()" name="add_vectordb::GetVectorStore.delete" shape="rect" style="rounded,filled" fillcolor="#cccccc" ];
+node_5b1175ed [label="135: insert()" name="add_vectordb::GetVectorStore.insert" shape="rect" style="rounded,filled" fillcolor="#6db33f" ];
+node_e96a8b7c [label="145: update()" name="add_vectordb::GetVectorStore.update" shape="rect" style="rounded,filled" fillcolor="#cccccc" ];
+node_6dc6ba18 [label="125: check_existed_data()" name="add_vectordb::check_existed_data" shape="rect" style="rounded,filled" fillcolor="#6db33f" ];
+node_03dc279e [label="71: create_ids()" name="add_vectordb::create_ids" shape="rect" style="rounded,filled" fillcolor="#6db33f" ];
+node_ba1cc301 [label="20: get_data_list()" name="add_vectordb::get_data_list" shape="rect" style="rounded,filled" fillcolor="#cccccc" ];
+node_76ea7487 [label="104: get_document()" name="add_vectordb::get_document" shape="rect" style="rounded,filled" fillcolor="#cccccc" ];
+node_b5a8f76f [label="35: read_and_split_files()" name="add_vectordb::read_and_split_files" shape="rect" style="rounded,filled" fillcolor="#cccccc" ];
+node_53c93e6f [label="0: (global)()" name="indexing_Split::(global)" shape="rect" style="rounded,filled" fillcolor="#966F33" ];
+node_40bbb064 [label="50: create_retriever()" name="indexing_Split::create_retriever" shape="rect" style="rounded,filled" fillcolor="#cccccc" ];
+node_fa144567 [label="117: gen_doc_from_history()" name="indexing_Split::gen_doc_from_history" shape="rect" style="rounded,filled" fillcolor="#6db33f" ];
+node_7d4b4651 -> node_d7743d95 [color="#E69F00" penwidth="2"];
+node_4c386252 -> node_71a3aeb0 [color="#56B4E9" penwidth="2"];
+node_4c386252 -> node_7c28ff05 [color="#56B4E9" penwidth="2"];
+node_4fbd994f -> node_71a3aeb0 [color="#CC79A7" penwidth="2"];
+node_4fbd994f -> node_7c28ff05 [color="#CC79A7" penwidth="2"];
+node_9bfa629c -> node_71a3aeb0 [color="#F0E442" penwidth="2"];
+node_9bfa629c -> node_7c28ff05 [color="#F0E442" penwidth="2"];
+node_7c28ff05 -> node_649e182e [color="#0072B2" penwidth="2"];
+node_7c28ff05 -> node_fdd77cdf [color="#0072B2" penwidth="2"];
+node_4413d1fa -> node_d7743d95 [color="#56B4E9" penwidth="2"];
+node_4413d1fa -> node_e96a8b7c [color="#56B4E9" penwidth="2"];
+node_4413d1fa -> node_76ea7487 [color="#56B4E9" penwidth="2"];
+node_d7743d95 -> node_d7743d95 [color="#0072B2" penwidth="2"];
+node_65de84e4 -> node_65de84e4 [color="#F0E442" penwidth="2"];
+node_e96a8b7c -> node_65de84e4 [color="#F0E442" penwidth="2"];
+node_e96a8b7c -> node_5b1175ed [color="#F0E442" penwidth="2"];
+node_ba1cc301 -> node_6dc6ba18 [color="#E69F00" penwidth="2"];
+node_76ea7487 -> node_03dc279e [color="#CC79A7" penwidth="2"];
+node_76ea7487 -> node_b5a8f76f [color="#CC79A7" penwidth="2"];
+node_b5a8f76f -> node_ba1cc301 [color="#CC79A7" penwidth="2"];
+node_53c93e6f -> node_7c28ff05 [color="#CC79A7" penwidth="2"];
+node_53c93e6f -> node_7c28ff05 [color="#CC79A7" penwidth="2"];
+node_53c93e6f -> node_40bbb064 [color="#CC79A7" penwidth="2"];
+node_40bbb064 -> node_fa144567 [color="#F0E442" penwidth="2"];
+subgraph cluster_a5d3d6e2 {
+    node_7d4b4651 node_4c386252 node_4fbd994f node_9bfa629c node_71a3aeb0;
+    label="File: RAG_app";
+    name="RAG_app";
+    style="filled";
+    graph[style=dotted];
+};
+subgraph cluster_d5bd3b3c {
+    node_7c28ff05 node_fdd77cdf node_649e182e;
+    label="File: RAG_strategy";
+    name="RAG_strategy";
+    style="filled";
+    graph[style=dotted];
+};
+subgraph cluster_3a83d666 {
+    node_ba1cc301 node_b5a8f76f node_03dc279e node_76ea7487 node_6dc6ba18 node_4413d1fa;
+    label="File: add_vectordb";
+    name="add_vectordb";
+    style="filled";
+    graph[style=dotted];
+    subgraph cluster_622c6110 {
+        node_d7743d95 node_5b1175ed node_65de84e4 node_e96a8b7c;
+        label="Class: GetVectorStore";
+        name="GetVectorStore";
+        style="filled";
+        graph[style=dotted];
+    };
+};
+subgraph cluster_87c7db5c {
+    node_40bbb064 node_fa144567 node_53c93e6f;
+    label="File: indexing_Split";
+    name="indexing_Split";
+    style="filled";
+    graph[style=dotted];
+};
+}

BIN
out.png


+ 29 - 0
ragas_data_generation.py

@@ -0,0 +1,29 @@
+from dotenv import load_dotenv
+load_dotenv('environment.env')
+
+
+from ragas.testset.generator import TestsetGenerator
+from ragas.testset.evolutions import simple, reasoning, multi_context 
+from langchain_openai import ChatOpenAi, OpenAIEmbeddings
+from langchain_community.document_loaders import DirectoryLoader
+from langchain_community.document_loaders import PyPDFLoader
+
+loader = DirectoryLoader("Documents")
+for file in 
+documents = loader.load()
+
+
+for document in documents:
+    document.metadata['filename'] = document.metadata['source']
+
+generator_llm = ChatOpenAi(model = "gpt-3.5-turbo-16k")
+critic_llm = ChatOpenAI(model="gpt-4")
+embeddings = OpenAIEmbeddings()
+
+generator = TestGenerator.from_langchain(
+    generator_llm,
+    critic_llm,
+    embeddings
+)
+# Generate testset
+testset = generator.generate_with_langchain_docs(documents, test_size=10, distributions={simple: 0.5, reasoning: 0.25, multi_context: 0.25})

+ 10 - 0
requirements.txt

@@ -140,3 +140,13 @@ wrapt==1.16.0
 xxhash==3.4.1
 xxhash==3.4.1
 yarl==1.9.4
 yarl==1.9.4
 zipp==3.18.1
 zipp==3.18.1
+python-dotenv
+fastapi
+sqlparse
+sqlalchemy
+pandas
+langchain
+datasets
+ragas
+supabase
+psycopg2-binary

+ 83 - 0
requirements_semantic_search.txt

@@ -0,0 +1,83 @@
+#!/bin/bash
+
+# Set environment variables
+export OPENAI_API_KEY="sk-proj-kGQPjKXup6g5QmjWvN3GT3BlbkFJDOYyhv8auoHBDIznmbgj"
+export SUPABASE_URI=postgresql://postgres:chuz8310xsystex@db.ptt.cx:5432/postgres
+export SUPABASE_URL="http://db.ptt.cx:8000/"
+export SUPABASE_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q"
+
+
+Function to check if Docker is running
+start_docker() {
+    if ! docker info > /dev/null 2>&1; then
+        echo "Starting Docker Desktop..."
+        open --background -a Docker
+        # Wait until Docker daemon is running
+        while ! docker info > /dev/null 2>&1; do
+            echo "Waiting for Docker to start..."
+            sleep 1
+        done
+        echo "Docker started."
+    else
+        echo "Docker is already running."
+    fi
+}
+
+#########################################
+# # Start Docker if it's not already running
+# if ! systemctl is-active --quiet docker; then
+#     echo "Starting Docker..."
+#     sudo systemctl start docker
+#     sleep 5  # Wait for Docker to fully start
+# fi
+
+# # Get the script directory
+# script_dir=$(dirname "$0")
+
+# # Change to the directory containing the docker-compose.yml file
+# cd "$script_dir"
+
+# # Start the services defined in docker-compose.yml
+# echo "Starting services with Docker Compose..."
+# docker-compose up -d
+
+# # Wait for services to be fully up
+# echo "Waiting for services to start..."
+# sleep 20  # Adjust this time as needed
+
+# # Change to the directory containing your Python script
+# cd "$script_dir/systex-RAG-sherry"
+
+# Run your Python script
+# echo "Running RAG application..."
+# python RAG_app_copy.py
+
+##########################################
+
+# Check and manage Redis Stack container
+if [ "$(docker ps -a -q -f name=redis-stack)" ]; then
+    if [ ! "$(docker ps -q -f name=redis-stack)" ]; then
+        echo "Starting existing Redis Stack container..."
+        docker start redis-stack
+    else
+        echo "Redis Stack container is already running."
+    fi
+else
+    echo "Creating and starting Redis Stack container..."
+    docker run -d --name redis-stack -p 6380:6379 redis/redis-stack:latest
+fi
+
+# Check if Redis container started successfully
+if [ ! "$(docker ps -q -f name=redis-stack)" ]; then
+    echo "Redis Stack container failed to start. Exiting script."
+    exit 1
+fi
+
+echo "Running RAG application..."
+python RAG_app_copy.py
+
+# 使脚本文件可执行:
+# chmod +x run.sh
+
+# /answer2?question=解釋碳排放法規
+

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 175 - 175
semantic_cache.ipynb


+ 102 - 0
test_connection.py

@@ -0,0 +1,102 @@
+# import os
+# import sys
+
+# from supabase import create_client, Client
+
+# # # Load environment variables
+# from dotenv import load_dotenv
+# load_dotenv('environment.env')
+
+# # Get Supabase configuration from environment variables
+# SUPABASE_URL = os.getenv("SUPABASE_URL")
+# SUPABASE_KEY = os.getenv("SUPABASE_KEY")
+# SUPABASE_URI = os.getenv("SUPABASE_URI")
+# OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
+
+# # Check if environment variables are successfully loaded
+# if not SUPABASE_URL or not SUPABASE_KEY or not OPENAI_API_KEY or not SUPABASE_URI:
+#     print("Please ensure SUPABASE_URL, SUPABASE_KEY, and OPENAI_API_KEY are correctly set in the .env file.")
+#     sys.exit(1)
+# else:
+#     print("Connection successful.")
+#     try:
+#         supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
+#         print("Client created successfully.")
+#     except Exception as e:
+#         print("Client creation failed:", e)
+#         sys.exit(1)
+
+# # List all table names
+# try:
+#     response = supabase.table('information_schema.tables').select('table_name').eq('table_schema', 'public').execute()
+#     table_names = [table['table_name'] for table in response.data]
+#     print("All table names:")
+#     for name in table_names:
+#         print(name)
+# except Exception as e:
+#     print("Connection failed:", e)
+#     sys.exit(1)
+
+
+# ### Test hugging face tokens for the TAIDE local model. ######################################################
+# from transformers import AutoTokenizer, AutoModelForCausalLM
+
+# token = os.getenv("HF_API_KEY_7B4BIT")
+
+# # Check if the token is loaded correctly
+# if token is None:
+#     raise ValueError("Hugging Face API token is not set. Please check your environment.env file.")
+
+# # Load the tokenizer and model with the token
+# try:
+#     tokenizer = AutoTokenizer.from_pretrained("../TAIDE-LX-7B-Chat-4bit", token=token)  
+#     model = AutoModelForCausalLM.from_pretrained("../TAIDE-LX-7B-Chat-4bit", token=token)
+    
+#     # Verify the model and tokenizer
+#     print(f"Loaded tokenizer: {tokenizer.name_or_path}")
+#     print(f"Loaded model: {model.name_or_path}")
+
+#     # Optional: Print model and tokenizer configuration for more details
+#     print(f"Model configuration: {model.config}")
+#     print(f"Tokenizer configuration: {tokenizer}")
+
+# except Exception as e:
+#     print(f"Error loading model or tokenizer: {e}")
+
+#################################################################################################################
+# import torch
+# from transformers import AutoModelForCausalLM, AutoTokenizer
+# from huggingface_hub import hf_hub_download
+# from llama_cpp import Llama
+
+# ## Download the GGUF model
+# model_name = "TheBloke/Mixtral-8x7B-Instruct-v0.1-GGUF"
+# model_file = "mixtral-8x7b-instruct-v0.1.Q4_K_M.gguf" # this is the specific model file we'll use in this example. It's a 4-bit quant, but other levels of quantization are available in the model repo if preferred
+# model_path = hf_hub_download(model_name, filename=model_file)
+
+
+
+
+# import requests
+
+# def generate_response(input_text, max_length=512, temperature=0.7):
+#     # URL to interact with the model
+#     url = "http://localhost:11434/v1/chat/completions"  # Adjust based on how Ollama exposes the model
+
+#     # Payload to send to the model
+#     payload = {
+#         "input": input_text,
+#         "parameters": {
+#             "max_length": max_length,
+#             "temperature": temperature
+#         }
+#     }
+
+#     # Make a request to the model
+#     response = requests.post(url, json=payload)
+#     return response.json()["output"]
+
+# if __name__ == "__main__":
+#     input_text = "I believe the meaning of life is"
+#     response = generate_response(input_text, max_length=128, temperature=0.5)
+#     print(f"Model: {response}")

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.