Commit Graph

11 Commits

Author SHA1 Message Date
liyizhouAI b7df4880c8 fix: v0.3.4 - production stability fixes for simulation pipeline
- LLM JSON truncation: add _repair_truncated_json() to handle max_tokens cutoff
- Ontology generation: increase max_tokens 4096→8192 to prevent truncation
- Config generation: parallel batch processing (3 threads × 30 agents/batch) for ~3x speedup
- Rate limit: reduce semaphore 30→8 to avoid GLM API 429 storms
- HuggingFace offline: set HF_HUB_OFFLINE=1 to skip unreachable hf-mirror.com
- Simulation recovery: auto-reset stuck "preparing" states on Flask restart
- Prepare endpoint: handle concurrent prepare requests gracefully
- Frontend: handle page-refresh-during-prepare edge case
- API: return 429 instead of 500 for LLM rate limit errors
2026-04-16 22:44:40 +08:00
liyizhouAI 7443082846 feat: v0.3.2 - CustomGraphBuilder replaces Graphiti for step 2 graph build
End of a long debugging rabbit hole. After ~10 attempts patching Graphiti's
compatibility with non-OpenAI LLMs (GLM, Qwen via SiliconFlow), every fix
uncovered another bug. Made the strategic call to abandon Graphiti entirely
for the graph-build path and write a minimal custom builder.

## Why Graphiti had to go

- Qwen 32B 32K context overflow on cumulative episode retrieval (60K-82K tokens)
- SiliconFlow Qwen 72B also 32K (not 128K as docs implied)
- GLM 4 Flash gives 128K context but triggers "20015 parameter invalid" on
  Graphiti's structured output calls (logprobs in reranker, empty input in
  embedder, nested dict in Neo4j writes)
- Each patch target was 1-2 levels deep in Graphiti internals
- 4 separate monkey-patches (EntityNode.save, bulk_utils, driver layer,
  reranker, embedder) still couldn't cover the extract_nodes path

## New architecture

backend/app/services/custom_graph_builder.py (NEW, 348 lines):
- Uses Foresight's own LLMClient (retry + GLM→Qwen fallback + token tracker)
- 1 LLM call per chunk (Graphiti needed 4-5)
- Single prompt extracts entities + relationships as JSON
- Writes directly to Neo4j via cypher MERGE (no Graphiti dependency)
- Schema identical to what Graphiti produced — downstream get_all_nodes /
  get_all_edges / zep_entity_reader all work unchanged
- ThreadPoolExecutor (10 workers) for concurrent chunk extraction
- Sequential Neo4j writes via shared session (avoids name conflicts in dedup)
- DDL wrapped in try/except (tolerates pre-existing Graphiti indexes)
- Entity name dedup via in-memory map → single uuid per canonical name
- Regex-sanitized label / relation type to prevent cypher injection

backend/app/api/graph.py:
- /api/graph/build endpoint now calls CustomGraphBuilder instead of
  builder.add_text_batches() → client.add_episodes_batch() (the old Graphiti path)

backend/app/services/graph_builder.py:
- _build_graph_worker also updated to use CustomGraphBuilder (dead code path
  but kept in sync)

backend/app/models/project.py:
- Default chunk_size 500 → 250 (to keep individual LLM prompts small)

backend/app/services/graphiti_client.py:
- Kept all monkey-patches for backward compat — they now only affect legacy
  Graphiti code paths that CustomGraphBuilder bypasses entirely:
  * _patch_neo4j_driver (AsyncSession.run nested-dict sanitize)
  * _patch_reranker_for_non_openai (GLM logprobs workaround)
  * _patch_embedder_empty_input (SiliconFlow empty-input guard)
  * _patch_entity_node_ops (EntityNode.save sanitize)
  * _patch_add_nodes_and_edges_bulk_tx (bulk-episode sanitize)
- These are kept for safety; Graphiti code path is no longer invoked in the
  production build flow but methods like add_episode still exist on the class

## Performance

- Sequential: ~194 chunks × 2-5s = 10-15 min
- Concurrent (10 workers): ~194 / 10 × 3-5s = **1-2 min** (5-8x speedup)
- Rate limiting handled by LLMClient retry/backoff, not raw thread contention

## Downstream compatibility

Verified:
- get_all_nodes: MATCH (n:Entity) WHERE n.group_id = $gid RETURN n, labels(n)
- get_all_edges: MATCH (a)-[r]->(b) WHERE r.group_id = $gid RETURN r, type(r)
- get_node / get_node_edges: MATCH by uuid

CustomGraphBuilder writes:
- (n:Entity [optional second label]) with uuid, name, summary, group_id, created_at
- [r:RELATION_TYPE] with uuid, name, fact, group_id, created_at

Schema matches exactly.

## Pipeline wiring

Step 1 ontology generation → Step 2 graph build (CustomGraphBuilder) →
Step 3 profile generation (ZepEntityReader queries Neo4j) → Step 4 simulation

No changes needed downstream of Step 2.
2026-04-16 07:54:07 +08:00
liyizhouAI 1fef01d979 feat: v0.3 - Manus replay + token tracking + SIGTERM fix + accelerate button
This is the v0.3 milestone commit before the v0.4 big version push.
Major themes: process replay, runtime stability, cost observability.

## New Features

