-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Try on kisski #84
Open
SeverusYixin
wants to merge
10
commits into
main
Choose a base branch
from
try_on_kisski
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Try on kisski #84
Changes from 9 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
6fe927f
sec try with the rag chat
SeverusYixin 523f02b
Sec Try with the chatbot
SeverusYixin 0b4bd25
delete my own token for security
SeverusYixin b37abdb
From Docker's log it looks like it is running on the CPU and needs so…
SeverusYixin 792f848
Give more authorisations to the token
SeverusYixin f63bf2b
Leveraging GPU for Chat Optimization
SeverusYixin d380627
This sub version base on the Kisski
SeverusYixin f6b5222
Fix a bug in the 'openai.chat.completions.create' function
SeverusYixin 47b36c4
Last updated Missed deleted
SeverusYixin df74e50
update for a security problem
SeverusYixin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
KISSKI_API_KEY='b6c89c0b03ba5bd30170933cc6861886' | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Use the official Python image as a base | ||
FROM python:3.12-slim | ||
|
||
# Set environment variables | ||
ENV PYTHONDONTWRITEBYTECODE 1 | ||
ENV PYTHONUNBUFFERED 1 | ||
|
||
# Set the working directory inside the container | ||
WORKDIR /app | ||
|
||
# Copy the requirements file into the container | ||
COPY requirements_chatbot.txt . | ||
|
||
# Install the dependencies | ||
RUN pip install --upgrade pip && pip install -r requirements_chatbot.txt | ||
|
||
# Copy the rest of the application code into the container | ||
COPY . . | ||
|
||
# Expose the port that the Flask app runs on | ||
EXPOSE 5000 | ||
|
||
# Run the application | ||
CMD ["python", "chatbot.py"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
from flask import Flask, request, jsonify | ||
from flask_cors import CORS | ||
from elasticsearch import Elasticsearch, ConnectionError | ||
from llm_utilities import LLMUtilities | ||
import logging | ||
import platform | ||
import time | ||
import os | ||
|
||
# Flask app setup | ||
app = Flask(__name__) | ||
CORS(app) | ||
|
||
# Logging setup | ||
logging.basicConfig(level=logging.INFO) | ||
logger = logging.getLogger(__name__) | ||
|
||
# Hardware information (informational only; actual GPU inference is on KISSKI's side) | ||
SYSTEM_INFO = { | ||
"Machine": platform.node(), | ||
"Processor": platform.processor(), | ||
"LocalGPU": "NVIDIA RTX 500 Ada Generation Laptop GPU (3.9GB dedicated / 37GB shared)" | ||
} | ||
logger.info(f"System Info: {SYSTEM_INFO}") | ||
|
||
# Function to connect to Elasticsearch with retry logic | ||
def connect_elasticsearch(): | ||
""" | ||
Connects to Elasticsearch with retry logic. | ||
Returns: | ||
Elasticsearch instance if connection is successful, otherwise raises an exception. | ||
""" | ||
es = None | ||
max_attempts = 120 # up to 20 minutes | ||
es_host = os.getenv("ELASTICSEARCH_HOST", "elasticsearch") | ||
es_port = os.getenv("ELASTICSEARCH_PORT", "9200") | ||
|
||
# Convert es_port to integer | ||
try: | ||
es_port = int(es_port) | ||
except ValueError: | ||
logger.error(f"ELASTICSEARCH_PORT is not a valid integer: {es_port}") | ||
raise | ||
|
||
for attempt in range(max_attempts): | ||
try: | ||
es = Elasticsearch( | ||
[{"host": es_host, "port": es_port, "scheme": "http"}], | ||
request_timeout=30 | ||
) | ||
if es.ping(): | ||
logger.info("Connected to Elasticsearch") | ||
return es | ||
else: | ||
logger.error("Elasticsearch ping failed") | ||
except ConnectionError: | ||
logger.warning( | ||
f"Elasticsearch not ready, attempt {attempt + 1}/{max_attempts}, retrying in 15 seconds..." | ||
) | ||
time.sleep(15) | ||
except Exception as e: | ||
logger.error(f"Unexpected error while connecting to Elasticsearch: {e}") | ||
time.sleep(15) | ||
raise Exception("Could not connect to Elasticsearch after several attempts") | ||
|
||
# Connect to Elasticsearch | ||
es = connect_elasticsearch() | ||
|
||
# Determine if GPU usage is set (informational only in this remote KISSKI scenario) | ||
use_gpu_env = os.getenv("USE_GPU", "False").lower() == "true" | ||
|
||
# Model name to use on KISSKI; defaults to a 70B Llama model | ||
model_name = os.getenv("MODEL_NAME", "meta-llama-3.1-70b-instruct") | ||
|
||
# Initialize the LLM utility for KISSKI | ||
llm_util = LLMUtilities(model_name=model_name, use_gpu=use_gpu_env) | ||
|
||
def retrieve_documents(query, top_k=3): | ||
""" | ||
Retrieves relevant documents from Elasticsearch based on a user query. | ||
Args: | ||
query (str): The search query. | ||
top_k (int): Number of top documents to retrieve. | ||
Returns: | ||
list: A list of retrieved documents. | ||
""" | ||
try: | ||
response = es.search( | ||
index="bioimage-training", | ||
body={ | ||
"query": { | ||
"multi_match": { | ||
"query": query, | ||
"fields": ["name^3", "description", "tags", "authors", "type", "license"], | ||
"type": "best_fields", | ||
} | ||
} | ||
}, | ||
size=top_k, | ||
) | ||
documents = [ | ||
{ | ||
"name": hit["_source"].get("name", "Unnamed"), | ||
"description": hit["_source"].get("description", "No description available"), | ||
"url": hit["_source"].get("url", ""), | ||
} | ||
for hit in response["hits"]["hits"] | ||
] | ||
return documents | ||
except Exception as e: | ||
logger.error(f"Error retrieving documents from Elasticsearch: {e}") | ||
return [] | ||
|
||
def generate_response(query, documents): | ||
""" | ||
Generates a context-aware response from the KISSKI LLM using the provided query and document context. | ||
""" | ||
context = "\n".join( | ||
[f"- {doc['name']}: {doc['description']} (URL: {doc['url']})" for doc in documents] | ||
) | ||
prompt = f""" | ||
Based on the following documents, answer the user's question concisely and include relevant links. | ||
|
||
## Documents | ||
{context} | ||
|
||
## Question | ||
{query} | ||
""" | ||
return llm_util.generate_response(prompt) | ||
|
||
# Chatbot API endpoint | ||
@app.route("/api/chat", methods=["POST"]) | ||
def chat(): | ||
""" | ||
Chat endpoint to process user queries and generate responses via the KISSKI LLM service. | ||
""" | ||
user_query = request.json.get("query", "") | ||
if not user_query: | ||
return jsonify({"error": "Query cannot be empty"}), 400 | ||
|
||
# Retrieve relevant documents from Elasticsearch | ||
documents = retrieve_documents(user_query) | ||
if not documents: | ||
return jsonify({"response": "No relevant documents found.", "sources": []}) | ||
|
||
# Generate the chatbot response using the KISSKI LLM | ||
reply = generate_response(user_query, documents) | ||
|
||
return jsonify({"response": reply, "sources": documents}) | ||
|
||
# Main entry point | ||
if __name__ == "__main__": | ||
logger.info(f"Starting chatbot. GPU usage requested = {use_gpu_env}, model = {model_name}") | ||
app.run(host="0.0.0.0", port=5000, debug=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import os | ||
import logging | ||
import openai | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
class LLMUtilities: | ||
""" | ||
A utility class for generating responses using the KISSKI LLM endpoint (OpenAI-compatible). | ||
""" | ||
def __init__(self, model_name="meta-llama-3.1-70b-instruct", use_gpu=True): | ||
""" | ||
Initialize the LLM utility with the specified model and GPU preference. | ||
Args: | ||
model_name (str): The KISSKI model name to load (e.g., "meta-llama-3.1-70b-instruct"). | ||
use_gpu (bool): Whether GPU usage is requested. Actual GPU usage depends on KISSKI's service. | ||
""" | ||
self.model_name = model_name | ||
self.use_gpu = use_gpu | ||
|
||
# Use the KISSKI-provided API key from environment | ||
openai.api_key = os.environ.get("KISSKI_API_KEY") | ||
if not openai.api_key: | ||
logger.error("Missing KISSKI_API_KEY environment variable.") | ||
raise EnvironmentError("Please set KISSKI_API_KEY for KISSKI LLM access.") | ||
|
||
# Point OpenAI client to the KISSKI Chat AI endpoint | ||
openai.api_base = "https://chat-ai.academiccloud.de/v1" | ||
|
||
logger.info( | ||
f"KISSKI LLM configured with model '{self.model_name}'. GPU usage = {self.use_gpu}." | ||
) | ||
|
||
def generate_response(self, prompt, max_new_tokens=150, num_return_sequences=1): | ||
""" | ||
Generate a response from the KISSKI LLM service using the new openai>=1.0.0 Chat interface. | ||
Args: | ||
prompt (str): The input prompt for the model. | ||
max_new_tokens (int): Maximum tokens to generate in the reply. | ||
num_return_sequences (int): How many responses to return. | ||
Returns: | ||
str: The generated response text from the LLM. | ||
""" | ||
try: | ||
messages = [{"role": "user", "content": prompt}] | ||
response = openai.chat.completions.create( | ||
model=self.model_name, | ||
messages=messages, | ||
max_tokens=max_new_tokens, | ||
n=num_return_sequences, | ||
temperature=0.7 | ||
) | ||
return response.choices[0].message.content.strip() | ||
except Exception as e: | ||
logger.error(f"Error during response generation via KISSKI LLM: {e}") | ||
return f"Sorry, I couldn't generate a response. Error: {e}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
elasticsearch | ||
flask | ||
flask-cors | ||
pyyaml | ||
requests | ||
openai==1.57.4 |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi Yixin,
never store API keys on Github so that others can read them.
I recommed you to revoke the huggingface and the Kisski key. Otherwise others can use the platforms on your behalf.
https://docs.github.com/en/rest/authentication/keeping-your-api-credentials-secure?apiVersion=2022-11-28#store-your-authentication-credentials-securely
Best,
Robert
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi Robert,
Thanks for your advice. I got a message last night, and in my latest version that I replaced it as "KISSKI_API_KEY=your_api_key" and uploaded it yesterday, but I don't know why you can still read it.
Best,
Yixin
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the git history contains it. Again, I recommend to revoke all keys you put on the internet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you know how to delete them? I tried using the "delete file" function, but it does not seem to work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean to delete the history
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should revoke the key instead of deleting the history.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
E.g. as shown here: https://huggingface.co/docs/hub/en/security-tokens#how-to-manage-user-access-tokens or by sending an email to the KISSKI folks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh, ok thank you, I will write an email to them to recreate a new one , thank you again
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They have already created a new one and the HF token has already been deleted.