| import os |
| import glob |
| import warnings |
| import gradio as gr |
|
|
| from langchain_openai import ChatOpenAI |
| from langchain_community.vectorstores import Chroma |
| from langchain_huggingface import HuggingFaceEmbeddings |
|
|
| from langchain.agents import create_agent |
| from langchain.agents.middleware import dynamic_prompt, ModelRequest |
| from huggingface_hub import snapshot_download |
|
|
| warnings.filterwarnings('ignore') |
| os.environ["WANDB_DISABLED"] = "true" |
|
|
| DATA_DIR = "./chroma" |
| ENDPOINT_URL = "https://router.huggingface.co/v1" |
| MODEL_NAME = "meta-llama/Llama-3.1-70B-Instruct" |
|
|
| chunk_size=1500 |
| chunk_overlap=30 |
| separator="\n" |
| max_tokens=1000 |
| splitter_type='recursive' |
|
|
| docs_path = f"{DATA_DIR}/refs/" |
| refs_path = f"{DATA_DIR}/links" |
|
|
| snapshot_download(repo_id="CGIAR/weai-refs", |
| repo_type="dataset", |
| token=os.getenv('HF_TOKEN'), |
| local_dir=DATA_DIR |
| ) |
|
|
| llm_client = ChatOpenAI(base_url=ENDPOINT_URL, |
| api_key=os.getenv('HF_TOKEN'), |
| model=MODEL_NAME, |
| temperature=0, |
| max_retries=2, |
| extra_headers={"X-HF-Bill-To": "cgiar"} |
| ) |
|
|
|
|
| embeddings = HuggingFaceEmbeddings( |
| model_name="sentence-transformers/all-mpnet-base-v2", |
| encode_kwargs={"normalize_embeddings": True}, |
| model_kwargs = {"device": "cpu"} |
| ) |
|
|
| |
| docs_vector_db = Chroma(persist_directory=docs_path, embedding_function=embeddings) |
| refs_vector_db = Chroma(persist_directory=refs_path, embedding_function=embeddings) |
|
|
| @dynamic_prompt |
| def ref_context(request: ModelRequest) -> str: |
| """Inject context into state messages.""" |
| last_query = request.state["messages"][-1].text |
| ref_content = refs_vector_db.similarity_search(last_query, k=10) |
|
|
| system_message = ( |
| """ |
| Use the given context to add citations to the attached research findings and: |
| - include source URLs as citations |
| - Format citations as markdown links: [Source Title](URL) |
| - Group sources in a "Sources:" section at the end of your response |
| |
| Make any necessary edits to the findings and only use links and citations from the 'Link/URL' field in the context. |
| |
| ### OUTDATED LINKS |
| these organisations and their corresponding websites are no longer active: |
| - USAID |
| - Feed the Future |
| """ |
| f"### Context\n\n{ref_content}" |
| ) |
|
|
| return system_message |
|
|
|
|
| @dynamic_prompt |
| def doc_context(request: ModelRequest) -> str: |
| """Inject context into state messages.""" |
| last_query = request.state["messages"][-1].text |
| doc_content = docs_vector_db.similarity_search(last_query, k=10) |
|
|
| system_message = ( |
| """You are a research agent specialized in the Women's Empowerment in Agriculture Index (WEAI). |
| |
| Use the following context to answer questions. |
| Be as detailed as possible, but don't make up any information that's not from the context and where possible reference related studies and resources |
| from the context you have. |
| """ |
| f"\n\n{doc_content}" |
| ) |
|
|
| return system_message |
|
|
| def weai_support(query: str): |
| findings = response_agent.invoke({"messages": [{"role": "user", "content": query}]}) |
| response = findings['messages'][-1].content |
|
|
| return findings, citation_agent.invoke({"messages": [{"role": "user", "content": response}]}) |
|
|
| response_agent = (create_agent(llm_client, tools=[], middleware=[doc_context])) |
| citation_agent = (create_agent(llm_client, tools=[], middleware=[ref_context])) |
|
|
| with gr.Blocks() as demo: |
| with gr.Sidebar(): |
| gr.LoginButton() |
| gr.Markdown("# WEAI-bot") |
| chatbot = gr.Chatbot(type='messages', |
| allow_tags=True) |
| msg = gr.Textbox() |
| clear = gr.ClearButton([msg, chatbot]) |
|
|
| def handle_undo(history, undo_data: gr.UndoData): |
| return history[:undo_data.index], history[undo_data.index]['content'][0]["text"] |
|
|
| def handle_retry(history, retry_data: gr.RetryData): |
| new_history = history[:retry_data.index] |
| previous_prompt = history[retry_data.index]['content'][0]["text"] |
| yield from support_agent_fn(previous_prompt, new_history) |
|
|
| def support_agent_fn(message, history): |
| findings, response = weai_support(message) |
|
|
| response = response['messages'][-1].content |
| history.append({"role": "user", "content": message}) |
| history.append({"role": "assistant", "content": response}) |
|
|
| return "", history |
| |
| def handle_like(data: gr.LikeData): |
| if data.liked: |
| print("You upvoted this response: ", data.value) |
| else: |
| print("You downvoted this response: ", data.value) |
|
|
| def handle_edit(history, edit_data: gr.EditData): |
| new_history = history[:edit_data.index] |
| new_history[-1]['content'] = [{"text": edit_data.value, "type": "text"}] |
| return new_history |
|
|
| msg.submit(support_agent_fn, [msg, chatbot], [msg, chatbot]) |
|
|
| chatbot.undo(handle_undo, chatbot, [chatbot, msg]) |
| chatbot.retry(handle_retry, chatbot, chatbot) |
| chatbot.like(handle_like, None, None) |
| chatbot.edit(handle_edit, chatbot, chatbot) |
|
|
| if __name__ == "__main__": |
| demo.launch() |
|
|