|
import os |
|
import json |
|
import bcrypt |
|
import pandas as pd |
|
import numpy as np |
|
from typing import List |
|
from pathlib import Path |
|
|
|
from langchain_openai import ChatOpenAI, OpenAI |
|
from langchain.schema.runnable.config import RunnableConfig |
|
from langchain.schema import StrOutputParser |
|
from langchain_core.prompts import ChatPromptTemplate |
|
|
|
from langchain.agents import AgentExecutor |
|
from langchain.agents.agent_types import AgentType |
|
|
|
from langchain_community.agent_toolkits import create_sql_agent |
|
from langchain_community.utilities import SQLDatabase |
|
from sqlalchemy import create_engine |
|
|
|
import chainlit as cl |
|
from chainlit.input_widget import TextInput, Select, Switch, Slider |
|
|
|
from deep_translator import GoogleTranslator |
|
from IPython.display import display |
|
|
|
from surveycaa import surveyCaa, surveyRh |
|
|
|
from literalai import LiteralClient |
|
literal_client = LiteralClient(api_key=os.getenv("LITERAL_API_KEY")) |
|
|
|
@cl.password_auth_callback |
|
def auth_callback(username: str, password: str): |
|
auth = json.loads(os.environ['CHAINLIT_AUTH_LOGIN']) |
|
ident = next(d['ident'] for d in auth if d['ident'] == username) |
|
pwd = next(d['pwd'] for d in auth if d['ident'] == username) |
|
resultLogAdmin = bcrypt.checkpw(username.encode('utf-8'), bcrypt.hashpw(ident.encode('utf-8'), bcrypt.gensalt())) |
|
resultPwdAdmin = bcrypt.checkpw(password.encode('utf-8'), bcrypt.hashpw(pwd.encode('utf-8'), bcrypt.gensalt())) |
|
resultRole = next(d['role'] for d in auth if d['ident'] == username) |
|
if resultLogAdmin and resultPwdAdmin and resultRole == "admindatapcc": |
|
return cl.User( |
|
identifier=ident + " : 🧑💼 Admin Datapcc", metadata={"role": "admin", "provider": "credentials"} |
|
) |
|
elif resultLogAdmin and resultPwdAdmin and resultRole == "userdatapcc": |
|
return cl.User( |
|
identifier=ident + " : 🧑🎓 User Datapcc", metadata={"role": "user", "provider": "credentials"} |
|
) |
|
|
|
@cl.step(type="run") |
|
def create_agent(filename: str): |
|
""" |
|
Créer un agent qui permet l'accès et l'usage d'un large language model (LLM). |
|
|
|
Args: |
|
filename: le chemin du fichier CSV qui contient les datas. |
|
|
|
Returns: |
|
Un agent qui peut accéder et utiliser le LLM. |
|
""" |
|
|
|
|
|
os.environ['OPENAI_API_KEY'] = os.environ['OPENAI_API_KEY'] |
|
llm = ChatOpenAI(temperature=0, model="gpt-4o-2024-08-06") |
|
|
|
|
|
if cl.user_session.get("createdb") == None: |
|
df = pd.read_csv(filename) |
|
engine = create_engine("sqlite:///sphinx" + str(cl.user_session.get("id")) + ".db") |
|
df.to_sql("sphinx" + str(cl.user_session.get("id")), engine, index=False) |
|
db = SQLDatabase(engine=engine) |
|
cl.user_session.set("createdb", "OK") |
|
cl.user_session.set("db", db) |
|
else: |
|
db = cl.user_session.get("db") |
|
|
|
|
|
return create_sql_agent(llm, db=db, agent_type="openai-tools", verbose=False) |
|
|
|
def query_agent(agent, query): |
|
""" |
|
Query an agent and return the response as a string. |
|
|
|
Args: |
|
agent: The agent to query. |
|
query: The query to ask the agent. |
|
|
|
Returns: |
|
The response from the agent as a string. |
|
""" |
|
|
|
prompt = ( |
|
""" |
|
For the following query, if it requires drawing a table, reply as follows: |
|
{"table": {"columns": ["column1", "column2", ...], "data": [[value1, value2, ...], [value1, value2, ...], ...]}} |
|
|
|
If the query requires creating a bar chart, reply as follows: |
|
{"bar": {"columns": ["A", "B", "C", ...], "data": [25, 24, 10, ...]}} |
|
|
|
If the query requires creating a line chart, reply as follows: |
|
{"line": {"columns": ["A", "B", "C", ...], "data": [25, 24, 10, ...]}} |
|
|
|
There can only be two types of chart, "bar" and "line". |
|
|
|
If it is just asking a question that requires neither, reply as follows: |
|
{"answer": "answer"} |
|
Example: |
|
{"answer": "The title with the highest rating is 'Gilead'"} |
|
|
|
If you do not know the answer, reply as follows: |
|
{"answer": "I do not know."} |
|
|
|
Return all output as a string. |
|
|
|
All strings in "columns" list and data list, should be in double quotes, |
|
|
|
For example: {"columns": ["title", "ratings_count"], "data": [["Gilead", 361], ["Spider's Web", 5164]]} |
|
|
|
Lets think step by step. |
|
|
|
Below is the query. |
|
Query: |
|
""" |
|
+ query |
|
) |
|
|
|
|
|
response = agent.invoke(prompt) |
|
|
|
return response.__str__() |
|
|
|
def decode_response(response: str) -> dict: |
|
"""This function converts the string response from the model to a dictionary object. |
|
|
|
Args: |
|
response (str): response from the model |
|
|
|
Returns: |
|
dict: dictionary with response data |
|
""" |
|
return json.loads("[" + response + "]") |
|
|
|
def write_response(response_dict: dict): |
|
""" |
|
Write a response from an agent to a Streamlit app. |
|
|
|
Args: |
|
response_dict: The response from the agent. |
|
|
|
Returns: |
|
None. |
|
""" |
|
|
|
|
|
return response_dict["answer"] |
|
|
|
@cl.action_callback("Download") |
|
async def on_action(action): |
|
content = [] |
|
content.append(action.value) |
|
arrayContent = np.array(content) |
|
df = pd.DataFrame(arrayContent) |
|
with open('./' + action.description + '.txt', 'wb') as csv_file: |
|
df.to_csv(path_or_buf=csv_file, index=False,header=False, encoding='utf-8') |
|
elements = [ |
|
cl.File( |
|
name= action.description + ".txt", |
|
path="./" + action.description + ".txt", |
|
display="inline", |
|
), |
|
] |
|
await cl.Message( |
|
content="[Lien] 🔗", elements=elements |
|
).send() |
|
await action.remove() |
|
|
|
@cl.set_chat_profiles |
|
async def chat_profile(): |
|
return [ |
|
cl.ChatProfile(name="Survey RH",markdown_description="Questionnaire pour le séminaire RH",icon="/public/logo-ofipe.png",), |
|
cl.ChatProfile(name="Survey CAA",markdown_description="Questionnaire auprès des professionnels de la branche de l'agencement",icon="/public/logo-ofipe.png",), |
|
|
|
|
|
] |
|
|
|
@cl.on_chat_start |
|
async def on_chat_start(): |
|
await cl.Message(f"> SURVEYIA").send() |
|
chat_profile = cl.user_session.get("chat_profile") |
|
if chat_profile == "Survey CAA": |
|
fileSurvey = await surveyCaa() |
|
cl.user_session.set("fileSurvey", fileSurvey) |
|
elif chat_profile == "Survey RH": |
|
fileSurvey = await surveyRh() |
|
cl.user_session.set("fileSurvey", fileSurvey) |
|
|
|
@cl.on_message |
|
async def on_message(message: cl.Message): |
|
await cl.Message(f"> SURVEYIA").send() |
|
agent = create_agent(cl.user_session.get("fileSurvey")) |
|
cb = cl.AsyncLangchainCallbackHandler() |
|
try: |
|
|
|
res = await agent.ainvoke({"input": "Réponds de la manière la plus complète et la plus intelligible, en langue française, à la question suivante : " + message.content + ". Réponds au format markdown ou au format tableau si le résultat nécessite l'affichage d'un tableau."}) |
|
|
|
await cl.Message(author="COPILOT",content=GoogleTranslator(source='auto', target='fr').translate(res['output'])).send() |
|
except ValueError as e: |
|
res = str(e) |
|
resArray = res.split(":") |
|
ans = '' |
|
if str(res).find('parsing') != -1: |
|
for i in range(2,len(resArray)): |
|
ans += resArray[i] |
|
await cl.Message(author="COPILOT",content=ans.replace("`","")).send() |
|
else: |
|
await cl.Message(author="COPILOT",content="Reformulez votre requête, s'il vous plait 😃").send() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|