Spaces:
Build error
Build error
File size: 5,820 Bytes
420a76d 5564d41 420a76d 5564d41 61935d4 420a76d 5564d41 61935d4 420a76d 5564d41 3d59ca3 5564d41 420a76d 5564d41 420a76d 1ad2e0c 3d59ca3 420a76d 5564d41 61935d4 420a76d 5564d41 3d59ca3 5564d41 3d59ca3 420a76d 5564d41 420a76d 3d59ca3 caeff2f 3d59ca3 420a76d 61935d4 420a76d 5564d41 e68ec86 61935d4 420a76d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
import gradio as gr
import pandas as pd
from datetime import datetime
import json
import io
from PIL import Image
import pytesseract
from huggingface_hub import hf_hub_download # Thư viện mới
from llama_cpp import Llama # Thư viện mới
# --- CẤU HÌNH VÀ TẢI MÔ HÌNH (SỬ DỤNG LLAMA.CPP) ---
print("Ứng dụng đang khởi động...")
# OCR không thay đổi
print("Sử dụng Tesseract OCR (siêu nhẹ).")
# THAY ĐỔI LỚN: DÙNG LLAMA-CPP-PYTHON
print("Đang tải mô hình LLM (Llama-3-8B GGUF for CPU)...")
model_repo = "bartowski/Meta-Llama-3-8B-Instruct-GGUF"
model_file = "Meta-Llama-3-8B-Instruct-Q4_K_M.gguf"
# Tải file mô hình về cache của Space
model_path = hf_hub_download(repo_id=model_repo, filename=model_file)
print(f"Đã tải xong file mô hình tại: {model_path}")
# Khởi tạo mô hình từ file đã tải
llm = Llama(
model_path=model_path,
n_ctx=4096, # Context length
n_gpu_layers=0, # Chạy hoàn toàn trên CPU
verbose=True, # In ra thông tin để debug
)
print("Tải xong và khởi tạo thành công mô hình LLM.")
# --- CÁC HÀM XỬ LÝ ---
def run_ocr(image: Image.Image) -> str:
# (Giữ nguyên)
try:
text = pytesseract.image_to_string(image)
return text
except Exception as e:
print(f"Lỗi Tesseract: {e}")
return "Lỗi khi đọc chữ từ ảnh."
def extract_order_from_text(text: str) -> dict:
# Cập nhật prompt và cách gọi cho Llama.cpp
prompt = f"""<|begin_of_text|><|start_header_id|>system<|end_header_id|>
You are an expert assistant that only outputs valid JSON. Extract order information from the text. The JSON object must contain "ten_khach_hang" (string, null if not found) and "danh_sach_hang" (an array of items). Each item must have "ten_hang" (string), "so_luong" (number), "don_vi" (string), "ma_hang" (string, null if not found), and "ghi_chu" (string, null if not found).<|eot_id|><|start_header_id|>user<|end_header_id|>
Text Content:
{text}<|eot_id|><|start_header_id|>assistant<|end_header_id|>
"""
output = llm(
prompt,
max_tokens=1024,
stop=["<|eot_id|>"],
temperature=0.1,
echo=False # Không in lại prompt trong kết quả
)
response_text = output['choices'][0]['text']
try:
json_str = response_text.strip()
start = json_str.find('{')
end = json_str.rfind('}') + 1
if start != -1 and end != 0:
json_str = json_str[start:end]
return json.loads(json_str)
except json.JSONDecodeError:
return {"error": "AI trả về định dạng không hợp lệ", "raw_response": response_text}
def create_excel_file(order_data: dict):
# (Giữ nguyên)
if not order_data or "danh_sach_hang" not in order_data or not order_data["danh_sach_hang"]: return None
flat_data = []
customer = order_data.get('ten_khach_hang', 'N/A')
for item in order_data['danh_sach_hang']:
flat_data.append({
'Khách hàng': customer, 'Mã hàng': item.get('ma_hang'),
'Tên hàng': item.get('ten_hang'), 'Số lượng': item.get('so_luong'),
'Đơn vị': item.get('don_vi'), 'Ghi chú': item.get('ghi_chu')
})
df = pd.DataFrame(flat_data)
output = io.BytesIO()
with pd.ExcelWriter(output, engine='openpyxl') as writer: df.to_excel(writer, index=False, sheet_name='DonHang')
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"don_hang_{timestamp}.xlsx"
return (filename, output.getvalue())
def process_image_and_extract(image):
# (Giữ nguyên)
try:
if image is None: return "Vui lòng dán ảnh vào.", None, None
extracted_text = run_ocr(image)
if not extracted_text.strip(): return "Không đọc được chữ từ hình ảnh.", None, None
order_data = extract_order_from_text(extracted_text)
if "error" in order_data: return extracted_text, f"Lỗi từ AI: {order_data['error']}\nPhản hồi gốc: {order_data['raw_response']}", None
excel_info = create_excel_file(order_data)
df_display = pd.DataFrame(order_data.get('danh_sach_hang', []))
if excel_info:
filename, filebytes = excel_info
with open(filename, "wb") as f: f.write(filebytes)
return extracted_text, df_display, filename
else: return extracted_text, df_display, None
except Exception as e:
import traceback
error_str = str(e)
traceback_str = traceback.format_exc()
print(traceback_str)
return f"Lỗi nghiêm trọng: {error_str}", None, None
# --- XÂY DỰNG GIAO DIỆN GRADIO (GIỮ NGUYÊN) ---
with gr.Blocks(theme=gr.themes.Soft()) as app:
gr.Markdown("# Ứng dụng Trích xuất Đơn hàng từ Ảnh chụp màn hình")
gr.Markdown("Chụp màn hình email/tin nhắn đặt hàng, sau đó dán (Ctrl+V) vào ô bên dưới và nhấn 'Xử lý'.")
with gr.Row():
with gr.Column(scale=1):
image_input = gr.Image(label="Dán ảnh chụp màn hình vào đây", type="pil", sources=["clipboard", "upload"])
process_btn = gr.Button("Xử lý", variant="primary")
with gr.Column(scale=2):
gr.Markdown("### Kết quả trích xuất")
output_table = gr.DataFrame(label="Chi tiết đơn hàng")
output_excel = gr.File(label="Tải file Excel")
gr.Markdown("### Văn bản đọc được từ ảnh (OCR)")
output_text = gr.Textbox(label="Text from Image", lines=10, interactive=False)
process_btn.click(fn=process_image_and_extract, inputs=image_input, outputs=[output_text, output_table, output_excel])
app.launch(debug=True) |