Skip to content
This repository was archived by the owner on Jun 7, 2025. It is now read-only.

Commit 80aaa5b

Browse files
authored
Merge pull request #22 from CodeHex16/fixes-bazzan-sprint15
2 parents 8ee0391 + dfe5240 commit 80aaa5b

20 files changed

Lines changed: 1216 additions & 495 deletions

app/config.py

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33

44

55
class Settings(BaseSettings):
6-
OPENAI_API_KEY: str = os.environ.get("OPENAI_API_KEY", "")
6+
OPENAI_API_KEY: str = os.environ.get("OPENAI_API_KEY")
77
DOCUMENTS_FOLDER: str = "documenti"
88
VECTOR_DB_PROVIDER: str = "chroma"
9-
VECTOR_DB_PERSIST_DIRECTORY: str = "chroma_db"
9+
VECTOR_DB_DIRECTORY: str = "chroma_db"
1010
EMBEDDING_MODEL_NAME: str = "text-embedding-ada-002"
1111
LLM_MODEL_NAME: str = "gpt-4o-mini"
1212
LLM_PROVIDER: str = "openai"
@@ -16,24 +16,11 @@ class Settings(BaseSettings):
1616
Missione:
1717
Assistere gli utenti nell'esplorazione dei prodotti forniti dall'azienda, informarli sulle caratteristiche del prodotto e consigliane l'acquisto.
1818
19-
Tratti della personalità:
20-
- Conoscenza: Fornisce risposte accurate dalla base di conoscenze.
21-
- Amichevole: cordiale e disponibile.
22-
- Trasparente: condivide solo informazioni convalidate.
23-
24-
Capacità:
25-
- Educare: Spiegare i prodotti presenti, consigliarne i possibili usi, la storia dell'azienda e i suoi valori utilizzando la base di conoscenze.
26-
- Assistere: Consigliare prodotti e fornire informazioni rigorosamente basate sui dati approvati.
27-
- Ispirare: evidenziare i vantaggi e gli usi di ogni prodotto.
28-
- Coinvolgere: Rispondere alle domande in modo chiaro ed educato, reindirizzando gli utenti al supporto se le risposte non sono disponibili.
29-
30-
Tono:
31-
- Positivo, professionale e privo di gergo.
32-
- Rispettoso ed empatico per garantire un'esperienza di supporto.
33-
3419
Regole comportamentali:
35-
- Utilizzare solo la base di conoscenze fornita.
20+
- È essenziale che tu usi il più possibile le informazioni fornite dai documenti passati come contesto.
3621
- Se una risposta non è disponibile, informare l'utente e suggerire di consultare l'assistenza clienti.
22+
- Sii chiaro ed elenca metodicamente le informazioni richieste.
23+
- Non esprimere opinioni personali o fare supposizioni.
3724
- Non fornire informazioni personali.
3825
"""
3926
CHUNK_SIZE: int = 400

app/main.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from fastapi import FastAPI
2-
from app.routes import llm
3-
from app.routes import documents
2+
from app.routes import llm, documents, faq
43

54
app = FastAPI(
65
title="LLM API",
@@ -10,3 +9,4 @@
109

1110
app.include_router(llm.router)
1211
app.include_router(documents.router)
12+
app.include_router(faq.router)

app/routes/documents.py

Lines changed: 40 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
from fastapi import APIRouter, Depends, HTTPException, File, UploadFile, Query
2-
from app.services.llm_service import LLM, OpenAI
1+
from fastapi import APIRouter, HTTPException, UploadFile, File, Form, Depends
32
from typing import List
43
import os
54

6-
# from app.services.chroma_services import embedding
75
from app.services.file_manager_service import (
86
get_file_manager,
97
get_file_manager_by_extension,
@@ -18,18 +16,17 @@
1816
)
1917

2018

21-
@router.post("/upload_file")
22-
async def upload_file(files: List[UploadFile] = File(...), token: str=Query(...)):
19+
@router.post("")
20+
async def upload_file(files: List[UploadFile], token: str):
2321
"""
24-
Carica il file nel database vettoriale
22+
Carica il file nel database vettoriale.
2523
26-
Args:
27-
- files (List[UploadFile]): I file da caricare. Devono essere file di testo o PDF.
24+
### Args:
25+
* **files (List[UploadFile])**: I file da caricare. Devono essere file di testo o PDF.
2826
29-
Raises:
30-
- HTTPException: Se il file non è valido o se si verifica un errore durante il caricamento.
31-
- HTTPException: Se il file esiste già nel database vettoriale.
32-
- HTTPException: Se si verifica un errore durante il caricamento e l'elaborazione del file.
27+
### Raises:
28+
* **HTTPException.400_BAD_REQUEST**: Se non sono stati forniti file o se i file non sono di tipo testo o PDF.
29+
* **HTTPException.500_INTERNAL_SERVER_ERROR**: Se si verifica un errore durante il caricamento dei file.
3330
"""
3431

3532
if not files:
@@ -97,59 +94,50 @@ async def upload_file(files: List[UploadFile] = File(...), token: str=Query(...)
9794
}
9895

9996

100-
@router.delete("/delete_file")
97+
@router.delete("")
10198
async def delete_file(fileDelete: schemas.DocumentDelete):
99+
"""
100+
Elimina un file dal database.
101+
102+
### Args:
103+
* **fileDelete (schemas.DocumentDelete)**: Il file da eliminare. Deve contenere il titolo, il token e la password corrente.
104+
105+
### Raises:
106+
* **HTTPException.400_BAD_REQUEST**: Se il file non esiste o se si verifica un errore durante l'eliminazione.
107+
* **HTTPException.500_INTERNAL_SERVER_ERROR**: Se si verifica un errore durante l'eliminazione del file.
108+
"""
102109
print("delete file title:", fileDelete)
103-
file_manager = get_file_manager_by_extension(fileDelete.title)
104-
if file_manager is None:
105-
raise HTTPException(status_code=400, detail="File manager not found")
106110
try:
111+
file_manager = get_file_manager_by_extension(fileDelete.title)
112+
if file_manager is None:
113+
raise HTTPException(status_code=400, detail="File manager not found")
114+
107115
file_path = file_manager.get_full_path(fileDelete.title)
108116
print("file path:", file_path)
109117
await file_manager.delete_document(
110118
fileDelete.id, file_path, fileDelete.token, fileDelete.current_password
111119
)
112-
except HTTPException as e:
113-
match e.status_code:
114-
case 404:
115-
print("error detail:", e.detail)
116-
raise HTTPException(
117-
status_code=404,
118-
detail="Document not found",
119-
)
120-
case 500:
121-
print("error detail:", e.detail)
122-
raise HTTPException(
123-
status_code=500,
124-
detail="Error in deleting file",
125-
)
126-
case _:
127-
print("error detail:", e.detail)
128-
raise HTTPException(
129-
status_code=500,
130-
detail="Error in deleting file",
131-
)
132120

121+
return {"message": "File deleted successfully"}
122+
except HTTPException as http_exc:
123+
raise http_exc
133124
except Exception as e:
134-
print("error detail:", e)
135-
raise HTTPException(
136-
status_code=500,
137-
detail="Error in deleting file",
138-
)
139-
140-
return {"message": "File deleted successfully"}
125+
raise HTTPException(status_code=500, detail=f"Error in deleting file: {str(e)}")
141126

142127

143-
@router.get("/get_documents")
128+
@router.get("")
144129
def get_documents():
145130
"""
146-
Ottiene la lista dei documenti dal database.
131+
Restituisce il numero di documenti e i loro nomi.
147132
148-
Args:
149-
- token (str): Il token di autenticazione dell'utente.
150-
151-
Raises:
152-
- HTTPException: Se si verifica un errore durante il recupero dei documenti.
133+
### Returns:
134+
* **int**: Il numero di documenti.
135+
* **List[str]**: I nomi dei documenti.
136+
* **List[str]**: I nomi dei file nella directory /data/documents.
153137
"""
154-
155-
return os.listdir("/data/documents")
138+
file_manager = get_file_manager()
139+
return (
140+
file_manager.get_documents_number(),
141+
file_manager.get_documents(),
142+
os.listdir("/data/documents"),
143+
)

app/routes/faq.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
from fastapi import APIRouter, HTTPException
2+
3+
from app.services.file_manager_service import (
4+
get_file_manager_by_extension,
5+
)
6+
7+
import app.schemas as schemas
8+
9+
10+
router = APIRouter(
11+
tags=["faqs"],
12+
prefix="/faqs",
13+
)
14+
15+
16+
@router.post("")
17+
async def create_faq(faq: schemas.FAQBase, token: str):
18+
"""
19+
Crea una nuova FAQ.
20+
21+
### Args:
22+
* **faq (schemas.FAQCreate)**: I dati della FAQ da creare.
23+
* **token (str)**: Il token di autenticazione.
24+
25+
### Raises:
26+
* **HTTPException.400_BAD_REQUEST**: Se non sono stati forniti dati per la creazione della FAQ.
27+
* **HTTPException.500_INTERNAL_SERVER_ERROR**: Se si verifica un errore durante la creazione della FAQ.
28+
"""
29+
if not faq:
30+
raise HTTPException(status_code=400, detail="No data provided for creation")
31+
32+
file_manager = get_file_manager_by_extension()
33+
if file_manager is None:
34+
raise HTTPException(status_code=500, detail="File manager not found")
35+
36+
faq_db = await file_manager.add_faq(faq, token)
37+
38+
return {"faq": faq_db, "message": "FAQ created successfully"}
39+
40+
41+
@router.delete("")
42+
async def delete_faq(faq: schemas.FAQDelete, token: str):
43+
"""
44+
Elimina una FAQ esistente.
45+
46+
### Args:
47+
* **faq (schemas.FAQDelete)**: I dati della FAQ da eliminare.
48+
49+
### Raises:
50+
* **HTTPException.400_BAD_REQUEST**: Se non sono stati forniti dati per l'eliminazione.
51+
* **HTTPException.404_NOT_FOUND**: Se la FAQ non esiste.
52+
* **HTTPException.500_INTERNAL_SERVER_ERROR**: Se si verifica un errore durante l'eliminazione della FAQ.
53+
"""
54+
if not faq:
55+
raise HTTPException(status_code=400, detail="No data provided for deletion")
56+
57+
file_manager = get_file_manager_by_extension()
58+
if file_manager is None:
59+
raise HTTPException(status_code=500, detail="File manager not found")
60+
61+
await file_manager.delete_faq(faq, token)
62+
return {"message": "FAQ deleted successfully"}
63+
64+
65+
@router.put("")
66+
async def update_faq(faq: schemas.FAQ, token: str):
67+
"""
68+
Aggiorna una FAQ esistente.
69+
70+
### Args:
71+
* **faq (schemas.FAQUpdate)**: I dati della FAQ da aggiornare.
72+
* **faq_id (str)**: L'ID della FAQ da aggiornare.
73+
74+
### Raises:
75+
* **HTTPException.400_BAD_REQUEST**: Se non sono stati forniti dati per l'aggiornamento.
76+
* **HTTPException.404_NOT_FOUND**: Se la FAQ non esiste.
77+
* **HTTPException.500_INTERNAL_SERVER_ERROR**: Se si verifica un errore durante l'aggiornamento della FAQ.
78+
"""
79+
if not faq:
80+
raise HTTPException(status_code=400, detail="No data provided for update")
81+
82+
file_manager = get_file_manager_by_extension()
83+
if file_manager is None:
84+
raise HTTPException(status_code=500, detail="File manager not found")
85+
86+
faq_db = await file_manager.update_faq(faq, token)
87+
return {"faq": faq_db, "message": "FAQ updated successfully"}

app/routes/llm.py

Lines changed: 22 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
from fastapi import APIRouter, Depends, HTTPException
2-
from app.services.llm_service import LLM, OpenAI
32

4-
# from app.services.chroma_services import embedding
5-
from app.services.vector_database_service import get_vector_database
63
from app.services.llm_response_service import LLMResponseService, get_llm_response_service
74

85
import app.schemas as schemas
@@ -19,48 +16,43 @@ async def generate_chat_response(
1916
"""
2017
Fornisce una risposta a una domanda utilizzando il contesto rilevante.
2118
22-
*Args*:
23-
question (schemas.Question): La domanda e lo storico dei messaggi.
24-
chat_service: Servizio di chat per generare risposte.
19+
### Args:
20+
* **question (schemas.Question)**: La domanda e lo storico dei messaggi.
2521
26-
*Returns*:
27-
La risposta generata dal modello LLM.
22+
### Returns:
23+
* **response**: La risposta generata dal modello LLM.
2824
29-
*Raises*:
30-
HTTPException: Se non viene fornita una domanda valida.
25+
### Raises:
26+
* **HTTPException.404_NOT_FOUND**: Se non viene trovato alcun contesto rilevante.
27+
* **HTTPException.400_BAD_REQUEST**: Se non viene fornita alcuna domanda.
28+
* **HTTPException.500_INTERNAL_SERVER_ERROR**: Se si verifica un errore interno del server.
3129
"""
3230
if not question.question or question.question.strip() == "":
3331
raise HTTPException(status_code=400, detail="Nessuna domanda fornita")
34-
32+
3533
return llm_response_service.generate_llm_response(question)
3634

3735

3836
@router.post("/chat_name")
3937
async def generate_chat_name(
40-
context: schemas.Context
38+
context: schemas.Context, llm_response_service: LLMResponseService = Depends(get_llm_response_service)
4139
):
42-
""" "
43-
Genera un nome per una chat.
40+
"""
41+
Genera un nome per la chat in base al contesto fornito.
42+
43+
### Args:
44+
* **context (schemas.Context)**: Il contesto della chat.
45+
46+
### Returns:
47+
* **response**: Il nome generato per la chat.
4448
45-
*Args*:
46-
context (schemas.Context): Il contesto della chat.
47-
*Returns*:
48-
str: Il nome generato per la chat.
49-
*Raises*:
50-
HTTPException: Se non viene fornito un contesto valido.
49+
### Raises:
50+
* **HTTPException.400_BAD_REQUEST**: Se non viene fornito alcun contesto.
51+
* **HTTPException.500_INTERNAL_SERVER_ERROR**: Se si verifica un errore interno del server.
5152
"""
5253
if not context.context:
5354
raise HTTPException(status_code=400, detail="Nessun contesto fornito")
5455

55-
llm_response_service = get_llm_response_service()
5656
return llm_response_service.generate_llm_chat_name(
5757
context.context
58-
)
59-
60-
61-
@router.get("/ping")
62-
async def ping():
63-
import requests
64-
65-
ris = requests.get("https://www.google.com")
66-
return {"status": "ok", "message": ris.text}
58+
)

0 commit comments

Comments
 (0)