精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Python+FAISS:五分鐘打造一個RAG系統

發布于 2025-9-17 00:02
瀏覽
0收藏

我遇到個麻煩:手頭有幾十(好吧,實際上是幾百)個 PDF 文件——研究論文、API 文檔、白皮書——散落在各個文件夾里。搜索慢得要死,瀏覽更煩。所以我搞了個 PDF 問答引擎,能把文件吃進去、分塊、嵌入、用 FAISS 索引、找最佳段落,還能給個簡潔的回答(而且有不用 API 的備選方案)。這篇文章把所有東西都給你——端到端的代碼,用大白話解釋清楚。

你能得到啥

? 本地 PDF 加載(不用云)

? 更聰明的分塊(保留上下文)

? 用 sentence-transformers 做 embeddings

? 用 FAISS 做向量搜索(cosine)+ SQLite 存 metadata

? Retriever → Answerer,支持可選 LLM(有 extractive summary 備選)

? 用 Gradio 做個簡潔的單頁 app

關鍵詞(方便別人找到這篇):AI document search, PDF search, vector database, FAISS, embeddings, Sentence Transformers, RAG, Gradio, OpenAI(可選)。

項目結構(直接復制成文件)

pdfqa/
  settings.py
  loader.py
  chunker.py
  embedder.py
  store.py
  searcher.py
  answerer.py
  app.py
  build_index.py
  requirements.txt

0) 環境要求

# requirements.txt
pdfplumber>=0.11.0
sentence-transformers>=3.0.1
faiss-cpu>=1.8.0
numpy>=1.26.4
scikit-learn>=1.5.1
tqdm>=4.66.4
gradio>=4.40.0
python-dotenv>=1.0.1
nltk>=3.9.1
rank-bm25>=0.2.2
openai>=1.40.0     # 可選;不用 API key 也能跑

安裝并準備 NLTK(只需一次):

python -c "import nltk; nltk.download('punkt_tab')" || python -c "import nltk; nltk.download('punkt')"

1) 設置

# settings.py
from pathlib import Path
from dataclasses import dataclass

@dataclass(frozen=True)
class Config:
    PDF_DIR: Path = Path("./pdfs")                 # 放你的 PDF 文件
    DB_PATH: Path = Path("./chunks.sqlite")        # SQLite 存 chunk metadata
    INDEX_PATH: Path = Path("./index.faiss")       # FAISS 索引文件
    MODEL_NAME: str = "sentence-transformers/all-MiniLM-L12-v2"
    CHUNK_SIZE: int = 1000                         # 每塊目標字符數
    CHUNK_OVERLAP: int = 200
    TOP_K: int = 4                                 # 檢索的段落數
    MAX_ANSWER_TOKENS: int = 500                   # 用于 LLM
CFG = Config()

2) 加載 PDF(本地,超快)

# loader.py
import pdfplumber
from pathlib import Path
from typing importList, Dict
from settings import CFG

defload_pdfs(pdf_dir: Path = CFG.PDF_DIR) -> List[Dict]:
    pdf_dir.mkdir(parents=True, exist_ok=True)
    docs = []
    for pdf_path insorted(pdf_dir.glob("*.pdf")):
        text_parts = []
        with pdfplumber.open(pdf_path) as pdf:
            for page in pdf.pages:
                # 比簡單 get_text 更穩;可根據需要調整
                text_parts.append(page.extract_text() or"")
        text = "\n".join(text_parts).strip()
        if text:
            docs.append({"filename": pdf_path.name, "text": text})
            print(f"? 加載 {pdf_path.name} ({len(text)} 字符)")
        else:
            print(f"?? 空的或無法提取:{pdf_path.name}")
    return docs

if __name__ == "__main__":
    load_pdfs()

3) 分塊,保留上下文(段落感知)

# chunker.py
from typing importList, Dict
from settings import CFG

