import sqlalchemy import marshmallow as ma from flask import Flask, request, render_template, jsonify from community_qa_bot.db import Session from community_qa_bot.types import Platform, FeedbackType from community_qa_bot.settings import ( TIDB_AI_API_KEY, TIDB_AI_FORUM_CHAT_ENGINE, ) from community_qa_bot.web.auth import token_required from community_qa_bot.web.schemas import ( SlackAIChannelSchema, CreateSlackAIChannelSchema, ) from community_qa_bot.models import ( SlackAIChannel, QaFeedback, QaHistory, User, ) from community_qa_bot.pingcap_qa_service import CommunityQAService from community_qa_bot.forum.app import forum_bp qa_service = CommunityQAService( api_key=TIDB_AI_API_KEY, chat_engine=TIDB_AI_FORUM_CHAT_ENGINE, ) app = Flask( __name__, static_folder='../frontend/dist/static/', template_folder='../frontend/dist/', ) app.register_blueprint(forum_bp, url_prefix='/forum') @app.route('/healthz') def health_check(): with Session() as session: session.execute(sqlalchemy.text('SELECT 1')) return 'ok' @app.route('/api/slack/ai-channels', methods=['GET']) @token_required def get_slack_ai_channels(): with Session() as session: channels = session.query(SlackAIChannel).all() return SlackAIChannelSchema().dump(channels, many=True) @app.route('/api/slack/ai-channels/', methods=['DELETE']) @token_required def delete_slack_ai_channel(id): with Session() as session: session.query(SlackAIChannel).filter(SlackAIChannel.id == id).delete() session.commit() return {'ok': True} @app.route('/api/slack/ai-channels', methods=['POST']) @token_required def create_slack_ai_channel(): data = request.json schema = CreateSlackAIChannelSchema() try: channel = schema.load(data) except ma.ValidationError as e: return jsonify({'error': e.messages}), 400 with Session() as session: session.add(SlackAIChannel(**channel)) session.commit() return schema.dump(channel) @app.route('/qa/', methods=['GET']) def qa_feedback(qa_id): return render_template('index.html') @app.route('/api/qa/', methods=['GET']) def get_qa_detail(qa_id): user_id = request.args.get('u') signature = request.args.get('s') if not QaHistory(id=qa_id).verify_signature(user_id, signature): return {'error': 'Invalid signature'}, 403 with Session() as session: qa = session.query(QaHistory).filter(QaHistory.id == qa_id).first() if not qa: return {'error': 'Q&A record not found'}, 404 return qa.qa_context def get_trace_id_by_user_type(user_type: str, qa_history: QaHistory) -> str: if not qa_history: return '' if user_type == Platform.SLACK.value: return qa_history.slack_message_id elif user_type == Platform.DISCORD.value: return qa_history.discord_message_id else: return '' @app.route('/api/qa//feedback', methods=['POST']) def submit_qa_feedback(qa_id): user_id = request.args.get('u') signature = request.args.get('s') if not QaHistory(id=qa_id).verify_signature(user_id, signature): return {'error': 'Invalid signature'}, 403 comment = request.json.get('comment') with Session() as session: qa = session.query(QaHistory).filter(QaHistory.id == qa_id).first() user = session.query(User).filter(User.id == user_id).first() if not qa: return {'error': 'Q&A record not found'}, 404 feedback_body = { 'comment': comment } qa_feedback = QaFeedback( qa_history_id=qa_id, user_id=user_id, feedback_type=FeedbackType.DISLIKE.value, feedback_body=feedback_body, ) comment = f'From {user.user_type}, user {user.username} submit dislike feedback, detail: {comment}' qa_service.dislike( origin=user.user_type, chat_message_id=qa.ai_chat_message_id, username=user.username, comment=comment ) with Session() as session: session.add(qa_feedback) session.commit() return {'ok': True}