2025-12-25 14:54:33 +00:00
import os
import chainlit as cl
import re
from datetime import datetime
import shutil
import uuid
2025-12-26 09:11:06 +00:00
import ollama
2025-12-26 09:58:49 +00:00
from qdrant_client import AsyncQdrantClient
from qdrant_client . models import PointStruct , Distance , VectorParams
2025-12-25 14:54:33 +00:00
2025-12-26 09:58:49 +00:00
# --- CONFIGURAZIONE HARD-CODED ---
2025-12-26 09:11:06 +00:00
OLLAMA_URL = " http://192.168.1.243:11434 "
2025-12-26 09:58:49 +00:00
# ---------------------------------
2025-12-26 09:11:06 +00:00
2025-12-25 14:54:33 +00:00
USER_ROLES = {
' moglie@esempio.com ' : ' business ' ,
' ingegnere@esempio.com ' : ' engineering ' ,
' architetto@esempio.com ' : ' architecture ' ,
' admin@esempio.com ' : ' admin '
}
2025-12-25 18:00:13 +00:00
2025-12-26 07:45:40 +00:00
WORKSPACES_DIR = " ./workspaces "
2025-12-25 18:00:13 +00:00
2025-12-25 14:54:33 +00:00
def create_workspace ( user_role ) :
2025-12-26 07:45:40 +00:00
workspace_path = os . path . join ( WORKSPACES_DIR , user_role )
if not os . path . exists ( workspace_path ) :
os . makedirs ( workspace_path )
2025-12-25 14:54:33 +00:00
def save_code_to_file ( code , user_role ) :
timestamp = datetime . now ( ) . strftime ( " % Y % m %d % H % M % S " )
file_name = f " code_ { timestamp } .py "
file_path = os . path . join ( WORKSPACES_DIR , user_role , file_name )
2025-12-26 07:45:40 +00:00
with open ( file_path , " w " ) as file :
2025-12-25 14:54:33 +00:00
file . write ( code )
2025-12-26 07:45:40 +00:00
2025-12-25 14:54:33 +00:00
return file_path
2025-12-26 07:45:40 +00:00
def limit_history ( history ) :
if len ( history ) > 20 :
history = history [ - 20 : ]
return history
2025-12-25 14:54:33 +00:00
2025-12-26 07:45:40 +00:00
async def connect_to_qdrant ( ) :
2025-12-26 09:58:49 +00:00
client = AsyncQdrantClient ( url = " http://qdrant:6333 " )
2025-12-26 07:45:40 +00:00
collection_name = " documents "
2025-12-26 09:58:49 +00:00
# Check if collection exists
if not await client . collection_exists ( collection_name ) :
await client . create_collection (
2025-12-26 07:45:40 +00:00
collection_name = collection_name ,
2025-12-26 09:58:49 +00:00
vectors_config = VectorParams ( size = 768 , distance = Distance . COSINE )
2025-12-25 14:54:33 +00:00
)
2025-12-26 07:45:40 +00:00
return client
async def get_embeddings ( text ) :
2025-12-26 09:58:49 +00:00
client = ollama . Client ( host = OLLAMA_URL )
2025-12-26 07:45:40 +00:00
2025-12-26 09:58:49 +00:00
# Limite di sicurezza per evitare errori 500 su Ollama
limit = 2000
if len ( text ) > limit :
text = text [ : limit ]
2025-12-26 07:45:40 +00:00
2025-12-26 09:11:06 +00:00
try :
response = client . embed ( model = ' nomic-embed-text ' , input = text )
if ' embeddings ' in response :
return response [ ' embeddings ' ] [ 0 ]
return response . get ( ' embedding ' )
except Exception as e :
print ( f " Errore Embedding: { e } " )
return [ ]
2025-12-25 18:00:13 +00:00
2025-12-26 07:45:40 +00:00
async def search_qdrant ( query_text , user_role ) :
""" Cerca documenti pertinenti su Qdrant """
try :
qdrant_client = await connect_to_qdrant ( )
query_embedding = await get_embeddings ( query_text )
2025-12-26 09:11:06 +00:00
if not query_embedding :
return " "
2025-12-26 09:58:49 +00:00
# Usa query_points (nuova API per AsyncClient)
search_result = await qdrant_client . query_points (
2025-12-26 07:45:40 +00:00
collection_name = " documents " ,
2025-12-26 09:58:49 +00:00
query = query_embedding ,
2025-12-26 07:45:40 +00:00
limit = 3
)
2025-12-26 09:58:49 +00:00
hits = search_result . points
2025-12-26 07:45:40 +00:00
contexts = [ ]
2025-12-26 09:58:49 +00:00
if hits :
for hit in hits :
2025-12-26 09:11:06 +00:00
try :
2025-12-26 09:58:49 +00:00
if hit . payload :
# --- FIX IMPORTANTE: Recupera il contenuto reale ---
nome_file = hit . payload . get ( ' file_name ' , ' Sconosciuto ' )
contenuto = hit . payload . get ( ' content ' , ' ' )
contexts . append ( f " --- Documento: { nome_file } --- \n { contenuto } \n ---------------- " )
except Exception as e :
print ( f " Error parsing hit: { e } " )
2025-12-26 07:45:40 +00:00
return " \n " . join ( contexts )
except Exception as e :
2025-12-26 09:11:06 +00:00
print ( f " Errore ricerca Qdrant: { e } " )
2025-12-26 07:45:40 +00:00
return " "
2025-12-25 18:00:13 +00:00
2025-12-25 14:54:33 +00:00
@cl.on_chat_start
async def chat_start ( ) :
2025-12-26 07:45:40 +00:00
user_email = " admin@esempio.com "
2025-12-25 14:54:33 +00:00
user_role = USER_ROLES . get ( user_email , ' guest ' )
create_workspace ( user_role )
cl . user_session . set ( " history " , [ ] )
cl . user_session . set ( " role " , user_role )
2025-12-26 09:58:49 +00:00
welcome_msg = f " Welcome, { user_role . capitalize ( ) } ! "
await cl . Message ( content = welcome_msg ) . send ( )
2025-12-25 14:54:33 +00:00
@cl.on_message
2025-12-26 07:45:40 +00:00
async def message ( message ) :
2025-12-25 14:54:33 +00:00
user_role = cl . user_session . get ( " role " , ' guest ' )
2025-12-26 07:45:40 +00:00
if not user_role :
await cl . Message ( content = " User role not found " ) . send ( )
return
try :
2025-12-26 09:11:06 +00:00
client = ollama . Client ( host = OLLAMA_URL )
2025-12-26 07:45:40 +00:00
history = cl . user_session . get ( " history " , [ ] )
history = limit_history ( history )
2025-12-25 14:54:33 +00:00
2025-12-26 09:58:49 +00:00
# --- PASSO 1: Gestione Upload e Indexing (PRIMA della ricerca) ---
2025-12-26 07:45:40 +00:00
if message . elements :
uploaded_files = [ ]
for element in message . elements :
2025-12-25 14:54:33 +00:00
try :
2025-12-26 07:45:40 +00:00
dest_path = os . path . join ( WORKSPACES_DIR , user_role , element . name )
with open ( element . path , ' rb ' ) as src , open ( dest_path , ' wb ' ) as dst :
shutil . copyfileobj ( src , dst )
2025-12-25 14:54:33 +00:00
2025-12-26 07:45:40 +00:00
if element . name . endswith ( ' .txt ' ) :
2025-12-26 09:58:49 +00:00
# Encoding utf-8 per sicurezza
with open ( dest_path , ' r ' , encoding = ' utf-8 ' ) as f :
2025-12-26 07:45:40 +00:00
content = f . read ( )
embeddings = await get_embeddings ( content )
2025-12-26 09:11:06 +00:00
if embeddings :
qdrant_client = await connect_to_qdrant ( )
2025-12-26 09:58:49 +00:00
point_id = str ( uuid . uuid4 ( ) )
# --- FIX IMPORTANTE: Salviamo anche il contenuto nel payload ---
point = PointStruct (
id = point_id ,
vector = embeddings ,
payload = {
" file_name " : element . name ,
" content " : content
}
)
await qdrant_client . upsert ( collection_name = " documents " , points = [ point ] )
2025-12-26 09:11:06 +00:00
await cl . Message ( content = f " Documento ' { element . name } ' indicizzato. " ) . send ( )
2025-12-25 14:54:33 +00:00
2025-12-26 07:45:40 +00:00
uploaded_files . append ( element . name )
2025-12-25 14:54:33 +00:00
except Exception as e :
2025-12-26 07:45:40 +00:00
await cl . Message ( content = f " Error saving { element . name } : { e } " ) . send ( )
if uploaded_files :
await cl . Message ( content = f " Files saved: { ' , ' . join ( uploaded_files ) } " ) . send ( )
2025-12-26 09:58:49 +00:00
# --- PASSO 2: Cerca nei documenti ---
context_text = await search_qdrant ( message . content , user_role )
if context_text :
system_prompt = f " Usa esclusivamente il seguente contesto per rispondere alla domanda. Se la risposta non è nel contesto, dillo. \n \n Contesto: \n { context_text } "
history . insert ( 0 , { " role " : " system " , " content " : system_prompt } )
history . append ( { " role " : " user " , " content " : message . content } )
2025-12-26 07:45:40 +00:00
2025-12-26 09:58:49 +00:00
# --- PASSO 3: Chat Generation ---
2025-12-26 07:45:40 +00:00
response = client . chat ( model = ' qwen2.5-coder:7b ' , messages = history )
2025-12-25 14:54:33 +00:00
2025-12-26 09:58:49 +00:00
# Code Extraction
2025-12-26 07:45:40 +00:00
code_blocks = re . findall ( r " ```python(.*?)``` " , response [ ' message ' ] [ ' content ' ] , re . DOTALL )
2025-12-25 14:54:33 +00:00
2025-12-26 07:45:40 +00:00
elements = [ ]
2025-12-25 14:54:33 +00:00
if code_blocks :
for code in code_blocks :
2025-12-26 07:45:40 +00:00
file_path = save_code_to_file ( code , user_role )
elements . append ( cl . File ( name = os . path . basename ( file_path ) , path = file_path ) )
history . append ( { " role " : " assistant " , " content " : response [ ' message ' ] [ ' content ' ] } )
2025-12-25 14:54:33 +00:00
cl . user_session . set ( " history " , history )
2025-12-26 07:45:40 +00:00
await cl . Message ( content = response [ ' message ' ] [ ' content ' ] , elements = elements ) . send ( )
2025-12-25 14:54:33 +00:00
except Exception as e :
2025-12-26 07:45:40 +00:00
await cl . Message ( content = f " Error: { e } " ) . send ( )