AIZEN-007 commited on
Commit
783be15
·
verified ·
1 Parent(s): 344ee5c

Update server.py

Browse files
Files changed (1) hide show
  1. server.py +186 -0
server.py CHANGED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import tempfile
3
+ import asyncio
4
+ from fastapi import FastAPI, File, UploadFile, HTTPException, Depends
5
+ from fastapi.middleware.cors import CORSMiddleware
6
+ from fastapi.responses import JSONResponse
7
+ from pydantic import BaseModel
8
+ from typing import Optional, Dict, Any
9
+ import uvicorn
10
+ from groq import Groq
11
+ from dotenv import load_dotenv
12
+ import librosa
13
+ import soundfile as sf
14
+ from main2 import UnifiedAudioAnalyzer, summarize_audio_analysis_with_llm
15
+
16
+ # Load environment variables
17
+ load_dotenv()
18
+
19
+ app = FastAPI(title="Audio Analysis API", version="1.0.0")
20
+
21
+ # CORS middleware
22
+ app.add_middleware(
23
+ CORSMiddleware,
24
+ allow_origins=["http://localhost:9002", "http://localhost:3000"], # Frontend URLs
25
+ allow_credentials=True,
26
+ allow_methods=["*"],
27
+ allow_headers=["*"],
28
+ )
29
+
30
+ # Initialize the audio analyzer
31
+ analyzer = UnifiedAudioAnalyzer(enable_parallel_processing=True)
32
+
33
+ # Groq client for chat
34
+ groq_client = None
35
+ try:
36
+ groq_api_key = os.getenv("GROQ_API_KEY")
37
+ if groq_api_key:
38
+ groq_client = Groq(api_key=groq_api_key)
39
+ except Exception as e:
40
+ print(f"Warning: Could not initialize Groq client: {e}")
41
+
42
+ # Pydantic models
43
+ class ChatRequest(BaseModel):
44
+ question: str
45
+ analysis_data: Dict[str, Any]
46
+
47
+ class ChatResponse(BaseModel):
48
+ answer: str
49
+
50
+ class AnalysisResponse(BaseModel):
51
+ success: bool
52
+ data: Optional[Dict[str, Any]] = None
53
+ error: Optional[str] = None
54
+
55
+ def convert_audio_to_wav(audio_file_path: str) -> str:
56
+ """Convert audio file to WAV format if needed"""
57
+ try:
58
+ # Load audio with librosa (supports many formats)
59
+ audio_data, sample_rate = librosa.load(audio_file_path, sr=16000)
60
+
61
+ # Create temporary WAV file
62
+ temp_wav = tempfile.NamedTemporaryFile(suffix='.wav', delete=False)
63
+ temp_wav_path = temp_wav.name
64
+ temp_wav.close()
65
+
66
+ # Save as WAV
67
+ sf.write(temp_wav_path, audio_data, sample_rate)
68
+
69
+ return temp_wav_path
70
+ except Exception as e:
71
+ raise HTTPException(status_code=400, detail=f"Error converting audio to WAV: {str(e)}")
72
+
73
+ @app.get("/")
74
+ async def root():
75
+ return {"message": "Audio Analysis API is running"}
76
+
77
+ @app.post("/upload", response_model=AnalysisResponse)
78
+ async def upload_audio(file: UploadFile = File(...)):
79
+ """Upload and analyze audio file"""
80
+ try:
81
+ # Check file type
82
+ if not file.content_type.startswith("audio/"):
83
+ raise HTTPException(status_code=400, detail="File must be an audio file")
84
+
85
+ # Create temporary file
86
+ with tempfile.NamedTemporaryFile(delete=False, suffix=f".{file.filename.split('.')[-1]}") as temp_file:
87
+ content = await file.read()
88
+ temp_file.write(content)
89
+ temp_file_path = temp_file.name
90
+
91
+ try:
92
+ # Convert to WAV if needed
93
+ wav_file_path = convert_audio_to_wav(temp_file_path)
94
+
95
+ # Perform analysis
96
+ analysis_results = analyzer.analyze_complete_audio(wav_file_path)
97
+
98
+ if not analysis_results:
99
+ raise HTTPException(status_code=500, detail="Analysis failed")
100
+
101
+ # Generate LLM summary
102
+ try:
103
+ summary = summarize_audio_analysis_with_llm(analysis_results)
104
+ analysis_results['llm_summary'] = summary
105
+ except Exception as e:
106
+ print(f"Warning: LLM summary failed: {e}")
107
+ analysis_results['llm_summary'] = "Summary generation failed"
108
+
109
+ return AnalysisResponse(
110
+ success=True,
111
+ data=analysis_results
112
+ )
113
+
114
+ finally:
115
+ # Clean up temporary files
116
+ try:
117
+ os.unlink(temp_file_path)
118
+ if 'wav_file_path' in locals():
119
+ os.unlink(wav_file_path)
120
+ except OSError:
121
+ pass
122
+
123
+ except Exception as e:
124
+ return AnalysisResponse(
125
+ success=False,
126
+ error=str(e)
127
+ )
128
+
129
+ @app.post("/chat", response_model=ChatResponse)
130
+ async def chat_with_analysis(request: ChatRequest):
131
+ """Chat with AI about the analysis results"""
132
+ if not groq_client:
133
+ raise HTTPException(status_code=500, detail="Groq API not configured")
134
+
135
+ try:
136
+ # Prepare context from analysis data
137
+ context = f"""
138
+ Audio Analysis Summary:
139
+ - File: {request.analysis_data.get('file_info', {}).get('filename', 'Unknown')}
140
+ - Duration: {request.analysis_data.get('file_info', {}).get('duration', 0):.2f} seconds
141
+ - LLM Summary: {request.analysis_data.get('llm_summary', 'No summary available')}
142
+
143
+ Speaker Diarization:
144
+ {request.analysis_data.get('diarization_transcription', [])}
145
+
146
+ Audio Events:
147
+ {request.analysis_data.get('audio_events', {}).get('top_events', [])}
148
+
149
+ Emotion Analysis:
150
+ {request.analysis_data.get('emotion_analysis', {})}
151
+
152
+ Paralinguistic Features:
153
+ {request.analysis_data.get('paralinguistic_features', {})}
154
+ """
155
+
156
+ # Create chat completion
157
+ response = groq_client.chat.completions.create(
158
+ model="llama-3.1-8b-instant", # Using smaller model as requested
159
+ messages=[
160
+ {
161
+ "role": "system",
162
+ "content": "You are an expert audio analyst. Answer questions about the provided audio analysis data. Be helpful and provide insights based on the analysis results."
163
+ },
164
+ {
165
+ "role": "user",
166
+ "content": f"Context: {context}\n\nQuestion: {request.question}"
167
+ }
168
+ ],
169
+ temperature=0.7,
170
+ max_tokens=1000
171
+ )
172
+
173
+ answer = response.choices[0].message.content.strip()
174
+
175
+ return ChatResponse(answer=answer)
176
+
177
+ except Exception as e:
178
+ raise HTTPException(status_code=500, detail=f"Chat error: {str(e)}")
179
+
180
+ @app.get("/health")
181
+ async def health_check():
182
+ """Health check endpoint"""
183
+ return {"status": "healthy", "analyzer_loaded": analyzer is not None}
184
+
185
+ if __name__ == "__main__":
186
+ uvicorn.run(app, host="0.0.0.0", port=8000)