def_paragraphs(txt: str) -> List[str]:
    # 按空行分割;保持結構輕量
    blocks = [b.strip() for b in txt.split("\n\n") if b.strip()]
    return blocks or [txt]

defchunk_document(doc: Dict, size: int = CFG.CHUNK_SIZE, overlap: int = CFG.CHUNK_OVERLAP) -> List[Dict]:
    paras = _paragraphs(doc["text"])
    chunks = []
    buf, start_char = [], 0
    cur_len = 0

    for p in paras:
        if cur_len + len(p) + 1 <= size:
            buf.append(p)
            cur_len += len(p) + 1
            continue
        # 清空緩沖
        block = "\n\n".join(buf).strip()
        if block:
            chunks.append({
                "filename": doc["filename"],
                "start": start_char,
                "end": start_char + len(block),
                "text": block
            })
        # 從尾部創建重疊部分
        tail = block[-overlap:] if overlap > 0andlen(block) > overlap else""
        buf = [tail, p] if tail else [p]
        start_char += max(0, len(block) - overlap)
        cur_len = len("\n\n".join(buf))

    # 最后一塊
    block = "\n\n".join(buf).strip()
    if block:
        chunks.append({
            "filename": doc["filename"],
            "start": start_char,
            "end": start_char + len(block),
            "text": block
        })
    return chunks

defchunk_all(docs: List[Dict]) -> List[Dict]:
    out = []
    for d in docs:
        out.extend(chunk_document(d))
    print(f"?? 創建了 {len(out)} 個 chunk")
    return out

if __name__ == "__main__":
    from loader import load_pdfs
    all_chunks = chunk_all(load_pdfs())

4) 嵌入(支持 cosine)

# embedder.py
import numpy as np
from typing importList, Dict
from sentence_transformers import SentenceTransformer
from settings import CFG
from tqdm import tqdm
from sklearn.preprocessing import normalize

_model = None

defget_model() -> SentenceTransformer:
    global _model
    if _model isNone:
        _model = SentenceTransformer(CFG.MODEL_NAME)
    return _model

defembed_texts(chunks: List[Dict]) -> np.ndarray:
    model = get_model()
    texts = [c["text"] for c in chunks]
    # encode → L2 歸一化,確保 Inner Product == Cosine similarity
    vecs = model.encode(texts, show_progress_bar=True, convert_to_numpy=True)
    return normalize(vecs)  # 對 IndexFlatIP 很重要

5) 存儲向量 + metadata(FAISS + SQLite)

# store.py
import sqlite3
import faiss
import numpy as np
from typing importList, Dict
from settings import CFG

definit_db():
    con = sqlite3.connect(CFG.DB_PATH)
    cur = con.cursor()
    cur.execute("""
      CREATE TABLE IF NOT EXISTS chunks (
        id INTEGER PRIMARY KEY,
        filename TEXT,
        start INTEGER,
        end INTEGER,
        text TEXT
      )
    """)
    con.commit()
    con.close()

defsave_chunks(chunks: List[Dict]):
    con = sqlite3.connect(CFG.DB_PATH)
    cur = con.cursor()
    cur.execute("DELETE FROM chunks")
    cur.executemany(
        "INSERT INTO chunks (filename, start, end, text) VALUES (?,?,?,?)",
        [(c["filename"], c["start"], c["end"], c["text"]) for c in chunks]
    )
    con.commit()
    con.close()

defbuild_faiss_index(vecs: np.ndarray):
    dim = vecs.shape[1]
    index = faiss.IndexFlatIP(dim)  # cosine(因為我們歸一化了向量)
    index.add(vecs.astype(np.float32))
    faiss.write_index(index, str(CFG.INDEX_PATH))
    print(f"?? FAISS 索引保存到 {CFG.INDEX_PATH}")

defread_faiss_index() -> faiss.Index:
    return faiss.read_index(str(CFG.INDEX_PATH))

