feat: audio playback working with bugs
This commit is contained in:
Binary file not shown.
@@ -96,6 +96,16 @@ def _build_prompt(transcript_text: str, title: str) -> str:
|
|||||||
f"{transcript_text}\n\n"
|
f"{transcript_text}\n\n"
|
||||||
"Answer user questions grounded in this transcript."
|
"Answer user questions grounded in this transcript."
|
||||||
)
|
)
|
||||||
|
def _add_audio_url(post: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
|
"""Add signed audio URL to post if ready"""
|
||||||
|
if post.get("status") == "ready":
|
||||||
|
try:
|
||||||
|
audio_data = get_original_audio_url(post["post_id"], expires_in=3600)
|
||||||
|
post["audio_url"] = audio_data["signed_url"]
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return post
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@api.get("/health")
|
@api.get("/health")
|
||||||
@@ -397,20 +407,32 @@ def api_create_post():
|
|||||||
return _error(str(e), 500)
|
return _error(str(e), 500)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@api.get("/posts")
|
@api.get("/posts")
|
||||||
def api_list_posts():
|
def api_list_posts():
|
||||||
page = request.args.get("page", default=1, type=int)
|
page = request.args.get("page", default=1, type=int)
|
||||||
limit = request.args.get("limit", default=20, type=int)
|
limit = request.args.get("limit", default=20, type=int)
|
||||||
visibility = request.args.get("visibility")
|
visibility = request.args.get("visibility")
|
||||||
user_id = request.args.get("user_id", type=int)
|
current_user_id = request.args.get("current_user_id", type=int) # NEW LINE
|
||||||
|
|
||||||
try:
|
try:
|
||||||
rows = list_audio_posts(page=page, limit=limit, visibility=visibility, user_id=user_id)
|
rows = list_audio_posts(page=page, limit=limit, visibility=visibility)
|
||||||
|
|
||||||
|
# NEW: Filter private posts
|
||||||
|
if current_user_id:
|
||||||
|
rows = [p for p in rows if p.get('visibility') == 'public' or p.get('user_id') == current_user_id]
|
||||||
|
else:
|
||||||
|
rows = [p for p in rows if p.get('visibility') == 'public']
|
||||||
|
|
||||||
|
# NEW: Add audio URLs - CHANGE THIS LINE ONLY
|
||||||
|
rows = [_add_audio_url(post) for post in rows]
|
||||||
|
|
||||||
return jsonify({"posts": rows, "page": page, "limit": min(max(1, limit), 100)})
|
return jsonify({"posts": rows, "page": page, "limit": min(max(1, limit), 100)})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return _error(str(e), 500)
|
return _error(str(e), 500)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@api.get("/posts/<int:post_id>")
|
@api.get("/posts/<int:post_id>")
|
||||||
def api_get_post(post_id: int):
|
def api_get_post(post_id: int):
|
||||||
row = get_audio_post_by_id(post_id)
|
row = get_audio_post_by_id(post_id)
|
||||||
@@ -583,20 +605,3 @@ def api_post_audit(post_id: int):
|
|||||||
return jsonify({"logs": list_audit_logs(post_id=post_id, page=page, limit=limit)})
|
return jsonify({"logs": list_audit_logs(post_id=post_id, page=page, limit=limit)})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return _error(str(e), 500)
|
return _error(str(e), 500)
|
||||||
|
|
||||||
@api.get("/posts/<int:post_id>/audio")
|
|
||||||
def api_get_audio_url(post_id: int):
|
|
||||||
"""
|
|
||||||
Get a signed URL for the original audio file.
|
|
||||||
"""
|
|
||||||
expires_in = request.args.get("expires_in", default=3600, type=int)
|
|
||||||
|
|
||||||
try:
|
|
||||||
audio_data = get_original_audio_url(post_id, expires_in=expires_in)
|
|
||||||
return jsonify(audio_data)
|
|
||||||
except ValueError as e:
|
|
||||||
return _error(str(e), 404)
|
|
||||||
except RuntimeError as e:
|
|
||||||
return _error(str(e), 500)
|
|
||||||
except Exception as e:
|
|
||||||
return _error(f"Failed to get audio URL: {e}", 500)
|
|
||||||
|
|||||||
@@ -137,6 +137,10 @@ class ApiClient {
|
|||||||
return this.request(`/posts/${postId}/metadata`);
|
return this.request(`/posts/${postId}/metadata`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getAudioUrl(postId, expiresIn = 3600) {
|
||||||
|
return this.request(`/posts/${postId}/audio?expires_in=${expiresIn}`);
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== Post Files ====================
|
// ==================== Post Files ====================
|
||||||
|
|
||||||
async getPostFiles(postId) {
|
async getPostFiles(postId) {
|
||||||
|
|||||||
@@ -12,6 +12,13 @@ export default function AudioPostCard({ post }) {
|
|||||||
const [transcriptExpanded, setTranscriptExpanded] = useState(false)
|
const [transcriptExpanded, setTranscriptExpanded] = useState(false)
|
||||||
const audioRef = useRef(null)
|
const audioRef = useRef(null)
|
||||||
|
|
||||||
|
// DEBUG: Log post data to console
|
||||||
|
useEffect(() => {
|
||||||
|
console.log('Post data:', post)
|
||||||
|
console.log('Audio URL:', post.audio_url)
|
||||||
|
console.log('Status:', post.status)
|
||||||
|
}, [post])
|
||||||
|
|
||||||
const formatDate = (dateString) => {
|
const formatDate = (dateString) => {
|
||||||
const date = new Date(dateString)
|
const date = new Date(dateString)
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
@@ -35,7 +42,14 @@ export default function AudioPostCard({ post }) {
|
|||||||
if (post.status === 'ready' && !transcript && !loadingTranscript) {
|
if (post.status === 'ready' && !transcript && !loadingTranscript) {
|
||||||
loadTranscript()
|
loadTranscript()
|
||||||
}
|
}
|
||||||
}, [post.post_id, post.status])
|
|
||||||
|
// Set audio source if available
|
||||||
|
if (post.audio_url && audioRef.current) {
|
||||||
|
console.log('Setting audio src to:', post.audio_url)
|
||||||
|
audioRef.current.src = post.audio_url
|
||||||
|
audioRef.current.load() // Force reload
|
||||||
|
}
|
||||||
|
}, [post.post_id, post.status, post.audio_url])
|
||||||
|
|
||||||
const loadTranscript = async () => {
|
const loadTranscript = async () => {
|
||||||
setLoadingTranscript(true)
|
setLoadingTranscript(true)
|
||||||
@@ -78,10 +92,16 @@ export default function AudioPostCard({ post }) {
|
|||||||
|
|
||||||
const handleLoadedMetadata = () => {
|
const handleLoadedMetadata = () => {
|
||||||
if (audioRef.current) {
|
if (audioRef.current) {
|
||||||
|
console.log('Audio metadata loaded, duration:', audioRef.current.duration)
|
||||||
setDuration(audioRef.current.duration)
|
setDuration(audioRef.current.duration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleAudioError = (e) => {
|
||||||
|
console.error('Audio error:', e)
|
||||||
|
console.error('Audio element error:', audioRef.current?.error)
|
||||||
|
}
|
||||||
|
|
||||||
const handleSeek = (e) => {
|
const handleSeek = (e) => {
|
||||||
const rect = e.currentTarget.getBoundingClientRect()
|
const rect = e.currentTarget.getBoundingClientRect()
|
||||||
const x = e.clientX - rect.left
|
const x = e.clientX - rect.left
|
||||||
@@ -155,11 +175,13 @@ export default function AudioPostCard({ post }) {
|
|||||||
{/* Hidden audio element */}
|
{/* Hidden audio element */}
|
||||||
<audio
|
<audio
|
||||||
ref={audioRef}
|
ref={audioRef}
|
||||||
src={post.audio_path}
|
|
||||||
onTimeUpdate={handleTimeUpdate}
|
onTimeUpdate={handleTimeUpdate}
|
||||||
onLoadedMetadata={handleLoadedMetadata}
|
onLoadedMetadata={handleLoadedMetadata}
|
||||||
onEnded={handleEnded}
|
onEnded={handleEnded}
|
||||||
|
onError={handleAudioError}
|
||||||
|
onCanPlay={() => console.log('Audio can play')}
|
||||||
preload="metadata"
|
preload="metadata"
|
||||||
|
crossOrigin="anonymous"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
|
|||||||
Reference in New Issue
Block a user