Skip to content

Commit b3e929f

Browse files
Adding a third agent 'ccr', improving reliability of solution, added a web app component for streaming answers
1 parent 56b70b1 commit b3e929f

24 files changed

+1288
-257
lines changed

.deployment

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[config]
2+
SCM_DO_BUILD_DURING_DEPLOYMENT=true
3+
WEBSITE_WEBDEPLOY_USE_SCM=true

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,3 +178,5 @@ hukoomi_new/
178178
qna.ipynb
179179
notebooks/
180180
demo copy.ipynb
181+
bing.ipynb
182+
app/

.vscode/settings.json

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"azureFunctions.deploySubpath": ".",
3-
"azureFunctions.scmDoBuildDuringDeployment": true,
3+
"azureFunctions.scmDoBuildDuringDeployment": true,
44
"azureFunctions.pythonVenv": ".venv",
55
"azureFunctions.projectLanguage": "Python",
66
"azureFunctions.projectRuntime": "~4",
@@ -13,7 +13,17 @@
1313
"build{,/**}",
1414
"develop-eggs{,/**}",
1515
"dist{,/**}",
16+
"backup{,/**}",
17+
"AzCogSearchDocCrackingFunc{,/**}",
18+
"BotQnAHTTPFunc{,/**}",
19+
"ServiceBusQueueNewDocument{,/**}",
20+
"kb_docs_samples{,/**}",
21+
"notebooks{,/**}",
22+
"dump{,/**}",
23+
".env copy{,/**}",
24+
".env copy 2{,/**}",
1625
"downloads{,/**}",
26+
".git{,/**}",
1727
"eggs{,/**}",
1828
".eggs{,/**}",
1929
"lib{,/**}",
@@ -37,5 +47,5 @@
3747
".vscode{,/**}"
3848
],
3949
"appService.defaultWebAppToDeploy": "/subscriptions/2a7eed04-714e-4ba9-96ba-47355c32a8d6/resourceGroups/km-demo/providers/Microsoft.Web/sites/kmaoiwebappdemo0001",
40-
"appService.deploySubpath": "app"
50+
"appService.deploySubpath": "."
4151
}

BotQnAHTTPFunc/__init__.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ def get_param(req, param_name):
2929

3030

3131
def check_param(param):
32-
if param == 'false':
33-
param = False
34-
else:
32+
if param == 'true':
3533
param = True
34+
else:
35+
param = False
3636

3737
return param
3838

@@ -52,14 +52,19 @@ def main(req: func.HttpRequest) -> func.HttpResponse:
5252
evaluate_step = get_param(req, 'evaluate_step')
5353
check_adequacy = get_param(req, 'check_adequacy')
5454
check_intent = get_param(req, 'check_intent')
55+
use_calendar = get_param(req, 'use_calendar')
56+
use_bing = get_param(req, 'use_bing')
57+
5558

5659
params_dict = {
5760
'enable_unified_search': check_param(enable_unified_search),
5861
'enable_redis_search': check_param(enable_redis_search),
5962
'enable_cognitive_search': check_param(enable_cognitive_search),
6063
'evaluate_step': check_param(evaluate_step),
6164
'check_adequacy': check_param(check_adequacy),
62-
'check_intent': check_param(check_intent)
65+
'check_intent': check_param(check_intent),
66+
'use_calendar': check_param(use_calendar),
67+
'use_bing': check_param(use_bing)
6368
}
6469

6570

WISHLIST.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,15 @@ The following features are added to the wishlist to be implemented:
1616
### TBD
1717
1. ARM: Adding Application Insights to the ARM template
1818
1. Code: Adding a custom skill that processes csv files
19-
1. GUI for triggering Cognitive Search and Form Recognizer document ingestion - streamlit
2019

20+
1. GUI for triggering Cognitive Search and Form Recognizer document ingestion -
21+
1. Backend: Python control part in Flask - Samer
22+
1. Frontend: React control part for the UI (generate with GPT4) - Yacine
23+
1. Chat client UI - demo - Yacine (1st Priority)
24+
1. Streaming capability with Flash SocketIO - Andrey (1st priority)
25+
1. (maximizing Cosmos use) - Translation Problem (checksum checking in Cosmos) - re-generate translations for all the chunks (cost) - get from Cosmos - Andrey (2nd priority)
26+
1. Streamlit vs Flask - Andrey (3rd priority)
27+
1. GPT4 Agent -- Samer
2128

2229
### Future
2330
1. Code: Adding support for fine-tuned models.

app/app.py renamed to app.py

