| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import { Router } from 'express' |
| import { |
| createInitialFeedbackState, |
| processFeedback, |
| computeHeuristics, |
| getFeedbackStats, |
| type FeedbackRecord, |
| type FeedbackState, |
| } from '../../src/lib/autotune-feedback' |
| import type { ContextType, AutoTuneParams } from '../../src/lib/autotune' |
| import { updateSharedProfiles } from './autotune' |
|
|
| export const feedbackRoutes = Router() |
|
|
| |
| let feedbackState: FeedbackState = createInitialFeedbackState() |
|
|
| const VALID_CONTEXTS: ContextType[] = ['code', 'creative', 'analytical', 'conversational', 'chaotic'] |
|
|
| feedbackRoutes.post('/', (req, res) => { |
| try { |
| const { |
| message_id, |
| context_type, |
| model = 'unknown', |
| persona = 'default', |
| rating, |
| params, |
| response_text, |
| } = req.body |
|
|
| |
| if (!message_id || typeof message_id !== 'string') { |
| res.status(400).json({ error: 'message_id (string) is required' }) |
| return |
| } |
|
|
| if (!VALID_CONTEXTS.includes(context_type)) { |
| res.status(400).json({ |
| error: `Invalid context_type. Must be one of: ${VALID_CONTEXTS.join(', ')}`, |
| }) |
| return |
| } |
|
|
| if (rating !== 1 && rating !== -1) { |
| res.status(400).json({ error: 'rating must be 1 (positive) or -1 (negative)' }) |
| return |
| } |
|
|
| if (!params || typeof params !== 'object') { |
| res.status(400).json({ error: 'params (AutoTuneParams object) is required' }) |
| return |
| } |
|
|
| |
| const heuristics = response_text |
| ? computeHeuristics(String(response_text)) |
| : { responseLength: 0, repetitionScore: 0, averageSentenceLength: 0, vocabularyDiversity: 0 } |
|
|
| const record: FeedbackRecord = { |
| messageId: message_id, |
| timestamp: Date.now(), |
| contextType: context_type, |
| model: String(model), |
| persona: String(persona), |
| params: params as AutoTuneParams, |
| rating, |
| heuristics, |
| } |
|
|
| |
| feedbackState = processFeedback(feedbackState, record) |
|
|
| |
| updateSharedProfiles(feedbackState.learnedProfiles) |
|
|
| res.json({ |
| accepted: true, |
| total_feedback: feedbackState.history.length, |
| context_type, |
| learned: feedbackState.learnedProfiles[context_type].sampleCount >= 3, |
| }) |
| } catch (err: any) { |
| res.status(500).json({ error: err.message }) |
| } |
| }) |
|
|
| feedbackRoutes.get('/stats', (_req, res) => { |
| const stats = getFeedbackStats(feedbackState) |
| res.json({ |
| total_feedback: stats.totalFeedback, |
| positive_rate: stats.positiveRate, |
| context_breakdown: stats.contextBreakdown, |
| oldest_record: stats.oldestRecord, |
| newest_record: stats.newestRecord, |
| }) |
| }) |
|
|