eli02 commited on
Commit
3145903
·
0 Parent(s):

Initial commit.

Browse files
.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ .venv
Dockerfile ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use the official Python 3.9 image
2
+ FROM python:3.9
3
+
4
+ # Set the working directory to /code
5
+ WORKDIR /code
6
+
7
+ # Copy the current directory contents into the container at /code
8
+ COPY ./requirements.txt /code/requirements.txt
9
+
10
+ # Install requirements.txt
11
+ RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
12
+
13
+ # Set up a new user named "user" with user ID 1000
14
+ RUN useradd -m -u 1000 user
15
+ # Switch to the "user" user
16
+ USER user
17
+ # Set home to the user's home directory
18
+ ENV HOME=/home/user \
19
+ PATH=/home/user/.local/bin:$PATH
20
+
21
+ # Set the working directory to the user's home directory
22
+ WORKDIR $HOME/app
23
+
24
+ # Copy the current directory contents into the container at $HOME/app setting the owner to the user
25
+ COPY --chown=user . $HOME/app
26
+
27
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
README.md ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Al Ghazali Rag Retrieval Api
3
+ emoji: 🔗
4
+ colorFrom: indigo
5
+ colorTo: blue
6
+ sdk: docker
7
+ app_port: 7860
8
+ pinned: false
9
+ license: unknown
10
+ ---
11
+
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
13
+
14
+ # Al Ghazali Rag Retrieval Api
15
+
16
+ ## Endpoints
17
+
18
+ ### 1. `/login` Endpoint
19
+ This endpoint is used to authenticate the user and issue an access token and a refresh token.
20
+
21
+ #### Request:
22
+ ```bash
23
+ curl -X POST https://humblebeeai-al-ghazali-rag-retrieval-api.hf.space/login \
24
+ -H "Content-Type: application/x-www-form-urlencoded" \
25
+ -d 'username=user1332&password=RmzmurS7aE!t'
26
+ ```
27
+
28
+ #### Response:
29
+ If the credentials are valid, the server responds with:
30
+ ```json
31
+ {
32
+ "access_token": "your-access-token",
33
+ "refresh_token": "your-refresh-token",
34
+ "token_type": "bearer",
35
+ "expires_in": 1800 // Access token expires in 30 minutes (1800 seconds)
36
+ }
37
+ ```
38
+
39
+ If the credentials are invalid, the server responds with:
40
+ ```json
41
+ {
42
+ "detail": "Invalid username or password"
43
+ }
44
+ ```
45
+
46
+ ### 2. `/refresh` Endpoint
47
+ This endpoint is used to refresh the access token using a valid refresh token.
48
+
49
+ #### Request:
50
+ ```bash
51
+ curl -X POST https://humblebeeai-al-ghazali-rag-retrieval-api.hf.space/refresh \
52
+ -H "Content-Type: application/json" \
53
+ -d '{"refresh_token": "your-refresh-token"}'
54
+ ```
55
+
56
+ #### Response:
57
+ If the refresh token is valid, the server responds with:
58
+ ```json
59
+ {
60
+ "access_token": "new-access-token",
61
+ "refresh_token": "your-refresh-token", // Optionally issue a new refresh token
62
+ "token_type": "bearer",
63
+ "expires_in": 1800
64
+ }
65
+ ```
66
+
67
+ If the refresh token is invalid or expired, the server responds with:
68
+ ```json
69
+ {
70
+ "detail": "Could not validate credentials"
71
+ }
72
+ ```
73
+
74
+ ### 3. `/search` Endpoint
75
+ This endpoint is used to send a search query and retrieve results. It requires a valid access token.
76
+
77
+ #### Request:
78
+ ```bash
79
+ curl -X POST https://humblebeeai-al-ghazali-rag-retrieval-api.hf.space/search \
80
+ -H "Content-Type: application/json" \
81
+ -H "Authorization: Bearer your-access-token" \
82
+ -d '{"query": "test query"}'
83
+ ```
84
+
85
+ #### Response:
86
+ If the access token is valid, the server responds with:
87
+ ```json
88
+ [
89
+ {
90
+ "text": "Result 1 text",
91
+ "similarity": 0.95
92
+ },
93
+ {
94
+ "text": "Result 2 text",
95
+ "similarity": 0.92
96
+ },
97
+ {
98
+ "text": "Result 3 text",
99
+ "similarity": 0.89
100
+ }
101
+ ]
102
+ ```
103
+
104
+ If the access token is invalid or expired, the server responds with:
105
+ ```json
106
+ {
107
+ "detail": "Could not validate credentials"
108
+ }
109
+ ```
110
+
111
+ ### 4. Root Endpoint (`/`)
112
+ This endpoint is used to check if the API is running.
113
+
114
+ #### Request:
115
+ ```bash
116
+ curl -X GET https://humblebeeai-al-ghazali-rag-retrieval-api.hf.space/
117
+ ```
118
+
119
+ #### Response:
120
+ ```json
121
+ {
122
+ "message": "Welcome to the Alchemy of Happiness API!"
123
+ }
124
+ ```
125
+
126
+ ## Workflow Example
127
+
128
+ ### Step 1: Login
129
+ 1. **Request**:
130
+ ```bash
131
+ curl -X POST https://humblebeeai-al-ghazali-rag-retrieval-api.hf.space/login \
132
+ -H "Content-Type: application/x-www-form-urlencoded" \
133
+ -d 'username=user1332&password=RmzmurS7aE!t'
134
+ ```
135
+ 2. **Response**:
136
+ ```json
137
+ {
138
+ "access_token": "your-access-token",
139
+ "refresh_token": "your-refresh-token",
140
+ "token_type": "bearer",
141
+ "expires_in": 1800
142
+ }
143
+ ```
144
+
145
+ ### Step 2: Search
146
+ 1. **Request**:
147
+ ```bash
148
+ curl -X POST https://humblebeeai-al-ghazali-rag-retrieval-api.hf.space/search \
149
+ -H "Content-Type: application/json" \
150
+ -H "Authorization: Bearer your-access-token" \
151
+ -d '{"query": "test query"}'
152
+ ```
153
+ 2. **Response**:
154
+ ```json
155
+ [
156
+ {
157
+ "text": "Result 1 text",
158
+ "similarity": 0.95
159
+ },
160
+ {
161
+ "text": "Result 2 text",
162
+ "similarity": 0.92
163
+ },
164
+ {
165
+ "text": "Result 3 text",
166
+ "similarity": 0.89
167
+ }
168
+ ]
169
+ ```
170
+
171
+ ### Step 3: Refresh Token
172
+ 1. **Request**:
173
+ ```bash
174
+ curl -X POST https://humblebeeai-al-ghazali-rag-retrieval-api.hf.space/refresh \
175
+ -H "Content-Type: application/json" \
176
+ -d '{"refresh_token": "your-refresh-token"}'
177
+ ```
178
+ 2. **Response**:
179
+ ```json
180
+ {
181
+ "access_token": "new-access-token",
182
+ "refresh_token": "your-refresh-token",
183
+ "token_type": "bearer",
184
+ "expires_in": 1800
185
+ }
186
+ ```
187
+
188
+ ## Summary
189
+ - **`/login`**: Authenticate and get tokens.
190
+ - **`/refresh`**: Refresh the access token.
191
+ - **`/search`**: Send a search query (requires a valid access token).
192
+ - **`/`**: Check if the API is running.
193
+
194
+ Let me know if you need further clarification or assistance!
[openai_embedded] The Alchemy of Happiness (Ghazzālī, Claud Field) (Z-Library).parquet ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9f94d381f4dfcff0bbf6bfa5c84def47794d1596e12e2204a2a4bb413fc25a05
3
+ size 2257769
main.py ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException, Depends, status
2
+ from fastapi.responses import FileResponse
3
+ from fastapi.staticfiles import StaticFiles
4
+ from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
5
+ from pydantic import BaseModel
6
+ from jose import JWTError, jwt
7
+ from datetime import datetime, timedelta
8
+ from openai import OpenAI
9
+ from typing import List
10
+ import pandas as pd
11
+ import os
12
+ import logging
13
+
14
+ # Configure logging
15
+ logging.basicConfig(level=logging.INFO)
16
+
17
+ # Initialize FastAPI app
18
+ app = FastAPI()
19
+
20
+ # JWT Configuration
21
+ SECRET_KEY = os.environ.get("prime_auth", "c0369f977b69e717dc16f6fc574039eb2b1ebde38014d2be")
22
+ REFRESH_SECRET_KEY = os.environ.get("prolonged_auth", "916018771b29084378c9362c0cd9e631fd4927b8aea07f91")
23
+ ALGORITHM = "HS256"
24
+ ACCESS_TOKEN_EXPIRE_MINUTES = 30
25
+ REFRESH_TOKEN_EXPIRE_DAYS = 7
26
+
27
+ # OAuth2 scheme for token authentication
28
+ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="login")
29
+
30
+ # Load credentials from environment variables
31
+ def load_credentials():
32
+ credentials = {}
33
+ for i in range(1, 51): # Assuming you have 50 credentials
34
+ username = os.environ.get(f"login_{i}")
35
+ password = os.environ.get(f"password_{i}")
36
+ if username and password:
37
+ credentials[username] = password
38
+ return credentials
39
+
40
+ # Authenticate user and create token
41
+ def authenticate_user(username: str, password: str):
42
+ credentials_dict = load_credentials()
43
+ if username in credentials_dict and credentials_dict[username] == password:
44
+ return username
45
+ return None
46
+
47
+ # Create JWT token
48
+ def create_token(data: dict, expires_delta: timedelta, secret_key: str):
49
+ to_encode = data.copy()
50
+ expire = datetime.utcnow() + expires_delta
51
+ to_encode.update({"exp": expire})
52
+ encoded_jwt = jwt.encode(to_encode, secret_key, algorithm=ALGORITHM)
53
+ return encoded_jwt
54
+
55
+ # Verify JWT token
56
+ def verify_token(token: str, secret_key: str):
57
+ credentials_exception = HTTPException(
58
+ status_code=status.HTTP_401_UNAUTHORIZED,
59
+ detail="Could not validate credentials",
60
+ headers={"WWW-Authenticate": "Bearer"},
61
+ )
62
+ try:
63
+ payload = jwt.decode(token, secret_key, algorithms=[ALGORITHM])
64
+ username: str = payload.get("sub")
65
+ if username is None:
66
+ raise credentials_exception
67
+ except JWTError:
68
+ raise credentials_exception
69
+ return username
70
+
71
+ # Verify access token
72
+ def verify_access_token(token: str = Depends(oauth2_scheme)):
73
+ return verify_token(token, SECRET_KEY)
74
+
75
+ # Verify refresh token
76
+ def verify_refresh_token(token: str):
77
+ return verify_token(token, REFRESH_SECRET_KEY)
78
+
79
+ # Load data from parquet file
80
+ def load_data(database_file):
81
+ df = pd.read_parquet(database_file)
82
+
83
+ return df
84
+
85
+ # Generate OpenAI embeddings
86
+ def generate_openai_embeddings(client, text):
87
+ response = client.embeddings.create(
88
+ input=text,
89
+ model="text-embedding-3-small"
90
+ )
91
+ return response.data[0].embedding
92
+
93
+ # Compute cosine similarity
94
+ def cosine_similarity(embedding_0, embedding_1):
95
+ dot_product = sum(a * b for a, b in zip(embedding_0, embedding_1))
96
+ norm_0 = sum(a * a for a in embedding_0) ** 0.5
97
+ norm_1 = sum(b * b for b in embedding_1) ** 0.5
98
+ return dot_product / (norm_0 * norm_1)
99
+
100
+ # Search query
101
+ def search_query(client, query, df, n=3):
102
+ embedding = generate_openai_embeddings(client, query)
103
+ df['similarities'] = df.openai_embedding.apply(lambda x: cosine_similarity(x, embedding))
104
+ res = df.sort_values('similarities', ascending=False).head(n)
105
+ return res
106
+
107
+ # Pydantic model for the query input
108
+ class QueryInput(BaseModel):
109
+ query: str
110
+
111
+ # Pydantic model for the search result
112
+ class SearchResult(BaseModel):
113
+ text: str
114
+ similarity: float
115
+
116
+ # Pydantic model for the token response
117
+ class TokenResponse(BaseModel):
118
+ access_token: str
119
+ refresh_token: str
120
+ token_type: str
121
+
122
+ app.mount("/", StaticFiles(directory="static", html=True), name="static")
123
+
124
+ # Root endpoint
125
+ @app.get("/")
126
+ def index() -> FileResponse:
127
+ return FileResponse(path="/app/static/index.html", media_type="text/html")
128
+
129
+ # Login endpoint to issue tokens
130
+ @app.post("/login", response_model=TokenResponse)
131
+ def login(form_data: OAuth2PasswordRequestForm = Depends()):
132
+ username = authenticate_user(form_data.username, form_data.password)
133
+ if not username:
134
+ raise HTTPException(
135
+ status_code=status.HTTP_401_UNAUTHORIZED,
136
+ detail="Invalid username or password",
137
+ headers={"WWW-Authenticate": "Bearer"},
138
+ )
139
+ access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
140
+ refresh_token_expires = timedelta(days=REFRESH_TOKEN_EXPIRE_DAYS)
141
+ access_token = create_token(data={"sub": username}, expires_delta=access_token_expires, secret_key=SECRET_KEY)
142
+ refresh_token = create_token(data={"sub": username}, expires_delta=refresh_token_expires, secret_key=REFRESH_SECRET_KEY)
143
+ return {"access_token": access_token, "refresh_token": refresh_token, "token_type": "bearer"}
144
+
145
+ # Refresh token endpoint
146
+ @app.post("/refresh", response_model=TokenResponse)
147
+ def refresh(refresh_token: str):
148
+ username = verify_refresh_token(refresh_token)
149
+ access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
150
+ access_token = create_token(data={"sub": username}, expires_delta=access_token_expires, secret_key=SECRET_KEY)
151
+ return {"access_token": access_token, "refresh_token": refresh_token, "token_type": "bearer"}
152
+
153
+ # Search endpoint
154
+ @app.post("/search", response_model=List[SearchResult])
155
+ def search(
156
+ query_input: QueryInput,
157
+ username: str = Depends(verify_access_token),
158
+ ):
159
+ # Initialize OpenAI client
160
+ client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
161
+
162
+ # Load database
163
+ database_file = "/app/[openai_embedded] The Alchemy of Happiness (Ghazzālī, Claud Field) (Z-Library).parquet"
164
+ df = load_data(database_file)
165
+ logging.info("Database loaded successfully")
166
+
167
+ # Perform search
168
+ res = search_query(client, query_input.query, df, n=3)
169
+
170
+ # Format results
171
+ results = [
172
+ SearchResult(text=row["ext"], similarity=row["similarities"])
173
+ for _, row in res.iterrows()
174
+ ]
175
+
176
+ return results
177
+
178
+ # Run the app
179
+ if __name__ == "__main__":
180
+ import uvicorn
181
+ uvicorn.run(app, host="0.0.0.0", port=7860)
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ pandas
4
+ openai
5
+ python-dotenv
6
+ python-jose[cryptography]
7
+ python-multipart
static/index.html ADDED
@@ -0,0 +1,480 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Al Ghazali RAG API Documentation</title>
7
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/prismjs/1.29.0/themes/prism-tomorrow.min.css" rel="stylesheet" />
8
+ <link href="style.css" rel="stylesheet" />
9
+ </head>
10
+ <body>
11
+ <div class="container">
12
+ <nav class="sidebar">
13
+ <div class="logo">
14
+ 🔗 Al Ghazali RAG API
15
+ </div>
16
+ <div class="nav-items">
17
+ <!-- Navigation items will be populated by JavaScript -->
18
+ </div>
19
+ </nav>
20
+ <main class="content">
21
+ <h1>Al Ghazali RAG Retrieval API</h1>
22
+
23
+ <section id="endpoints">
24
+ <h2>Endpoints</h2>
25
+
26
+ <div class="endpoint" id="login">
27
+ <h3>1. Login Endpoint</h3>
28
+ <p><span class="method">POST</span><span class="endpoint-url">/login</span></p>
29
+ <p>This endpoint is used to authenticate the user and issue an access token and a refresh token.</p>
30
+
31
+ <h4>cURL Request:</h4>
32
+ <pre><code class="language-bash">curl -X POST https://humblebeeai-al-ghazali-rag-retrieval-api.hf.space/login \
33
+ -H "Content-Type: application/x-www-form-urlencoded" \
34
+ -d 'username=user123&password=password123'</code></pre>
35
+
36
+ <h4>Flutter Implementation:</h4>
37
+ <pre><code class="language-dart">Future<LoginResponse> login(String username, String password) async {
38
+ final url = Uri.parse('https://humblebeeai-al-ghazali-rag-retrieval-api.hf.space/login');
39
+
40
+ try {
41
+ final response = await http.post(
42
+ url,
43
+ headers: {'Content-Type': 'application/x-www-form-urlencoded'},
44
+ body: {
45
+ 'username': username,
46
+ 'password': password,
47
+ },
48
+ );
49
+
50
+ if (response.statusCode == 200) {
51
+ return LoginResponse.fromJson(jsonDecode(response.body));
52
+ } else {
53
+ throw Exception('Failed to login: ${response.body}');
54
+ }
55
+ } catch (e) {
56
+ throw Exception('Network error: $e');
57
+ }
58
+ }
59
+
60
+ // Model class
61
+ class LoginResponse {
62
+ final String accessToken;
63
+ final String refreshToken;
64
+ final String tokenType;
65
+ final int expiresIn;
66
+
67
+ LoginResponse({
68
+ required this.accessToken,
69
+ required this.refreshToken,
70
+ required this.tokenType,
71
+ required this.expiresIn,
72
+ });
73
+
74
+ factory LoginResponse.fromJson(Map<String, dynamic> json) {
75
+ return LoginResponse(
76
+ accessToken: json['access_token'],
77
+ refreshToken: json['refresh_token'],
78
+ tokenType: json['token_type'],
79
+ expiresIn: json['expires_in'],
80
+ );
81
+ }
82
+ }</code></pre>
83
+
84
+ <h4>Response:</h4>
85
+ <pre><code class="language-json">{
86
+ "access_token": "your-access-token",
87
+ "refresh_token": "your-refresh-token",
88
+ "token_type": "bearer",
89
+ "expires_in": 1800
90
+ }</code></pre>
91
+ </div>
92
+
93
+ <div class="endpoint" id="refresh">
94
+ <h3>2. Refresh Token Endpoint</h3>
95
+ <p><span class="method">POST</span><span class="endpoint-url">/refresh</span></p>
96
+ <p>This endpoint is used to refresh the access token using a valid refresh token.</p>
97
+
98
+ <h4>cURL Request:</h4>
99
+ <pre><code class="language-bash">curl -X POST https://humblebeeai-al-ghazali-rag-retrieval-api.hf.space/refresh \
100
+ -H "Content-Type: application/json" \
101
+ -d '{"refresh_token": "your-refresh-token"}'</code></pre>
102
+
103
+ <h4>Flutter Implementation:</h4>
104
+ <pre><code class="language-dart">Future<LoginResponse> refreshToken(String refreshToken) async {
105
+ final url = Uri.parse('https://humblebeeai-al-ghazali-rag-retrieval-api.hf.space/refresh');
106
+
107
+ try {
108
+ final response = await http.post(
109
+ url,
110
+ headers: {'Content-Type': 'application/json'},
111
+ body: jsonEncode({
112
+ 'refresh_token': refreshToken,
113
+ }),
114
+ );
115
+
116
+ if (response.statusCode == 200) {
117
+ return LoginResponse.fromJson(jsonDecode(response.body));
118
+ } else {
119
+ throw Exception('Failed to refresh token: ${response.body}');
120
+ }
121
+ } catch (e) {
122
+ throw Exception('Network error: $e');
123
+ }
124
+ }</code></pre>
125
+
126
+ <h4>Response:</h4>
127
+ <pre><code class="language-json">{
128
+ "access_token": "new-access-token",
129
+ "refresh_token": "your-refresh-token",
130
+ "token_type": "bearer",
131
+ "expires_in": 1800
132
+ }</code></pre>
133
+ </div>
134
+
135
+ <div class="endpoint" id="search">
136
+ <h3>3. Search Endpoint</h3>
137
+ <p><span class="method">POST</span><span class="endpoint-url">/search</span></p>
138
+ <p>This endpoint is used to send a search query and retrieve results. It requires a valid access token.</p>
139
+
140
+ <h4>cURL Request:</h4>
141
+ <pre><code class="language-bash">curl -X POST https://humblebeeai-al-ghazali-rag-retrieval-api.hf.space/search \
142
+ -H "Content-Type: application/json" \
143
+ -H "Authorization: Bearer your-access-token" \
144
+ -d '{"query": "test query"}'</code></pre>
145
+
146
+ <h4>Flutter Implementation:</h4>
147
+ <pre><code class="language-dart">class SearchResult {
148
+ final String text;
149
+ final double similarity;
150
+
151
+ SearchResult({
152
+ required this.text,
153
+ required this.similarity,
154
+ });
155
+
156
+ factory SearchResult.fromJson(Map<String, dynamic> json) {
157
+ return SearchResult(
158
+ text: json['text'],
159
+ similarity: json['similarity'].toDouble(),
160
+ );
161
+ }
162
+ }
163
+
164
+ Future<List<SearchResult>> search(String query, String accessToken) async {
165
+ final url = Uri.parse('https://humblebeeai-al-ghazali-rag-retrieval-api.hf.space/search');
166
+
167
+ try {
168
+ final response = await http.post(
169
+ url,
170
+ headers: {
171
+ 'Content-Type': 'application/json',
172
+ 'Authorization': 'Bearer $accessToken',
173
+ },
174
+ body: jsonEncode({
175
+ 'query': query,
176
+ }),
177
+ );
178
+
179
+ if (response.statusCode == 200) {
180
+ List<dynamic> jsonList = jsonDecode(response.body);
181
+ return jsonList.map((json) => SearchResult.fromJson(json)).toList();
182
+ } else {
183
+ throw Exception('Search failed: ${response.body}');
184
+ }
185
+ } catch (e) {
186
+ throw Exception('Network error: $e');
187
+ }
188
+ }</code></pre>
189
+
190
+ <h4>Response:</h4>
191
+ <pre><code class="language-json">[
192
+ {
193
+ "text": "Result 1 text",
194
+ "similarity": 0.95
195
+ },
196
+ {
197
+ "text": "Result 2 text",
198
+ "similarity": 0.92
199
+ },
200
+ {
201
+ "text": "Result 3 text",
202
+ "similarity": 0.89
203
+ }
204
+ ]</code></pre>
205
+ </div>
206
+ </section>
207
+
208
+ <section id="workflow">
209
+ <h2>Workflow Example</h2>
210
+ <p>Here's a complete workflow demonstrating how to use the API:</p>
211
+
212
+ <h3>cURL Implementation</h3>
213
+ <div class="endpoint">
214
+ <h3>Step 1: Login</h3>
215
+ <pre><code class="language-bash">curl -X POST https://humblebeeai-al-ghazali-rag-retrieval-api.hf.space/login \
216
+ -H "Content-Type: application/x-www-form-urlencoded" \
217
+ -d 'username=user123&password=password123'</code></pre>
218
+ </div>
219
+
220
+ <div class="endpoint">
221
+ <h3>Step 2: Search</h3>
222
+ <pre><code class="language-bash">curl -X POST https://humblebeeai-al-ghazali-rag-retrieval-api.hf.space/search \
223
+ -H "Content-Type: application/json" \
224
+ -H "Authorization: Bearer your-access-token" \
225
+ -d '{"query": "test query"}'</code></pre>
226
+ </div>
227
+
228
+ <div class="endpoint">
229
+ <h3>Step 3: Refresh Token</h3>
230
+ <pre><code class="language-bash">curl -X POST https://humblebeeai-al-ghazali-rag-retrieval-api.hf.space/refresh \
231
+ -H "Content-Type: application/json" \
232
+ -d '{"refresh_token": "your-refresh-token"}'</code></pre>
233
+ </div>
234
+
235
+ <h3>Flutter Implementation</h3>
236
+ <div class="endpoint">
237
+ <h4>Complete Flutter Example</h4>
238
+ <pre><code class="language-dart">import 'dart:convert';
239
+ import 'package:flutter/material.dart';
240
+ import 'package:http/http.dart' as http;
241
+
242
+ void main() {
243
+ runApp(MyApp());
244
+ }
245
+
246
+ class MyApp extends StatelessWidget {
247
+ @override
248
+ Widget build(BuildContext context) {
249
+ return MaterialApp(
250
+ title: 'Al Ghazali RAG API Example',
251
+ home: ApiWorkflowExample(),
252
+ );
253
+ }
254
+ }
255
+
256
+ class ApiWorkflowExample extends StatefulWidget {
257
+ @override
258
+ _ApiWorkflowExampleState createState() => _ApiWorkflowExampleState();
259
+ }
260
+
261
+ class _ApiWorkflowExampleState extends State<ApiWorkflowExample> {
262
+ String _accessToken = '';
263
+ String _refreshToken = '';
264
+ List<SearchResult> _searchResults = [];
265
+
266
+ Future<void> _login() async {
267
+ final username = 'user123';
268
+ final password = 'password123';
269
+
270
+ try {
271
+ final loginResponse = await login(username, password);
272
+ setState(() {
273
+ _accessToken = loginResponse.accessToken;
274
+ _refreshToken = loginResponse.refreshToken;
275
+ });
276
+ ScaffoldMessenger.of(context).showSnackBar(
277
+ SnackBar(content: Text('Login successful!')),
278
+ );
279
+ } catch (e) {
280
+ ScaffoldMessenger.of(context).showSnackBar(
281
+ SnackBar(content: Text('Login failed: $e')),
282
+ );
283
+ }
284
+ }
285
+
286
+ Future<void> _search() async {
287
+ final query = 'test query';
288
+
289
+ try {
290
+ final results = await search(query, _accessToken);
291
+ setState(() {
292
+ _searchResults = results;
293
+ });
294
+ ScaffoldMessenger.of(context).showSnackBar(
295
+ SnackBar(content: Text('Search successful!')),
296
+ );
297
+ } catch (e) {
298
+ ScaffoldMessenger.of(context).showSnackBar(
299
+ SnackBar(content: Text('Search failed: $e')),
300
+ );
301
+ }
302
+ }
303
+
304
+ Future<void> _refreshToken() async {
305
+ try {
306
+ final loginResponse = await refreshToken(_refreshToken);
307
+ setState(() {
308
+ _accessToken = loginResponse.accessToken;
309
+ });
310
+ ScaffoldMessenger.of(context).showSnackBar(
311
+ SnackBar(content: Text('Token refreshed successfully!')),
312
+ );
313
+ } catch (e) {
314
+ ScaffoldMessenger.of(context).showSnackBar(
315
+ SnackBar(content: Text('Token refresh failed: $e')),
316
+ );
317
+ }
318
+ }
319
+
320
+ @override
321
+ Widget build(BuildContext context) {
322
+ return Scaffold(
323
+ appBar: AppBar(
324
+ title: Text('Al Ghazali RAG API Workflow'),
325
+ ),
326
+ body: Padding(
327
+ padding: const EdgeInsets.all(16.0),
328
+ child: Column(
329
+ crossAxisAlignment: CrossAxisAlignment.stretch,
330
+ children: [
331
+ ElevatedButton(
332
+ onPressed: _login,
333
+ child: Text('Login'),
334
+ ),
335
+ ElevatedButton(
336
+ onPressed: _search,
337
+ child: Text('Search'),
338
+ ),
339
+ ElevatedButton(
340
+ onPressed: _refreshToken,
341
+ child: Text('Refresh Token'),
342
+ ),
343
+ Expanded(
344
+ child: ListView.builder(
345
+ itemCount: _searchResults.length,
346
+ itemBuilder: (context, index) {
347
+ final result = _searchResults[index];
348
+ return ListTile(
349
+ title: Text(result.text),
350
+ subtitle: Text('Similarity: ${result.similarity}'),
351
+ );
352
+ },
353
+ ),
354
+ ),
355
+ ],
356
+ ),
357
+ ),
358
+ );
359
+ }
360
+ }
361
+
362
+ Future<LoginResponse> login(String username, String password) async {
363
+ final url = Uri.parse('https://humblebeeai-al-ghazali-rag-retrieval-api.hf.space/login');
364
+
365
+ try {
366
+ final response = await http.post(
367
+ url,
368
+ headers: {'Content-Type': 'application/x-www-form-urlencoded'},
369
+ body: {
370
+ 'username': username,
371
+ 'password': password,
372
+ },
373
+ );
374
+
375
+ if (response.statusCode == 200) {
376
+ return LoginResponse.fromJson(jsonDecode(response.body));
377
+ } else {
378
+ throw Exception('Failed to login: ${response.body}');
379
+ }
380
+ } catch (e) {
381
+ throw Exception('Network error: $e');
382
+ }
383
+ }
384
+
385
+ Future<LoginResponse> refreshToken(String refreshToken) async {
386
+ final url = Uri.parse('https://humblebeeai-al-ghazali-rag-retrieval-api.hf.space/refresh');
387
+
388
+ try {
389
+ final response = await http.post(
390
+ url,
391
+ headers: {'Content-Type': 'application/json'},
392
+ body: jsonEncode({
393
+ 'refresh_token': refreshToken,
394
+ }),
395
+ );
396
+
397
+ if (response.statusCode == 200) {
398
+ return LoginResponse.fromJson(jsonDecode(response.body));
399
+ } else {
400
+ throw Exception('Failed to refresh token: ${response.body}');
401
+ }
402
+ } catch (e) {
403
+ throw Exception('Network error: $e');
404
+ }
405
+ }
406
+
407
+ Future<List<SearchResult>> search(String query, String accessToken) async {
408
+ final url = Uri.parse('https://humblebeeai-al-ghazali-rag-retrieval-api.hf.space/search');
409
+
410
+ try {
411
+ final response = await http.post(
412
+ url,
413
+ headers: {
414
+ 'Content-Type': 'application/json',
415
+ 'Authorization': 'Bearer $accessToken',
416
+ },
417
+ body: jsonEncode({
418
+ 'query': query,
419
+ }),
420
+ );
421
+
422
+ if (response.statusCode == 200) {
423
+ List<dynamic> jsonList = jsonDecode(response.body);
424
+ return jsonList.map((json) => SearchResult.fromJson(json)).toList();
425
+ } else {
426
+ throw Exception('Search failed: ${response.body}');
427
+ }
428
+ } catch (e) {
429
+ throw Exception('Network error: $e');
430
+ }
431
+ }
432
+
433
+ class LoginResponse {
434
+ final String accessToken;
435
+ final String refreshToken;
436
+ final String tokenType;
437
+ final int expiresIn;
438
+
439
+ LoginResponse({
440
+ required this.accessToken,
441
+ required this.refreshToken,
442
+ required this.tokenType,
443
+ required this.expiresIn,
444
+ });
445
+
446
+ factory LoginResponse.fromJson(Map<String, dynamic> json) {
447
+ return LoginResponse(
448
+ accessToken: json['access_token'],
449
+ refreshToken: json['refresh_token'],
450
+ tokenType: json['token_type'],
451
+ expiresIn: json['expires_in'],
452
+ );
453
+ }
454
+ }
455
+
456
+ class SearchResult {
457
+ final String text;
458
+ final double similarity;
459
+
460
+ SearchResult({
461
+ required this.text,
462
+ required this.similarity,
463
+ });
464
+
465
+ factory SearchResult.fromJson(Map<String, dynamic> json) {
466
+ return SearchResult(
467
+ text: json['text'],
468
+ similarity: json['similarity'].toDouble(),
469
+ );
470
+ }
471
+ }
472
+ </main>
473
+ </div>
474
+
475
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/prismjs/1.29.0/prism.min.js"></script>
476
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/prismjs/1.29.0/components/prism-bash.min.js"></script>
477
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/prismjs/1.29.0/components/prism-json.min.js"></script>
478
+ <script src="script.js"></script>
479
+ </body>
480
+ </html>
static/script.js ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Generate navigation items
2
+ const sections = [
3
+ { id: 'endpoints', title: 'Endpoints' },
4
+ { id: 'login', title: 'Login' },
5
+ { id: 'refresh', title: 'Refresh Token' },
6
+ { id: 'search', title: 'Search' },
7
+ { id: 'workflow', title: 'Workflow Example' }
8
+ ];
9
+
10
+ const navItems = document.querySelector('.nav-items');
11
+ sections.forEach(section => {
12
+ const item = document.createElement('div');
13
+ item.className = 'nav-item';
14
+ item.textContent = section.title;
15
+ item.setAttribute('data-section', section.id);
16
+ item.addEventListener('click', () => {
17
+ document.getElementById(section.id).scrollIntoView({ behavior: 'smooth' });
18
+ });
19
+ navItems.appendChild(item);
20
+ });
21
+
22
+ // Highlight current section in navigation
23
+ const observerCallback = (entries) => {
24
+ entries.forEach(entry => {
25
+ if (entry.isIntersecting) {
26
+ const currentNav = document.querySelector(`.nav-item[data-section="${entry.target.id}"]`);
27
+ if (currentNav) {
28
+ document.querySelectorAll('.nav-item').forEach(item => {
29
+ item.style.backgroundColor = '';
30
+ });
31
+ currentNav.style.backgroundColor = '#f3f4f6';
32
+ }
33
+ }
34
+ });
35
+ };
36
+
37
+ const observer = new IntersectionObserver(observerCallback, {
38
+ threshold: 0.2
39
+ });
40
+
41
+ document.querySelectorAll('section').forEach(section => {
42
+ observer.observe(section);
43
+ });
static/style.css ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ :root {
2
+ --primary-color: #4f46e5;
3
+ --secondary-color: #1e40af;
4
+ --text-color: #1f2937;
5
+ --code-bg: #1e1e1e;
6
+ --border-color: #e5e7eb;
7
+ }
8
+
9
+ * {
10
+ margin: 0;
11
+ padding: 0;
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ body {
16
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
17
+ line-height: 1.6;
18
+ color: var(--text-color);
19
+ background-color: #f9fafb;
20
+ }
21
+
22
+ .container {
23
+ display: flex;
24
+ min-height: 100vh;
25
+ }
26
+
27
+ .sidebar {
28
+ width: 280px;
29
+ background-color: white;
30
+ border-right: 1px solid var(--border-color);
31
+ padding: 2rem;
32
+ position: fixed;
33
+ height: 100vh;
34
+ overflow-y: auto;
35
+ }
36
+
37
+ .content {
38
+ flex: 1;
39
+ padding: 2rem;
40
+ margin-left: 280px;
41
+ max-width: 1200px;
42
+ }
43
+
44
+ .logo {
45
+ font-size: 1.5rem;
46
+ font-weight: bold;
47
+ color: var(--primary-color);
48
+ margin-bottom: 2rem;
49
+ display: flex;
50
+ align-items: center;
51
+ gap: 0.5rem;
52
+ }
53
+
54
+ .nav-item {
55
+ margin: 0.5rem 0;
56
+ cursor: pointer;
57
+ padding: 0.5rem;
58
+ border-radius: 0.375rem;
59
+ transition: background-color 0.2s;
60
+ }
61
+
62
+ .nav-item:hover {
63
+ background-color: #f3f4f6;
64
+ }
65
+
66
+ h1 {
67
+ font-size: 2.5rem;
68
+ margin-bottom: 1.5rem;
69
+ color: var(--primary-color);
70
+ }
71
+
72
+ h2 {
73
+ font-size: 1.8rem;
74
+ margin: 2rem 0 1rem;
75
+ padding-top: 2rem;
76
+ border-top: 1px solid var(--border-color);
77
+ }
78
+
79
+ h3 {
80
+ font-size: 1.4rem;
81
+ margin: 1.5rem 0 1rem;
82
+ color: var(--secondary-color);
83
+ }
84
+
85
+ p {
86
+ margin-bottom: 1rem;
87
+ }
88
+
89
+ pre {
90
+ margin: 1rem 0;
91
+ padding: 1rem;
92
+ border-radius: 0.5rem;
93
+ background-color: #2d2d2d !important;
94
+ overflow-x: auto;
95
+ border: 1px solid #3f3f3f;
96
+ }
97
+
98
+ code {
99
+ font-family: 'Fira Code', monospace;
100
+ font-size: 0.9rem;
101
+ color: #e6e6e6;
102
+ }
103
+
104
+ /* Specific syntax highlighting overrides */
105
+ .language-bash {
106
+ color: #e6e6e6 !important;
107
+ }
108
+
109
+ .language-bash .token.function {
110
+ color: #87ceeb !important;
111
+ }
112
+
113
+ .language-bash .token.operator {
114
+ color: #87ceeb !important;
115
+ }
116
+
117
+ .language-bash .token.string {
118
+ color: #98c379 !important;
119
+ }
120
+
121
+ .language-json {
122
+ color: #e6e6e6 !important;
123
+ }
124
+
125
+ .language-json .token.property {
126
+ color: #87ceeb !important;
127
+ }
128
+
129
+ .language-json .token.string {
130
+ color: #98c379 !important;
131
+ }
132
+
133
+ .language-json .token.number {
134
+ color: #d19a66 !important;
135
+ }
136
+
137
+ /* Add a subtle glow effect to code blocks */
138
+ pre code {
139
+ text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
140
+ }
141
+
142
+ .endpoint {
143
+ background-color: white;
144
+ border: 1px solid var(--border-color);
145
+ border-radius: 0.5rem;
146
+ padding: 1.5rem;
147
+ margin: 1.5rem 0;
148
+ }
149
+
150
+ .method {
151
+ display: inline-block;
152
+ padding: 0.25rem 0.5rem;
153
+ border-radius: 0.25rem;
154
+ background-color: var(--primary-color);
155
+ color: white;
156
+ font-weight: 500;
157
+ margin-right: 0.5rem;
158
+ }
159
+
160
+ .endpoint-url {
161
+ font-family: 'Fira Code', monospace;
162
+ color: var(--secondary-color);
163
+ }
164
+
165
+ @media (max-width: 768px) {
166
+ .sidebar {
167
+ display: none;
168
+ }
169
+ .content {
170
+ margin-left: 0;
171
+ }
172
+ }