Lines changed: 77 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,25 @@
33
from flask import Flask, redirect, url_for, request, jsonify
44
from flask_socketio import SocketIO
55
from flask_socketio import send, emit
6-
7-
import sys
8-
sys.path.insert(0, '../')
6+
import urllib
97

108
from utils import bot_helpers
9+
from utils import langchain_helpers
10+
from utils import langchain_agent
11+
from utils import redis_helpers
12+
13+
14+
15+
global_params_dict = {
16+
'enable_unified_search': True,
17+
'enable_redis_search': False,
18+
'enable_cognitive_search': False,
19+
'evaluate_step': False,
20+
'check_adequacy': False,
21+
'check_intent': False
22+
}
23+
24+
redis_conn = redis_helpers.get_new_conn()
1125

1226

1327
CHOSEN_EMB_MODEL = os.environ['CHOSEN_EMB_MODEL']
@@ -18,20 +32,57 @@
1832
NUM_TOP_MATCHES = int(os.environ['NUM_TOP_MATCHES'])
1933

2034
app = Flask(__name__)
21-
app.config['SECRET_KEY'] = 'secret!'
2235
socketio = SocketIO(app)
36+
app.config['SECRET_KEY'] = 'secret!'
37+
2338

2439
# source venv/bin/activate
2540
# flask --app app.py --debug run
2641

42+
agents_sid = {}
43+
44+
45+
@app.route("/", defaults={"path": "index.html"})
46+
@app.route("/<path:path>")
47+
def static_file(path):
48+
print("path", path)
49+
return app.send_static_file(path)
50+
51+
52+
@socketio.on('connect')
53+
def on_connect():
54+
print(f"connected {request.sid}")
55+
connection = {'socketio': socketio, 'connection_id':request.sid}
56+
ccr_agent = langchain_agent.KMOAI_Agent(agent_name = 'os', params_dict=global_params_dict, stream = True, connection=connection)
57+
agents_sid[request.sid] = ccr_agent
58+
2759

28-
@app.route("/")
29-
def hello():
30-
print("hello there 3")
31-
return "<html><body><h1>Hello Enterprise Search with OpenAI Solution!</h1></body></html>\n"
60+
@socketio.on('disconnect')
61+
def on_disconnect():
62+
del agents_sid[request.sid]
3263

3364

3465

66+
@socketio.on('message')
67+
def handle_message(q):
68+
print(f'received message: {q} from {request.sid}')
69+
emit('new_message', "Query: " + q + '\n')
70+
answer, sources, likely_sources, s_id = agents_sid[request.sid].run(q, redis_conn, request.sid)
71+
sources_str = ''
72+
if len(sources) > 0:
73+
for s in sources:
74+
try:
75+
linkname = urllib.parse.unquote(os.path.basename(s.split('?')[0]))
76+
except:
77+
linkname = 'Link'
78+
sources_str += '[<a href="' + s + f'" target="_blank">{linkname}</a>]'
79+
send('Links:'+ sources_str)
80+
81+
82+
83+
##### IMPORTANT
84+
##### INCLUDE IN THE POST HEADER --> Content-Type: application/json
85+
##### IMPORTANT
3586
@app.route('/kmoai_request', methods=['POST'])
3687
def kmoai_request():
3788
data = request.get_json()
@@ -40,10 +91,10 @@ def kmoai_request():
4091

4192

4293
def check_param(param):
43-
if param == 'false':
44-
param = False
45-
else:
94+
if param == 'true':
4695
param = True
96+
else:
97+
param = False
4798

4899
return param
49100

@@ -53,6 +104,10 @@ def get_param(req, param_name):
53104
return param
54105

55106

107+
108+
##### IMPORTANT
109+
##### INCLUDE IN THE POST HEADER --> Content-Type: application/json
110+
##### IMPORTANT
56111
def process_kmoai_request(req):
57112
logging.info('Python HTTP trigger function processed a request.')
58113

@@ -67,14 +122,18 @@ def process_kmoai_request(req):
67122
evaluate_step = get_param(req, 'evaluate_step')
68123
check_adequacy = get_param(req, 'check_adequacy')
69124
check_intent = get_param(req, 'check_intent')
125+
use_calendar = get_param(req, 'use_calendar')
126+
use_bing = get_param(req, 'use_bing')
70127

71128
params_dict = {
72129
'enable_unified_search': check_param(enable_unified_search),
73130
'enable_redis_search': check_param(enable_redis_search),
74131
'enable_cognitive_search': check_param(enable_cognitive_search),
75132
'evaluate_step': check_param(evaluate_step),
76133
'check_adequacy': check_param(check_adequacy),
77-
'check_intent': check_param(check_intent)
134+
'check_intent': check_param(check_intent),
135+
'use_calendar': check_param(use_calendar),
136+
'use_bing': check_param(use_bing)
78137
}
79138

