Skip to content

Commit

Permalink
Merge pull request #149 from bioimage-io/add-ackonwledgement
Browse files Browse the repository at this point in the history
Add acknowledgement for articles/books
  • Loading branch information
oeway authored Aug 14, 2024
2 parents 73c8ad6 + af0c69a commit 132123f
Show file tree
Hide file tree
Showing 9 changed files with 364 additions and 82 deletions.
23 changes: 22 additions & 1 deletion bioimageio_chatbot/chatbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,28 @@ class ThoughtsSchema(BaseModel):
tool_usage_prompt=tool_usage_prompt,
)
result_steps = metadata["steps"]

# Create a map to store the mapping of result step names to their corresponding info
info_map = {}
# Iterate through each extension in the dictionary
for ext_id, ext in extensions_by_id.items():
# Iterate through the info dictionary of each extension
for tool_key, tool_info in ext.info.items():
# remove all special characters and convert to lowercase, and add `ext_id` to the beginning
step_name = f"{ext_id}-{tool_key}".replace(" ", "").replace("-", "").replace("_","").lower()
# Map the step name to the tool info
info_map[step_name] = tool_info

for idx, step_list in enumerate(result_steps):
for step in step_list:
# Get the step name
step_name = step['name'].lower()
# Get the corresponding info for the step
step_info = info_map.get(step_name)
if step_info:
# Add the info to the step details
step["info"] = step_info

