Skip to content

Commit 2c0dbdf

Browse files
committed
Merge menu into main
2 parents 7857e23 + bfcd3ed commit 2c0dbdf

File tree

13 files changed

+498
-87
lines changed

13 files changed

+498
-87
lines changed

agents.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import os
2+
from utils import load_yaml_file
3+
from dotenv import load_dotenv, find_dotenv
4+
from mistralai import Mistral
5+
6+
config_data = load_yaml_file("config.yaml")
7+
load_dotenv(find_dotenv())
8+
9+
# Get API key
10+
mistral_api_key = os.getenv("MISTRALAI_API_KEY")
11+
client = Mistral(mistral_api_key)
12+
13+
def get_websearch_agent():
14+
"""
15+
Create and return a web search agent using Mistral API.
16+
"""
17+
websearch_agent = client.beta.agents.create(
18+
model=config_data["model_name"],
19+
description="Agent able to search information over the web",
20+
name="Websearch Agent",
21+
instructions="You have the ability to perform web searches with `web_search` to find up-to-date information. **Always provide the source URLs when you use web search to answer a question.**",
22+
tools=[{"type": "web_search"}],
23+
completion_args={
24+
"temperature": 0.3,
25+
"top_p": 0.95,
26+
}
27+
)
28+
return websearch_agent

app.py

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,39 @@
11
import streamlit as st
2-
from menu import menu
2+
from menu import menu, unauthenticated_menu
33
from database import create_connection, create_table, get_user, insert_user
44
from homepage import gethomepage
55

66
# Get markdown homepage
77
st.markdown(body=gethomepage(), unsafe_allow_html=True)
88

9-
# Check if user is authenticated
10-
if not st.user.is_logged_in:
11-
if st.button("Log in or Sign up"):
12-
st.login("auth0")
13-
st.stop()
14-
15-
# Initialize session state
9+
# Initialize session state for user_type and username
1610
if "user_type" not in st.session_state:
1711
st.session_state.user_type = None
1812
if "username" not in st.session_state:
1913
st.session_state.username = None
2014

21-
# Only access user info if available
22-
if hasattr(st.user, "email"):
15+
# Check if user is authenticated
16+
if st.user.is_logged_in:
2317
conn = create_connection()
2418
if conn is not None:
2519
create_table(conn)
26-
27-
# Check if user exists
2820
user_data = get_user(conn, st.user.email)
2921
if user_data is not None:
3022
st.session_state['user_type'] = user_data[3]
3123
st.session_state['username'] = user_data[1]
3224
else:
33-
user_type = 'guest'
25+
user_type = 'user'
3426
username = st.user.email
3527
st.session_state['user_type'] = user_type
3628
st.session_state['username'] = username
3729
insert_user(conn, username, st.user.email, user_type)
38-
39-
# Show menu
40-
menu()
30+
31+
# Show authenticated menu
32+
menu()
33+
34+
else:
35+
st.session_state['user_type'] = 'guest'
36+
st.session_state['username'] = 'guest'
37+
38+
# Show menu for unauthenticated users, which will now have a link to the chatbot
39+
unauthenticated_menu()

chat_history.py

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,93 @@
11
import sqlite3
2+
import streamlit as st
3+
from utils import load_yaml_file
24

3-
DB_FILE = "users.db"
5+
# Read config data
6+
config_data = load_yaml_file("config.yaml")
7+
8+
DB_FILE = config_data["dbpath"]
49

510
# create a SQLite database to store chat history
611
# and user information
712
def init_db():
813
with sqlite3.connect(DB_FILE) as conn:
914
conn.execute('''
10-
CREATE TABLE IF NOT EXISTS messages (
15+
CREATE TABLE IF NOT EXISTS messages (
1116
id INTEGER PRIMARY KEY AUTOINCREMENT,
1217
username TEXT NOT NULL,
1318
role TEXT NOT NULL,
1419
content TEXT NOT NULL,
15-
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
20+
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
21+
feedback INTEGER DEFAULT NULL,
22+
session_id TEXT DEFAULT NULL,
23+
ip_address TEXT DEFAULT NULL
24+
)
25+
''')
26+
27+
cursor = conn.execute("PRAGMA table_info(messages)")
28+
existing_columns = [col[1] for col in cursor.fetchall()]
29+
30+
if "feedback" not in existing_columns:
31+
conn.execute('ALTER TABLE messages ADD COLUMN feedback INTEGER DEFAULT NULL')
32+
33+
if "session_id" not in existing_columns:
34+
conn.execute('ALTER TABLE messages ADD COLUMN session_id TEXT DEFAULT NULL')
35+
36+
if "ip_address" not in existing_columns:
37+
conn.execute('ALTER TABLE messages ADD COLUMN ip_address TEXT DEFAULT NULL')
38+
39+
conn.execute('''
40+
CREATE TABLE IF NOT EXISTS analytics (
41+
id INTEGER PRIMARY KEY AUTOINCREMENT,
42+
title TEXT NOT NULL,
43+
sql_query TEXT NULL,
44+
options TEXT NULL,
45+
notes TEXT NULL
1646
)
1747
''')
48+
1849
conn.commit()
1950

