feat: Agrega primera version de template (revisar archivo de documentacion - docs.md)
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.env
|
||||||
1
app/__init__.py
Normal file
1
app/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
BIN
app/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
app/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
app/__pycache__/main.cpython-312.pyc
Normal file
BIN
app/__pycache__/main.cpython-312.pyc
Normal file
Binary file not shown.
1
app/api/v1/__init__.py
Normal file
1
app/api/v1/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
"""API v1 package"""
|
||||||
BIN
app/api/v1/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
app/api/v1/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
app/api/v1/endpoints/__pycache__/router.cpython-312.pyc
Normal file
BIN
app/api/v1/endpoints/__pycache__/router.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
38
app/api/v1/endpoints/audio/transcription.py
Normal file
38
app/api/v1/endpoints/audio/transcription.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
"""
|
||||||
|
Gateway de IA de Qualidot - Módulo de Procesamiento de Audio
|
||||||
|
|
||||||
|
Propósito:
|
||||||
|
Este endpoint recibe un audio y lo convierte a texto usando inteligencia artificial.
|
||||||
|
|
||||||
|
Homologación:
|
||||||
|
Sin importar qué proveedor de IA se utilice, el resultado siempre se entrega en el mismo formato estándar para Qualidot.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from fastapi import APIRouter, Depends, UploadFile, File, HTTPException
|
||||||
|
from fastapi.security import APIKeyHeader
|
||||||
|
from app.api.v1.endpoints import router
|
||||||
|
from app.schemas.audio_standard import StandardTranscriptionResult, AudioRequestFile
|
||||||
|
from app.services.audio.transcription_adapters import transcribe_audio_with_provider
|
||||||
|
|
||||||
|
# Inicializar el router de FastAPI para este módulo
|
||||||
|
audio_router_transcription = APIRouter()
|
||||||
|
|
||||||
|
@audio_router_transcription.post("/transcripts/", response_model=StandardTranscriptionResult)
|
||||||
|
async def transcribe_audio(audio_request: AudioRequestFile = Depends()) -> StandardTranscriptionResult:
|
||||||
|
"""
|
||||||
|
Endpoint para transcribir audio simple infiriendo el proveedor de IA
|
||||||
|
|
||||||
|
Args:
|
||||||
|
audio_request: Objeto AudioRequestFile que contiene el archivo de audio,
|
||||||
|
el proveedor, el modelo y las opciones de diarización, marcas de tiempo y análisis de sentimiento.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
StandardTranscriptionResult: Resultado de la transcripción en formato estándar de Qualidot
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Transcribir usando el adaptador de transcripción que infiere el proveedor
|
||||||
|
transcription_result = await transcribe_audio_with_provider(audio_request)
|
||||||
|
return transcription_result
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
Binary file not shown.
39
app/api/v1/endpoints/image/rubricated_analysis.py
Normal file
39
app/api/v1/endpoints/image/rubricated_analysis.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
"""
|
||||||
|
Gateway de IA de Qualidot - Módulo de Procesamiento de Imágenes con una rubrica de análisis
|
||||||
|
|
||||||
|
Propósito:
|
||||||
|
Este endpoint recibe una imagen y la analiza usando una rúbrica de evaluación basada en inteligencia artificial.
|
||||||
|
|
||||||
|
Homologación:
|
||||||
|
Sin importar qué proveedor de IA se utilice, el resultado siempre se entrega en el mismo formato estándar para Qualidot.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from fastapi import APIRouter, Depends, UploadFile, File, HTTPException
|
||||||
|
from fastapi.security import APIKeyHeader
|
||||||
|
from app.api.v1.endpoints import router
|
||||||
|
from app.schemas.image_standard import StandardImageAnalysisResult, ImageRequestFile
|
||||||
|
|
||||||
|
from app.services.image.evaluations_adapters import evaluate_image_with_provider
|
||||||
|
|
||||||
|
# Inicializar el router de FastAPI para este módulo
|
||||||
|
image_router_analysis = APIRouter()
|
||||||
|
|
||||||
|
@image_router_analysis.post("/evaluations/", response_model=StandardImageAnalysisResult)
|
||||||
|
async def evaluate_image(image_request: ImageRequestFile = Depends()) -> StandardImageAnalysisResult:
|
||||||
|
"""
|
||||||
|
Endpoint para analizar imágenes usando una rúbrica de evaluación infiriendo el proveedor de IA
|
||||||
|
|
||||||
|
Args:
|
||||||
|
image_request: Objeto ImageRequestFile que contiene la imagen,
|
||||||
|
el proveedor, el modelo y las opciones de análisis.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
StandardImageAnalysisResult: Resultado del análisis de imágenes en formato estándar de Qualidot
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Analizar imagen usando el adaptador de análisis de imagen que infiere el proveedor
|
||||||
|
analysis_result = await evaluate_image_with_provider(image_request)
|
||||||
|
return analysis_result
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
61
app/api/v1/endpoints/router.py
Normal file
61
app/api/v1/endpoints/router.py
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
"""
|
||||||
|
Gateway de IA de Qualidot - Módulo maestro de endpoints de procesamiento.
|
||||||
|
|
||||||
|
Propósito:
|
||||||
|
Este módulo actúa como el punto central de enrutamiento para todos los
|
||||||
|
endpoints relacionados con el procesamiento de audio, imágenes,
|
||||||
|
documentos, video, etc.
|
||||||
|
|
||||||
|
Homologación:
|
||||||
|
Sin importar qué proveedor de IA se utilice, el resultado siempre se
|
||||||
|
entrega en el mismo formato estándar para Qualidot.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from fastapi import APIRouter, UploadFile, File, HTTPException
|
||||||
|
from fastapi.security import APIKeyHeader
|
||||||
|
|
||||||
|
# Importar los routers específicos de cada módulo
|
||||||
|
from app.api.v1.endpoints.audio.transcription import audio_router_transcription # Endpoint de transcripción de audio
|
||||||
|
from app.api.v1.endpoints.texto.resume import text_router_summary # Endpoint de resumen de texto
|
||||||
|
from app.api.v1.endpoints.texto.rubricated_analysis import text_router_analysis # Endpoint de análisis rubricado de texto
|
||||||
|
from app.api.v1.endpoints.video.transcription import video_router_transcription # Endpoint de transcripción de video
|
||||||
|
from app.api.v1.endpoints.image.rubricated_analysis import image_router_analysis # Endpoint de análisis rubricado de imágenes
|
||||||
|
|
||||||
|
# Inicializar el router de FastAPI para los módulos de procesamiento
|
||||||
|
api_router_audio = APIRouter()
|
||||||
|
api_router_text = APIRouter()
|
||||||
|
api_router_video = APIRouter()
|
||||||
|
api_router_image = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
api_router_audio.include_router(
|
||||||
|
audio_router_transcription,
|
||||||
|
prefix="/audio",
|
||||||
|
tags=["Procesamiento de Audio"]
|
||||||
|
)
|
||||||
|
|
||||||
|
api_router_text.include_router(
|
||||||
|
text_router_summary,
|
||||||
|
prefix="/text",
|
||||||
|
tags=["Procesamiento de Texto"]
|
||||||
|
)
|
||||||
|
|
||||||
|
api_router_text.include_router(
|
||||||
|
text_router_analysis,
|
||||||
|
prefix="/text",
|
||||||
|
tags=["Procesamiento de Texto"]
|
||||||
|
)
|
||||||
|
|
||||||
|
api_router_video.include_router(
|
||||||
|
video_router_transcription,
|
||||||
|
prefix="/video",
|
||||||
|
tags=["Procesamiento de Video"]
|
||||||
|
)
|
||||||
|
|
||||||
|
api_router_image.include_router(
|
||||||
|
image_router_analysis,
|
||||||
|
prefix="/image",
|
||||||
|
tags=["Procesamiento de Imágenes"]
|
||||||
|
)
|
||||||
BIN
app/api/v1/endpoints/texto/__pycache__/resume.cpython-312.pyc
Normal file
BIN
app/api/v1/endpoints/texto/__pycache__/resume.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
39
app/api/v1/endpoints/texto/resume.py
Normal file
39
app/api/v1/endpoints/texto/resume.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
"""
|
||||||
|
Gateway de IA de Qualidot - Módulo de Procesamiento de Texto para Resumen
|
||||||
|
|
||||||
|
Propósito:
|
||||||
|
Este endpoint recibe un texto y lo resume usando inteligencia artificial.
|
||||||
|
|
||||||
|
Homologación:
|
||||||
|
Sin importar qué proveedor de IA se utilice, el resultado siempre se entrega en el mismo formato estándar para Qualidot.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from fastapi import APIRouter, Depends, UploadFile, File, HTTPException
|
||||||
|
from fastapi.security import APIKeyHeader
|
||||||
|
from app.api.v1.endpoints import router
|
||||||
|
from app.schemas.text_standard import StandardTextAnalysisResult, TextRequestFile
|
||||||
|
#from app.services.transcription_adapters import transcribe_audio_with_provider
|
||||||
|
from app.services.text.resume_adapters import summarize_text_with_provider
|
||||||
|
|
||||||
|
# Inicializar el router de FastAPI para este módulo
|
||||||
|
text_router_summary = APIRouter()
|
||||||
|
|
||||||
|
@text_router_summary.post("/summaries/", response_model=StandardTextAnalysisResult)
|
||||||
|
async def summarize_text(text_request: TextRequestFile = Depends()) -> StandardTextAnalysisResult:
|
||||||
|
"""
|
||||||
|
Endpoint para resumir texto simple infiriendo el proveedor de IA
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text_request: Objeto TextRequestFile que contiene el archivo de texto,
|
||||||
|
el proveedor, el modelo y las opciones de diarización, marcas de tiempo y análisis de sentimiento.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
StandardTextAnalysisResult: Resultado del análisis de texto en formato estándar de Qualidot
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Resumir texto usando el adaptador de resumen de texto que infiere el proveedor
|
||||||
|
analysis_result = await summarize_text_with_provider(text_request)
|
||||||
|
return analysis_result
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
39
app/api/v1/endpoints/texto/rubricated_analysis.py
Normal file
39
app/api/v1/endpoints/texto/rubricated_analysis.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
"""
|
||||||
|
Gateway de IA de Qualidot - Módulo de Procesamiento de Texto para Análisis Rubricado
|
||||||
|
|
||||||
|
Propósito:
|
||||||
|
Este endpoint recibe un texto y lo analiza usando una rúbrica de evaluación basada en inteligencia artificial.
|
||||||
|
|
||||||
|
Homologación:
|
||||||
|
Sin importar qué proveedor de IA se utilice, el resultado siempre se entrega en el mismo formato estándar para Qualidot.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from fastapi import APIRouter, Depends, UploadFile, File, HTTPException
|
||||||
|
from fastapi.security import APIKeyHeader
|
||||||
|
from app.api.v1.endpoints import router
|
||||||
|
from app.schemas.text_standard import StandardTextAnalysisResult, TextRequestFile
|
||||||
|
#from app.services.transcription_adapters import transcribe_audio_with_provider
|
||||||
|
from app.services.text.evaluations_adapters import evaluate_text_with_provider
|
||||||
|
|
||||||
|
# Inicializar el router de FastAPI para este módulo
|
||||||
|
text_router_analysis = APIRouter()
|
||||||
|
|
||||||
|
@text_router_analysis.post("/evaluations/", response_model=StandardTextAnalysisResult)
|
||||||
|
async def evaluate_text(text_request: TextRequestFile = Depends()) -> StandardTextAnalysisResult:
|
||||||
|
"""
|
||||||
|
Endpoint para analizar texto usando una rúbrica de evaluación infiriendo el proveedor de IA
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text_request: Objeto TextRequestFile que contiene el archivo de texto,
|
||||||
|
el proveedor, el modelo y las opciones de diarización, marcas de tiempo y análisis de sentimiento.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
StandardTextAnalysisResult: Resultado del análisis de texto en formato estándar de Qualidot
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Analizar texto usando el adaptador de análisis de texto que infiere el proveedor
|
||||||
|
analysis_result = await evaluate_text_with_provider(text_request)
|
||||||
|
return analysis_result
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
Binary file not shown.
36
app/api/v1/endpoints/video/transcription.py
Normal file
36
app/api/v1/endpoints/video/transcription.py
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
"""
|
||||||
|
Gateway de IA de Qualidot - Módulo de Procesamiento de Videos
|
||||||
|
|
||||||
|
Propósito:
|
||||||
|
Este endpoint recibe un video y lo convierte a texto usando inteligencia artificial.
|
||||||
|
|
||||||
|
Homologación:
|
||||||
|
Sin importar qué proveedor de IA se utilice, el resultado siempre se entrega en el mismo formato estándar para Qualidot.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from fastapi import APIRouter, Depends, UploadFile, File, HTTPException
|
||||||
|
from app.schemas.video_standard import StandardTranscriptionResult, VideoRequestFile
|
||||||
|
from app.services.video.transcription_adapters import transcribe_video_with_provider
|
||||||
|
|
||||||
|
# Inicializar el router de FastAPI para este módulo
|
||||||
|
video_router_transcription = APIRouter()
|
||||||
|
|
||||||
|
@video_router_transcription.post("/transcripts/", response_model=StandardTranscriptionResult)
|
||||||
|
async def transcribe_video(video_request: VideoRequestFile = Depends()) -> StandardTranscriptionResult:
|
||||||
|
"""
|
||||||
|
Endpoint para transcribir video simple infiriendo el proveedor de IA
|
||||||
|
|
||||||
|
Args:
|
||||||
|
video_request: Objeto VideoRequestFile que contiene el archivo de video,
|
||||||
|
el proveedor, el modelo y las opciones de diarización, marcas de tiempo y análisis de sentimiento.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
StandardTranscriptionResult: Resultado de la transcripción en formato estándar de Qualidot
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Transcribir usando el adaptador de transcripción que infiere el proveedor
|
||||||
|
transcription_result = await transcribe_video_with_provider(video_request)
|
||||||
|
return transcription_result
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
BIN
app/core/__pycache__/config.cpython-312.pyc
Normal file
BIN
app/core/__pycache__/config.cpython-312.pyc
Normal file
Binary file not shown.
26
app/core/config.py
Normal file
26
app/core/config.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import os
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
class Settings:
|
||||||
|
# Configuración para las claves de API de los proveedores de IA
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------
|
||||||
|
# Proveedores de Audio
|
||||||
|
# ---------------------------------------------------------------
|
||||||
|
# OpenAI
|
||||||
|
OPENAI_API_KEY: str = os.getenv("OPENAI_API_KEY", "")
|
||||||
|
|
||||||
|
#AssemblyAI
|
||||||
|
ASSEMBLYAI_API_KEY: str = os.getenv("ASSEMBLYAI_API_KEY", "")
|
||||||
|
|
||||||
|
# Deepgram
|
||||||
|
DEEPGRAM_API_KEY: str = os.getenv("DEEPGRAM_API_KEY", "")
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------
|
||||||
|
# Proveedores de Imagen
|
||||||
|
# ---------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
settings = Settings()
|
||||||
60
app/main.py
Normal file
60
app/main.py
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
from fastapi import FastAPI
|
||||||
|
from app.api.v1.endpoints.router import api_router_audio, api_router_text, api_router_image, api_router_video
|
||||||
|
|
||||||
|
app = FastAPI(
|
||||||
|
title="Template de API de Procesamiento general",
|
||||||
|
description="Template de API para procesamiento de audio, imagenes, documento, video, etc",
|
||||||
|
version="1.0.0"
|
||||||
|
)
|
||||||
|
|
||||||
|
app.include_router(api_router_audio, prefix="/api/v1", tags=["Procesamiento de Audio"])
|
||||||
|
app.include_router(api_router_text, prefix="/api/v1", tags=["Procesamiento de Texto"])
|
||||||
|
app.include_router(api_router_image, prefix="/api/v1", tags=["Procesamiento de Imágenes"])
|
||||||
|
app.include_router(api_router_video, prefix="/api/v1", tags=["Procesamiento de Video"])
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
def root():
|
||||||
|
"""
|
||||||
|
Endpoint raíz para verificar que la API está corriendo y proporcionar información básica sobre los endpoints disponibles.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Un mensaje de bienvenida y un resumen de los endpoints disponibles en la API.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"message": "Template de API de Procesamiento general está corriendo con normalidad",
|
||||||
|
"docs": "/docs",
|
||||||
|
"endpoints": {
|
||||||
|
"audio": {
|
||||||
|
"transcripción de audio": "/api/v1/audio/transcripts/",
|
||||||
|
},
|
||||||
|
"texto": {
|
||||||
|
"resumen de texto": "/api/v1/text/summaries/",
|
||||||
|
"análisis rubricado": "/api/v1/text/evaluations/"
|
||||||
|
},
|
||||||
|
"imágenes": {
|
||||||
|
"análisis rubricado": "/api/v1/image/evaluations/",
|
||||||
|
},
|
||||||
|
"video": {
|
||||||
|
"transcripción de video": "/api/v1/video/transcripts/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"modelos_disponibles": {
|
||||||
|
"audio": {
|
||||||
|
"openai": [
|
||||||
|
"gpt-4o-transcribe",
|
||||||
|
"whisper-1"
|
||||||
|
],
|
||||||
|
"assemblyai": ["universal-3-pro", "universal-2"]
|
||||||
|
},
|
||||||
|
"texto": {
|
||||||
|
"pendiente de agregar proveedores y modelos específicos para procesamiento de texto"
|
||||||
|
},
|
||||||
|
"imágenes": {
|
||||||
|
"pendiente de agregar proveedores y modelos específicos para procesamiento de imágenes"
|
||||||
|
},
|
||||||
|
"video": {
|
||||||
|
"pendiente de agregar proveedores y modelos específicos para procesamiento de video"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
app/schemas/__pycache__/audio_standar.cpython-312.pyc
Normal file
BIN
app/schemas/__pycache__/audio_standar.cpython-312.pyc
Normal file
Binary file not shown.
BIN
app/schemas/__pycache__/audio_standard.cpython-312.pyc
Normal file
BIN
app/schemas/__pycache__/audio_standard.cpython-312.pyc
Normal file
Binary file not shown.
BIN
app/schemas/__pycache__/image_standard.cpython-312.pyc
Normal file
BIN
app/schemas/__pycache__/image_standard.cpython-312.pyc
Normal file
Binary file not shown.
BIN
app/schemas/__pycache__/text_standard.cpython-312.pyc
Normal file
BIN
app/schemas/__pycache__/text_standard.cpython-312.pyc
Normal file
Binary file not shown.
BIN
app/schemas/__pycache__/video_standard.cpython-312.pyc
Normal file
BIN
app/schemas/__pycache__/video_standard.cpython-312.pyc
Normal file
Binary file not shown.
92
app/schemas/audio_standard.py
Normal file
92
app/schemas/audio_standard.py
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
"""
|
||||||
|
Esquema de resultado esperado de modelos de transcripción.
|
||||||
|
|
||||||
|
Propósito:
|
||||||
|
Define el formato estándar de los resultados devueltos por los modelos de transcripción
|
||||||
|
de audio, independientemente del proveedor de IA utilizado.
|
||||||
|
|
||||||
|
Homologación:
|
||||||
|
Garantiza que el resultado de la transcripción siempre se entregue en el mismo
|
||||||
|
formato estándar para Qualidot.
|
||||||
|
|
||||||
|
Pendiente (recomendación personal):
|
||||||
|
- Definir mejor la estructura de cada segmento según las opciones avanzadas (diarization, timestamps, sentiment)
|
||||||
|
- Delimitar los proveedores de IA soportados inicialmente
|
||||||
|
"""
|
||||||
|
|
||||||
|
from fastapi import UploadFile
|
||||||
|
from fastapi.params import File, Form
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
class AudioRequestFile:
|
||||||
|
"""Modelo de solicitud para transcripción de audio."""
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
file: UploadFile = File(..., description="Archivo de audio a procesar (ej. mp3, wav)"),
|
||||||
|
provider: str = Form(..., description="Proveedor de IA a utilizar (ej. openai, assemblyai)"),
|
||||||
|
model: str = Form(..., description="Modelo de IA a utilizar (ej. whisper-1)"),
|
||||||
|
diarization: Optional[bool] = Form(False, description="Activa la separación e identificación de múltiples hablantes"),
|
||||||
|
timestamps: Optional[bool] = Form(False, description="Activa las marcas de tiempo exactas por cada segmento hablado"),
|
||||||
|
sentiment: Optional[bool] = Form(False, description="Activa el análisis de sentimiento (POSITIVO/NEGATIVO) por segmento")
|
||||||
|
):
|
||||||
|
self.file = file
|
||||||
|
self.provider = provider
|
||||||
|
self.model = model
|
||||||
|
self.diarization = diarization
|
||||||
|
self.timestamps = timestamps
|
||||||
|
self.sentiment = sentiment
|
||||||
|
|
||||||
|
class TranscriptionSegment(BaseModel):
|
||||||
|
"""Modelo que representa un segmento de transcripción de audio detallado."""
|
||||||
|
text: str = Field(
|
||||||
|
...,
|
||||||
|
description="Texto transcrito en este fragmento específico"
|
||||||
|
)
|
||||||
|
speaker: Optional[str] = Field(
|
||||||
|
None,
|
||||||
|
description="Identificador del hablante (ej. 'Speaker A') si diarization está activo"
|
||||||
|
)
|
||||||
|
start_time: Optional[float] = Field(
|
||||||
|
None,
|
||||||
|
description="Marca de tiempo en segundos donde inicia el segmento"
|
||||||
|
)
|
||||||
|
end_time: Optional[float] = Field(
|
||||||
|
None,
|
||||||
|
description="Marca de tiempo en segundos donde termina el segmento"
|
||||||
|
)
|
||||||
|
sentiment: Optional[str] = Field(
|
||||||
|
None,
|
||||||
|
description="Sentimiento detectado en el segmento (ej. 'POSITIVE', 'NEGATIVE')"
|
||||||
|
)
|
||||||
|
|
||||||
|
class StandardTranscriptionResult(BaseModel):
|
||||||
|
"""Modelo que representa el resultado estándar de una transcripción de audio para Qualidot."""
|
||||||
|
status: str = Field(
|
||||||
|
...,
|
||||||
|
description="Estado final de la petición ('success' o 'error')"
|
||||||
|
)
|
||||||
|
original_filename: str = Field(
|
||||||
|
...,
|
||||||
|
description="Nombre original del archivo de audio procesado"
|
||||||
|
)
|
||||||
|
provider_used: str = Field(
|
||||||
|
...,
|
||||||
|
description="Proveedor de IA que ejecutó la transcripción (ej. OpenAI)"
|
||||||
|
)
|
||||||
|
model_used: str = Field(
|
||||||
|
...,
|
||||||
|
description="Modelo específico utilizado para el proceso"
|
||||||
|
)
|
||||||
|
full_transcript: Optional[str] = Field(
|
||||||
|
None,
|
||||||
|
description="Texto completo y continuo de toda la transcripción"
|
||||||
|
)
|
||||||
|
segments: Optional[List[TranscriptionSegment]] = Field(
|
||||||
|
None,
|
||||||
|
description="Lista detallada de segmentos si se solicitaron opciones avanzadas (diarization, timestamps, sentiment)"
|
||||||
|
)
|
||||||
|
confidence_score: Optional[float] = Field(
|
||||||
|
None,
|
||||||
|
description="Nivel de certeza global del modelo (valor entre 0.0 y 1.0)"
|
||||||
|
)
|
||||||
44
app/schemas/image_standard.py
Normal file
44
app/schemas/image_standard.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
"""
|
||||||
|
Esquema de resultado esperado de modelos de análisis de imágenes.
|
||||||
|
|
||||||
|
Propósito:
|
||||||
|
Define el formato estándar de los resultados devueltos por los modelos de análisis
|
||||||
|
de imágenes, independientemente del proveedor de IA utilizado.
|
||||||
|
|
||||||
|
Homologación:
|
||||||
|
Garantiza que el resultado del análisis de imágenes siempre se entregue en el mismo
|
||||||
|
formato estándar para Qualidot.
|
||||||
|
"""
|
||||||
|
from fastapi import UploadFile
|
||||||
|
from fastapi.params import File, Form
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
class ImageRequestFile:
|
||||||
|
"""Modelo de solicitud para análisis de imágenes."""
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
file: UploadFile = File(..., description="Archivo de imagen a procesar (ej. jpg, png)"),
|
||||||
|
provider: str = Form(..., description="Proveedor de IA a utilizar (ej. openai, google)"),
|
||||||
|
model: str = Form(..., description="Modelo de IA a utilizar (ej. vision-1)"),
|
||||||
|
rubric: Optional[str] = Form(None, description="Rúbrica de evaluación personalizada para el análisis")
|
||||||
|
):
|
||||||
|
self.file = file
|
||||||
|
self.provider = provider
|
||||||
|
self.model = model
|
||||||
|
self.rubric = rubric
|
||||||
|
|
||||||
|
class StandardImageAnalysisResult(BaseModel):
|
||||||
|
"""Modelo que representa el resultado estándar de un análisis de imágenes para Qualidot."""
|
||||||
|
status: str = Field(
|
||||||
|
...,
|
||||||
|
description="Estado del análisis (ej. 'success', 'error')"
|
||||||
|
)
|
||||||
|
analysis: Optional[dict] = Field(
|
||||||
|
None,
|
||||||
|
description="Resultados detallados del análisis de la imagen, estructurados según la rúbrica si se proporcionó"
|
||||||
|
)
|
||||||
|
error: Optional[str] = Field(
|
||||||
|
None,
|
||||||
|
description="Mensaje de error en caso de que el análisis haya fallado"
|
||||||
|
)
|
||||||
44
app/schemas/text_standard.py
Normal file
44
app/schemas/text_standard.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
"""
|
||||||
|
Esquema de resultado esperado de modelos de análisis de texto (JSON).
|
||||||
|
|
||||||
|
Propósito:
|
||||||
|
Define el formato estándar de los resultados devueltos por los modelos de análisis
|
||||||
|
de texto, independientemente del proveedor de IA utilizado.
|
||||||
|
|
||||||
|
Homologación:
|
||||||
|
Garantiza que el resultado del análisis de texto siempre se entregue en el mismo
|
||||||
|
formato estándar para Qualidot.
|
||||||
|
"""
|
||||||
|
from fastapi import UploadFile
|
||||||
|
from fastapi.params import File, Form
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
class TextRequestFile:
|
||||||
|
"""Modelo de solicitud para análisis de texto."""
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
file: UploadFile = File(..., description="Archivo de texto a procesar (ej. txt, json)"),
|
||||||
|
provider: str = Form(..., description="Proveedor de IA a utilizar (ej. openai, google)"),
|
||||||
|
model: str = Form(..., description="Modelo de IA a utilizar (ej. text-1)"),
|
||||||
|
rubric: Optional[str] = Form(None, description="Rúbrica de evaluación personalizada para el análisis")
|
||||||
|
):
|
||||||
|
self.file = file
|
||||||
|
self.provider = provider
|
||||||
|
self.model = model
|
||||||
|
self.rubric = rubric
|
||||||
|
|
||||||
|
class StandardTextAnalysisResult(BaseModel):
|
||||||
|
"""Modelo que representa el resultado estándar de un análisis de texto para Qualidot."""
|
||||||
|
status: str = Field(
|
||||||
|
...,
|
||||||
|
description="Estado del análisis (ej. 'success', 'error')"
|
||||||
|
)
|
||||||
|
analysis: Optional[dict] = Field(
|
||||||
|
None,
|
||||||
|
description="Resultados detallados del análisis de texto, estructurados según la rúbrica si se proporcionó"
|
||||||
|
)
|
||||||
|
error: Optional[str] = Field(
|
||||||
|
None,
|
||||||
|
description="Mensaje de error en caso de que el análisis haya fallado"
|
||||||
|
)
|
||||||
65
app/schemas/video_standard.py
Normal file
65
app/schemas/video_standard.py
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
"""
|
||||||
|
Esquema de resultado esperado de modelos de transcripción de video.
|
||||||
|
|
||||||
|
Propósito:
|
||||||
|
Define el formato estándar de los resultados devueltos por los modelos de transcripción
|
||||||
|
de video, independientemente del proveedor de IA utilizado.
|
||||||
|
|
||||||
|
Homologación:
|
||||||
|
Garantiza que el resultado de la transcripción siempre se entregue en el mismo
|
||||||
|
formato estándar para Qualidot.
|
||||||
|
"""
|
||||||
|
from fastapi import UploadFile
|
||||||
|
from fastapi.params import File, Form
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
class VideoRequestFile:
|
||||||
|
"""Modelo de solicitud para transcripción de video."""
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
file: UploadFile = File(..., description="Archivo de video a procesar (ej. mp4, mov)"),
|
||||||
|
provider: str = Form(..., description="Proveedor de IA a utilizar (ej. openai, assemblyai)"),
|
||||||
|
model: str = Form(..., description="Modelo de IA a utilizar (ej. whisper-1)"),
|
||||||
|
diarization: Optional[bool] = Form(False, description="Activa la separación e identificación de múltiples hablantes"),
|
||||||
|
timestamps: Optional[bool] = Form(False, description="Activa las marcas de tiempo exactas por cada segmento hablado"),
|
||||||
|
sentiment: Optional[bool] = Form(False, description="Activa el análisis de sentimiento (POSITIVO/NEGATIVO) por segmento")
|
||||||
|
):
|
||||||
|
self.file = file
|
||||||
|
self.provider = provider
|
||||||
|
self.model = model
|
||||||
|
self.diarization = diarization
|
||||||
|
self.timestamps = timestamps
|
||||||
|
self.sentiment = sentiment
|
||||||
|
|
||||||
|
|
||||||
|
class StandardTranscriptionResult(BaseModel):
|
||||||
|
"""Modelo que representa el resultado estándar de una transcripción de video para Qualidot."""
|
||||||
|
status: str = Field(
|
||||||
|
...,
|
||||||
|
description="Estado final de la petición ('success' o 'error')"
|
||||||
|
)
|
||||||
|
original_filename: str = Field(
|
||||||
|
...,
|
||||||
|
description="Nombre original del archivo de video procesado"
|
||||||
|
)
|
||||||
|
provider_used: str = Field(
|
||||||
|
...,
|
||||||
|
description="Proveedor de IA que ejecutó la transcripción (ej. OpenAI)"
|
||||||
|
)
|
||||||
|
model_used: str = Field(
|
||||||
|
...,
|
||||||
|
description="Modelo específico utilizado para el proceso"
|
||||||
|
)
|
||||||
|
full_transcript: Optional[str] = Field(
|
||||||
|
None,
|
||||||
|
description="Texto completo y continuo de toda la transcripción"
|
||||||
|
)
|
||||||
|
segments: Optional[List[dict]] = Field( ##Queda pendiente definir mejor la estructura de cada segmento según las opciones avanzadas
|
||||||
|
None,
|
||||||
|
description="Lista detallada de segmentos si se solicitaron opciones avanzadas (diarization, timestamps, sentiment)"
|
||||||
|
)
|
||||||
|
confidence_score: Optional[float] = Field(
|
||||||
|
None,
|
||||||
|
description="Nivel de certeza global del modelo (valor entre 0.0 y 1.0)"
|
||||||
|
)
|
||||||
BIN
app/services/__pycache__/transcription_adapters.cpython-312.pyc
Normal file
BIN
app/services/__pycache__/transcription_adapters.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
163
app/services/audio/transcription_adapters.py
Normal file
163
app/services/audio/transcription_adapters.py
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
"""
|
||||||
|
Gateway de IA de Qualidot - Módulo de Adaptadores de Transcripción
|
||||||
|
|
||||||
|
Propósito:
|
||||||
|
Este módulo contiene funciones de adaptadores que permiten transcribir audio usando diferentes proveedores de IA.
|
||||||
|
Cada función de adaptador se encarga de interactuar con un proveedor específico (como OpenAI, AssemblyAI, Deepgram, etc.)
|
||||||
|
y de convertir la respuesta del proveedor al formato estándar de transcripción de Qualidot.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import tempfile
|
||||||
|
import os
|
||||||
|
from fastapi import HTTPException
|
||||||
|
from openai import OpenAI, AsyncOpenAI
|
||||||
|
import assemblyai as aai
|
||||||
|
from app.core.config import settings
|
||||||
|
from app.schemas.audio_standard import AudioRequestFile
|
||||||
|
from app.schemas.audio_standard import StandardTranscriptionResult
|
||||||
|
from app.utilities.audio_utilities import validate_audio_file, validate_audio_size, validate_audio_request
|
||||||
|
from app.core import config
|
||||||
|
|
||||||
|
# Función de adaptador principal que infiere el proveedor y llama al adaptador específico
|
||||||
|
async def transcribe_audio_with_provider(audio_request: AudioRequestFile) -> StandardTranscriptionResult:
|
||||||
|
"""
|
||||||
|
Función de adaptador para transcribir audio usando el proveedor de IA configurado.
|
||||||
|
"""
|
||||||
|
provider = audio_request.provider.lower()
|
||||||
|
|
||||||
|
match provider:
|
||||||
|
case "openai":
|
||||||
|
return await transcribe_with_openai(audio_request)
|
||||||
|
case "assemblyai":
|
||||||
|
return await transcribe_with_assemblyai(audio_request)
|
||||||
|
case _:
|
||||||
|
raise ValueError(f"Proveedor de IA no soportado: {audio_request.provider}")
|
||||||
|
|
||||||
|
# Función de adaptador para transcribir audio usando OpenAI
|
||||||
|
async def transcribe_with_openai(audio_request: AudioRequestFile) -> StandardTranscriptionResult:
|
||||||
|
"""
|
||||||
|
Función de adaptador para transcribir audio usando OpenAI.
|
||||||
|
"""
|
||||||
|
client = AsyncOpenAI(api_key=settings.OPENAI_API_KEY)
|
||||||
|
|
||||||
|
audio_content = await audio_request.file.read()
|
||||||
|
|
||||||
|
temp_audio_path = None # Inicializamos la variable fuera del try
|
||||||
|
|
||||||
|
# Validar el audio antes de continuar
|
||||||
|
validate_audio_request(audio_request, audio_content)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Crear archivo temporal para el audio
|
||||||
|
with tempfile.NamedTemporaryFile(
|
||||||
|
delete=False,
|
||||||
|
suffix=os.path.splitext(audio_request.file.filename)[1]
|
||||||
|
) as temp_audio:
|
||||||
|
temp_audio.write(audio_content)
|
||||||
|
temp_audio_path = temp_audio.name
|
||||||
|
|
||||||
|
with open(temp_audio_path, "rb") as audio_file_obj:
|
||||||
|
transcription = await client.audio.transcriptions.create(
|
||||||
|
model=audio_request.model,
|
||||||
|
file=audio_file_obj,
|
||||||
|
response_format="text"
|
||||||
|
)
|
||||||
|
|
||||||
|
result = StandardTranscriptionResult(
|
||||||
|
status="success",
|
||||||
|
original_filename=audio_request.file.filename,
|
||||||
|
full_transcript=transcription,
|
||||||
|
model_used=audio_request.model,
|
||||||
|
provider_used="OpenAI",
|
||||||
|
confidence_score=None
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
# Capturamos cualquier error de OpenAI o de lectura de archivos
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=500,
|
||||||
|
detail=f"Error transcribiendo el audio: {str(e)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if temp_audio_path and os.path.exists(temp_audio_path):
|
||||||
|
try:
|
||||||
|
os.unlink(temp_audio_path)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Función de adaptador para transcribir audio usando AssemblyAI
|
||||||
|
async def transcribe_with_assemblyai(audio_request: AudioRequestFile) -> StandardTranscriptionResult:
|
||||||
|
"""
|
||||||
|
Función de adaptador para transcribir audio usando AssemblyAI.
|
||||||
|
"""
|
||||||
|
aai.settings.api_key = settings.ASSEMBLYAI_API_KEY
|
||||||
|
|
||||||
|
audio_content = await audio_request.file.read()
|
||||||
|
temp_audio_path = None
|
||||||
|
|
||||||
|
# Validar el audio antes de continuar
|
||||||
|
validate_audio_request(audio_request, audio_content)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Crear archivo temporal para el audio
|
||||||
|
with tempfile.NamedTemporaryFile(
|
||||||
|
delete=False,
|
||||||
|
suffix=os.path.splitext(audio_request.file.filename)[1]
|
||||||
|
) as temp_audio:
|
||||||
|
temp_audio.write(audio_content)
|
||||||
|
temp_audio_path = temp_audio.name
|
||||||
|
|
||||||
|
#Definimos el modelo a usar
|
||||||
|
config = aai.TranscriptionConfig(language_code="es", speaker_labels=audio_request.diarization,
|
||||||
|
sentiment_analysis=audio_request.sentiment)
|
||||||
|
|
||||||
|
transcription_obj = aai.Transcriber(config=config).transcribe(temp_audio_path)
|
||||||
|
|
||||||
|
iterable = transcription_obj.sentiment_analysis if audio_request.sentiment else transcription_obj.utterances
|
||||||
|
|
||||||
|
|
||||||
|
if transcription_obj.status == aai.TranscriptStatus.error:
|
||||||
|
raise Exception(f"AssemblyAI Error: {transcription_obj.error}")
|
||||||
|
|
||||||
|
assemblyaiSegment = "utterances" if not audio_request.sentiment else "sentiment_analysis"
|
||||||
|
|
||||||
|
result = StandardTranscriptionResult(
|
||||||
|
status="success",
|
||||||
|
original_filename=audio_request.file.filename,
|
||||||
|
full_transcript=transcription_obj.text,
|
||||||
|
model_used=audio_request.model,
|
||||||
|
provider_used="AssemblyAI",
|
||||||
|
confidence_score=None,
|
||||||
|
segments=[
|
||||||
|
{
|
||||||
|
"text": segment.text,
|
||||||
|
"speaker": segment.speaker if audio_request.diarization else None,
|
||||||
|
"start_time": segment.start if audio_request.timestamps else None,
|
||||||
|
"end_time": segment.end if audio_request.timestamps else None,
|
||||||
|
"sentiment": segment.sentiment if audio_request.sentiment else None
|
||||||
|
}
|
||||||
|
for segment in iterable
|
||||||
|
] if (audio_request.diarization or audio_request.timestamps or audio_request.sentiment) else None
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
# Capturamos cualquier error de OpenAI o de lectura de archivos
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=500,
|
||||||
|
detail=f"Error transcribiendo el audio: {str(e)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if temp_audio_path and os.path.exists(temp_audio_path):
|
||||||
|
try:
|
||||||
|
os.unlink(temp_audio_path)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
# Aquí iría la implementación específica para AssemblyAI, similar a la de OpenAI pero usando su SDK y formato de respuesta
|
||||||
|
pass
|
||||||
Binary file not shown.
68
app/services/image/evaluations_adapters.py
Normal file
68
app/services/image/evaluations_adapters.py
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
"""
|
||||||
|
Gateway de IA de Qualidot - Módulo de Adaptadores de Evaluación de Imágenes
|
||||||
|
|
||||||
|
Propósito:
|
||||||
|
Este módulo contiene funciones de adaptadores que permiten evaluar imágenes usando diferentes proveedores de IA.
|
||||||
|
Cada función de adaptador se encarga de interactuar con un proveedor específico (como OpenAI, AssemblyAI, Deepgram, etc.)
|
||||||
|
y de convertir la respuesta del proveedor al formato estándar de evaluación de imágenes de Qualidot.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import tempfile
|
||||||
|
import os
|
||||||
|
from fastapi import HTTPException
|
||||||
|
from openai import OpenAI, AsyncOpenAI
|
||||||
|
import assemblyai as aai
|
||||||
|
from app.core.config import settings
|
||||||
|
from app.schemas.image_standard import ImageRequestFile, StandardImageAnalysisResult
|
||||||
|
from app.core import config
|
||||||
|
|
||||||
|
# Función de adaptador principal que infiere el proveedor y llama al adaptador específico
|
||||||
|
async def evaluate_image_with_provider(image_request: ImageRequestFile) -> StandardImageAnalysisResult:
|
||||||
|
"""
|
||||||
|
Función de adaptador para evaluar imágenes usando el proveedor de IA configurado.
|
||||||
|
"""
|
||||||
|
provider = image_request.provider.lower()
|
||||||
|
|
||||||
|
match provider:
|
||||||
|
case "openai":
|
||||||
|
return await evaluate_with_openai(image_request)
|
||||||
|
case "inserte nombre de otra ia aqui":
|
||||||
|
return await evaluate_with_ai_model2(image_request)
|
||||||
|
|
||||||
|
# AGREGAR OTROS CASOS PARA DIFERENTES PROVEEDORES DE IA AQUÍ
|
||||||
|
|
||||||
|
case _:
|
||||||
|
raise ValueError(f"Proveedor de IA no soportado: {image_request.provider}")
|
||||||
|
|
||||||
|
# Función de adaptador para evaluar imágenes usando OpenAI
|
||||||
|
async def evaluate_with_openai(image_request: ImageRequestFile) -> StandardImageAnalysisResult:
|
||||||
|
"""
|
||||||
|
Función de adaptador para evaluar imágenes usando OpenAI.
|
||||||
|
(Plantilla para futuras implementaciones)
|
||||||
|
"""
|
||||||
|
client = AsyncOpenAI(api_key=settings.OPENAI_API_KEY)
|
||||||
|
|
||||||
|
# PASOS A SEGUIR PARA IMPLEMENTAR LA LÓGICA DE EVALUACIÓN CON OPENAI:
|
||||||
|
# 1. Validar la imagen de entrada (tamaño, formato, etc.)
|
||||||
|
# 2. Configurar el cliente de OpenAI con la clave API
|
||||||
|
# 3. Llamar a la API de OpenAI para evaluar la imagen
|
||||||
|
# 4. Convertir la respuesta de OpenAI al formato estándar de evaluación de imágenes de Qualidot
|
||||||
|
# 5. Manejar errores y excepciones adecuadamente
|
||||||
|
raise NotImplementedError("La función evaluate_with_openai aún no está implementada.")
|
||||||
|
|
||||||
|
async def evaluate_with_ai_model2(image_request: ImageRequestFile) -> StandardImageAnalysisResult:
|
||||||
|
"""
|
||||||
|
Función de adaptador para transcribir video usando otra AI.
|
||||||
|
(Plantilla para futuras implementaciones)
|
||||||
|
"""
|
||||||
|
|
||||||
|
# PASOS A SEGUIR PARA IMPLEMENTAR LA LÓGICA DE TRANSCRIPCIÓN CON IA (ELEGIR MODELO):
|
||||||
|
# 1. Validar el video de entrada (tamaño, formato, etc.)
|
||||||
|
# 2. Configurar el cliente de OpenAI con la clave API
|
||||||
|
# 3. Llamar a la API de OpenAI para transcribir el video
|
||||||
|
# 4. Convertir la respuesta de OpenAI al formato estándar de resumen de texto de Qualidot
|
||||||
|
# 5. Manejar errores y excepciones adecuadamente
|
||||||
|
raise NotImplementedError("La función transcribe_with_ai_model2 aún no está implementada.")
|
||||||
|
|
||||||
|
# Otros modelos de IA
|
||||||
Binary file not shown.
BIN
app/services/text/__pycache__/resume_adapters.cpython-312.pyc
Normal file
BIN
app/services/text/__pycache__/resume_adapters.cpython-312.pyc
Normal file
Binary file not shown.
50
app/services/text/evaluations_adapters.py
Normal file
50
app/services/text/evaluations_adapters.py
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
"""
|
||||||
|
Gateway de IA de Qualidot - Módulo de Adaptadores de Resumen de Texto
|
||||||
|
|
||||||
|
Propósito:
|
||||||
|
Este módulo contiene funciones de adaptadores que permiten resumir texto usando diferentes proveedores de IA.
|
||||||
|
Cada función de adaptador se encarga de interactuar con un proveedor específico (como OpenAI, AssemblyAI, Deepgram, etc.)
|
||||||
|
y de convertir la respuesta del proveedor al formato estándar de resumen de texto de Qualidot.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import tempfile
|
||||||
|
import os
|
||||||
|
from fastapi import HTTPException
|
||||||
|
from openai import OpenAI, AsyncOpenAI
|
||||||
|
import assemblyai as aai
|
||||||
|
from app.core.config import settings
|
||||||
|
from app.schemas.text_standard import TextRequestFile, StandardTextAnalysisResult
|
||||||
|
from app.core import config
|
||||||
|
|
||||||
|
# Función de adaptador principal que infiere el proveedor y llama al adaptador específico
|
||||||
|
async def evaluate_text_with_provider(text_request: TextRequestFile) -> StandardTextAnalysisResult:
|
||||||
|
"""
|
||||||
|
Función de adaptador para evaluar texto usando el proveedor de IA configurado.
|
||||||
|
"""
|
||||||
|
provider = text_request.provider.lower()
|
||||||
|
|
||||||
|
match provider:
|
||||||
|
case "openai":
|
||||||
|
return await evaluate_with_openai(text_request)
|
||||||
|
# AGREGAR OTROS CASOS PARA DIFERENTES PROVEEDORES DE IA AQUÍ
|
||||||
|
case _:
|
||||||
|
raise ValueError(f"Proveedor de IA no soportado: {text_request.provider}")
|
||||||
|
|
||||||
|
# Función de adaptador para evaluar texto usando OpenAI
|
||||||
|
async def evaluate_with_openai(text_request: TextRequestFile) -> StandardTextAnalysisResult:
|
||||||
|
"""
|
||||||
|
Función de adaptador para evaluar texto usando OpenAI.
|
||||||
|
(Plantilla para futuras implementaciones)
|
||||||
|
"""
|
||||||
|
client = AsyncOpenAI(api_key=settings.OPENAI_API_KEY)
|
||||||
|
|
||||||
|
# PASOS A SEGUIR PARA IMPLEMENTAR LA LÓGICA DE EVALUACIÓN CON OPENAI:
|
||||||
|
# 1. Validar el texto de entrada (tamaño, formato, etc.)
|
||||||
|
# 2. Configurar el cliente de OpenAI con la clave API
|
||||||
|
# 3. Llamar a la API de OpenAI para evaluar el texto
|
||||||
|
# 4. Convertir la respuesta de OpenAI al formato estándar de evaluación de texto de Qualidot
|
||||||
|
# 5. Manejar errores y excepciones adecuadamente
|
||||||
|
raise NotImplementedError("La función evaluate_with_openai aún no está implementada.")
|
||||||
|
|
||||||
|
# Otros modelos de IA
|
||||||
50
app/services/text/resume_adapters.py
Normal file
50
app/services/text/resume_adapters.py
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
"""
|
||||||
|
Gateway de IA de Qualidot - Módulo de Adaptadores de Resumen de Texto
|
||||||
|
|
||||||
|
Propósito:
|
||||||
|
Este módulo contiene funciones de adaptadores que permiten resumir texto usando diferentes proveedores de IA.
|
||||||
|
Cada función de adaptador se encarga de interactuar con un proveedor específico (como OpenAI, AssemblyAI, Deepgram, etc.)
|
||||||
|
y de convertir la respuesta del proveedor al formato estándar de resumen de texto de Qualidot.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import tempfile
|
||||||
|
import os
|
||||||
|
from fastapi import HTTPException
|
||||||
|
from openai import OpenAI, AsyncOpenAI
|
||||||
|
import assemblyai as aai
|
||||||
|
from app.core.config import settings
|
||||||
|
from app.schemas.text_standard import TextRequestFile, StandardTextAnalysisResult
|
||||||
|
from app.core import config
|
||||||
|
|
||||||
|
# Función de adaptador principal que infiere el proveedor y llama al adaptador específico
|
||||||
|
async def summarize_text_with_provider(text_request: TextRequestFile) -> StandardTextAnalysisResult:
|
||||||
|
"""
|
||||||
|
Función de adaptador para resumir texto usando el proveedor de IA configurado.
|
||||||
|
"""
|
||||||
|
provider = text_request.provider.lower()
|
||||||
|
|
||||||
|
match provider:
|
||||||
|
case "openai":
|
||||||
|
return await summarize_with_openai(text_request)
|
||||||
|
# AGREGAR OTROS CASOS PARA DIFERENTES PROVEEDORES DE IA AQUÍ
|
||||||
|
case _:
|
||||||
|
raise ValueError(f"Proveedor de IA no soportado: {text_request.provider}")
|
||||||
|
|
||||||
|
# Función de adaptador para resumir texto usando OpenAI
|
||||||
|
async def summarize_with_openai(text_request: TextRequestFile) -> StandardTextAnalysisResult:
|
||||||
|
"""
|
||||||
|
Función de adaptador para resumir texto usando OpenAI.
|
||||||
|
(Plantilla para futuras implementaciones)
|
||||||
|
"""
|
||||||
|
client = AsyncOpenAI(api_key=settings.OPENAI_API_KEY)
|
||||||
|
|
||||||
|
# PASOS A SEGUIR PARA IMPLEMENTAR LA LÓGICA DE RESUMEN CON OPENAI:
|
||||||
|
# 1. Validar el texto de entrada (tamaño, formato, etc.)
|
||||||
|
# 2. Configurar el cliente de OpenAI con la clave API
|
||||||
|
# 3. Llamar a la API de OpenAI para resumir el texto
|
||||||
|
# 4. Convertir la respuesta de OpenAI al formato estándar de resumen de texto de Qualidot
|
||||||
|
# 5. Manejar errores y excepciones adecuadamente
|
||||||
|
raise NotImplementedError("La función summarize_with_openai aún no está implementada.")
|
||||||
|
|
||||||
|
# Otros modelos de IA
|
||||||
Binary file not shown.
67
app/services/video/transcription_adapters.py
Normal file
67
app/services/video/transcription_adapters.py
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
"""
|
||||||
|
Gateway de IA de Qualidot - Módulo de Adaptadores de Transcripción de Video
|
||||||
|
|
||||||
|
Propósito:
|
||||||
|
Este módulo contiene funciones de adaptadores que permiten resumir texto usando diferentes proveedores de IA.
|
||||||
|
Cada función de adaptador se encarga de interactuar con un proveedor específico (como OpenAI, AssemblyAI, Deepgram, etc.)
|
||||||
|
y de convertir la respuesta del proveedor al formato estándar de resumen de texto de Qualidot.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import tempfile
|
||||||
|
import os
|
||||||
|
from fastapi import HTTPException
|
||||||
|
from openai import OpenAI, AsyncOpenAI
|
||||||
|
import assemblyai as aai
|
||||||
|
from app.core.config import settings
|
||||||
|
from app.schemas.video_standard import VideoRequestFile, StandardTranscriptionResult
|
||||||
|
from app.core import config
|
||||||
|
|
||||||
|
# Función de adaptador principal que infiere el proveedor y llama al adaptador específico
|
||||||
|
async def transcribe_video_with_provider(video_request: VideoRequestFile) -> StandardTranscriptionResult:
|
||||||
|
"""
|
||||||
|
Función de adaptador para transcribir video usando el proveedor de IA configurado.
|
||||||
|
"""
|
||||||
|
provider = video_request.provider.lower()
|
||||||
|
|
||||||
|
match provider:
|
||||||
|
case "nombre de la ia 1 aqui":
|
||||||
|
return await transcribe_with_ai_model1(video_request)
|
||||||
|
case "nombre de la ia 2 aqui":
|
||||||
|
return await transcribe_with_ai_model2(video_request)
|
||||||
|
|
||||||
|
# AGREGAR OTROS CASOS PARA DIFERENTES PROVEEDORES DE IA AQUÍ
|
||||||
|
|
||||||
|
case _:
|
||||||
|
raise ValueError(f"Proveedor de IA no soportado: {video_request.provider}")
|
||||||
|
|
||||||
|
# Función de adaptador para transcribir video usando OpenAI
|
||||||
|
async def transcribe_with_ai_model1(video_request: VideoRequestFile) -> StandardTranscriptionResult:
|
||||||
|
"""
|
||||||
|
Función de adaptador para transcribir video usando OpenAI.
|
||||||
|
(Plantilla para futuras implementaciones)
|
||||||
|
"""
|
||||||
|
|
||||||
|
# PASOS A SEGUIR PARA IMPLEMENTAR LA LÓGICA DE TRANSCRIPCIÓN CON IA (ELEGIR MODELO):
|
||||||
|
# 1. Validar el video de entrada (tamaño, formato, etc.)
|
||||||
|
# 2. Configurar el cliente de OpenAI con la clave API
|
||||||
|
# 3. Llamar a la API de OpenAI para transcribir el video
|
||||||
|
# 4. Convertir la respuesta de OpenAI al formato estándar de resumen de texto de Qualidot
|
||||||
|
# 5. Manejar errores y excepciones adecuadamente
|
||||||
|
raise NotImplementedError("La función transcribe_with_ai_model1 aún no está implementada.")
|
||||||
|
|
||||||
|
async def transcribe_with_ai_model2(video_request: VideoRequestFile) -> StandardTranscriptionResult:
|
||||||
|
"""
|
||||||
|
Función de adaptador para transcribir video usando OpenAI.
|
||||||
|
(Plantilla para futuras implementaciones)
|
||||||
|
"""
|
||||||
|
|
||||||
|
# PASOS A SEGUIR PARA IMPLEMENTAR LA LÓGICA DE TRANSCRIPCIÓN CON IA (ELEGIR MODELO):
|
||||||
|
# 1. Validar el video de entrada (tamaño, formato, etc.)
|
||||||
|
# 2. Configurar el cliente de OpenAI con la clave API
|
||||||
|
# 3. Llamar a la API de OpenAI para transcribir el video
|
||||||
|
# 4. Convertir la respuesta de OpenAI al formato estándar de resumen de texto de Qualidot
|
||||||
|
# 5. Manejar errores y excepciones adecuadamente
|
||||||
|
raise NotImplementedError("La función transcribe_with_ai_model2 aún no está implementada.")
|
||||||
|
|
||||||
|
# Otros modelos de IA
|
||||||
BIN
app/utilities/__pycache__/audio_utilities.cpython-312.pyc
Normal file
BIN
app/utilities/__pycache__/audio_utilities.cpython-312.pyc
Normal file
Binary file not shown.
62
app/utilities/audio_utilities.py
Normal file
62
app/utilities/audio_utilities.py
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
"""
|
||||||
|
Validadores comunes para los endpoints de audio.
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
from fastapi import UploadFile, HTTPException
|
||||||
|
|
||||||
|
from app.schemas.audio_standard import AudioRequestFile
|
||||||
|
|
||||||
|
# Configuración de validaciones
|
||||||
|
ALLOWED_AUDIO_FORMATS = ["audio/mpeg", "audio/wav", "audio/x-wav", "audio/mp4", "audio/x-m4a"]
|
||||||
|
ALLOWED_EXTENSIONS = [".mp3", ".wav", ".m4a"]
|
||||||
|
MAX_AUDIO_SIZE_MB = 25 # Tamaño máximo en MB
|
||||||
|
MAX_AUDIO_SIZE_BYTES = MAX_AUDIO_SIZE_MB * 1024 * 1024
|
||||||
|
|
||||||
|
|
||||||
|
def validate_audio_file(audio_file: UploadFile) -> None:
|
||||||
|
"""
|
||||||
|
Valida el formato y tamaño del archivo de audio.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
audio_file: Archivo de audio a validar
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
HTTPException: Si el archivo no cumple con los requisitos
|
||||||
|
"""
|
||||||
|
# Validar formato (content-type)
|
||||||
|
if audio_file.content_type not in ALLOWED_AUDIO_FORMATS:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=400,
|
||||||
|
detail=f"Formato de audio no válido. Solo se permiten: MP3, WAV, M4A"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Validar extensión del archivo
|
||||||
|
file_extension = os.path.splitext(audio_file.filename)[1].lower()
|
||||||
|
if file_extension not in ALLOWED_EXTENSIONS:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=400,
|
||||||
|
detail=f"Extensión de archivo no válida. Solo se permiten: .mp3, .wav, .m4a"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_audio_size(audio_content: bytes) -> None:
|
||||||
|
"""
|
||||||
|
Valida el tamaño del contenido del audio.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
audio_content: Contenido del archivo de audio en bytes
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
HTTPException: Si el archivo excede el tamaño máximo
|
||||||
|
"""
|
||||||
|
if len(audio_content) > MAX_AUDIO_SIZE_BYTES:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=400,
|
||||||
|
detail=f"El archivo excede el tamaño máximo permitido de {MAX_AUDIO_SIZE_MB}MB"
|
||||||
|
)
|
||||||
|
|
||||||
|
def validate_audio_request(audio_request: AudioRequestFile, audio_content: bytes):
|
||||||
|
# Validar el archivo de audio
|
||||||
|
validate_audio_file(audio_request.file)
|
||||||
|
# Validar tamaño del archivo
|
||||||
|
validate_audio_size(audio_content)
|
||||||
77
docs.md
Normal file
77
docs.md
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
# Qualidot AI Gateway - FastAPI Template
|
||||||
|
|
||||||
|
## Metadatos
|
||||||
|
|
||||||
|
- **Autor:** Alan Ivan Sánchez Gómez
|
||||||
|
- **Revisor:** Francisco Pineda
|
||||||
|
- **Proyecto:** Qualidot
|
||||||
|
- **Versión:** 1.0
|
||||||
|
- **Fecha de creación:** 12/03/2026
|
||||||
|
- **Última actualización:** 14/03/2026
|
||||||
|
- **Lenguaje:** Python 3.12+
|
||||||
|
- **Tipo:** Microservicio
|
||||||
|
- **Dominio:** IA / NLP / Audio / Visión / Multimodal
|
||||||
|
- **Estado:** Desarrollo (MVP Funcional)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Descripción General
|
||||||
|
|
||||||
|
Este microservicio es una **Template de FastAPI** diseñada para el consumo de modelos de IA (OpenAI, AssemblyAI, etc.). Su característica principal es la **homologación de respuestas**: sin importar el proveedor utilizado, el cliente siempre recibe los resultados en un formato estándar de Qualidot.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Objetivo
|
||||||
|
|
||||||
|
- **Estandarización:** Proveer una base sólida para integrar nuevos modelos de IA rápidamente.
|
||||||
|
- **Evaluación:** Facilitar el testing de modelos mediante Postman con una estructura de datos predecible.
|
||||||
|
- **Escalabilidad:** Separar la lógica de negocio de los proveedores externos mediante el uso de adaptadores.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Cambios a Implementar
|
||||||
|
|
||||||
|
- Agregar endpoints para procesamiento de texto, imagen y video.
|
||||||
|
- Mejorar la gestión de errores y mensajes de validación.
|
||||||
|
- Implementar autenticación y autorización (JWT o API Key).
|
||||||
|
- Añadir pruebas unitarias y de integración.
|
||||||
|
- Optimizar el manejo de archivos temporales y recursos.
|
||||||
|
- Agregar ejemplos de uso y scripts de automatización para testing.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Arquitectura / Flujo
|
||||||
|
|
||||||
|
Entrada (Postman/Client)
|
||||||
|
↓
|
||||||
|
Validación (Check de extensión y peso del archivo)
|
||||||
|
↓
|
||||||
|
Preprocesamiento (Creación de archivos temporales / Seek(0))
|
||||||
|
↓
|
||||||
|
Modelo(s) IA (Adaptadores de OpenAI, AssemblyAI, etc.)
|
||||||
|
↓
|
||||||
|
Postprocesamiento (Mapeo a esquema homologado StandardTranscriptionResult)
|
||||||
|
↓
|
||||||
|
Salida (Respuesta JSON estandarizada)
|
||||||
|
|
||||||
|
## Estructura del proyecto
|
||||||
|
Para mantener el orden y evitar errores de importación circular, el proyecto se organiza de la siguiente manera:
|
||||||
|
|
||||||
|
fastApiTemplate/
|
||||||
|
├── app/
|
||||||
|
│ ├── api/
|
||||||
|
│ │ └── v1/
|
||||||
|
│ │ └── endpoints/ # Definición de rutas y routers
|
||||||
|
│ │ ├── audio/ # Endpoints específicos de procesamiento de audio
|
||||||
|
│ │ ├── image/ # (Pendiente) Procesamiento de visión
|
||||||
|
│ │ ├── video/ # (Pendiente) Procesamiento de video
|
||||||
|
│ │ └── router.py # Router maestro que unifica los módulos
|
||||||
|
│ ├── core/
|
||||||
|
│ │ └── config.py # Configuración central (Settings y Pydantic-settings)
|
||||||
|
│ ├── schemas/ # Contratos de datos (Pydantic Models)
|
||||||
|
│ ├── services/ # Adaptadores y lógica con proveedores de IA
|
||||||
|
│ ├── utilities/ # Helpers (Validaciones, conversiones de audio)
|
||||||
|
│ └── main.py # Punto de entrada de la aplicación
|
||||||
|
├── .env # Credenciales y API Keys (No trackeado en Git)
|
||||||
|
├── requirements.txt # Dependencias del proyecto
|
||||||
|
└── docs.md # Documentación técnica
|
||||||
28
requirements.txt
Normal file
28
requirements.txt
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# Dependencias principales
|
||||||
|
annotated-doc==0.0.4
|
||||||
|
annotated-types==0.7.0
|
||||||
|
anyio==4.11.0
|
||||||
|
fastapi[standard]==0.121.3
|
||||||
|
idna==3.11
|
||||||
|
pydantic==2.12.4
|
||||||
|
pydantic_core==2.41.5
|
||||||
|
sniffio==1.3.1
|
||||||
|
starlette==0.50.0
|
||||||
|
typing-inspection==0.4.2
|
||||||
|
typing_extensions==4.15.0
|
||||||
|
uvicorn[standard]
|
||||||
|
python-multipart
|
||||||
|
python-dotenv
|
||||||
|
|
||||||
|
# Procesamiento de audio
|
||||||
|
noisereduce
|
||||||
|
librosa
|
||||||
|
soundfile
|
||||||
|
praat-parselmouth
|
||||||
|
numpy
|
||||||
|
|
||||||
|
# Modelos de IA e integraciones
|
||||||
|
openai
|
||||||
|
langchain
|
||||||
|
langchain-openai
|
||||||
|
assemblyai
|
||||||
Reference in New Issue
Block a user