HarmonyOS NEXT AI 智能生活助手:AI 待办事项生成

HarmonyOS NEXT AI 智能生活助手:AI 待办事项生成

前言

第14篇中,我们实现了 AI 代码解释。本文将实现AI 待办事项生成------用户用自然语言描述任务,AI 自动提取待办事项、设置优先级、归类。

AI 待办生成 是效率工具的核心能力。只需一句话如"明天上午开会,下午写报告,晚上去健身",AI 就能自动拆解为结构化的待办列表。

本文将实现:

  1. 自然语言转待办:一句话生成结构化待办
  2. 四档优先级:紧急/重要/普通/低优
  3. 自动分类:工作/生活/学习分类
  4. 排序与过滤:按优先级和分类展示

图1:AI 待办事项生成页面布局

一、功能设计

1.1 页面布局

复制代码
┌─────────────────────────┐
│ ← 返回    AI 待办       │
├─────────────────────────┤
│                         │
│  ┌─────────────────────┐│
│  │ 输入描述任务...       ││  ← 自然语言输入
│  │ "明天上午开会         ││
│  │  下午写报告..."       ││
│  └─────────────────────┘│
│                         │
│  ⟳ 生成待办              │
│                         │
│  ┌─────────────────────┐│
│  │ [文档] 待办列表 (5项)  ││
│  │                     ││
│  │ [红点] 紧急              ││
│  │   □ 明天上午9点开会   ││  ← 按优先级分组
│  │                     ││
│  │ [黄点] 重要              ││
│  │   □ 下午完成报告     ││
│  │                     ││
│  │ [绿点] 普通              ││
│  │   □ 晚上健身         ││
│  └─────────────────────┘│
└─────────────────────────┘

1.2 技术架构

typescript 复制代码
// 待办事项模块架构
/*
  ┌─────────────────────────────────────────┐
  │            TodoPage.ets                 │
  │      (UI 展示 / 输入 / 状态切换)          │
  └─────────────────┬───────────────────────┘
                    │
  ┌─────────────────▼───────────────────────┐
  │          TodoManager.ts                 │
  │   (待办生成 / 排序 / 分类 / 统计)         │
  └─────────────────┬───────────────────────┘
                    │
        ┌───────────┼───────────┐
        ▼           ▼           ▼
  ┌─────────┐ ┌─────────┐ ┌─────────┐
  │AIService│ │CacheMgr │ │relational│
  │(多Provider│ │(缓存)   │ │Store     │
  │ 切换)   │ │         │ │(待办数据) │
  └─────────┘ └─────────┘ └─────────┘
*/

二、数据模型

2.1 待办事项数据结构

typescript 复制代码
// model/TodoItem.ts
export interface TodoItem {
  id: string;
  title: string;                    // 标题
  description?: string;             // 描述
  priority: Priority;               // 优先级
  category: TodoCategory;           // 分类
  deadline?: string;                 // 截止日期
  estimatedMinutes?: number;        // 预估时长
  isCompleted: boolean;              // 是否完成
  createdTime: number;               // 创建时间
  tags: string[];                    // 标签
}

export type Priority = 'urgent' | 'important' | 'normal' | 'low';
export type TodoCategory = 'work' | 'life' | 'study' | 'health' | 'other';

// 优先级配置
export const PRIORITY_CONFIG: Record<Priority, { label: string; icon: string; color: string; score: number }> = {
  urgent: { label: '紧急', icon: 'ic_priority_urgent', color: '#E17055', score: 0 },
  important: { label: '重要', icon: 'ic_priority_important', color: '#FDCB6E', score: 1 },
  normal: { label: '普通', icon: 'ic_priority_normal', color: '#00B894', score: 2 },
  low: { label: '低优', icon: 'ic_priority_low', color: '#B2BEC3', score: 3 }
};

// 分类配置
export const CATEGORY_CONFIG: Record<TodoCategory, { label: string; icon: string; color: string }> = {
  work: { label: '工作', icon: 'ic_category_work', color: '#6C5CE7' },
  life: { label: '生活', icon: 'ic_category_life', color: '#00B894' },
  study: { label: '学习', icon: 'ic_category_study', color: '#0984E3' },
  health: { label: '健康', icon: 'ic_category_health', color: '#E17055' },
  other: { label: '其他', icon: 'ic_category_other', color: '#B2BEC3' }
};

2.2 待办事项数据库表