- **Manus-style process replay** (frontend + backend)
  - `GET /api/simulation/<id>/replay` returns full workflow + agents + rounds + aggregate
  - `frontend/src/views/SimulationReplayView.vue` 3-column layout (workflow / actions / stats)
  - bottom scrubber with play/pause/step + 5 speed levels (0.5x-10x)
  - filters out stale actions from previous runs via latest simulation_start timestamp

- **Token usage tracking** (`backend/app/utils/token_tracker.py`)
  - process-wide stage→model→tokens counter
  - LLMClient auto-records prompt/completion tokens after each call
  - stages tagged at API entry: step1_ontology, step2_graph_build, step3_prepare, step5_report
  - `GET /api/usage/summary` for live stats + CNY cost estimate
  - `GET /api/usage/estimate-simulation` for OASIS subprocess estimation
  - pricing table for GLM/SiliconFlow/MiniMax/OpenAI/Anthropic models
  - documented as internal-use, removed from customer-facing builds

- **Step 2 "Skip & Continue" button**
  - lets user stop profile generation early and proceed with what's already generated
  - `simulation_manager.request_accelerate()` + cancel_check in oasis_profile_generator
  - new endpoint `POST /api/simulation/prepare/accelerate`

## Critical Bug Fix

- **SIGTERM no longer kills running simulation subprocess**
  - root cause: `SimulationRunner.register_cleanup()` registered SIGTERM/SIGINT/SIGHUP handlers
    that called `os.killpg` on every tracked sim child, even though spawn already used
    `start_new_session=True` to give children isolated sessions
  - fix: neutered `register_cleanup` to a no-op; `cleanup_all_simulations` itself preserved
    for explicit stop_simulation paths
  - validated: killed Flask backend twice, simulation subprocess kept running
  - impact: hot-reload backend code without interrupting in-flight simulations

## Performance & Tuning

- semaphore 30 → 100 (twitter + reddit) for higher LLM concurrency
- discovered 200 agents as memory/cost/statistical sweet spot for 8G server
  (503 agents OOMs both platforms; 200 agents fits cleanly with 95% confidence margin)

## Documentation

- **PRD.md** rewritten as v0.3 baseline (10 chapters + 2 appendices, 639 lines)
  - product positioning across 3 usage modes (one-shot / model-reuse / SaaS)
  - v0.4 roadmap: domestic platforms (douyin/wechat/xiaohongshu/weibo), fork sim, multi-tenant
  - operational lessons: HF mirror, Tencent PyPI mirror, GLM-4-Flash choice, agent count
  - decision log with dates
  - per-stage token/cost breakdown for typical 200-agent run
- **README.md / README-ZH.md** updated with replay step + Graphiti+Neo4j

## Files Touched

19 files changed, 1105 insertions(+), 246 deletions(-)
2026-04-15 09:37:22 +08:00
liyizhouAI d5a908077a perf: upgrade Graphiti LLM to Qwen 32B + improve progress feedback
- Upgrade from Qwen2.5-7B to Qwen2.5-32B-Instruct (faster, better quality)
- Add real-time progress messages: "正在处理第 X/Y 个文本块"
- Log per-episode processing time
- Expand progress range from 15-55% to 15-90% (no more episode polling step)
- Add GRAPHITI_LLM_* separate config for graph building LLM

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-04-13 15:31:16 +08:00
liyizhouAI a35ba347f3 fix: use SiliconFlow free LLM+embedding for Graphiti
- Graphiti LLM: SiliconFlow Qwen/Qwen2.5-7B-Instruct (free, supports structured output)
- Graphiti Embedding: SiliconFlow BAAI/bge-m3 (free, OpenAI-compatible)
- MiniMax Coding Plan doesn't support structured output needed by Graphiti
- Separate GRAPHITI_LLM_* config from main LLM_* config
- Remove _wait_for_episodes call (Graphiti processes synchronously)

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-04-13 14:09:26 +08:00
liyizhouAI ded715feb2 feat: merge upstream i18n + rebrand MiroFish → Foresight 先见之明
- Merge 41 upstream commits (i18n for 7 languages, security fixes, new features)
- Rebrand all MiroFish references to Foresight/先见之明 across 37 files
- Re-apply dark theme CSS overhaul (pure black/gray, no blue tints)
- Re-apply Teleport-based theme toggle (inline with brand, 20px gap)
- Restore Foresight logo and favicon
- Update GitHub links to liyizhouAI/foresight
- Update locale files, README, package.json

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-04-11 16:40:13 +08:00
ghostubborn 7c07237544 fix(i18n): pass locale to background threads via thread-local storage
Background threads (graph building, simulation prep, report generation,
profile generation) now inherit the requesting user's locale preference.
Previously these fell back to 'zh' because Flask request context was
unavailable in spawned threads.
2026-04-01 16:55:51 +08:00
ghostubborn 9d43b77511 feat(i18n): replace hardcoded Chinese in backend SSE progress messages 2026-04-01 16:32:10 +08:00
ghostubborn 74f673a238 feat(i18n): replace hardcoded Chinese in backend API responses with t() calls 2026-04-01 15:32:24 +08:00
666ghj c60e6e1089 Refactor project creation process in API documentation and code
- Updated README.md to reflect the removal of the project creation endpoint, adjusting the workflow steps accordingly.
- Removed the `create_project` function from graph.py, streamlining the project management API by eliminating deprecated functionality.
2025-11-29 00:47:54 +08:00
666ghj 08f417f3b7 Introduce Project ID for context management, finalizing the stateful API pipeline from file submission to graph construction. 2025-11-28 17:21:08 +08:00