2051
# create a table to store user information
21-
def save_message(username, role, content):
52+
def save_message(username, role, content, session_id=None, ipaddress=None):
2253
with sqlite3.connect(DB_FILE) as conn:
23-
conn.execute(
24-
'INSERT INTO messages (username, role, content) VALUES (?, ?, ?)',
25-
(username, role, content)
54+
cursor = conn.execute(
55+
'INSERT INTO messages (username, role, content, session_id, ip_address) VALUES (?, ?, ?, ?, ?)',
56+
(username, role, content, session_id, ipaddress)
2657
)
2758
conn.commit()
59+
return cursor.lastrowid
60+
2861

2962
# retrieve chat history for a specific user
3063
# and return it as a list of dictionaries
3164
def get_messages(username):
3265
with sqlite3.connect(DB_FILE) as conn:
3366
cursor = conn.execute(
34-
'SELECT role, content FROM messages WHERE username = ? ORDER BY timestamp ASC',
67+
'SELECT id, role, content, feedback FROM messages WHERE username = ? ORDER BY timestamp ASC',
3568
(username,)
3669
)
37-
return [{"role": row[0], "content": row[1]} for row in cursor.fetchall()]
70+
return [{"id": row[0], "role": row[1], "content": row[2], "feedback": row[3]} for row in cursor.fetchall()]
71+
72+
def update_feedback(message_id, feedback):
73+
with sqlite3.connect(DB_FILE) as conn:
74+
conn.execute(
75+
'UPDATE messages SET feedback = ? WHERE id = ?',
76+
(feedback, message_id)
77+
)
78+
conn.commit()
79+
80+
def on_feedback_change(message_id, fb_key):
81+
feedback = st.session_state[fb_key]
82+
update_feedback(message_id, feedback)
83+
84+
def get_feedback(message_id):
85+
with sqlite3.connect(DB_FILE) as conn:
86+
cursor = conn.execute(
87+
'SELECT feedback FROM messages WHERE id = ?',
88+
(message_id,)
89+
)
90+
row = cursor.fetchone()
91+
return row[0] if row else None
92+
93+

config.yaml.example

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,13 @@ port: 8080
1616
system_prompt: ""
1717
query_rewriting_prompt: ""
1818
logo_pth: ""
19-
company_name: ""
19+
company_name: ""
20+
feedback_options: "thumbs" # thumbs, stars, or faces
21+
no_answer_message: "I don't have the answer to that question"
22+
nr_documents: 5
23+
# analytics
24+
analytics_model: "mistral-small-latest"
25+
analytics_prompt: "Given the following SQLite database schema: \n'''CREATE TABLE IF NOT EXISTS users (id integer PRIMARY KEY, username text NOT NULL UNIQUE, email text NOT NULL UNIQUE, type text DEFAULT 'guest', user_group text, email_verified integer DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP); CREATE TABLE IF NOT EXISTS messages (id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT NOT NULL, role TEXT NOT NULL, content TEXT NOT NULL, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, feedback INTEGER DEFAULT NULL);''' where 'role' field contains 'user' for questions and 'assistant' for answers, 'feedback' field is 1 for positive feedback or thumb up, 0 for negative or thumb down \nGenerate a SQL query to answer the user question \nReturn ONLY the SQL query, nothing else and do not use 'start of week' or 'start of day', use alias for count field. User question: "
26+
dbpath: "users.db"
27+
landing_page: "https://aifaq.pro/"
28+
contact_page: ""

data_engine.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import os
2+
import pandas as pd
3+
import streamlit as st
4+
from mistralai import Mistral
5+
from utils import load_yaml_file
6+
import sqlite3
7+
8+
config_data = load_yaml_file("config.yaml")
9+
10+
def get_sql_query(question: str) -> str:
11+
12+
prompt = config_data["analytics_prompt"] + question
13+
14+
# Get API keys
15+
mistral_api_key = os.getenv("MISTRALAI_API_KEY")
16+
model = config_data["analytics_model"]
17+
18+
client = Mistral(api_key=mistral_api_key)
19+
20+
response = client.chat.complete(
21+
model= model,
22+
messages = [
23+
{
24+
"role": "user",
25+
"content": prompt,
26+
},
27+
]
28+
)
29+
sql_query = response.choices[0].message.content
30+
sql_query = sql_query.replace("```sql", "").replace("```", "").strip()
31+
32+
return sql_query
33+
34+
def run_sql_query(sql_query: str) -> pd.DataFrame:
35+
# Run SQL query on SQLite DB and return results as DataFrame.
36+
conn = sqlite3.connect(config_data["dbpath"])
37+
try:
38+
df = pd.read_sql(sql_query, conn)
39+
except Exception as e:
40+
st.error(f"SQL Error: {e}")
41+
df = pd.DataFrame()
42+
finally:
43+
conn.close()
44+
return df
45+
46+
def load_analytics():
47+
conn = sqlite3.connect(config_data["dbpath"])
48+
try:
49+
cursor = conn.execute("""
50+
SELECT
51+
id,
52+
title,
53+
sql_query,
54+
options
55+
FROM analytics
56+
ORDER BY id;
57+
""")
58+
options = []
59+
for row in cursor.fetchall():
60+
option_list = [opt.strip() for opt in row[3].split(",") if opt.strip()]
61+
options.append({
62+
"key": row[0],
63+
"title": row[1],
64+
"sql_query": row[2],
65+
"options": option_list
66+
})
67+
except Exception as e:
68+
st.error(f"Error loading analytics options: {e}")
69+
options = []
70+
finally:
71+
conn.close()
72+
return options
73+
74+
def get_analytics_query(query_id: int) -> str:
75+
conn = sqlite3.connect(config_data["dbpath"])
76+
try:
77+
cursor = conn.execute("""
78+
SELECT sql_query
79+
FROM analytics
80+
WHERE id = ?
81+
""", (query_id,))
82+
row = cursor.fetchone()
83+
sql_query = row[0] if row else None
84+
except Exception as e:
85+
st.error(f"Error fetching query: {e}")
86+
sql_query = None
87+
finally:
88+
conn.close()
89+
return sql_query

database.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,47 @@
11
import sqlite3
2+
from utils import load_yaml_file
3+
4+
# Read config data
5+
config_data = load_yaml_file("config.yaml")
26

37
# This script creates a SQLite database to store user information.
48
# It includes functions to create a connection to the database, create a table for users,
59
# insert a new user, update user information, and retrieve user data.
610
def create_connection():
711
conn = None
812
try:
9-
conn = sqlite3.connect('users.db')
13+
conn = sqlite3.connect(config_data["dbpath"])
1014
except sqlite3.Error as e:
1115
print(e)
1216
return conn
1317

1418
def create_table(conn):
1519
try:
16-
sql = '''CREATE TABLE IF NOT EXISTS users (
20+
conn.execute('''
21+
CREATE TABLE IF NOT EXISTS users (
1722
id integer PRIMARY KEY,
1823
username text NOT NULL UNIQUE,
1924
email text NOT NULL UNIQUE,
2025
type text DEFAULT 'guest',
2126
user_group text,
22-
email_verified integer DEFAULT 0
23-
);'''
24-
conn.cursor().execute(sql)
27+
email_verified integer DEFAULT 0,
28+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
29+
);''')
30+
31+
cursor = conn.execute("PRAGMA table_info(users)")
32+
existing_columns = [col[1] for col in cursor.fetchall()]
33+
34+
if "created_at" not in existing_columns:
35+
conn.execute('ALTER TABLE users ADD COLUMN created_at DATETIME DEFAULT now')
36+
37+
conn.commit()
2538
except sqlite3.Error as e:
2639
print(e)
2740