80139
if filter_param is None:
@@ -83,3 +142,9 @@ def process_kmoai_request(req):
83142
os.environ['redis_filter_param'] = filter_param
84143

85144
return bot_helpers.openai_interrogate_text(query, session_id=session_id, filter_param=filter_param, agent_name=search_method, params_dict=params_dict)
145+
146+
147+
148+
if __name__ == '__main__':
149+
app.run()
150+
socketio.run(app, allow_unsafe_werkzeug=True)

app/.deployment

Lines changed: 0 additions & 2 deletions
This file was deleted.

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@ lxml
2424
azure-ai-textanalytics
2525
langchain
2626
flask
27-
flask-socketio
27+
flask-socketio

static/index.html

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>AI Chat App</title>
7+
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js" integrity="sha512-q/dWJ3kcmjBLU4Qc47E4A9kTB4m3wuTY7vkFJDTZKjTs8jhyGQnaUrxa0Ytd0ssMZhbNua9hE+E7Qv1j+DyZwA==" crossorigin="anonymous"></script>
8+
<link rel="stylesheet" href="styles.css">
9+
<script type="text/javascript" src="script.js" defer></script>
10+
</head>
11+
<body>
12+
13+
<div id="mySidebar" class="sidebar">
14+
<a href="javascript:void(0)" class="closebtn" onclick="closeNav()">&times;</a>
15+
<h3>Search Methods</h3>
16+
<ul>
17+
<li>
18+
<input type="radio" name="search-method" id="method-1" value="method-1">
19+
<label for="method-1">Method 1</label>
20+
</li>
21+
<li>
22+
<input type="radio" name="search-method" id="method-2" value="method-2">
23+
<label for="method-2">Method 2</label>
24+
</li>
25+
<li>
26+
<input type="radio" name="search-method" id="method-3" value="method-3">
27+
<label for="method-3">Method 3</label>
28+
</li>
29+
</ul>
30+
</div>
31+
32+
<div id="main">
33+
<button class="openbtn" onclick="openNav()">&#9776; Options</button>
34+
</div>
35+
36+
<div id="chat-container">
37+
<!-- Chat messages will be appended here -->
38+
</div>
39+
40+
<div id="input-container">
41+
<input type="text" id="input-message" placeholder="Type your message...">
42+
<button id="send-button">Send</button>
43+
</div>
44+
45+
</body>
46+
</html>

static/index_old.html

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<html>
2+
<body>
3+
<h1>Chat App</h1>
4+
<form id="message-form">
5+
<input type="text" id="message-input" placeholder="Type your message">
6+
<button type="submit">Send</button>
7+
</form>
8+
<div id="messages"></div>
9+
</body>
10+
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js" integrity="sha512-q/dWJ3kcmjBLU4Qc47E4A9kTB4m3wuTY7vkFJDTZKjTs8jhyGQnaUrxa0Ytd0ssMZhbNua9hE+E7Qv1j+DyZwA==" crossorigin="anonymous"></script>
11+
<script type="text/javascript" charset="utf-8">
12+
var socket = io();
13+
const messages = document.querySelector('#messages');
14+
const messageForm = document.querySelector('#message-form');
15+
const messageInput = document.querySelector('#message-input');
16+
var latest_div = document.getElementById("messages").lastChild;
17+
18+
console.log("starting")
19+
20+
messageForm.addEventListener('submit', (event) => {
21+
event.preventDefault();
22+
const message = messageInput.value;
23+
socket.emit('message', message);
24+
messageInput.value = '';
25+
});
26+
27+
socket.on('message', (message) => {
28+
// const messageElement = document.createElement('div');
29+
console.log(message)
30+
console.log(document.getElementById("messages").lastChild.innerHTML )
31+
document.getElementById("messages").lastChild.innerHTML = document.getElementById("messages").lastChild.innerHTML + '<br/>' + message + '<br/><br/>';
32+
// messages.appendChild(messageElement);
33+
});
34+
35+
socket.on('new_message', (message) => {
36+
const messageElement = document.createElement('div');
37+
messageElement.textContent = message
38+
messageElement.innerHTML = messageElement.innerHTML + '<br/>';
39+
messages.appendChild(messageElement);
40+
});
41+
42+
socket.on('token', (message) => {
43+
document.getElementById("messages").lastChild.textContent = document.getElementById("messages").lastChild.textContent + message;
44+
});
45+
46+
socket.on('connect', function() {
47+
socket.emit('connect_message', {data: 'Im connected!'});
48+
});
49+
</script>
50+
</html>

0 commit comments

Comments
 (0)