typescript 复制代码
// model/TodoRecord.ts
export interface TodoRecord {
  id: string;
  title: string;
  description?: string;
  priority: string;
  category: string;
  deadline?: string;
  estimatedMinutes?: number;
  isCompleted: boolean;
  createdTime: number;
  tags: string;
}

export const TODO_TABLE = {
  tableName: 'todos',
  columns: [
    { name: 'id', type: 'TEXT PRIMARY KEY' },
    { name: 'title', type: 'TEXT NOT NULL' },
    { name: 'description', type: 'TEXT' },
    { name: 'priority', type: 'TEXT' },
    { name: 'category', type: 'TEXT' },
    { name: 'deadline', type: 'TEXT' },
    { name: 'estimated_minutes', type: 'INTEGER' },
    { name: 'is_completed', type: 'INTEGER' },
    { name: 'created_time', type: 'INTEGER' },
    { name: 'tags', type: 'TEXT' }
  ]
};

三、TodoManager 实现

3.1 核心代码

typescript 复制代码
// ai/TodoManager.ts
export class TodoManager {
  private static instance: TodoManager;
  private aiService = AIService.getInstance();
  private promptManager = PromptManager.getInstance();
  private cacheManager = CacheManager.getInstance();
  private todos: TodoItem[] = [];

  static getInstance(): TodoManager {
    if (!TodoManager.instance) {
      TodoManager.instance = new TodoManager();
    }
    return TodoManager.instance;
  }

  // 从自然语言生成待办
  async generateTodos(text: string): Promise<TodoItem[]> {
    // 检查缓存
    const cacheKey = `todo_${this.hashText(text)}`;
    const cached = this.cacheManager.get<TodoItem[]>(cacheKey);
    if (cached) return cached;

    const prompt = this.promptManager.buildPrompt('todo', {});
    const response = await this.aiService.chat([
      { role: 'system', content: prompt },
      { role: 'user', content: `从以下文本中提取待办事项:\n\n${text}` }
    ]);

    const todos = this.parseTodos(response.content);
    this.todos.push(...todos);

    // 写入缓存
    this.cacheManager.set(cacheKey, todos, 60 * 60 * 1000);

    return todos;
  }

  // 按优先级排序
  sortTodos(todos?: TodoItem[]): TodoItem[] {
    const list = todos || this.todos;
    const priorityOrder = { urgent: 0, important: 1, normal: 2, low: 3 };
    return [...list].sort((a, b) => {
      const pa = priorityOrder[a.priority] ?? 2;
      const pb = priorityOrder[b.priority] ?? 2;
      return pa - pb;
    });
  }

  // 按分类过滤
  getByCategory(category: TodoCategory): TodoItem[] {
    return this.todos.filter(t => t.category === category);
  }

  // 切换完成状态
  toggleComplete(id: string): void {
    const todo = this.todos.find(t => t.id === id);
    if (todo) todo.isCompleted = !todo.isCompleted;
  }

  // 删除待办
  deleteTodo(id: string): void {
    this.todos = this.todos.filter(t => t.id !== id);
  }

  // 获取统计数据
  getStats(): TodoStats {
    return TodoOrganizer.getStats(this.todos);
  }

  private parseTodos(content: string): TodoItem[] {
    try {
      const jsonMatch = content.match(/\[[\s\S]*?\]/);
      if (jsonMatch) {
        return JSON.parse(jsonMatch[0]).map((t: any) => ({
          ...t,
          id: t.id || Date.now().toString(36) + Math.random().toString(36).substr(2, 5),
          isCompleted: false,
          createdTime: Date.now(),
          tags: t.tags || []
        }));
      }
    } catch {}
    return [];
  }

  private hashText(text: string): string {
    let hash = 0;
    for (let i = 0; i < text.length; i++) {
      const char = text.charCodeAt(i);
      hash = ((hash << 5) - hash) + char;
      hash |= 0;
    }
    return hash.toString(36);
  }
}

3.2 排序与分类

typescript 复制代码
// ai/TodoOrganizer.ts
export class TodoOrganizer {
  // Eisenhower Matrix 分类
  static classifyByMatrix(todo: TodoItem): 'do' | 'decide' | 'delegate' | 'delete' {
    if (todo.priority === 'urgent' && todo.category === 'work') return 'do';
    if (todo.priority === 'important') return 'decide';
    if (todo.priority === 'normal') return 'delegate';
    return 'delete';
  }

