Initial commit
This commit is contained in:
commit
598617025f
|
|
@ -0,0 +1,114 @@
|
|||
// --- Configuration ---
|
||||
// IMPORTANT: For production, use a SEARCH-ONLY API Key.
|
||||
// NEVER expose your Admin API Key in client-side code.
|
||||
// Best practice is to proxy requests through your backend
|
||||
// or use Typesense Scoped Search Keys.
|
||||
const TYPESENSE_CONFIG = {
|
||||
nodes: [{
|
||||
host: '192.168.2.203', // Or your Typesense host
|
||||
port: '8108',
|
||||
protocol: 'http'
|
||||
}],
|
||||
apiKey: 'imdiowenxodjioqwenlj', // Generate a search-only API key in Typesense
|
||||
connectionTimeoutSeconds: 2
|
||||
};
|
||||
|
||||
const typesenseClient = new Typesense.Client(TYPESENSE_CONFIG);
|
||||
|
||||
// --- DOM Elements ---
|
||||
const searchInput = document.getElementById('user-search-input');
|
||||
const suggestionsList = document.getElementById('suggestions-list');
|
||||
const selectedUserIdEl = document.getElementById('selected-user-id');
|
||||
const selectedUserNameEl = document.getElementById('selected-user-name');
|
||||
|
||||
// --- Debounce Function (to limit API calls) ---
|
||||
let debounceTimer;
|
||||
function debounce(func, delay) {
|
||||
return function(...args) {
|
||||
clearTimeout(debounceTimer);
|
||||
debounceTimer = setTimeout(() => func.apply(this, args), delay);
|
||||
};
|
||||
}
|
||||
|
||||
// --- Fetch and Display Suggestions ---
|
||||
async function fetchSuggestions(query) {
|
||||
if (!query.trim()) {
|
||||
suggestionsList.innerHTML = '';
|
||||
suggestionsList.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
const searchParameters = {
|
||||
'q': query,
|
||||
'query_by': 'user_name', // Field to search in
|
||||
'per_page': 5, // Number of suggestions to show
|
||||
// 'sort_by': '_text_match:desc', // Default, or 'user_name_lowercase_sort:asc' if you use that field
|
||||
'infix': 'always', // Ensure infix search is active if not default for the field
|
||||
// 'filter_by': 'is_active:=true' // Example: if you have an is_active boolean field
|
||||
};
|
||||
|
||||
try {
|
||||
const searchResults = await typesenseClient.collections('users').documents().search(searchParameters);
|
||||
displaySuggestions(searchResults.hits || []);
|
||||
} catch (error) {
|
||||
console.error('Typesense search error:', error);
|
||||
suggestionsList.innerHTML = '<li>Error fetching suggestions</li>';
|
||||
suggestionsList.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
function displaySuggestions(hits) {
|
||||
suggestionsList.innerHTML = ''; // Clear previous suggestions
|
||||
if (hits.length === 0) {
|
||||
suggestionsList.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
hits.forEach(hit => {
|
||||
const user = hit.document; // The actual document data
|
||||
const li = document.createElement('li');
|
||||
|
||||
// Create a highlighted version of the name if available
|
||||
let displayName = user.user_name;
|
||||
if (hit.highlights && hit.highlights.length > 0) {
|
||||
const nameHighlight = hit.highlights.find(h => h.field === 'user_name');
|
||||
if (nameHighlight && nameHighlight.snippet) {
|
||||
displayName = nameHighlight.snippet; // Use Typesense's highlighted version
|
||||
}
|
||||
}
|
||||
li.innerHTML = displayName; // Display name (can be highlighted)
|
||||
|
||||
// Store full user data (or just ID) for selection
|
||||
li.dataset.userId = user.user_id;
|
||||
li.dataset.userName = user.user_name; // Store the original, non-highlighted name
|
||||
|
||||
li.addEventListener('click', () => {
|
||||
searchInput.value = user.user_name; // Fill input with selected name
|
||||
selectedUserIdEl.textContent = user.user_id;
|
||||
selectedUserNameEl.textContent = user.user_name;
|
||||
suggestionsList.innerHTML = ''; // Clear suggestions
|
||||
suggestionsList.style.display = 'none';
|
||||
|
||||
// You now have user.user_id and user.user_name
|
||||
console.log('Selected:', { id: user.user_id, name: user.user_name });
|
||||
// Here, you might want to submit a form, make another API call, etc.
|
||||
});
|
||||
suggestionsList.appendChild(li);
|
||||
});
|
||||
suggestionsList.style.display = 'block';
|
||||
}
|
||||
|
||||
// --- Event Listeners ---
|
||||
searchInput.addEventListener('input', debounce((event) => {
|
||||
fetchSuggestions(event.target.value);
|
||||
}, 300)); // 300ms debounce
|
||||
|
||||
// Optional: Hide suggestions when clicking outside
|
||||
document.addEventListener('click', (event) => {
|
||||
if (!searchInput.contains(event.target) && !suggestionsList.contains(event.target)) {
|
||||
suggestionsList.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
console.log("Autocomplete App Initialized. Make sure your Typesense server is running and accessible.");
|
||||
console.log("And ensure you've replaced 'YOUR_SEARCH_ONLY_API_KEY' with a valid key.");
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Typesense Autocomplete</title>
|
||||
<style>
|
||||
body { font-family: sans-serif; margin: 20px; }
|
||||
#user-search-input { padding: 10px; font-size: 16px; width: 300px; margin-bottom: 5px; }
|
||||
#suggestions-list {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 1px solid #ccc;
|
||||
border-top: none;
|
||||
width: 310px; /* Match input width + padding */
|
||||
}
|
||||
#suggestions-list li {
|
||||
padding: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#suggestions-list li:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
#selected-user { margin-top: 20px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>User Autocomplete</h1>
|
||||
|
||||
<input type="text" id="user-search-input" placeholder="Type a user name...">
|
||||
<ul id="suggestions-list"></ul>
|
||||
|
||||
<div id="selected-user">
|
||||
<p>Selected User ID: <span id="selected-user-id">N/A</span></p>
|
||||
<p>Selected User Name: <span id="selected-user-name">N/A</span></p>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/typesense@2.0.3/dist/typesense.min.js"></script>
|
||||
<script src="app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
# Using Python client for schema creation
|
||||
import typesense
|
||||
|
||||
# Sample user data
|
||||
users_data = [
|
||||
{'user_id': 'uid101', 'user_name': 'Alice Wonderland'},
|
||||
{'user_id': 'uid102', 'user_name': 'Bob The Builder'},
|
||||
{'user_id': 'uid103', 'user_name': 'Charlie Chaplin'},
|
||||
{'user_id': 'uid104', 'user_name': 'Diana Prince'},
|
||||
{'user_id': 'uid105', 'user_name': 'Edward Scissorhands'},
|
||||
{'user_id': 'uid106', 'user_name': 'alice cooper'}, # For case testing
|
||||
{'user_id': 'uid107', 'user_name': '任小寅'},
|
||||
{'user_id': 'uid108', 'user_name': '任大寅'},
|
||||
{'user_id': 'uid109', 'user_name': '张三'},
|
||||
{'user_id': 'uid110', 'user_name': '李四'},
|
||||
{'user_id': 'uid111', 'user_name': '王五'},
|
||||
{'user_id': 'uid112', 'user_name': '赵六'},
|
||||
{'user_id': 'uid113', 'user_name': '孙七'},
|
||||
{'user_id': 'uid114', 'user_name': '周八'},
|
||||
{'user_id': 'uid115', 'user_name': '吴九'},
|
||||
{'user_id': 'uid116', 'user_name': '郑十'},
|
||||
|
||||
]
|
||||
users_schema = {
|
||||
'name': 'users',
|
||||
'fields': [
|
||||
{'name': 'user_id', 'type': 'string', 'index': True, 'facet': False},
|
||||
{'name': 'user_name', 'type': 'string', 'index': True, 'facet': False, 'infix': True},
|
||||
# Optional: for cleaner prefix sorting if needed, otherwise _text_match often suffices
|
||||
{'name': 'user_name_lowercase_sort', 'type': 'string', 'sort': True, 'optional': True}
|
||||
]
|
||||
}
|
||||
client = typesense.Client({
|
||||
'nodes': [{
|
||||
'host': '192.168.2.203', # Or your Typesense host
|
||||
'port': '8108',
|
||||
'protocol': 'http'
|
||||
}],
|
||||
'api_key': 'imdiowenxodjioqwenlj', # Use admin key for schema operations
|
||||
'connection_timeout_seconds': 2
|
||||
})
|
||||
|
||||
# Prepare documents for Typesense (add the optional sort field if you defined it)
|
||||
documents_to_index = []
|
||||
for user in users_data:
|
||||
doc = {
|
||||
'user_id': user['user_id'],
|
||||
'user_name': user['user_name'],
|
||||
}
|
||||
# If using the optional sort field:
|
||||
if 'user_name_lowercase_sort' in [f['name'] for f in users_schema['fields']]:
|
||||
doc['user_name_lowercase_sort'] = user['user_name'].lower()
|
||||
documents_to_index.append(doc)
|
||||
|
||||
|
||||
# Index the documents (batch import is recommended for larger datasets)
|
||||
try:
|
||||
results = client.collections['users'].documents.import_(documents_to_index, {'action': 'upsert'})
|
||||
print("Documents indexed successfully.")
|
||||
# print(results) # You can inspect the results if needed
|
||||
successful_imports = sum(1 for r in results if r.get('success', False))
|
||||
print(f"Successfully imported {successful_imports}/{len(results)} documents.")
|
||||
for r in results:
|
||||
if not r.get('success', False):
|
||||
print(f"Failed import: {r.get('error', 'Unknown error')} - Document: {r.get('document', '{}')}")
|
||||
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error indexing documents: {e}")
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
# Using Python client for schema creation
|
||||
import typesense
|
||||
|
||||
client = typesense.Client({
|
||||
'nodes': [{
|
||||
'host': '192.168.2.203', # Or your Typesense host
|
||||
'port': '8108',
|
||||
'protocol': 'http'
|
||||
}],
|
||||
'api_key': 'imdiowenxodjioqwenlj', # Use admin key for schema operations
|
||||
'connection_timeout_seconds': 2
|
||||
})
|
||||
|
||||
# Define the schema
|
||||
users_schema = {
|
||||
'name': 'users',
|
||||
'fields': [
|
||||
{'name': 'user_id', 'type': 'string', 'index': True, 'facet': False},
|
||||
{'name': 'user_name', 'type': 'string', 'index': True, 'facet': False, 'infix': True},
|
||||
# Optional: for cleaner prefix sorting if needed, otherwise _text_match often suffices
|
||||
{'name': 'user_name_lowercase_sort', 'type': 'string', 'sort': True, 'optional': True}
|
||||
]
|
||||
}
|
||||
|
||||
# Delete collection if it already exists (for development)
|
||||
try:
|
||||
client.collections['users'].delete()
|
||||
print("Collection 'users' deleted.")
|
||||
except Exception as e:
|
||||
print(f"Collection 'users' does not exist or could not be deleted: {e}")
|
||||
|
||||
# Create the collection
|
||||
try:
|
||||
client.collections.create(users_schema)
|
||||
print("Collection 'users' created successfully.")
|
||||
except Exception as e:
|
||||
print(f"Error creating collection 'users': {e}")
|
||||
Loading…
Reference in New Issue