Initial parser admin implementation

This commit is contained in:
Your Name
2026-06-15 21:14:07 +05:00
commit 59c899dc9c
51 changed files with 7052 additions and 0 deletions
+50
View File
@@ -0,0 +1,50 @@
ALTER TABLE raw_posts
ADD COLUMN IF NOT EXISTS qualification_status TEXT,
ADD COLUMN IF NOT EXISTS qualification_score INTEGER,
ADD COLUMN IF NOT EXISTS qualification_decision TEXT,
ADD COLUMN IF NOT EXISTS qualification_reason TEXT,
ADD COLUMN IF NOT EXISTS qualification_model TEXT,
ADD COLUMN IF NOT EXISTS qualification_prompt_hash TEXT,
ADD COLUMN IF NOT EXISTS qualification_batch_id BIGINT,
ADD COLUMN IF NOT EXISTS qualified_at TIMESTAMPTZ;
CREATE INDEX IF NOT EXISTS idx_raw_posts_qualification_claim
ON raw_posts(status, qualification_status, created_at)
WHERE status='storage_ready';
CREATE TABLE IF NOT EXISTS ai_qualification_batches (
id BIGSERIAL PRIMARY KEY,
status TEXT NOT NULL DEFAULT 'processing',
provider TEXT NOT NULL,
model TEXT NOT NULL,
prompt_hash TEXT NOT NULL,
posts_count INTEGER NOT NULL DEFAULT 0,
accepted_count INTEGER NOT NULL DEFAULT 0,
rejected_count INTEGER NOT NULL DEFAULT 0,
maybe_count INTEGER NOT NULL DEFAULT 0,
request_json JSONB NOT NULL DEFAULT '{}'::jsonb,
response_json JSONB,
error TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
completed_at TIMESTAMPTZ
);
INSERT INTO worker_controls(name, enabled, settings_json)
VALUES ('ai-qualifier', FALSE, '{}'::jsonb)
ON CONFLICT (name) DO NOTHING;
INSERT INTO app_settings(key, value_json, value_type, title, description, category)
VALUES
('ai_qualifier_enabled', 'false'::jsonb, 'bool', 'AI qualifier enabled', 'Enable qualification requests to AI API.', 'AI Qualifier'),
('ai_qualifier_provider', '"openrouter"'::jsonb, 'str', 'Provider', 'LiteLLM provider: openrouter, openai, anthropic, gemini, openai_compatible.', 'AI Qualifier'),
('ai_qualifier_model', '"openrouter/openai/gpt-4.1-mini"'::jsonb, 'str', 'Model', 'Model name in LiteLLM format.', 'AI Qualifier'),
('ai_qualifier_api_key', '""'::jsonb, 'secret', 'API key', 'AI provider API key.', 'AI Qualifier'),
('ai_qualifier_api_base', '""'::jsonb, 'str', 'API base', 'Optional base URL for OpenAI-compatible providers.', 'AI Qualifier'),
('ai_qualifier_batch_size', '30'::jsonb, 'int', 'Batch size', 'How many raw posts to classify in one request.', 'AI Qualifier'),
('ai_qualifier_min_score', '7'::jsonb, 'int', 'Minimum accepted score', 'Posts with score >= this value are accepted.', 'AI Qualifier'),
('ai_qualifier_interval_sec', '60'::jsonb, 'int', 'Idle interval, sec', 'Pause between qualifier checks.', 'AI Qualifier'),
('ai_qualifier_max_text_chars', '2000'::jsonb, 'int', 'Max text chars per post', 'Trim raw text before sending it to AI.', 'AI Qualifier'),
('ai_qualifier_temperature', '0'::jsonb, 'float', 'Temperature', 'AI sampling temperature for stable classification.', 'AI Qualifier'),
('ai_qualifier_timeout_sec', '120'::jsonb, 'int', 'Timeout, sec', 'AI request timeout.', 'AI Qualifier'),
('ai_qualifier_prompt', '"Ты квалификатор постов для проекта, который собирает посты производителей и магазинов милитари, тактической и airsoft-снаряги.\\n\\nОцени каждый raw-пост по пригодности для дальнейшего рерайта и публикации.\\n\\nПодходит: товарные посты, новинки, обзоры, производство, экипировка, тактическая одежда, броня, подсумки, рюкзаки, разгрузки, ремни, патчи, аксессуары, airsoft/страйкбольная снаряга, полезные анонсы производителя.\\n\\nМусор: мемы, поздравления, вакансии, политика, бытовуха, пустые посты, посты без конкретного товара/снаряжения, розыгрыши без предметного контента, чистая реклама скидки без понятного товара, нерелевантные новости.\\n\\nВерни только JSON-объект по схеме: {\\\"results\\\":[{\\\"id\\\":123,\\\"score\\\":8,\\\"decision\\\":\\\"accepted\\\",\\\"reason\\\":\\\"короткая причина\\\"}]}. score — целое число от 1 до 10. decision: accepted, rejected или maybe. Не добавляй markdown и пояснения вне JSON."'::jsonb, 'text', 'Prompt', 'Main qualification prompt.', 'AI Qualifier')
ON CONFLICT (key) DO NOTHING;