defget_chunk_by_ids(ids: List[int]) -> List[Dict]:
    con = sqlite3.connect(CFG.DB_PATH)
    cur = con.cursor()
    rows = []
    for i in ids:
        cur.execute("SELECT id, filename, start, end, text FROM chunks WHERE id=?", (i+1,))
        r = cur.fetchone()
        if r:
            rows.append({
                "id": r[0]-1, "filename": r[1], "start": r[2], "end": r[3], "text": r[4]
            })
    con.close()
    return rows

注意:SQLite 的 row ID 從 1 開始;FAISS 向量從 0 開始索引。我們按插入順序存儲 → 查詢時用 (faiss_id + 1)。

6) 搜索(嵌入查詢 → 找最近鄰)

# searcher.py
import numpy as np
import faiss
from sentence_transformers import SentenceTransformer
from sklearn.preprocessing import normalize
from settings import CFG
from store import read_faiss_index, get_chunk_by_ids

_qmodel = None
def_qembed(q: str) -> np.ndarray:
    global _qmodel
    if _qmodel isNone:
        _qmodel = SentenceTransformer(CFG.MODEL_NAME)
    qv = _qmodel.encode([q], convert_to_numpy=True)
    return normalize(qv)  # cosine,和 corpus 一致

defsearch(query: str, k: int = CFG.TOP_K):
    index: faiss.Index = read_faiss_index()
    qv = _qembed(query)
    D, I = index.search(qv.astype(np.float32), k)
    ids = I[0].tolist()
    return get_chunk_by_ids(ids)

7) 回答生成(可選 LLM + extractive 備選)

# answerer.py
import os, re
from typing importList, Dict
from rank_bm25 import BM25Okapi

SYSTEM_PROMPT = (
"你只能從提供的上下文回答。\n"
"引用段落用 [1], [2], ...,按片段順序。\n"
"如果信息不足,簡短說明。\n"
)

def_try_openai(question: str, snippets: List[str]) -> str:
    try:
        from openai import OpenAI
        client = OpenAI()  # 需要環境變量 OPENAI_API_KEY
        ctx = "\n\n".join(f"[{i+1}] {s}"for i, s inenumerate(snippets))
        prompt = f"{SYSTEM_PROMPT}\nContext:\n{ctx}\n\nQuestion: {question}\nAnswer:"
        resp = client.chat.completions.create(
            model=os.getenv("LLM_MODEL", "gpt-4o-mini"),
            messages=[{"role": "user", "content": prompt}],
            temperature=0.2,
            max_tokens=500
        )
        return resp.choices[0].message.content
    except Exception:
        return""

def_extractive_fallback(question: str, snippets: List[str]) -> str:
    # 用 BM25 給片段中的句子評分,拼接成簡短總結
    sents, source_ids = [], []
    for i, s inenumerate(snippets):
        for sent in re.split(r"(?<=[.!?])\s+", s):
            if sent.strip():
                sents.append(sent.strip())
                source_ids.append(i)
    tokenized = [st.lower().split() for st in sents]
    bm25 = BM25Okapi(tokenized)
    scores = bm25.get_scores(question.lower().split())
    ranked = sorted(zip(sents, source_ids, scores), key=lambda x: x[2], reverse=True)[:6]
    stitched = []
    used_sources = set()
    for sent, sid, _ in ranked:
        stitched.append(sent + f" [{sid+1}]")
        used_sources.add(sid+1)
    return" ".join(stitched) or"我沒有足夠的信息來回答。"

defanswer(question: str, passages: List[Dict]) -> str:
    snippets = [p["text"] for p in passages]
    ans = _try_openai(question, snippets)
    return ans if ans.strip() else _extractive_fallback(question, snippets)

8) 構建腳本(一次性索引)

# build_index.py
from loader import load_pdfs
from chunker import chunk_all
from embedder import embed_texts
from store import init_db, save_chunks, build_faiss_index

if __name__ == "__main__":
    docs = load_pdfs()
    chunks = chunk_all(docs)
    init_db()
    save_chunks(chunks)
    vecs = embed_texts(chunks)
    build_faiss_index(vecs)
    print("? 索引完成!可以開始提問了!")

