Skip to content

Commit

Permalink
fix deployment
Browse files Browse the repository at this point in the history
  • Loading branch information
vemonet committed Jan 17, 2025
1 parent f62cce9 commit b8c3398
Show file tree
Hide file tree
Showing 12 changed files with 55 additions and 69 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ RUN pip install -e ".[cpu]" "../sparql-llm"

# https://github.com/tiangolo/uvicorn-gunicorn-docker/blob/master/docker-images/gunicorn_conf.py

CMD ["uvicorn", "src.expasy_agent.api:app", "--host", "0.0.0.0", "--port", "80", "--workers", "8"]
CMD ["uvicorn", "src.expasy_agent.api:app", "--host", "0.0.0.0", "--port", "80", "--workers", "6"]
# CMD ["uvicorn", "src.expasy_agent.api", "--host", "0.0.0.0", "--port", "80", "--workers", "4", "--http", "h11"]
11 changes: 7 additions & 4 deletions chat-with-context/demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<link href="./style.css" rel="stylesheet" />

<script type="module" src="../src/chat-with-context.tsx"></script>
<link href="../src/style.css" rel="stylesheet" />

<!-- <link href="https://unpkg.com/@sib-swiss/chat-with-context/dist/style.css" rel="stylesheet" />
<script type="module" src="https://unpkg.com/@sib-swiss/chat-with-context/dist/chat-with-context.js"></script> -->
Expand Down Expand Up @@ -49,18 +50,20 @@ <h2 class="text-xl text-center font-semibold border-b">
</div>
</h2>
<p>
<strong>ExpasyGPT</strong> is reshaping how researchers explore life science data, streamlining searches across
the <a href="https://www.sib.swiss/">SIB Swiss Institute of Bioinformatics</a>’ databases (learn more
<strong>ExpasyGPT</strong> is reshaping how researchers explore life science data, streamlining searches
across the <a href="https://www.sib.swiss/">SIB Swiss Institute of Bioinformatics</a>’ databases (learn more
<a href="/about-chat">here</a>). This AI-driven tool is powered by metadata and example queries from SPARQL
endpoints like:
</p>
<ul style="list-style: inside;">
<ul style="list-style: inside">
<li>
<a href="http://www.uniprot.org/uniprot/" target="_blank">UniProt</a>, an expertly curated database of
proteins
</li>
<li><a href="https://omabrowser.org/oma/home/" target="_blank">OMA</a>, the orthologous matrix</li>
<li><a href="https://www.bgee.org/" target="_blank">Bgee</a>, an expertly curated gene expression database</li>
<li>
<a href="https://www.bgee.org/" target="_blank">Bgee</a>, an expertly curated gene expression database
</li>
<li>
<a href="https://www.rhea-db.org/" target="_blank">Rhea</a>, an expertly curated database of biochemical
reactions
Expand Down
10 changes: 6 additions & 4 deletions chat-with-context/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,20 @@ <h2 class="text-xl text-center font-semibold border-b pb-2">
</div>
</h2>
<p>
<strong>ExpasyGPT</strong> is reshaping how researchers explore life science data, streamlining searches across
the <a href="https://www.sib.swiss/">SIB Swiss Institute of Bioinformatics</a>’ databases (learn more
<strong>ExpasyGPT</strong> is reshaping how researchers explore life science data, streamlining searches
across the <a href="https://www.sib.swiss/">SIB Swiss Institute of Bioinformatics</a>’ databases (learn more
<a href="/about-chat">here</a>). This AI-driven tool is powered by metadata and example queries from SPARQL
endpoints like:
</p>
<ul style="list-style: inside;">
<ul style="list-style: inside">
<li>
<a href="http://www.uniprot.org/uniprot/" target="_blank">UniProt</a>, an expertly curated database of
proteins
</li>
<li><a href="https://omabrowser.org/oma/home/" target="_blank">OMA</a>, the orthologous matrix</li>
<li><a href="https://www.bgee.org/" target="_blank">Bgee</a>, an expertly curated gene expression database</li>
<li>
<a href="https://www.bgee.org/" target="_blank">Bgee</a>, an expertly curated gene expression database
</li>
<li>
<a href="https://www.rhea-db.org/" target="_blank">Rhea</a>, an expertly curated database of biochemical
reactions
Expand Down
4 changes: 0 additions & 4 deletions chat-with-context/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,10 @@
"version": "npm run lint && npm run build && npm publish"
},
"dependencies": {
"@ai-sdk/openai": "^1.0.18",
"@langchain/core": "^0.3.27",
"@langchain/langgraph": "^0.2.39",
"@langchain/langgraph-sdk": "^0.0.33",
"ai": "^4.0.33",
"dompurify": "^3.2.3",
"feather-icons": "^4.29.2",
"highlight.js": "^11.10.0",
"marked": "^15.0.3",
"solid-element": "^1.9.1",
Expand All @@ -47,7 +44,6 @@
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@types/eslint__js": "^8.42.3",
"@types/feather-icons": "^4.29.4",
"@types/node": "^22.10.2",
"@types/sparqljs": "^3.1.12",
"auto-changelog": "^2.5.0",
Expand Down
5 changes: 3 additions & 2 deletions chat-with-context/src/chat-with-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {streamResponse, ChatState} from "./providers";
// SolidJS custom element: https://github.com/solidjs/solid/blob/main/packages/solid-element/README.md
// https://github.com/solidjs/templates/tree/main/ts-tailwindcss


/**
* Custom element to create a chat interface with a context-aware assistant.
* @example <chat-with-context api="http://localhost:8000/"></chat-with-context>
Expand Down Expand Up @@ -107,7 +106,9 @@ customElement("chat-with-context", {api: "", examples: "", apiKey: "", feedbackA
}

return (
<div class={`chat-with-context w-full h-full flex flex-col ${state.messages().length === 0 ? "justify-center" : ""}`}>
<div
class={`chat-with-context w-full h-full flex flex-col ${state.messages().length === 0 ? "justify-center" : ""}`}
>
<style>{style}</style>
{/* Main chat container */}
<div ref={chatContainerEl} class={`overflow-y-auto ${state.messages().length !== 0 ? "flex-grow" : ""}`}>
Expand Down
44 changes: 14 additions & 30 deletions chat-with-context/src/providers.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import {Accessor, createSignal, Setter} from "solid-js";
import {Client} from "@langchain/langgraph-sdk";
import {RemoteRunnable} from "@langchain/core/runnables/remote";
import {streamText} from 'ai';
import {createOpenAI} from '@ai-sdk/openai';
// import { RemoteGraph } from "@langchain/langgraph/remote";
// import { isAIMessageChunk } from "@langchain/core/messages";

Expand Down Expand Up @@ -52,11 +49,7 @@ export class ChatState {
setMessages: Setter<Message[]>;
abortController: AbortController;

constructor({apiUrl, apiKey, model}: {
apiUrl: string;
apiKey: string;
model: string;
}) {
constructor({apiUrl, apiKey, model}: {apiUrl: string; apiKey: string; model: string}) {
this.apiUrl = apiUrl.endsWith("/") ? apiUrl : apiUrl + "/";
this.apiKey = apiKey;
this.model = model;
Expand All @@ -70,7 +63,7 @@ export class ChatState {
abortRequest = () => {
this.abortController.abort();
this.abortController = new AbortController();
}
};

lastMsg = () => this.messages()[this.messages().length - 1];

Expand Down Expand Up @@ -102,23 +95,18 @@ export class ChatState {
};
}



// Stream a response from various LLM agent providers (OpenAI-like, LangGraph, LangServe)
export async function streamResponse(state: ChatState, question: string) {
state.appendMessage(question, "user");
if (state.apiUrl.endsWith(":2024/") || state.apiUrl.endsWith(":8123/")) {
// Query LangGraph API
await streamLangGraphApi(state);

} else if (state.apiUrl.endsWith("/langgraph/")) {
// Query LangGraph through LangServe API
await streamCustomLangGraph(state);

} else {
} else if (state.apiUrl.endsWith("/completions/")) {
// Query the OpenAI-compatible chat API
await streamOpenAILikeApi(state);
// await streamCustomLangGraph(statse);
} else {
// Query LangGraph through our custom API
await streamCustomLangGraph(state);
}
}

Expand All @@ -145,7 +133,10 @@ async function processLangGraphChunk(state: ChatState, chunk: any) {
if (nodeData.extracted_entities.sparql_query) {
state.lastMsg().setLinks([
{
url: getEditorUrl(nodeData.extracted_entities.sparql_query, nodeData.extracted_entities.sparql_endpoint_url),
url: getEditorUrl(
nodeData.extracted_entities.sparql_query,
nodeData.extracted_entities.sparql_endpoint_url,
),
...queryLinkLabels,
},
]);
Expand All @@ -155,12 +146,7 @@ async function processLangGraphChunk(state: ChatState, chunk: any) {
if (nodeData.validation) {
for (const validationStep of nodeData.validation) {
// Handle messages related to tools (includes post generation validation)
state.appendStepToLastMsg(
validationStep.label,
nodeId,
[],
validationStep.details,
);
state.appendStepToLastMsg(validationStep.label, nodeId, [], validationStep.details);
if (validationStep.type === "recall") {
// When recall-model is called, the model will re-generate the response, so we need to update the message
// If the update contains a message with a fix (e.g. done during post generation validation)
Expand All @@ -185,7 +171,6 @@ async function processLangGraphChunk(state: ChatState, chunk: any) {
if (msg.content && msg.type === "tool") {
// If tool called by model
state.appendStepToLastMsg(`🔧 Tool ${msg.name} result: ${msg.content}`, metadata.langgraph_node);

} else if (msg.content && msg.type === "AIMessageChunk") {
// Response from the model
state.appendContentToLastMsg(msg.content);
Expand All @@ -198,7 +183,7 @@ async function streamCustomLangGraph(state: ChatState) {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${state.apiKey}`
Authorization: `Bearer ${state.apiKey}`,
},
signal: state.abortController.signal,
body: JSON.stringify({
Expand Down Expand Up @@ -229,7 +214,7 @@ async function streamCustomLangGraph(state: ChatState) {
// console.log(line)
try {
const json = JSON.parse(line);
processLangGraphChunk(state, json)
processLangGraphChunk(state, json);
partialLine = "";
} catch {
partialLine += line;
Expand Down Expand Up @@ -261,13 +246,12 @@ async function streamLangGraphApi(state: ChatState) {
}
}


async function streamOpenAILikeApi(state: ChatState) {
const response = await fetch(`${state.apiUrl}chat/completions`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${state.apiKey}`
Authorization: `Bearer ${state.apiKey}`,
},
signal: state.abortController.signal,
body: JSON.stringify({
Expand Down
20 changes: 12 additions & 8 deletions chat-with-context/src/utils.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export const queryLinkLabels = {label: "Run and edit the query", title: "Open the SPARQL query in an editor in a new tab"};
export const queryLinkLabels = {
label: "Run and edit the query",
title: "Open the SPARQL query in an editor in a new tab",
};

export function extractSparqlQuery(markdownContent: string) {
// Regular expression to match SPARQL queries within code blocks
Expand All @@ -13,7 +16,7 @@ export function extractSparqlQuery(markdownContent: string) {
const endpointMatch = lastQuery.match(endpointRegex);
const endpointUrl = endpointMatch ? endpointMatch[1] : null;
if (!endpointUrl) return null;
return getEditorUrl(lastQuery, endpointUrl)
return getEditorUrl(lastQuery, endpointUrl);
// return <a
// class="my-3 px-3 py-1 text-sm text-black dark:text-white bg-gray-300 hover:bg-gray-400 dark:bg-gray-700 dark:hover:bg-gray-800 rounded-lg"
// href="https://sib-swiss.github.io/sparql-editor/?endpoint=${endpointUrl}&query=${encodeURIComponent(lastQuery)}"
Expand All @@ -24,7 +27,7 @@ export function extractSparqlQuery(markdownContent: string) {
}

export function getEditorUrl(query: string, endpointUrl: string = "") {
return `https://sib-swiss.github.io/sparql-editor/?${(endpointUrl) ? `endpoint=${endpointUrl}&` : ""}query=${encodeURIComponent(query)}`;
return `https://sib-swiss.github.io/sparql-editor/?${endpointUrl ? `endpoint=${endpointUrl}&` : ""}query=${encodeURIComponent(query)}`;
}

export function getLangForDocType(docType: string) {
Expand All @@ -50,9 +53,10 @@ export const style = `chat-with-context {
}
.iconBtn {
filter: invert(44%) sepia(22%) saturate(496%) hue-rotate(176deg) brightness(93%) contrast(79%);
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}`;

// @keyframes spin {
// to {
// transform: rotate(360deg);
// }
// }
6 changes: 2 additions & 4 deletions compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,9 @@ services:
- 8000:80
volumes:
- ./packages:/app/packages
environment:
- VECTORDB_HOST=vectordb
command: ["uvicorn", "src.expasy_agent.api:app", "--host", "0.0.0.0", "--port", "80", "--reload"]
# command: ["uvicorn", "src.expasy_agent.api:app", "--host", "0.0.0.0", "--port", "80", "--http", "httptools"]
# command: ["uvicorn", "src.expasy_agent.api:app", "--host", "0.0.0.0", "--port", "80", "--http", "h11"]
# h11 written in python, httptools in C
# entrypoint: /start-reload.sh --http h11

# langgraph-redis:
# extends:
Expand Down
8 changes: 3 additions & 5 deletions compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ services:
# - ./qdrant_config.yml:/qdrant/config/production.yaml
environment:
- QDRANT_ALLOW_RECOVERY_MODE=true
ports:
- 6333:6333
- 6334:6334
# command:
# - ./qdrant --config-path /qdrant/config/production.yaml

Expand All @@ -25,8 +22,9 @@ services:
ports:
- 443:80
environment:
- MAX_WORKERS=6
# cf. https://github.com/tiangolo/uvicorn-gunicorn-docker/blob/master/docker-images/gunicorn_conf.py
# NOTE: disguting hack to fix a bug with podman internal network (podman devs are not competent, this bug comes and goes)
- VECTORDB_HOST=10.89.1.2
# https://github.com/tiangolo/uvicorn-gunicorn-docker/blob/master/docker-images/gunicorn_conf.py
volumes:
- ./data/fastembed_cache:/tmp/fastembed_cache
- ./data/logs:/logs
Expand Down
6 changes: 3 additions & 3 deletions packages/expasy-agent/src/expasy_agent/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def stream_dict(d: dict) -> str:


# @app.post("/chat/completions")
@app.post("/langgraph")
@app.post("/chat")
async def chat(request: Request):
"""Chat with the assistant main endpoint."""
auth_header = request.headers.get("Authorization")
Expand Down Expand Up @@ -263,13 +263,13 @@ def get_user_logs(request: LogsRequest):

@app.get("/", response_class=HTMLResponse, include_in_schema=False)
def chat_ui(request: Request) -> Any:
"""Render the chat UI using jinja2 + HTML"""
"""Render the chat UI using jinja2 + HTML."""
return templates.TemplateResponse(
"index.html",
{
"request": request,
"expasy_key": settings.expasy_api_key,
"api_url": "https://chat.expasy.org/langgraph/",
"api_url": "https://chat.expasy.org/chat/",
"examples": ",".join([
"Which resources are available at the SIB?",
"How can I get the HGNC symbol for the protein P68871?",
Expand Down
7 changes: 3 additions & 4 deletions packages/expasy-agent/src/expasy_agent/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from openai import OpenAI
from pydantic_settings import BaseSettings, SettingsConfigDict
from qdrant_client import QdrantClient
from sparql_llm.utils import get_prefixes_for_endpoints

from expasy_agent import prompts

Expand All @@ -37,10 +36,10 @@ class Settings(BaseSettings):
ontology_chunk_size: int = 3000
ontology_chunk_overlap: int = 200

# vectordb_host: str = "vectordb"
vectordb_host: str = "vectordb"
# vectordb_host: str = "localhost"
# NOTE: old hack to fix a bug with podman internal network, can be removed soon
vectordb_host: str = "10.89.1.2"
# NOTE: disguting hack to fix a bug with podman internal network
# vectordb_host: str = "10.89.1.2"

docs_collection_name: str = "expasy"
entities_collection_name: str = "entities"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Index Wikidata endpoint to be used for QALD-10 benchmark."""

0 comments on commit b8c3398

Please sign in to comment.