| | from fastapi import FastAPI, Depends, HTTPException, BackgroundTasks, File, UploadFile, Form, Query |
| | from fastapi.middleware.cors import CORSMiddleware |
| | from fastapi.responses import JSONResponse |
| | from fastapi.staticfiles import StaticFiles |
| | from pydantic import BaseModel |
| | from sqlalchemy.orm import Session |
| | from typing import List, Optional, Dict, Any |
| | import os |
| | import shutil |
| | import json |
| | from datetime import datetime |
| |
|
| | from app.db.database import get_db, engine |
| | from app.db.models import Base, ChatHistory, Document |
| | from app.agent import create_agent |
| | from app import document_processor |
| | from app import document_generator |
| |
|
| | |
| | Base.metadata.create_all(bind=engine) |
| |
|
| | |
| | app = FastAPI( |
| | title="Endüstri Chatbot API", |
| | description="Endüstriyel maliyet hesaplama için chatbot API", |
| | version="0.1.0" |
| | ) |
| |
|
| | |
| | app.add_middleware( |
| | CORSMiddleware, |
| | allow_origins=["*"], |
| | allow_credentials=True, |
| | allow_methods=["*"], |
| | allow_headers=["*"], |
| | ) |
| |
|
| | |
| | class ChatRequest(BaseModel): |
| | message: str |
| |
|
| | class ChatResponse(BaseModel): |
| | response: str |
| | |
| | class HealthResponse(BaseModel): |
| | status: str |
| | model_name: str |
| |
|
| | class DocumentResponse(BaseModel): |
| | id: int |
| | filename: str |
| | content_type: str |
| | file_size: int |
| | document_type: Optional[str] = None |
| | template_type: Optional[str] = None |
| | uploaded_at: datetime |
| | analyzed_at: Optional[datetime] = None |
| | analysis_summary: Optional[str] = None |
| |
|
| | class DocumentAnalysisResponse(BaseModel): |
| | id: int |
| | filename: str |
| | analysis_result: Dict[str, Any] |
| | analyzed_at: datetime |
| | |
| | class DocumentGenerateRequest(BaseModel): |
| | document_type: str |
| | template_type: str |
| | data: Dict[str, Any] |
| |
|
| | class DocumentGenerateResponse(BaseModel): |
| | id: int |
| | filename: str |
| | document_type: str |
| | template_type: str |
| | file_path: str |
| | file_size: int |
| | uploaded_at: datetime |
| |
|
| | |
| | def save_chat_history(db: Session, user_input: str, assistant_response: str): |
| | chat_entry = ChatHistory( |
| | user_input=user_input, |
| | assistant_response=assistant_response |
| | ) |
| | db.add(chat_entry) |
| | db.commit() |
| |
|
| | |
| | @app.get("/health", response_model=HealthResponse) |
| | def health_check(): |
| | return { |
| | "status": "ok", |
| | "model_name": os.getenv("MODEL_NAME", "bigscience/bloomz-560m") |
| | } |
| |
|
| | |
| | @app.post("/chat", response_model=ChatResponse) |
| | async def chat(request: ChatRequest, background_tasks: BackgroundTasks, db: Session = Depends(get_db)): |
| | try: |
| | |
| | agent_executor = create_agent(db) |
| | |
| | |
| | result = agent_executor.invoke({"input": request.message}) |
| | response = result["output"] |
| | |
| | |
| | background_tasks.add_task(save_chat_history, db, request.message, response) |
| | |
| | return {"response": response} |
| | except Exception as e: |
| | raise HTTPException(status_code=500, detail=f"Error processing request: {str(e)}") |
| |
|
| | |
| | @app.get("/chat/history", response_model=List[dict]) |
| | def get_chat_history(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)): |
| | history = db.query(ChatHistory).order_by(ChatHistory.created_at.desc()).offset(skip).limit(limit).all() |
| | return [{ |
| | "id": entry.id, |
| | "user_input": entry.user_input, |
| | "assistant_response": entry.assistant_response, |
| | "created_at": entry.created_at |
| | } for entry in history] |
| |
|
| | |
| | @app.post("/documents/upload", response_model=DocumentResponse) |
| | async def upload_document( |
| | file: UploadFile = File(...), |
| | analyze: bool = Form(False), |
| | db: Session = Depends(get_db) |
| | ): |
| | |
| | if file.content_type not in document_processor.SUPPORTED_CONTENT_TYPES: |
| | raise HTTPException( |
| | status_code=400, |
| | detail=f"Desteklenmeyen dosya türü: {file.content_type}. Desteklenen türler: {list(document_processor.SUPPORTED_CONTENT_TYPES.keys())}" |
| | ) |
| | |
| | try: |
| | |
| | filename = f"{datetime.now().strftime('%Y%m%d%H%M%S')}_{file.filename}" |
| | file_path = document_processor.save_uploaded_file(file, filename) |
| | file_size = os.path.getsize(file_path) |
| | |
| | |
| | content_text = None |
| | analysis_result = None |
| | |
| | if analyze: |
| | content_text = document_processor.process_document(file_path, file.content_type) |
| | if content_text: |
| | analysis_result = document_processor.analyze_document_content(content_text, db) |
| | |
| | |
| | document = document_processor.save_document_to_db( |
| | db, filename, file.content_type, file_path, file_size, content_text, analysis_result |
| | ) |
| | |
| | |
| | response = { |
| | "id": document.id, |
| | "filename": document.filename, |
| | "content_type": document.content_type, |
| | "file_size": document.file_size, |
| | "uploaded_at": document.uploaded_at, |
| | "analyzed_at": document.analyzed_at |
| | } |
| | |
| | if analysis_result: |
| | response["analysis_summary"] = "Belge analiz edildi. /documents/{id}/analysis endpoint'inden sonuçları görüntüleyebilirsiniz." |
| | |
| | return response |
| | |
| | except Exception as e: |
| | raise HTTPException(status_code=500, detail=f"Belge yükleme hatası: {str(e)}") |
| |
|
| | |
| | @app.post("/documents/{document_id}/analyze", response_model=DocumentAnalysisResponse) |
| | async def analyze_document( |
| | document_id: int, |
| | db: Session = Depends(get_db) |
| | ): |
| | |
| | document = db.query(Document).filter(Document.id == document_id).first() |
| | if not document: |
| | raise HTTPException(status_code=404, detail=f"Belge bulunamadı: {document_id}") |
| | |
| | try: |
| | |
| | if not document.content_text: |
| | document.content_text = document_processor.process_document(document.file_path, document.content_type) |
| | db.commit() |
| | |
| | |
| | analysis_result = document_processor.analyze_document_content(document.content_text, db) |
| | |
| | |
| | document.analysis_result = analysis_result |
| | document.analyzed_at = datetime.now() |
| | db.commit() |
| | |
| | |
| | return { |
| | "id": document.id, |
| | "filename": document.filename, |
| | "analysis_result": json.loads(document.analysis_result), |
| | "analyzed_at": document.analyzed_at |
| | } |
| | |
| | except Exception as e: |
| | raise HTTPException(status_code=500, detail=f"Belge analiz hatası: {str(e)}") |
| |
|
| | |
| | @app.get("/documents", response_model=List[DocumentResponse]) |
| | async def list_documents( |
| | skip: int = 0, |
| | limit: int = 10, |
| | db: Session = Depends(get_db) |
| | ): |
| | documents = db.query(Document).order_by(Document.uploaded_at.desc()).offset(skip).limit(limit).all() |
| | |
| | return [ |
| | { |
| | "id": doc.id, |
| | "filename": doc.filename, |
| | "content_type": doc.content_type, |
| | "file_size": doc.file_size, |
| | "uploaded_at": doc.uploaded_at, |
| | "analyzed_at": doc.analyzed_at, |
| | "analysis_summary": "Analiz sonuçları mevcut" if doc.analysis_result else None |
| | } |
| | for doc in documents |
| | ] |
| |
|
| | |
| | @app.get("/documents/{document_id}", response_model=DocumentResponse) |
| | async def get_document( |
| | document_id: int, |
| | db: Session = Depends(get_db) |
| | ): |
| | document = db.query(Document).filter(Document.id == document_id).first() |
| | if not document: |
| | raise HTTPException(status_code=404, detail=f"Belge bulunamadı: {document_id}") |
| | |
| | return { |
| | "id": document.id, |
| | "filename": document.filename, |
| | "content_type": document.content_type, |
| | "file_size": document.file_size, |
| | "uploaded_at": document.uploaded_at, |
| | "analyzed_at": document.analyzed_at, |
| | "analysis_summary": "Analiz sonuçları mevcut" if document.analysis_result else None |
| | } |
| |
|
| | |
| | @app.get("/documents/{document_id}/analysis", response_model=DocumentAnalysisResponse) |
| | async def get_document_analysis( |
| | document_id: int, |
| | db: Session = Depends(get_db) |
| | ): |
| | document = db.query(Document).filter(Document.id == document_id).first() |
| | if not document: |
| | raise HTTPException(status_code=404, detail=f"Belge bulunamadı: {document_id}") |
| | |
| | if not document.analysis_result: |
| | raise HTTPException(status_code=404, detail=f"Belge henüz analiz edilmemiş: {document_id}") |
| | |
| | return { |
| | "id": document.id, |
| | "filename": document.filename, |
| | "analysis_result": json.loads(document.analysis_result), |
| | "analyzed_at": document.analyzed_at |
| | } |
| |
|
| | |
| | @app.get("/") |
| | def read_root(): |
| | return {"message": "Endüstri Chatbot API'ye Hoş Geldiniz! /docs adresinden API dokümantasyonuna ulaşabilirsiniz."} |
| |
|
| | |
| | app.mount("/uploads", StaticFiles(directory="uploads"), name="uploads") |
| |
|
| | |
| | @app.post("/documents/generate", response_model=DocumentGenerateResponse) |
| | async def generate_document( |
| | request: DocumentGenerateRequest, |
| | db: Session = Depends(get_db) |
| | ): |
| | try: |
| | |
| | if request.document_type.lower() == 'word': |
| | file_path = document_generator.create_word_document(request.data, request.template_type) |
| | elif request.document_type.lower() == 'excel': |
| | file_path = document_generator.create_excel_document(request.data, request.template_type) |
| | else: |
| | raise HTTPException(status_code=400, detail=f"Desteklenmeyen doküman türü: {request.document_type}. Desteklenen türler: word, excel") |
| | |
| | |
| | file_size = os.path.getsize(file_path) |
| | |
| | |
| | filename = os.path.basename(file_path) |
| | |
| | |
| | content_type = "application/vnd.openxmlformats-officedocument.wordprocessingml.document" if request.document_type.lower() == 'word' else "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" |
| | |
| | |
| | document = document_generator.save_document_to_db( |
| | db, filename, content_type, file_path, file_size, |
| | request.document_type.lower(), request.template_type |
| | ) |
| | |
| | |
| | return { |
| | "id": document.id, |
| | "filename": document.filename, |
| | "document_type": document.document_type, |
| | "template_type": document.template_type, |
| | "file_path": document.file_path, |
| | "file_size": document.file_size, |
| | "uploaded_at": document.uploaded_at |
| | } |
| | |
| | except Exception as e: |
| | raise HTTPException(status_code=500, detail=f"Doküman oluşturma hatası: {str(e)}") |
| |
|
| | |
| | @app.get("/documents/templates") |
| | async def get_document_templates(): |
| | return { |
| | "templates": [ |
| | { |
| | "id": "maliyet_raporu", |
| | "name": "Maliyet Raporu", |
| | "description": "İşçilik ve malzeme maliyetlerini içeren detaylı maliyet raporu", |
| | "supported_formats": ["word", "excel"] |
| | }, |
| | { |
| | "id": "teklif", |
| | "name": "Teklif", |
| | "description": "Müşteriye sunulacak resmi teklif dokümanı", |
| | "supported_formats": ["word", "excel"] |
| | } |
| | ] |
| | } |
| |
|
| | |
| | if __name__ == "__main__": |
| | import uvicorn |
| | uvicorn.run("app.main:app", host="0.0.0.0", port=8000, reload=True) |