diff --git a/.env.example b/.env.example index 524c4474..9b846141 100644 --- a/.env.example +++ b/.env.example @@ -15,7 +15,8 @@ APP_MAINTENANCE_STORE=database APP_COPYRIGHT=wi-wissen.de -DOC_URL=https://wi-wissen.github.io/instahub-doc-de/ +HUB_DEFAULT_GENERATION=1 +HUB_DOC_1_URL=https://wi-wissen.github.io/instahub-doc-de/ BCRYPT_ROUNDS=12 @@ -55,6 +56,11 @@ MAIL_ENCRYPTION=null MAIL_FROM_ADDRESS="hello@example.com" MAIL_FROM_NAME="${APP_NAME}" +AZURE_RESOURCE_NAME= +AZURE_DEPLOYMENT_ID= +AZURE_OPENAI_KEY= +AZURE_VERSION=2024-02-01 + VITE_APP_NAME="${APP_NAME}" WORD=achatgrau,ahornrot,agavengruen,alaskagrau,alpinaweiss,altrosa,aluminiumgrau,amarant,amarantrot,amazonasgruen,ameisenrot,ananasgelb,anthrazit,anthrazitgrau,antikgelb,antikrot,antiktuerkis,antikweiss,apfelgruen,aquamarin,aquamarinblau,asphaltgrau,atlantikblau,atlantisblau,azorenblau,azurblau,ballettrosa,bananengelb,basaltgrau,beige,beigerot,betongrau,birkengruen,blattgruen,blau,bleigrau,bluescreenblau,blutorange,blutrot,braun,braunbeige,braunrot,brillantblau,brombeerrot,bronze,burgunderrot,cappuccino,capriblau,carrerarot,cayennerot,cherry,chromgelb,creepergruen,cremeweiss,currygelb,cyan,dahliengelb,delphinblau,diamantblau,diamantgruen,diamantrot,diamantschwarz,dunkelblau,dunkelbraun,dunkelgelb,dunkelgrau,dunkelgruen,dunkellila,dunkelrosa,dunkelrot,eisblau,eisengrau,elefantengrau,elfenbein,enzianblau,erdbeerrot,erikarot,espressobraun,estorilblau,farblos,farngruen,fehengrau,fenstergrau,feuerrot,flamingorosa,flamingorot,flaschengruen,flieder,froschgruen,fruehlingsgruen,fuchsienrot,gelb,gelbgruen,gelblich,gelborange,geraniumrot,giftgruen,gilblich,ginstergelb,gletscherblau,gold,goldbraun,golden,goldgelb,granitgrau,graphitgrau,grasgruen,grau,graubeige,gruen,gruenbeige,gruenlich,guelden,haselnussbraun,heidelbeerblau,hellblau,hellbraun,hellelfenbein,hellgelb,hellgrau,hellgruen,hellrosa,hellrot,hellrotorange,himbeerrot,himmelblau,honiggelb,hummerrot,indianerrot,indigo,indigoblau,indigorot,indischgelb,indischrot,infernorot,inkarnat,italienischrot,jadegruen,jerichorot,johannisbeerrot,kadmiumgelb,kaffeebraun,kamillengelb,kanariengelb,karamellbraun,kardinalrot,karibikblau,karminrot,karminrot,kastanienbraun,kieferngruen,kieselgrau,kirschrot,kiwigruen,khakigrau,khakigruen,kobaltblau,kobaltgruen,koenigsblau,korallenrosa,korallenrot,kornblumenblau,koronagelb,kosmosschwarz,kupferrot,lachsorange,lachsrosa,lachsrot,laubgruen,lavendelblau,lehmbraun,lemongruen,leuchtgelb,leuchthellorange,leuchthellrot,leuchtorange,leuchtrot,lichtblau,lila,limonengruen,lindgruen,lotusrot,magenta,magnolienrosa,magnolienrot,mahagonibraun,mahagonirot,maigruen,maisgelb,marmor,mandelbraun,marineblau,mauritiusblau,mausgrau,meeresgruen,melonengelb,mintgruen,mohnrot,moosgrau,moosgruen,nachtblau,narzissengelb,neapelgelb,neonblau,neongelb,neongruen,neonlila,neonorange,neonpink,neonrosa,neonrot,neontuerkis,neonviolett,nougatbraun,nussbraun,ocker,ockerbraun,ockergelb,ockerrot,olivgelb,olivgrau,olivgruen,orange,orangegelb,orangerot,orchidee,orientrot,oxidrot,ozeanblau,papageirot,paprikarot,papyrus,papyrusweiss,pastell,pastellgelb,pastellorange,patinagruen,pazifikblau,pechrabenschwarz,perlbeige,perlgold,perlgrau,perlorange,perlrosa,perlrubinrot,perlweiss,permamentrosa,permamentrot,persischrot,petrol,pfirsichrot,pigmentgruen,pink,pistaziengruen,platingrau,plazentarot,porzellanblau,pflaumenblau,pumucklrot,purpur,purpurlila,purpurrot,quarzgrau,quittegelb,quittengelb,rapsgelb,rehbraun,reinorange,reinrot,resedagruen,rhabarberrot,rindenbraun,ringelblumengelb,rosa,rosenrosa,rosenrot,rosig,rostbraun,rostrot,rot,rotorange,royalblau,rubinrot,safrangelb,safranrot,saharagelb,sandgelb,sandgelb,sandsteinrot,saphirblau,scharlachrot,schiefergrau,schilfgruen,schneeweiss,schokoladenbraun,schwarz,schwarzbraun,schwarzrot,schwefelgelb,seegruen,seidengrau,sepiabraun,siena,sienabraun,signalgelb,signalorange,signalrot,silber,silbergrau,silbrig,smalteblau,smaragdgruen,sonnengelb,stahlblau,staubgrau,suedseeblau,steingrau,tabakbraun,tannengruen,taubenblau,terrabraun,terracotta,tieforange,tiefschwarz,tintenblau,tintenrot,tintenschwarz,titangrau,tizianrot,tomatenrot,torfbraun,tumblau,tuerkis,tuerkischrot,umbra,universalblau,ultramarinblau,veilchenblau,venezianischrot,violett,walnussbraun,wasserblau,weinrot,weiss,wiesengruen,wuestenrot,xenon,zartgruen,zartrosa,zeltgrau,zementgrau,ziegelrot,zimtbraun,zinkgelb,zinnoberrot,zitronengelb,zitrusgelb,zyan diff --git a/app/Helpers/HubHelper.php b/app/Helpers/HubHelper.php index 477f4a6c..52c70fff 100644 --- a/app/Helpers/HubHelper.php +++ b/app/Helpers/HubHelper.php @@ -119,6 +119,24 @@ public function name() } } + public function generation() + { + if ($this->isHub()) { + return $this->hub->generation; + } else { + return null; + } + } + + public function query_level() + { + if ($this->isHub()) { + return $this->hub->query_level; + } else { + return null; + } + } + public function url($name = null) { $protocol = $_SERVER['PROTOCOL'] = isset($_SERVER['HTTPS']) && ! empty($_SERVER['HTTPS']) ? 'https' : 'http'; diff --git a/app/Http/Controllers/FileController.php b/app/Http/Controllers/FileController.php index 261cc4b5..98ae4a70 100644 --- a/app/Http/Controllers/FileController.php +++ b/app/Http/Controllers/FileController.php @@ -24,13 +24,16 @@ public function showPhoto($filename) { $entry = Photo::where('url', '=', 'photos/'.$filename)->firstOrFail(); - //$this->authorize('view', $entry); + $url = $entry->url; + if (strpos($url, '_960') == false || strpos($url, '-unsplash') == false) { + $url = 'photos/generation_1/'.$filename; // legacy support + } - if (Storage::disk('local')->exists($entry->url)) { - $file = Storage::disk('local')->get($entry->url); + if (Storage::disk('local')->exists($url)) { + $file = Storage::disk('local')->get($url); return (new Response($file, 200)) - ->header('Content-Type', Storage::mimeType($entry->url)) + ->header('Content-Type', Storage::mimeType($url)) ->header('Content-Disposition', 'attachment; filename="'.'photo'.'"'); } else { abort(404); @@ -53,10 +56,15 @@ public function showAvatar($filename) $user = User::where('avatar', '=', 'avatars/'.$filename)->firstOrFail(); - $file = Storage::disk('local')->get($user->avatar); + $avatar = $user->avatar; + if (preg_match('/^(\d{3})\.jpg$/', $filename) && intval($filename) <= 196) { + $avatar = 'avatars/generation_1/'.$filename; // legacy support + } + + $file = Storage::disk('local')->get($avatar); return (new Response($file, 200)) - ->header('Content-Type', Storage::mimeType($user->avatar)) + ->header('Content-Type', Storage::mimeType($avatar)) ->header('Content-Disposition', 'attachment; filename="'.$user->username.'"'); } @@ -70,10 +78,10 @@ public function destroyAvatar($filename) { $user = User::where('avatar', '=', 'avatars/'.$filename)->firstOrFail(); - $preset_avatars = ['000.jpg', '001.jpg', '002.jpg', '003.jpg', '004.jpg', '005.jpg', '006.jpg', '007.jpg', '008.jpg', '009.jpg', '010.jpg', '011.jpg', '012.jpg', '013.jpg', '014.jpg', '015.jpg', '016.jpg', '017.jpg', '018.jpg', '019.jpg', '020.jpg', '021.jpg', '022.jpg', '023.jpg', '024.jpg', '025.jpg', '026.jpg', '027.jpg', '028.jpg', '029.jpg', '030.jpg', '031.jpg', '032.jpg', '033.jpg', '034.jpg', '035.jpg', '036.jpg', '037.jpg', '038.jpg', '039.jpg', '040.jpg', '041.jpg', '042.jpg', '043.jpg', '044.jpg', '045.jpg', '046.jpg', '047.jpg', '048.jpg', '049.jpg', '050.jpg', '051.jpg', '052.jpg', '053.jpg', '054.jpg', '055.jpg', '056.jpg', '057.jpg', '058.jpg', '059.jpg', '060.jpg', '061.jpg', '062.jpg', '063.jpg', '064.jpg', '065.jpg', '066.jpg', '067.jpg', '068.jpg', '069.jpg', '070.jpg', '071.jpg', '072.jpg', '073.jpg', '074.jpg', '075.jpg', '076.jpg', '077.jpg', '078.jpg', '079.jpg', '080.jpg', '081.jpg', '082.jpg', '083.jpg', '084.jpg', '085.jpg', '086.jpg', '087.jpg', '088.jpg', '089.jpg', '090.jpg', '091.jpg', '092.jpg', '093.jpg', '094.jpg', '095.jpg', '096.jpg', '097.jpg', '098.jpg', '099.jpg', '100.jpg', '101.jpg', '102.jpg', '103.jpg', '104.jpg', '105.jpg', '106.jpg', '107.jpg', '108.jpg', '109.jpg', '110.jpg', '111.jpg', '112.jpg', '113.jpg', '114.jpg', '115.jpg', '116.jpg', '117.jpg', '118.jpg', '119.jpg', '120.jpg', '121.jpg', '122.jpg', '123.jpg', '124.jpg', '125.jpg', '126.jpg', '127.jpg', '128.jpg', '129.jpg', '130.jpg', '131.jpg', '132.jpg', '133.jpg', '134.jpg', '135.jpg', '136.jpg', '137.jpg', '138.jpg', '139.jpg', '140.jpg', '141.jpg', '142.jpg', '143.jpg', '144.jpg', '145.jpg', '146.jpg', '147.jpg', '148.jpg', '149.jpg', '150.jpg', '151.jpg', '152.jpg', '153.jpg', '154.jpg', '155.jpg', '156.jpg', '157.jpg', '158.jpg', '159.jpg', '160.jpg', '161.jpg', '162.jpg', '163.jpg', '164.jpg', '165.jpg', '166.jpg', '167.jpg', '168.jpg', '169.jpg', '170.jpg', '171.jpg', '172.jpg', '173.jpg', '174.jpg', '175.jpg', '176.jpg', '177.jpg', '178.jpg', '179.jpg', '180.jpg', '181.jpg', '182.jpg', '183.jpg', '184.jpg', '185.jpg', '186.jpg', '187.jpg', '188.jpg', '189.jpg', '190.jpg', '191.jpg', '192.jpg', '193.jpg', '194.jpg', '195.jpg', '196.jpg']; + $isPresetAvatar = preg_match('/^(\d{3})\.jpg$/', $filename) && intval($filename) <= 196; - if (! in_array($filename, $preset_avatars)) { - //uploaded avater + if (!$isPresetAvatar) { + // uploaded avatar return Storage::disk('local')->delete($user->avatar); } } diff --git a/app/Http/Controllers/HubController.php b/app/Http/Controllers/HubController.php index 2d5afec1..b7c7929a 100644 --- a/app/Http/Controllers/HubController.php +++ b/app/Http/Controllers/HubController.php @@ -163,13 +163,16 @@ function ($attribute, $value, $fail) { RequestHub::setHubDB($hub->id); - DB::statement('SET FOREIGN_KEY_CHECKS = 0'); - Schema::dropIfExists('users'); //not necesary but sometimes happend strage bug while registering.. - DB::statement('SET FOREIGN_KEY_CHECKS = 1'); - - Artisan::call('migrate', ['--path' => 'database/migrations/create/users', '--force' => true]); - Artisan::call('db:seed', ['--class' => 'UsersTableSeeder', '--force' => true]); - Schema::dropIfExists('migrations'); //sorry laravel, but thats the only way. + // hydrate hub + if(Auth::user()->hub_default_creating == 'users') { + $hub->changeTables(['users'], 'users'); + } + else if(Auth::user()->hub_default_creating == 'all_empty') { + $hub->changeTables(['users'], 'create'); + } + else if(Auth::user()->hub_default_creating == 'all_full') { + $hub->changeTables(['users','photos','tags','likes','follows','comments','analytics','ads'], 'fill'); + } //insert admin $url = 'avatar.png'; diff --git a/app/Http/Controllers/SqlController.php b/app/Http/Controllers/SqlController.php index 8b7a6fc0..3557b0a8 100644 --- a/app/Http/Controllers/SqlController.php +++ b/app/Http/Controllers/SqlController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers; +use App\Facades\RequestHub; use App\Http\Controllers\Controller; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; @@ -21,6 +22,19 @@ public function sql() public function selectGui() { + if(RequestHub::query_level() != 'gui' && RequestHub::query_level() != 'ai') { + abort(403); + } + return view('admin.select'); } + + public function sqlAi() + { + if(RequestHub::query_level() != 'ai') { + abort(403); + } + + return view('admin.ai'); + } } diff --git a/app/Livewire/Admin/Sql.php b/app/Livewire/Admin/Sql.php index a2ee463b..b67843ea 100644 --- a/app/Livewire/Admin/Sql.php +++ b/app/Livewire/Admin/Sql.php @@ -13,7 +13,8 @@ class Sql extends Component public $result = ''; public $tables = ''; public $message = null; - public $type = null; + public $results = []; + public function mount() { @@ -30,61 +31,38 @@ public function runQuery() { $this->result = ''; $this->message = null; - $this->type = null; try { if (strpos(strtolower(trim($this->query)), 'select') !== 0) { DB::statement($this->query); - $this->message = 'Anfrage ausgeführt.'; - $this->type = 'success'; + $this->message = [ + 'type' => 'success', + 'text' => __('Query executed.'), + ]; } else { - $r = DB::select($this->query); - if (!$r) { - $this->message = __('Query executed. 0 results found.'); - $this->type = 'warning'; + $this->results = DB::select($this->query); + if (! $this->results) { + $this->message = [ + 'type' => 'warning', + 'text' => __('Query executed. 0 results found.'), + ]; } else { - $this->message = __('Query executed successfully. :count results found.', ['count' => count($r)]); - $this->type = 'success'; - $this->result = $this->formatResult($r); + $this->message = [ + 'type' => 'success', + 'text' => __('Query executed successfully. :count results found.', ['count' => count($this->results)]) + ]; } } - } catch (QueryException $ex) { - $this->message = $ex->getMessage(); - $this->type = 'danger'; + } catch (QueryException $e) { + $this->message = [ + 'type' => 'danger', + 'text' => $e->getMessage() + ]; } session(['last_query' => $this->query]); } - private function formatResult($r) - { - $cols = array_keys((array) $r[0]); - $t = ""; - $t .= ""; - foreach ($cols as $col) { - $t .= ""; - } - $t .= ""; - foreach ($r as $row) { - $t .= ""; - foreach ($cols as $col) { - $value = $row->$col; - if ($value === null) { - $t .= ""; - } elseif (filter_var($value, FILTER_VALIDATE_URL)) { - $t .= ""; - } elseif (preg_match("/^.*\.(jpg|jpeg|png|gif)$/i", $value)) { - $t .= ""; - } else { - $t .= ""; - } - } - $t .= ""; - } - $t .= "
" . htmlspecialchars($col) . "
NULL" . htmlspecialchars($value) . "" . htmlspecialchars($value) . "" . htmlspecialchars($value) . "
"; - return $t; - } - private function loadTables() { $r = DB::table('information_schema.tables')->where('table_schema', DB::getDatabaseName())->get(); diff --git a/app/Livewire/Admin/SqlAi.php b/app/Livewire/Admin/SqlAi.php new file mode 100644 index 00000000..6f6c7ece --- /dev/null +++ b/app/Livewire/Admin/SqlAi.php @@ -0,0 +1,150 @@ +prompt = session('last_prompt', ''); + $this->loadTables(); + } + + public function render() + { + return view('livewire.admin.sql-ai'); + } + + public function runQuery() + { + $this->result = ''; + $this->message = null; + + if(! $this->prompt) { + return; + } + + try { + $client = OpenAI::factory() + ->withBaseUri(config('azure.resource_name').'.openai.azure.com/openai/deployments/'.config('azure.deployment_id')) + ->withHttpHeader('api-key', config('azure.openai_key')) + ->withQueryParam('api-version', config('azure.api_version')) + ->make(); + + $result = $client->chat()->create([ + 'messages' => [ + ['role' => 'system', 'content' => $this->buildSystemPrompt()], + ['role' => 'user', 'content' => $this->prompt], + ], + 'max_tokens' => 100, + ]); + + $this->query = $this->extractSQL($result->choices[0]->message->content); + + if($this->query == 'UNKNOWN') { + $this->message = [ + 'type' => 'danger', + 'text' => __('The input cannot be implemented with a database query.'), + ]; + + return; + } + } catch (Throwable $e) { + $this->message = [ + 'type' => 'danger', + 'text' => (config('app.debug')) ? $e->getMessage() : __('Error in the AI query.'), + ]; + + return; + } + + try { + if (strpos(strtolower(trim($this->query)), 'select') !== 0) { + DB::statement($this->query); + $this->message = [ + 'type' => 'success', + 'text' => __('Query executed.'), + ]; + } else { + $this->results = DB::select($this->query); + if (! $this->results) { + $this->message = [ + 'type' => 'warning', + 'text' => __('Query executed. 0 results found.'), + ]; + } else { + $this->message = [ + 'type' => 'success', + 'text' => __('Query executed successfully. :count results found.', ['count' => count($this->results)]) + ]; + } + } + } catch (QueryException $e) { + $this->message = [ + 'type' => 'danger', + 'text' => $e->getMessage() + ]; + } + + session(['last_prompt' => $this->prompt]); + } + + private function buildSystemPrompt() + { + $command = <<<'EOT' +Du bist ein SQL-Generator. Du antwortest ausschließlich in gültigen SQL. + +Der Nutzer hat eine Aufgabe, die sich mit SQL Lösen lässt. Andernfalls schreibe nur UNKNOWN + +Folgende einzelne Tabellen können abgefragt werden: +EOT; + + return $command . '\n' . $this->loadTables(); + } + + private function loadTables() + { + $r = DB::table('information_schema.tables')->where('table_schema', DB::getDatabaseName())->get(); + $dbclass = ''; + foreach ($r as $v) { + if (!strcmp($v->TABLE_TYPE, 'BASE TABLE') && $v->TABLE_NAME != 'migrations') { + $dbclass .= $v->TABLE_NAME . ': '; + $columns = Schema::getColumnListing($v->TABLE_NAME); + $dbclass .= implode(', ', $columns); + $dbclass .= '\n'; + } + } + $this->tables = $dbclass; + } + + private function extractSQL($input) { + // Entferne Leerzeichen am Anfang und Ende + $input = trim($input); + + // Prüfe, ob der Input mit Markdown-Codeblock-Syntax beginnt + if (preg_match('/^```sql\s*(.*?)\s*```$/s', $input, $matches)) { + // Extrahiere den SQL-Code aus dem Markdown-Codeblock + return trim($matches[1]); + } elseif (preg_match('/^```\s*(.*?)\s*```$/s', $input, $matches)) { + // Für den Fall, dass 'sql' nach '```' fehlt, aber es trotzdem ein Codeblock ist + return trim($matches[1]); + } else { + // Wenn kein Markdown-Codeblock gefunden wurde, gib den gesamten Input zurück + return $input; + } + } +} \ No newline at end of file diff --git a/app/Livewire/Admin/SqlBuilder.php b/app/Livewire/Admin/SqlBuilder.php index 11a8e6ff..c916ae0c 100644 --- a/app/Livewire/Admin/SqlBuilder.php +++ b/app/Livewire/Admin/SqlBuilder.php @@ -2,6 +2,7 @@ namespace App\Livewire\Admin; +use Exception; use Livewire\Component; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; @@ -31,7 +32,7 @@ class SqlBuilder extends Component public $attr = []; public $rules = []; public $message = null; - public $table = null; + public $results = []; public function mount() { @@ -97,48 +98,23 @@ public function getQueryRules() public function getResult() { try { - $results = DB::select($this->query); - if (!$results) { + $this->results = DB::select($this->query); + if (! $this->results) { $this->message = [ 'type' => 'warning', - 'text' => __('Anfrage ausgeführt. 0 Ergebnisse gefunden.') + 'text' => __('Query executed. 0 results found.'), ]; } else { $this->message = [ 'type' => 'success', - 'text' => __('Query executed successfully. :count results found.', ['count' => count($results)]) + 'text' => __('Query executed successfully. :count results found.', ['count' => count($this->results)]) ]; } - $this->table = $this->formatResult($results); - } catch (\Exception $e) { + } catch (Exception $e) { $this->message = [ 'type' => 'danger', 'text' => $e->getMessage() ]; } } - - private function formatResult($results) - { - if (empty($results)) { - return null; - } - - $html = ''; - foreach (array_keys((array)$results[0]) as $column) { - $html .= ""; - } - $html .= ''; - - foreach ($results as $row) { - $html .= ''; - foreach ((array)$row as $value) { - $html .= ""; - } - $html .= ''; - } - - $html .= '
$column
$value
'; - return $html; - } } \ No newline at end of file diff --git a/app/Livewire/Hub/Index.php b/app/Livewire/Hub/Index.php index 4b88ad9e..ef6f84a1 100644 --- a/app/Livewire/Hub/Index.php +++ b/app/Livewire/Hub/Index.php @@ -20,6 +20,13 @@ class Index extends Component protected $queryString = ['search']; + public $selectedQueryLevel; + + public function mount(Hub $hub) + { + $this->selectedQueryLevel = $hub->query_level; + } + public function updatingSearch() { $this->resetPage(); @@ -47,35 +54,32 @@ public function render() public function setActivate($hubId, $activate) { - $this->loading['activate'] = true; - $hub = Hub::findOrFail($hubId); $hub->activated = $activate; // computed property - - $this->loading['activate'] = false; } public function setReadonly($hubId, $readonly) { - $this->loading['readonly'] = true; - $hub = Hub::findOrFail($hubId); $hub->readonly = $readonly; // computed property + } + + public function setQueryLevel($hubId, $queryLevel) + { + $hub = Hub::findOrFail($hubId); + $hub->query_level = $queryLevel; + $hub->save(); - $this->loading['readonly'] = false; + $this->selectedQueryLevel = $queryLevel; } public function fillTables($hubId, $tables) { - $this->loading['fill'] = true; - $hub = Hub::findOrFail($hubId); $tableArray = explode(',', $tables); $hub->changeTables($tableArray, 'fill'); - - $this->loading['fill'] = false; } } \ No newline at end of file diff --git a/app/Livewire/UserHubSettings.php b/app/Livewire/UserHubSettings.php new file mode 100644 index 00000000..64a5c3ac --- /dev/null +++ b/app/Livewire/UserHubSettings.php @@ -0,0 +1,55 @@ + 'required|integer', + 'hubDefaultCreating' => 'required|in:users,all_empty,all_full', + 'hubDefaultQueryLevel' => 'required|in:ai,gui,sql', + ]; + + public function mount() + { + $user = Auth::user(); + $this->generation = $user->hub_default_generation; + $this->hubDefaultCreating = $user->hub_default_creating; + $this->hubDefaultQueryLevel = $user->hub_default_query_level; + $this->availableGenerations = config('hub.generations'); + } + + public function updatedHubDefaultQueryLevel() + { + if ($this->hubDefaultQueryLevel === 'ai' && !Auth::user()->is_sponsor) { + $this->hubDefaultQueryLevel = 'gui'; + $this->addError('hubDefaultQueryLevel', __('You need to be a sponsor to use AI query level.')); + } + } + + public function save() + { + $this->validate(); + + $user = Auth::user(); + $user->hub_default_generation = $this->generation; + $user->hub_default_creating = $this->hubDefaultCreating; + $user->hub_default_query_level = $this->hubDefaultQueryLevel; + $user->save(); + + session()->flash('message', __('Settings updated successfully.')); + } + + public function render() + { + return view('livewire.user-hub-settings'); + } +} \ No newline at end of file diff --git a/app/Models/Hub.php b/app/Models/Hub.php index 3a5b4373..8ccc07c8 100644 --- a/app/Models/Hub.php +++ b/app/Models/Hub.php @@ -8,6 +8,7 @@ use Config; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\Artisan; +use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; use Storage; @@ -16,7 +17,7 @@ class Hub extends Model { protected $table = 'hubs'; - protected $fillable = ['teacher_id', 'password', 'name']; + protected $fillable = ['teacher_id', 'password', 'name', 'generation', 'query_level']; public function teacher() { @@ -208,7 +209,7 @@ public function fillTable($tablename) Schema::dropIfExists('migrations'); //sorry laravel, but thats the only way. } - Artisan::call('db:seed', ['--class' => ucfirst($tablename).'TableSeeder', '--force' => true]); + Artisan::call('db:seed', ['--class' => 'Database\Seeders\Generation'.Auth::user()->hub_default_generation.'\\'.ucfirst($tablename).'TableSeeder', '--force' => true]); // $this->messages[] = "Table $tablename filled with dummy data."; diff --git a/app/Models/User.php b/app/Models/User.php index 347e900d..e27fdb7e 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -34,6 +34,7 @@ class User extends Authenticatable implements MustVerifyEmail protected $fillable = [ 'username', 'name', 'email', 'password', 'bio', 'avatar', 'birthday', 'city', 'country', 'gender', 'centimeters', 'is_active', 'role', 'is_admin', + 'is_sponsor', 'hub_default_generation', 'hub_default_creating', 'hub_default_query_level', ]; /** diff --git a/composer.json b/composer.json index f348a2bf..44d28e80 100644 --- a/composer.json +++ b/composer.json @@ -12,6 +12,7 @@ "laravel/tinker": "^2.9", "laravel/ui": "^4.5", "livewire/livewire": "^3.5", + "openai-php/client": "^0.10.1", "orangehill/iseed": "^3.0" }, "require-dev": { diff --git a/composer.lock b/composer.lock index 34e69f0a..5830bccc 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "52c6015c185ec9e06e0e4ea560209646", + "content-hash": "1995d0662a503b94587803beec5e5d2b", "packages": [ { "name": "brick/math", @@ -2956,6 +2956,98 @@ ], "time": "2024-03-06T16:17:14+00:00" }, + { + "name": "openai-php/client", + "version": "v0.10.1", + "source": { + "type": "git", + "url": "https://github.com/openai-php/client.git", + "reference": "8b63d27a2f009a7ce4714fda77769e93d883c8da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/openai-php/client/zipball/8b63d27a2f009a7ce4714fda77769e93d883c8da", + "reference": "8b63d27a2f009a7ce4714fda77769e93d883c8da", + "shasum": "" + }, + "require": { + "php": "^8.1.0", + "php-http/discovery": "^1.19.4", + "php-http/multipart-stream-builder": "^1.3.0", + "psr/http-client": "^1.0.3", + "psr/http-client-implementation": "^1.0.1", + "psr/http-factory-implementation": "*", + "psr/http-message": "^1.1.0|^2.0.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "^7.8.1", + "guzzlehttp/psr7": "^2.6.2", + "laravel/pint": "^1.16.0", + "mockery/mockery": "^1.6.12", + "nunomaduro/collision": "^7.10.0", + "pestphp/pest": "^2.34.7", + "pestphp/pest-plugin-arch": "^2.7", + "pestphp/pest-plugin-type-coverage": "^2.8.2", + "phpstan/phpstan": "^1.11.2", + "rector/rector": "^1.1.0", + "symfony/var-dumper": "^6.4.7" + }, + "type": "library", + "autoload": { + "files": [ + "src/OpenAI.php" + ], + "psr-4": { + "OpenAI\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + }, + { + "name": "Sandro Gehri" + } + ], + "description": "OpenAI PHP is a supercharged PHP API client that allows you to interact with the Open AI API", + "keywords": [ + "GPT-3", + "api", + "client", + "codex", + "dall-e", + "language", + "natural", + "openai", + "php", + "processing", + "sdk" + ], + "support": { + "issues": "https://github.com/openai-php/client/issues", + "source": "https://github.com/openai-php/client/tree/v0.10.1" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/gehrisandro", + "type": "github" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + } + ], + "time": "2024-06-06T20:27:51+00:00" + }, { "name": "orangehill/iseed", "version": "v3.0.4", @@ -3019,6 +3111,141 @@ }, "time": "2024-03-27T08:01:21+00:00" }, + { + "name": "php-http/discovery", + "version": "1.19.4", + "source": { + "type": "git", + "url": "https://github.com/php-http/discovery.git", + "reference": "0700efda8d7526335132360167315fdab3aeb599" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/discovery/zipball/0700efda8d7526335132360167315fdab3aeb599", + "reference": "0700efda8d7526335132360167315fdab3aeb599", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0|^2.0", + "php": "^7.1 || ^8.0" + }, + "conflict": { + "nyholm/psr7": "<1.0", + "zendframework/zend-diactoros": "*" + }, + "provide": { + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/http-client-implementation": "*", + "psr/http-factory-implementation": "*", + "psr/http-message-implementation": "*" + }, + "require-dev": { + "composer/composer": "^1.0.2|^2.0", + "graham-campbell/phpspec-skip-example-extension": "^5.0", + "php-http/httplug": "^1.0 || ^2.0", + "php-http/message-factory": "^1.0", + "phpspec/phpspec": "^5.1 || ^6.1 || ^7.3", + "sebastian/comparator": "^3.0.5 || ^4.0.8", + "symfony/phpunit-bridge": "^6.4.4 || ^7.0.1" + }, + "type": "composer-plugin", + "extra": { + "class": "Http\\Discovery\\Composer\\Plugin", + "plugin-optional": true + }, + "autoload": { + "psr-4": { + "Http\\Discovery\\": "src/" + }, + "exclude-from-classmap": [ + "src/Composer/Plugin.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "Finds and installs PSR-7, PSR-17, PSR-18 and HTTPlug implementations", + "homepage": "http://php-http.org", + "keywords": [ + "adapter", + "client", + "discovery", + "factory", + "http", + "message", + "psr17", + "psr7" + ], + "support": { + "issues": "https://github.com/php-http/discovery/issues", + "source": "https://github.com/php-http/discovery/tree/1.19.4" + }, + "time": "2024-03-29T13:00:05+00:00" + }, + { + "name": "php-http/multipart-stream-builder", + "version": "1.3.1", + "source": { + "type": "git", + "url": "https://github.com/php-http/multipart-stream-builder.git", + "reference": "ed56da23b95949ae4747378bed8a5b61a2fdae24" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/multipart-stream-builder/zipball/ed56da23b95949ae4747378bed8a5b61a2fdae24", + "reference": "ed56da23b95949ae4747378bed8a5b61a2fdae24", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0", + "php-http/discovery": "^1.15", + "psr/http-factory-implementation": "^1.0" + }, + "require-dev": { + "nyholm/psr7": "^1.0", + "php-http/message": "^1.5", + "php-http/message-factory": "^1.0.2", + "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Http\\Message\\MultipartStream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com" + } + ], + "description": "A builder class that help you create a multipart stream", + "homepage": "http://php-http.org", + "keywords": [ + "factory", + "http", + "message", + "multipart stream", + "stream" + ], + "support": { + "issues": "https://github.com/php-http/multipart-stream-builder/issues", + "source": "https://github.com/php-http/multipart-stream-builder/tree/1.3.1" + }, + "time": "2024-06-10T14:51:55+00:00" + }, { "name": "phpoption/phpoption", "version": "1.9.2", @@ -10176,5 +10403,5 @@ "php": "^8.2" }, "platform-dev": [], - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/config/azure.php b/config/azure.php new file mode 100644 index 00000000..8667752b --- /dev/null +++ b/config/azure.php @@ -0,0 +1,8 @@ + env('AZURE_RESOURCE_NAME'), + 'deployment_id' => env('AZURE_DEPLOYMENT_ID'), + 'openai_key' => env('AZURE_OPENAI_KEY'), + 'api_version' => env('AZURE_VERSION'), +]; \ No newline at end of file diff --git a/config/hub.php b/config/hub.php new file mode 100644 index 00000000..1cc2d478 --- /dev/null +++ b/config/hub.php @@ -0,0 +1,11 @@ + env('HUB_DEFAULT_GENERATION'), + 'generations' => [ + 1 => [ + 'name' => 'Generation 2017', + 'url' => env('HUB_DOC_1_URL'), + ], + ], +]; \ No newline at end of file diff --git a/database/migrations/2024_07_10_155013_add_hub_related_fields_to_users_table.php b/database/migrations/2024_07_10_155013_add_hub_related_fields_to_users_table.php new file mode 100644 index 00000000..d9600439 --- /dev/null +++ b/database/migrations/2024_07_10_155013_add_hub_related_fields_to_users_table.php @@ -0,0 +1,28 @@ +boolean('is_sponsor')->default(false)->after('is_active'); + $table->integer('hub_default_generation')->default(1)->after('is_sponsor'); + $table->enum('hub_default_creating', ['users', 'all_empty', 'all_full'])->after('hub_default_generation'); + $table->enum('hub_default_query_level', ['ai', 'gui', 'sql'])->default('gui')->after('hub_default_creating'); + }); + } + + public function down() + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('hub_default_generation'); + $table->dropColumn('is_sponsor'); + $table->dropColumn('hub_default_creating'); + $table->dropColumn('hub_default_query_level'); + }); + } +}; \ No newline at end of file diff --git a/database/migrations/2024_07_10_155039_add_generation_and_query_level_to_hubs_table.php b/database/migrations/2024_07_10_155039_add_generation_and_query_level_to_hubs_table.php new file mode 100644 index 00000000..bfd9a158 --- /dev/null +++ b/database/migrations/2024_07_10_155039_add_generation_and_query_level_to_hubs_table.php @@ -0,0 +1,24 @@ +integer('generation')->default(1)->after('password'); + $table->enum('query_level', ['ai', 'gui', 'sql'])->default('gui')->after('generation'); + }); + } + + public function down() + { + Schema::table('hubs', function (Blueprint $table) { + $table->dropColumn('generation'); + $table->dropColumn('query_level'); + }); + } +}; \ No newline at end of file diff --git a/database/migrations/update/2024_07_10_155039_add_generation_and_query_level_to_hubs_table.php b/database/migrations/update/2024_07_10_155039_add_generation_and_query_level_to_hubs_table.php new file mode 100644 index 00000000..bfd9a158 --- /dev/null +++ b/database/migrations/update/2024_07_10_155039_add_generation_and_query_level_to_hubs_table.php @@ -0,0 +1,24 @@ +integer('generation')->default(1)->after('password'); + $table->enum('query_level', ['ai', 'gui', 'sql'])->default('gui')->after('generation'); + }); + } + + public function down() + { + Schema::table('hubs', function (Blueprint $table) { + $table->dropColumn('generation'); + $table->dropColumn('query_level'); + }); + } +}; \ No newline at end of file diff --git a/database/seeders/AdsTableSeeder.php b/database/seeders/Generation1/AdsTableSeeder.php similarity index 99% rename from database/seeders/AdsTableSeeder.php rename to database/seeders/Generation1/AdsTableSeeder.php index 988839c0..f26a73b7 100644 --- a/database/seeders/AdsTableSeeder.php +++ b/database/seeders/Generation1/AdsTableSeeder.php @@ -1,6 +1,6 @@ diff --git a/resources/views/admin/ai.blade.php b/resources/views/admin/ai.blade.php new file mode 100644 index 00000000..ec025ad5 --- /dev/null +++ b/resources/views/admin/ai.blade.php @@ -0,0 +1,21 @@ +@extends('layouts.app') + +@section('content') +
+
+
+ @include('flash::message') +
+
+

