update ai stuff
This commit is contained in:
@@ -5,10 +5,8 @@ import { promises as fs } from 'fs';
|
||||
import { load } from 'js-yaml';
|
||||
import path from 'path';
|
||||
|
||||
|
||||
export const prerender = false;
|
||||
|
||||
|
||||
function getEnv(key: string): string {
|
||||
const value = process.env[key];
|
||||
if (!value) {
|
||||
@@ -211,7 +209,7 @@ export const POST: APIRoute = async ({ request }) => {
|
||||
'Authorization': `Bearer ${process.env.AI_API_KEY}`
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: AI_MODEL, // or whatever model is available
|
||||
model: 'gpt-4o-mini', // or whatever model is available
|
||||
messages: [
|
||||
{
|
||||
role: 'system',
|
||||
@@ -248,8 +246,7 @@ export const POST: APIRoute = async ({ request }) => {
|
||||
// Parse AI JSON response
|
||||
let recommendation;
|
||||
try {
|
||||
const cleanedContent = stripMarkdownJson(aiContent);
|
||||
recommendation = JSON.parse(cleanedContent);
|
||||
recommendation = JSON.parse(aiContent);
|
||||
} catch (error) {
|
||||
console.error('Failed to parse AI response:', aiContent);
|
||||
return new Response(JSON.stringify({ error: 'Invalid AI response format' }), {
|
||||
|
||||
@@ -1,13 +1,31 @@
|
||||
// src/pages/api/auth/status.ts
|
||||
import type { APIRoute } from 'astro';
|
||||
import { getSessionFromRequest, verifySession } from '../../../utils/auth.js';
|
||||
|
||||
export const prerender = false;
|
||||
|
||||
export const GET: APIRoute = async ({ request }) => {
|
||||
try {
|
||||
// Check if authentication is required
|
||||
const authRequired = process.env.AUTHENTICATION_NECESSARY !== 'false';
|
||||
|
||||
if (!authRequired) {
|
||||
// If authentication is not required, always return authenticated
|
||||
return new Response(JSON.stringify({
|
||||
authenticated: true,
|
||||
authRequired: false
|
||||
}), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
}
|
||||
|
||||
const sessionToken = getSessionFromRequest(request);
|
||||
|
||||
if (!sessionToken) {
|
||||
return new Response(JSON.stringify({
|
||||
authenticated: false
|
||||
authenticated: false,
|
||||
authRequired: true
|
||||
}), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
@@ -18,6 +36,7 @@ export const GET: APIRoute = async ({ request }) => {
|
||||
|
||||
return new Response(JSON.stringify({
|
||||
authenticated: session !== null,
|
||||
authRequired: true,
|
||||
expires: session?.exp ? new Date(session.exp * 1000).toISOString() : null
|
||||
}), {
|
||||
status: 200,
|
||||
@@ -27,6 +46,7 @@ export const GET: APIRoute = async ({ request }) => {
|
||||
} catch (error) {
|
||||
return new Response(JSON.stringify({
|
||||
authenticated: false,
|
||||
authRequired: process.env.AUTHENTICATION_NECESSARY !== 'false',
|
||||
error: 'Session verification failed'
|
||||
}), {
|
||||
status: 200,
|
||||
|
||||
@@ -3,6 +3,7 @@ import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
import ToolCard from '../components/ToolCard.astro';
|
||||
import ToolFilters from '../components/ToolFilters.astro';
|
||||
import ToolMatrix from '../components/ToolMatrix.astro';
|
||||
import AIQueryInterface from '../components/AIQueryInterface.astro';
|
||||
import { promises as fs } from 'fs';
|
||||
import { load } from 'js-yaml';
|
||||
import path from 'path';
|
||||
@@ -45,6 +46,16 @@ const tools = data.tools;
|
||||
</svg>
|
||||
SSO & Zugang erfahren
|
||||
</a>
|
||||
|
||||
<!-- New AI Query Button -->
|
||||
<button id="ai-query-btn" class="btn btn-accent" style="padding: 0.75rem 1.5rem; background-color: var(--color-accent); color: white;">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-right: 0.5rem;">
|
||||
<path d="M9 11H5a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7a2 2 0 0 0-2-2h-4"/>
|
||||
<path d="M9 11V7a3 3 0 0 1 6 0v4"/>
|
||||
</svg>
|
||||
KI befragen
|
||||
</button>
|
||||
|
||||
<a href="#filters-section" class="btn btn-secondary" style="padding: 0.75rem 1.5rem;">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-right: 0.5rem;">
|
||||
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path>
|
||||
@@ -61,6 +72,9 @@ const tools = data.tools;
|
||||
<section id="filters-section" style="padding: 2rem 0;">
|
||||
<ToolFilters />
|
||||
</section>
|
||||
|
||||
<!-- AI Query Interface -->
|
||||
<AIQueryInterface />
|
||||
|
||||
<!-- Tools Grid -->
|
||||
<section id="tools-grid" style="padding-bottom: 2rem;">
|
||||
@@ -86,10 +100,13 @@ const tools = data.tools;
|
||||
const toolsContainer = document.getElementById('tools-container');
|
||||
const toolsGrid = document.getElementById('tools-grid');
|
||||
const matrixContainer = document.getElementById('matrix-container');
|
||||
const aiInterface = document.getElementById('ai-interface');
|
||||
const filtersSection = document.getElementById('filters-section');
|
||||
const noResults = document.getElementById('no-results');
|
||||
const aiQueryBtn = document.getElementById('ai-query-btn');
|
||||
|
||||
// Guard against null elements
|
||||
if (!toolsContainer || !toolsGrid || !matrixContainer || !noResults) {
|
||||
if (!toolsContainer || !toolsGrid || !matrixContainer || !noResults || !aiInterface || !filtersSection) {
|
||||
console.error('Required DOM elements not found');
|
||||
return;
|
||||
}
|
||||
@@ -97,14 +114,90 @@ const tools = data.tools;
|
||||
// Initial tools HTML
|
||||
const initialToolsHTML = toolsContainer.innerHTML;
|
||||
|
||||
// Authentication check function
|
||||
async function checkAuthentication() {
|
||||
try {
|
||||
const response = await fetch('/api/auth/status');
|
||||
const data = await response.json();
|
||||
return data.authenticated;
|
||||
} catch (error) {
|
||||
console.error('Auth check failed:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// AI Query Button Handler
|
||||
if (aiQueryBtn) {
|
||||
aiQueryBtn.addEventListener('click', async () => {
|
||||
const isAuthenticated = await checkAuthentication();
|
||||
|
||||
if (!isAuthenticated) {
|
||||
// Redirect to login, then back to AI view
|
||||
const returnUrl = `${window.location.pathname}?view=ai`;
|
||||
window.location.href = `/api/auth/login?returnTo=${encodeURIComponent(returnUrl)}`;
|
||||
} else {
|
||||
// Switch to AI view
|
||||
switchToView('ai');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Check URL parameters on page load for view switching
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const viewParam = urlParams.get('view');
|
||||
if (viewParam === 'ai') {
|
||||
// User was redirected after authentication, switch to AI view
|
||||
switchToView('ai');
|
||||
}
|
||||
|
||||
// Function to switch between different views
|
||||
function switchToView(view) {
|
||||
// Hide all views first (using non-null assertions since we've already checked)
|
||||
toolsGrid!.style.display = 'none';
|
||||
matrixContainer!.style.display = 'none';
|
||||
aiInterface!.style.display = 'none';
|
||||
filtersSection!.style.display = 'none';
|
||||
|
||||
// Update view toggle buttons
|
||||
const viewToggles = document.querySelectorAll('.view-toggle');
|
||||
viewToggles.forEach(btn => {
|
||||
btn.classList.toggle('active', btn.getAttribute('data-view') === view);
|
||||
});
|
||||
|
||||
// Show appropriate view
|
||||
switch (view) {
|
||||
case 'ai':
|
||||
aiInterface!.style.display = 'block';
|
||||
// Focus on the input
|
||||
const aiInput = document.getElementById('ai-query-input');
|
||||
if (aiInput) {
|
||||
setTimeout(() => aiInput.focus(), 100);
|
||||
}
|
||||
break;
|
||||
case 'matrix':
|
||||
matrixContainer!.style.display = 'block';
|
||||
filtersSection!.style.display = 'block';
|
||||
break;
|
||||
default: // grid
|
||||
toolsGrid!.style.display = 'block';
|
||||
filtersSection!.style.display = 'block';
|
||||
break;
|
||||
}
|
||||
|
||||
// Clear URL parameters after switching
|
||||
if (window.location.search) {
|
||||
window.history.replaceState({}, '', window.location.pathname);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle filtered results
|
||||
window.addEventListener('toolsFiltered', (event: Event) => {
|
||||
const customEvent = event as CustomEvent;
|
||||
const filtered = customEvent.detail;
|
||||
const currentView = document.querySelector('.view-toggle.active')?.getAttribute('data-view');
|
||||
|
||||
if (currentView === 'matrix') {
|
||||
// Matrix view handles its own rendering
|
||||
if (currentView === 'matrix' || currentView === 'ai') {
|
||||
// Matrix and AI views handle their own rendering
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -128,16 +221,12 @@ const tools = data.tools;
|
||||
window.addEventListener('viewChanged', (event: Event) => {
|
||||
const customEvent = event as CustomEvent;
|
||||
const view = customEvent.detail;
|
||||
|
||||
if (view === 'matrix') {
|
||||
toolsGrid.style.display = 'none';
|
||||
matrixContainer.style.display = 'block';
|
||||
} else {
|
||||
toolsGrid.style.display = 'block';
|
||||
matrixContainer.style.display = 'none';
|
||||
}
|
||||
switchToView(view);
|
||||
});
|
||||
|
||||
// Make switchToView available globally for the AI button
|
||||
(window as any).switchToAIView = () => switchToView('ai');
|
||||
|
||||
function createToolCard(tool) {
|
||||
const hasValidProjectUrl = tool.projectUrl !== undefined &&
|
||||
tool.projectUrl !== null &&
|
||||
|
||||
Reference in New Issue
Block a user