diff --git a/.chainlit/config.toml b/.chainlit/config.toml index f192c501..7b288140 100644 --- a/.chainlit/config.toml +++ b/.chainlit/config.toml @@ -24,7 +24,7 @@ allow_origins = ["*"] [features] # Process and display HTML in messages. This can be a security risk (see https://stackoverflow.com/questions/19603097/why-is-it-dangerous-to-render-user-generated-html-or-javascript) -unsafe_allow_html = false +unsafe_allow_html = true # Process and display mathematical expressions. This can clash with "$" characters in messages. latex = false @@ -57,7 +57,7 @@ reaction_on_message_received = false # 3. For specific file extensions: # accept = { "application/octet-stream" = [".xyz", ".pdb"] } # Note: Using "*/*" is not recommended as it may cause browser warnings - accept = ["*/*"] + accept = ["*"] max_files = 20 max_size_mb = 500 @@ -86,11 +86,11 @@ reaction_on_message_received = false [UI] # Name of the assistant. -name = "Assistant" +name = "Ai Station DFFM" -# default_theme = "dark" +default_theme = "dark" -# layout = "wide" +layout = "wide" default_sidebar_state = "open" @@ -104,6 +104,14 @@ cot = "full" # The CSS file can be served from the public directory or via an external link. # custom_css = "/public/test.css" +# CSS personalizzato +custom_css = "/public/custom.css" + +# Logo custom +[UI.theme] +primary_color = "#0066CC" # Colore brand +background_color = "#1a1a1a" + # Specify additional attributes for a custom CSS file # custom_css_attributes = "media=\"print\"" diff --git a/.files/0df80e24-55a7-4d81-b20e-c048d4dc9de3/6329ce5b-e0b9-409e-bf1b-740f22412f61 b/.files/0df80e24-55a7-4d81-b20e-c048d4dc9de3/6329ce5b-e0b9-409e-bf1b-740f22412f61 new file mode 100644 index 00000000..d8dfb5c4 Binary files /dev/null and b/.files/0df80e24-55a7-4d81-b20e-c048d4dc9de3/6329ce5b-e0b9-409e-bf1b-740f22412f61 differ diff --git a/.files/3656e301-423c-41a3-95cc-aa9c1d0a6d60/9ea4f57e-fd04-417a-a467-f5594c405972 b/.files/3656e301-423c-41a3-95cc-aa9c1d0a6d60/9ea4f57e-fd04-417a-a467-f5594c405972 new file mode 100644 index 00000000..1e116396 Binary files /dev/null and b/.files/3656e301-423c-41a3-95cc-aa9c1d0a6d60/9ea4f57e-fd04-417a-a467-f5594c405972 differ diff --git a/.files/47dcfcf5-095b-4b0f-8895-b52859a242cf/ac4be05d-3c02-4f6c-8ac7-bdbfdcb437c7.pdf b/.files/47dcfcf5-095b-4b0f-8895-b52859a242cf/ac4be05d-3c02-4f6c-8ac7-bdbfdcb437c7.pdf new file mode 100644 index 00000000..562d9231 Binary files /dev/null and b/.files/47dcfcf5-095b-4b0f-8895-b52859a242cf/ac4be05d-3c02-4f6c-8ac7-bdbfdcb437c7.pdf differ diff --git a/.files/6e654425-7858-497f-ba4c-dcc53af4d26d/42a80328-c46c-4168-bf1e-6326d354b9d9 b/.files/6e654425-7858-497f-ba4c-dcc53af4d26d/42a80328-c46c-4168-bf1e-6326d354b9d9 new file mode 100644 index 00000000..d8dfb5c4 Binary files /dev/null and b/.files/6e654425-7858-497f-ba4c-dcc53af4d26d/42a80328-c46c-4168-bf1e-6326d354b9d9 differ diff --git a/.files/88144b6d-1339-4122-823c-f79b205993ae/16115c1a-aad0-4bc7-bf60-057af05361fb.pdf b/.files/88144b6d-1339-4122-823c-f79b205993ae/16115c1a-aad0-4bc7-bf60-057af05361fb.pdf new file mode 100644 index 00000000..562d9231 Binary files /dev/null and b/.files/88144b6d-1339-4122-823c-f79b205993ae/16115c1a-aad0-4bc7-bf60-057af05361fb.pdf differ diff --git a/.files/88144b6d-1339-4122-823c-f79b205993ae/87b7394a-6fc7-4459-b17d-855b5de71630.pdf b/.files/88144b6d-1339-4122-823c-f79b205993ae/87b7394a-6fc7-4459-b17d-855b5de71630.pdf new file mode 100644 index 00000000..ff70ae8a Binary files /dev/null and b/.files/88144b6d-1339-4122-823c-f79b205993ae/87b7394a-6fc7-4459-b17d-855b5de71630.pdf differ diff --git a/.files/9fe2fbbc-be5f-4b83-b69c-aedfb9df25a8/01ffba51-a4ca-40fb-b732-80f5725a1fb9.pdf b/.files/9fe2fbbc-be5f-4b83-b69c-aedfb9df25a8/01ffba51-a4ca-40fb-b732-80f5725a1fb9.pdf new file mode 100644 index 00000000..00b03c2c Binary files /dev/null and b/.files/9fe2fbbc-be5f-4b83-b69c-aedfb9df25a8/01ffba51-a4ca-40fb-b732-80f5725a1fb9.pdf differ diff --git a/.files/9fe2fbbc-be5f-4b83-b69c-aedfb9df25a8/f10b54f7-8dca-4665-b442-9918c40bba39 b/.files/9fe2fbbc-be5f-4b83-b69c-aedfb9df25a8/f10b54f7-8dca-4665-b442-9918c40bba39 new file mode 100644 index 00000000..5b9189d0 Binary files /dev/null and b/.files/9fe2fbbc-be5f-4b83-b69c-aedfb9df25a8/f10b54f7-8dca-4665-b442-9918c40bba39 differ diff --git a/.files/aa8e686d-0d34-421e-be02-0ec587b14adc/3306e6a4-fb7b-4cb7-8518-8b237a712667.pdf b/.files/aa8e686d-0d34-421e-be02-0ec587b14adc/3306e6a4-fb7b-4cb7-8518-8b237a712667.pdf new file mode 100644 index 00000000..562d9231 Binary files /dev/null and b/.files/aa8e686d-0d34-421e-be02-0ec587b14adc/3306e6a4-fb7b-4cb7-8518-8b237a712667.pdf differ diff --git a/.files/ac1bab01-7ff6-4e50-ab1d-30ddf6cd3d59/17b9be9b-c319-4406-936d-674589ad63a7 b/.files/ac1bab01-7ff6-4e50-ab1d-30ddf6cd3d59/17b9be9b-c319-4406-936d-674589ad63a7 new file mode 100644 index 00000000..2de9199b Binary files /dev/null and b/.files/ac1bab01-7ff6-4e50-ab1d-30ddf6cd3d59/17b9be9b-c319-4406-936d-674589ad63a7 differ diff --git a/.files/b7e1daf3-eca7-44c4-a1b1-32f3d0bf03f6/6d477977-149d-4c97-ad86-2ced01cdc811.pdf b/.files/b7e1daf3-eca7-44c4-a1b1-32f3d0bf03f6/6d477977-149d-4c97-ad86-2ced01cdc811.pdf new file mode 100644 index 00000000..ff70ae8a Binary files /dev/null and b/.files/b7e1daf3-eca7-44c4-a1b1-32f3d0bf03f6/6d477977-149d-4c97-ad86-2ced01cdc811.pdf differ diff --git a/.files/bf4072da-0c48-4d57-840e-ab845afa5ff0/4577193b-9fe2-443f-8587-ab59faa2c122.png b/.files/bf4072da-0c48-4d57-840e-ab845afa5ff0/4577193b-9fe2-443f-8587-ab59faa2c122.png new file mode 100644 index 00000000..88b07644 Binary files /dev/null and b/.files/bf4072da-0c48-4d57-840e-ab845afa5ff0/4577193b-9fe2-443f-8587-ab59faa2c122.png differ diff --git a/.files/d8a2ce01-1792-4d49-b580-57aa8216d112/55078a22-7b82-4e20-80c8-79a8d53f37f8.pdf b/.files/d8a2ce01-1792-4d49-b580-57aa8216d112/55078a22-7b82-4e20-80c8-79a8d53f37f8.pdf new file mode 100644 index 00000000..562d9231 Binary files /dev/null and b/.files/d8a2ce01-1792-4d49-b580-57aa8216d112/55078a22-7b82-4e20-80c8-79a8d53f37f8.pdf differ diff --git a/.files/f49178c6-be52-47f5-93c1-9114b9a67a29/d65f66a2-2673-4cc2-9b84-2ad316a17f75 b/.files/f49178c6-be52-47f5-93c1-9114b9a67a29/d65f66a2-2673-4cc2-9b84-2ad316a17f75 new file mode 100644 index 00000000..1e116396 Binary files /dev/null and b/.files/f49178c6-be52-47f5-93c1-9114b9a67a29/d65f66a2-2673-4cc2-9b84-2ad316a17f75 differ diff --git a/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/013a0fb6-459d-462f-827c-e0d9c227bfa5/Fatture 2025.xlsx b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/013a0fb6-459d-462f-827c-e0d9c227bfa5/Fatture 2025.xlsx new file mode 100644 index 00000000..1e116396 Binary files /dev/null and b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/013a0fb6-459d-462f-827c-e0d9c227bfa5/Fatture 2025.xlsx differ diff --git a/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/16115c1a-aad0-4bc7-bf60-057af05361fb/esempio manuale Omron.pdf b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/16115c1a-aad0-4bc7-bf60-057af05361fb/esempio manuale Omron.pdf new file mode 100644 index 00000000..562d9231 Binary files /dev/null and b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/16115c1a-aad0-4bc7-bf60-057af05361fb/esempio manuale Omron.pdf differ diff --git a/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/3306e6a4-fb7b-4cb7-8518-8b237a712667/esempio manuale Omron.pdf b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/3306e6a4-fb7b-4cb7-8518-8b237a712667/esempio manuale Omron.pdf new file mode 100644 index 00000000..562d9231 Binary files /dev/null and b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/3306e6a4-fb7b-4cb7-8518-8b237a712667/esempio manuale Omron.pdf differ diff --git a/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/3f168cf3-0444-48da-b16c-90c095f159c7/b71188b4-ae12-4321-8ada-e3f858d851e4.png b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/3f168cf3-0444-48da-b16c-90c095f159c7/b71188b4-ae12-4321-8ada-e3f858d851e4.png new file mode 100644 index 00000000..8e1034cf Binary files /dev/null and b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/3f168cf3-0444-48da-b16c-90c095f159c7/b71188b4-ae12-4321-8ada-e3f858d851e4.png differ diff --git a/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/42a80328-c46c-4168-bf1e-6326d354b9d9/Alarms Table TCO2307.xlsx b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/42a80328-c46c-4168-bf1e-6326d354b9d9/Alarms Table TCO2307.xlsx new file mode 100644 index 00000000..d8dfb5c4 Binary files /dev/null and b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/42a80328-c46c-4168-bf1e-6326d354b9d9/Alarms Table TCO2307.xlsx differ diff --git a/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/55078a22-7b82-4e20-80c8-79a8d53f37f8/esempio manuale Omron.pdf b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/55078a22-7b82-4e20-80c8-79a8d53f37f8/esempio manuale Omron.pdf new file mode 100644 index 00000000..562d9231 Binary files /dev/null and b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/55078a22-7b82-4e20-80c8-79a8d53f37f8/esempio manuale Omron.pdf differ diff --git a/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/6329ce5b-e0b9-409e-bf1b-740f22412f61/Alarms Table TCO2307.xlsx b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/6329ce5b-e0b9-409e-bf1b-740f22412f61/Alarms Table TCO2307.xlsx new file mode 100644 index 00000000..d8dfb5c4 Binary files /dev/null and b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/6329ce5b-e0b9-409e-bf1b-740f22412f61/Alarms Table TCO2307.xlsx differ diff --git a/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/6d477977-149d-4c97-ad86-2ced01cdc811/Dichiarazion_Degenza.pdf b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/6d477977-149d-4c97-ad86-2ced01cdc811/Dichiarazion_Degenza.pdf new file mode 100644 index 00000000..ff70ae8a Binary files /dev/null and b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/6d477977-149d-4c97-ad86-2ced01cdc811/Dichiarazion_Degenza.pdf differ diff --git a/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/7a4ce70a-2f2d-4980-83e9-1ff64ca67195/Alarms Table TCO2307.xlsx b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/7a4ce70a-2f2d-4980-83e9-1ff64ca67195/Alarms Table TCO2307.xlsx new file mode 100644 index 00000000..d8dfb5c4 Binary files /dev/null and b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/7a4ce70a-2f2d-4980-83e9-1ff64ca67195/Alarms Table TCO2307.xlsx differ diff --git a/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/87141a69-74d3-48ac-9e11-33ce513fb189/b71188b4-ae12-4321-8ada-e3f858d851e4.png b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/87141a69-74d3-48ac-9e11-33ce513fb189/b71188b4-ae12-4321-8ada-e3f858d851e4.png new file mode 100644 index 00000000..8e1034cf Binary files /dev/null and b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/87141a69-74d3-48ac-9e11-33ce513fb189/b71188b4-ae12-4321-8ada-e3f858d851e4.png differ diff --git a/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/87b7394a-6fc7-4459-b17d-855b5de71630/Dichiarazion_Degenza.pdf b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/87b7394a-6fc7-4459-b17d-855b5de71630/Dichiarazion_Degenza.pdf new file mode 100644 index 00000000..ff70ae8a Binary files /dev/null and b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/87b7394a-6fc7-4459-b17d-855b5de71630/Dichiarazion_Degenza.pdf differ diff --git a/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/9a46bb8a-bf71-4fc5-9ec6-ba1408e6f8ce/Alarms Table TCO2307.xlsx b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/9a46bb8a-bf71-4fc5-9ec6-ba1408e6f8ce/Alarms Table TCO2307.xlsx new file mode 100644 index 00000000..5367ad53 Binary files /dev/null and b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/9a46bb8a-bf71-4fc5-9ec6-ba1408e6f8ce/Alarms Table TCO2307.xlsx differ diff --git a/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/9ea4f57e-fd04-417a-a467-f5594c405972/Fatture 2025.xlsx b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/9ea4f57e-fd04-417a-a467-f5594c405972/Fatture 2025.xlsx new file mode 100644 index 00000000..1e116396 Binary files /dev/null and b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/9ea4f57e-fd04-417a-a467-f5594c405972/Fatture 2025.xlsx differ diff --git a/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/a98d6f7b-5275-452d-92c1-7e3968dcb526/app.py b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/a98d6f7b-5275-452d-92c1-7e3968dcb526/app.py new file mode 100644 index 00000000..73f2cb95 --- /dev/null +++ b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/a98d6f7b-5275-452d-92c1-7e3968dcb526/app.py @@ -0,0 +1,463 @@ +import os +import re +import uuid +import shutil +import requests +import time +import json +from datetime import datetime +from typing import Optional, Dict, List, Any +import chainlit as cl +import ollama +from docling.document_converter import DocumentConverter +from qdrant_client import AsyncQdrantClient +# CORREZIONE IMPORT: Importiamo le classi necessarie direttamente dalla libreria +from qdrant_client.models import PointStruct, Distance, VectorParams, SparseVectorParams, Prefetch +from chainlit.data.sql_alchemy import SQLAlchemyDataLayer +from chainlit.types import ThreadDict +from functools import lru_cache + +# === FIX IMPORT ROBUSTO === +try: + from chainlit.data.storage_clients import BaseStorageClient +except ImportError: + try: + from chainlit.data.base import BaseStorageClient + except ImportError: + from chainlit.data.storage_clients.base import BaseStorageClient + +# === CONFIGURAZIONE === +DATABASE_URL = os.getenv("DATABASE_URL", "postgresql+asyncpg://ai_user:secure_password_here@postgres:5432/ai_station") +OLLAMA_URL = os.getenv("OLLAMA_URL", "http://192.168.1.243:11434") +QDRANT_URL = os.getenv("QDRANT_URL", "http://qdrant:6333") +BGE_API_URL = os.getenv("BGE_API_URL", "http://192.168.1.243:8001/embed") + +VISION_MODEL = "minicpm-v" +DEFAULT_TEXT_MODEL = "glm-4.6:cloud" + +WORKSPACES_DIR = "./workspaces" +STORAGE_DIR = "./.files" + +os.makedirs(STORAGE_DIR, exist_ok=True) +os.makedirs(WORKSPACES_DIR, exist_ok=True) + +# === MAPPING UTENTI === +USER_PROFILES = { + "giuseppe@defranceschi.pro": { "role": "admin", "name": "Giuseppe", "workspace": "admin_workspace", "rag_collection": "admin_docs", "capabilities": ["debug", "all"], "show_code": True }, + "giuseppe.defranceschi@gmail.com": { "role": "admin", "name": "Giuseppe", "workspace": "admin_workspace", "rag_collection": "admin_docs", "capabilities": ["debug", "all"], "show_code": True }, + "federica.tecchio@gmail.com": { "role": "business", "name": "Federica", "workspace": "business_workspace", "rag_collection": "contabilita", "capabilities": ["basic_chat"], "show_code": False }, + "riccardob545@gmail.com": { "role": "engineering", "name": "Riccardo", "workspace": "engineering_workspace", "rag_collection": "engineering_docs", "capabilities": ["code"], "show_code": True }, + "giuliadefranceschi05@gmail.com": { "role": "architecture", "name": "Giulia", "workspace": "architecture_workspace", "rag_collection": "architecture_manuals", "capabilities": ["visual"], "show_code": False } +} + +# === STORAGE CLIENT === +class LocalStorageClient(BaseStorageClient): + def __init__(self, storage_path: str): + self.storage_path = storage_path + os.makedirs(storage_path, exist_ok=True) + async def upload_file(self, object_key: str, data: bytes, mime: str = "application/octet-stream", overwrite: bool = True) -> Dict[str, str]: + file_path = os.path.join(self.storage_path, object_key) + os.makedirs(os.path.dirname(file_path), exist_ok=True) + with open(file_path, "wb") as f: f.write(data) + return {"object_key": object_key, "url": f"/files/{object_key}"} + async def get_read_url(self, object_key: str) -> str: return f"/files/{object_key}" + async def delete_file(self, object_key: str) -> bool: + path = os.path.join(self.storage_path, object_key) + if os.path.exists(path): os.remove(path); return True + return False + async def close(self): pass + +@cl.data_layer +def get_data_layer(): + return SQLAlchemyDataLayer(conninfo=DATABASE_URL, storage_provider=LocalStorageClient(STORAGE_DIR)) + +# === OAUTH & UTILS === +@cl.oauth_callback +def oauth_callback(provider_id: str, token: str, raw_user_data: Dict[str, str], default_user: cl.User) -> Optional[cl.User]: + if provider_id == "google": + email = raw_user_data.get("email", "").lower() + profile = USER_PROFILES.get(email, USER_PROFILES.get("guest", {"role": "guest", "name": "Guest", "workspace": "guest", "rag_collection": "public", "show_code": False})) + default_user.metadata.update({"role": profile["role"], "workspace": profile["workspace"], "rag_collection": profile["rag_collection"], "show_code": profile["show_code"], "display_name": profile["name"]}) + return default_user + return default_user + +def create_workspace(workspace_name: str) -> str: + path = os.path.join(WORKSPACES_DIR, workspace_name) + os.makedirs(path, exist_ok=True) + return path + + +# === CORE: DOCLING === +def process_file_with_docling(file_path: str) -> str: + try: + converter = DocumentConverter() + result = converter.convert(file_path) + return result.document.export_to_markdown() + except Exception as e: + print(f"❌ Docling Error: {e}") + return "" + +# === CORE: BGE-M3 CLIENT === +def get_bge_embeddings(text: str) -> Optional[Dict[str, Any]]: + try: + payload = {"texts": [text[:8000]]} + response = requests.post(BGE_API_URL, json=payload, timeout=30) + response.raise_for_status() + data = response.json().get("data", []) + if data: + return data[0] + return None + except Exception as e: + print(f"❌ BGE API Error: {e}") + return None + +# === CORE: QDRANT === +async def ensure_collection(collection_name: str): + client = AsyncQdrantClient(url=QDRANT_URL) + if not await client.collection_exists(collection_name): + await client.create_collection( + collection_name=collection_name, + vectors_config={"dense": VectorParams(size=1024, distance=Distance.COSINE)}, + sparse_vectors_config={"sparse": SparseVectorParams()} + ) + +async def index_document(file_name: str, content: str, collection_name: str): + await ensure_collection(collection_name) + client = AsyncQdrantClient(url=QDRANT_URL) + + chunk_size = 2000 + overlap = 200 + + points = [] + for i in range(0, len(content), chunk_size - overlap): + chunk = content[i : i + chunk_size] + embedding_data = get_bge_embeddings(chunk) + + if embedding_data: + points.append(PointStruct( + id=str(uuid.uuid4()), + vector={ + "dense": embedding_data["dense"], + "sparse": embedding_data["sparse"] + }, + payload={ + "file_name": file_name, + "content": chunk, + "indexed_at": datetime.now().isoformat() + } + )) + + if points: + await client.upsert(collection_name=collection_name, points=points) + return len(points) + return 0 + +async def search_hybrid(query: str, collection_name: str, limit: int = 4) -> str: + client = AsyncQdrantClient(url=QDRANT_URL) + if not await client.collection_exists(collection_name): return "" + + query_emb = get_bge_embeddings(query) + if not query_emb: return "" + + # CORREZIONE QUI: Usiamo l'oggetto Prefetch importato correttamente + results = await client.query_points( + collection_name=collection_name, + prefetch=[ + Prefetch( + query=query_emb["sparse"], + using="sparse", + limit=limit * 2 + ) + ], + query=query_emb["dense"], + using="dense", + limit=limit + ) + + context = [] + for hit in results.points: + context.append(f"--- DA {hit.payload['file_name']} ---\n{hit.payload['content']}") + + return "\n\n".join(context) + +# === Caching Embeddings === +@lru_cache(maxsize=1000) +def get_bge_embeddings_cached(text: str): + """Cache per query ripetute""" + return get_bge_embeddings(text) + +# === CHAINLIT HANDLERS === +@cl.on_chat_start +async def start(): + # 1. Profilo utente + user = cl.user_session.get("user") + email = user.identifier if user else "guest" + profile = USER_PROFILES.get(email, USER_PROFILES["giuseppe@defranceschi.pro"]) + + cl.user_session.set("profile", profile) + create_workspace(profile["workspace"]) + + # 2. Badge HTML personalizzato + role_color = { + "admin": "#e74c3c", + "engineering": "#3498db", + "business": "#2ecc71", + "architecture": "#9b59b6", + }.get(profile["role"], "#95a5a6") + + badge_html = f""" +
+ 👤 {profile['name']} | 🔧 {profile['role'].upper()} | 📁 {profile['workspace']} +
+ """ + await cl.Message(content=badge_html).send() + + # 3. Settings UI + settings = await cl.ChatSettings( + [ + cl.input_widget.Slider( + id="top_k", + label="Numero Documenti RAG", + initial=4, + min=1, + max=10, + step=1, + ), + cl.input_widget.Select( + id="vision_detail", + label="Dettaglio Analisi Immagini", + values=["auto", "low", "high"], + initial_value="auto", + ), + cl.input_widget.TextInput( + id="system_instruction", + label="Istruzione Sistema Custom (opzionale)", + initial="", + placeholder="Es: Rispondi sempre in formato tecnico...", + ), + cl.input_widget.Select( + id="model", + label="Modello di Ragionamento", + values=[DEFAULT_TEXT_MODEL, "llama3.2", "mistral", "qwen2.5-coder:32b"], + initial_value=DEFAULT_TEXT_MODEL, + ), + cl.input_widget.Slider( + id="temperature", + label="Creatività (Temperatura)", + initial=0.3, + min=0, + max=1, + step=0.1, + ), + cl.input_widget.Switch( + id="rag_enabled", + label="Usa Conoscenza Documenti (RAG)", + initial=True, + ), + ] + ).send() + + cl.user_session.set("settings", settings) + + # 4. Messaggio iniziale (opzionale) + await cl.Message( + content=( + f"🚀 **Vision-RAG Hybrid System Online**\n" + f"Utente: {profile['name']} | Workspace: {profile['workspace']}\n" + f"Engine: Docling + BGE-M3 + {VISION_MODEL}" + ) + ).send() + + + cl.user_session.set("settings", settings) + + await cl.Message(f"🚀 **Vision-RAG Hybrid System Online**\nUtente: {profile['name']} | Workspace: {profile['workspace']}\nEngine: Docling + BGE-M3 + {VISION_MODEL}").send() + +@cl.on_settings_update +async def setup_agent(settings): + cl.user_session.set("settings", settings) + await cl.Message(content=f"✅ Impostazioni aggiornate: Modello {settings['model']}").send() + +async def log_metrics(metrics: dict): + # Versione minima: log su stdout + print("[METRICS]", metrics) + + # In futuro puoi: + # - salvarle in Postgres + # - mandarle a Prometheus / Grafana + # - scriverle su file JSON per analisi settimanale + +# - Resume Chat Handler + +@cl.on_chat_resume +async def on_chat_resume(thread: ThreadDict): + """ + Viene chiamato quando l'utente clicca 'Riprendi' su una chat archiviata. + Chainlit carica già i messaggi nella UI, qui puoi solo ripristinare la sessione. + """ + # Se vuoi, puoi recuperare l'identifier dell’utente dal thread + user_identifier = thread.get("userIdentifier") + profile = USER_PROFILES.get( + user_identifier, + USER_PROFILES["giuseppe@defranceschi.pro"], + ) + cl.user_session.set("profile", profile) + + # Puoi anche ripristinare eventuale stato custom (es: impostazioni di default) + # oppure semplicemente salutare l’utente + await cl.Message( + content="👋 Bentornato! Possiamo riprendere da questa conversazione." + ).send() + +@cl.on_message +async def main(message: cl.Message): + start_time = time.time() + + profile = cl.user_session.get("profile") + settings = cl.user_session.get("settings", {}) + + selected_model = settings.get("model", DEFAULT_TEXT_MODEL) + temperature = settings.get("temperature", 0.3) + rag_enabled = settings.get("rag_enabled", True) + + workspace = create_workspace(profile["workspace"]) + + images_for_vision = [] + doc_context = "" + rag_context = "" # ← la inizializzi qui, così esiste sempre + + # 1. GESTIONE FILE + if message.elements: + for element in message.elements: + file_path = os.path.join(workspace, element.name) + shutil.copy(element.path, file_path) + + if "image" in element.mime: + images_for_vision.append(file_path) + msg_img = cl.Message( + content=f"👁️ Analizzo immagine **{element.name}** con {VISION_MODEL}..." + ) + await msg_img.send() + + with open(file_path, "rb") as img_file: + img_bytes = img_file.read() + + client_sync = ollama.Client(host=OLLAMA_URL) + res = client_sync.chat( + model=VISION_MODEL, + messages=[{ + "role": "user", + "content": ( + "Analizza questa immagine tecnica. Trascrivi testi, codici " + "e descrivi diagrammi o tabelle in dettaglio." + ), + "images": [img_bytes], + }], + ) + desc = res["message"]["content"] + doc_context += f"\n\n[DESCRIZIONE IMMAGINE {element.name}]:\n{desc}" + msg_img.content = f"✅ Immagine analizzata:\n{desc[:200]}..." + await msg_img.update() + + elif element.name.endswith((".pdf", ".docx")): + msg_doc = cl.Message( + content=f"📄 Leggo **{element.name}** con Docling (tabelle/formule)..." + ) + await msg_doc.send() + + markdown_content = process_file_with_docling(file_path) + if markdown_content: + chunks = await index_document( + element.name, markdown_content, profile["rag_collection"] + ) + msg_doc.content = ( + f"✅ **{element.name}**: Convertito e salvato {chunks} " + "frammenti nel DB vettoriale." + ) + doc_context += ( + f"\n\n[CONTENUTO FILE {element.name}]:\n" + f"{markdown_content[:1000]}..." + ) + else: + msg_doc.content = f"❌ Errore lettura {element.name}" + await msg_doc.update() + + # 2. RAG RETRIEVAL + if rag_enabled and not images_for_vision: + rag_context = await search_hybrid( + message.content, profile["rag_collection"] + ) + + final_context = "" + if rag_context: + final_context += f"CONTESTO RAG:\n{rag_context}\n" + if doc_context: + final_context += f"CONTESTO SESSIONE CORRENTE:\n{doc_context}\n" + + system_prompt = ( + "Sei un assistente tecnico esperto. Usa il contesto fornito " + "(incluso Markdown di tabelle e descrizioni immagini) per " + "rispondere con precisione. Cita i documenti fonte." + ) + + msg = cl.Message(content="") + await msg.send() + + error = None + + # 3. GENERAZIONE + try: + client_async = ollama.AsyncClient(host=OLLAMA_URL) + stream = await client_async.chat( + model=selected_model, + messages=[ + {"role": "system", "content": system_prompt}, + { + "role": "user", + "content": f"Domanda: {message.content}\n\n{final_context}", + }, + ], + options={"temperature": temperature}, + stream=True, + ) + + async for chunk in stream: + content = chunk["message"]["content"] + await msg.stream_token(content) + await msg.update() + except Exception as e: + error = str(e) + await msg.stream_token(f"❌ Errore AI: {error}") + await msg.update() + + # 4. SALVATAGGIO CODICE + if profile["show_code"]: + code_blocks = re.findall(r"``````", msg.content, re.DOTALL) + if code_blocks: + for i, code in enumerate(code_blocks): + fname = f"script_{datetime.now().strftime('%H%M%S')}_{i}.py" + with open(os.path.join(workspace, fname), "w") as f: + f.write(code.strip()) + await cl.Message( + content=f"💾 Script salvato: `{fname}`" + ).send() + + # 5. METRICHE (ALLA FINE) + elapsed = time.time() - start_time + + # Se rag_context è una stringa concatenata, puoi stimare i "rag_hits" + # contando i separatori che usi in search_hybrid (es. '--- DA ') + if rag_context: + rag_hits = rag_context.count("--- DA ") + else: + rag_hits = 0 + + metrics = { + "response_time": elapsed, + "rag_hits": rag_hits, + "model": selected_model, + "user_role": profile["role"], + "error": error, + } + + await log_metrics(metrics) diff --git a/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/cb54f22c-d8c6-406b-9290-00e62e42b515/Alarms Table TCO2307.xlsx b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/cb54f22c-d8c6-406b-9290-00e62e42b515/Alarms Table TCO2307.xlsx new file mode 100644 index 00000000..d8dfb5c4 Binary files /dev/null and b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/cb54f22c-d8c6-406b-9290-00e62e42b515/Alarms Table TCO2307.xlsx differ diff --git a/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/f8c60587-20a4-4927-be0f-a487f707ae17/Alarms Table TCO2307.xlsx b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/f8c60587-20a4-4927-be0f-a487f707ae17/Alarms Table TCO2307.xlsx new file mode 100644 index 00000000..d8dfb5c4 Binary files /dev/null and b/.files/fe508c80-f90f-471d-a7f8-fc98d4a018d6/f8c60587-20a4-4927-be0f-a487f707ae17/Alarms Table TCO2307.xlsx differ diff --git a/.files/unknown/ac4be05d-3c02-4f6c-8ac7-bdbfdcb437c7/esempio manuale Omron.pdf b/.files/unknown/ac4be05d-3c02-4f6c-8ac7-bdbfdcb437c7/esempio manuale Omron.pdf new file mode 100644 index 00000000..562d9231 Binary files /dev/null and b/.files/unknown/ac4be05d-3c02-4f6c-8ac7-bdbfdcb437c7/esempio manuale Omron.pdf differ diff --git a/.files/unknown/d65f66a2-2673-4cc2-9b84-2ad316a17f75/Fatture 2025.xlsx b/.files/unknown/d65f66a2-2673-4cc2-9b84-2ad316a17f75/Fatture 2025.xlsx new file mode 100644 index 00000000..1e116396 Binary files /dev/null and b/.files/unknown/d65f66a2-2673-4cc2-9b84-2ad316a17f75/Fatture 2025.xlsx differ diff --git a/Dockerfile b/Dockerfile index 0ff6ac6b..6d8ae60e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,9 +3,12 @@ FROM python:3.11-slim WORKDIR /app # Installa dipendenze sistema +# Aggiunte libgl1 e libglib2.0-0 per il supporto Docling/CV2 RUN apt-get update && apt-get install -y \ gcc \ postgresql-client \ + libgl1 \ + libglib2.0-0 \ && rm -rf /var/lib/apt/lists/* # Copia requirements e installa diff --git a/app.py b/app.py index 230d6b51..73f2cb95 100644 --- a/app.py +++ b/app.py @@ -2,17 +2,22 @@ import os import re import uuid import shutil +import requests +import time +import json from datetime import datetime -from typing import Optional, Dict, List +from typing import Optional, Dict, List, Any import chainlit as cl import ollama -import fitz # PyMuPDF +from docling.document_converter import DocumentConverter from qdrant_client import AsyncQdrantClient -from qdrant_client.models import PointStruct, Distance, VectorParams +# CORREZIONE IMPORT: Importiamo le classi necessarie direttamente dalla libreria +from qdrant_client.models import PointStruct, Distance, VectorParams, SparseVectorParams, Prefetch from chainlit.data.sql_alchemy import SQLAlchemyDataLayer +from chainlit.types import ThreadDict +from functools import lru_cache # === FIX IMPORT ROBUSTO === -# Gestisce le differenze tra le versioni di Chainlit 2.x try: from chainlit.data.storage_clients import BaseStorageClient except ImportError: @@ -25,320 +30,434 @@ except ImportError: DATABASE_URL = os.getenv("DATABASE_URL", "postgresql+asyncpg://ai_user:secure_password_here@postgres:5432/ai_station") OLLAMA_URL = os.getenv("OLLAMA_URL", "http://192.168.1.243:11434") QDRANT_URL = os.getenv("QDRANT_URL", "http://qdrant:6333") +BGE_API_URL = os.getenv("BGE_API_URL", "http://192.168.1.243:8001/embed") + +VISION_MODEL = "minicpm-v" +DEFAULT_TEXT_MODEL = "glm-4.6:cloud" + WORKSPACES_DIR = "./workspaces" STORAGE_DIR = "./.files" os.makedirs(STORAGE_DIR, exist_ok=True) os.makedirs(WORKSPACES_DIR, exist_ok=True) -# === MAPPING UTENTI E RUOLI === +# === MAPPING UTENTI === USER_PROFILES = { - "giuseppe@defranceschi.pro": { - "role": "admin", - "name": "Giuseppe", - "workspace": "admin_workspace", - "rag_collection": "admin_docs", - "capabilities": ["debug", "system_prompts", "user_management", "all_models"], - "show_code": True - }, - "federica.tecchio@gmail.com": { - "role": "business", - "name": "Federica", - "workspace": "business_workspace", - "rag_collection": "contabilita", - "capabilities": ["pdf_upload", "basic_chat"], - "show_code": False - }, - "giuseppe.defranceschi@gmail.com": { - "role": "admin", - "name": "Giuseppe", - "workspace": "admin_workspace", - "rag_collection": "admin_docs", - "capabilities": ["debug", "system_prompts", "user_management", "all_models"], - "show_code": True - }, - "riccardob545@gmail.com": { - "role": "engineering", - "name": "Riccardo", - "workspace": "engineering_workspace", - "rag_collection": "engineering_docs", - "capabilities": ["code_execution", "data_viz", "advanced_chat"], - "show_code": True - }, - "giuliadefranceschi05@gmail.com": { - "role": "architecture", - "name": "Giulia", - "workspace": "architecture_workspace", - "rag_collection": "architecture_manuals", - "capabilities": ["visual_chat", "pdf_upload", "image_gen"], - "show_code": False - } + "giuseppe@defranceschi.pro": { "role": "admin", "name": "Giuseppe", "workspace": "admin_workspace", "rag_collection": "admin_docs", "capabilities": ["debug", "all"], "show_code": True }, + "giuseppe.defranceschi@gmail.com": { "role": "admin", "name": "Giuseppe", "workspace": "admin_workspace", "rag_collection": "admin_docs", "capabilities": ["debug", "all"], "show_code": True }, + "federica.tecchio@gmail.com": { "role": "business", "name": "Federica", "workspace": "business_workspace", "rag_collection": "contabilita", "capabilities": ["basic_chat"], "show_code": False }, + "riccardob545@gmail.com": { "role": "engineering", "name": "Riccardo", "workspace": "engineering_workspace", "rag_collection": "engineering_docs", "capabilities": ["code"], "show_code": True }, + "giuliadefranceschi05@gmail.com": { "role": "architecture", "name": "Giulia", "workspace": "architecture_workspace", "rag_collection": "architecture_manuals", "capabilities": ["visual"], "show_code": False } } -# === CUSTOM LOCAL STORAGE CLIENT (FIXED) ===# Questa classe ora implementa tutti i metodi astratti richiesti da Chainlit 2.8.3 +# === STORAGE CLIENT === class LocalStorageClient(BaseStorageClient): - """Storage locale su filesystem per file/elementi""" - def __init__(self, storage_path: str): self.storage_path = storage_path os.makedirs(storage_path, exist_ok=True) - - async def upload_file( - self, - object_key: str, - data: bytes, - mime: str = "application/octet-stream", - overwrite: bool = True, - ) -> Dict[str, str]: + async def upload_file(self, object_key: str, data: bytes, mime: str = "application/octet-stream", overwrite: bool = True) -> Dict[str, str]: file_path = os.path.join(self.storage_path, object_key) os.makedirs(os.path.dirname(file_path), exist_ok=True) - with open(file_path, "wb") as f: - f.write(data) + with open(file_path, "wb") as f: f.write(data) return {"object_key": object_key, "url": f"/files/{object_key}"} - - # Implementazione metodi obbligatori mancanti nella versione precedente - async def get_read_url(self, object_key: str) -> str: - return f"/files/{object_key}" - + async def get_read_url(self, object_key: str) -> str: return f"/files/{object_key}" async def delete_file(self, object_key: str) -> bool: - file_path = os.path.join(self.storage_path, object_key) - if os.path.exists(file_path): - os.remove(file_path) - return True + path = os.path.join(self.storage_path, object_key) + if os.path.exists(path): os.remove(path); return True return False + async def close(self): pass - async def close(self): - pass - -# === DATA LAYER === @cl.data_layer def get_data_layer(): - return SQLAlchemyDataLayer( - conninfo=DATABASE_URL, - user_thread_limit=1000, - storage_provider=LocalStorageClient(storage_path=STORAGE_DIR) - ) + return SQLAlchemyDataLayer(conninfo=DATABASE_URL, storage_provider=LocalStorageClient(STORAGE_DIR)) -# === OAUTH CALLBACK === +# === OAUTH & UTILS === @cl.oauth_callback -def oauth_callback( - provider_id: str, - token: str, - raw_user_data: Dict[str, str], - default_user: cl.User, -) -> Optional[cl.User]: +def oauth_callback(provider_id: str, token: str, raw_user_data: Dict[str, str], default_user: cl.User) -> Optional[cl.User]: if provider_id == "google": email = raw_user_data.get("email", "").lower() - - # Verifica se utente è autorizzato (opzionale: blocca se non in lista) - # if email not in USER_PROFILES: - # return None - - # Recupera profilo o usa default Guest - profile = USER_PROFILES.get(email, get_user_profile("guest")) - - default_user.metadata.update({ - "picture": raw_user_data.get("picture", ""), - "role": profile["role"], - "workspace": profile["workspace"], - "rag_collection": profile["rag_collection"], - "capabilities": profile["capabilities"], - "show_code": profile["show_code"], - "display_name": profile["name"] - }) + profile = USER_PROFILES.get(email, USER_PROFILES.get("guest", {"role": "guest", "name": "Guest", "workspace": "guest", "rag_collection": "public", "show_code": False})) + default_user.metadata.update({"role": profile["role"], "workspace": profile["workspace"], "rag_collection": profile["rag_collection"], "show_code": profile["show_code"], "display_name": profile["name"]}) return default_user return default_user -# === UTILITY FUNCTIONS === -def get_user_profile(user_email: str) -> Dict: - return USER_PROFILES.get(user_email.lower(), { - "role": "guest", - "name": "Ospite", - "workspace": "guest_workspace", - "rag_collection": "documents", - "capabilities": [], - "show_code": False - }) - def create_workspace(workspace_name: str) -> str: path = os.path.join(WORKSPACES_DIR, workspace_name) os.makedirs(path, exist_ok=True) return path -def save_code_to_file(code: str, workspace: str) -> str: - timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") - file_name = f"code_{timestamp}.py" - file_path = os.path.join(WORKSPACES_DIR, workspace, file_name) - with open(file_path, "w", encoding="utf-8") as f: - f.write(code) - return file_path -def extract_text_from_pdf(pdf_path: str) -> str: +# === CORE: DOCLING === +def process_file_with_docling(file_path: str) -> str: try: - doc = fitz.open(pdf_path) - text = "\n".join([page.get_text() for page in doc]) - doc.close() - return text - except Exception: + converter = DocumentConverter() + result = converter.convert(file_path) + return result.document.export_to_markdown() + except Exception as e: + print(f"❌ Docling Error: {e}") return "" -# === QDRANT FUNCTIONS === -async def get_qdrant_client() -> AsyncQdrantClient: - return AsyncQdrantClient(url=QDRANT_URL) +# === CORE: BGE-M3 CLIENT === +def get_bge_embeddings(text: str) -> Optional[Dict[str, Any]]: + try: + payload = {"texts": [text[:8000]]} + response = requests.post(BGE_API_URL, json=payload, timeout=30) + response.raise_for_status() + data = response.json().get("data", []) + if data: + return data[0] + return None + except Exception as e: + print(f"❌ BGE API Error: {e}") + return None +# === CORE: QDRANT === async def ensure_collection(collection_name: str): - client = await get_qdrant_client() + client = AsyncQdrantClient(url=QDRANT_URL) if not await client.collection_exists(collection_name): await client.create_collection( collection_name=collection_name, - vectors_config=VectorParams(size=768, distance=Distance.COSINE) + vectors_config={"dense": VectorParams(size=1024, distance=Distance.COSINE)}, + sparse_vectors_config={"sparse": SparseVectorParams()} ) -async def get_embeddings(text: str) -> list: - client = ollama.Client(host=OLLAMA_URL) - try: - response = client.embed(model='nomic-embed-text', input=text[:2000]) - if 'embeddings' in response: return response['embeddings'][0] - return response.get('embedding', []) - except: return [] - -async def index_document(file_name: str, content: str, collection_name: str) -> bool: - try: - await ensure_collection(collection_name) - embedding = await get_embeddings(content) - if not embedding: return False +async def index_document(file_name: str, content: str, collection_name: str): + await ensure_collection(collection_name) + client = AsyncQdrantClient(url=QDRANT_URL) + + chunk_size = 2000 + overlap = 200 + + points = [] + for i in range(0, len(content), chunk_size - overlap): + chunk = content[i : i + chunk_size] + embedding_data = get_bge_embeddings(chunk) - qdrant = await get_qdrant_client() - await qdrant.upsert( - collection_name=collection_name, - points=[PointStruct( + if embedding_data: + points.append(PointStruct( id=str(uuid.uuid4()), - vector=embedding, - payload={"file_name": file_name, "content": content[:3000], "indexed_at": datetime.now().isoformat()} - )] - ) - return True - except: return False + vector={ + "dense": embedding_data["dense"], + "sparse": embedding_data["sparse"] + }, + payload={ + "file_name": file_name, + "content": chunk, + "indexed_at": datetime.now().isoformat() + } + )) + + if points: + await client.upsert(collection_name=collection_name, points=points) + return len(points) + return 0 -async def search_qdrant(query: str, collection: str) -> str: - try: - client = await get_qdrant_client() - if not await client.collection_exists(collection): return "" - emb = await get_embeddings(query) - if not emb: return "" - res = await client.query_points(collection_name=collection, query=emb, limit=3) - return "\n\n".join([hit.payload['content'] for hit in res.points if hit.payload]) - except: return "" +async def search_hybrid(query: str, collection_name: str, limit: int = 4) -> str: + client = AsyncQdrantClient(url=QDRANT_URL) + if not await client.collection_exists(collection_name): return "" + + query_emb = get_bge_embeddings(query) + if not query_emb: return "" + + # CORREZIONE QUI: Usiamo l'oggetto Prefetch importato correttamente + results = await client.query_points( + collection_name=collection_name, + prefetch=[ + Prefetch( + query=query_emb["sparse"], + using="sparse", + limit=limit * 2 + ) + ], + query=query_emb["dense"], + using="dense", + limit=limit + ) + + context = [] + for hit in results.points: + context.append(f"--- DA {hit.payload['file_name']} ---\n{hit.payload['content']}") + + return "\n\n".join(context) + +# === Caching Embeddings === +@lru_cache(maxsize=1000) +def get_bge_embeddings_cached(text: str): + """Cache per query ripetute""" + return get_bge_embeddings(text) # === CHAINLIT HANDLERS === - @cl.on_chat_start -async def on_chat_start(): +async def start(): + # 1. Profilo utente user = cl.user_session.get("user") + email = user.identifier if user else "guest" + profile = USER_PROFILES.get(email, USER_PROFILES["giuseppe@defranceschi.pro"]) - if not user: - # Fallback locale se non c'è auth - user_email = "guest@local" - profile = get_user_profile(user_email) - else: - user_email = user.identifier - # I metadati sono già popolati dalla callback oauth - profile = USER_PROFILES.get(user_email, get_user_profile("guest")) - - # Salva in sessione - cl.user_session.set("email", user_email) - cl.user_session.set("role", profile["role"]) - cl.user_session.set("workspace", profile["workspace"]) - cl.user_session.set("rag_collection", profile["rag_collection"]) - cl.user_session.set("show_code", profile["show_code"]) - + cl.user_session.set("profile", profile) create_workspace(profile["workspace"]) - # === SETTINGS WIDGETS === - settings_widgets = [ - cl.input_widget.Select( - id="model", - label="Modello AI", - values=["glm-4.6:cloud", "llama3.2", "mistral", "qwen2.5-coder:32b"], - initial_value="glm-4.6:cloud", - ), - cl.input_widget.Slider( - id="temperature", - label="Temperatura", - initial=0.7, min=0, max=2, step=0.1, - ), - ] - if profile["role"] == "admin": - settings_widgets.append(cl.input_widget.Switch(id="rag_enabled", label="Abilita RAG", initial=True)) + # 2. Badge HTML personalizzato + role_color = { + "admin": "#e74c3c", + "engineering": "#3498db", + "business": "#2ecc71", + "architecture": "#9b59b6", + }.get(profile["role"], "#95a5a6") - await cl.ChatSettings(settings_widgets).send() - - await cl.Message( - content=f"👋 Ciao **{profile['name']}**!\n" - f"Ruolo: `{profile['role']}` | Workspace: `{profile['workspace']}`\n" + badge_html = f""" +
+ 👤 {profile['name']} | 🔧 {profile['role'].upper()} | 📁 {profile['workspace']} +
+ """ + await cl.Message(content=badge_html).send() + + # 3. Settings UI + settings = await cl.ChatSettings( + [ + cl.input_widget.Slider( + id="top_k", + label="Numero Documenti RAG", + initial=4, + min=1, + max=10, + step=1, + ), + cl.input_widget.Select( + id="vision_detail", + label="Dettaglio Analisi Immagini", + values=["auto", "low", "high"], + initial_value="auto", + ), + cl.input_widget.TextInput( + id="system_instruction", + label="Istruzione Sistema Custom (opzionale)", + initial="", + placeholder="Es: Rispondi sempre in formato tecnico...", + ), + cl.input_widget.Select( + id="model", + label="Modello di Ragionamento", + values=[DEFAULT_TEXT_MODEL, "llama3.2", "mistral", "qwen2.5-coder:32b"], + initial_value=DEFAULT_TEXT_MODEL, + ), + cl.input_widget.Slider( + id="temperature", + label="Creatività (Temperatura)", + initial=0.3, + min=0, + max=1, + step=0.1, + ), + cl.input_widget.Switch( + id="rag_enabled", + label="Usa Conoscenza Documenti (RAG)", + initial=True, + ), + ] ).send() -@cl.on_settings_update -async def on_settings_update(settings): cl.user_session.set("settings", settings) - await cl.Message(content="✅ Impostazioni aggiornate").send() + + # 4. Messaggio iniziale (opzionale) + await cl.Message( + content=( + f"🚀 **Vision-RAG Hybrid System Online**\n" + f"Utente: {profile['name']} | Workspace: {profile['workspace']}\n" + f"Engine: Docling + BGE-M3 + {VISION_MODEL}" + ) + ).send() + + + cl.user_session.set("settings", settings) + + await cl.Message(f"🚀 **Vision-RAG Hybrid System Online**\nUtente: {profile['name']} | Workspace: {profile['workspace']}\nEngine: Docling + BGE-M3 + {VISION_MODEL}").send() + +@cl.on_settings_update +async def setup_agent(settings): + cl.user_session.set("settings", settings) + await cl.Message(content=f"✅ Impostazioni aggiornate: Modello {settings['model']}").send() + +async def log_metrics(metrics: dict): + # Versione minima: log su stdout + print("[METRICS]", metrics) + + # In futuro puoi: + # - salvarle in Postgres + # - mandarle a Prometheus / Grafana + # - scriverle su file JSON per analisi settimanale + +# - Resume Chat Handler + +@cl.on_chat_resume +async def on_chat_resume(thread: ThreadDict): + """ + Viene chiamato quando l'utente clicca 'Riprendi' su una chat archiviata. + Chainlit carica già i messaggi nella UI, qui puoi solo ripristinare la sessione. + """ + # Se vuoi, puoi recuperare l'identifier dell’utente dal thread + user_identifier = thread.get("userIdentifier") + profile = USER_PROFILES.get( + user_identifier, + USER_PROFILES["giuseppe@defranceschi.pro"], + ) + cl.user_session.set("profile", profile) + + # Puoi anche ripristinare eventuale stato custom (es: impostazioni di default) + # oppure semplicemente salutare l’utente + await cl.Message( + content="👋 Bentornato! Possiamo riprendere da questa conversazione." + ).send() @cl.on_message -async def on_message(message: cl.Message): - workspace = cl.user_session.get("workspace") - rag_collection = cl.user_session.get("rag_collection") - user_role = cl.user_session.get("role") - show_code = cl.user_session.get("show_code") - +async def main(message: cl.Message): + start_time = time.time() + + profile = cl.user_session.get("profile") settings = cl.user_session.get("settings", {}) - model = settings.get("model", "glm-4.6:cloud") - temperature = settings.get("temperature", 0.7) - rag_enabled = settings.get("rag_enabled", True) if user_role == "admin" else True + + selected_model = settings.get("model", DEFAULT_TEXT_MODEL) + temperature = settings.get("temperature", 0.3) + rag_enabled = settings.get("rag_enabled", True) + + workspace = create_workspace(profile["workspace"]) + + images_for_vision = [] + doc_context = "" + rag_context = "" # ← la inizializzi qui, così esiste sempre # 1. GESTIONE FILE if message.elements: for element in message.elements: - dest = os.path.join(WORKSPACES_DIR, workspace, element.name) - shutil.copy(element.path, dest) - if element.name.endswith(".pdf"): - text = extract_text_from_pdf(dest) - if text: - await index_document(element.name, text, rag_collection) - await cl.Message(content=f"✅ **{element.name}** indicizzato.").send() + file_path = os.path.join(workspace, element.name) + shutil.copy(element.path, file_path) + + if "image" in element.mime: + images_for_vision.append(file_path) + msg_img = cl.Message( + content=f"👁️ Analizzo immagine **{element.name}** con {VISION_MODEL}..." + ) + await msg_img.send() + + with open(file_path, "rb") as img_file: + img_bytes = img_file.read() + + client_sync = ollama.Client(host=OLLAMA_URL) + res = client_sync.chat( + model=VISION_MODEL, + messages=[{ + "role": "user", + "content": ( + "Analizza questa immagine tecnica. Trascrivi testi, codici " + "e descrivi diagrammi o tabelle in dettaglio." + ), + "images": [img_bytes], + }], + ) + desc = res["message"]["content"] + doc_context += f"\n\n[DESCRIZIONE IMMAGINE {element.name}]:\n{desc}" + msg_img.content = f"✅ Immagine analizzata:\n{desc[:200]}..." + await msg_img.update() + + elif element.name.endswith((".pdf", ".docx")): + msg_doc = cl.Message( + content=f"📄 Leggo **{element.name}** con Docling (tabelle/formule)..." + ) + await msg_doc.send() + + markdown_content = process_file_with_docling(file_path) + if markdown_content: + chunks = await index_document( + element.name, markdown_content, profile["rag_collection"] + ) + msg_doc.content = ( + f"✅ **{element.name}**: Convertito e salvato {chunks} " + "frammenti nel DB vettoriale." + ) + doc_context += ( + f"\n\n[CONTENUTO FILE {element.name}]:\n" + f"{markdown_content[:1000]}..." + ) + else: + msg_doc.content = f"❌ Errore lettura {element.name}" + await msg_doc.update() + + # 2. RAG RETRIEVAL + if rag_enabled and not images_for_vision: + rag_context = await search_hybrid( + message.content, profile["rag_collection"] + ) + + final_context = "" + if rag_context: + final_context += f"CONTESTO RAG:\n{rag_context}\n" + if doc_context: + final_context += f"CONTESTO SESSIONE CORRENTE:\n{doc_context}\n" + + system_prompt = ( + "Sei un assistente tecnico esperto. Usa il contesto fornito " + "(incluso Markdown di tabelle e descrizioni immagini) per " + "rispondere con precisione. Cita i documenti fonte." + ) - # 2. RAG - context = "" - if rag_enabled: - context = await search_qdrant(message.content, rag_collection) - - system_prompt = "Sei un assistente esperto." - if context: system_prompt += f"\n\nCONTESTO:\n{context}" - - # 3. GENERAZIONE - client = ollama.AsyncClient(host=OLLAMA_URL) msg = cl.Message(content="") await msg.send() - - stream = await client.chat( - model=model, - messages=[{"role": "system", "content": system_prompt}, {"role": "user", "content": message.content}], - options={"temperature": temperature}, - stream=True - ) - - full_resp = "" - async for chunk in stream: - token = chunk['message']['content'] - full_resp += token - await msg.stream_token(token) - await msg.update() + + error = None + + # 3. GENERAZIONE + try: + client_async = ollama.AsyncClient(host=OLLAMA_URL) + stream = await client_async.chat( + model=selected_model, + messages=[ + {"role": "system", "content": system_prompt}, + { + "role": "user", + "content": f"Domanda: {message.content}\n\n{final_context}", + }, + ], + options={"temperature": temperature}, + stream=True, + ) + + async for chunk in stream: + content = chunk["message"]["content"] + await msg.stream_token(content) + await msg.update() + except Exception as e: + error = str(e) + await msg.stream_token(f"❌ Errore AI: {error}") + await msg.update() # 4. SALVATAGGIO CODICE - if show_code: - blocks = re.findall(r"``````", full_resp, re.DOTALL) - elements = [] - for code in blocks: - path = save_code_to_file(code.strip(), workspace) - elements.append(cl.File(name=os.path.basename(path), path=path, display="inline")) - if elements: - await cl.Message(content="💾 Codice salvato", elements=elements).send() \ No newline at end of file + if profile["show_code"]: + code_blocks = re.findall(r"``````", msg.content, re.DOTALL) + if code_blocks: + for i, code in enumerate(code_blocks): + fname = f"script_{datetime.now().strftime('%H%M%S')}_{i}.py" + with open(os.path.join(workspace, fname), "w") as f: + f.write(code.strip()) + await cl.Message( + content=f"💾 Script salvato: `{fname}`" + ).send() + + # 5. METRICHE (ALLA FINE) + elapsed = time.time() - start_time + + # Se rag_context è una stringa concatenata, puoi stimare i "rag_hits" + # contando i separatori che usi in search_hybrid (es. '--- DA ') + if rag_context: + rag_hits = rag_context.count("--- DA ") + else: + rag_hits = 0 + + metrics = { + "response_time": elapsed, + "rag_hits": rag_hits, + "model": selected_model, + "user_role": profile["role"], + "error": error, + } + + await log_metrics(metrics) diff --git a/Marimo_Multi-User_Hub.md b/bck/Marimo_Multi-User_Hub.md similarity index 100% rename from Marimo_Multi-User_Hub.md rename to bck/Marimo_Multi-User_Hub.md diff --git a/PROMPT_V2.md b/bck/PROMPT_V2.md similarity index 100% rename from PROMPT_V2.md rename to bck/PROMPT_V2.md diff --git a/SPEC.md b/bck/SPEC.md similarity index 100% rename from SPEC.md rename to bck/SPEC.md diff --git a/bck/app-bck212.py b/bck/app-bck212.py new file mode 100644 index 00000000..230d6b51 --- /dev/null +++ b/bck/app-bck212.py @@ -0,0 +1,344 @@ +import os +import re +import uuid +import shutil +from datetime import datetime +from typing import Optional, Dict, List +import chainlit as cl +import ollama +import fitz # PyMuPDF +from qdrant_client import AsyncQdrantClient +from qdrant_client.models import PointStruct, Distance, VectorParams +from chainlit.data.sql_alchemy import SQLAlchemyDataLayer + +# === FIX IMPORT ROBUSTO === +# Gestisce le differenze tra le versioni di Chainlit 2.x +try: + from chainlit.data.storage_clients import BaseStorageClient +except ImportError: + try: + from chainlit.data.base import BaseStorageClient + except ImportError: + from chainlit.data.storage_clients.base import BaseStorageClient + +# === CONFIGURAZIONE === +DATABASE_URL = os.getenv("DATABASE_URL", "postgresql+asyncpg://ai_user:secure_password_here@postgres:5432/ai_station") +OLLAMA_URL = os.getenv("OLLAMA_URL", "http://192.168.1.243:11434") +QDRANT_URL = os.getenv("QDRANT_URL", "http://qdrant:6333") +WORKSPACES_DIR = "./workspaces" +STORAGE_DIR = "./.files" + +os.makedirs(STORAGE_DIR, exist_ok=True) +os.makedirs(WORKSPACES_DIR, exist_ok=True) + +# === MAPPING UTENTI E RUOLI === +USER_PROFILES = { + "giuseppe@defranceschi.pro": { + "role": "admin", + "name": "Giuseppe", + "workspace": "admin_workspace", + "rag_collection": "admin_docs", + "capabilities": ["debug", "system_prompts", "user_management", "all_models"], + "show_code": True + }, + "federica.tecchio@gmail.com": { + "role": "business", + "name": "Federica", + "workspace": "business_workspace", + "rag_collection": "contabilita", + "capabilities": ["pdf_upload", "basic_chat"], + "show_code": False + }, + "giuseppe.defranceschi@gmail.com": { + "role": "admin", + "name": "Giuseppe", + "workspace": "admin_workspace", + "rag_collection": "admin_docs", + "capabilities": ["debug", "system_prompts", "user_management", "all_models"], + "show_code": True + }, + "riccardob545@gmail.com": { + "role": "engineering", + "name": "Riccardo", + "workspace": "engineering_workspace", + "rag_collection": "engineering_docs", + "capabilities": ["code_execution", "data_viz", "advanced_chat"], + "show_code": True + }, + "giuliadefranceschi05@gmail.com": { + "role": "architecture", + "name": "Giulia", + "workspace": "architecture_workspace", + "rag_collection": "architecture_manuals", + "capabilities": ["visual_chat", "pdf_upload", "image_gen"], + "show_code": False + } +} + +# === CUSTOM LOCAL STORAGE CLIENT (FIXED) ===# Questa classe ora implementa tutti i metodi astratti richiesti da Chainlit 2.8.3 +class LocalStorageClient(BaseStorageClient): + """Storage locale su filesystem per file/elementi""" + + def __init__(self, storage_path: str): + self.storage_path = storage_path + os.makedirs(storage_path, exist_ok=True) + + async def upload_file( + self, + object_key: str, + data: bytes, + mime: str = "application/octet-stream", + overwrite: bool = True, + ) -> Dict[str, str]: + file_path = os.path.join(self.storage_path, object_key) + os.makedirs(os.path.dirname(file_path), exist_ok=True) + with open(file_path, "wb") as f: + f.write(data) + return {"object_key": object_key, "url": f"/files/{object_key}"} + + # Implementazione metodi obbligatori mancanti nella versione precedente + async def get_read_url(self, object_key: str) -> str: + return f"/files/{object_key}" + + async def delete_file(self, object_key: str) -> bool: + file_path = os.path.join(self.storage_path, object_key) + if os.path.exists(file_path): + os.remove(file_path) + return True + return False + + async def close(self): + pass + +# === DATA LAYER === +@cl.data_layer +def get_data_layer(): + return SQLAlchemyDataLayer( + conninfo=DATABASE_URL, + user_thread_limit=1000, + storage_provider=LocalStorageClient(storage_path=STORAGE_DIR) + ) + +# === OAUTH CALLBACK === +@cl.oauth_callback +def oauth_callback( + provider_id: str, + token: str, + raw_user_data: Dict[str, str], + default_user: cl.User, +) -> Optional[cl.User]: + if provider_id == "google": + email = raw_user_data.get("email", "").lower() + + # Verifica se utente è autorizzato (opzionale: blocca se non in lista) + # if email not in USER_PROFILES: + # return None + + # Recupera profilo o usa default Guest + profile = USER_PROFILES.get(email, get_user_profile("guest")) + + default_user.metadata.update({ + "picture": raw_user_data.get("picture", ""), + "role": profile["role"], + "workspace": profile["workspace"], + "rag_collection": profile["rag_collection"], + "capabilities": profile["capabilities"], + "show_code": profile["show_code"], + "display_name": profile["name"] + }) + return default_user + return default_user + +# === UTILITY FUNCTIONS === +def get_user_profile(user_email: str) -> Dict: + return USER_PROFILES.get(user_email.lower(), { + "role": "guest", + "name": "Ospite", + "workspace": "guest_workspace", + "rag_collection": "documents", + "capabilities": [], + "show_code": False + }) + +def create_workspace(workspace_name: str) -> str: + path = os.path.join(WORKSPACES_DIR, workspace_name) + os.makedirs(path, exist_ok=True) + return path + +def save_code_to_file(code: str, workspace: str) -> str: + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + file_name = f"code_{timestamp}.py" + file_path = os.path.join(WORKSPACES_DIR, workspace, file_name) + with open(file_path, "w", encoding="utf-8") as f: + f.write(code) + return file_path + +def extract_text_from_pdf(pdf_path: str) -> str: + try: + doc = fitz.open(pdf_path) + text = "\n".join([page.get_text() for page in doc]) + doc.close() + return text + except Exception: + return "" + +# === QDRANT FUNCTIONS === +async def get_qdrant_client() -> AsyncQdrantClient: + return AsyncQdrantClient(url=QDRANT_URL) + +async def ensure_collection(collection_name: str): + client = await get_qdrant_client() + if not await client.collection_exists(collection_name): + await client.create_collection( + collection_name=collection_name, + vectors_config=VectorParams(size=768, distance=Distance.COSINE) + ) + +async def get_embeddings(text: str) -> list: + client = ollama.Client(host=OLLAMA_URL) + try: + response = client.embed(model='nomic-embed-text', input=text[:2000]) + if 'embeddings' in response: return response['embeddings'][0] + return response.get('embedding', []) + except: return [] + +async def index_document(file_name: str, content: str, collection_name: str) -> bool: + try: + await ensure_collection(collection_name) + embedding = await get_embeddings(content) + if not embedding: return False + + qdrant = await get_qdrant_client() + await qdrant.upsert( + collection_name=collection_name, + points=[PointStruct( + id=str(uuid.uuid4()), + vector=embedding, + payload={"file_name": file_name, "content": content[:3000], "indexed_at": datetime.now().isoformat()} + )] + ) + return True + except: return False + +async def search_qdrant(query: str, collection: str) -> str: + try: + client = await get_qdrant_client() + if not await client.collection_exists(collection): return "" + emb = await get_embeddings(query) + if not emb: return "" + res = await client.query_points(collection_name=collection, query=emb, limit=3) + return "\n\n".join([hit.payload['content'] for hit in res.points if hit.payload]) + except: return "" + +# === CHAINLIT HANDLERS === + +@cl.on_chat_start +async def on_chat_start(): + user = cl.user_session.get("user") + + if not user: + # Fallback locale se non c'è auth + user_email = "guest@local" + profile = get_user_profile(user_email) + else: + user_email = user.identifier + # I metadati sono già popolati dalla callback oauth + profile = USER_PROFILES.get(user_email, get_user_profile("guest")) + + # Salva in sessione + cl.user_session.set("email", user_email) + cl.user_session.set("role", profile["role"]) + cl.user_session.set("workspace", profile["workspace"]) + cl.user_session.set("rag_collection", profile["rag_collection"]) + cl.user_session.set("show_code", profile["show_code"]) + + create_workspace(profile["workspace"]) + + # === SETTINGS WIDGETS === + settings_widgets = [ + cl.input_widget.Select( + id="model", + label="Modello AI", + values=["glm-4.6:cloud", "llama3.2", "mistral", "qwen2.5-coder:32b"], + initial_value="glm-4.6:cloud", + ), + cl.input_widget.Slider( + id="temperature", + label="Temperatura", + initial=0.7, min=0, max=2, step=0.1, + ), + ] + if profile["role"] == "admin": + settings_widgets.append(cl.input_widget.Switch(id="rag_enabled", label="Abilita RAG", initial=True)) + + await cl.ChatSettings(settings_widgets).send() + + await cl.Message( + content=f"👋 Ciao **{profile['name']}**!\n" + f"Ruolo: `{profile['role']}` | Workspace: `{profile['workspace']}`\n" + ).send() + +@cl.on_settings_update +async def on_settings_update(settings): + cl.user_session.set("settings", settings) + await cl.Message(content="✅ Impostazioni aggiornate").send() + +@cl.on_message +async def on_message(message: cl.Message): + workspace = cl.user_session.get("workspace") + rag_collection = cl.user_session.get("rag_collection") + user_role = cl.user_session.get("role") + show_code = cl.user_session.get("show_code") + + settings = cl.user_session.get("settings", {}) + model = settings.get("model", "glm-4.6:cloud") + temperature = settings.get("temperature", 0.7) + rag_enabled = settings.get("rag_enabled", True) if user_role == "admin" else True + + # 1. GESTIONE FILE + if message.elements: + for element in message.elements: + dest = os.path.join(WORKSPACES_DIR, workspace, element.name) + shutil.copy(element.path, dest) + if element.name.endswith(".pdf"): + text = extract_text_from_pdf(dest) + if text: + await index_document(element.name, text, rag_collection) + await cl.Message(content=f"✅ **{element.name}** indicizzato.").send() + + # 2. RAG + context = "" + if rag_enabled: + context = await search_qdrant(message.content, rag_collection) + + system_prompt = "Sei un assistente esperto." + if context: system_prompt += f"\n\nCONTESTO:\n{context}" + + # 3. GENERAZIONE + client = ollama.AsyncClient(host=OLLAMA_URL) + msg = cl.Message(content="") + await msg.send() + + stream = await client.chat( + model=model, + messages=[{"role": "system", "content": system_prompt}, {"role": "user", "content": message.content}], + options={"temperature": temperature}, + stream=True + ) + + full_resp = "" + async for chunk in stream: + token = chunk['message']['content'] + full_resp += token + await msg.stream_token(token) + await msg.update() + + # 4. SALVATAGGIO CODICE + if show_code: + blocks = re.findall(r"``````", full_resp, re.DOTALL) + elements = [] + for code in blocks: + path = save_code_to_file(code.strip(), workspace) + elements.append(cl.File(name=os.path.basename(path), path=path, display="inline")) + if elements: + await cl.Message(content="💾 Codice salvato", elements=elements).send() \ No newline at end of file diff --git a/app-final.py b/bck/app-final.py similarity index 100% rename from app-final.py rename to bck/app-final.py diff --git a/app-oauth2.py b/bck/app-oauth2.py similarity index 100% rename from app-oauth2.py rename to bck/app-oauth2.py diff --git a/app.py.backup b/bck/app.py.backup similarity index 100% rename from app.py.backup rename to bck/app.py.backup diff --git a/app.py.broken-082810 b/bck/app.py.broken-082810 similarity index 100% rename from app.py.broken-082810 rename to bck/app.py.broken-082810 diff --git a/app.py.broken-20251229-081214 b/bck/app.py.broken-20251229-081214 similarity index 100% rename from app.py.broken-20251229-081214 rename to bck/app.py.broken-20251229-081214 diff --git a/bck/cpu.txt b/bck/cpu.txt new file mode 100644 index 00000000..acc5b76d --- /dev/null +++ b/bck/cpu.txt @@ -0,0 +1,39 @@ +Architecture: x86_64 +CPU op-mode(s): 32-bit, 64-bit +Address sizes: 40 bits physical, 48 bits virtual +Byte Order: Little Endian +CPU(s): 16 +On-line CPU(s) list: 0-15 +Vendor ID: GenuineIntel +Model name: QEMU Virtual CPU version 2.5+ +CPU family: 15 +Model: 107 +Thread(s) per core: 1 +Core(s) per socket: 4 +Socket(s): 4 +Stepping: 1 +BogoMIPS: 4999.99 +Flags: fpu de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx lm constant_tsc nopl xtopology cpuid tsc_known_freq pni ssse3 cx16 sse4_1 sse4_2 x2apic popcnt aes hypervisor lahf_lm cpuid_fault pti +Hypervisor vendor: KVM +Virtualization type: full +L1d cache: 512 KiB (16 instances) +L1i cache: 512 KiB (16 instances) +L2 cache: 64 MiB (16 instances) +L3 cache: 64 MiB (4 instances) +NUMA node(s): 1 +NUMA node0 CPU(s): 0-15 +Vulnerability Gather data sampling: Not affected +Vulnerability Itlb multihit: KVM: Mitigation: VMX unsupported +Vulnerability L1tf: Mitigation; PTE Inversion +Vulnerability Mds: Vulnerable: Clear CPU buffers attempted, no microcode; SMT Host state unknown +Vulnerability Meltdown: Mitigation; PTI +Vulnerability Mmio stale data: Unknown: No mitigations +Vulnerability Reg file data sampling: Not affected +Vulnerability Retbleed: Not affected +Vulnerability Spec rstack overflow: Not affected +Vulnerability Spec store bypass: Vulnerable +Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization +Vulnerability Spectre v2: Mitigation; Retpolines; STIBP disabled; RSB filling; PBRSB-eIBRS Not affected; BHI Retpoline +Vulnerability Srbds: Not affected +Vulnerability Tsx async abort: Not affected +Vulnerability Vmscape: Not affected diff --git a/debugchainlit-app.txt b/bck/debugchainlit-app.txt similarity index 100% rename from debugchainlit-app.txt rename to bck/debugchainlit-app.txt diff --git a/debugchanlit-app.txt b/bck/debugchanlit-app.txt similarity index 100% rename from debugchanlit-app.txt rename to bck/debugchanlit-app.txt diff --git a/docker.logs b/bck/docker.logs similarity index 100% rename from docker.logs rename to bck/docker.logs diff --git a/dockerignore b/bck/dockerignore similarity index 100% rename from dockerignore rename to bck/dockerignore diff --git a/bck/error.log b/bck/error.log new file mode 100644 index 00000000..9de595d7 --- /dev/null +++ b/bck/error.log @@ -0,0 +1,717 @@ +ai-station-app | [INFO] 2025-12-31 10:20:23,724 [RapidOCR] download_file.py:82: Download size: 25.67MB +ai-station-app | [INFO] 2025-12-31 10:20:27,451 [RapidOCR] download_file.py:95: Successfully saved to: /usr/local/lib/python3.11/site-packages/rapidocr/models/ch_PP-OCRv4_rec_infer.pth +ai-station-app | [INFO] 2025-12-31 10:20:27,460 [RapidOCR] main.py:50: Using /usr/local/lib/python3.11/site-packages/rapidocr/models/ch_PP-OCRv4_rec_infer.pth +ai-station-app | 2025-12-31 10:20:28 - Auto OCR model selected rapidocr with torch. +ai-station-app | 2025-12-31 10:20:28 - Loading plugin 'docling_defaults' +ai-station-app | 2025-12-31 10:20:28 - Registered layout engines: ['docling_layout_default', 'docling_experimental_table_crops_layout'] +ai-station-app | 2025-12-31 10:20:28 - Accelerator device: 'cpu' +ai-station-app | 2025-12-31 10:20:59 - Loading plugin 'docling_defaults' +ai-station-app | 2025-12-31 10:20:59 - Registered table structure engines: ['docling_tableformer'] +ai-station-app | 2025-12-31 10:22:00 - Accelerator device: 'cpu' +ai-station-app | 2025-12-31 10:22:02 - Processing document esempio manuale Omron.pdf +ai-station-app | 2025-12-31 10:23:07 - Finished converting document esempio manuale Omron.pdf in 173.75 sec. +ai-station-app | 2025-12-31 10:23:07 - HTTP Request: GET http://qdrant:6333 "HTTP/1.1 200 OK" +ai-station-app | 2025-12-31 10:23:07 - An unexpected error occurred: +ai-station-app | 2025-12-31 10:23:07 - Translation file for it-IT not found. Using default translation en-US. +ai-station-qdrant | 2025-12-31T10:23:07.266024Z INFO actix_web::middleware::logger: 172.18.0.4 "GET /collections/admin_docs/exists HTTP/1.1" 200 69 "-" "python-client/1.16.2 python/3.11.14" 0.001423 +ai-station-app | 2025-12-31 10:23:07 - HTTP Request: GET http://qdrant:6333/collections/admin_docs/exists "HTTP/1.1 200 OK" +ai-station-qdrant | 2025-12-31T10:23:07.422109Z INFO storage::content_manager::toc::collection_meta_ops: Creating collection admin_docs +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | 2025-12-31 10:23:07 - Task exception was never retrieved +ai-station-app | future: exception=ValueError('Session not found')> +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/asyncio/tasks.py", line 277, in __step +ai-station-app | result = coro.send(None) +ai-station-app | ^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 607, in _handle_event_internal +ai-station-app | r = await server._trigger_event(data[0], namespace, sid, *data[1:]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/socketio/async_server.py", line 634, in _trigger_event +ai-station-app | ret = await handler(*args) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/socket.py", line 323, in window_message +ai-station-app | session = WebsocketSession.require(sid) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/session.py", line 354, in require +ai-station-app | raise ValueError("Session not found") +ai-station-app | ValueError: Session not found +ai-station-app | post request handler error +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/site-packages/engineio/async_server.py", line 306, in handle_request +ai-station-app | await socket.handle_post_request(environ) +ai-station-app | File "/usr/local/lib/python3.11/site-packages/engineio/async_socket.py", line 109, in handle_post_request +ai-station-app | p = payload.Payload(encoded_payload=body) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/engineio/payload.py", line 13, in __init__ +ai-station-app | self.decode(encoded_payload) +ai-station-app | File "/usr/local/lib/python3.11/site-packages/engineio/payload.py", line 44, in decode +ai-station-app | raise ValueError('Too many packets in payload') +ai-station-app | ValueError: Too many packets in payload +ai-station-app | 2025-12-31 10:23:07 - post request handler error +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/site-packages/engineio/async_server.py", line 306, in handle_request +ai-station-app | await socket.handle_post_request(environ) +ai-station-app | File "/usr/local/lib/python3.11/site-packages/engineio/async_socket.py", line 109, in handle_post_request +ai-station-app | p = payload.Payload(encoded_payload=body) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/engineio/payload.py", line 13, in __init__ +ai-station-app | self.decode(encoded_payload) +ai-station-app | File "/usr/local/lib/python3.11/site-packages/engineio/payload.py", line 44, in decode +ai-station-app | raise ValueError('Too many packets in payload') +ai-station-app | ValueError: Too many packets in payload +ai-station-qdrant | 2025-12-31T10:23:07.898915Z INFO actix_web::middleware::logger: 172.18.0.4 "PUT /collections/admin_docs HTTP/1.1" 200 57 "-" "python-client/1.16.2 python/3.11.14" 0.478796 +ai-station-app | 2025-12-31 10:23:07 - HTTP Request: PUT http://qdrant:6333/collections/admin_docs "HTTP/1.1 200 OK" +ai-station-app | 2025-12-31 10:23:08 - HTTP Request: GET http://qdrant:6333 "HTTP/1.1 200 OK" +ai-station-qdrant | 2025-12-31T10:23:12.256007Z INFO actix_web::middleware::logger: 172.18.0.4 "PUT /collections/admin_docs/points?wait=true HTTP/1.1" 200 84 "-" "python-client/1.16.2 python/3.11.14" 0.128378 +ai-station-app | 2025-12-31 10:23:12 - HTTP Request: PUT http://qdrant:6333/collections/admin_docs/points?wait=true "HTTP/1.1 200 OK" +ai-station-app | 2025-12-31 10:23:12 - HTTP Request: GET http://qdrant:6333 "HTTP/1.1 200 OK" +ai-station-qdrant | 2025-12-31T10:23:12.413564Z INFO actix_web::middleware::logger: 172.18.0.4 "GET /collections/admin_docs/exists HTTP/1.1" 200 68 "-" "python-client/1.16.2 python/3.11.14" 0.006418 +ai-station-app | 2025-12-31 10:23:12 - HTTP Request: GET http://qdrant:6333/collections/admin_docs/exists "HTTP/1.1 200 OK" +ai-station-app | 2025-12-31 10:23:12 - module 'chainlit.data' has no attribute 'qdrant_client' +ai-station-app | Traceback (most recent call last): +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/utils.py", line 57, in wrapper +ai-station-app | return await user_function(**params_values) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/usr/local/lib/python3.11/site-packages/chainlit/callbacks.py", line 161, in with_parent_id +ai-station-app | await func(message) +ai-station-app | File "/app/app.py", line 250, in main +ai-station-app | rag_context = await search_hybrid(message.content, profile["rag_collection"]) +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | File "/app/app.py", line 166, in search_hybrid +ai-station-app | cl.data.qdrant_client.models.Prefetch( +ai-station-app | ^^^^^^^^^^^^^^^^^^^^^ +ai-station-app | AttributeError: module 'chainlit.data' has no attribute 'qdrant_client' +ai-station-app | 2025-12-31 10:23:28 - Translation file for it-IT not found. Using default translation en-US. +ai-station-postgres | 2025-12-31 10:23:35.822 UTC [28] LOG: checkpoint starting: time +ai-station-postgres | 2025-12-31 10:23:37.312 UTC [28] LOG: checkpoint complete: wrote 17 buffers (0.1%); 0 WAL file(s) added, 0 removed, 0 recycled; write=1.428 s, sync=0.019 s, total=1.491 s; sync files=11, longest=0.009 s, average=0.002 s; distance=68 kB, estimate=68 kB +^C +giuseppe@ai-srv:~/ai-station$ \ No newline at end of file diff --git a/requirements-backup.txt b/bck/requirements-backup.txt similarity index 100% rename from requirements-backup.txt rename to bck/requirements-backup.txt diff --git a/requirements-oauth2.txt b/bck/requirements-oauth2.txt similarity index 100% rename from requirements-oauth2.txt rename to bck/requirements-oauth2.txt diff --git a/docker-compose.yml b/docker-compose.yml index c32439ea..3058954f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: chainlit-app: build: . @@ -12,7 +10,7 @@ services: - DATABASE_URL=postgresql+asyncpg://ai_user:secure_password_here@postgres:5432/ai_station - OLLAMA_URL=http://192.168.1.243:11434 - QDRANT_URL=http://qdrant:6333 - - BGE_API_URL=http://192.168.1.243:8001 + - BGE_API_URL=http://192.168.1.243:8001/embed volumes: - ./workspaces:/app/workspaces - ./public:/app/public # ⬅️ VERIFICA QUESTO diff --git a/error.log b/error.log deleted file mode 100644 index 5d66a3e8..00000000 --- a/error.log +++ /dev/null @@ -1,133 +0,0 @@ -qdrant-1 | _ _ -chainlit-app-1 | 2025-12-25 18:05:12 - INFO - chainlit - Your app is available at http://0.0.0.0:8000 -postgres-1 | -postgres-1 | PostgreSQL Database directory appears to contain a database; Skipping initialization -postgres-1 | -postgres-1 | 2025-12-25 16:38:01.071 UTC [1] LOG: starting PostgreSQL 18.1 (Debian 18.1-1.pgdg13+2) on x86_64-pc-linux-gnu, compiled by gcc (Debian 14.2.0-19) 14.2.0, 64-bit -qdrant-1 | __ _ __| |_ __ __ _ _ __ | |_ -qdrant-1 | / _` |/ _` | '__/ _` | '_ \| __| -qdrant-1 | | (_| | (_| | | | (_| | | | | |_ -qdrant-1 | \__, |\__,_|_| \__,_|_| |_|\__| -postgres-1 | 2025-12-25 16:38:01.072 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432 -postgres-1 | 2025-12-25 16:38:01.072 UTC [1] LOG: listening on IPv6 address "::", port 5432 -postgres-1 | 2025-12-25 16:38:01.093 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" -postgres-1 | 2025-12-25 16:38:01.126 UTC [32] LOG: database system was shut down at 2025-12-25 14:34:55 UTC -postgres-1 | 2025-12-25 16:38:01.155 UTC [1] LOG: database system is ready to accept connections -qdrant-1 | |_| -qdrant-1 | -qdrant-1 | Access web UI at https://ui.qdrant.tech/?v=v1.0.0 -qdrant-1 | -qdrant-1 | [2025-12-25T16:38:00.816Z INFO storage::content_manager::consensus::persistent] Initializing new raft state at ./storage/raft_state -qdrant-1 | [2025-12-25T16:38:00.861Z INFO qdrant] Distributed mode disabled -qdrant-1 | [2025-12-25T16:38:00.861Z INFO qdrant] Telemetry reporting enabled, id: e6113e43-627c-471d-8374-0f1b61799d76 -qdrant-1 | [2025-12-25T16:38:00.872Z INFO qdrant::tonic] Qdrant gRPC listening on 6334 -qdrant-1 | [2025-12-25T16:38:00.890Z INFO actix_server::builder] Starting 3 workers -qdrant-1 | [2025-12-25T16:38:00.890Z INFO actix_server::server] Actix runtime found; starting in Actix runtime -qdrant-1 | [2025-12-25T16:39:02.504Z INFO actix_server::server] SIGTERM received; starting graceful shutdown -qdrant-1 | [2025-12-25T16:39:02.505Z INFO actix_server::worker] Shutting down idle worker -qdrant-1 | [2025-12-25T16:39:02.508Z INFO actix_server::accept] Accept thread stopped -qdrant-1 | [2025-12-25T16:39:02.508Z INFO actix_server::worker] Shutting down idle worker -qdrant-1 | [2025-12-25T16:39:02.508Z INFO actix_server::worker] Shutting down idle worker -qdrant-1 | _ _ -qdrant-1 | __ _ __| |_ __ __ _ _ __ | |_ -qdrant-1 | / _` |/ _` | '__/ _` | '_ \| __| -qdrant-1 | | (_| | (_| | | | (_| | | | | |_ -postgres-1 | 2025-12-25 16:39:02.495 UTC [1] LOG: received fast shutdown request -postgres-1 | 2025-12-25 16:39:02.505 UTC [1] LOG: aborting any active transactions -postgres-1 | 2025-12-25 16:39:02.521 UTC [1] LOG: background worker "logical replication launcher" (PID 35) exited with exit code 1 -postgres-1 | 2025-12-25 16:39:02.521 UTC [30] LOG: shutting down -postgres-1 | 2025-12-25 16:39:02.533 UTC [30] LOG: checkpoint starting: shutdown immediate -chainlit-app-1 | 2025-12-25 18:05:25 - INFO - httpx - HTTP Request: GET http://qdrant:6333 "HTTP/1.1 200 OK" -chainlit-app-1 | /app/app.py:43: UserWarning: Qdrant client version 1.16.2 is incompatible with server version 1.0.0. Major versions should match and minor version difference must not exceed 1. Set check_compatibility=False to skip version check. -chainlit-app-1 | return QdrantClient(url=QDRANT_URL) -qdrant-1 | \__, |\__,_|_| \__,_|_| |_|\__| -chainlit-app-1 | 2025-12-25 18:05:25 - INFO - httpx - HTTP Request: GET http://qdrant:6333/collections/documents "HTTP/1.1 404 Not Found" -chainlit-app-1 | 2025-12-25 18:06:08 - WARNING - chainlit - Translation file for it-IT not found. Using parent translation it. -chainlit-app-1 | 2025-12-25 18:06:10 - WARNING - chainlit - Translation file for it-IT not found. Using parent translation it. -qdrant-1 | |_| -qdrant-1 | -qdrant-1 | Access web UI at https://ui.qdrant.tech/?v=v1.0.0 -qdrant-1 | -qdrant-1 | [2025-12-25T16:43:53.592Z INFO storage::content_manager::consensus::persistent] Loading raft state from ./storage/raft_state -qdrant-1 | [2025-12-25T16:43:53.612Z INFO qdrant] Distributed mode disabled -postgres-1 | 2025-12-25 16:39:02.601 UTC [30] LOG: checkpoint complete: wrote 0 buffers (0.0%), wrote 3 SLRU buffers; 0 WAL file(s) added, 0 removed, 0 recycled; write=0.019 s, sync=0.009 s, total=0.079 s; sync files=2, longest=0.005 s, average=0.005 s; distance=0 kB, estimate=0 kB; lsn=0/1BEF980, redo lsn=0/1BEF980 -postgres-1 | 2025-12-25 16:39:02.644 UTC [1] LOG: database system is shut down -postgres-1 | -postgres-1 | PostgreSQL Database directory appears to contain a database; Skipping initialization -postgres-1 | -postgres-1 | 2025-12-25 16:43:53.946 UTC [1] LOG: starting PostgreSQL 18.1 (Debian 18.1-1.pgdg13+2) on x86_64-pc-linux-gnu, compiled by gcc (Debian 14.2.0-19) 14.2.0, 64-bit -postgres-1 | 2025-12-25 16:43:53.947 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432 -postgres-1 | 2025-12-25 16:43:53.947 UTC [1] LOG: listening on IPv6 address "::", port 5432 -qdrant-1 | [2025-12-25T16:43:53.612Z INFO qdrant] Telemetry reporting enabled, id: 2a83356a-9770-47d3-a0bd-638f75769522 -qdrant-1 | [2025-12-25T16:43:53.615Z INFO qdrant::tonic] Qdrant gRPC listening on 6334 -qdrant-1 | [2025-12-25T16:43:53.616Z INFO actix_server::builder] Starting 3 workers -postgres-1 | 2025-12-25 16:43:53.965 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" -postgres-1 | 2025-12-25 16:43:53.990 UTC [32] LOG: database system was shut down at 2025-12-25 16:39:02 UTC -postgres-1 | 2025-12-25 16:43:54.013 UTC [1] LOG: database system is ready to accept connections -postgres-1 | 2025-12-25 16:48:54.089 UTC [30] LOG: checkpoint starting: time -postgres-1 | 2025-12-25 16:48:54.175 UTC [30] LOG: checkpoint complete: wrote 0 buffers (0.0%), wrote 3 SLRU buffers; 0 WAL file(s) added, 0 removed, 0 recycled; write=0.036 s, sync=0.009 s, total=0.088 s; sync files=2, longest=0.005 s, average=0.005 s; distance=0 kB, estimate=0 kB; lsn=0/1BEFA88, redo lsn=0/1BEFA30 -postgres-1 | 2025-12-25 16:56:42.002 UTC [1] LOG: received fast shutdown request -postgres-1 | 2025-12-25 16:56:42.018 UTC [1] LOG: aborting any active transactions -postgres-1 | 2025-12-25 16:56:42.026 UTC [1] LOG: background worker "logical replication launcher" (PID 35) exited with exit code 1 -postgres-1 | 2025-12-25 16:56:42.030 UTC [30] LOG: shutting down -postgres-1 | 2025-12-25 16:56:42.039 UTC [30] LOG: checkpoint starting: shutdown immediate -postgres-1 | 2025-12-25 16:56:42.086 UTC [30] LOG: checkpoint complete: wrote 0 buffers (0.0%), wrote 0 SLRU buffers; 0 WAL file(s) added, 0 removed, 0 recycled; write=0.004 s, sync=0.001 s, total=0.057 s; sync files=0, longest=0.000 s, average=0.000 s; distance=0 kB, estimate=0 kB; lsn=0/1BEFB38, redo lsn=0/1BEFB38 -postgres-1 | 2025-12-25 16:56:42.131 UTC [1] LOG: database system is shut down -postgres-1 | -postgres-1 | PostgreSQL Database directory appears to contain a database; Skipping initialization -postgres-1 | -chainlit-app-1 | 2025-12-25 18:06:10 - WARNING - chainlit - Translated markdown file for it-IT not found. Defaulting to chainlit.md. -chainlit-app-1 | 2025-12-25 18:06:13 - INFO - chainlit - Missing custom logo. Falling back to default logo. -chainlit-app-1 | 2025-12-25 18:06:21 - WARNING - chainlit - Translation file for it-IT not found. Using parent translation it. -chainlit-app-1 | 2025-12-25 18:06:21 - WARNING - chainlit - Translation file for it-IT not found. Using parent translation it. -qdrant-1 | [2025-12-25T16:43:53.617Z INFO actix_server::server] Actix runtime found; starting in Actix runtime -qdrant-1 | [2025-12-25T16:56:42.005Z INFO actix_server::server] SIGTERM received; starting graceful shutdown -qdrant-1 | [2025-12-25T16:56:42.006Z INFO actix_server::worker] Shutting down idle worker -qdrant-1 | [2025-12-25T16:56:42.006Z INFO actix_server::worker] Shutting down idle worker -qdrant-1 | [2025-12-25T16:56:42.007Z INFO actix_server::worker] Shutting down idle worker -qdrant-1 | [2025-12-25T16:56:42.007Z INFO actix_server::accept] Accept thread stopped -qdrant-1 | _ _ -qdrant-1 | __ _ __| |_ __ __ _ _ __ | |_ -qdrant-1 | / _` |/ _` | '__/ _` | '_ \| __| -qdrant-1 | | (_| | (_| | | | (_| | | | | |_ -qdrant-1 | \__, |\__,_|_| \__,_|_| |_|\__| -qdrant-1 | |_| -qdrant-1 | -qdrant-1 | Access web UI at https://ui.qdrant.tech/?v=v1.0.0 -qdrant-1 | -qdrant-1 | [2025-12-25T16:56:52.790Z INFO storage::content_manager::consensus::persistent] Loading raft state from ./storage/raft_state -qdrant-1 | [2025-12-25T16:56:52.796Z INFO qdrant] Distributed mode disabled -qdrant-1 | [2025-12-25T16:56:52.796Z INFO qdrant] Telemetry reporting enabled, id: f821b8ea-9ee5-497e-a172-dfebf253f7b1 -qdrant-1 | [2025-12-25T16:56:52.797Z INFO qdrant::tonic] Qdrant gRPC listening on 6334 -qdrant-1 | [2025-12-25T16:56:52.798Z INFO actix_server::builder] Starting 3 workers -qdrant-1 | [2025-12-25T16:56:52.798Z INFO actix_server::server] Actix runtime found; starting in Actix runtime -qdrant-1 | [2025-12-25T18:05:25.183Z INFO actix_web::middleware::logger] 172.18.0.4 "GET /collections/documents HTTP/1.1" 404 110 "-" "python-client/1.16.2 python/3.10.19" 0.007704 -qdrant-1 | [2025-12-25T18:05:30.499Z INFO actix_web::middleware::logger] 172.18.0.4 "PUT /collections/documents HTTP/1.1" 200 71 "-" "python-client/1.16.2 python/3.10.19" 5.311157 -qdrant-1 | [2025-12-25T18:06:22.662Z INFO actix_web::middleware::logger] 172.18.0.4 "GET /collections/documents HTTP/1.1" 200 413 "-" "python-client/1.16.2 python/3.10.19" 0.005606 -postgres-1 | 2025-12-25 16:56:43.530 UTC [1] LOG: starting PostgreSQL 18.1 (Debian 18.1-1.pgdg13+2) on x86_64-pc-linux-gnu, compiled by gcc (Debian 14.2.0-19) 14.2.0, 64-bit -postgres-1 | 2025-12-25 16:56:43.532 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432 -postgres-1 | 2025-12-25 16:56:43.532 UTC [1] LOG: listening on IPv6 address "::", port 5432 -postgres-1 | 2025-12-25 16:56:43.552 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" -postgres-1 | 2025-12-25 16:56:43.585 UTC [32] LOG: database system was shut down at 2025-12-25 16:56:42 UTC -postgres-1 | 2025-12-25 16:56:43.616 UTC [1] LOG: database system is ready to accept connections -postgres-1 | 2025-12-25 17:01:43.645 UTC [30] LOG: checkpoint starting: time -postgres-1 | 2025-12-25 17:01:43.712 UTC [30] LOG: checkpoint complete: wrote 0 buffers (0.0%), wrote 3 SLRU buffers; 0 WAL file(s) added, 0 removed, 0 recycled; write=0.019 s, sync=0.009 s, total=0.068 s; sync files=2, longest=0.005 s, average=0.005 s; distance=0 kB, estimate=0 kB; lsn=0/1BEFC40, redo lsn=0/1BEFBE8 -chainlit-app-1 | 2025-12-25 18:06:21 - WARNING - chainlit - Translated markdown file for it-IT not found. Defaulting to chainlit.md. -chainlit-app-1 | 2025-12-25 18:06:22 - INFO - httpx - HTTP Request: GET http://qdrant:6333 "HTTP/1.1 200 OK" -chainlit-app-1 | 2025-12-25 18:06:22 - INFO - httpx - HTTP Request: GET http://qdrant:6333/collections/documents "HTTP/1.1 200 OK" -chainlit-app-1 | 2025-12-25 18:06:28 - WARNING - chainlit - Translation file for it-IT not found. Using parent translation it. -chainlit-app-1 | 2025-12-25 18:06:36 - INFO - httpx - HTTP Request: GET http://qdrant:6333 "HTTP/1.1 200 OK" -chainlit-app-1 | 2025-12-25 18:06:37 - INFO - httpx - HTTP Request: POST http://192.168.1.243:11434/api/embed "HTTP/1.1 500 Internal Server Error" -chainlit-app-1 | 2025-12-25 18:06:39 - INFO - httpx - HTTP Request: POST http://192.168.1.243:11434/api/chat "HTTP/1.1 200 OK" -chainlit-app-1 | 2025-12-25 18:06:48 - WARNING - chainlit - Translation file for it-IT not found. Using parent translation it. -chainlit-app-1 | 2025-12-25 18:07:02 - WARNING - chainlit - Translation file for it-IT not found. Using parent translation it. -chainlit-app-1 | 2025-12-25 18:07:16 - INFO - httpx - HTTP Request: GET http://qdrant:6333 "HTTP/1.1 200 OK" -chainlit-app-1 | 2025-12-25 18:07:22 - INFO - httpx - HTTP Request: POST http://192.168.1.243:11434/api/embed "HTTP/1.1 500 Internal Server Error" -chainlit-app-1 | 2025-12-25 18:07:22 - INFO - httpx - HTTP Request: POST http://192.168.1.243:11434/api/chat "HTTP/1.1 200 OK" -chainlit-app-1 | 2025-12-25 18:07:49 - WARNING - chainlit - Translation file for it-IT not found. Using parent translation it. -chainlit-app-1 | 2025-12-25 18:07:54 - WARNING - chainlit - Translation file for it-IT not found. Using parent translation it. -chainlit-app-1 | 2025-12-25 18:08:15 - INFO - httpx - HTTP Request: POST http://192.168.1.243:11434/api/chat "HTTP/1.1 200 OK" -chainlit-app-1 | 2025-12-25 18:08:30 - WARNING - chainlit - Translation file for it-IT not found. Using parent translation it. -chainlit-app-1 | 2025-12-25 18:08:57 - INFO - httpx - HTTP Request: GET http://qdrant:6333 "HTTP/1.1 200 OK" -chainlit-app-1 | 2025-12-25 18:09:03 - INFO - httpx - HTTP Request: POST http://192.168.1.243:11434/api/embed "HTTP/1.1 500 Internal Server Error" -chainlit-app-1 | 2025-12-25 18:09:03 - INFO - httpx - HTTP Request: POST http://192.168.1.243:11434/api/chat "HTTP/1.1 200 OK" diff --git a/public/custom.css b/public/custom.css index 68d56a43..c3495381 100755 --- a/public/custom.css +++ b/public/custom.css @@ -1,36 +1,12 @@ -/* dFm AI Station - Perplexity Clean Style */ -:root { - --bg-color: #0B0F1A; - --card-color: #161B2C; - --accent-color: #6366F1; +.user-badge { + background: linear-gradient(45deg, #667eea 0%, #764ba2 100%); + padding: 4px 12px; + border-radius: 12px; + font-size: 0.85em; } -body { background-color: var(--bg-color) !important; color: #F1F5F9 !important; } - -/* Header e Logo */ -header { - background: rgba(11, 15, 26, 0.8) !important; - backdrop-filter: blur(8px); - border-bottom: 1px solid #23293F !important; -} - -/* Sidebar */ -.MuiDrawer-paper { - background-color: var(--bg-color) !important; - border-right: 1px solid #23293F !important; -} - -/* Messaggi */ -div[class*="user"] { - background: #1E253A !important; - border-radius: 12px !important; - border-left: 4px solid var(--accent-color) !important; -} - -/* Input Area */ -form { - background: var(--card-color) !important; - border-radius: 20px !important; - border: 1px solid #334155 !important; - box-shadow: 0 4px 20px rgba(0,0,0,0.5) !important; +/* Evidenzia codice */ +.message pre { + background: #2d2d2d; + border-left: 4px solid #0066CC; } diff --git a/requirements.txt b/requirements.txt index 0f574f8c..ee0742f3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -26,4 +26,7 @@ aiofiles>=23.0.0 sniffio aiohttp boto3>=1.28.0 -azure-storage-file-datalake>=12.14.0 \ No newline at end of file +azure-storage-file-datalake>=12.14.0 +docling +pillow +requests diff --git a/note command.txt b/script/note_command.txt similarity index 100% rename from note command.txt rename to script/note_command.txt diff --git a/script/test_vision.py b/script/test_vision.py new file mode 100644 index 00000000..7c94ff74 --- /dev/null +++ b/script/test_vision.py @@ -0,0 +1,23 @@ +import httpx +import base64 +import sys + +# Configurazione +OLLAMA_URL = "http://192.168.1.243:11434" +MODEL = "minicpm-v" + +print(f"👁️ Test Visione su {OLLAMA_URL} con modello {MODEL}...") + +# 1. Controlla se il modello è caricato +try: + r = httpx.get(f"{OLLAMA_URL}/api/tags") + models = [m['name'] for m in r.json()['models']] + if MODEL not in str(models): + print(f"❌ Errore: Il modello {MODEL} non è stato trovato su Ollama!") + sys.exit(1) + print(f"✅ Modello {MODEL} trovato.") +except Exception as e: + print(f"❌ Errore connessione Ollama: {e}") + sys.exit(1) + +print("🚀 Tutto pronto per l'implementazione!")