Ana2012 commited on
Commit
e9058d2
·
verified ·
1 Parent(s): 3d48d38

Update app/main.py

Browse files
Files changed (1) hide show
  1. app/main.py +250 -238
app/main.py CHANGED
@@ -1,238 +1,250 @@
1
- import os
2
- import threading
3
- from pathlib import Path
4
- from typing import Optional
5
-
6
- from fastapi import FastAPI, Query, Response
7
- from fastapi.middleware.cors import CORSMiddleware
8
- from fastapi.responses import FileResponse, HTMLResponse, RedirectResponse
9
- from pydantic import BaseModel
10
-
11
- from .agent import ShoppingAgent
12
- from .feedback import caminho_feedback, google_sheets_habilitado, salvar_feedback
13
- from .google_oauth import build_flow, get_authorization_url, load_credentials, save_credentials
14
- from .logger import salvar_log_busca
15
- from .memory import caminho_memoria_negativa
16
-
17
- EMBEDDING_PROVIDER = os.getenv("EMBEDDING_PROVIDER", "transformers").strip().lower()
18
- HF_MODEL_REPO = os.getenv("HF_MODEL_REPO", "Ana2012/bertimbau-buscador").strip()
19
-
20
-
21
- def _env_flag(name, default="true"):
22
- return os.getenv(name, default).strip().lower() in {"1", "true", "yes", "on"}
23
-
24
-
25
- PRELOAD_AGENT = _env_flag("PRELOAD_AGENT", "true")
26
- LOGS_DIR = os.getenv("LOGS_DIR", "/data/logs")
27
- DATA_DIR = "/data"
28
-
29
- app = FastAPI(title="TCC2 Agent API")
30
-
31
- app.add_middleware(
32
- CORSMiddleware,
33
- allow_origins=["*"],
34
- allow_credentials=False,
35
- allow_methods=["*"],
36
- allow_headers=["*"],
37
- )
38
-
39
- agent = None
40
- agent_lock = threading.Lock()
41
-
42
-
43
- def get_agent():
44
- global agent
45
- if agent is None:
46
- with agent_lock:
47
- if agent is None:
48
- agent = ShoppingAgent()
49
- return agent
50
-
51
-
52
- @app.on_event("startup")
53
- def preload_agent():
54
- if PRELOAD_AGENT:
55
- get_agent()
56
-
57
-
58
- class ChatRequest(BaseModel):
59
- query: Optional[str] = None
60
- message: Optional[str] = None
61
- top_k: int = 5
62
-
63
-
64
- class FeedbackRequest(BaseModel):
65
- query: str
66
- product_id: str
67
- product_name: str
68
- rating: Optional[int] = None
69
- is_helpful: Optional[bool] = None
70
- note: Optional[str] = None
71
- categoria_inferida: Optional[str] = None
72
- feedback: Optional[str] = None
73
- motivo: Optional[str] = None
74
- score_final: Optional[float] = None
75
- score_semantico: Optional[float] = None
76
- bonus_lexical: Optional[float] = None
77
- penalidade_feedback: Optional[float] = None
78
- user_message: Optional[str] = None
79
-
80
-
81
- @app.get("/health")
82
- def health():
83
- runtime = get_agent().runtime_info() if agent is not None else None
84
- return {
85
- "status": "ok",
86
- "agent_ready": agent is not None,
87
- "embedding_provider": EMBEDDING_PROVIDER,
88
- "model_repo": HF_MODEL_REPO,
89
- "preload_agent": PRELOAD_AGENT,
90
- "runtime": runtime,
91
- "feedback_storage": "google_sheets" if google_sheets_habilitado() else "csv",
92
- }
93
-
94
-
95
- @app.get("/", include_in_schema=False)
96
- def root():
97
- return RedirectResponse(url="/docs")
98
-
99
-
100
- @app.get("/favicon.ico", include_in_schema=False)
101
- def favicon():
102
- return Response(status_code=204)
103
-
104
-
105
- @app.get("/auth/google")
106
- def auth_google():
107
- authorization_url, _state = get_authorization_url()
108
- return RedirectResponse(url=authorization_url)
109
-
110
-
111
- @app.get("/oauth2callback")
112
- def oauth2callback(code: str = Query(...)):
113
- flow = build_flow()
114
- flow.fetch_token(code=code)
115
- save_credentials(flow.credentials)
116
- return HTMLResponse(
117
- "<h3>Autorizacao concluida. O backend ja pode salvar feedbacks no Google Sheets.</h3>"
118
- )
119
-
120
-
121
- @app.get("/auth/status")
122
- def auth_status():
123
- credentials = load_credentials()
124
- connected = credentials is not None and credentials.valid
125
- return {
126
- "google_sheets_connected": connected,
127
- "message": (
128
- "Google Sheets autorizado e pronto para uso."
129
- if connected
130
- else "Google Sheets ainda nao autorizado. Acesse /auth/google para conectar."
131
- ),
132
- }
133
-
134
-
135
- @app.get("/debug/files")
136
- def debug_files():
137
- data_path = Path(DATA_DIR)
138
- logs_path = Path(LOGS_DIR)
139
- feedback_path = Path(caminho_feedback())
140
- memory_path = Path(caminho_memoria_negativa())
141
-
142
- return {
143
- "data_exists": data_path.exists(),
144
- "logs_exists": logs_path.exists(),
145
- "feedback_exists": feedback_path.exists(),
146
- "negative_memory_exists": memory_path.exists(),
147
- "data_files": sorted(p.name for p in data_path.iterdir()) if data_path.exists() else [],
148
- "logs_files": sorted(p.name for p in logs_path.iterdir()) if logs_path.exists() else [],
149
- "feedback_file": str(feedback_path),
150
- "negative_memory_file": str(memory_path),
151
- "feedback_storage": "google_sheets" if google_sheets_habilitado() else "csv",
152
- }
153
-
154
-
155
- @app.get("/debug/feedback")
156
- def debug_feedback():
157
- feedback_path = Path(caminho_feedback())
158
- if not feedback_path.exists():
159
- return {"error": "arquivo nao existe"}
160
-
161
- return {"conteudo": feedback_path.read_text(encoding="utf-8")}
162
-
163
-
164
- @app.get("/download/feedback")
165
- def download_feedback():
166
- feedback_path = caminho_feedback()
167
- if not os.path.exists(feedback_path):
168
- return {"error": "arquivo nao existe"}
169
-
170
- return FileResponse(feedback_path, filename="feedback.csv")
171
-
172
-
173
- @app.get("/debug/memory")
174
- def debug_memory():
175
- memory_path = Path(caminho_memoria_negativa())
176
- if not memory_path.exists():
177
- return {"status": "missing", "file": str(memory_path)}
178
-
179
- return {
180
- "status": "ok",
181
- "file": str(memory_path),
182
- "content": memory_path.read_text(encoding="utf-8"),
183
- }
184
-
185
-
186
- @app.post("/chat")
187
- def chat(request: ChatRequest):
188
- texto = request.query or request.message
189
-
190
- if not texto:
191
- return {"error": "query ou message deve ser informado"}
192
-
193
- resultado = get_agent().responder(texto, top_k=request.top_k)
194
- salvar_log_busca(resultado)
195
- return resultado
196
-
197
-
198
- @app.post("/feedback")
199
- def feedback(request: FeedbackRequest):
200
- feedback_file = caminho_feedback()
201
- print(
202
- "Salvando feedback:",
203
- {
204
- "query": request.query,
205
- "product_id": request.product_id,
206
- "feedback_file": feedback_file,
207
- "logs_dir_exists": os.path.exists(LOGS_DIR),
208
- "google_sheets_enabled": google_sheets_habilitado(),
209
- },
210
- )
211
-
212
- try:
213
- return salvar_feedback(
214
- query=request.query,
215
- product_id=request.product_id,
216
- product_name=request.product_name,
217
- rating=request.rating,
218
- is_helpful=request.is_helpful,
219
- note=request.note,
220
- categoria_inferida=request.categoria_inferida,
221
- feedback=request.feedback,
222
- motivo=request.motivo,
223
- score_final=request.score_final,
224
- score_semantico=request.score_semantico,
225
- bonus_lexical=request.bonus_lexical,
226
- penalidade_feedback=request.penalidade_feedback,
227
- user_message=request.user_message,
228
- )
229
- except Exception as exc:
230
- return {
231
- "ok": False,
232
- "saved_local": False,
233
- "saved_google_sheets": False,
234
- "detail": str(exc),
235
- "feedback_file": feedback_file,
236
- "logs_dir_exists": os.path.exists(LOGS_DIR),
237
- "google_sheets_enabled": google_sheets_habilitado(),
238
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import threading
3
+ from pathlib import Path
4
+ from typing import Optional
5
+
6
+ from fastapi import FastAPI, Query, Response
7
+ from fastapi.middleware.cors import CORSMiddleware
8
+ from fastapi.responses import FileResponse, HTMLResponse, RedirectResponse
9
+ from pydantic import BaseModel
10
+ from app.google_oauth import build_flow, save_credentials
11
+
12
+
13
+ from .agent import ShoppingAgent
14
+ from .feedback import caminho_feedback, google_sheets_habilitado, salvar_feedback
15
+ from .google_oauth import build_flow, get_authorization_url, load_credentials, save_credentials
16
+ from .logger import salvar_log_busca
17
+ from .memory import caminho_memoria_negativa
18
+
19
+ EMBEDDING_PROVIDER = os.getenv("EMBEDDING_PROVIDER", "transformers").strip().lower()
20
+ HF_MODEL_REPO = os.getenv("HF_MODEL_REPO", "Ana2012/bertimbau-buscador").strip()
21
+
22
+
23
+ def _env_flag(name, default="true"):
24
+ return os.getenv(name, default).strip().lower() in {"1", "true", "yes", "on"}
25
+
26
+
27
+ PRELOAD_AGENT = _env_flag("PRELOAD_AGENT", "true")
28
+ LOGS_DIR = os.getenv("LOGS_DIR", "/data/logs")
29
+ DATA_DIR = "/data"
30
+
31
+ app = FastAPI(title="TCC2 Agent API")
32
+
33
+ app.add_middleware(
34
+ CORSMiddleware,
35
+ allow_origins=["*"],
36
+ allow_credentials=False,
37
+ allow_methods=["*"],
38
+ allow_headers=["*"],
39
+ )
40
+
41
+ agent = None
42
+ agent_lock = threading.Lock()
43
+
44
+
45
+ def get_agent():
46
+ global agent
47
+ if agent is None:
48
+ with agent_lock:
49
+ if agent is None:
50
+ agent = ShoppingAgent()
51
+ return agent
52
+
53
+
54
+ @app.on_event("startup")
55
+ def preload_agent():
56
+ if PRELOAD_AGENT:
57
+ get_agent()
58
+
59
+
60
+ class ChatRequest(BaseModel):
61
+ query: Optional[str] = None
62
+ message: Optional[str] = None
63
+ top_k: int = 5
64
+
65
+
66
+ class FeedbackRequest(BaseModel):
67
+ query: str
68
+ product_id: str
69
+ product_name: str
70
+ rating: Optional[int] = None
71
+ is_helpful: Optional[bool] = None
72
+ note: Optional[str] = None
73
+ categoria_inferida: Optional[str] = None
74
+ feedback: Optional[str] = None
75
+ motivo: Optional[str] = None
76
+ score_final: Optional[float] = None
77
+ score_semantico: Optional[float] = None
78
+ bonus_lexical: Optional[float] = None
79
+ penalidade_feedback: Optional[float] = None
80
+ user_message: Optional[str] = None
81
+
82
+
83
+ @app.get("/health")
84
+ def health():
85
+ runtime = get_agent().runtime_info() if agent is not None else None
86
+ return {
87
+ "status": "ok",
88
+ "agent_ready": agent is not None,
89
+ "embedding_provider": EMBEDDING_PROVIDER,
90
+ "model_repo": HF_MODEL_REPO,
91
+ "preload_agent": PRELOAD_AGENT,
92
+ "runtime": runtime,
93
+ "feedback_storage": "google_sheets" if google_sheets_habilitado() else "csv",
94
+ }
95
+
96
+
97
+ @app.get("/", include_in_schema=False)
98
+ def root():
99
+ return RedirectResponse(url="/docs")
100
+
101
+
102
+ @app.get("/favicon.ico", include_in_schema=False)
103
+ def favicon():
104
+ return Response(status_code=204)
105
+
106
+
107
+ @app.get("/auth/google")
108
+ def auth_google():
109
+ authorization_url, _state = get_authorization_url()
110
+ return RedirectResponse(url=authorization_url)
111
+
112
+
113
+ @app.get("/oauth2callback")
114
+ def oauth2callback(request: Request):
115
+ flow = build_flow()
116
+
117
+ code = request.query_params.get("code")
118
+
119
+ if not code:
120
+ return HTMLResponse("Erro: código OAuth não recebido.")
121
+
122
+ flow.fetch_token(code=code)
123
+
124
+ credentials = flow.credentials
125
+ save_credentials(credentials)
126
+
127
+ return HTMLResponse("""
128
+ <h2>✅ Google Sheets autorizado com sucesso!</h2>
129
+ <p>Agora o backend já pode salvar feedbacks na planilha.</p>
130
+ """)
131
+
132
+
133
+ @app.get("/auth/status")
134
+ def auth_status():
135
+ credentials = load_credentials()
136
+ connected = credentials is not None and credentials.valid
137
+ return {
138
+ "google_sheets_connected": connected,
139
+ "message": (
140
+ "Google Sheets autorizado e pronto para uso."
141
+ if connected
142
+ else "Google Sheets ainda nao autorizado. Acesse /auth/google para conectar."
143
+ ),
144
+ }
145
+
146
+
147
+ @app.get("/debug/files")
148
+ def debug_files():
149
+ data_path = Path(DATA_DIR)
150
+ logs_path = Path(LOGS_DIR)
151
+ feedback_path = Path(caminho_feedback())
152
+ memory_path = Path(caminho_memoria_negativa())
153
+
154
+ return {
155
+ "data_exists": data_path.exists(),
156
+ "logs_exists": logs_path.exists(),
157
+ "feedback_exists": feedback_path.exists(),
158
+ "negative_memory_exists": memory_path.exists(),
159
+ "data_files": sorted(p.name for p in data_path.iterdir()) if data_path.exists() else [],
160
+ "logs_files": sorted(p.name for p in logs_path.iterdir()) if logs_path.exists() else [],
161
+ "feedback_file": str(feedback_path),
162
+ "negative_memory_file": str(memory_path),
163
+ "feedback_storage": "google_sheets" if google_sheets_habilitado() else "csv",
164
+ }
165
+
166
+
167
+ @app.get("/debug/feedback")
168
+ def debug_feedback():
169
+ feedback_path = Path(caminho_feedback())
170
+ if not feedback_path.exists():
171
+ return {"error": "arquivo nao existe"}
172
+
173
+ return {"conteudo": feedback_path.read_text(encoding="utf-8")}
174
+
175
+
176
+ @app.get("/download/feedback")
177
+ def download_feedback():
178
+ feedback_path = caminho_feedback()
179
+ if not os.path.exists(feedback_path):
180
+ return {"error": "arquivo nao existe"}
181
+
182
+ return FileResponse(feedback_path, filename="feedback.csv")
183
+
184
+
185
+ @app.get("/debug/memory")
186
+ def debug_memory():
187
+ memory_path = Path(caminho_memoria_negativa())
188
+ if not memory_path.exists():
189
+ return {"status": "missing", "file": str(memory_path)}
190
+
191
+ return {
192
+ "status": "ok",
193
+ "file": str(memory_path),
194
+ "content": memory_path.read_text(encoding="utf-8"),
195
+ }
196
+
197
+
198
+ @app.post("/chat")
199
+ def chat(request: ChatRequest):
200
+ texto = request.query or request.message
201
+
202
+ if not texto:
203
+ return {"error": "query ou message deve ser informado"}
204
+
205
+ resultado = get_agent().responder(texto, top_k=request.top_k)
206
+ salvar_log_busca(resultado)
207
+ return resultado
208
+
209
+
210
+ @app.post("/feedback")
211
+ def feedback(request: FeedbackRequest):
212
+ feedback_file = caminho_feedback()
213
+ print(
214
+ "Salvando feedback:",
215
+ {
216
+ "query": request.query,
217
+ "product_id": request.product_id,
218
+ "feedback_file": feedback_file,
219
+ "logs_dir_exists": os.path.exists(LOGS_DIR),
220
+ "google_sheets_enabled": google_sheets_habilitado(),
221
+ },
222
+ )
223
+
224
+ try:
225
+ return salvar_feedback(
226
+ query=request.query,
227
+ product_id=request.product_id,
228
+ product_name=request.product_name,
229
+ rating=request.rating,
230
+ is_helpful=request.is_helpful,
231
+ note=request.note,
232
+ categoria_inferida=request.categoria_inferida,
233
+ feedback=request.feedback,
234
+ motivo=request.motivo,
235
+ score_final=request.score_final,
236
+ score_semantico=request.score_semantico,
237
+ bonus_lexical=request.bonus_lexical,
238
+ penalidade_feedback=request.penalidade_feedback,
239
+ user_message=request.user_message,
240
+ )
241
+ except Exception as exc:
242
+ return {
243
+ "ok": False,
244
+ "saved_local": False,
245
+ "saved_google_sheets": False,
246
+ "detail": str(exc),
247
+ "feedback_file": feedback_file,
248
+ "logs_dir_exists": os.path.exists(LOGS_DIR),
249
+ "google_sheets_enabled": google_sheets_habilitado(),
250
+ }