steps.append(
ResponseStep(
name=f"step-{idx}", details={"details": convert_to_dict(step_list)}
Expand Down Expand Up @@ -215,7 +236,7 @@ class ThoughtsSchema(BaseModel):

# convert to a list
all_extensions = [
{"id": ext.id, "name": ext.name, "description": ext.description} for ext in builtin_extensions
{"id": ext.id, "name": ext.name, "description": ext.description, "info": ext.info} for ext in builtin_extensions
]
# remove item with 'book' in all_extensions
melman_extensions = [
Expand Down
25 changes: 21 additions & 4 deletions bioimageio_chatbot/chatbot_extensions/docs_extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,22 @@ async def run_extension(

channel_id = collection["id"]
base_url = collection.get("base_url")
reference = collection.get("reference")
if base_url:
base_url_prompt = f" The documentation is available at {base_url}."
else:
base_url_prompt = ""


if reference:
reference_prompt = f" The reference is available at {reference}."
else:
reference_prompt = ""
run_extension.__name__ = "Search" + title_case(channel_id)
run_extension.__doc__ = f"""Searching documentation for {channel_id}: {collection['description']}.{base_url_prompt}"""
run_extension.__doc__ = f"""Searching documentation for {channel_id}: {collection['description']}.{base_url_prompt}. {reference_prompt}"""
return schema_tool(run_extension)

INFO_KEYS = ["name","description", "authors", "license", "reference"]

def get_extension():
collections = get_manifest()["collections"]
knowledge_base_path = os.environ.get(
Expand All @@ -141,26 +148,36 @@ def get_extension():
docs_store_dict = load_knowledge_base(knowledge_base_path)

docs_tools = {}
docs_info = {}
books_tools = {}
books_info = {}
for col in collections:
info = {k: col[k] for k in INFO_KEYS if k in col}
if "book" in col["id"]:
books_tools["search_" + col["id"]] = create_tool(docs_store_dict, col)
if info:
books_info["search_" + col["id"]] = info
else:
docs_tools["search_" + col["id"]] = create_tool(docs_store_dict, col)
if info:
docs_info["search_" + col["id"]] = info


if docs_tools:
sinfo1 = ChatbotExtension(
id="docs",
name="Search BioImage Docs",
description="Search information in the documents of the bioimage.io knowledge base. Provide a list of keywords to search information in the documents. Returns a list of relevant documents.",
description="Search information in the documents of the bioimage.io knowledge base. Provide a list of keywords to search information in the documents. Returns a list of relevant documents. Ensure that the reference to the document is ALWAYS included!",
tools=docs_tools,
info=docs_info
)
if books_tools:
sinfo2 = ChatbotExtension(
id="books",
name="Search BioImage Books",
description="Search information in BioImage books. Provide a list of keywords to search information in the books. Returns a list of relevant documents.",
description="Search information in BioImage books. Provide a list of keywords to search information in the books. Returns a list of relevant documents. Ensure that the reference to the book is ALWAYS included!",
tools=books_tools,
info=books_info
)

return sinfo1, sinfo2
10 changes: 2 additions & 8 deletions bioimageio_chatbot/knowledge_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,14 @@
import pickle
from bioimageio_chatbot.utils import get_manifest, download_file

KNOWLEDGE_BASE_URL = os.environ.get("BIOIMAGEIO_KNOWLEDGE_BASE_URL", "https://uk1s3.embassy.ebi.ac.uk/public-datasets/bioimageio-knowledge-base")


def load_docs_store(db_path, collection_name):
# Each collection has two files [collection_name].faiss and [collection_name].pkl
# Check if it exists, otherwise, download from {KNOWLEDGE_BASE_URL}/[collection].faiss
if not os.path.exists(os.path.join(db_path, f"{collection_name}.faiss")):
print(f"Downloading {collection_name}.faiss from {KNOWLEDGE_BASE_URL}/{collection_name}.faiss")
download_file(f"{KNOWLEDGE_BASE_URL}/{collection_name}.faiss", os.path.join(db_path, f"{collection_name}.faiss"))

raise Exception(f"Please build the docs store {collection_name} by running create_vector_knowledge_base first.")
if not os.path.exists(os.path.join(db_path, f"{collection_name}.pkl")):
print(f"Downloading {collection_name}.pkl from {KNOWLEDGE_BASE_URL}/{collection_name}.pkl")
download_file(f"{KNOWLEDGE_BASE_URL}/{collection_name}.pkl", os.path.join(db_path, f"{collection_name}.pkl"))

raise Exception(f"Please build the docs store {collection_name} by running create_vector_knowledge_base first.")
# Load from vector store
embeddings = OpenAIEmbeddings()
docs_store = FAISS.load_local(index_name=collection_name, folder_path=db_path, embeddings=embeddings, allow_dangerous_deserialization=True)
Expand Down
196 changes: 152 additions & 44 deletions bioimageio_chatbot/static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -341,12 +341,7 @@
<i class="fas fa-thumbs-down"></i>
</button> for each response, or by clicking the 'Feedback' button below.
</p>

<p>Note that the chatbot is still in beta and is being actively developed, we will log the message you input into
the chatbot for further investigation of issues and support our development. See <a
href="https://github.com/bioimage-io/bioimageio-chatbot/blob/main/docs/DISCLAIMER.md" target="_blank">the
Disclaimer</a> for more details. If you want to to remove your chat logs, please contact us via <a
href="https://oeway.typeform.com/to/K3j2tJt7" target="_blank">this form</a>.</p>
<p>Note that the BioImage.IO Chatbot is part of a research project focused on Text and Data Mining (TDM) and is still in beta, being actively developed. The chatbot is intended for research and educational purposes only and is not meant for production or commercial use. We log the messages you input into the chatbot to support ongoing research, improve the service, and investigate any issues. Please be aware that the chatbot utilizes copyrighted materials under the EU's TDM exception. For more details, see <a href="https://github.com/bioimage-io/bioimageio-chatbot/blob/main/docs/DISCLAIMER.md" target="_blank">the Disclaimer</a>. If you are an author and wish to opt-out your material or if you want your chat logs removed, please contact us via <a href="https://oeway.typeform.com/to/K3j2tJt7" target="_blank">this form</a>.</p>
<button class="feedback-button" onclick="confirmDisclaimer()">OK, got it!</button>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" value="" id="dont-ask-again-check">
Expand Down Expand Up @@ -491,6 +486,7 @@ <h3 class="text-center">Welcome to BioImage.IO Chatbot</h3>
<br>
<span>Extensions: </span>
<select multiple="multiple" style="width: calc(100% - 100px);" id="extensions"></select>
<div id="about-extensions" style="margin-top:10px"></div>
</div>
</div>
</div>
Expand Down Expand Up @@ -1607,6 +1603,7 @@ <h3 class="text-center">Welcome to BioImage.IO Chatbot</h3>
}
}
updateDropdownOptions(extensions);
updateAboutExtensions(extensions);
showReadyStatus();
appendRobotMessage(allAssistants[assistantName]['welcome_message'], "message-0"); // Append robot message to the message container
return svc;
Expand Down Expand Up @@ -1686,6 +1683,81 @@ <h3 class="text-center">Welcome to BioImage.IO Chatbot</h3>
return '<a target="_blank" href="' + href + '" title="' + title + '">' + text + '</a>';
}

function updateAboutExtensions(extensions) {
$('#about-extensions').empty();

// Create the card structure
const card = document.createElement('div');
card.className = 'card';
const cardHeader = `
<div class="card-header">
<img src="https://bioimage.io/static/img/bioimage-io-icon.svg" alt="BioImage.IO Icon" style="height: 24px; margin-right: 10px">
About BioImage.IO Chatbot Extensions
</div>`;

const cardBody = document.createElement('div');
cardBody.className = 'card-body';

// Add leading text
const leadingText = `<div class="leading-text">
<p>Our chatbot is enhanced by a diverse set of extensions that utilize the following valuable sources. We extend our sincere gratitude to all contributors, particularly the original authors whose works have significantly enriched this project. These sources are primarily used for research purposes, in accordance with the European Union's copyright exception on Text and Data Mining (TDM) under <a href="https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX%3A32019L0790" target="_blank">Directive (EU) 2019/790</a>.</p>
<p>If you are an author of any material used within these extensions and wish to have your content removed or updated, we respectfully request that you contact us directly. You can do so via <a href="https://oeway.typeform.com/to/K3j2tJt7" target="_blank">this form</a>. We will promptly address your concerns and ensure that your material is removed from our system.</p>
<p><strong>Notice:</strong> Users of this chatbot are kindly reminded to carefully check with the original sources for accuracy and completeness. For any work derived from these sources, please ensure that you respect their respective licenses and adhere to the conditions set forth by the original authors.</p>
</div>`;

// Append title and leading text to the card body
cardBody.innerHTML = leadingText;

// Initialize a markdown renderer
const renderer = new marked.Renderer();

for (const ext of extensions) {
const extInfo = document.createElement('div');

// Start creating markdown content with improved formatting
let markdownContent = `### ${ext.name} 📚\n\n#### ${ext.description}\n\n`;

// Iterate through each tool in the extension info
for (const [key, tool] of Object.entries(ext.info)) {
markdownContent += `----\n**${tool.name} 🛠️**\n\n`;
markdownContent += `**📝 Description**: ${tool.description}\n\n`;
if(tool.authors && tool.authors.length > 0){
markdownContent += `**👥 Authors**:\n`;
for (const author of tool.authors) {
markdownContent += `- ${author.name}, *${author.organization}*\n`;
}
}
if(tool.license){
markdownContent += `**📜 License**: ${tool.license}\n\n`;
}
if (tool.reference) {
markdownContent += `**🔗 [Reference](${tool.reference})**: ${tool.reference}\n\n`;
}
}

// Convert markdown content to HTML using marked
const renderedContent = marked(markdownContent, { renderer: renderer });

// Wrap the content in a collapsible <details> block
extInfo.innerHTML = `
<details class='details-box'>
<summary>Extension: ${ext.name}</summary>
${renderedContent}
</details>
`;

// Append the rendered content to the card body
cardBody.appendChild(extInfo);
}

// Combine the card structure
card.innerHTML = cardHeader;
card.appendChild(cardBody);

// Append the entire card to the about-extensions section
$('#about-extensions').append(card);
}

function autoResize() {
this.style.height = (this.scrollHeight) + 'px';
}
Expand Down Expand Up @@ -1838,49 +1910,85 @@ <h3 class="text-center">Welcome to BioImage.IO Chatbot</h3>
}
const steps = response.steps;
let message = response.text && marked(response.text, { renderer: renderer }) || "";
if (steps && steps.length > 0) {
let details = "<details class='details-box'> <summary>🔍More Details</summary>\n\n"
for (let step of steps) {
details += `## ${step.name}\n\n`;

if (step.details.details) {
for (let detail of step.details.details) {
details += `-----\n### Tool Call: \`${detail.name}\`\n\n`;
details += "#### Arguments:\n\n";
if (detail.args && detail.args.length > 0) {
for (let arg of detail.args) {
const argValue = JSON.stringify(arg);
details += `\`\`\`\n${argValue}\n\`\`\`\n\n`;
}
details += "\n\n";
}

if (detail.kwargs) {
for (let kwarg in detail.kwargs) {
const kwargValue = typeof detail.kwargs[kwarg] === 'string' ? detail.kwargs[kwarg] : JSON.stringify(detail.kwargs[kwarg], null, 2);
if(kwargValue.includes('\n'))
details += `**- \`${kwarg}\`**:\n\n\`\`\`\n${kwargValue}\n\`\`\`\n\n`;
else
details += `**- \`${kwarg}\`**: \`${kwargValue}\`\n\n`;
}
details += "\n\n";
}

if(detail.result){
const result = typeof detail.result === 'string' ? detail.result : JSON.stringify(detail.result, null, 2);
if(result.includes('\n'))
details += `#### Result:\n\n\`\`\`\n${result}\n\`\`\`\n\n`;
else
details += `#### Result: \`${result}\`\n\n`;
if (steps && steps.length > 0) {
let details = "<details class='details-box'> <summary>🔍More Details</summary>\n\n";

for (let step of steps) {
details += `## ${step.name}\n\n`;

if (step.details.details) {
for (let detail of step.details.details) {
details += `-----\n### Tool Call: \`${detail.name}\`\n\n`;
details += "#### Arguments:\n\n";

if (detail.args && detail.args.length > 0) {
for (let arg of detail.args) {
const argValue = JSON.stringify(arg);
details += `\`\`\`\n${argValue}\n\`\`\`\n\n`;
}
details += "\n\n";
}

if (detail.kwargs) {
for (let kwarg in detail.kwargs) {
const kwargValue = typeof detail.kwargs[kwarg] === 'string' ? detail.kwargs[kwarg] : JSON.stringify(detail.kwargs[kwarg], null, 2);
if (kwargValue.includes('\n')) {
details += `**- \`${kwarg}\`**:\n\n\`\`\`\n${kwargValue}\n\`\`\`\n\n`;
} else {
details += `**- \`${kwarg}\`**: \`${kwargValue}\`\n\n`;
}
}
details += "\n\n";
}

if (detail.result) {
const result = typeof detail.result === 'string' ? detail.result : JSON.stringify(detail.result, null, 2);
if (result.includes('\n')) {
details += `#### Result:\n\n\`\`\`\n${result}\n\`\`\`\n\n`;
} else {
details += `#### Result: \`${result}\`\n\n`;
}
}

// Check for the existence of 'info' and display it if available
if (detail.info) {
const tool = detail.info;
details += `----\n> **Source:**\n>\n`; // Quoted title "Source"
details += `> **📚 Source Name**: ${tool.name}\n>\n`; // Quoted source name with book emoji

details += `> **📝 Description**: ${tool.description}\n>\n`; // Quoted description

if (tool.authors && tool.authors.length > 0) {
details += `> **👥 Authors**:\n>`;
for (const author of tool.authors) {
details += `\n> - ${author.name}, *${author.organization}*`;
}
details += `\n>\n`; // Ensure spacing after authors
}

if (tool.license) {
details += `> **📜 License**: ${tool.license}\n>\n`;
}

if (tool.reference) {
details += `> **🔗 [Reference](${tool.reference})**: ${tool.reference}\n>\n`;
}
details += `----\n`; // Close the quoted section
}


}
}
}
}
}
details += "\n\n</details>";
details = marked(details, { renderer: renderer });
message = message + details;

details += "\n\n</details>";
details = marked(details, { renderer: renderer });
message = message + details;
}

$(`#content-${currentMessageId}`).html(message);


}
catch (e) {
Expand Down
Loading

0 comments on commit 132123f

Please sign in to comment.