  // 预估番茄钟数量
  static estimatePomodoros(minutes: number): number {
    return Math.ceil(minutes / 25);
  }

  // 时间分组
  static groupByTimeframe(todos: TodoItem[]): Record<string, TodoItem[]> {
    const groups: Record<string, TodoItem[]> = {
      today: [],
      tomorrow: [],
      thisWeek: [],
      future: []
    };

    for (const todo of todos) {
      if (!todo.deadline) { groups.future.push(todo); continue; }
      const deadline = new Date(todo.deadline);
      const now = new Date();
      const diff = deadline.getTime() - now.getTime();
      const days = Math.ceil(diff / (1000 * 60 * 60 * 24));

      if (days <= 0) groups.today.push(todo);
      else if (days <= 1) groups.tomorrow.push(todo);
      else if (days <= 7) groups.thisWeek.push(todo);
      else groups.future.push(todo);
    }

    return groups;
  }

  // 分类统计
  static getStats(todos: TodoItem[]): TodoStats {
    return {
      total: todos.length,
      completed: todos.filter(t => t.isCompleted).length,
      urgent: todos.filter(t => t.priority === 'urgent').length,
      overdue: todos.filter(t => {
        if (!t.deadline || t.isCompleted) return false;
        return new Date(t.deadline).getTime() < Date.now();
      }).length
    };
  }
}

interface TodoStats {
  total: number;
  completed: number;
  urgent: number;
  overdue: number;
}

四象限法则:利用 Eisenhower Matrix 对任务进行"重要-紧急"分类,帮助用户优先处理最重要的事务。


四、Prompt 模板

4.1 todo.md

markdown 复制代码
---
name: todo
version: 1.1.0
description: AI 待办事项生成
---

你是一个任务管理专家。从用户输入的文本中提取待办事项。

## 提取规则

1. 识别所有明确的任务描述
2. 推断合理的优先级(urgent/important/normal/low)
3. 分类到合适的类别(work/life/study/health/other)
4. 提取时间信息作为截止日期

## 输出格式

返回 JSON 数组:
[
  {
    "title": "明天上午开会",
    "description": "准备季度汇报材料",
    "priority": "urgent",
    "category": "work",
    "deadline": "2025-01-15",
    "estimatedMinutes": 120,
    "tags": ["会议"]
  }
]

五、主界面实现

5.1 TodoPage

typescript 复制代码
// pages/TodoPage.ets
import { display } from '@kit.ArkUI';

@Entry
@Component
struct TodoPage {
  @State inputText: string = '';
  @State todos: TodoItem[] = [];
  @State isLoading: boolean = false;
  @State filterCategory: string = 'all';
  @State statusBarHeight: number = 0;
  @State navBarHeight: number = 0;
  private todoManager = TodoManager.getInstance();

  aboutToAppear() {
    this.statusBarHeight = AppStorage.get<number>('statusBarHeight') || 0;
    this.navBarHeight = AppStorage.get<number>('navBarHeight') || 0;
  }

