Trae Assistant
Initial commit: LogicStream Agent
2d0e2ae
import os
import json
import sqlite3
import requests
import datetime
import uuid
from flask import Flask, render_template, request, jsonify, send_from_directory
from flask_cors import CORS
app = Flask(__name__, static_folder='static', template_folder='templates')
CORS(app)
# Configuration
SILICONFLOW_API_KEY = os.environ.get("SILICONFLOW_API_KEY", "sk-vimuseiptfbomzegyuvmebjzooncsqbyjtlddrfodzcdskgi")
SILICONFLOW_API_URL = "https://api.siliconflow.cn/v1/chat/completions"
DB_PATH = os.path.join(app.instance_path, "logic_stream.db")
# Ensure instance folder exists
os.makedirs(app.instance_path, exist_ok=True)
# Database Initialization
def init_db():
conn = sqlite3.connect(DB_PATH)
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS workflows
(id TEXT PRIMARY KEY, name TEXT, description TEXT, steps TEXT, created_at TEXT, updated_at TEXT)''')
c.execute('''CREATE TABLE IF NOT EXISTS runs
(id TEXT PRIMARY KEY, workflow_id TEXT, status TEXT, result TEXT, logs TEXT, created_at TEXT)''')
# Check if empty, add default data
c.execute("SELECT count(*) FROM workflows")
if c.fetchone()[0] == 0:
default_workflow = {
"id": str(uuid.uuid4()),
"name": "市场趋势分析 (Market Trend Analysis)",
"description": "自动分析市场新闻并生成简报 (Auto-analyze market news and generate brief)",
"steps": json.dumps([
{"id": "step_1", "type": "input", "name": "输入主题", "content": "AI Agent 2025年发展趋势"},
{"id": "step_2", "type": "llm", "name": "深度分析", "prompt": "请分析以下主题的市场趋势和商业机会:{{step_1.output}}。输出 JSON 格式。"},
{"id": "step_3", "type": "llm", "name": "生成简报", "prompt": "根据以下分析生成一份简洁的投资简报:{{step_2.output}}"}
]),
"created_at": datetime.datetime.now().isoformat(),
"updated_at": datetime.datetime.now().isoformat()
}
c.execute("INSERT INTO workflows VALUES (?, ?, ?, ?, ?, ?)",
(default_workflow["id"], default_workflow["name"], default_workflow["description"],
default_workflow["steps"], default_workflow["created_at"], default_workflow["updated_at"]))
conn.commit()
print("Default data initialized.")
conn.commit()
conn.close()
init_db()
def get_db_connection():
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
return conn
# Routes
@app.route('/')
def index():
return render_template('index.html')
@app.route('/api/workflows', methods=['GET'])
def get_workflows():
conn = get_db_connection()
workflows = conn.execute('SELECT * FROM workflows ORDER BY updated_at DESC').fetchall()
conn.close()
return jsonify([dict(w) for w in workflows])
@app.route('/api/workflows', methods=['POST'])
def create_workflow():
data = request.json
workflow_id = str(uuid.uuid4())
now = datetime.datetime.now().isoformat()
conn = get_db_connection()
conn.execute('INSERT INTO workflows (id, name, description, steps, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)',
(workflow_id, data['name'], data.get('description', ''), json.dumps(data['steps']), now, now))
conn.commit()
conn.close()
return jsonify({"id": workflow_id, "status": "created"})
@app.route('/api/workflows/<id>', methods=['PUT'])
def update_workflow(id):
data = request.json
now = datetime.datetime.now().isoformat()
conn = get_db_connection()
conn.execute('UPDATE workflows SET name = ?, description = ?, steps = ?, updated_at = ? WHERE id = ?',
(data['name'], data.get('description', ''), json.dumps(data['steps']), now, id))
conn.commit()
conn.close()
return jsonify({"status": "updated"})
@app.route('/api/workflows/<id>', methods=['DELETE'])
def delete_workflow(id):
conn = get_db_connection()
conn.execute('DELETE FROM workflows WHERE id = ?', (id,))
conn.commit()
conn.close()
return jsonify({"status": "deleted"})
@app.route('/api/run_workflow', methods=['POST'])
def run_workflow():
data = request.json
workflow_id = data.get('workflow_id')
steps = data.get('steps', [])
# If workflow_id is provided, fetch steps from DB (optional, but here we assume frontend sends current steps)
run_id = str(uuid.uuid4())
logs = []
context = {}
try:
for step in steps:
step_id = step['id']
step_type = step['type']
step_name = step['name']
logs.append({"timestamp": datetime.datetime.now().isoformat(), "level": "INFO", "message": f"Starting step: {step_name} ({step_type})"})
output = ""
if step_type == 'input':
output = step.get('content', '')
logs.append({"timestamp": datetime.datetime.now().isoformat(), "level": "SUCCESS", "message": f"Input received: {output[:50]}..."})
elif step_type == 'llm':
prompt_template = step.get('prompt', '')
# Simple variable substitution {{step_id.output}}
prompt = prompt_template
for prev_step_id, prev_output in context.items():
prompt = prompt.replace(f"{{{{{prev_step_id}.output}}}}", str(prev_output))
logs.append({"timestamp": datetime.datetime.now().isoformat(), "level": "INFO", "message": f"Calling LLM with prompt: {prompt[:50]}..."})
# Call SiliconFlow API
try:
headers = {
"Authorization": f"Bearer {SILICONFLOW_API_KEY}",
"Content-Type": "application/json"
}
payload = {
"model": "Qwen/Qwen2.5-7B-Instruct", # Reliable model
"messages": [
{"role": "system", "content": "You are a helpful business logic assistant. Output clean, structured responses."},
{"role": "user", "content": prompt}
],
"stream": False,
"temperature": 0.7
}
response = requests.post(SILICONFLOW_API_URL, headers=headers, json=payload, timeout=30)
response.raise_for_status()
result = response.json()
output = result['choices'][0]['message']['content']
logs.append({"timestamp": datetime.datetime.now().isoformat(), "level": "SUCCESS", "message": "LLM response received."})
except Exception as e:
logs.append({"timestamp": datetime.datetime.now().isoformat(), "level": "ERROR", "message": f"LLM Error: {str(e)}"})
# Mock fallback for reliability
output = f"[Mock Output] Failed to call API. Mock result for prompt: {prompt[:20]}..."
# Store output in context
context[step_id] = output
# Also update the step object to return to frontend
step['output'] = output
final_status = "success"
except Exception as e:
final_status = "error"
logs.append({"timestamp": datetime.datetime.now().isoformat(), "level": "CRITICAL", "message": f"Workflow failed: {str(e)}"})
# Save run
conn = get_db_connection()
conn.execute('INSERT INTO runs (id, workflow_id, status, result, logs, created_at) VALUES (?, ?, ?, ?, ?, ?)',
(run_id, workflow_id, final_status, json.dumps(context), json.dumps(logs), datetime.datetime.now().isoformat()))
conn.commit()
conn.close()
return jsonify({
"run_id": run_id,
"status": final_status,
"logs": logs,
"results": context
})
@app.route('/api/chat', methods=['POST'])
def chat():
# Direct chat endpoint for "Assistant" feature
data = request.json
message = data.get('message', '')
try:
headers = {
"Authorization": f"Bearer {SILICONFLOW_API_KEY}",
"Content-Type": "application/json"
}
payload = {
"model": "Qwen/Qwen2.5-7B-Instruct",
"messages": [
{"role": "system", "content": "You are LogicStream AI, an intelligent assistant for building business workflows."},
{"role": "user", "content": message}
],
"stream": False
}
response = requests.post(SILICONFLOW_API_URL, headers=headers, json=payload, timeout=30)
return jsonify(response.json())
except Exception as e:
return jsonify({"error": str(e)}), 500
if __name__ == '__main__':
app.run(host='0.0.0.0', port=7860, debug=True)