Tungdabiban commited on
Commit
864b667
·
verified ·
1 Parent(s): 2be45ba

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +87 -40
app.py CHANGED
@@ -7,10 +7,14 @@ import re
7
  from typing import Optional
8
  from fastapi import FastAPI, File, UploadFile, HTTPException
9
  from fastapi.middleware.cors import CORSMiddleware
 
10
  from pydantic import BaseModel
11
  from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
12
  import torch
13
  import fitz # PyMuPDF
 
 
 
14
 
15
  # ============================================================
16
  # Initialize FastAPI App
@@ -303,26 +307,85 @@ async def summarize_text(request: SummarizeRequest):
303
  detail="Văn bản quá ngắn để tóm tắt (cần ít nhất 50 ký tự)."
304
  )
305
 
306
- # Generate summaries
307
- summaries = summarize_long_text(text)
 
 
 
 
 
 
 
 
 
 
 
 
 
308
 
309
- if not summaries:
310
- raise HTTPException(
311
- status_code=500,
312
- detail="Không thể tạo tóm tắt."
313
- )
314
 
315
- # Format as bullet points với giới hạn số lượng
316
- bullet_points = format_as_bullet_points(summaries, max_points=max_points)
317
 
318
- return {
319
- "success": True,
320
- "original_length": len(text),
321
- "word_count": len(text.split()),
322
- "num_chunks": len(summaries),
323
- "length_level": length_level,
324
- "summary": bullet_points
325
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
326
 
327
 
328
  @app.post("/upload-pdf")
@@ -330,7 +393,7 @@ async def upload_pdf(file: UploadFile = File(...), length_level: int = 1):
330
  """
331
  Upload và tóm tắt file PDF.
332
  Đọc qua byte stream, KHÔNG lưu file ra đĩa.
333
- Trả về danh sách Bullet Points.
334
  length_level: 0 = Ngắn (2-3 ý), 1 = Trung bình (4-5 ý), 2 = Chi tiết (6+ ý)
335
  """
336
  # Map length_level to max_points
@@ -365,7 +428,7 @@ async def upload_pdf(file: UploadFile = File(...), length_level: int = 1):
365
  detail="File quá lớn. Giới hạn 10MB."
366
  )
367
 
368
- # Extract text from PDF bytes (dùng fitz.open(stream=contents, filetype='pdf'))
369
  text = extract_text_from_pdf_bytes(contents)
370
 
371
  # Validate extracted text
@@ -375,27 +438,11 @@ async def upload_pdf(file: UploadFile = File(...), length_level: int = 1):
375
  detail="Văn bản trích xuất từ PDF quá ngắn."
376
  )
377
 
378
- # Generate summaries
379
- summaries = summarize_long_text(text)
380
-
381
- if not summaries:
382
- raise HTTPException(
383
- status_code=500,
384
- detail="Không thể tạo tóm tắt."
385
- )
386
-
387
- # Format as bullet points với giới hạn số lượng
388
- bullet_points = format_as_bullet_points(summaries, max_points=max_points)
389
-
390
- return {
391
- "success": True,
392
- "filename": file.filename,
393
- "original_length": len(text),
394
- "word_count": len(text.split()),
395
- "num_chunks": len(summaries),
396
- "length_level": length_level,
397
- "summary": bullet_points
398
- }
399
 
400
 
401
  # ============================================================
 
7
  from typing import Optional
8
  from fastapi import FastAPI, File, UploadFile, HTTPException
9
  from fastapi.middleware.cors import CORSMiddleware
10
+ from fastapi.responses import StreamingResponse
11
  from pydantic import BaseModel
12
  from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
13
  import torch
14
  import fitz # PyMuPDF
15
+ import json
16
+ import gc
17
+ import asyncio
18
 
19
  # ============================================================
20
  # Initialize FastAPI App
 
307
  detail="Văn bản quá ngắn để tóm tắt (cần ít nhất 50 ký tự)."
308
  )
309
 