  build() {
    Column() {
      // 状态栏占位
      Row().width('100%').height(this.statusBarHeight);

      // 导航栏
      Row() {
        Image($r('app.media.ic_back')).width(24).height(24)
          .onClick(() => RouterUtil.back());
        Text('AI 待办').fontSize(18).fontWeight(FontWeight.Bold).margin({ left: 12 });
        Blank();
        Text('统计').fontSize(14).fontColor('#6C5CE7')
          .onClick(() => this.showStats());
      }
      .width('100%').height(56).padding({ left: 16, right: 16 });

      // 输入区域
      TextArea({
        text: this.inputText,
        placeholder: '用自然语言描述任务,如"明天上午开会,下午写周报..."'
      })
      .height(120).backgroundColor(Color.White).borderRadius(12)
      .padding(12).fontSize(15).margin(16)
      .onChange(v => this.inputText = v);

      // 生成按钮
      Button() {
        if (this.isLoading) {
          LoadingView({ text: '生成中...' });
        } else {
          Row() {
            Image($r('app.media.ic_generate')).width(18).height(18);
            Text('生成待办').fontSize(16).fontColor(Color.White).margin({ left: 6 });
          }
        }
      }
      .width('90%').height(44).backgroundColor('#6C5CE7').borderRadius(22)
      .disabled(!this.inputText.trim() || this.isLoading)
      .margin({ bottom: 16 })
      .onClick(() => this.generateTodos());

      // 待办列表
      if (this.todos.length > 0) {
        Row() {
          Text('待办列表').fontSize(16).fontWeight(FontWeight.Bold);
          Blank();
          Text(`共 ${this.todos.length} 项`).fontSize(13).fontColor(Color.Gray);
        }
        .padding({ left: 16, right: 16, bottom: 8 });

        Scroll() {
          Column() {
            // 按优先级分组展示
            ForEach(['urgent', 'important', 'normal', 'low'] as Priority[], (priority) => {
              const items = this.todos.filter(t => t.priority === priority);
              if (items.length === 0) return;

              Column() {
                Row() {
                  Image($r(`app.media.${PRIORITY_CONFIG[priority].icon}`)).width(14).height(14);
                  Text(PRIORITY_CONFIG[priority].label).fontSize(14)
                    .fontWeight(FontWeight.Bold).margin({ left: 4 });
                  Text(`(${items.length})`).fontSize(12).fontColor(Color.Gray);
                }
                .width('100%').margin({ bottom: 6 });

                ForEach(items, (item: TodoItem) => {
                  this.todoItem(item);
                }, (item: TodoItem) => item.id);
              }
              .width('100%').padding(16).backgroundColor(Color.White)
              .borderRadius(12).margin({ bottom: 8 });
            }, (p: string) => p);
          }
          .padding(16);
        }
        .layoutWeight(1);
      }

      // 底部导航栏占位
      Row().width('100%').height(this.navBarHeight);
    }
    .width('100%').height('100%').backgroundColor('#F5F6FA');
  }

  @Builder
  todoItem(item: TodoItem) {
    Row() {
      // 复选框
      Toggle({ type: ToggleType.Checkbox, isOn: item.isCompleted })
        .width(22).height(22).margin({ right: 12 })
        .onChange(() => this.todoManager.toggleComplete(item.id));

      // 内容
      Column() {
        Text(item.title).fontSize(15)
          .decoration({ type: item.isCompleted ? TextDecorationType.LineThrough : TextDecorationType.None })
          .fontColor(item.isCompleted ? Color.Gray : '#2D3436');
        if (item.deadline) {
          Text(`${item.deadline}`).fontSize(12).fontColor(Color.Gray).margin({ top: 2 });
        }
        Row() {
          ForEach(item.tags, (tag: string) => {
            Text(tag).fontSize(10).fontColor('#6C5CE7')
              .backgroundColor('#F0F0FF').borderRadius(4)
              .padding({ left: 4, right: 4, top: 1, bottom: 1 }).margin({ right: 4 });
          }, (tag: string) => tag);
        }
        .margin({ top: 4 });
      }
      .layoutWeight(1);

      // 优先级标识
      Text(PRIORITY_CONFIG[item.priority].label).fontSize(11)
        .fontColor(Color.White).borderRadius(8).padding({ left: 6, right: 6, top: 2, bottom: 2 })
        .backgroundColor(PRIORITY_CONFIG[item.priority].color);
    }
    .padding(12).border({ bottom: { width: 0.5, color: '#F0F0F0' } });
  }

  async generateTodos() {
    this.isLoading = true;
    try {
      const newTodos = await this.todoManager.generateTodos(this.inputText);
      this.todos = newTodos;
    } catch {
      ToastUtil.show('生成失败');
    } finally {
      this.isLoading = false;
    }
  }

  showStats() {
    const stats = this.todoManager.getStats();
    AlertDialog.show({
      title: '待办统计',
      message: `总计:${stats.total}\n已完成:${stats.completed}\n紧急:${stats.urgent}\n逾期:${stats.overdue}`
    });
  }
}

六、数据持久化与缓存

6.1 使用 relationalStore 持久化待办

typescript 复制代码
// database/TodoDatabase.ts
import { relationalStore } from '@kit.ArkData';

export class TodoDatabase {
  private static instance: TodoDatabase;
  private rdbStore: relationalStore.RdbStore | null = null;

  static getInstance(): TodoDatabase {
    if (!TodoDatabase.instance) {
      TodoDatabase.instance = new TodoDatabase();
    }
    return TodoDatabase.instance;
  }

  async init(context: Context): Promise<void> {
    const config: relationalStore.StoreConfig = {
      name: 'todo.db',
      securityLevel: relationalStore.SecurityLevel.S1
    };
    this.rdbStore = await relationalStore.getRdbStore(context, config);
    await this.rdbStore?.executeSql(`
      CREATE TABLE IF NOT EXISTS todos (
        id TEXT PRIMARY KEY,
        title TEXT NOT NULL,
        description TEXT,
        priority TEXT,
        category TEXT,
        deadline TEXT,
        estimated_minutes INTEGER,
        is_completed INTEGER,
        created_time INTEGER,
        tags TEXT
      )
    `);
  }