運行:

python build_index.py

9) 簡潔的 Web 應用(Gradio)

# app.py
import gradio as gr
from searcher import search
from answerer import answer

defask(query: str):
    ifnot query.strip():
        return"輸入一個問題開始吧。", ""
    results = search(query, k=4)
    ctx = "\n\n---\n\n".join([r["text"] for r in results])
    ans = answer(query, results)
    cites = "\n".join(f"[{i+1}] {r['filename']} ({r['start']}–{r['end']})"for i, r inenumerate(results))
    return ans, cites

with gr.Blocks(title="PDF Q&A") as demo:
    gr.Markdown("## ?? PDF Q&A — 從你的文檔中問任何問題")
    inp = gr.Textbox(label="你的問題", placeholder="例如:解釋 transformers 中的 attention")
    btn = gr.Button("搜索并回答")
    out = gr.Markdown(label="回答")
    refs = gr.Markdown(label="引用")
    btn.click(fn=ask, inputs=inp, outputs=[out, refs])

if __name__ == "__main__":
    demo.launch()

運行:

python app.py

我學到的經驗(別重蹈我的覆轍)

?檢索質量 = 回答質量。精準的 top-k 比花哨的 prompt 更重要。

?分塊是個平衡游戲。段落感知的合并加上小范圍重疊,既好讀又保留上下文。

?Cosine + 歸一化很重要。對 embeddings 做 L2 歸一化,用 IndexFlatIP 確保 FAISS 里的 cosine 準確。

?可選 LLM,強制備選。別讓工具依賴 API key。extractive 方案 + BM25 句子排序效果意外不錯。

?Metadata 省時間。存好 (filename, start, end),就能立刻深鏈或顯示引用。

下一步升級

? 語義分塊(支持標題、目錄感知)

? Rerankers(Cohere Rerank 或 BGE cross-encoder)優化最終列表

? 對話記憶(支持后續問題)

? 用 vector DB 持久化(Weaviate, Qdrant 等)

? 服務端部署(Docker + 小型 FastAPI 包裝)

小 FAQ

可以完全離線跑嗎?可以。Embeddings + FAISS + extractive 備選都是本地的,LLM 是可選的。

能處理幾千個 chunk 嗎?可以。FAISS 在 CPU 上擴展很好。如果數據量超大,換成 IVF 或 HNSW 索引。

為啥用 Gradio,不用 Streamlit?Gradio 輕量、連接快。用你喜歡的工具——移植很簡單。

幾個有用的官方文檔鏈接

? Sentence Transformers: https://www.sbert.net/

? FAISS: https://github.com/facebookresearch/faiss

? Gradio: https://www.gradio.app/

本文轉載自??PyTorch研習社??,作者:AI研究生

