Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/brkddd_lawagent2.json
T

1 line
15 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "brkddd/lawagent2", "files": {"main.py": {"5ed78d8305568e99a4cdcfb97397749b4e42fa33": {"t": 1785674063.362636, "n": 2725, "h": "b2e2352bb1661261", "c": "\"\"\"\r\nSpoonOS 法律公正助手 - 主程序\r\n支持法律检索、回答与区块链存证。\r\n\"\"\"\r\nimport asyncio\r\nimport os\r\nfrom flask import Flask, request, jsonify\r\nfrom flask_cors import CORS\r\n\r\nfrom dotenv import load_dotenv\r\n\r\n# 1. 最先加载 .env,确保后续代码能读取环境变量\r\nload_dotenv()\r\napp = Flask(__name__)\r\nCORS(app) # 解决跨域问题\r\n\r\n# 2. 显式获取配置(必须在创建 LLM 之前)\r\napi_key = os.getenv(\"OPENAI_API_KEY\")\r\napi_base = os.getenv(\"OPENAI_BASE_URL\", \"https://api.deepseek.com\")\r\nmodel_name = os.getenv(\"MODEL_NAME\", \"deepseek-chat\")\r\n\r\nif not api_key:\r\n raise ValueError(\r\n \"请在 .env 中配置 OPENAI_API_KEY。当前未读取到有效的 API Key。\"\r\n )\r\n\r\n# 3. 显式初始化 DeepSeek LLM,使用 OpenAILike 避免模型名校验\r\nfrom llama_index.llms.openai_like import OpenAILike\r\n\r\nllm = OpenAILike(\r\n api_key=api_key,\r\n api_base=api_base,\r\n model=model_name,\r\n is_chat_model=True,\r\n)\r\n\r\n# 4. 配置全局 Settings\r\nfrom llama_index.core import Settings\r\nfrom llama_index.embeddings.huggingface import HuggingFaceEmbedding\r\n\r\nSettings.llm = llm\r\nSettings.embed_model = HuggingFaceEmbedding(model_name=\"BAAI/bge-small-zh-v1.5\")\r\n\r\n# 5. 引入技能(需在 Settings 配置之后)\r\nfrom llama_index.core.agent.workflow import ReActAgent\r\nfrom llama_index.core.agent.workflow import AgentStream\r\nfrom llama_index.core.memory import ChatMemoryBuffer\r\nfrom llama_index.core.workflow import Context\r\n\r\nfrom skills.legal_skill import search_laws\r\nfrom skills.notary_skill import notarize_on_chain\r\n\r\n# 6. 系统提示词:SpoonOS 法律公正助手\r\nSYSTEM_PROMPT = \"\"\"你是 SpoonOS 法律公正助手。\r\n\r\n工作流程要求:\r\n1. 先使用 search_laws 工具检索相关法律条文,再基于检索结果回答用户问题。\r\n2. 回答用户的法律相关问题。\r\n3. 如果用户明确要求对某段内容进行存证,则调用 notarize_on_chain 工具完成区块链存证。\r\n\"\"\"\r\n\r\n# 7. 构建 ReActAgent,显式传入 llm\r\nagent = ReActAgent(\r\n tools=[search_laws, notarize_on_chain],\r\n llm=llm,\r\n system_prompt=SYSTEM_PROMPT,\r\n verbose=True,\r\n)\r\n\r\n# 8. 创建上下文与记忆\r\nctx = Context(agent)\r\nmemory = ChatMemoryBuffer.from_defaults(llm=llm)\r\n\r\n\r\n# --- 3. API 路由 ---\r\n# --- 修改后的 API 路由 ---\r\n@app.route('/api/chat', methods=['POST'])\r\nasync def chat():\r\n user_input = request.json.get('message')\r\n if not user_input:\r\n return jsonify({\"error\": \"No message\"}), 400\r\n\r\n try:\r\n # 使用 agent.run 获取执行句柄\r\n handler = agent.run(user_input, memory=memory, ctx=ctx)\r\n \r\n # 这种方式会自动处理 ReAct 的思考过程,最终结果会直接包含在响应对象中\r\n response = await handler \r\n \r\n # response 对象通常包含最终的 content,过滤掉中间的推理步骤\r\n return jsonify({\"response\": str(response)})\r\n except Exception as e:\r\n return jsonify({\"error\": str(e)}), 500\r\n# 原有的上传逻辑可保留在这里...\r\n@app.route('/api/upload-evidence', methods=['POST'])\r\ndef upload_evidence():\r\n # ... 你之前的 Flask 存证逻辑 ...\r\n return jsonify({\"success\": True, \"tx_hash\": \"0x...\", \"evidence_hash\": \"...\"})\r\n\r\nif __name__ == \"__main__\":\r\n app.run(port=5000, debug=True)"}, "7df29157692e4f7f5bc1e09e626e53b87128d311": {"t": 1785766531.9956021, "n": 2725, "h": "b2e2352bb1661261", "c": "\"\"\"\r\nSpoonOS 法律公正助手 - 主程序\r\n支持法律检索、回答与区块链存证。\r\n\"\"\"\r\nimport asyncio\r\nimport os\r\nfrom flask import Flask, request, jsonify\r\nfrom flask_cors import CORS\r\n\r\nfrom dotenv import load_dotenv\r\n\r\n# 1. 最先加载 .env,确保后续代码能读取环境变量\r\nload_dotenv()\r\napp = Flask(__name__)\r\nCORS(app) # 解决跨域问题\r\n\r\n# 2. 显式获取配置(必须在创建 LLM 之前)\r\napi_key = os.getenv(\"OPENAI_API_KEY\")\r\napi_base = os.getenv(\"OPENAI_BASE_URL\", \"https://api.deepseek.com\")\r\nmodel_name = os.getenv(\"MODEL_NAME\", \"deepseek-chat\")\r\n\r\nif not api_key:\r\n raise ValueError(\r\n \"请在 .env 中配置 OPENAI_API_KEY。当前未读取到有效的 API Key。\"\r\n )\r\n\r\n# 3. 显式初始化 DeepSeek LLM,使用 OpenAILike 避免模型名校验\r\nfrom llama_index.llms.openai_like import OpenAILike\r\n\r\nllm = OpenAILike(\r\n api_key=api_key,\r\n api_base=api_base,\r\n model=model_name,\r\n is_chat_model=True,\r\n)\r\n\r\n# 4. 配置全局 Settings\r\nfrom llama_index.core import Settings\r\nfrom llama_index.embeddings.huggingface import HuggingFaceEmbedding\r\n\r\nSettings.llm = llm\r\nSettings.embed_model = HuggingFaceEmbedding(model_name=\"BAAI/bge-small-zh-v1.5\")\r\n\r\n# 5. 引入技能(需在 Settings 配置之后)\r\nfrom llama_index.core.agent.workflow import ReActAgent\r\nfrom llama_index.core.agent.workflow import AgentStream\r\nfrom llama_index.core.memory import ChatMemoryBuffer\r\nfrom llama_index.core.workflow import Context\r\n\r\nfrom skills.legal_skill import search_laws\r\nfrom skills.notary_skill import notarize_on_chain\r\n\r\n# 6. 系统提示词:SpoonOS 法律公正助手\r\nSYSTEM_PROMPT = \"\"\"你是 SpoonOS 法律公正助手。\r\n\r\n工作流程要求:\r\n1. 先使用 search_laws 工具检索相关法律条文,再基于检索结果回答用户问题。\r\n2. 回答用户的法律相关问题。\r\n3. 如果用户明确要求对某段内容进行存证,则调用 notarize_on_chain 工具完成区块链存证。\r\n\"\"\"\r\n\r\n# 7. 构建 ReActAgent,显式传入 llm\r\nagent = ReActAgent(\r\n tools=[search_laws, notarize_on_chain],\r\n llm=llm,\r\n system_prompt=SYSTEM_PROMPT,\r\n verbose=True,\r\n)\r\n\r\n# 8. 创建上下文与记忆\r\nctx = Context(agent)\r\nmemory = ChatMemoryBuffer.from_defaults(llm=llm)\r\n\r\n\r\n# --- 3. API 路由 ---\r\n# --- 修改后的 API 路由 ---\r\n@app.route('/api/chat', methods=['POST'])\r\nasync def chat():\r\n user_input = request.json.get('message')\r\n if not user_input:\r\n return jsonify({\"error\": \"No message\"}), 400\r\n\r\n try:\r\n # 使用 agent.run 获取执行句柄\r\n handler = agent.run(user_input, memory=memory, ctx=ctx)\r\n \r\n # 这种方式会自动处理 ReAct 的思考过程,最终结果会直接包含在响应对象中\r\n response = await handler \r\n \r\n # response 对象通常包含最终的 content,过滤掉中间的推理步骤\r\n return jsonify({\"response\": str(response)})\r\n except Exception as e:\r\n return jsonify({\"error\": str(e)}), 500\r\n# 原有的上传逻辑可保留在这里...\r\n@app.route('/api/upload-evidence', methods=['POST'])\r\ndef upload_evidence():\r\n # ... 你之前的 Flask 存证逻辑 ...\r\n return jsonify({\"success\": True, \"tx_hash\": \"0x...\", \"evidence_hash\": \"...\"})\r\n\r\nif __name__ == \"__main__\":\r\n app.run(port=5000, debug=True)"}}, "app.py": {"5ed78d8305568e99a4cdcfb97397749b4e42fa33": {"t": 1785674064.3075614, "n": 6709, "h": "92a5ecad9374af53", "c": "\"\"\"\r\nSpoonOS 法律公正助手 + 区块链证据存证 后端\r\n\"\"\"\r\nimport os\r\nimport json\r\nimport asyncio\r\nfrom flask import Flask, request, jsonify\r\nfrom flask_cors import CORS\r\nfrom dotenv import load_dotenv\r\n\r\n# ================== 1. 环境变量 & Flask ==================\r\nload_dotenv()\r\n\r\napp = Flask(__name__)\r\nCORS(app)\r\n\r\n# ================== 2. 区块链证据上传工具(spoon_ai) ==================\r\nupload_tool = None\r\n\r\ndef init_upload_agent():\r\n global upload_tool\r\n try:\r\n from examples.user_evidence_upload_agent import UserEvidenceUploadTool\r\n upload_tool = UserEvidenceUploadTool()\r\n print(\"✅ 证据上传工具初始化成功\")\r\n return True\r\n except Exception as e:\r\n print(f\"❌ 证据上传工具初始化失败: {e}\")\r\n return False\r\n\r\n\r\n@app.route('/api/upload-evidence', methods=['POST'])\r\ndef upload_evidence():\r\n \"\"\"上传证据并上链\"\"\"\r\n try:\r\n if upload_tool is None:\r\n return jsonify({'error': '证据上传工具未初始化'}), 500\r\n\r\n # 获取上传的文件\r\n if 'evidence_file' not in request.files:\r\n return jsonify({'error': '没有提供文件'}), 400\r\n\r\n file = request.files['evidence_file']\r\n if file.filename == '':\r\n return jsonify({'error': '没有选择文件'}), 400\r\n\r\n # 获取表单数据\r\n evidence_type = request.form.get('evidence_type', 'document')\r\n # 前端历史值兼容:text -> document\r\n if evidence_type == 'text':\r\n evidence_type = 'document'\r\n evidence_source = request.form.get('evidence_source', 'user_upload')\r\n user_address = request.form.get('user_address', '')\r\n description = request.form.get('description', '')\r\n\r\n # 读取文件内容\r\n file_content = file.read()\r\n if isinstance(file_content, bytes):\r\n try:\r\n file_content = file_content.decode('utf-8')\r\n except UnicodeDecodeError:\r\n # 如果不是文本文件,转换为 base64\r\n import base64\r\n file_content = base64.b64encode(file_content).decode('utf-8')\r\n evidence_type = 'binary'\r\n\r\n # 运行工具(异步)\r\n loop = asyncio.new_event_loop()\r\n asyncio.set_event_loop(loop)\r\n\r\n try:\r\n # sign_with 参数目前仅用于接口兼容;真实上链使用 .env 的 PRIVATE_KEY\r\n sign_with = user_address or \"local\"\r\n result = loop.run_until_complete(\r\n upload_tool.execute(\r\n evidence_content=file_content,\r\n evidence_type=evidence_type,\r\n source=evidence_source,\r\n sign_with=sign_with,\r\n description=description,\r\n uploader_address=user_address,\r\n file_name=file.filename,\r\n metadata={\r\n \"content_encoding\": \"utf-8\" if evidence_type != \"binary\" else \"base64\",\r\n },\r\n )\r\n )\r\n finally:\r\n loop.close()\r\n\r\n # 解析结果\r\n if isinstance(result, str):\r\n # 尝试解析 JSON 结果\r\n try:\r\n parsed_result = json.loads(result)\r\n # 兼容前端:统一输出 success/tx_hash/evidence_hash 等字段\r\n status = parsed_result.get(\"status\")\r\n success = status == \"success\"\r\n\r\n onchain = parsed_result.get(\"onchain\")\r\n onchain_dict = onchain if isinstance(onchain, dict) else {}\r\n\r\n response_body = {\r\n \"success\": bool(success),\r\n \"status\": status,\r\n \"message\": parsed_result.get(\"message\") or (\"OK\" if success else \"FAILED\"),\r\n \"error\": parsed_result.get(\"error\"),\r\n # 扁平化常用字段,便于前端展示\r\n \"tx_hash\": onchain_dict.get(\"tx_hash\"),\r\n \"evidence_hash\": onchain_dict.get(\"evidence_hash\"),\r\n \"signature\": onchain_dict.get(\"signature\"),\r\n \"timestamp\": onchain_dict.get(\"timestamp\"),\r\n \"explorer_url\": onchain_dict.get(\"explorer\"),\r\n # 保留完整细节\r\n \"result\": parsed_result,\r\n \"onchain\": onchain,\r\n }\r\n return jsonify(response_body)\r\n except json.JSONDecodeError:\r\n return jsonify({\r\n 'success': False,\r\n 'error': 'invalid_json',\r\n 'message': result,\r\n 'raw_response': result,\r\n })\r\n else:\r\n return jsonify({\r\n 'success': False,\r\n 'error': 'invalid_result_type',\r\n 'result': str(result)\r\n })\r\n\r\n except Exception as e:\r\n print(f\"上传失败: {e}\")\r\n return jsonify({'error': str(e)}), 500\r\n\r\n\r\n@app.route('/api/health', methods=['GET'])\r\ndef health():\r\n return jsonify({\r\n \"status\": \"ok\",\r\n \"upload_tool_ready\": upload_tool is not None\r\n })\r\n\r\n\r\n# ================== 3. LLM / Agent(法律助手) ==================\r\nfrom llama_index.llms.openai_like import OpenAILike\r\nfrom llama_index.core import Settings\r\nfrom llama_index.embeddings.huggingface import HuggingFaceEmbedding\r\nfrom llama_index.core.agent.workflow import ReActAgent\r\nfrom llama_index.core.memory import ChatMemoryBuffer\r\nfrom llama_index.core.workflow import Context\r\n\r\nfrom skills.legal_skill import search_laws\r\nfrom skills.notary_skill import notarize_on_chain\r\n\r\napi_key = os.getenv(\"OPENAI_API_KEY\")\r\napi_base = os.getenv(\"OPENAI_BASE_URL\", \"https://api.deepseek.com\")\r\nmodel_name = os.getenv(\"MODEL_NAME\", \"deepseek-chat\")\r\n\r\nllm = OpenAILike(\r\n api_key=api_key,\r\n api_base=api_base,\r\n model=model_name,\r\n is_chat_model=True,\r\n)\r\n\r\nSettings.llm = llm\r\nSettings.embed_model = HuggingFaceEmbedding(model_name=\"BAAI/bge-small-zh-v1.5\")\r\n\r\nSYSTEM_PROMPT = \"\"\"\r\n你是 SpoonOS 法律公正助手。\r\n\r\n流程:\r\n1. 使用 search_laws 检索法律条文\r\n2. 基于结果回答\r\n3. 若用户要求存证,调用 notarize_on_chain\r\n\"\"\"\r\n\r\nagent = ReActAgent(\r\n tools=[search_laws, notarize_on_chain],\r\n llm=llm,\r\n system_prompt=SYSTEM_PROMPT,\r\n verbose=True,\r\n)\r\n\r\nctx = Context(agent)\r\nmemory = ChatMemoryBuffer.from_defaults(llm=llm)\r\n\r\n\r\n@app.route('/api/chat', methods=['POST'])\r\nasync def chat():\r\n user_input = request.json.get(\"message\")\r\n if not user_input:\r\n return jsonify({\"error\": \"message 不能为空\"}), 400\r\n\r\n try:\r\n handler = agent.run(user_input, memory=memory, ctx=ctx)\r\n response = await handler\r\n return jsonify({\"response\": str(response)})\r\n except Exception as e:\r\n return jsonify({\"error\": str(e)}), 500\r\n\r\n\r\n# ================== 4. 启动入口 ==================\r\nif __name__ == \"__main__\":\r\n init_upload_agent()\r\n print(\"🚀 SpoonOS 法律公正助手后端启动中...\")\r\n app.run(host=\"0.0.0.0\", port=5000, debug=True)\r\n"}}}}