  async insert(todo: TodoItem): Promise<number> {
    const bucket: relationalStore.ValuesBucket = {
      id: todo.id,
      title: todo.title,
      description: todo.description,
      priority: todo.priority,
      category: todo.category,
      deadline: todo.deadline,
      estimated_minutes: todo.estimatedMinutes,
      is_completed: todo.isCompleted ? 1 : 0,
      created_time: todo.createdTime,
      tags: JSON.stringify(todo.tags)
    };
    return await this.rdbStore?.insert('todos', bucket) || -1;
  }

  async queryAll(): Promise<TodoItem[]> {
    const predicates = new relationalStore.RdbPredicates('todos');
    predicates.orderByDesc('created_time');
    const resultSet = await this.rdbStore?.query(predicates);
    const list: TodoItem[] = [];
    while (resultSet?.goToNextRow()) {
      list.push({
        id: resultSet.getString(resultSet.getColumnIndex('id')),
        title: resultSet.getString(resultSet.getColumnIndex('title')),
        description: resultSet.getString(resultSet.getColumnIndex('description')),
        priority: resultSet.getString(resultSet.getColumnIndex('priority')) as Priority,
        category: resultSet.getString(resultSet.getColumnIndex('category')) as TodoCategory,
        deadline: resultSet.getString(resultSet.getColumnIndex('deadline')),
        estimatedMinutes: resultSet.getLong(resultSet.getColumnIndex('estimated_minutes')),
        isCompleted: resultSet.getLong(resultSet.getColumnIndex('is_completed')) === 1,
        createdTime: resultSet.getLong(resultSet.getColumnIndex('created_time')),
        tags: JSON.parse(resultSet.getString(resultSet.getColumnIndex('tags')) || '[]')
      });
    }
    resultSet?.close();
    return list;
  }

  async updateStatus(id: string, isCompleted: boolean): Promise<void> {
    const bucket: relationalStore.ValuesBucket = {
      is_completed: isCompleted ? 1 : 0
    };
    const predicates = new relationalStore.RdbPredicates('todos');
    predicates.equalTo('id', id);
    await this.rdbStore?.update(bucket, predicates);
  }

  async deleteById(id: string): Promise<void> {
    const predicates = new relationalStore.RdbPredicates('todos');
    predicates.equalTo('id', id);
    await this.rdbStore?.delete(predicates);
  }
}

6.2 CacheManager 缓存策略

typescript 复制代码
// cache/CacheManager.ts
export class CacheManager {
  private static instance: CacheManager;
  private memoryCache: Map<string, CacheEntry> = new Map();

  static getInstance(): CacheManager {
    if (!CacheManager.instance) {
      CacheManager.instance = new CacheManager();
    }
    return CacheManager.instance;
  }

  set<T>(key: string, value: T, ttl: number = 60 * 60 * 1000): void {
    this.memoryCache.set(key, {
      data: value,
      expireAt: Date.now() + ttl
    });
  }

  get<T>(key: string): T | null {
    const entry = this.memoryCache.get(key);
    if (!entry) return null;
    if (Date.now() > entry.expireAt) {
      this.memoryCache.delete(key);
      return null;
    }
    return entry.data as T;
  }

  async persist<T>(key: string, value: T): Promise<void> {
    const pref = await getPreferences(getContext(), 'todo_cache');
    await pref.put(key, JSON.stringify(value));
    await pref.flush();
  }

  clear(): void {
    this.memoryCache.clear();
  }
}

interface CacheEntry {
  data: unknown;
  expireAt: number;
}

七、待办统计与报表

7.1 统计指标表

指标 说明 计算方式
总计 待办总数 todos.length
已完成 已完成数量 filter(isCompleted).length
完成率 完成百分比 completed / total * 100%
紧急 紧急优先级数量 filter(priority === 'urgent').length
逾期 超过截止日期 filter(deadline < now && !isCompleted).length
平均用时 预估时长平均值 sum(estimatedMinutes) / total

7.2 分类统计