已于2025-9-17 00:02:45修改
收藏
回復
舉報
回復
相關推薦
在线视频1卡二卡三卡| 综合操久久久| 久久久久久不卡| 99re8这里有精品热视频8在线| 一区二区三区鲁丝不卡| 成人午夜电影在线播放| 国产精品30p| 欧美wwwsss9999| 在线亚洲一区观看| 日韩欧美99| 国产乱码久久久| 亚洲福利精品| 色综久久综合桃花网| 国产综合内射日韩久| 久久精品女人天堂av免费观看| 国产精品理伦片| 国产伦精品一区二区三区高清版 | 国产又大又黑又粗| 亚洲精品孕妇| 色系列之999| 天天躁日日躁狠狠躁免费麻豆| 国产精选在线| 国产精品看片你懂得| 国产高清精品一区| 中文字幕一区二区久久人妻| 日韩精品免费一区二区三区| 欧美疯狂性受xxxxx喷水图片| 福利视频一区二区三区四区| 91美女视频在线| 99r国产精品| 国产精品私拍pans大尺度在线| 久久久精品99| 久久网站免费观看| 亚洲激情视频在线播放| 男生操女生视频在线观看| 蜜桃视频在线观看播放| 亚洲欧美另类综合偷拍| 国产精品永久入口久久久| 岳乳丰满一区二区三区| 亚洲成人直播| 欧美精品日韩三级| 在线 丝袜 欧美 日韩 制服| 久久影院一区二区三区| 日韩欧美极品在线观看| 99视频精品全部免费看| 国产原创av在线| 成人av资源站| 91美女高潮出水| 中国一级特黄视频| 爽好多水快深点欧美视频| 午夜免费久久久久| 黄色一级视频在线观看| 91精品成人| 久久精品国产一区二区三区| 久久午夜精品视频| 精品高清在线| 尤物yw午夜国产精品视频明星| 精品一区二区视频在线观看| 国产精品高清一区二区| 在线播放国产精品二区一二区四区| www日韩在线观看| 欧美色网一区| 欧美性极品少妇精品网站| 国产原创中文在线观看| h片在线观看视频免费免费| 国产精品入口麻豆原神| 亚洲欧美成人一区| 精品亚洲综合| 久久综合九色综合欧美98| 久久久7777| 日韩一区av| 国产日韩欧美激情| 亚洲va韩国va欧美va精四季| √新版天堂资源在线资源| 日本一二三不卡| 亚洲午夜精品久久| 麻豆视频在线免费观看| 亚洲欧洲精品一区二区三区| 一区二区免费在线观看| 麻豆网在线观看| 一区二区三区av电影| 阿v天堂2018| 三级在线看中文字幕完整版| 在线欧美一区二区| 国产原创精品在线| 国产精品一区二区三区www| 91精品国产欧美日韩| 伊人久久久久久久久| 久久影院资源站| 亚洲免费一在线| 无码人妻精品一区二区中文| 日韩成人免费| 久久成人国产精品| 日本免费一二三区| 久久久天天操| 成人国产精品日本在线| 精品人妻午夜一区二区三区四区| 97精品超碰一区二区三区| 成人h在线播放| 久久久久久久影视| 中文字幕亚洲一区二区av在线| 日本精品福利视频| 中文字幕在线免费观看视频| 欧美图区在线视频| 激情久久综合网| 亚欧日韩另类中文欧美| 久久国产精品99国产精| 神马久久久久久久| 国产91丝袜在线观看| 久久99精品久久久久久三级| www在线免费观看视频| 色综合视频在线观看| www日本在线观看| 国产精品99一区二区三区| 91a在线视频| 国产日韩欧美视频在线观看| 久久久噜噜噜久噜久久综合| 分分操这里只有精品| 日韩黄色在线| 亚洲精品网站在线播放gif| 久久久久亚洲天堂| 国产在线视频一区二区三区| 日韩福利影院| 成人免费无遮挡| 欧美精品一区男女天堂| www青青草原| 美女视频黄久久| 青青影院一区二区三区四区| h片在线观看| 日韩免费观看高清完整版在线观看| 后入内射无码人妻一区| 丝袜美腿亚洲综合| 鲁丝一区二区三区免费| 懂色av一区| 日韩欧美一区二区视频| 国产黄a三级三级| 人禽交欧美网站| 神马影院午夜我不卡| 日韩美女在线看免费观看| 日韩精品福利在线| 日韩视频免费观看高清| www.久久精品| 僵尸世界大战2 在线播放| 一区二区三区国产好| 伦伦影院午夜日韩欧美限制| 91精品中文字幕| 成人欧美一区二区三区黑人麻豆| 性生活免费在线观看| 欧洲激情视频| 91精品久久久久久久久青青| 91最新在线| 欧美日韩高清不卡| 五月天色婷婷丁香| 国产一区二区三区久久久| 看一级黄色录像| 亚洲视频精选| 国外成人在线视频| 香蕉av一区二区三区| 欧美性色视频在线| 88久久精品无码一区二区毛片| 日日骚欧美日韩| 视频一区视频二区视频三区视频四区国产 | 91av在线免费观看| 黄片毛片在线看| 亚洲电影激情视频网站| 日本黄色录像片| 久久午夜激情| 自拍偷拍一区二区三区| 91精品国产自产精品男人的天堂 | 亚洲人成人99网站| 亚洲中文无码av在线| 国产精品久久久久久久久免费丝袜| 国产传媒免费观看| 亚洲特色特黄| 欧美日韩综合另类| 亚洲电影二区| 久久人人爽人人爽人人片av高请| 婷婷色在线观看| 在线精品视频免费播放| 任我爽在线视频| 成人精品视频.| 亚洲人成无码www久久久| 欧美gayvideo| 国产一区在线免费| 91精品国产66| 久久久久久久久久久人体 | 欧美国产视频日韩| 青青草在线视频免费观看| 欧美日韩三级一区二区| 国产性一乱一性一伧一色| 久久综合九色欧美综合狠狠 | 丁香另类激情小说| 黄色高清无遮挡| 国产综合网站| 亚洲v国产v| 玖玖玖免费嫩草在线影院一区| 国产精品视频网| 成人免费一区二区三区牛牛| 国产亚洲精品综合一区91| 精品人妻午夜一区二区三区四区| 欧美性猛交xxxx富婆| 麻豆成人在线视频| 国产丝袜美腿一区二区三区| 在线播放av网址| 免费成人美女在线观看.| 国产精品又粗又长| 久久久9色精品国产一区二区三区| 久久国产精品亚洲va麻豆| 色综合视频一区二区三区日韩 | 亚洲成a人片777777久久| 69视频在线播放| 爆操欧美美女| 色偷偷888欧美精品久久久| 日韩av资源| 日韩欧美亚洲国产精品字幕久久久 | 欧美三级乱码| 亚洲蜜桃av| 国产精品午夜一区二区三区| 国产精品三区四区| 日韩高清一区| 国产美女91呻吟求| 欧美aaa视频| 97色在线观看| 久久亚洲资源| 久久天天躁日日躁| 淫片在线观看| 国产亚洲欧美日韩精品| 亚洲欧洲精品视频| 精品处破学生在线二十三| 国产欧美熟妇另类久久久 | 亚洲av成人无码网天堂| 日韩一区二区在线观看| 91麻豆视频在线观看| 欧美在线高清视频| 一区二区三区在线观看av| 黄色91在线观看| 福利一区二区三区四区| 亚洲午夜在线视频| 国产一级在线视频| 亚洲午夜在线观看视频在线| 欧美成人国产精品高潮| 亚洲视频在线一区| 乱h高h女3p含苞待放| 日韩一区在线看| 国产探花视频在线| 国产精品天美传媒| 日日碰狠狠添天天爽| 国产精品麻豆网站| 久久一级免费视频| 亚洲欧美日韩中文字幕一区二区三区| 天堂av免费在线| 亚洲天堂福利av| 日本青青草视频| 亚洲制服欧美中文字幕中文字幕| 加勒比av在线播放| 亚洲成人免费在线| 亚洲黄色免费观看| 欧美视频第二页| 91精品国产乱码久久久| 欧美一区欧美二区| 亚洲精品一区二区三区蜜桃| 亚洲国产精品女人久久久| 视频三区在线观看| 亚洲一区999| 麻豆视频在线免费观看| 久精品免费视频| 九色porny丨首页入口在线| 欧洲亚洲女同hd| 国产亚洲精彩久久| 亚洲一区亚洲二区| 欧美中文一区| 亚洲精品免费在线看| 欧美 亚欧 日韩视频在线| 国产乱子伦农村叉叉叉| 日韩精品一区第一页| 想看黄色一级片| 成人丝袜18视频在线观看| 成人午夜福利一区二区| 国产精品成人在线观看| 国产精品50页| 欧美在线观看一区二区| 国产丰满果冻videossex| 日韩黄色在线免费观看| 日本福利专区在线观看| 欧美精品videossex性护士| 日韩大尺度黄色| 91免费看国产| 岳的好大精品一区二区三区| 一道精品一区二区三区| 亚洲黄色精品| 欧美美女性视频| 91免费版在线| 亚洲天堂一级片| 欧美午夜美女看片| 国产女无套免费视频| 亚洲欧美在线播放| 综合久久2o19| 国产精品国产三级国产专播精品人 | caoporn-草棚在线视频最| 国产精国产精品| jizz性欧美23| 中文字幕一区二区三区乱码| 日韩亚洲国产欧美| 国产精品自在自线| 久久免费电影网| 国产精品成人久久| 91精品国产综合久久久蜜臀图片| 亚洲 小说区 图片区 都市| 久久精品国产亚洲| 国产一区一一区高清不卡| 国产欧美亚洲日本| 91成人免费| 热久久久久久久久| 久久久www成人免费毛片麻豆 | 免费av在线网址| 国产福利精品在线| 一本一道久久久a久久久精品91| 成年人午夜视频| 日韩欧美高清| 中文字幕欧美日韩一区二区三区| 国产欧美成人| 久久精品aⅴ无码中文字字幕重口| 国产亚洲成aⅴ人片在线观看| 国产网址在线观看| 日韩欧美成人一区| 国产黄色在线观看| 国产一区二区香蕉| 成人嘿咻视频免费看| 国产熟女高潮视频| 99久久精品情趣| 国产一卡二卡在线| 亚洲成人性视频| 国精一区二区三区| 99re视频在线| 欧美成人一品| 日本少妇激三级做爰在线| 中文一区二区完整视频在线观看| 免费黄色av片| 亚洲欧美日韩精品久久| 原纱央莉成人av片| 精品一区二区视频| 在线亚洲观看| 中文字幕 亚洲一区| 高跟丝袜一区二区三区| 天天干视频在线观看| 91精品国产色综合久久不卡98口| 国产精品天天看天天狠| 少妇高潮喷水在线观看| jlzzjlzz国产精品久久| 日韩少妇裸体做爰视频| 日韩精品福利在线| 日本综合久久| 亚洲一区二区免费视频软件合集| 蜜桃91丨九色丨蝌蚪91桃色| 国产精品成人在线视频| 欧美精品欧美精品系列| 国产激情小视频在线| 超碰97在线人人| 99国产精品久久久久久久| 精品人妻一区二区三区香蕉| 在线免费观看一区| 在线观看美女网站大全免费| 成人免费淫片视频软件| 狠狠爱www人成狠狠爱综合网| 成年人小视频在线观看| 欧美日韩国产在线看| 成人欧美一区| 91精品视频免费观看| 国内久久视频| 亚洲av无码国产精品久久| 欧美亚洲愉拍一区二区| 黄色成人在线| 国产伦精品一区二区三区视频黑人 | 激情综合色播五月| 国产精品50页| 国产一区二区三区在线观看视频| 9999精品| 男女视频网站在线观看| 国产婷婷一区二区| 国产超碰人人模人人爽人人添| 26uuu亚洲伊人春色| 欧美激情黄色片| 亚洲精品乱码久久久久久不卡| 91久久精品日日躁夜夜躁欧美| 国产精品剧情一区二区在线观看| 国产亚洲精品久久飘花| 日本三级亚洲精品| 精品无码m3u8在线观看| 亚洲欧美国产日韩天堂区| 91精品国产一区二区在线观看| 成年人午夜免费视频| 欧美国产日韩在线观看| 亚洲免费成人网| 国产精品久久久久久久久久尿 | 91tv亚洲精品香蕉国产一区7ujn| 成人高清电影网站| 性色av蜜臀av色欲av| 在线成人高清不卡| 日韩精品一区二区三区| 中文字幕在线中文|