mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-10-20 20:12:39 +03:00
Vectors: Started front-end work, moved to own controller
This commit is contained in:
53
app/Search/QueryController.php
Normal file
53
app/Search/QueryController.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace BookStack\Search;
|
||||
|
||||
use BookStack\Http\Controller;
|
||||
use BookStack\Search\Vectors\VectorSearchRunner;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class QueryController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
protected SearchRunner $searchRunner,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the view to start a vector/LLM-based query search.
|
||||
*/
|
||||
public function show(Request $request)
|
||||
{
|
||||
// TODO - Validate if query system is active
|
||||
$query = $request->get('ask', '');
|
||||
|
||||
// TODO - Placeholder
|
||||
$entities = $this->searchRunner->searchEntities(SearchOptions::fromString("cat"), 'all', 1, 20)['results'];
|
||||
|
||||
// TODO - Set page title
|
||||
|
||||
return view('search.query', [
|
||||
'query' => $query,
|
||||
'entities' => $entities,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a vector/LLM-based query search.
|
||||
*/
|
||||
public function run(Request $request, VectorSearchRunner $runner)
|
||||
{
|
||||
// TODO - Validate if query system is active
|
||||
$query = $request->get('query', '');
|
||||
|
||||
if ($query) {
|
||||
$results = $runner->run($query);
|
||||
} else {
|
||||
$results = null;
|
||||
}
|
||||
|
||||
return view('search.query', [
|
||||
'results' => $results,
|
||||
]);
|
||||
}
|
||||
}
|
@@ -129,7 +129,7 @@ class SearchController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Search siblings items in the system.
|
||||
* Search sibling items in the system.
|
||||
*/
|
||||
public function searchSiblings(Request $request, SiblingFetcher $siblingFetcher)
|
||||
{
|
||||
@@ -140,23 +140,4 @@ class SearchController extends Controller
|
||||
|
||||
return view('entities.list-basic', ['entities' => $entities, 'style' => 'compact']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a vector/LLM-based query search.
|
||||
*/
|
||||
public function searchQuery(Request $request, VectorSearchRunner $runner)
|
||||
{
|
||||
// TODO - Validate if query system is active
|
||||
$query = $request->get('query', '');
|
||||
|
||||
if ($query) {
|
||||
$results = $runner->run($query);
|
||||
} else {
|
||||
$results = null;
|
||||
}
|
||||
|
||||
return view('search.query', [
|
||||
'results' => $results,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@@ -44,6 +44,7 @@ export {PagePicker} from './page-picker';
|
||||
export {PermissionsTable} from './permissions-table';
|
||||
export {Pointer} from './pointer';
|
||||
export {Popup} from './popup';
|
||||
export {QueryManager} from './query-manager';
|
||||
export {SettingAppColorScheme} from './setting-app-color-scheme';
|
||||
export {SettingColorPicker} from './setting-color-picker';
|
||||
export {SettingHomepageControl} from './setting-homepage-control';
|
||||
|
25
resources/js/components/query-manager.ts
Normal file
25
resources/js/components/query-manager.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import {Component} from "./component";
|
||||
|
||||
export class QueryManager extends Component {
|
||||
protected input!: HTMLTextAreaElement;
|
||||
protected generatedLoading!: HTMLElement;
|
||||
protected generatedDisplay!: HTMLElement;
|
||||
protected contentLoading!: HTMLElement;
|
||||
protected contentDisplay!: HTMLElement;
|
||||
protected form!: HTMLFormElement;
|
||||
|
||||
setup() {
|
||||
this.input = this.$refs.input as HTMLTextAreaElement;
|
||||
this.form = this.$refs.form as HTMLFormElement;
|
||||
this.generatedLoading = this.$refs.generatedLoading;
|
||||
this.generatedDisplay = this.$refs.generatedDisplay;
|
||||
this.contentLoading = this.$refs.contentLoading;
|
||||
this.contentDisplay = this.$refs.contentDisplay;
|
||||
|
||||
// TODO - Start lookup if query set
|
||||
|
||||
// TODO - Update URL on query change
|
||||
|
||||
// TODO - Handle query form submission
|
||||
}
|
||||
}
|
@@ -597,3 +597,21 @@ input.shortcut-input {
|
||||
max-width: 120px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.query-form {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: vars.$m;
|
||||
textarea {
|
||||
font-size: 1.4rem;
|
||||
height: 100px;
|
||||
box-shadow: vars.$bs-card;
|
||||
border-radius: 8px;
|
||||
color: #444;
|
||||
}
|
||||
button {
|
||||
align-self: start;
|
||||
margin: 0;
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
}
|
@@ -1,29 +1,62 @@
|
||||
@extends('layouts.simple')
|
||||
|
||||
@section('body')
|
||||
<div class="container mt-xl" id="search-system">
|
||||
<div component="query-manager" class="container small pt-xxl">
|
||||
|
||||
<form action="{{ url('/search/query') }}" method="get">
|
||||
<input name="query" type="text">
|
||||
<button class="button">Query</button>
|
||||
</form>
|
||||
<div class="card content-wrap auto-height">
|
||||
<h1 class="list-heading">Start a Query</h1>
|
||||
<form action="{{ url('/query') }}"
|
||||
refs="query-manager@form"
|
||||
title="Run Query"
|
||||
method="post"
|
||||
class="query-form">
|
||||
<textarea name="query"
|
||||
refs="query-manager@input"
|
||||
class="input-fill-width"
|
||||
rows="5"
|
||||
placeholder="Enter a query"
|
||||
autocomplete="off">{{ $query }}</textarea>
|
||||
<button class="button icon">@icon('search')</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@if($results)
|
||||
<h2>Results</h2>
|
||||
<div class="card content-wrap auto-height pb-xl">
|
||||
<h2 class="list-heading">Generated Response</h2>
|
||||
<div refs="query-manager@generated-loading">
|
||||
@include('common.loading-icon')
|
||||
</div>
|
||||
<p refs="query-manager@generated-display">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ad adipisci aliquid architecto cupiditate dolor doloribus eligendi et expedita facilis fugiat fugit illo, ipsa laboriosam maiores, molestias mollitia non obcaecati porro quasi quis quos reprehenderit rerum sunt tenetur ullam unde voluptate voluptates! Distinctio et eum id molestiae nisi quisquam sed ut.</p>
|
||||
</div>
|
||||
|
||||
<h3>LLM Output</h3>
|
||||
<p>{{ $results['llm_result'] }}</p>
|
||||
|
||||
<h3>Entity Matches</h3>
|
||||
@foreach($results['entity_matches'] as $match)
|
||||
<div>
|
||||
<div><strong>{{ $match['entity_type'] }}:{{ $match['entity_id'] }}; Distance: {{ $match['distance'] }}</strong></div>
|
||||
<details>
|
||||
<summary>match text</summary>
|
||||
<div>{{ $match['text'] }}</div>
|
||||
</details>
|
||||
<div class="card content-wrap auto-height pb-xl">
|
||||
<h2 class="list-heading">Relevant Content</h2>
|
||||
<div refs="query-manager@content-loading">
|
||||
@include('common.loading-icon')
|
||||
</div>
|
||||
<div class="book-contents">
|
||||
<div refs="query-manager@content-display" class="entity-list">
|
||||
@include('entities.list', ['entities' => $entities, 'showPath' => true, 'showTags' => true])
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- @if($results)--}}
|
||||
{{-- <h2>Results</h2>--}}
|
||||
|
||||
{{-- <h3>LLM Output</h3>--}}
|
||||
{{-- <p>{{ $results['llm_result'] }}</p>--}}
|
||||
|
||||
{{-- <h3>Entity Matches</h3>--}}
|
||||
{{-- @foreach($results['entity_matches'] as $match)--}}
|
||||
{{-- <div>--}}
|
||||
{{-- <div><strong>{{ $match['entity_type'] }}:{{ $match['entity_id'] }}; Distance: {{ $match['distance'] }}</strong></div>--}}
|
||||
{{-- <details>--}}
|
||||
{{-- <summary>match text</summary>--}}
|
||||
{{-- <div>{{ $match['text'] }}</div>--}}
|
||||
{{-- </details>--}}
|
||||
{{-- </div>--}}
|
||||
{{-- @endforeach--}}
|
||||
{{-- @endif--}}
|
||||
</div>
|
||||
@stop
|
||||
|
@@ -11,6 +11,7 @@ use BookStack\Exports\Controllers as ExportControllers;
|
||||
use BookStack\Http\Middleware\VerifyCsrfToken;
|
||||
use BookStack\Permissions\PermissionsController;
|
||||
use BookStack\References\ReferenceController;
|
||||
use BookStack\Search\QueryController;
|
||||
use BookStack\Search\SearchController;
|
||||
use BookStack\Settings as SettingControllers;
|
||||
use BookStack\Sorting as SortingControllers;
|
||||
@@ -189,7 +190,6 @@ Route::middleware('auth')->group(function () {
|
||||
|
||||
// Search
|
||||
Route::get('/search', [SearchController::class, 'search']);
|
||||
Route::get('/search/query', [SearchController::class, 'searchQuery']);
|
||||
Route::get('/search/book/{bookId}', [SearchController::class, 'searchBook']);
|
||||
Route::get('/search/chapter/{bookId}', [SearchController::class, 'searchChapter']);
|
||||
Route::get('/search/entity/siblings', [SearchController::class, 'searchSiblings']);
|
||||
@@ -197,6 +197,10 @@ Route::middleware('auth')->group(function () {
|
||||
Route::get('/search/entity-selector-templates', [SearchController::class, 'templatesForSelector']);
|
||||
Route::get('/search/suggest', [SearchController::class, 'searchSuggestions']);
|
||||
|
||||
// Queries
|
||||
Route::get('/query', [QueryController::class, 'show']);
|
||||
Route::post('/query', [QueryController::class, 'run']);
|
||||
|
||||
// User Search
|
||||
Route::get('/search/users/select', [UserControllers\UserSearchController::class, 'forSelect']);
|
||||
|
||||
|
Reference in New Issue
Block a user