gitdataai/libs/transport/richtext.rs
ZhenYi 14f6e1e500 feat(core): initialize project with access control and AI integration
- Add gitignore and prettier configuration files for project scaffolding
- Implement room access control service with project member verification
- Create user access key management with CRUD operations and activity logging
- Add accordion UI component for frontend expandable sections
- Implement room AI configuration with list, upsert, and delete operations
- Add AI event types for agent join/leave/status change tracking
- Create streaming AI processing services for mode and react patterns
- Build room AI service with model detection and idempotency handling
- Integrate chat service orchestration for AI message processing
- Add typing indicators and stream cancellation for AI interactions
- Implement mention parsing and context extraction for AI agents
2026-05-03 06:04:31 +08:00

84 lines
2.4 KiB
Rust

use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RichTextBlock {
pub block_type: BlockType,
pub content: String,
pub attributes: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum BlockType {
Text,
Code,
Quote,
Link,
Mention,
Emoji,
Image,
}
pub struct RichTextRenderer {
}
impl RichTextRenderer {
pub fn new() -> Self {
Self {}
}
pub fn parse_markdown(&self, content: &str) -> Vec<RichTextBlock> {
let mut blocks = Vec::new();
blocks.push(RichTextBlock {
block_type: BlockType::Text,
content: content.to_string(),
attributes: None,
});
blocks
}
pub fn parse_mentions(&self, content: &str) -> Vec<Uuid> {
let mut mentions = Vec::new();
for word in content.split_whitespace() {
if word.starts_with('@') {
if let Ok(uuid) = Uuid::parse_str(&word[1..]) {
mentions.push(uuid);
}
}
}
mentions
}
pub fn highlight_code(&self, code: &str, language: &str) -> String {
format!("```{}\n{}\n```", language, code)
}
pub fn render_to_html(&self, blocks: &[RichTextBlock]) -> String {
blocks.iter()
.map(|block| match block.block_type {
BlockType::Text => format!("<p>{}</p>", html_escape(&block.content)),
BlockType::Code => format!("<pre><code>{}</code></pre>", html_escape(&block.content)),
BlockType::Quote => format!("<blockquote>{}</blockquote>", html_escape(&block.content)),
BlockType::Link => format!("<a href=\"{}\">{}</a>", html_escape(&block.content), html_escape(&block.content)),
BlockType::Mention => format!("<span class=\"mention\">@{}</span>", html_escape(&block.content)),
BlockType::Emoji => format!("<span class=\"emoji\">{}</span>", html_escape(&block.content)),
BlockType::Image => format!("<img src=\"{}\" />", html_escape(&block.content)),
})
.collect::<Vec<_>>()
.join("\n")
}
}
fn html_escape(s: &str) -> String {
s.replace('&', "&amp;")
.replace('<', "&lt;")
.replace('>', "&gt;")
.replace('"', "&quot;")
.replace('\'', "&#x27;")
}