310
+ # Return StreamingResponse
311
+ return StreamingResponse(
312
+ stream_summary_generator(text, max_points),
313
+ media_type="application/x-ndjson"
314
+ )
315
+
316
+
317
+ async def stream_summary_generator(text: str, max_points: int = None):
318
+ """
319
+ Generator function to stream summary chunks.
320
+ Implements: Recursive chunking, Context-aware summarization, Memory optimization.
321
+ YIELDS JSON: {"text": "• Point 1\n", "done": False} + "\n"
322
+ """
323
+ chunks = chunk_text_by_words(text, max_words=800)
324
+ total_chunks = len(chunks)
325
 
326
+ # Context cho chunk tiếp theo (summary của chunk trước)
327
+ context_summary = ""
 
 
 
328
 
329
+ bullet_count = 0
 
330
 
331
+ for i, chunk in enumerate(chunks):
332
+ # 1. Prepare input: Context + Current Chunk
333
+ # Nếu có context, nối vào đầu chunk (có phân cách)
334
+ if context_summary:
335
+ # Giới hạn context để tránh quá dài (lấy 200 ký tự cuối của summary trước)
336
+ short_context = context_summary[-200:] if len(context_summary) > 200 else context_summary
337
+ input_text = f"Tóm tắt tiếp theo ngữ cảnh: {short_context}\nNội dung: {chunk}"
338
+ else:
339
+ input_text = chunk
340
+
341
+ # 2. Generate Summary
342
+ # Chạy trong threadpool để không chặn event loop của FastAPI
343
+ try:
344
+ summary_part = await asyncio.to_thread(generate_summary, input_text)
345
+ except Exception as e:
346
+ error_json = json.dumps({"error": str(e), "done": True})
347
+ yield error_json + "\n"
348
+ return
349
+
350
+ # 3. Format as bullets
351
+ # Chỉ lấy max_points còn lại nếu có giới hạn
352
+ points_limit = None
353
+ if max_points is not None:
354
+ points_limit = max_points - bullet_count
355
+ if points_limit <= 0:
356
+ break # Đã đủ số ý
357
+
358
+ bullets_text = format_as_bullet_points([summary_part], max_points=points_limit)
359
+
360
+ if bullets_text:
361
+ # Update context for next iteration
362
+ context_summary = summary_part.replace('\n', ' ')
363
+
364
+ # Count bullets
365
+ new_points = bullets_text.count('•')
366
+ bullet_count += new_points
367
+
368
+ # Yield Result
369
+ result_json = json.dumps({
370
+ "text": bullets_text + "\n",
371
+ "done": False,
372
+ "progress": int((i + 1) / total_chunks * 100)
373
+ })
374
+ yield result_json + "\n"
375
+
376
+ # 4. Memory Optimization
377
+ try:
378
+ del input_text
379
+ del summary_part
380
+ except UnboundLocalError:
381
+ pass
382
+ gc.collect() # Force garbage collection
383
+
384
+ # Nhường CPU cho request khác 1 chút
385
+ await asyncio.sleep(0.1)
386
+
387
+ # Final message
388
+ yield json.dumps({"text": "", "done": True, "progress": 100}) + "\n"
389
 
390
 
391
  @app.post("/upload-pdf")
 
393
  """
394
  Upload và tóm tắt file PDF.
395
  Đọc qua byte stream, KHÔNG lưu file ra đĩa.
396
+ Trả về StreamingResponse (NDJSON).
397
  length_level: 0 = Ngắn (2-3 ý), 1 = Trung bình (4-5 ý), 2 = Chi tiết (6+ ý)
398
  """
399
  # Map length_level to max_points
 
428
  detail="File quá lớn. Giới hạn 10MB."
429
  )
430
 
431
+ # Extract text from PDF bytes
432
  text = extract_text_from_pdf_bytes(contents)
433
 
434
  # Validate extracted text
 
438
  detail="Văn bản trích xuất từ PDF quá ngắn."
439
  )
440
 
441
+ # Return StreamingResponse
442
+ return StreamingResponse(
443
+ stream_summary_generator(text, max_points),
444
+ media_type="application/x-ndjson"
445
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
446
 
447
 
448
  # ============================================================