Development of an AI transcription system with a web interface. The transcription web interface is a full-fledged SaaS product or an internal company tool: file upload, task management, transcript editing, export. The user does not need to understand the technical part. ### Stack - Backend: FastAPI + Celery + Redis - Frontend: React + Type
Script + Tailwind - STT: faster-whisper (GPU) + cloud fallback - Storage: S3 (MinIO for on-premise) - DB: PostgreSQL ### Backend API```python from fastapi import FastAPI, UploadFile, BackgroundTasks from celery import Celery import uuid
app = FastAPI() celery = Celery('transcription', broker='redis://localhost:6379/0')
@app.post("/api/transcription/upload") async def upload_audio( file: UploadFile, language: str = "ru", speakers: int = None, user_id: str = Depends(get_current_user) ): # Сохраняем файл job_id = str(uuid.uuid4()) file_path = await save_to_storage(file, job_id)
# Создаём задачу
job = await db.transcription_jobs.insert_one({
"id": job_id,
"user_id": user_id,
"status": "queued",
"file_path": file_path,
"language": language,
"created_at": datetime.utcnow()
})
# Ставим в очередь
celery.send_task(
'transcribe_audio',
args=[job_id, file_path, language, speakers]
)
return {"job_id": job_id, "status": "queued"}
@app.get("/api/transcription/{job_id}")
async def get_transcription(job_id: str, user_id = Depends(get_current_user)):
job = await db.transcription_jobs.find_one({"id": job_id, "user_id": user_id})
if not job:
raise HTTPException(404)
return job
### React Loading Componenttsx
const TranscriptionUploader: React.FC = () => {
const [status, setStatus] = useState<'idle'|'uploading'|'processing'|'done'>('idle');
const [jobId, setJobId] = useState
const handleUpload = async (file: File) => { setStatus('uploading'); const form = new FormData(); form.append('file', file); form.append('language', 'ru');
const { job_id } = await api.post('/transcription/upload', form);
setJobId(job_id);
setStatus('processing');
// Polling статуса
const interval = setInterval(async () => {
const job = await api.get(`/transcription/${job_id}`);
if (job.status === 'completed') {
setTranscript(job.transcript);
setStatus('done');
clearInterval(interval);
}
}, 3000);
};
return (







