From 26d7b584b4dd9b80778c3675a082faf655af4940 Mon Sep 17 00:00:00 2001 From: rrayatec <79470126+rrayatec@users.noreply.github.com> Date: Wed, 4 Dec 2024 03:37:29 +0000 Subject: [PATCH] init --- .env | 2 + .vscode/launch.json | 25 +++++++++++ app.py | 104 +++++++++++++++++++++++++++++++++++++++++-- requirements.txt | 1 + static/chat.js | 27 +++++++++++ static/main.css | 89 +++++++++++++++++++++++++----------- templates/index.html | 20 +++++---- 7 files changed, 230 insertions(+), 38 deletions(-) create mode 100644 .env create mode 100644 .vscode/launch.json create mode 100644 static/chat.js diff --git a/.env b/.env new file mode 100644 index 0000000..1a1b5d8 --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +OPENAI_API_KEY = +ES_API_KEY = \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..8a213fd --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,25 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python Debugger: Flask", + "type": "debugpy", + "request": "launch", + "module": "flask", + "env": { + "FLASK_APP": "app.py", + "FLASK_DEBUG": "1" + }, + "args": [ + "run", + "--no-debugger", + "--no-reload" + ], + "jinja": true, + "autoStartBrowser": false + } + ] +} \ No newline at end of file diff --git a/app.py b/app.py index f034480..675a1d1 100644 --- a/app.py +++ b/app.py @@ -1,7 +1,105 @@ -from flask import Flask, render_template +from flask import Flask, render_template, request, jsonify +from elasticsearch import Elasticsearch +from openai import OpenAI +import os + + +es_client = Elasticsearch( + "https://1e41b810031542e193f1e4ac1c67d3b5.us-central1.gcp.cloud.es.io:443", + api_key=os.environ["ES_API_KEY"] +) + +openai_client = OpenAI( + api_key=os.environ["OPENAI_API_KEY"], +) +index_source_fields = { + "search-clip-web": [ + "body_content", + "text" + ] +} + +client = OpenAI() app = Flask(__name__) +def get_elasticsearch_results(query): + es_query = { + "retriever": { + "standard": { + "query": { + "knn": { + "field": "vector", + "num_candidates": 100, + "query_vector_builder": { + "text_embedding": { + "model_id": ".multilingual-e5-small_linux-x86_64", + "model_text": query + } + } + } + } + } + }, + "size": 3 + } + result = es_client.search(index="search-clip-web", body=es_query) + return result["hits"]["hits"] + +def create_openai_prompt(results): + context = "" + for hit in results: + inner_hit_path = f"{hit['_index']}.{index_source_fields.get(hit['_index'])[0]}" + ## For semantic_text matches, we need to extract the text from the inner_hits + if 'inner_hits' in hit and inner_hit_path in hit['inner_hits']: + context += '\n --- \n'.join(inner_hit['_source']['text'] for inner_hit in hit['inner_hits'][inner_hit_path]['hits']['hits']) + else: + source_field = index_source_fields.get(hit["_index"])[1] + hit_context = hit["_source"][source_field] + context += f"{hit_context}\n" + prompt = f""" + Instructions: + + - You are an assistant for question-answering tasks. + - Answer questions truthfully and factually using only the context presented. + - If you don't know the answer, just say that you don't know, don't make up an answer. + - You must always cite the document where the answer was extracted using inline academic citation style [], using the position. + - Use markdown format for code examples. + - You are correct, factual, precise, and reliable. + + Context: + {context} + + """ + return prompt + +def generate_openai_completion(user_prompt, question): + response = openai_client.chat.completions.create( + model="gpt-3.5-turbo", + messages=[ + {"role": "system", "content": user_prompt}, + {"role": "user", "content": question}, + ] + ) + return response.choices[0].message.content + + @app.route("/") -def hello_world(): - return render_template("index.html", title="Hello") +def welcome(): + return render_template('index.html', title='Chat App', message='Welcome to the chat!') + + +@app.route('/chat', methods=['POST']) +def chat(): + data = request.get_json() + question =data.get('message') + elasticsearch_results = get_elasticsearch_results(question) + context_prompt = create_openai_prompt(elasticsearch_results) + openai_completion = generate_openai_completion(context_prompt, question) + print(openai_completion) + + return jsonify({'response': openai_completion}) + + +if __name__ == '__main__': + app.run(debug=True) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 5aad892..eba5247 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ Flask==2.3.2 +python-dotenv \ No newline at end of file diff --git a/static/chat.js b/static/chat.js new file mode 100644 index 0000000..812cfd1 --- /dev/null +++ b/static/chat.js @@ -0,0 +1,27 @@ +document.addEventListener('DOMContentLoaded', (event) => { + const chatForm = document.getElementById('chat-form'); + const messageInput = document.getElementById('message-input'); + const messagesDiv = document.getElementById('messages'); + + chatForm.addEventListener('submit', async (e) => { + e.preventDefault(); + const message = messageInput.value; + + const response = await fetch('/chat', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ message: message }) + }); + + const data = await response.json(); + const newMessage = document.createElement('div'); + newMessage.textContent = data.response; + newMessage.classList.add('message'); + messagesDiv.appendChild(newMessage); + + messageInput.value = ''; + messagesDiv.scrollTop = messagesDiv.scrollHeight; // Scroll to the bottom + }); +}); \ No newline at end of file diff --git a/static/main.css b/static/main.css index afe300e..1f94ef1 100644 --- a/static/main.css +++ b/static/main.css @@ -1,45 +1,80 @@ body { + font-family: Arial, sans-serif; + background-color: #f5f5f5; margin: 0; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", - "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; + padding: 0; + position: relative; } -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", - monospace; +.App { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100vh; + position: relative; + z-index: 1; } -.App { +.App-header { + background-color: rgba(40, 44, 52, 0.8); + /* Fondo semi-transparente */ + padding: 20px; + color: white; text-align: center; + width: 100%; + position: relative; + z-index: 2; } -.App-logo { - height: 40vmin; - pointer-events: none; +#chat { + background-color: rgba(255, 255, 255, 0.9); + /* Fondo semi-transparente */ + border: 1px solid #ccc; + border-radius: 10px; + width: 80%; + max-width: 600px; + padding: 20px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + position: relative; + z-index: 2; } -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; +#messages { + max-height: 300px; + overflow-y: auto; + margin-bottom: 20px; } -.App-link { - color: #61dafb; +.message { + background-color: #e1ffc7; + border-radius: 10px; + padding: 10px; + margin-bottom: 10px; + word-wrap: break-word; } -.heart { - color: #ff0000; +#chat-form { + display: flex; } -.small { - font-size: 0.75rem; +#message-input { + flex: 1; + padding: 10px; + border: 1px solid #ccc; + border-radius: 5px; + margin-right: 10px; } + +button { + padding: 10px 20px; + border: none; + border-radius: 5px; + background-color: #007bff; + color: white; + cursor: pointer; +} + +button:hover { + background-color: #0056b3; +} \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index 7bee67b..b22ccb3 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,19 +1,23 @@ {{ title }} - + +
-

- GitHub Codespaces ♥️ Flask -

-

- Edit templates/index.html and refresh to see your changes! + {{ message }}

+
+
+
+ + +
+
+ - - + \ No newline at end of file