typescript 复制代码
export class TodoStatsAnalyzer {
  static getCategoryDistribution(todos: TodoItem[]): Record<TodoCategory, number> {
    const distribution: Record<string, number> = {
      work: 0, life: 0, study: 0, health: 0, other: 0
    };
    for (const todo of todos) {
      distribution[todo.category] = (distribution[todo.category] || 0) + 1;
    }
    return distribution as Record<TodoCategory, number>;
  }

  static getPriorityDistribution(todos: TodoItem[]): Record<Priority, number> {
    const distribution: Record<string, number> = {
      urgent: 0, important: 0, normal: 0, low: 0
    };
    for (const todo of todos) {
      distribution[todo.priority] = (distribution[todo.priority] || 0) + 1;
    }
    return distribution as Record<Priority, number>;
  }

  static getWeeklyTrend(todos: TodoItem[]): { day: string; completed: number; created: number }[] {
    const days = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
    return days.map((day, index) => ({
      day,
      completed: todos.filter(t => {
        const d = new Date(t.createdTime);
        return d.getDay() === (index + 1) % 7 && t.isCompleted;
      }).length,
      created: todos.filter(t => {
        const d = new Date(t.createdTime);
        return d.getDay() === (index + 1) % 7;
      }).length
    }));
  }
}

7.3 完成趋势图表数据

日期 新增 完成 累计
周一 5 3 2
周二 3 4 1
周三 4 2 3
周四 2 5 0
周五 6 4 2

八、Git 提交

bash 复制代码
git add .
git commit -m "feat(todo): 完成 AI 待办事项生成

- 自然语言转结构化待办
- 四档优先级 + 四象限分类
- 按时间分组(今天/明天/本周/未来)
- 完成状态切换和删除
- 待办统计功能
- 集成 relationalStore 持久化待办数据
- 实现 CacheManager 缓存策略
- 支持 OpenAI/DeepSeek/Qwen/智谱/豆包 多 Provider
- 实现安全区适配(AppStorage + display)
- 使用 SVG 矢量图替代 emoji
- 实现 PromptManager 版本控制
- 分类统计与趋势分析

Co-Authored-By: AtomCode (deepseek-v4-flash) <noreply@atomgit.com>"

git tag v0.1.4

总结

本文实现了 AI 待办事项生成 功能。核心要点:

  1. 自然语言理解:一句话自动提取待办事项
  2. 四档优先级:紧急/重要/普通/低优,Eisenhower Matrix 分类
  3. 时间分组:今天/明天/本周/未来,自动排期
  4. 分类统计:总计、完成、逾期一目了然
  5. 灵活操作:勾选完成、删除、标签管理
  6. 多 Provider 支持:OpenAI、DeepSeek、Qwen、智谱、豆包
  7. PromptManager:独立管理 prompt,支持版本控制
  8. 安全区适配:通过 AppStorage 获取 statusBarHeight 和 navBarHeight
  9. 数据持久化:使用 relationalStore 保存待办数据
  10. 双层缓存:CacheManager 内存缓存 + 持久化缓存
  11. SVG 图标:所有图标使用矢量图,不使用 emoji
  12. 统计报表:分类分布、优先级分布、周趋势分析

如果这篇文章对你有帮助,欢迎点赞、收藏、关注,你的支持是我持续创作的动力!


相关资源

相关推荐
武子康1 小时前
开放权重不是唯一控制权:Kimi K3、Tencent Hy3 与 ByteDance Seed 的九项交付比较
人工智能·llm·agent
Zzj_tju1 小时前
Instruction Tuning 论文精读路线:从 Supervised Fine-Tuning 到 Instruction Following
人工智能·笔记·学习·语言模型·自然语言处理
2601_960906721 小时前
AI研发加速中式及泛亚洲
人工智能·vscode·macos·sublime text·phpstorm
为啥全要学1 小时前
在大语言模型上使用 PPO 算法
人工智能·算法·语言模型
studyrunner1 小时前
【AI开源】Buzz 实战教程:搭建人类与多 AI Agent 协同工作的自托管工作区
人工智能·开源
动物园猫1 小时前
夜间野生动物目标检测数据集:17类别、17,000张图像 | 目标检测
人工智能·目标检测·计算机视觉
小马9261 小时前
2026年8月4日科技热点深度解析:AI大模型群雄逐鹿、卫星互联网组网提速、半导体封装材料革命
人工智能·科技·deepseek
烛衔溟1 小时前
HarmonyOS 网络连接 —— HTTP 请求、Axios 与 Socket 通信
http·华为·harmonyos