| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172 |
- """Explicit live smoke command. Saves outputs only under ignored output/.
- No credentials, company fields or full request bodies are printed to logs.
- """
- import argparse
- from dataclasses import replace
- import json
- from pathlib import Path
- from .graph import build_graph
- from .intent import deepseek_analyzer
- from .qcc import QccClient, load_config
- from .recommendation import JsonModel, Recommender
- from .retrieval import Retriever
- from .report import export
- from langgraph.types import Command
- def main():
- parser = argparse.ArgumentParser()
- parser.add_argument('--mode', choices=('personal', 'enterprise'), required=True)
- args = parser.parse_args()
- root = Path(__file__).resolve().parents[2]
- env = root / '.env'
- client = QccClient(replace(load_config(env), honor_max_pages=1))
- retriever = Retriever(env, root / 'knowledge/prepared/ingestion/manifest.json')
- retriever.warmup()
- graph = build_graph(client, deepseek_analyzer(env), retriever=retriever, recommender=Recommender(JsonModel(env)))
- # Public vendor fixture; never identifies this entity as the user's company.
- company_name = '企查查科技股份有限公司'
- question = ('我在青浦失业了,想参加职业技能培训,能得到什么帮助?' if args.mode == 'personal' else
- company_name + '想在青浦设立分公司,招聘研发人员,有哪些人才或研发支持?')
- config = {'configurable': {'thread_id': 'live-' + args.mode}, 'recursion_limit': 100}
- result = graph.invoke({'question': question}, config)
- clarified = False
- if result.get('__interrupt__') and args.mode == 'enterprise' and result['__interrupt__'][0].value['kind'] == 'company_need':
- clarified = True
- result = graph.invoke(Command(resume={'needs_company': True, 'company_hint': company_name}), config)
- if result.get('__interrupt__'):
- value = result['__interrupt__'][0].value
- if args.mode == 'enterprise' and value['kind'] == 'company_selection':
- selected = [r for r in value['result']['candidates'] if r['Name'] == company_name]
- if len(selected) != 1:
- result = graph.invoke(Command(resume={'action': 'refine', 'keyword': company_name}), config)
- value = result['__interrupt__'][0].value
- selected = [r for r in value['result']['candidates'] if r['Name'] == company_name]
- if len(selected) != 1:
- raise ValueError('fixture_not_unique')
- result = graph.invoke(Command(resume={'action': 'select', 'key_no': selected[0]['KeyNo']}), config)
- else:
- raise ValueError('unexpected_intent_interrupt')
- answer = result['recommendation']
- html, output_json = export(answer, root / 'output/consultations')
- print(json.dumps({'mode': args.mode, 'complete': answer['complete'],
- 'retrieval_analysis_complete': answer['retrieval_analysis_complete'],
- 'recommendations': len(answer['items']), 'sources': len(answer['sources']),
- 'analysis_errors': answer['analysis_errors'],
- 'failed_databases': answer['retrieval']['failed_databases'],
- 'content_failures': answer['retrieval']['content_failures'],
- 'qcc_profile_verified': result.get('profile') is not None,
- 'intent_clarified': clarified,
- 'html': str(html), 'json': str(output_json)}, ensure_ascii=False), flush=True)
- if __name__ == '__main__':
- try:
- main()
- except Exception as exc:
- safe_code = str(exc) if str(exc) in ('fixture_not_unique', 'unexpected_intent_interrupt') else 'live_smoke_failed'
- print(json.dumps({'error_type': type(exc).__name__, 'status': safe_code}), flush=True)
- raise SystemExit(1) from None
|