{{__('Ask')}}

+
+
+ @livewire('admin.sql-ai') +
+
+
+
+
+
+
+@endsection \ No newline at end of file diff --git a/resources/views/admin/partials/result-table.blade.php b/resources/views/admin/partials/result-table.blade.php new file mode 100644 index 00000000..7ac7ff6c --- /dev/null +++ b/resources/views/admin/partials/result-table.blade.php @@ -0,0 +1,32 @@ +@if(!empty($results)) + + + + @foreach(array_keys((array)$results[0]) as $column) + + @endforeach + + + + @foreach($results as $row) + + @foreach((array)$row as $value) + + @endforeach + + @endforeach + +
{{ $column }}
+ @if(is_null($value)) + NULL + @elseif(filter_var($value, FILTER_VALIDATE_URL)) + {{ $value }} + @elseif(preg_match("/^.*\.(jpg|jpeg|png|gif)$/i", $value)) + {{ $value }} + @else + {{ $value }} + @endif +
+@else +

Keine Ergebnisse gefunden.

+@endif \ No newline at end of file diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php index 0734e19a..7c448055 100644 --- a/resources/views/auth/login.blade.php +++ b/resources/views/auth/login.blade.php @@ -73,7 +73,7 @@

{{ __('messages.firstStepTeacher') }}

- {{ __('Documentation') }} + {{ __('Documentation') }} diff --git a/resources/views/hub/index.blade.php b/resources/views/hub/index.blade.php index 478a7093..1cc13a9c 100644 --- a/resources/views/hub/index.blade.php +++ b/resources/views/hub/index.blade.php @@ -3,6 +3,10 @@ @section('content')

{{ __('Hubs') }}

+
+ @livewire('user-hub-settings') +
+
@livewire('hub.index')
@endsection diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index 9ed600e0..3251fcf7 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -114,6 +114,7 @@ {{ __('Database') }} @@ -122,7 +123,7 @@ @if (!Auth::guest() && ! RequestHub::isHub() && Auth::user()->allowed('teacher'))