2841
# This function creates a new user in the database.
2942
# It takes a connection object, username, email, and type as parameters.
3043
def insert_user(conn, username, email, type):
31-
sql = '''INSERT INTO users(username, email, type) VALUES(?,?,?)'''
44+
sql = '''INSERT INTO users(username, email, type, created_at) VALUES(?,?,?,CURRENT_TIMESTAMP)'''
3245
cur = conn.cursor()
3346
cur.execute(sql, (username, email, type))
3447
conn.commit()

homepage.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,27 @@
88
def gethomepage():
99
markdown_string = f"""
1010
<div style="text-align: center;">
11-
<img src={config_data["logo_pth"]} alt="AIFAQ logo" style="height: 110px">
12-
<h1>AI Agent powered by <em>{config_data["company_name"]}</em></h1>
11+
<img src={config_data["logo_pth"]} alt="AIFAQ logo" style="height: 60px">
12+
<h3>AI Agent powered by <em>AIFAQ</em> (beta)</h3>
1313
</div>
1414
15-
## Try for free
15+
---
16+
17+
##### Try for free
1618
1719
Here the [Official GitHub Repository](https://github.com/hyperledger-labs/aifaq)
1820
19-
## Links and Resources
21+
---
22+
23+
##### Links and Resources
24+
25+
26+
AIFAQ Inc. [website]({config_data["landing_page"]})
2027
21-
AIFAQ Inc. [website](https://aifaqpro.wordpress.com/)
28+
---
2229
23-
## {config_data["company_name"]}
30+
##### {config_data["company_name"]}
31+
This chatbot is a {config_data["company_name"]} conversational AI tool.
2432
25-
This chatbot is a {config_data["company_name"]} conversational AI tool. Please, register or login:
2633
"""
2734
return markdown_string

0 commit comments

Comments
 (0)